From e9fcbf866ea59580d9d860a35927be34b4d9572e Mon Sep 17 00:00:00 2001 From: Louis Moureaux Date: Sat, 6 Aug 2022 20:48:57 +0200 Subject: [PATCH 1/5] Remove NUM_INFO_FIELDS This was stupid design. --- client/citydlg.cpp | 29 ++++++++++++++--------------- client/citydlg.h | 3 +-- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/client/citydlg.cpp b/client/citydlg.cpp index 58b08c1106..d08bb39757 100644 --- a/client/citydlg.cpp +++ b/client/citydlg.cpp @@ -938,8 +938,6 @@ void city_label::set_city(city *pciti) { pcity = pciti; } city_info::city_info(QWidget *parent) : QWidget(parent) { - int iter; - QLabel *ql; QStringList info_list; QGridLayout *info_grid_layout = new QGridLayout(); @@ -953,16 +951,17 @@ city_info::city_info(QWidget *parent) : QWidget(parent) info_grid_layout->setSpacing(0); info_grid_layout->setContentsMargins(0, 0, 0, 0); - fc_assert(info_list.count() == NUM_INFO_FIELDS); - for (iter = 0; iter < NUM_INFO_FIELDS; iter++) { - ql = new QLabel(info_list[iter], this); + for (int i = 0; i < info_list.size(); i++) { + auto ql = new QLabel(info_list[i], this); ql->setFont(small_font); ql->setProperty(fonts::notify_label, "true"); - info_grid_layout->addWidget(ql, iter, 0); - qlt[iter] = new QLabel(this); - qlt[iter]->setFont(small_font); - qlt[iter]->setProperty(fonts::notify_label, "true"); - info_grid_layout->addWidget(qlt[iter], iter, 1); + info_grid_layout->addWidget(ql, i, 0); + + ql = new QLabel(this); + ql->setFont(small_font); + ql->setProperty(fonts::notify_label, "true"); + info_grid_layout->addWidget(ql, i, 1); + m_labels.push_back(ql); } setLayout(info_grid_layout); } @@ -971,7 +970,7 @@ void city_info::update_labels(struct city *pcity, cityIconInfoLabel *ciil) { int illness = 0; char buffer[512]; - char buf[2 * NUM_INFO_FIELDS][512]; + char buf[2 * m_labels.size()][512]; int granaryturns; enum { @@ -1074,15 +1073,15 @@ void city_info::update_labels(struct city *pcity, cityIconInfoLabel *ciil) get_city_dialog_output_text(pcity, O_FOOD, buffer, sizeof(buffer)); - for (int i = 0; i < NUM_INFO_FIELDS; i++) { + for (int i = 0; i < m_labels.size(); i++) { int j = 2 * i; - qlt[i]->setText(QString(buf[2 * i])); + m_labels[i]->setText(QString(buf[2 * i])); if (j != GROWTH && j != GRANARY && j != WASTE && j != CORRUPTION && j != STEAL) { - qlt[i]->setToolTip("
" + QString(buf[2 * i + 1]).toHtmlEscaped()
-                         + "
"); + m_labels[i]->setToolTip( + "
" + QString(buf[2 * i + 1]).toHtmlEscaped() + "
"); } } diff --git a/client/citydlg.h b/client/citydlg.h index 72f010edbc..2c92f158d1 100644 --- a/client/citydlg.h +++ b/client/citydlg.h @@ -65,7 +65,6 @@ class icon_list : public QListWidget { bool oneliner; }; -#define NUM_INFO_FIELDS 15 /**************************************************************************** Custom progressbar with animated progress and right click event ****************************************************************************/ @@ -318,7 +317,7 @@ class city_info : public QWidget { void update_labels(struct city *ci_city, cityIconInfoLabel *); private: - QLabel *qlt[NUM_INFO_FIELDS]; + std::vector m_labels; }; class governor_sliders : public QGroupBox { From 5b978255f42da1906b83141eb6064db6c0f564d8 Mon Sep 17 00:00:00 2001 From: Louis Moureaux Date: Sat, 6 Aug 2022 21:23:29 +0200 Subject: [PATCH 2/5] Use QString in city_info::update_labels Makes us save a few lines and makes the code easier to understand. --- client/citydlg.cpp | 101 ++++++++++++++------------------- client/citydlg_common.cpp | 115 +++++++++++++++++--------------------- client/citydlg_common.h | 23 +++----- 3 files changed, 103 insertions(+), 136 deletions(-) diff --git a/client/citydlg.cpp b/client/citydlg.cpp index d08bb39757..fbabfd5669 100644 --- a/client/citydlg.cpp +++ b/client/citydlg.cpp @@ -23,6 +23,7 @@ #include #include // utility +#include "fc_types.h" #include "fcintl.h" #include "support.h" // common @@ -969,8 +970,8 @@ city_info::city_info(QWidget *parent) : QWidget(parent) void city_info::update_labels(struct city *pcity, cityIconInfoLabel *ciil) { int illness = 0; - char buffer[512]; - char buf[2 * m_labels.size()][512]; + QString buffer; + QString buf[2 * m_labels.size()]; int granaryturns; enum { @@ -992,86 +993,70 @@ void city_info::update_labels(struct city *pcity, cityIconInfoLabel *ciil) }; // fill the buffers with the necessary info - fc_snprintf(buf[FOOD], sizeof(buf[FOOD]), "%3d (%+4d)", - pcity->prod[O_FOOD], pcity->surplus[O_FOOD]); - fc_snprintf(buf[SHIELD], sizeof(buf[SHIELD]), "%3d (%+4d)", - pcity->prod[O_SHIELD] + pcity->waste[O_SHIELD], - pcity->surplus[O_SHIELD]); - fc_snprintf(buf[TRADE], sizeof(buf[TRADE]), "%3d (%+4d)", - pcity->surplus[O_TRADE] + pcity->waste[O_TRADE], - pcity->surplus[O_TRADE]); - fc_snprintf(buf[GOLD], sizeof(buf[GOLD]), "%3d (%+4d)", - pcity->prod[O_GOLD], pcity->surplus[O_GOLD]); - fc_snprintf(buf[LUXURY], sizeof(buf[LUXURY]), "%3d", - pcity->prod[O_LUXURY]); - fc_snprintf(buf[SCIENCE], sizeof(buf[SCIENCE]), "%3d", - pcity->prod[O_SCIENCE]); - fc_snprintf(buf[GRANARY], sizeof(buf[GRANARY]), "%4d/%-4d", - pcity->food_stock, city_granary_size(city_size_get(pcity))); - - get_city_dialog_output_text(pcity, O_FOOD, buf[FOOD + 1], - sizeof(buf[FOOD + 1])); - get_city_dialog_output_text(pcity, O_SHIELD, buf[SHIELD + 1], - sizeof(buf[SHIELD + 1])); - get_city_dialog_output_text(pcity, O_TRADE, buf[TRADE + 1], - sizeof(buf[TRADE + 1])); - get_city_dialog_output_text(pcity, O_GOLD, buf[GOLD + 1], - sizeof(buf[GOLD + 1])); - get_city_dialog_output_text(pcity, O_SCIENCE, buf[SCIENCE + 1], - sizeof(buf[SCIENCE + 1])); - get_city_dialog_output_text(pcity, O_LUXURY, buf[LUXURY + 1], - sizeof(buf[LUXURY + 1])); - get_city_dialog_culture_text(pcity, buf[CULTURE + 1], - sizeof(buf[CULTURE + 1])); - get_city_dialog_pollution_text(pcity, buf[POLLUTION + 1], - sizeof(buf[POLLUTION + 1])); - get_city_dialog_illness_text(pcity, buf[ILLNESS + 1], - sizeof(buf[ILLNESS + 1])); + buf[FOOD] = QString::asprintf("%3d (%+4d)", pcity->prod[O_FOOD], + pcity->surplus[O_FOOD]); + buf[SHIELD] = QString::asprintf("%3d (%+4d)", pcity->prod[O_SHIELD], + pcity->surplus[O_SHIELD]); + buf[TRADE] = QString::asprintf("%3d (%+4d)", pcity->prod[O_TRADE], + pcity->surplus[O_TRADE]); + buf[GOLD] = QString::asprintf("%3d (%+4d)", pcity->prod[O_GOLD], + pcity->surplus[O_GOLD]); + buf[LUXURY] = QString::asprintf("%3d (%+4d)", pcity->prod[O_LUXURY], + pcity->surplus[O_LUXURY]); + buf[SCIENCE] = QString::asprintf("%3d (%+4d)", pcity->prod[O_SCIENCE], + pcity->surplus[O_SCIENCE]); + buf[GRANARY] = QString::asprintf("%4d/%-4d", pcity->food_stock, + city_granary_size(city_size_get(pcity))); + + buf[FOOD + 1] = get_city_dialog_output_text(pcity, O_FOOD); + buf[SHIELD + 1] = get_city_dialog_output_text(pcity, O_SHIELD); + buf[TRADE + 1] = get_city_dialog_output_text(pcity, O_TRADE); + buf[GOLD + 1] = get_city_dialog_output_text(pcity, O_GOLD); + buf[SCIENCE + 1] = get_city_dialog_output_text(pcity, O_SCIENCE); + buf[LUXURY + 1] = get_city_dialog_output_text(pcity, O_LUXURY); + buf[CULTURE + 1] = get_city_dialog_culture_text(pcity); + buf[POLLUTION + 1] = get_city_dialog_pollution_text(pcity); + buf[ILLNESS + 1] = get_city_dialog_illness_text(pcity); granaryturns = city_turns_to_grow(pcity); if (granaryturns == 0) { // TRANS: city growth is blocked. Keep short. - fc_snprintf(buf[GROWTH], sizeof(buf[GROWTH]), _("blocked")); + buf[GROWTH] = _("blocked"); } else if (granaryturns == FC_INFINITY) { // TRANS: city is not growing. Keep short. - fc_snprintf(buf[GROWTH], sizeof(buf[GROWTH]), _("never")); + buf[GROWTH] = _("never"); } else { /* A negative value means we'll have famine in that many turns. But that's handled down below. */ // TRANS: city growth turns. Keep short. - fc_snprintf(buf[GROWTH], sizeof(buf[GROWTH]), - PL_("%d turn", "%d turns", abs(granaryturns)), - abs(granaryturns)); + buf[GROWTH] = QString::asprintf( + PL_("%d turn", "%d turns", abs(granaryturns)), abs(granaryturns)); } - fc_snprintf(buf[CORRUPTION], sizeof(buf[CORRUPTION]), "%4d", - pcity->waste[O_TRADE]); - fc_snprintf(buf[WASTE], sizeof(buf[WASTE]), "%4d", pcity->waste[O_SHIELD]); - fc_snprintf(buf[CULTURE], sizeof(buf[CULTURE]), "%4d", - pcity->client.culture); - fc_snprintf(buf[POLLUTION], sizeof(buf[POLLUTION]), "%4d", - pcity->pollution); + buf[CORRUPTION] = QString::asprintf("%4d", pcity->waste[O_TRADE]); + buf[WASTE] = QString::asprintf("%4d", pcity->waste[O_SHIELD]); + buf[CULTURE] = QString::asprintf("%4d", pcity->client.culture); + buf[POLLUTION] = QString::asprintf("%4d", pcity->pollution); if (!game.info.illness_on) { - fc_snprintf(buf[ILLNESS], sizeof(buf[ILLNESS]), " -.-"); + buf[ILLNESS] = QStringLiteral(" -.-"); } else { illness = city_illness_calc(pcity, nullptr, nullptr, nullptr, nullptr); // illness is in tenth of percent - fc_snprintf(buf[ILLNESS], sizeof(buf[ILLNESS]), "%4.1f%%", - static_cast(illness) / 10.0); + buf[ILLNESS] = + QString::asprintf("%4.1f%%", static_cast(illness) / 10.0); } if (pcity->steal) { - fc_snprintf(buf[STEAL], sizeof(buf[STEAL]), _("%d times"), pcity->steal); + buf[STEAL] = QString::asprintf(_("%d times"), pcity->steal); } else { - fc_snprintf(buf[STEAL], sizeof(buf[STEAL]), _("Not stolen")); + buf[STEAL] = QString::asprintf(_("Not stolen")); } - get_city_dialog_airlift_value(pcity, buf[AIRLIFT], sizeof(buf[AIRLIFT])); - get_city_dialog_airlift_text(pcity, buf[AIRLIFT + 1], - sizeof(buf[AIRLIFT + 1])); + buf[AIRLIFT] = get_city_dialog_airlift_value(pcity); + buf[AIRLIFT + 1] = get_city_dialog_airlift_text(pcity); - get_city_dialog_output_text(pcity, O_FOOD, buffer, sizeof(buffer)); + buffer = get_city_dialog_output_text(pcity, O_FOOD); for (int i = 0; i < m_labels.size(); i++) { int j = 2 * i; diff --git a/client/citydlg_common.cpp b/client/citydlg_common.cpp index 8e0785e547..6f6a8f6243 100644 --- a/client/citydlg_common.cpp +++ b/client/citydlg_common.cpp @@ -362,10 +362,10 @@ static inline int city_sum_compare(double val1, double val2) account_for_unknown is optional, as not every sum wants it (consider pollution's clipping). */ -static void fc__attribute((__format__(__printf__, 5, 6))) - fc__attribute((nonnull(1, 2, 5))) - city_sum_print(struct city_sum *sum, char *buf, size_t bufsz, - bool account_for_unknown, const char *totalfmt, ...) +static QString fc__attribute((__format__(__printf__, 3, 4))) + fc__attribute((nonnull(1, 3))) + city_sum_print(struct city_sum *sum, bool account_for_unknown, + const char *totalfmt, ...) { va_list args; size_t i; @@ -390,35 +390,35 @@ static void fc__attribute((__format__(__printf__, 5, 6))) } } + QString result; for (i = 0; i < sum->n; i++) { if (!sum->sums[i].suppress_if_zero || city_sum_compare(sum->sums[i].value, 0) != 0) { - cat_snprintf( - buf, bufsz, qUtf8Printable(sum->format), sum->sums[i].value, + result += QString::asprintf( + qUtf8Printable(sum->format), sum->sums[i].value, (sum->sums[i].value < 0) ? qUtf8Printable(sum->sums[i].negdesc) : qUtf8Printable(sum->sums[i].posdesc)); if (!sum->sums[i].auxfmt.isEmpty()) { - cat_snprintf(buf, bufsz, qUtf8Printable(sum->sums[i].auxfmt), - sum->sums[i].aux); + result += QString::asprintf(qUtf8Printable(sum->sums[i].auxfmt), + sum->sums[i].aux); } - cat_snprintf(buf, bufsz, "\n"); + result += QStringLiteral("\n"); } } va_start(args, totalfmt); - fc_vsnprintf(buf + qstrlen(buf), bufsz - qstrlen(buf), totalfmt, args); + result += QString::asprintf(totalfmt, args); va_end(args); delete sum; - sum = nullptr; + return result; } /** Return text describing the production output. */ -void get_city_dialog_output_text(const struct city *pcity, - Output_type_id otype, char *buf, - size_t bufsz) +QString get_city_dialog_output_text(const struct city *pcity, + Output_type_id otype) { int priority; int tax[O_LAST]; @@ -427,8 +427,6 @@ void get_city_dialog_output_text(const struct city *pcity, * to "Total surplus" */ struct city_sum *sum = city_sum_new(Q_("?city_surplus:%+4.0f : %s")); - buf[0] = '\0'; - city_sum_add(sum, pcity->citizen_base[otype], Q_("?city_surplus:Citizens")); @@ -567,28 +565,24 @@ void get_city_dialog_output_text(const struct city *pcity, city_sum_add(sum, -pcity->usage[otype], Q_("?city_surplus:Used")); } - city_sum_print(sum, buf, bufsz, true, - Q_("?city_surplus:" - "==== : Adds up to\n" - "%4.0f : Total surplus"), - static_cast(pcity->surplus[otype])); + return city_sum_print(sum, true, + Q_("?city_surplus:" + "==== : Adds up to\n" + "%4.0f : Total surplus"), + static_cast(pcity->surplus[otype])); } /** Return text describing the chance for a plague. */ -void get_city_dialog_illness_text(const struct city *pcity, char *buf, - size_t bufsz) +QString get_city_dialog_illness_text(const struct city *pcity) { int illness, ill_base, ill_size, ill_trade, ill_pollution; struct effect_list *plist; struct city_sum *sum; - buf[0] = '\0'; - if (!game.info.illness_on) { - cat_snprintf(buf, bufsz, _("Illness deactivated in ruleset.")); - return; + return _("Illness deactivated in ruleset."); } sum = city_sum_new(Q_("?city_plague:%+5.1f%% : %s")); @@ -641,18 +635,17 @@ void get_city_dialog_illness_text(const struct city *pcity, char *buf, * add up due to rounding. Making it always add up probably requires * arbitrary assignment of 0.1% rounding figures to particular * effects with something like distribute(). */ - city_sum_print(sum, buf, bufsz, false, - Q_("?city_plague:" - "====== : Adds up to\n" - "%5.1f%% : Plague chance per turn"), - (static_cast(illness) / 10.0)); + return city_sum_print(sum, false, + Q_("?city_plague:" + "====== : Adds up to\n" + "%5.1f%% : Plague chance per turn"), + (static_cast(illness) / 10.0)); } /** Return text describing the pollution output. */ -void get_city_dialog_pollution_text(const struct city *pcity, char *buf, - size_t bufsz) +QString get_city_dialog_pollution_text(const struct city *pcity) { int pollu, prod, pop, mod; struct city_sum *sum = city_sum_new(Q_("?city_pollution:%+4.0f : %s")); @@ -662,29 +655,25 @@ void get_city_dialog_pollution_text(const struct city *pcity, char *buf, pollu = city_pollution_types( pcity, pcity->prod[O_SHIELD] + pcity->unhappy_penalty[O_SHIELD], &prod, &pop, &mod); - buf[0] = '\0'; city_sum_add(sum, prod, Q_("?city_pollution:Pollution from shields")); city_sum_add(sum, pop, Q_("?city_pollution:Pollution from citizens")); city_sum_add(sum, mod, Q_("?city_pollution:Pollution modifier")); - city_sum_print(sum, buf, bufsz, false, - Q_("?city_pollution:" - "==== : Adds up to\n" - "%4.0f : Total surplus"), - static_cast(pollu)); + return city_sum_print(sum, false, + Q_("?city_pollution:" + "==== : Adds up to\n" + "%4.0f : Total surplus"), + static_cast(pollu)); } /** Return text describing the culture output. */ -void get_city_dialog_culture_text(const struct city *pcity, char *buf, - size_t bufsz) +QString get_city_dialog_culture_text(const struct city *pcity) { struct effect_list *plist; struct city_sum *sum = city_sum_new(Q_("?city_culture:%4.0f : %s")); - buf[0] = '\0'; - /* XXX: no way to check whether client's idea of gain/turn is accurate */ city_sum_add(sum, pcity->history, Q_("?city_culture:History (%+d/turn)"), city_history_gain(pcity)); @@ -720,18 +709,17 @@ void get_city_dialog_culture_text(const struct city *pcity, char *buf, effect_list_iterate_end; effect_list_destroy(plist); - city_sum_print(sum, buf, bufsz, true, - Q_("?city_culture:" - "==== : Adds up to\n" - "%4.0f : Total culture"), - static_cast(pcity->client.culture)); + return city_sum_print(sum, true, + Q_("?city_culture:" + "==== : Adds up to\n" + "%4.0f : Total culture"), + static_cast(pcity->client.culture)); } /** Return text describing airlift capacity. */ -void get_city_dialog_airlift_text(const struct city *pcity, char *buf, - size_t bufsz) +QString get_city_dialog_airlift_text(const struct city *pcity) { char src[512]; char dest[512]; @@ -783,20 +771,20 @@ void get_city_dialog_airlift_text(const struct city *pcity, char *buf, switch (unlimited) { case 2: // TRANS: airlift take offs and landings - fc_snprintf(buf, bufsz, _("unlimited take offs and landings")); + return _("unlimited take offs and landings"); break; case 1: /* TRANS: airlift take offs and landings. One is unlimited. The first * string is the take offs text. The 2nd string is the landings text. */ - fc_snprintf(buf, bufsz, _("%s and %s"), src, dest); + return QString::asprintf(_("%s and %s"), src, dest); break; default: - fc_snprintf(buf, bufsz, - /* TRANS: airlift take offs or landings, no unlimited. - * Number is airlift capacity. */ - PL_("%d take off or landing", "%d take offs or landings", - pcity->airlift), - pcity->airlift); + return QString::asprintf( + /* TRANS: airlift take offs or landings, no unlimited. + * Number is airlift capacity. */ + PL_("%d take off or landing", "%d take offs or landings", + pcity->airlift), + pcity->airlift); break; } } @@ -804,8 +792,7 @@ void get_city_dialog_airlift_text(const struct city *pcity, char *buf, /** Return airlift capacity. */ -void get_city_dialog_airlift_value(const struct city *pcity, char *buf, - size_t bufsz) +QString get_city_dialog_airlift_value(const struct city *pcity) { char src[512]; char dest[512]; @@ -849,16 +836,16 @@ void get_city_dialog_airlift_value(const struct city *pcity, char *buf, switch (unlimited) { case 2: // TRANS: unlimited airlift take offs and landings - fc_snprintf(buf, bufsz, _("∞")); + return _("∞"); break; case 1: /* TRANS: airlift take offs and landings. One is unlimited. The first * string is the take offs text. The 2nd string is the landings text. */ - fc_snprintf(buf, bufsz, _("s: %s d: %s"), src, dest); + return QString::asprintf(_("s: %s d: %s"), src, dest); break; default: // TRANS: airlift take offs or landings, no unlimited - fc_snprintf(buf, bufsz, _("%s"), src); + return QString::asprintf(_("%s"), src); break; } } diff --git a/client/citydlg_common.h b/client/citydlg_common.h index 4be3e6d8eb..dec0e5b1e4 100644 --- a/client/citydlg_common.h +++ b/client/citydlg_common.h @@ -17,7 +17,8 @@ #include "city.h" #include "fc_types.h" -class QPixmap; +#include + struct worklist; int get_citydlg_canvas_width(); @@ -28,20 +29,14 @@ char *city_production_cost_str(const struct city *pcity); void get_city_dialog_production(struct city *pcity, char *buffer, size_t buffer_len); -void get_city_dialog_output_text(const struct city *pcity, - Output_type_id otype, char *buffer, - size_t bufsz); -void get_city_dialog_pollution_text(const struct city *pcity, char *buf, - size_t bufsz); -void get_city_dialog_culture_text(const struct city *pcity, char *buf, - size_t bufsz); -void get_city_dialog_illness_text(const struct city *pcity, char *buf, - size_t bufsz); -void get_city_dialog_airlift_text(const struct city *pcity, char *buf, - size_t bufsz); +QString get_city_dialog_output_text(const struct city *pcity, + Output_type_id otype); +QString get_city_dialog_pollution_text(const struct city *pcity); +QString get_city_dialog_culture_text(const struct city *pcity); +QString get_city_dialog_illness_text(const struct city *pcity); +QString get_city_dialog_airlift_text(const struct city *pcity); -void get_city_dialog_airlift_value(const struct city *pcity, char *buf, - size_t bufsz); +QString get_city_dialog_airlift_value(const struct city *pcity); int get_city_citizen_types(struct city *pcity, enum citizen_feeling index, enum citizen_category *categories); From a0d68c02c0d92e397c4896c243aa78a8fd7ed521 Mon Sep 17 00:00:00 2001 From: Louis Moureaux Date: Sat, 6 Aug 2022 22:01:48 +0200 Subject: [PATCH 3/5] Use named widgets in city_info This makes the code much more readable. --- client/citydlg.cpp | 229 +++++++++++++++++--------------------- client/citydlg.h | 7 +- client/citydlg_common.cpp | 19 ++++ client/citydlg_common.h | 1 + 4 files changed, 126 insertions(+), 130 deletions(-) diff --git a/client/citydlg.cpp b/client/citydlg.cpp index fbabfd5669..5d0763c22f 100644 --- a/client/citydlg.cpp +++ b/client/citydlg.cpp @@ -877,22 +877,33 @@ void cityIconInfoLabel::updateText() } labs[1].setText(QString::number(pcity->surplus[O_FOOD])); + labs[0].setToolTip(get_city_dialog_output_text(pcity, O_FOOD)); + labs[1].setToolTip(get_city_dialog_output_text(pcity, O_FOOD)); + labs[3].setText(QString::number(pcity->surplus[O_SHIELD])); - labs[9].setText(QString::number(pcity->surplus[O_TRADE])); + labs[2].setToolTip(get_city_dialog_output_text(pcity, O_SHIELD)); + labs[3].setToolTip(get_city_dialog_output_text(pcity, O_SHIELD)); + labs[5].setText(QString::number(pcity->surplus[O_GOLD])); + labs[4].setToolTip(get_city_dialog_output_text(pcity, O_GOLD)); + labs[5].setToolTip(get_city_dialog_output_text(pcity, O_GOLD)); + labs[7].setText(QString::number(pcity->surplus[O_SCIENCE])); + labs[6].setToolTip(get_city_dialog_output_text(pcity, O_SCIENCE)); + labs[7].setToolTip(get_city_dialog_output_text(pcity, O_SCIENCE)); + + labs[9].setText(QString::number(pcity->surplus[O_TRADE])); + labs[8].setToolTip(get_city_dialog_output_text(pcity, O_TRADE)); + labs[9].setToolTip(get_city_dialog_output_text(pcity, O_TRADE)); + if (city_turns_to_grow(pcity) < 1000) { grow_time = QString::number(city_turns_to_grow(pcity)); } else { grow_time = QStringLiteral("∞"); } labs[11].setText(grow_time); -} - -void cityIconInfoLabel::updateTooltip(int nr, const QString &tooltipText) -{ - labs[nr].setToolTip(tooltipText); - labs[nr + 1].setToolTip(tooltipText); + labs[10].setToolTip(get_city_dialog_growth_value(pcity)); + labs[11].setToolTip(get_city_dialog_growth_value(pcity)); } /** @@ -939,143 +950,107 @@ void city_label::set_city(city *pciti) { pcity = pciti; } city_info::city_info(QWidget *parent) : QWidget(parent) { - QStringList info_list; - QGridLayout *info_grid_layout = new QGridLayout(); - auto small_font = fcFont::instance()->getFont(fonts::notify_label); - info_list << _("Food:") << _("Prod:") << _("Trade:") << _("Gold:") - << _("Luxury:") << _("Science:") << _("Granary:") - << _("Change in:") << _("Corruption:") << _("Waste:") - << _("Culture:") << _("Pollution:") << _("Plague risk:") - << _("Tech Stolen:") << _("Airlift:"); - setFont(small_font); info_grid_layout->setSpacing(0); info_grid_layout->setContentsMargins(0, 0, 0, 0); + setLayout(info_grid_layout); + + auto small_font = fcFont::instance()->getFont(fonts::notify_label); - for (int i = 0; i < info_list.size(); i++) { - auto ql = new QLabel(info_list[i], this); - ql->setFont(small_font); - ql->setProperty(fonts::notify_label, "true"); - info_grid_layout->addWidget(ql, i, 0); + // We use this to shorten the code below, as it would otherwise be very + // repetitive. It creates a label for the description and another for the + // value, and returns the second. + const auto create_labels = [&](const char *title) { + auto label = new QLabel(title, this); + label->setFont(small_font); + label->setProperty(fonts::notify_label, "true"); + info_grid_layout->addWidget(label, info_grid_layout->rowCount(), 0); + + label = new QLabel(this); + label->setFont(small_font); + label->setProperty(fonts::notify_label, "true"); + info_grid_layout->addWidget(label, info_grid_layout->rowCount() - 1, 1); + return label; + }; - ql = new QLabel(this); - ql->setFont(small_font); - ql->setProperty(fonts::notify_label, "true"); - info_grid_layout->addWidget(ql, i, 1); - m_labels.push_back(ql); - } - setLayout(info_grid_layout); + m_food = create_labels(_("Food:")); + m_production = create_labels(_("Prod:")); + m_trade = create_labels(_("Trade:")); + m_gold = create_labels(_("Gold:")); + m_luxury = create_labels(_("Luxury:")); + m_science = create_labels(_("Science:")); + m_granary = create_labels(_("Granary:")); + m_growth = create_labels(_("Change in:")); + m_corruption = create_labels(_("Corruption:")); + m_waste = create_labels(_("Waste:")); + m_culture = create_labels(_("Culture:")); + m_pollution = create_labels(_("Pollution:")); + m_plague = create_labels(_("Plague risk:")); + m_stolen = create_labels(_("Tech Stolen:")); + m_airlift = create_labels(_("Airlift:")); } -void city_info::update_labels(struct city *pcity, cityIconInfoLabel *ciil) -{ - int illness = 0; - QString buffer; - QString buf[2 * m_labels.size()]; - int granaryturns; - - enum { - FOOD = 0, - SHIELD = 2, - TRADE = 4, - GOLD = 6, - LUXURY = 8, - SCIENCE = 10, - GRANARY = 12, - GROWTH = 14, - CORRUPTION = 16, - WASTE = 18, - CULTURE = 20, - POLLUTION = 22, - ILLNESS = 24, - STEAL = 26, - AIRLIFT = 28, - }; +void city_info::update_labels(struct city *pcity) +{ + m_food->setText(QString::asprintf("%3d (%+4d)", pcity->prod[O_FOOD], + pcity->surplus[O_FOOD])); + m_food->setToolTip(get_city_dialog_output_text(pcity, O_FOOD)); - // fill the buffers with the necessary info - buf[FOOD] = QString::asprintf("%3d (%+4d)", pcity->prod[O_FOOD], - pcity->surplus[O_FOOD]); - buf[SHIELD] = QString::asprintf("%3d (%+4d)", pcity->prod[O_SHIELD], - pcity->surplus[O_SHIELD]); - buf[TRADE] = QString::asprintf("%3d (%+4d)", pcity->prod[O_TRADE], - pcity->surplus[O_TRADE]); - buf[GOLD] = QString::asprintf("%3d (%+4d)", pcity->prod[O_GOLD], - pcity->surplus[O_GOLD]); - buf[LUXURY] = QString::asprintf("%3d (%+4d)", pcity->prod[O_LUXURY], - pcity->surplus[O_LUXURY]); - buf[SCIENCE] = QString::asprintf("%3d (%+4d)", pcity->prod[O_SCIENCE], - pcity->surplus[O_SCIENCE]); - buf[GRANARY] = QString::asprintf("%4d/%-4d", pcity->food_stock, - city_granary_size(city_size_get(pcity))); - - buf[FOOD + 1] = get_city_dialog_output_text(pcity, O_FOOD); - buf[SHIELD + 1] = get_city_dialog_output_text(pcity, O_SHIELD); - buf[TRADE + 1] = get_city_dialog_output_text(pcity, O_TRADE); - buf[GOLD + 1] = get_city_dialog_output_text(pcity, O_GOLD); - buf[SCIENCE + 1] = get_city_dialog_output_text(pcity, O_SCIENCE); - buf[LUXURY + 1] = get_city_dialog_output_text(pcity, O_LUXURY); - buf[CULTURE + 1] = get_city_dialog_culture_text(pcity); - buf[POLLUTION + 1] = get_city_dialog_pollution_text(pcity); - buf[ILLNESS + 1] = get_city_dialog_illness_text(pcity); - - granaryturns = city_turns_to_grow(pcity); - - if (granaryturns == 0) { - // TRANS: city growth is blocked. Keep short. - buf[GROWTH] = _("blocked"); - } else if (granaryturns == FC_INFINITY) { - // TRANS: city is not growing. Keep short. - buf[GROWTH] = _("never"); - } else { - /* A negative value means we'll have famine in that many turns. - But that's handled down below. */ - // TRANS: city growth turns. Keep short. - buf[GROWTH] = QString::asprintf( - PL_("%d turn", "%d turns", abs(granaryturns)), abs(granaryturns)); - } + m_production->setText(QString::asprintf( + "%3d (%+4d)", pcity->prod[O_SHIELD], pcity->surplus[O_SHIELD])); + m_production->setToolTip(get_city_dialog_output_text(pcity, O_SHIELD)); + + m_trade->setText(QString::asprintf("%3d (%+4d)", pcity->prod[O_TRADE], + pcity->surplus[O_TRADE])); + m_trade->setToolTip(get_city_dialog_output_text(pcity, O_TRADE)); + + m_gold->setText(QString::asprintf("%3d (%+4d)", pcity->prod[O_GOLD], + pcity->surplus[O_GOLD])); + m_gold->setToolTip(get_city_dialog_output_text(pcity, O_GOLD)); + + m_luxury->setText(QString::asprintf("%3d (%+4d)", pcity->prod[O_LUXURY], + pcity->surplus[O_LUXURY])); + m_luxury->setToolTip(get_city_dialog_output_text(pcity, O_LUXURY)); + + m_science->setText(QString::asprintf("%3d (%+4d)", pcity->prod[O_SCIENCE], + pcity->surplus[O_SCIENCE])); + m_science->setToolTip(get_city_dialog_output_text(pcity, O_SCIENCE)); + + m_granary->setText( + QString::asprintf("%4d/%-4d", pcity->food_stock, + city_granary_size(city_size_get(pcity)))); + + m_growth->setText(get_city_dialog_growth_value(pcity)); + + m_corruption->setText(QString::asprintf("%4d", pcity->waste[O_TRADE])); - buf[CORRUPTION] = QString::asprintf("%4d", pcity->waste[O_TRADE]); - buf[WASTE] = QString::asprintf("%4d", pcity->waste[O_SHIELD]); - buf[CULTURE] = QString::asprintf("%4d", pcity->client.culture); - buf[POLLUTION] = QString::asprintf("%4d", pcity->pollution); + m_waste->setText(QString::asprintf("%4d", pcity->waste[O_SHIELD])); + + m_culture->setText(QString::asprintf("%4d", pcity->client.culture)); + m_culture->setToolTip(get_city_dialog_culture_text(pcity)); + + m_pollution->setText(QString::asprintf("%4d", pcity->pollution)); + m_pollution->setToolTip(get_city_dialog_pollution_text(pcity)); if (!game.info.illness_on) { - buf[ILLNESS] = QStringLiteral(" -.-"); + m_plague->setText(QStringLiteral(" -.-")); } else { - illness = city_illness_calc(pcity, nullptr, nullptr, nullptr, nullptr); + auto illness = + city_illness_calc(pcity, nullptr, nullptr, nullptr, nullptr); // illness is in tenth of percent - buf[ILLNESS] = - QString::asprintf("%4.1f%%", static_cast(illness) / 10.0); + m_plague->setText( + QString::asprintf("%4.1f%%", static_cast(illness) / 10.0)); } + m_plague->setToolTip(get_city_dialog_illness_text(pcity)); + if (pcity->steal) { - buf[STEAL] = QString::asprintf(_("%d times"), pcity->steal); + m_stolen->setText(QString::asprintf(_("%d times"), pcity->steal)); } else { - buf[STEAL] = QString::asprintf(_("Not stolen")); - } - - buf[AIRLIFT] = get_city_dialog_airlift_value(pcity); - buf[AIRLIFT + 1] = get_city_dialog_airlift_text(pcity); - - buffer = get_city_dialog_output_text(pcity, O_FOOD); - - for (int i = 0; i < m_labels.size(); i++) { - int j = 2 * i; - - m_labels[i]->setText(QString(buf[2 * i])); - - if (j != GROWTH && j != GRANARY && j != WASTE && j != CORRUPTION - && j != STEAL) { - m_labels[i]->setToolTip( - "
" + QString(buf[2 * i + 1]).toHtmlEscaped() + "
"); - } + m_stolen->setText(QString::asprintf(_("Not stolen"))); } - ciil->updateTooltip(0, buf[FOOD + 1]); - ciil->updateTooltip(2, buf[SHIELD + 1]); - ciil->updateTooltip(4, buf[GOLD + 1]); - ciil->updateTooltip(6, buf[SCIENCE + 1]); - ciil->updateTooltip(8, buf[TRADE + 1]); - ciil->updateTooltip(10, buf[GROWTH]); + m_airlift->setText(get_city_dialog_airlift_value(pcity)); + m_airlift->setToolTip(get_city_dialog_airlift_text(pcity)); } governor_sliders::governor_sliders(QWidget *parent) : QGroupBox(parent) @@ -2157,7 +2132,7 @@ void city_dialog::update_nation_table() */ void city_dialog::update_info_label() { - ui.info_wdg->update_labels(pcity, ui.info_icon_label); + ui.info_wdg->update_labels(pcity); ui.info_icon_label->setCity(pcity); ui.info_icon_label->updateText(); } diff --git a/client/citydlg.h b/client/citydlg.h index 2c92f158d1..e88ea653e9 100644 --- a/client/citydlg.h +++ b/client/citydlg.h @@ -280,7 +280,6 @@ class cityIconInfoLabel : public QWidget { cityIconInfoLabel(QWidget *parent = 0); void setCity(struct city *pcity); void updateText(); - void updateTooltip(int, const QString &); private: void initLayout(); @@ -314,10 +313,12 @@ class city_info : public QWidget { public: city_info(QWidget *parent = 0); - void update_labels(struct city *ci_city, cityIconInfoLabel *); + void update_labels(struct city *ci_city); private: - std::vector m_labels; + QLabel *m_food, *m_production, *m_trade, *m_gold, *m_luxury, *m_science, + *m_granary, *m_growth, *m_corruption, *m_waste, *m_culture, + *m_pollution, *m_plague, *m_stolen, *m_airlift; }; class governor_sliders : public QGroupBox { diff --git a/client/citydlg_common.cpp b/client/citydlg_common.cpp index 6f6a8f6243..ce4faf09ca 100644 --- a/client/citydlg_common.cpp +++ b/client/citydlg_common.cpp @@ -789,6 +789,25 @@ QString get_city_dialog_airlift_text(const struct city *pcity) } } +/** + * Return time until next growth + */ +QString get_city_dialog_growth_value(const struct city *pcity) +{ + auto granaryturns = city_turns_to_grow(pcity); + if (granaryturns == 0) { + // TRANS: city growth is blocked. Keep short. + return _("blocked"); + } else if (granaryturns == FC_INFINITY) { + // TRANS: city is not growing. Keep short. + return _("never"); + } else { + // TRANS: city growth turns. Keep short. + return QString::asprintf(PL_("%d turn", "%d turns", abs(granaryturns)), + abs(granaryturns)); + } +} + /** Return airlift capacity. */ diff --git a/client/citydlg_common.h b/client/citydlg_common.h index dec0e5b1e4..06dd4983cf 100644 --- a/client/citydlg_common.h +++ b/client/citydlg_common.h @@ -36,6 +36,7 @@ QString get_city_dialog_culture_text(const struct city *pcity); QString get_city_dialog_illness_text(const struct city *pcity); QString get_city_dialog_airlift_text(const struct city *pcity); +QString get_city_dialog_growth_value(const struct city *pcity); QString get_city_dialog_airlift_value(const struct city *pcity); int get_city_citizen_types(struct city *pcity, enum citizen_feeling index, From bca27580ddfb08978a5f077f1013205bfc8f9c61 Mon Sep 17 00:00:00 2001 From: Louis Moureaux Date: Sat, 6 Aug 2022 22:23:33 +0200 Subject: [PATCH 4/5] Add details about citizens in the city size tooltip It's not the best layout ever but it works. See #438. --- client/citydlg.cpp | 4 ++++ client/citydlg.h | 4 ++-- client/citydlg_common.cpp | 30 ++++++++++++++++++++++++++++++ client/citydlg_common.h | 1 + 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/client/citydlg.cpp b/client/citydlg.cpp index 5d0763c22f..c01bc2aed0 100644 --- a/client/citydlg.cpp +++ b/client/citydlg.cpp @@ -973,6 +973,7 @@ city_info::city_info(QWidget *parent) : QWidget(parent) return label; }; + m_size = create_labels(_("Citizens:")); m_food = create_labels(_("Food:")); m_production = create_labels(_("Prod:")); m_trade = create_labels(_("Trade:")); @@ -992,6 +993,9 @@ city_info::city_info(QWidget *parent) : QWidget(parent) void city_info::update_labels(struct city *pcity) { + m_size->setText(QString::asprintf("%3d", pcity->size)); + m_size->setToolTip(get_city_dialog_size_text(pcity)); + m_food->setText(QString::asprintf("%3d (%+4d)", pcity->prod[O_FOOD], pcity->surplus[O_FOOD])); m_food->setToolTip(get_city_dialog_output_text(pcity, O_FOOD)); diff --git a/client/citydlg.h b/client/citydlg.h index e88ea653e9..7b4ba8d53f 100644 --- a/client/citydlg.h +++ b/client/citydlg.h @@ -316,8 +316,8 @@ class city_info : public QWidget { void update_labels(struct city *ci_city); private: - QLabel *m_food, *m_production, *m_trade, *m_gold, *m_luxury, *m_science, - *m_granary, *m_growth, *m_corruption, *m_waste, *m_culture, + QLabel *m_size, *m_food, *m_production, *m_trade, *m_gold, *m_luxury, + *m_science, *m_granary, *m_growth, *m_corruption, *m_waste, *m_culture, *m_pollution, *m_plague, *m_stolen, *m_airlift; }; diff --git a/client/citydlg_common.cpp b/client/citydlg_common.cpp index ce4faf09ca..ba80470dd4 100644 --- a/client/citydlg_common.cpp +++ b/client/citydlg_common.cpp @@ -789,6 +789,36 @@ QString get_city_dialog_airlift_text(const struct city *pcity) } } +/** + * Return text describing the city's citizens. + */ +QString get_city_dialog_size_text(const struct city *pcity) +{ + auto text = QString(); + // TRANS: Number of happy citizens + text += QString(_("Happy: %1\n")) + .arg(pcity->feel[CITIZEN_HAPPY][FEELING_FINAL]); + // TRANS: Number of content citizens + text += QString(_("Content: %1\n")) + .arg(pcity->feel[CITIZEN_CONTENT][FEELING_FINAL]); + // TRANS: Number of unhappy citizens + text += QString(_("Unhappy: %1\n")) + .arg(pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL]); + // TRANS: Number of angry citizens + text += QString(_("Angry: %1\n")) + .arg(pcity->feel[CITIZEN_ANGRY][FEELING_FINAL]); + + specialist_type_iterate(sp) + { + text += QStringLiteral("%1: %2\n") + .arg(specialist_plural_translation(specialist_by_number(sp))) + .arg(pcity->specialists[sp]); + } + specialist_type_iterate_end; + + return text.trimmed(); +} + /** * Return time until next growth */ diff --git a/client/citydlg_common.h b/client/citydlg_common.h index 06dd4983cf..c43652fbc2 100644 --- a/client/citydlg_common.h +++ b/client/citydlg_common.h @@ -35,6 +35,7 @@ QString get_city_dialog_pollution_text(const struct city *pcity); QString get_city_dialog_culture_text(const struct city *pcity); QString get_city_dialog_illness_text(const struct city *pcity); QString get_city_dialog_airlift_text(const struct city *pcity); +QString get_city_dialog_size_text(const struct city *pcity); QString get_city_dialog_growth_value(const struct city *pcity); QString get_city_dialog_airlift_value(const struct city *pcity); From 05fdfc03a2658cfa366293ba94ce6e4fb282c66f Mon Sep 17 00:00:00 2001 From: Louis Moureaux Date: Sat, 6 Aug 2022 22:31:46 +0200 Subject: [PATCH 5/5] Fix formatting of city stats tooltips The easiest way to make tooltips use a fixed width font is to use a
 HTML
element.
---
 client/citydlg_common.cpp | 36 +++++++++++++++++++++++-------------
 1 file changed, 23 insertions(+), 13 deletions(-)

diff --git a/client/citydlg_common.cpp b/client/citydlg_common.cpp
index ba80470dd4..8a9af6495e 100644
--- a/client/citydlg_common.cpp
+++ b/client/citydlg_common.cpp
@@ -166,6 +166,15 @@ void get_city_dialog_production(struct city *pcity, char *buffer,
   }
 }
 
+namespace {
+/**
+ * Embeds the content in an HTML preformatted element
+ */
+QString html_pre(const QString &content)
+{
+  return QStringLiteral("
") + content + QStringLiteral("
"); +} + /** Helper structure to accumulate a breakdown of the constributions to some numeric city property. Contributions are returned in order, @@ -198,7 +207,7 @@ struct city_sum { (the first item is the numeric value and must have a 'f' conversion spec; the second is the description). */ -static struct city_sum *city_sum_new(const char *format) +struct city_sum *city_sum_new(const char *format) { struct city_sum *sum = new city_sum(); @@ -214,10 +223,10 @@ static struct city_sum *city_sum_new(const char *format) If 'posdesc'/'negdesc' and other properties match an existing entry, 'value' is added to the existing entry, else a new one is appended. */ -static void city_sum_add_real(struct city_sum *sum, double value, - bool suppress_if_zero, const QString &auxfmt, - double aux, const QString &posdesc, - const QString &negdesc) +void city_sum_add_real(struct city_sum *sum, double value, + bool suppress_if_zero, const QString &auxfmt, + double aux, const QString &posdesc, + const QString &negdesc) { size_t i; @@ -256,7 +265,7 @@ static void city_sum_add_real(struct city_sum *sum, double value, - Allows control over whether the item will be discarded if its net value is zero (suppress_if_zero). */ -static void fc__attribute((__format__(__printf__, 6, 8))) +void fc__attribute((__format__(__printf__, 6, 8))) fc__attribute((__format__(__printf__, 7, 8))) fc__attribute((nonnull(1, 6, 7))) city_sum_add_full(struct city_sum *sum, double value, @@ -286,7 +295,7 @@ static void fc__attribute((__format__(__printf__, 6, 8))) - not suppressed if net value is zero (compare city_sum_add_nonzero()) - no auxiliary number */ -static void fc__attribute((__format__(__printf__, 3, 4))) +void fc__attribute((__format__(__printf__, 3, 4))) fc__attribute((nonnull(1, 3))) city_sum_add(struct city_sum *sum, double value, const char *descfmt, ...) @@ -309,7 +318,7 @@ static void fc__attribute((__format__(__printf__, 3, 4))) - suppressed if net value is zero (compare city_sum_add()) - no auxiliary number */ -static void fc__attribute((__format__(__printf__, 3, 4))) +void fc__attribute((__format__(__printf__, 3, 4))) fc__attribute((nonnull(1, 3))) city_sum_add_if_nonzero(struct city_sum *sum, double value, const char *descfmt, ...) @@ -328,7 +337,7 @@ static void fc__attribute((__format__(__printf__, 3, 4))) /** Return the net total accumulated in the sum so far. */ -static double city_sum_total(struct city_sum *sum) +double city_sum_total(struct city_sum *sum) { size_t i; double total = 0; @@ -345,7 +354,7 @@ static double city_sum_total(struct city_sum *sum) 0: val1 == val2 (approximately) +1: val1 > val2 */ -static inline int city_sum_compare(double val1, double val2) +inline int city_sum_compare(double val1, double val2) { /* Fudgey epsilon -- probably the numbers we're dealing with have at * most 1% or 0.1% real difference */ @@ -362,7 +371,7 @@ static inline int city_sum_compare(double val1, double val2) account_for_unknown is optional, as not every sum wants it (consider pollution's clipping). */ -static QString fc__attribute((__format__(__printf__, 3, 4))) +QString fc__attribute((__format__(__printf__, 3, 4))) fc__attribute((nonnull(1, 3))) city_sum_print(struct city_sum *sum, bool account_for_unknown, const char *totalfmt, ...) @@ -411,8 +420,9 @@ static QString fc__attribute((__format__(__printf__, 3, 4))) va_end(args); delete sum; - return result; + return html_pre(result); } +} // anonymous namespace /** Return text describing the production output. @@ -816,7 +826,7 @@ QString get_city_dialog_size_text(const struct city *pcity) } specialist_type_iterate_end; - return text.trimmed(); + return html_pre(text.trimmed()); } /**