• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Return-To-The-Roots / s25client / 16516169180

25 Jul 2025 07:14AM UTC coverage: 50.479% (+0.03%) from 50.446%
16516169180

Pull #1786

github

web-flow
Merge 59ab88a61 into f7859b8bd
Pull Request #1786: Add id's for statistics control and gui works for arbitrary players

0 of 152 new or added lines in 1 file covered. (0.0%)

18 existing lines in 3 files now uncovered.

22496 of 44565 relevant lines covered (50.48%)

33880.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/libs/s25main/ingameWindows/iwStatistics.cpp
1
// Copyright (C) 2005 - 2025 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "iwStatistics.h"
6
#include "GamePlayer.h"
7
#include "GlobalGameSettings.h"
8
#include "Loader.h"
9
#include "Settings.h"
10
#include "WindowManager.h"
11
#include "addons/const_addons.h"
12
#include "controls/ctrlButton.h"
13
#include "controls/ctrlOptionGroup.h"
14
#include "controls/ctrlText.h"
15
#include "helpers/Range.h"
16
#include "iwHelp.h"
17
#include "network/GameClient.h"
18
#include "ogl/FontStyle.h"
19
#include "ogl/glFont.h"
20
#include "world/GameWorldBase.h"
21
#include "world/GameWorldViewer.h"
22
#include "gameData/PortraitConsts.h"
23
#include "gameData/const_gui_ids.h"
24
#include <limits>
25

26
namespace {
27

28
/// Size of the diagram area
29
constexpr Extent diagramSize(180, 80);
30
/// Starting point of the diagram (relative to window position)
31
constexpr DrawPoint topLeftRel(37, 124);
32

33
/// (Horizontal) center position of all player portrait buttons
34
constexpr DrawPoint playerButtonsCenterPos(126, 22);
35
constexpr Extent playerBtSize(34, 47);
36

37
/// Distance between statistic values on the x-axis
38
constexpr int stepX = diagramSize.x / NUM_STAT_STEPS;
39

UNCOV
40
std::string getPlayerStatus(const GamePlayer& player)
×
41
{
42
    if(player.IsDefeated())
×
43
        return "---";
×
44
    else if(player.isHuman())
×
45
        return "#" + std::to_string(player.GetPlayerId() + 1);
×
46
    else
47
        return _("COMP");
×
48
}
49

50
enum
51
{
52
    ID_btPlayer_Start,
53
    ID_imgStatistic = ID_btPlayer_Start + MAX_PLAYERS,
54
    ID_grpStatType,
55
    ID_btTypeSize,
56
    ID_btTypeBuildings,
57
    ID_btTypeInhabitants,
58
    ID_btTypeMerchandise,
59
    ID_btTypeMilitary,
60
    ID_btTypeGold,
61
    ID_btTypeProductivity,
62
    ID_btTypeVanquishedEnemies,
63
    ID_grpTime,
64
    ID_time15m,
65
    ID_time1h,
66
    ID_time4h,
67
    ID_time16h,
68
    ID_txtHeader,
69
    ID_txtXAxisValuesStart,
70
    ID_txtMaxY = ID_txtXAxisValuesStart + iwStatistics::MAX_TIME_LABELS,
71
    ID_txtMinY,
72
    ID_btHelp,
73
};
74

75
} // namespace
76

77
iwStatistics::iwStatistics(const GameWorldViewer& gwv)
×
78
    : IngameWindow(CGI_STATISTICS, IngameWindow::posLastOrCenter, Extent(252, 336), _("Statistics"),
×
79
                   LOADER.GetImageN("resource", 41)),
×
NEW
80
      gwv(gwv), showStatistic(MAX_PLAYERS)
×
81
{
82
    // Count active players
UNCOV
83
    numPlayingPlayers = 0;
×
84
    const GameWorldBase& world = gwv.GetWorld();
×
NEW
85
    for(const auto i : helpers::range(world.GetNumPlayers()))
×
86
    {
87
        if(world.GetPlayer(i).isUsed())
×
88
            numPlayingPlayers++;
×
89
    }
90

NEW
91
    DrawPoint curBtPos = playerButtonsCenterPos - DrawPoint(numPlayingPlayers * playerBtSize.x / 2, 0);
×
92

NEW
93
    for(const auto i : helpers::range(world.GetNumPlayers()))
×
94
    {
95
        // Ignore unused players
96
        const GamePlayer& curPlayer = world.GetPlayer(i);
×
97
        if(!curPlayer.isUsed())
×
98
            continue;
×
99

100
        // Set visibility based on addon setting
101
        switch(GAMECLIENT.IsReplayModeOn() ? 0 : world.GetGGS().getSelection(AddonId::STATISTICS_VISIBILITY))
×
102
        {
NEW
103
            default:
×
NEW
104
                RTTR_Assert_Msg(false, "Invalid Addon Setting");
×
105
                showStatistic[i] = false;
106
                break;
NEW
107
            case 0: // Visible for all
×
NEW
108
                showStatistic[i] = true;
×
NEW
109
                break;
×
NEW
110
            case 1: // Only for allies
×
NEW
111
                showStatistic[i] = gwv.GetPlayer().IsAlly(i);
×
NEW
112
                break;
×
NEW
113
            case 2: // Only own statistic
×
NEW
114
                showStatistic[i] = (gwv.GetPlayerId() == i);
×
115
                break;
×
116
        }
117

NEW
118
        RTTR_Assert(curPlayer.portraitIndex < Portraits.size());
×
NEW
119
        const auto& portrait = Portraits[curPlayer.portraitIndex];
×
120
        auto* btPortrait =
NEW
121
          AddImageButton(ID_btPlayer_Start + i, curBtPos, playerBtSize, TextureColor::Green1,
×
NEW
122
                         LOADER.GetImageN(portrait.resourceId, portrait.resourceIndex), curPlayer.name);
×
NEW
123
        curBtPos.x += playerBtSize.x;
×
NEW
124
        btPortrait->SetBorder(false);
×
NEW
125
        btPortrait->SetEnabled(showStatistic[i]);
×
126
    }
127

NEW
128
    AddImage(ID_imgStatistic, DrawPoint(126, 165), LOADER.GetImageN("io", 228));
×
129

130
    // Buttons for changing the statistic type shown
NEW
131
    ctrlOptionGroup* statChanger = AddOptionGroup(ID_grpStatType, GroupSelectType::Illuminate);
×
NEW
132
    statChanger->AddImageButton(ID_btTypeSize, DrawPoint(18, 250), Extent(26, 30), TextureColor::Grey,
×
NEW
133
                                LOADER.GetImageN("io", 167), _("Size of country"));
×
NEW
134
    statChanger->AddImageButton(ID_btTypeBuildings, DrawPoint(45, 250), Extent(26, 30), TextureColor::Grey,
×
NEW
135
                                LOADER.GetImageN("io", 168), _("Buildings"));
×
NEW
136
    statChanger->AddImageButton(ID_btTypeInhabitants, DrawPoint(72, 250), Extent(26, 30), TextureColor::Grey,
×
NEW
137
                                LOADER.GetImageN("io", 169), _("Inhabitants"));
×
NEW
138
    statChanger->AddImageButton(ID_btTypeMerchandise, DrawPoint(99, 250), Extent(26, 30), TextureColor::Grey,
×
NEW
139
                                LOADER.GetImageN("io", 170), _("Merchandise"));
×
NEW
140
    statChanger->AddImageButton(ID_btTypeMilitary, DrawPoint(126, 250), Extent(26, 30), TextureColor::Grey,
×
141
                                LOADER.GetImageN("io", 171), _("Military strength"));
×
NEW
142
    statChanger->AddImageButton(ID_btTypeGold, DrawPoint(153, 250), Extent(26, 30), TextureColor::Grey,
×
143
                                LOADER.GetImageN("io", 172), _("Gold"));
×
NEW
144
    statChanger->AddImageButton(ID_btTypeProductivity, DrawPoint(180, 250), Extent(26, 30), TextureColor::Grey,
×
145
                                LOADER.GetImageN("io", 173), _("Productivity"));
×
NEW
146
    statChanger->AddImageButton(ID_btTypeVanquishedEnemies, DrawPoint(207, 250), Extent(26, 30), TextureColor::Grey,
×
147
                                LOADER.GetImageN("io", 217), _("Vanquished enemies"));
×
148

149
    // Buttons for duration
NEW
150
    constexpr Extent timeBtSize(43, 28);
×
NEW
151
    ctrlOptionGroup* timeChanger = AddOptionGroup(ID_grpTime, GroupSelectType::Illuminate);
×
NEW
152
    timeChanger->AddTextButton(ID_time15m, DrawPoint(51, 288), timeBtSize, TextureColor::Grey, _("15 m"), NormalFont);
×
NEW
153
    timeChanger->AddTextButton(ID_time1h, DrawPoint(96, 288), timeBtSize, TextureColor::Grey, _("1 h"), NormalFont);
×
NEW
154
    timeChanger->AddTextButton(ID_time4h, DrawPoint(141, 288), timeBtSize, TextureColor::Grey, _("4 h"), NormalFont);
×
NEW
155
    timeChanger->AddTextButton(ID_time16h, DrawPoint(186, 288), timeBtSize, TextureColor::Grey, _("16 h"), NormalFont);
×
156

NEW
157
    AddImageButton(ID_btHelp, DrawPoint(18, 288), Extent(30, 32), TextureColor::Grey, LOADER.GetImageN("io", 225),
×
NEW
158
                   _("Help"));
×
159

NEW
160
    const auto labelColor = MakeColor(255, 136, 96, 52);
×
161
    // Current header
NEW
162
    headline = AddText(ID_txtHeader, DrawPoint(130, 120), _("Size of country"), labelColor,
×
NEW
163
                       FontStyle::CENTER | FontStyle::BOTTOM | FontStyle::NO_OUTLINE, NormalFont);
×
164

165
    // Current maximum of y-axis
NEW
166
    txtMaxValueY = AddText(ID_txtMaxY, DrawPoint(211, 125), "1", labelColor,
×
NEW
167
                           FontStyle::RIGHT | FontStyle::VCENTER | FontStyle::NO_OUTLINE, NormalFont);
×
168

169
    // Current minimum of y-axis
NEW
170
    txtMinValueY = AddText(ID_txtMinY, DrawPoint(211, 200), "0", labelColor,
×
NEW
171
                           FontStyle::RIGHT | FontStyle::VCENTER | FontStyle::NO_OUTLINE, NormalFont);
×
172

173
    // Time values on the x-axis
NEW
174
    for(const auto i : helpers::range(timeAnnotations.size()))
×
175
    {
NEW
176
        timeAnnotations[i] = AddText(ID_txtXAxisValuesStart + i, DrawPoint(0, 0), "", labelColor,
×
177
                                     FontStyle::CENTER | FontStyle::TOP | FontStyle::NO_OUTLINE, NormalFont);
×
178
    }
179

180
    // Default values:
NEW
181
    statChanger->SetSelection(ID_btTypeSize);
×
182
    currentView = StatisticType::Country;
×
NEW
183
    timeChanger->SetSelection(ID_time15m, true);
×
184
    currentTime = StatisticTime::T15Minutes;
×
185

186
    if(!SETTINGS.ingame.scale_statistics)
×
NEW
187
        txtMinValueY->SetVisible(false);
×
188
}
×
189

190
iwStatistics::~iwStatistics() = default;
×
191

192
void iwStatistics::Msg_ButtonClick(const unsigned ctrl_id)
×
193
{
NEW
194
    const unsigned playerIndex = ctrl_id - ID_btPlayer_Start;
×
NEW
195
    if(playerIndex < showStatistic.size())
×
NEW
196
        showStatistic[playerIndex] = !showStatistic[playerIndex];
×
NEW
197
    else if(ctrl_id == ID_btHelp)
×
198
    {
NEW
199
        WINDOWMANAGER.ReplaceWindow(
×
NEW
200
          std::make_unique<iwHelp>(_("This window allows a direct comparison with the enemies. "
×
201
                                     "Factors such as the wealth, territorial area, inhabitants, "
202
                                     "etc. of all parties can be compared. This data can be shown "
NEW
203
                                     "over four different time periods.")));
×
204
    }
205
}
×
206

207
void iwStatistics::Msg_OptionGroupChange(const unsigned ctrl_id, const unsigned selection)
×
208
{
209
    switch(ctrl_id)
×
210
    {
NEW
211
        case ID_grpStatType:
×
212
            switch(selection)
213
            {
NEW
214
                case ID_btTypeSize:
×
215
                    currentView = StatisticType::Country;
×
216
                    headline->SetText(_("Size of country"));
×
217
                    break;
×
NEW
218
                case ID_btTypeBuildings:
×
219
                    currentView = StatisticType::Buildings;
×
220
                    headline->SetText(_("Buildings"));
×
221
                    break;
×
NEW
222
                case ID_btTypeInhabitants:
×
223
                    currentView = StatisticType::Inhabitants;
×
224
                    headline->SetText(_("Inhabitants"));
×
225
                    break;
×
NEW
226
                case ID_btTypeMerchandise:
×
227
                    currentView = StatisticType::Merchandise;
×
228
                    headline->SetText(_("Merchandise"));
×
229
                    break;
×
NEW
230
                case ID_btTypeMilitary:
×
231
                    currentView = StatisticType::Military;
×
232
                    headline->SetText(_("Military strength"));
×
233
                    break;
×
NEW
234
                case ID_btTypeGold:
×
235
                    currentView = StatisticType::Gold;
×
236
                    headline->SetText(_("Gold"));
×
237
                    break;
×
NEW
238
                case ID_btTypeProductivity:
×
239
                    currentView = StatisticType::Productivity;
×
240
                    headline->SetText(_("Productivity"));
×
241
                    break;
×
NEW
242
                case ID_btTypeVanquishedEnemies:
×
243
                    currentView = StatisticType::Vanquished;
×
244
                    headline->SetText(_("Vanquished enemies"));
×
245
                    break;
×
246
            }
247
            break;
×
NEW
248
        case ID_grpTime:
×
249
            switch(selection)
250
            {
NEW
251
                case ID_time15m: currentTime = StatisticTime::T15Minutes; break;
×
NEW
252
                case ID_time1h: currentTime = StatisticTime::T1Hour; break;
×
NEW
253
                case ID_time4h: currentTime = StatisticTime::T4Hours; break;
×
NEW
254
                case ID_time16h: currentTime = StatisticTime::T16Hours; break;
×
255
            }
NEW
256
            updateTimeAxisLabels();
×
UNCOV
257
            break;
×
258
    }
259
}
×
260

261
void iwStatistics::DrawContent()
×
262
{
263
    // Draw the alliances and the colored boxes under the portraits
264
    DrawPlayerOverlays();
×
265

UNCOV
266
    DrawAxis();
×
267

268
    // Draw lines making up the statistic
269
    DrawStatistic(currentView);
×
270
}
×
271

272
void iwStatistics::DrawPlayerOverlays()
×
273
{
NEW
274
    DrawPoint drawPt = GetDrawPos() + playerButtonsCenterPos - DrawPoint(numPlayingPlayers * playerBtSize.x / 2, 0);
×
275

NEW
276
    for(const auto i : helpers::range(gwv.GetWorld().GetNumPlayers()))
×
277
    {
278
        const GamePlayer& player = gwv.GetWorld().GetPlayer(i);
×
279
        if(!player.isUsed())
×
280
            continue;
×
281

NEW
282
        if(showStatistic[i])
×
283
        {
284
            // Draw the alliances at top of the player image
285
            DrawPlayerAlliances(drawPt, player);
×
286
            // Draw player boxes and player status at bottom
287
            DrawPlayerBox(drawPt, player);
×
288
        }
NEW
289
        drawPt.x += playerBtSize.x;
×
290
    }
291
}
×
292

293
void iwStatistics::DrawPlayerBox(DrawPoint const& drawPt, const GamePlayer& player)
×
294
{
295
    auto const playerBoxRect = Rect(DrawPoint(drawPt.x, drawPt.y + 47), Extent(34, 12));
×
296
    auto const playerStatusPosition =
297
      DrawPoint(playerBoxRect.getOrigin() + playerBoxRect.getSize() / 2 + DrawPoint(0, 1));
×
298
    DrawRectangle(playerBoxRect, player.color);
×
299
    SmallFont->Draw(playerStatusPosition, getPlayerStatus(player), FontStyle::CENTER | FontStyle::VCENTER,
×
300
                    COLOR_YELLOW);
301
}
×
302

303
void iwStatistics::DrawPlayerAlliances(DrawPoint const& drawPt, const GamePlayer& player)
×
304
{
305
    constexpr unsigned spacingAllianceRects = 1;
×
306
    constexpr Extent allianceRectExtent(4, 6);
×
307
    constexpr unsigned allianceRectOffset = allianceRectExtent.x + spacingAllianceRects;
×
308

309
    auto pactPos = drawPt + DrawPoint::all(spacingAllianceRects);
×
310
    for(auto idxOther : helpers::range(gwv.GetWorld().GetNumPlayers()))
×
311
    {
312
        if(idxOther != player.GetPlayerId() && player.IsAlly(idxOther))
×
313
        {
314
            DrawRectangle(Rect(pactPos, allianceRectExtent), gwv.GetWorld().GetPlayer(idxOther).color);
×
315
            pactPos.x += allianceRectOffset;
×
316
        }
317
    }
318
}
×
319

320
void iwStatistics::DrawStatistic(StatisticType type)
×
321
{
322
    // Find min and max value
323
    unsigned max = 1;
×
NEW
324
    auto min = std::numeric_limits<unsigned>::max();
×
UNCOV
325
    const GameWorldBase& world = gwv.GetWorld();
×
NEW
326
    for(const auto p : helpers::range(world.GetNumPlayers()))
×
327
    {
NEW
328
        if(!showStatistic[p])
×
329
            continue;
×
330
        const GamePlayer::Statistic& stat = world.GetPlayer(p).GetStatistic(currentTime);
×
331

NEW
332
        const auto currentIndex = stat.currentIndex;
×
NEW
333
        for(const auto i : helpers::range(NUM_STAT_STEPS))
×
334
        {
NEW
335
            const auto idx = (currentIndex >= i) ? (currentIndex - i) : (NUM_STAT_STEPS - i + currentIndex);
×
NEW
336
            max = std::max(max, stat.data[type][idx]);
×
NEW
337
            if(SETTINGS.ingame.scale_statistics) //-V807
×
NEW
338
                min = std::min(min, stat.data[type][idx]);
×
339
        }
340
    }
341

NEW
342
    if(max == min)
×
343
    {
344
        --min;
×
345
        ++max;
×
346
    }
347
    // Add values to axis
NEW
348
    txtMaxValueY->SetText(std::to_string(max));
×
349
    if(SETTINGS.ingame.scale_statistics)
×
NEW
350
        txtMinValueY->SetText(std::to_string(min));
×
351

352
    // Draw the line diagram
NEW
353
    const DrawPoint topLeft = GetPos() + topLeftRel;
×
NEW
354
    DrawPoint previousPos;
×
355

NEW
356
    for(const auto p : helpers::range(world.GetNumPlayers()))
×
357
    {
NEW
358
        if(!showStatistic[p])
×
359
            continue;
×
360
        const GamePlayer::Statistic& stat = world.GetPlayer(p).GetStatistic(currentTime);
×
NEW
361
        const auto playerColor = world.GetPlayer(p).color;
×
362

NEW
363
        const auto currentIndex = stat.currentIndex;
×
NEW
364
        for(const auto i : helpers::range(NUM_STAT_STEPS))
×
365
        {
NEW
366
            DrawPoint curPos = topLeft + DrawPoint((NUM_STAT_STEPS - i) * stepX, diagramSize.y);
×
367
            unsigned curStatVal =
368
              stat.data[type][(currentIndex >= i) ? (currentIndex - i) : (NUM_STAT_STEPS - i + currentIndex)];
×
369
            if(SETTINGS.ingame.scale_statistics)
×
NEW
370
                curPos.y -= ((curStatVal - min) * diagramSize.y) / (max - min);
×
371
            else
NEW
372
                curPos.y -= (curStatVal * diagramSize.y) / max;
×
373
            if(i != 0)
×
NEW
374
                DrawLine(curPos, previousPos, 2, playerColor);
×
375
            previousPos = curPos;
×
376
        }
377
    }
378
}
×
379

380
void iwStatistics::DrawAxis()
×
381
{
NEW
382
    const DrawPoint topLeft = GetPos() + topLeftRel;
×
NEW
383
    const auto axisColor = MakeColor(255, 88, 44, 16);
×
384

385
    // X-axis, horizontal
386
    // slightly lower to see zero line, offset so it starts with last (leftmost) value of right-aligned graph
NEW
387
    const auto startPoint = topLeft + DrawPoint(stepX, diagramSize.y + 2);
×
NEW
388
    DrawLine(startPoint, topLeft + diagramSize + DrawPoint(0, 2), 1, axisColor);
×
389

390
    // Y-axis, vertical
NEW
391
    DrawLine(topLeft + DrawPoint(diagramSize.x, 0), topLeft + diagramSize + DrawPoint(0, 5), 1, axisColor);
×
392

393
    // Marks on y-axis
NEW
394
    DrawLine(topLeft + DrawPoint(diagramSize.x - 3, 0), topLeft + DrawPoint(diagramSize.x + 4, 0), 1, axisColor);
×
NEW
395
    DrawLine(topLeft + DrawPoint(diagramSize.x - 3, diagramSize.y / 2),
×
NEW
396
             topLeft + DrawPoint(diagramSize.x + 4, diagramSize.y / 2), 1, axisColor);
×
397

398
    // Marks on x-axis
NEW
399
    for(const auto* lbl : timeAnnotations)
×
400
    {
NEW
401
        if(lbl->IsVisible())
×
402
        {
NEW
403
            const auto lblPos = lbl->GetDrawPos();
×
NEW
404
            DrawLine(lblPos - DrawPoint(0, 4), lblPos - DrawPoint(0, 2), 1, axisColor);
×
405
        }
406
    }
NEW
407
}
×
408

NEW
409
void iwStatistics::updateTimeAxisLabels()
×
410
{
411
    // Labels on x-axis
412

NEW
413
    int numMarks = 0;
×
UNCOV
414
    switch(currentTime)
×
415
    {
416
        case StatisticTime::T15Minutes:
×
NEW
417
            timeAnnotations[1]->SetText("-15");
×
NEW
418
            timeAnnotations[2]->SetText("-12");
×
NEW
419
            timeAnnotations[3]->SetText("-9");
×
NEW
420
            timeAnnotations[4]->SetText("-6");
×
NEW
421
            timeAnnotations[5]->SetText("-3");
×
NEW
422
            numMarks = 6;
×
423
            break;
×
424
        case StatisticTime::T1Hour:
×
NEW
425
            timeAnnotations[1]->SetText("-60");
×
NEW
426
            timeAnnotations[2]->SetText("-50");
×
NEW
427
            timeAnnotations[3]->SetText("-40");
×
NEW
428
            timeAnnotations[4]->SetText("-30");
×
NEW
429
            timeAnnotations[5]->SetText("-20");
×
NEW
430
            timeAnnotations[6]->SetText("-10");
×
NEW
431
            numMarks = 7;
×
432
            break;
×
433
        case StatisticTime::T4Hours:
×
NEW
434
            timeAnnotations[1]->SetText("-240");
×
NEW
435
            timeAnnotations[2]->SetText("-180");
×
NEW
436
            timeAnnotations[3]->SetText("-120");
×
NEW
437
            timeAnnotations[4]->SetText("-60");
×
NEW
438
            numMarks = 5;
×
439
            break;
×
440
        case StatisticTime::T16Hours:
×
NEW
441
            timeAnnotations[1]->SetText("-960");
×
NEW
442
            timeAnnotations[2]->SetText("-720");
×
NEW
443
            timeAnnotations[3]->SetText("-480");
×
NEW
444
            timeAnnotations[4]->SetText("-240");
×
NEW
445
            numMarks = 5;
×
UNCOV
446
            break;
×
447
    }
NEW
448
    constexpr DrawPoint offset(stepX, 6);
×
NEW
449
    DrawPoint curPos = topLeftRel + offset + DrawPoint(0, diagramSize.y);
×
NEW
450
    for(const auto i : helpers::range(1, numMarks))
×
451
    {
NEW
452
        timeAnnotations[i]->SetPos(curPos);
×
NEW
453
        timeAnnotations[i]->SetVisible(true);
×
NEW
454
        curPos.x += (diagramSize.x - offset.x) / (numMarks - 1);
×
455
    }
NEW
456
    for(const auto i : helpers::range<unsigned>(numMarks, timeAnnotations.size()))
×
NEW
457
        timeAnnotations[i]->SetVisible(false);
×
458

459
    // Zero is used for all time periods
NEW
460
    timeAnnotations[0]->SetPos(topLeftRel + diagramSize + DrawPoint(0, offset.y)); // Exactly at the end of the x-axis
×
NEW
461
    timeAnnotations[0]->SetText("0");
×
UNCOV
462
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc