Skip to content

Commit 18ad9ce

Browse files
committed
Improve result card label fitting
1 parent dc325d2 commit 18ad9ce

1 file changed

Lines changed: 107 additions & 3 deletions

File tree

src/application/ScenarioResultWidget.cpp

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,95 @@ QString formatPressureScore(double score) {
7676
return QString::number(score, 'f', 1);
7777
}
7878

79+
QString simplifyLocationLabel(QString text) {
80+
text = text.simplified();
81+
if (text.isEmpty()) {
82+
return text;
83+
}
84+
85+
QStringList words = text.split(' ', Qt::SkipEmptyParts);
86+
static const QStringList genericSuffixes{
87+
"Room",
88+
"Area",
89+
"Zone",
90+
"Passage",
91+
"Corridor",
92+
"Hallway",
93+
"Hall",
94+
"Lobby",
95+
"Section",
96+
};
97+
98+
while (words.size() > 1 && genericSuffixes.contains(words.back(), Qt::CaseInsensitive)) {
99+
words.removeLast();
100+
}
101+
return words.join(' ');
102+
}
103+
104+
QString compactWords(QString text, int maxCharactersPerSide) {
105+
text = text.simplified();
106+
if (text.size() <= maxCharactersPerSide) {
107+
return text;
108+
}
109+
110+
const auto words = text.split(' ', Qt::SkipEmptyParts);
111+
if (words.size() >= 2) {
112+
QString compact = words.front();
113+
for (int index = 1; index < words.size(); ++index) {
114+
const auto candidate = compact + ' ' + words[index];
115+
if (candidate.size() > maxCharactersPerSide) {
116+
break;
117+
}
118+
compact = candidate;
119+
}
120+
if (compact.size() <= maxCharactersPerSide) {
121+
return compact;
122+
}
123+
}
124+
125+
if (maxCharactersPerSide <= 3) {
126+
return text.left(std::max(1, maxCharactersPerSide));
127+
}
128+
return text.left(maxCharactersPerSide - 3).trimmed() + QStringLiteral("...");
129+
}
130+
131+
QString compactBottleneckLabel(QString label) {
132+
label = label.simplified();
133+
if (label.isEmpty()) {
134+
return label;
135+
}
136+
137+
constexpr int kCompactLabelLimit = 18;
138+
if (label.size() <= kCompactLabelLimit) {
139+
return label.replace(QStringLiteral("->"), QStringLiteral(">"));
140+
}
141+
142+
const auto segments = label.split(QStringLiteral("->"), Qt::SkipEmptyParts);
143+
if (segments.size() != 2) {
144+
const auto simplified = simplifyLocationLabel(label);
145+
return compactWords(simplified, kCompactLabelLimit);
146+
}
147+
148+
auto from = simplifyLocationLabel(segments[0]);
149+
auto to = simplifyLocationLabel(segments[1]);
150+
QString compact = QStringLiteral("%1 > %2").arg(from, to);
151+
if (compact.size() <= kCompactLabelLimit) {
152+
return compact;
153+
}
154+
155+
const int sideBudget = std::max(5, (kCompactLabelLimit - 3) / 2);
156+
from = compactWords(from, sideBudget);
157+
to = compactWords(to, sideBudget);
158+
compact = QStringLiteral("%1 > %2").arg(from, to);
159+
if (compact.size() <= kCompactLabelLimit) {
160+
return compact;
161+
}
162+
163+
return QStringLiteral("%1 > %2")
164+
.arg(compactWords(from, sideBudget - 1))
165+
.arg(compactWords(to, sideBudget - 1));
166+
}
167+
79168
QString formatPercent(double ratio) {
80169
return QString("%1%").arg(std::clamp(ratio, 0.0, 1.0) * 100.0, 0, 'f', 0);
81170
}
@@ -445,7 +534,20 @@ QFrame* createMetricCard(const QString& title, const QString& value, QWidget* pa
445534
auto* titleLabel = createLabel(title, card, ui::FontRole::Caption);
446535
titleLabel->setStyleSheet(ui::mutedTextStyleSheet());
447536
auto* valueLabel = createLabel(value, card, ui::FontRole::SectionTitle);
448-
valueLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred);
537+
const bool longValue = value.size() >= 12 || value.contains('>') || value.contains(' ');
538+
auto valueFont = longValue
539+
? ui::font(ui::FontRole::Caption)
540+
: valueLabel->font();
541+
if (longValue) {
542+
valueFont.setWeight(QFont::DemiBold);
543+
} else {
544+
valueFont.setPointSize(std::max(11, valueFont.pointSize() - 1));
545+
}
546+
valueLabel->setFont(valueFont);
547+
valueLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::MinimumExpanding);
548+
valueLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
549+
const auto minimumLines = longValue ? 2 : 1;
550+
valueLabel->setMinimumHeight((QFontMetrics(valueFont).lineSpacing() * minimumLines) + 4);
449551
if (!tooltip.isEmpty()) {
450552
titleLabel->setToolTip(tooltip);
451553
valueLabel->setToolTip(tooltip);
@@ -961,9 +1063,10 @@ QWidget* createResultPanel(
9611063
metricsGrid->setColumnStretch(0, 1);
9621064
metricsGrid->setColumnStretch(1, 1);
9631065
const auto completionTime = resultCompletionTime(frame, artifacts);
964-
const auto worstBottleneck = risk.bottlenecks.empty()
1066+
const auto worstBottleneckFull = risk.bottlenecks.empty()
9651067
? QString("None")
9661068
: QString::fromStdString(risk.bottlenecks.front().label);
1069+
const auto worstBottleneck = compactBottleneckLabel(worstBottleneckFull);
9671070
const auto slowestGroup = artifacts.placementCompletion.empty()
9681071
? QString("Pending")
9691072
: QString::fromStdString(artifacts.placementCompletion.front().placementId);
@@ -994,7 +1097,8 @@ QWidget* createResultPanel(
9941097
"Bottleneck",
9951098
worstBottleneck,
9961099
panel,
997-
QString("Worst bottleneck observed during the run.\n\n%1")
1100+
QString("Worst bottleneck observed during the run.\n\nFull label: %1\n\n%2")
1101+
.arg(worstBottleneckFull)
9981102
.arg(safecrowd::domain::scenarioBottleneckDefinition())), 1, 1);
9991103
metricsGrid->addWidget(createMetricCard(
10001104
"Slowest",

0 commit comments

Comments
 (0)