Freeciv21
Develop your civilization from humble roots to a global empire
citydlg.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 1996-2023 Freeciv21 and Freeciv contributors. This file is
3  part of Freeciv21. Freeciv21 is free software: you can redistribute it
4  and/or modify it under the terms of the GNU General Public License as
5  published by the Free Software Foundation, either version 3 of the
6  License, or (at your option) any later version. You should have received
7  a copy of the GNU General Public License along with Freeciv21. If not,
8  see https://www.gnu.org/licenses/.
9  */
10 
11 #include "citydlg.h"
12 // Qt
13 #include <QApplication>
14 #include <QCheckBox>
15 #include <QGroupBox>
16 #include <QHeaderView>
17 #include <QMouseEvent>
18 #include <QPainter>
19 #include <QScreen>
20 #include <QScrollArea>
21 #include <QScrollBar>
22 #include <QSpacerItem>
23 #include <QSplitter>
24 #include <QVBoxLayout>
25 #include <QWidgetAction>
26 // utility
27 #include "fc_types.h"
28 #include "fcintl.h"
29 #include "player.h"
30 #include "support.h"
31 // common
32 #include "citizens.h"
33 #include "city.h"
34 #include "game.h"
35 
36 // client
37 #include "canvas.h"
38 #include "citydlg_common.h"
39 #include "client_main.h"
40 #include "climisc.h"
41 #include "control.h"
42 #include "fc_client.h"
43 #include "fonts.h"
44 #include "global_worklist.h"
45 #include "governor.h"
46 #include "hudwidget.h"
47 #include "icons.h"
48 #include "mapctrl_common.h"
49 #include "page_game.h"
50 #include "qtg_cxxside.h"
51 #include "text.h"
52 #include "tileset/tilespec.h"
53 #include "tooltips.h"
54 #include "top_bar.h"
55 #include "unitlist.h"
57 #include "utils/unit_quick_menu.h"
58 #include "utils/unit_utils.h"
59 #include "views/view_cities.h" // hIcon
60 #include "views/view_map.h"
61 #include "views/view_map_common.h"
63 
64 extern QString split_text(const QString &text, bool cut);
65 extern QString cut_helptext(const QString &text);
66 
70 unit_list_widget::unit_list_widget(QWidget *parent) : QListWidget(parent)
71 {
72  // Make sure viewportSizeHint is used
73  setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
74  setWrapping(true);
75  setMovement(QListView::Static);
76 
77  connect(this, &QListWidget::itemDoubleClicked, this,
79 }
80 
85 {
86  if (!m_oneliner) {
87  return QSize(1, 5555);
88  }
89  // Try to put everything on one line
90  QSize hint;
91  for (int i = 0; i < count(); ++i) {
92  hint = hint.expandedTo(sizeHintForIndex(indexFromItem(item(i))));
93  }
94  hint.setWidth(hint.width() * count());
95  return hint;
96 }
97 
101 void unit_list_widget::set_units(unit_list *units)
102 {
103  setUpdatesEnabled(false);
104  clear();
105 
106  QSize icon_size;
107  for (const auto *punit : sorted(units)) {
108  auto *item = new QListWidgetItem();
109  item->setToolTip(unit_description(punit));
110  item->setData(Qt::UserRole, punit->id);
111 
112  auto pixmap = create_unit_image(punit);
113  icon_size = icon_size.expandedTo(pixmap.size());
114  item->setIcon(QIcon(pixmap));
115  addItem(item);
116  }
117 
118  setGridSize(icon_size);
119  setIconSize(icon_size);
120 
121  setUpdatesEnabled(true);
122  updateGeometry();
123 }
124 
128 std::vector<unit *> unit_list_widget::selected_playable_units() const
129 {
130  if (!can_client_issue_orders()) {
131  return {};
132  }
133 
134  auto units = std::vector<unit *>();
135  for (const auto item : selectedItems()) {
136  auto id = item->data(Qt::UserRole).toInt();
137  const auto unit = game_unit_by_number(id);
138  if (unit && unit_owner(unit) == client_player()) {
139  units.push_back(unit);
140  }
141  }
142  return units;
143 }
144 
149 {
150  const auto units = selected_playable_units();
151  if (units.empty()) {
152  return;
153  }
154 
155  auto menu = new QMenu;
156  menu->setAttribute(Qt::WA_DeleteOnClose);
157  freeciv::add_quick_unit_actions(menu, units);
158  menu->popup(event->globalPos());
159 
160  event->accept();
161 }
162 
167 {
168  const auto selection = selected_playable_units();
169 
170  unit_focus_set(nullptr); // Clear
171  for (const auto unit : selection) {
173  }
174 
175  if (!selection.empty()) {
176  queen()->city_overlay->dont_focus = true;
178  }
179 }
180 
185 {
186  int happy_cost = 0;
187  if (m_show_upkeep) {
188  if (auto home = game_city_by_number(punit->homecity)) {
189  auto free_unhappy = get_city_bonus(home, EFT_MAKE_CONTENT_MIL);
190  happy_cost = city_unit_unhappiness(punit, &free_unhappy);
191  }
192  }
193 
194  double isosize = 0.6;
196  isosize = 0.45;
197  }
198 
199  auto unit_pixmap = QPixmap();
200  if (punit) {
201  if (m_show_upkeep) {
202  unit_pixmap = QPixmap(tileset_unit_width(get_tileset()),
204  } else {
205  unit_pixmap = QPixmap(tileset_unit_width(get_tileset()),
207  }
208 
209  unit_pixmap.fill(Qt::transparent);
210  put_unit(punit, &unit_pixmap, QPoint());
211 
212  if (m_show_upkeep) {
213  put_unit_city_overlays(punit, &unit_pixmap, 0,
215  punit->upkeep, happy_cost);
216  }
217  }
218 
219  auto img = unit_pixmap.toImage();
220  auto crop_rect = zealous_crop_rect(img);
221  img = img.copy(crop_rect);
222 
224  return QPixmap::fromImage(
225  img.scaledToHeight(tileset_unit_width(get_tileset()) * isosize,
226  Qt::SmoothTransformation));
227  } else {
228  return QPixmap::fromImage(img.scaledToHeight(
229  tileset_unit_width(get_tileset()), Qt::SmoothTransformation));
230  }
231 }
232 
236 progress_bar::progress_bar(QWidget *parent) : QProgressBar(parent)
237 {
238  create_region();
239  sfont = new QFont;
240  pix = nullptr;
241 }
242 
247 {
248  delete pix;
249  delete sfont;
250 }
251 
255 void progress_bar::resizeEvent(QResizeEvent *event)
256 {
257  Q_UNUSED(event);
258  create_region();
259 }
260 
265 {
266  const QPixmap *sprite;
267  QImage cropped_img;
268  QImage img;
269  QPixmap tpix;
270  QRect crop;
271 
272  if (VUT_UTYPE == target->kind) {
273  sprite = get_unittype_sprite(get_tileset(), target->value.utype,
274  direction8_invalid());
275  } else {
276  sprite = get_building_sprite(tileset, target->value.building);
277  }
278  delete pix;
279  if (sprite == nullptr) {
280  pix = nullptr;
281  return;
282  }
283  img = sprite->toImage();
284  crop = zealous_crop_rect(img);
285  cropped_img = img.copy(crop);
286  tpix = QPixmap::fromImage(cropped_img);
287  pix = new QPixmap(tpix.width(), tpix.height());
288  pix->fill(Qt::transparent);
289  pixmap_copy(pix, &tpix, 0, 0, 0, 0, tpix.width(), tpix.height());
290 }
291 
296 {
297  const QPixmap *sprite = nullptr;
298  if (valid_advance_by_number(n)) {
299  sprite = get_tech_sprite(tileset, n);
300  }
301  delete pix;
302  if (sprite == nullptr) {
303  pix = nullptr;
304  return;
305  }
306  pix = new QPixmap(sprite->width(), sprite->height());
307  pix->fill(Qt::transparent);
308  pixmap_copy(pix, sprite, 0, 0, 0, 0, sprite->width(), sprite->height());
309  if (isVisible()) {
310  update();
311  }
312 }
313 
317 void progress_bar::paintEvent(QPaintEvent *event)
318 {
319  Q_UNUSED(event)
320  QPainter p;
321  QLinearGradient g, gx;
322  QColor c;
323  QRect r, rx, r2;
324  int max;
325  int f_size;
326  int pix_width = 0;
327  int point_size = sfont->pointSize();
328  int pixel_size = sfont->pixelSize();
329 
330  if (pix != nullptr) {
331  pix_width = height() - 4;
332  }
333  if (point_size < 0) {
334  f_size = pixel_size;
335  } else {
336  f_size = point_size;
337  }
338 
339  rx.setX(0);
340  rx.setY(0);
341  rx.setWidth(width());
342  rx.setHeight(height());
343  p.begin(this);
344  p.drawLine(rx.topLeft(), rx.topRight());
345  p.drawLine(rx.bottomLeft(), rx.bottomRight());
346 
347  max = maximum();
348 
349  if (max == 0) {
350  max = 1;
351  }
352 
353  r = QRect(0, 0, width() * value() / max, height());
354 
355  gx = QLinearGradient(0, 0, 0, height());
356  c = QColor(palette().color(QPalette::Highlight));
357  gx.setColorAt(0, c);
358  gx.setColorAt(0.5, QColor(40, 40, 40));
359  gx.setColorAt(1, c);
360  p.fillRect(r, QBrush(gx));
361  p.setClipRegion(reg);
362 
363  g = QLinearGradient(0, 0, width(), height());
364  c.setAlphaF(0.1);
365  g.setColorAt(0, c);
366  c.setAlphaF(0.9);
367  g.setColorAt(1, c);
368  p.fillRect(r, QBrush(g));
369 
370  p.setClipping(false);
371  r2 = QRect(width() * value() / max, 0, width(), height());
372  c = palette().color(QPalette::Window);
373  p.fillRect(r2, c);
374 
375  // draw icon
376  if (pix != nullptr) {
377  p.setCompositionMode(QPainter::CompositionMode_SourceOver);
378  p.drawPixmap(
379  2, 2, pix_width * static_cast<float>(pix->width()) / pix->height(),
380  pix_width, *pix, 0, 0, pix->width(), pix->height());
381  }
382 
383  // draw text
384  c = palette().color(QPalette::Text);
385  p.setPen(c);
386  sfont->setCapitalization(QFont::AllUppercase);
387  sfont->setBold(true);
388  p.setFont(*sfont);
389 
390  if (text().contains('\n')) {
391  QString s1, s2;
392  int i, j;
393 
394  i = text().indexOf('\n');
395  s1 = text().left(i);
396  s2 = text().right(text().count() - i);
397 
398  if (2 * f_size >= 2 * height() / 3) {
399  if (point_size < 0) {
400  sfont->setPixelSize(height() / 4);
401  } else {
402  sfont->setPointSize(height() / 4);
403  }
404  }
405 
406  j = height() - 2 * f_size;
407 
408  QFontMetrics fm(*sfont);
409  if (fm.horizontalAdvance(s1) > rx.width()) {
410  s1 = fm.elidedText(s1, Qt::ElideRight, rx.width());
411  }
412 
413  i = rx.width() - fm.horizontalAdvance(s1) + pix_width;
414  i = qMax(0, i);
415  p.drawText(i / 2, j / 3 + f_size, s1);
416 
417  if (fm.horizontalAdvance(s2) > rx.width()) {
418  s2 = fm.elidedText(s2, Qt::ElideRight, rx.width());
419  }
420 
421  i = rx.width() - fm.horizontalAdvance(s2) + pix_width;
422  i = qMax(0, i);
423 
424  p.drawText(i / 2, height() - j / 3, s2);
425  } else {
426  QString s;
427  int i, j;
428  s = text();
429  j = height() - f_size;
430 
431  QFontMetrics fm(*sfont);
432  if (fm.horizontalAdvance(s) > rx.width()) {
433  s = fm.elidedText(s, Qt::ElideRight, rx.width());
434  }
435 
436  i = rx.width() - fm.horizontalAdvance(s) + pix_width;
437  i = qMax(0, i);
438  p.drawText(i / 2, j / 2 + f_size, s);
439  }
440  p.end();
441 }
442 
447 {
448  int offset;
449  QRect r(-50, 0, width() + 50, height());
450  int chunk_width = 16;
451  int size = width() + 50;
452  reg = QRegion();
453 
454  for (offset = 0; offset < (size * 2); offset += (chunk_width * 2)) {
455  QPolygon a;
456 
457  a.setPoints(4, r.x(), r.y() + offset, r.x() + r.width(),
458  (r.y() + offset) - size, r.x() + r.width(),
459  (r.y() + offset + chunk_width) - size, r.x(),
460  r.y() + offset + chunk_width);
461  reg += QRegion(a);
462  }
463 }
464 
468 static void pixmap_put_x(QPixmap *pix)
469 {
470  QPen pen(QColor(0, 0, 0));
471  QPainter p;
472 
473  pen.setWidth(2);
474  p.begin(pix);
475  p.setRenderHint(QPainter::Antialiasing);
476  p.setPen(pen);
477  p.drawLine(0, 0, pix->width(), pix->height());
478  p.drawLine(pix->width(), 0, 0, pix->height());
479  p.end();
480 }
481 
482 cityIconInfoLabel::cityIconInfoLabel(QWidget *parent) : QWidget(parent)
483 {
485  QFontMetrics fm(f);
486 
487  pixHeight = fm.height();
488 
489  initLayout();
490 }
491 
492 void cityIconInfoLabel::setCity(city *pciti) { pcity = pciti; }
493 
494 // inits icons only
496 {
497  QHBoxLayout *l = new QHBoxLayout();
498  labs[0].setPixmap(
499  (hIcon::i()->get(QStringLiteral("foodplus"))).pixmap(pixHeight));
500  l->addWidget(&labs[0]);
501  l->addWidget(&labs[1]);
502 
503  labs[2].setPixmap(
504  (hIcon::i()->get(QStringLiteral("prodplus"))).pixmap(pixHeight));
505  l->addWidget(&labs[2]);
506  l->addWidget(&labs[3]);
507 
508  labs[4].setPixmap(
509  (hIcon::i()->get(QStringLiteral("gold"))).pixmap(pixHeight));
510  l->addWidget(&labs[4]);
511  l->addWidget(&labs[5]);
512 
513  labs[6].setPixmap(
514  (hIcon::i()->get(QStringLiteral("science"))).pixmap(pixHeight));
515  l->addWidget(&labs[6]);
516  l->addWidget(&labs[7]);
517 
518  labs[8].setPixmap(
519  (hIcon::i()->get(QStringLiteral("tradeplus"))).pixmap(pixHeight));
520  l->addWidget(&labs[8]);
521  l->addWidget(&labs[9]);
522 
523  labs[10].setPixmap(
524  (hIcon::i()->get(QStringLiteral("resize"))).pixmap(pixHeight));
525  l->addWidget(&labs[10]);
526  l->addWidget(&labs[11]);
527 
528  setLayout(l);
529 }
530 
532 {
533  QString grow_time;
534  if (!pcity) {
535  return;
536  }
537 
538  labs[1].setText(QString::number(pcity->surplus[O_FOOD]));
539  labs[0].setToolTip(get_city_dialog_output_text(pcity, O_FOOD));
540  labs[1].setToolTip(get_city_dialog_output_text(pcity, O_FOOD));
541 
542  labs[3].setText(QString::number(pcity->surplus[O_SHIELD]));
545 
546  labs[5].setText(QString::number(pcity->surplus[O_GOLD]));
547  labs[4].setToolTip(get_city_dialog_output_text(pcity, O_GOLD));
548  labs[5].setToolTip(get_city_dialog_output_text(pcity, O_GOLD));
549 
550  labs[7].setText(QString::number(pcity->surplus[O_SCIENCE]));
553 
554  labs[9].setText(QString::number(pcity->surplus[O_TRADE]));
557 
558  if (city_turns_to_grow(pcity) < 1000) {
559  grow_time = QString::number(city_turns_to_grow(pcity));
560  } else {
561  grow_time = QStringLiteral("∞");
562  }
563  labs[11].setText(grow_time);
564  labs[10].setToolTip(get_city_dialog_growth_value(pcity));
565  labs[11].setToolTip(get_city_dialog_growth_value(pcity));
566 }
567 
572 city_label::city_label(QWidget *parent) : QLabel(parent)
573 {
575 }
576 
577 void city_label::set_type(int x) { type = x; }
582 {
583  if (!pcity) {
584  return;
585  }
586 
587  if (cma_is_city_under_agent(pcity, nullptr)) {
588  return;
589  }
590 
591  if (!can_client_issue_orders()) {
592  return;
593  }
594 
595  int sprite_width = tileset_small_sprite_width(tileset);
596  int sprite_height = tileset_small_sprite_height(tileset);
597 
598  int num_citizens = pcity->size;
599 
600  // if there's less than CITIZENS_PER_ROW citizens, we may have space on the
601  // sides, so account for that
602  int horizontal_spacing =
603  (this->width() - MIN(CITIZENS_PER_ROW, num_citizens) * sprite_width)
604  / 2;
605 
606  int citizen_x = (event->x() - horizontal_spacing) / sprite_width;
607  int citizen_y = event->y() / sprite_height;
608 
609  int citizen_index = citizen_y * CITIZENS_PER_ROW + citizen_x;
610 
611  // users can click in empty space beyond the citizen sprites if there are
612  // incomplete rows
613  if (citizen_index < 0 || citizen_index > num_citizens - 1) {
614  return;
615  }
616 
617  city_rotate_specialist(pcity, citizen_index);
618 }
619 
621 {
622  auto pix = this->pixmap(Qt::ReturnByValue);
623  if (pix.isNull()) {
624  return {0, 0};
625  } else {
626  return pix.size();
627  }
628 }
629 
630 QSize city_label::minimumSizeHint() const { return this->get_pixmap_size(); }
631 
632 QSize city_label::sizeHint() const { return this->get_pixmap_size(); }
633 
637 void city_label::set_city(city *pciti) { pcity = pciti; }
638 
639 city_info::city_info(QWidget *parent) : QWidget(parent)
640 {
641  QGridLayout *info_grid_layout = new QGridLayout();
642  info_grid_layout->setHorizontalSpacing(6);
643  info_grid_layout->setVerticalSpacing(0);
644  info_grid_layout->setContentsMargins(0, 0, 0, 0);
645  info_grid_layout->setColumnStretch(1, 100);
646  setLayout(info_grid_layout);
647 
648  auto small_font = fcFont::instance()->getFont(fonts::notify_label);
649 
650  // We use this to shorten the code below, as it would otherwise be very
651  // repetitive. It creates a label for the description and another for the
652  // value, and returns the second.
653  const auto create_labels = [&](const char *title) {
654  auto label = new QLabel(title, this);
655  label->setFont(small_font);
656  label->setProperty(fonts::notify_label, "true");
657  info_grid_layout->addWidget(label, info_grid_layout->rowCount(), 0);
658 
659  auto value = new QLabel(this);
660  value->setFont(small_font);
661  value->setProperty(fonts::notify_label, "true");
662  info_grid_layout->addWidget(value, info_grid_layout->rowCount() - 1, 1);
663  return std::make_pair(label, value);
664  };
665 
666  QLabel *dummy;
667  std::tie(dummy, m_food) = create_labels(_("<b>Food:</b>"));
668  std::tie(dummy, m_granary) = create_labels(_("Granary:"));
669  std::tie(dummy, m_size) = create_labels(_("Citizens:"));
670  std::tie(dummy, m_growth) = create_labels(_("Change in:"));
671 
672  info_grid_layout->addItem(new QSpacerItem(0, 9),
673  info_grid_layout->rowCount(), 0);
674 
675  std::tie(dummy, m_production) = create_labels(_("<b>Production:</b>"));
676  std::tie(dummy, m_waste) = create_labels(_("Waste:"));
677 
678  info_grid_layout->addItem(new QSpacerItem(0, 9),
679  info_grid_layout->rowCount(), 0);
680 
681  std::tie(dummy, m_trade) = create_labels(_("<b>Trade:</b>"));
682  std::tie(dummy, m_corruption) = create_labels(_("Corruption:"));
683  std::tie(dummy, m_gold) = create_labels(_("Gold:"));
684  std::tie(dummy, m_science) = create_labels(_("Science:"));
685  std::tie(dummy, m_luxury) = create_labels(_("Luxury:"));
686 
687  info_grid_layout->addItem(new QSpacerItem(0, 9),
688  info_grid_layout->rowCount(), 0);
689 
690  std::tie(dummy, m_culture) = create_labels(_("Culture:"));
691  std::tie(dummy, m_pollution) = create_labels(_("Pollution:"));
692  std::tie(m_plague_label, m_plague) = create_labels(_("Plague risk:"));
693  std::tie(dummy, m_stolen) = create_labels(_("Tech Stolen:"));
694  std::tie(dummy, m_airlift) = create_labels(_("Airlift:"));
695 }
696 
697 void city_info::update_labels(struct city *pcity)
698 {
699  m_size->setText(
700  QString::asprintf("%3d (%s)", pcity->size,
701  qUtf8Printable(get_city_dialog_status_text(pcity))));
702  m_size->setToolTip(get_city_dialog_size_text(pcity));
703 
704  if (pcity->surplus[O_FOOD] < 0) {
705  m_food->setText(QString::asprintf(
706  "<b style=\"white-space:pre;\">%3d (<b "
707  "style=\"color:red;\">%+4d</b>)</b>",
708  pcity->prod[O_FOOD] + pcity->waste[O_FOOD], pcity->surplus[O_FOOD]));
709  m_food->setToolTip(get_city_dialog_output_text(pcity, O_FOOD));
710  m_growth->setText(get_city_dialog_growth_value(pcity));
711  m_growth->setStyleSheet("QLabel { color:red; }");
712  } else {
713  m_food->setText(QString::asprintf(
714  "<b style=\"white-space:pre;\">%3d (%+4d)</b>",
715  pcity->prod[O_FOOD] + pcity->waste[O_FOOD], pcity->surplus[O_FOOD]));
716  m_food->setToolTip(get_city_dialog_output_text(pcity, O_FOOD));
717  m_growth->setText(get_city_dialog_growth_value(pcity));
718  m_growth->setStyleSheet("QLabel { white-space:pre; }");
719  }
720 
721  if (pcity->surplus[O_SHIELD] < 0) {
722  m_production->setText(
723  QString::asprintf("<b style=\"white-space:pre\">%3d (<b "
724  "style=\"color:red;\">%+4d</b>)</b>",
725  pcity->prod[O_SHIELD] + pcity->waste[O_SHIELD],
726  pcity->surplus[O_SHIELD]));
728  } else {
729  m_production->setText(
730  QString::asprintf("<b style=\"white-space:pre\">%3d (%+4d)</b>",
731  pcity->prod[O_SHIELD] + pcity->waste[O_SHIELD],
732  pcity->surplus[O_SHIELD]));
734  }
735 
736  if (pcity->surplus[O_TRADE] < 0) {
737  m_trade->setText(
738  QString::asprintf("<b style=\"white-space:pre\">%3d (<b "
739  "style=\"color:red;\">%+4d</b>)</b>",
740  pcity->prod[O_TRADE] + pcity->waste[O_TRADE],
741  pcity->surplus[O_TRADE]));
742  m_trade->setToolTip(get_city_dialog_output_text(pcity, O_TRADE));
743  } else {
744  m_trade->setText(
745  QString::asprintf("<b style=\"white-space:pre\">%3d (%+4d)</b>",
746  pcity->prod[O_TRADE] + pcity->waste[O_TRADE],
747  pcity->surplus[O_TRADE]));
748  m_trade->setToolTip(get_city_dialog_output_text(pcity, O_TRADE));
749  }
750 
751  if (pcity->surplus[O_GOLD] < 0) {
752  m_gold->setText(QString::asprintf(
753  "<span style=\"white-space:pre\">%3d (<b "
754  "style=\"color:red;\">%+4d</b>)</span>",
755  pcity->prod[O_GOLD] + pcity->waste[O_GOLD], pcity->surplus[O_GOLD]));
756  m_gold->setToolTip(get_city_dialog_output_text(pcity, O_GOLD));
757  } else {
758  m_gold->setText(QString::asprintf(
759  "<span style=\"white-space:pre\">%3d (%+4d)</span>",
760  pcity->prod[O_GOLD] + pcity->waste[O_GOLD], pcity->surplus[O_GOLD]));
761  m_gold->setToolTip(get_city_dialog_output_text(pcity, O_GOLD));
762  }
763 
764  if (pcity->surplus[O_LUXURY] < 0) {
765  m_luxury->setText(
766  QString::asprintf("<span style=\"white-space:pre\">%3d (<b "
767  "style=\"color:red;\">%+4d</b>)</span>",
768  pcity->prod[O_LUXURY] + pcity->waste[O_LUXURY],
769  pcity->surplus[O_LUXURY]));
770  m_luxury->setToolTip(get_city_dialog_output_text(pcity, O_LUXURY));
771  } else {
772  m_luxury->setText(QString::asprintf(
773  "<span style=\"white-space:pre\">%3d (%+4d)</span>",
774  pcity->prod[O_LUXURY] + pcity->waste[O_LUXURY],
775  pcity->surplus[O_LUXURY]));
776  m_luxury->setToolTip(get_city_dialog_output_text(pcity, O_LUXURY));
777  }
778 
779  if (pcity->surplus[O_SCIENCE] < 0) {
780  m_science->setText(
781  QString::asprintf("<span style=\"white-space:pre\">%3d (<b "
782  "style=\"color:red;\">%+4d</b>)</span>",
783  pcity->prod[O_SCIENCE] + pcity->waste[O_SCIENCE],
784  pcity->surplus[O_SCIENCE]));
785  m_science->setToolTip(get_city_dialog_output_text(pcity, O_SCIENCE));
786  } else {
787  m_science->setText(QString::asprintf(
788  "<span style=\"white-space:pre\">%3d (%+4d)</span>",
789  pcity->prod[O_SCIENCE] + pcity->waste[O_SCIENCE],
790  pcity->surplus[O_SCIENCE]));
791  m_science->setToolTip(get_city_dialog_output_text(pcity, O_SCIENCE));
792  }
793 
794  m_granary->setText(
795  QString::asprintf("%3d/%-4d", pcity->food_stock,
797 
798  m_corruption->setText(QString::asprintf("%3d", pcity->waste[O_TRADE]));
799 
800  m_waste->setText(QString::asprintf("%3d", pcity->waste[O_SHIELD]));
801 
802  m_culture->setText(QString::asprintf("%3d", pcity->client.culture));
803  m_culture->setToolTip(get_city_dialog_culture_text(pcity));
804 
805  m_pollution->setText(QString::asprintf("%3d", pcity->pollution));
806  m_pollution->setToolTip(get_city_dialog_pollution_text(pcity));
807 
808  if (game.info.illness_on) {
809  auto illness =
810  city_illness_calc(pcity, nullptr, nullptr, nullptr, nullptr);
811  // illness is in tenth of percent
812  m_plague->setText(
813  QString::asprintf("%3.1f%%", static_cast<float>(illness) / 10.0));
814  m_plague->setToolTip(get_city_dialog_illness_text(pcity));
815  }
816  m_plague_label->setVisible(game.info.illness_on);
817  m_plague->setVisible(game.info.illness_on);
818 
819  if (pcity->steal > 0) {
820  m_stolen->setText(QString::asprintf(
821  PL_("%3d time", "%3d times", pcity->steal), pcity->steal));
822  } else {
823  m_stolen->setText(_("Not stolen"));
824  }
825 
826  m_airlift->setText(get_city_dialog_airlift_value(pcity));
827  m_airlift->setToolTip(get_city_dialog_airlift_text(pcity));
828 }
829 
833 city_dialog::city_dialog(QWidget *parent) : QWidget(parent)
834 
835 {
836  QFont f = QApplication::font();
837  QFontMetrics fm(f);
838  QHeaderView *header;
839 
840  int h = 2 * fm.height() + 2;
841  auto small_font = fcFont::instance()->getFont(fonts::notify_label);
842  ui.setupUi(this);
843 
844  // Prevent mouse events from going through the panels to the main map
845  for (auto child : findChildren<QWidget *>()) {
846  child->setAttribute(Qt::WA_NoMousePropagation);
847  }
848 
849  setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
850  setMouseTracking(true);
851  selected_row_p = -1;
852  pcity = nullptr;
853 
854  // main tab
855  ui.lcity_name->setToolTip(_("Click to change city name"));
856  ui.buy_button->setIcon(
857  fcIcons::instance()->getIcon(QStringLiteral("help-donate")));
858  connect(ui.buy_button, &QAbstractButton::clicked, this, &city_dialog::buy);
859  connect(ui.lcity_name, &QAbstractButton::clicked, this,
861  citizen_pixmap = nullptr;
862  ui.bclose->setIcon(
863  fcIcons::instance()->getIcon(QStringLiteral("city-close")));
864  ui.bclose->setToolTip(_("Close city dialog"));
865  connect(ui.bclose, &QAbstractButton::clicked, this, &QWidget::hide);
866  ui.next_city_but->setIcon(
867  fcIcons::instance()->getIcon(QStringLiteral("city-right")));
868  ui.next_city_but->setToolTip(_("Show next city"));
869  connect(ui.next_city_but, &QAbstractButton::clicked, this,
871  connect(ui.prev_city_but, &QAbstractButton::clicked, this,
873  ui.prev_city_but->setIcon(
874  fcIcons::instance()->getIcon(QStringLiteral("city-left")));
875  ui.prev_city_but->setToolTip(_("Show previous city"));
876  ui.work_next_but->setIcon(
877  fcIcons::instance()->getIcon(QStringLiteral("go-down")));
878  ui.work_prev_but->setIcon(
879  fcIcons::instance()->getIcon(QStringLiteral("go-up")));
880  ui.work_add_but->setIcon(
881  fcIcons::instance()->getIcon(QStringLiteral("list-add")));
882  ui.work_rem_but->setIcon(
883  style()->standardIcon(QStyle::SP_DialogDiscardButton));
884  ui.production_combo_p->setToolTip(_("Click to change current production"));
885  ui.production_combo_p->setFixedHeight(h);
886  ui.p_table_p->setMinimumWidth(160);
887  ui.p_table_p->setContextMenuPolicy(Qt::CustomContextMenu);
888  header = ui.p_table_p->horizontalHeader();
889  header->setStretchLastSection(true);
890  connect(ui.p_table_p, &QWidget::customContextMenuRequested, this,
892  connect(ui.production_combo_p, &progress_bar::clicked, this,
894  connect(ui.work_add_but, &QAbstractButton::clicked, this,
896  connect(ui.work_prev_but, &QAbstractButton::clicked, this,
898  connect(ui.work_next_but, &QAbstractButton::clicked, this,
900  connect(ui.work_rem_but, &QAbstractButton::clicked, this,
902  connect(ui.p_table_p, &QTableWidget::itemDoubleClicked, this,
904  connect(ui.p_table_p->selectionModel(),
905  &QItemSelectionModel::selectionChanged, this,
907  connect(ui.present_units_exp_col_but, &QAbstractButton::clicked, this,
909 
910  // governor tab
911  ui.qgbox->setTitle(_("Presets:"));
912 
913  ui.cma_table->horizontalHeader()->setSectionResizeMode(
914  QHeaderView::Stretch);
915 
916  connect(ui.cma_table->selectionModel(),
917  &QItemSelectionModel::selectionChanged, this,
919  connect(ui.cma_table, &QWidget::customContextMenuRequested, this,
921  connect(ui.cma_table, &QTableWidget::cellDoubleClicked, this,
923 
924  ui.cma_enable_but->setFocusPolicy(Qt::TabFocus);
925  connect(ui.cma_enable_but, &QAbstractButton::pressed, this,
927 
928  ui.bsavecma->setText(_("Save"));
929  ui.bsavecma->setIcon(style()->standardIcon(QStyle::SP_DialogSaveButton));
930  connect(ui.bsavecma, &QAbstractButton::pressed, this,
932 
933  ui.nationality_group->setTitle(_("Nationality"));
934  ui.happiness_group->setTitle(_("Happiness"));
935  ui.label1->setText(_("Cities:"));
936  ui.label2->setText(_("Luxuries:"));
937  ui.label3->setText(_("Buildings:"));
938  ui.label4->setText(_("Nationality:"));
939  ui.label5->setText(_("Units:"));
940  ui.label6->setText(_("Wonders:"));
941  ui.label1->setFont(small_font);
942  ui.label2->setFont(small_font);
943  ui.label4->setFont(small_font);
944  ui.label3->setFont(small_font);
945  ui.label5->setFont(small_font);
946  ui.label6->setFont(small_font);
947  lab_table[0] = ui.lab_table1;
948  lab_table[1] = ui.lab_table2;
949  lab_table[2] = ui.lab_table3;
950  lab_table[3] = ui.lab_table4;
951  lab_table[4] = ui.lab_table5;
952  lab_table[5] = ui.lab_table6;
953  for (int x = 0; x < 6; x++) {
954  lab_table[5]->set_type(x);
955  }
956 
957  ui.tabs_right->setTabText(0, _("General"));
958  ui.tabs_right->setTabText(1, _("Citizens"));
959  ui.tabs_right->setTabText(2, _("Governor"));
960 
961  connect(ui.governor, &freeciv::governor_widget::parameters_changed, this,
963 
964  ui.present_units_list->set_oneliner(true);
965 
966  installEventFilter(this);
967 }
968 
973 {
974  cid cprod;
975  int i, pos;
976  int item, targets_used;
977  QList<cid> prod_list;
978  struct item items[MAX_NUM_PRODUCTION_TARGETS];
979  struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
980  struct universal univ;
981 
982  pos = 0;
983  cprod = cid_encode(pcity->production);
984  targets_used = collect_eventually_buildable_targets(targets, pcity, false);
985  name_and_sort_items(targets, targets_used, items, false, pcity);
986 
987  for (item = 0; item < targets_used; item++) {
988  if (can_city_build_now(pcity, &items[item].item)) {
989  prod_list << cid_encode(items[item].item);
990  }
991  }
992 
993  for (i = 0; i < prod_list.size(); i++) {
994  if (prod_list.at(i) == cprod) {
995  if (next) {
996  pos = i + 1;
997  } else {
998  pos = i - 1;
999  }
1000  }
1001  }
1002  if (pos == prod_list.size()) {
1003  pos = 0;
1004  }
1005  if (pos == -1) {
1006  pos = prod_list.size() - 1;
1007  }
1008  univ = cid_decode(static_cast<cid>(prod_list.at(pos)));
1009  city_change_production(pcity, &univ);
1010 }
1011 
1016 {
1017  const auto can_edit =
1019  ui.prev_city_but->setEnabled(can_edit);
1020  ui.next_city_but->setEnabled(can_edit);
1021  ui.buy_button->setEnabled(can_edit);
1022  ui.cma_enable_but->setEnabled(can_edit);
1023  ui.production_combo_p->setEnabled(can_edit);
1025 }
1026 
1031 {
1032  ui.work_next_but->setEnabled(false);
1033  ui.work_prev_but->setEnabled(false);
1034  ui.work_add_but->setEnabled(false);
1035  ui.work_rem_but->setEnabled(false);
1036 
1038  && city_owner(pcity) == client.conn.playing) {
1039  ui.work_add_but->setEnabled(true);
1040 
1041  if (selected_row_p >= 0 && selected_row_p < ui.p_table_p->rowCount()) {
1042  ui.work_rem_but->setEnabled(true);
1043  }
1044 
1045  if (selected_row_p >= 0
1046  && selected_row_p < ui.p_table_p->rowCount() - 1) {
1047  ui.work_next_but->setEnabled(true);
1048  }
1049 
1050  if (selected_row_p > 0 && selected_row_p < ui.p_table_p->rowCount()) {
1051  ui.work_prev_but->setEnabled(true);
1052  }
1053  }
1054 }
1055 
1060 {
1061  delete citizen_pixmap;
1062  removeEventFilter(this);
1063 }
1064 
1069 {
1070  if (event->spontaneous()) {
1071  return;
1072  }
1073 
1074  if (pcity) {
1075  if (!dont_focus) {
1077  }
1079  pcity = nullptr;
1080  }
1082  king()->menu_bar->minimap_status->setEnabled(true);
1083 }
1084 
1089 {
1090  if (event->spontaneous()) {
1091  return;
1092  }
1093 
1094  dont_focus = false;
1095  if (pcity) {
1096  unit_focus_set(nullptr);
1098  king()->menu_bar->minimap_status->setEnabled(false);
1099  }
1100 }
1101 
1105 bool city_dialog::eventFilter(QObject *obj, QEvent *event)
1106 {
1107  if (obj == this) {
1108  if (event->type() == QEvent::ShortcutOverride) {
1109  QKeyEvent *key_event = static_cast<QKeyEvent *>(event);
1110  if (key_event->key() == Qt::Key_Up) {
1111  change_production(true);
1112  event->setAccepted(true);
1113  return true;
1114  }
1115  if (key_event->key() == Qt::Key_Down) {
1116  change_production(false);
1117  event->setAccepted(true);
1118  return true;
1119  }
1120  }
1121  }
1122  return QObject::eventFilter(obj, event);
1123 }
1124 
1129 {
1130  hud_input_box *ask;
1131  const int city_id = pcity->id;
1132 
1133  if (!can_client_issue_orders()) {
1134  return;
1135  }
1136 
1137  ask = new hud_input_box(king()->central_wdg);
1138  ask->set_text_title_definput(_("What should we rename the city to?"),
1139  _("Rename City"), city_name_get(pcity));
1140  ask->setAttribute(Qt::WA_DeleteOnClose);
1141  connect(ask, &hud_message_box::accepted, this, [=]() {
1142  struct city *pcity = game_city_by_number(city_id);
1143  QByteArray ask_bytes;
1144 
1145  if (!pcity) {
1146  return;
1147  }
1148 
1149  ask_bytes = ask->input_edit.text().toLocal8Bit();
1150  ::city_rename(pcity, ask_bytes.data());
1151  });
1152  ask->show();
1153 }
1154 
1159 {
1160  hud_input_box *ask = new hud_input_box(king()->central_wdg);
1161 
1162  ask->set_text_title_definput(_("What should we name the preset?"),
1163  _("Name new preset"), _("new preset"));
1164  ask->setAttribute(Qt::WA_DeleteOnClose);
1165  connect(ask, &hud_message_box::accepted, this, [=]() {
1166  auto name = ask->input_edit.text();
1167  if (!name.isEmpty()) {
1168  const auto params = ui.governor->parameters();
1169  cmafec_preset_add(qUtf8Printable(name), &params);
1170  update_cma_tab();
1171  }
1172  });
1173  ask->show();
1174 }
1175 
1180 {
1181  if (cma_is_city_under_agent(pcity, nullptr)) {
1183  return;
1184  }
1185 
1186  cma_changed();
1187  update_cma_tab();
1188 }
1189 
1194 {
1195  const auto params = ui.governor->parameters();
1196  cma_put_city_under_agent(pcity, &params);
1197 }
1198 
1202 void city_dialog::cma_double_clicked(int row, int column)
1203 {
1204  Q_UNUSED(column)
1205  const struct cm_parameter *param;
1206 
1207  if (!can_client_issue_orders()) {
1208  return;
1209  }
1210  param = cmafec_preset_get_parameter(row);
1211 
1213  if (cma_is_city_under_agent(pcity, nullptr)) {
1214  update_cma_tab();
1215  }
1216 }
1217 
1221 void city_dialog::cma_selected(const QItemSelection &sl,
1222  const QItemSelection &ds)
1223 {
1224  Q_UNUSED(ds)
1225  const struct cm_parameter *param;
1226  QModelIndex index;
1227  QModelIndexList indexes = sl.indexes();
1228 
1229  if (indexes.isEmpty() || ui.cma_table->signalsBlocked()) {
1230  return;
1231  }
1232 
1233  index = indexes.at(0);
1234  int ind = index.row();
1235 
1236  if (ui.cma_table->currentRow() == -1 || cmafec_preset_num() == 0) {
1237  return;
1238  }
1239 
1240  param = cmafec_preset_get_parameter(ind);
1241 
1242  if (cma_is_city_under_agent(pcity, nullptr)) {
1244  }
1245 
1246  if (cma_is_city_under_agent(pcity, nullptr)) {
1247  update_cma_tab();
1248  } else {
1249  update_sliders();
1250  }
1251 }
1252 
1257 {
1258  QString s;
1259  QTableWidgetItem *item;
1260  struct cm_parameter param;
1261  int i;
1262 
1263  ui.cma_table->clear();
1264  ui.cma_table->setRowCount(0);
1265 
1266  for (i = 0; i < cmafec_preset_num(); i++) {
1267  item = new QTableWidgetItem;
1268  item->setText(cmafec_preset_get_descr(i));
1269  ui.cma_table->insertRow(i);
1270  ui.cma_table->setItem(i, 0, item);
1271  }
1272 
1273  if (cmafec_preset_num() == 0) {
1274  ui.cma_table->insertRow(0);
1275  item = new QTableWidgetItem;
1276  item->setText(_("No governor defined"));
1277  ui.cma_table->setItem(0, 0, item);
1278  }
1279 
1280  if (cma_is_city_under_agent(pcity, nullptr)) {
1281  // view->update(); sveinung - update map here ?
1282  s = QString(cmafec_get_short_descr_of_city(pcity));
1283  auto icon = style()->standardIcon(QStyle::SP_DialogApplyButton);
1284  ui.cma_result_pix->setPixmap(icon.pixmap(32));
1285  // TRANS: %1 is custom string chosen by player
1286  ui.cma_result->setText(QString(_("<h3>Governor Enabled<br>(%1)</h3>"))
1287  .arg(s.toHtmlEscaped()));
1288  } else {
1289  auto icon = style()->standardIcon(QStyle::SP_DialogCancelButton);
1290  ui.cma_result_pix->setPixmap(icon.pixmap(32));
1291  ui.cma_result->setText(QString(_("<h3>Governor Disabled</h3>")));
1292  }
1293  ui.cma_result->setAlignment(Qt::AlignCenter);
1294 
1295  if (cma_is_city_under_agent(pcity, nullptr)) {
1296  cmafec_get_fe_parameter(pcity, &param);
1298  const_cast<struct cm_parameter *const>(&param));
1299  if (i >= 0 && i < ui.cma_table->rowCount()) {
1300  ui.cma_table->blockSignals(true);
1301  ui.cma_table->setCurrentCell(i, 0);
1302  ui.cma_table->blockSignals(false);
1303  }
1304 
1305  ui.cma_enable_but->setText(_("Disable"));
1306  } else {
1307  ui.cma_enable_but->setText(_("Enable"));
1308  }
1309  update_sliders();
1310 }
1311 
1316 {
1317  int i;
1318  hud_message_box *ask;
1319 
1320  i = ui.cma_table->currentRow();
1321 
1322  if (i == -1 || cmafec_preset_num() == 0) {
1323  return;
1324  }
1325 
1326  ask = new hud_message_box(this);
1327  ask->set_text_title(_("Remove this preset?"), cmafec_preset_get_descr(i));
1328  ask->setStandardButtons(QMessageBox::No | QMessageBox::Yes);
1329  ask->setDefaultButton(QMessageBox::No);
1330  ask->setAttribute(Qt::WA_DeleteOnClose);
1331  connect(ask, &hud_message_box::accepted, this, [=]() {
1333  update_cma_tab();
1334  });
1335  ask->show();
1336 }
1337 
1341 void city_dialog::disband_state_changed(bool allow_disband)
1342 {
1343  bv_city_options new_options;
1344 
1345  BV_CLR_ALL(new_options);
1346 
1347  if (allow_disband) {
1348  BV_SET(new_options, CITYO_DISBAND);
1349  } else {
1350  BV_CLR(new_options, CITYO_DISBAND);
1351  }
1352 
1353  if (!client_is_observer()) {
1354  dsend_packet_city_options_req(&client.conn, pcity->id, new_options);
1355  }
1356 }
1357 
1362 {
1363  QMenu *cma_menu = new QMenu(this);
1364  QAction *cma_del_item;
1365 
1366  cma_menu->setAttribute(Qt::WA_DeleteOnClose);
1367  cma_del_item = cma_menu->addAction(_("Remove Governor"));
1368  connect(cma_menu, &QMenu::triggered, this, [=](QAction *act) {
1369  if (act == cma_del_item) {
1370  cma_remove();
1371  }
1372  });
1373 
1374  cma_menu->popup(QCursor::pos());
1375 }
1376 
1381 {
1382  QAction *action, *disband, *wl_save, *wl_clear, *wl_empty,
1383  *submenu_buildings, *submenu_futures, *submenu_units, *submenu_wonders;
1384  QMap<QString, cid> list;
1386  QMenu *change_menu;
1387  QMenu *insert_menu;
1388  QMenu *list_menu;
1389  QMenu *options_menu;
1390  int city_id = pcity->id;
1391 
1392  if (!can_client_issue_orders()) {
1393  return;
1394  }
1395  list_menu = new QMenu(this);
1396  change_menu = list_menu->addMenu(_("Change worklist"));
1397  insert_menu = list_menu->addMenu(_("Insert worklist"));
1398  wl_clear = list_menu->addAction(_("Clear"));
1399  connect(wl_clear, &QAction::triggered, this, &city_dialog::clear_worklist);
1400  list.clear();
1401 
1403  {
1404  list.insert(global_worklist_name(pgwl), global_worklist_id(pgwl));
1405  }
1407 
1408  if (list.count() == 0) {
1409  wl_empty = change_menu->addAction(_("(no worklists defined)"));
1410  insert_menu->addAction(wl_empty);
1411  }
1412 
1413  map_iter = list.constBegin();
1414 
1415  while (map_iter != list.constEnd()) {
1416  action = change_menu->addAction(map_iter.key());
1417  action->setData(map_iter.value());
1418 
1419  action = insert_menu->addAction(map_iter.key());
1420  action->setData(map_iter.value());
1421 
1422  ++map_iter;
1423  }
1424 
1425  wl_save = list_menu->addAction(_("Save worklist"));
1426  connect(wl_save, &QAction::triggered, this, &city_dialog::save_worklist);
1427  options_menu = list_menu->addMenu(_("Options"));
1428  submenu_units = options_menu->addAction(_("Show units"));
1429  submenu_buildings = options_menu->addAction(_("Show buildings"));
1430  submenu_wonders = options_menu->addAction(_("Show wonders"));
1431  submenu_futures = options_menu->addAction(_("Show future targets"));
1432  submenu_futures->setCheckable(true);
1433  submenu_wonders->setCheckable(true);
1434  submenu_buildings->setCheckable(true);
1435  submenu_units->setCheckable(true);
1436  submenu_futures->setChecked(future_targets);
1437  connect(submenu_futures, &QAction::triggered, this,
1438  [=]() { future_targets = !future_targets; });
1439  submenu_units->setChecked(show_units);
1440  connect(submenu_units, &QAction::triggered, this,
1441  [=]() { show_units = !show_units; });
1442  submenu_buildings->setChecked(show_buildings);
1443  connect(submenu_buildings, &QAction::triggered, this,
1444  [=]() { show_buildings = !show_buildings; });
1445  submenu_wonders->setChecked(show_wonders);
1446  connect(submenu_wonders, &QAction::triggered, this,
1447  [=]() { show_wonders = !show_wonders; });
1448  disband = options_menu->addAction(_("Allow disbanding city"));
1449  disband->setCheckable(true);
1450  disband->setChecked(is_city_option_set(pcity, CITYO_DISBAND));
1451  connect(disband, &QAction::triggered, this,
1453 
1454  connect(change_menu, &QMenu::triggered, this, [=](QAction *act) {
1455  QVariant id = act->data();
1456  struct city *pcity = game_city_by_number(city_id);
1457  const struct worklist *worklist;
1458 
1459  if (!pcity) {
1460  return;
1461  }
1462 
1463  fc_assert_ret(id.type() == QVariant::Int);
1466  });
1467 
1468  connect(insert_menu, &QMenu::triggered, this, [=](QAction *act) {
1469  QVariant id = act->data();
1470  struct city *pcity = game_city_by_number(city_id);
1471  const struct worklist *worklist;
1472 
1473  if (!pcity) {
1474  return;
1475  }
1476 
1477  fc_assert_ret(id.type() == QVariant::Int);
1480  });
1481 
1482  list_menu->popup(QCursor::pos());
1483 }
1484 
1489 {
1490  QString str;
1491  int value;
1492 
1493  ui.buy_button->setEnabled(false);
1494 
1495  if (!client_is_observer() && client.conn.playing != nullptr) {
1496  value = pcity->client.buy_cost;
1497  str = QString(PL_("Buy (%1 gold)", "Buy (%1 gold)", value))
1498  .arg(QString::number(value));
1499 
1500  if (client.conn.playing->economic.gold >= value && value != 0) {
1501  ui.buy_button->setEnabled(true);
1502  }
1503  } else {
1504  str = QString(_("Buy"));
1505  }
1506 
1507  ui.buy_button->setText(str);
1508 }
1509 
1513 void city_dialog::fill_citizens_pixmap(QPixmap *pixmap, QPainter *painter,
1514  const citizen_category *categories,
1515  int num_citizens)
1516 {
1517  int sprite_width = tileset_small_sprite_width(tileset);
1518  int sprite_height = tileset_small_sprite_height(tileset);
1519 
1520  QRect sprite_rectangle(0, 0, sprite_width, sprite_height);
1521  QRect painting_area(0, 0, sprite_width, sprite_height);
1522 
1523  pixmap->fill(Qt::transparent);
1524  for (int i = 0; i < num_citizens; i++) {
1525  painting_area.moveTo((i % CITIZENS_PER_ROW) * sprite_width,
1526  (i / CITIZENS_PER_ROW) * sprite_height);
1527  auto pix = get_citizen_sprite(tileset, categories[i], i, pcity);
1528  painter->begin(citizen_pixmap);
1529  painter->drawPixmap(painting_area, *pix, sprite_rectangle);
1530  painter->end();
1531  }
1532 }
1533 
1538 {
1539  enum citizen_category categories[MAX_CITY_SIZE];
1540  int num_citizens =
1542 
1543  int num_rows = num_citizens / CITIZENS_PER_ROW;
1544 
1545  // extra incomplete row for leftover citizens
1546  if (num_citizens % CITIZENS_PER_ROW > 0) {
1547  num_rows += 1;
1548  }
1549 
1550  int sprite_width = tileset_small_sprite_width(tileset);
1551  int sprite_height = tileset_small_sprite_height(tileset);
1552 
1553  int canvas_width = sprite_width * MIN(CITIZENS_PER_ROW, num_citizens);
1554  int canvas_height = sprite_height * num_rows;
1555 
1556  if (citizen_pixmap) {
1557  citizen_pixmap->detach();
1558  delete citizen_pixmap;
1559  }
1560 
1561  citizen_pixmap = new QPixmap(canvas_width, canvas_height);
1562  QPainter painter;
1563 
1564  this->fill_citizens_pixmap(citizen_pixmap, &painter, categories,
1565  num_citizens);
1566 
1567  ui.citizens_label->set_city(pcity);
1568  ui.citizens_label->setPixmap(*citizen_pixmap);
1569  ui.citizens_label->updateGeometry();
1570 
1571  lab_table[FEELING_FINAL]->setPixmap(*citizen_pixmap);
1572  lab_table[FEELING_FINAL]->updateGeometry();
1574 
1575  for (int i = 0; i < FEELING_LAST - 1; i++) {
1576  lab_table[i]->set_city(pcity);
1577  num_citizens = get_city_citizen_types(
1578  pcity, static_cast<citizen_feeling>(i), categories);
1579  this->fill_citizens_pixmap(citizen_pixmap, &painter, categories,
1580  num_citizens);
1581 
1582  lab_table[i]->setPixmap(*citizen_pixmap);
1583  lab_table[i]->updateGeometry();
1584  }
1585 
1589  lab_table[FEELING_NATIONALITY]->setToolTip(
1592 }
1593 
1598 {
1599  setUpdatesEnabled(false);
1600  ui.production_combo_p->blockSignals(true);
1601 
1602  if (pcity) {
1603  update_title();
1606  update_citizens();
1607  update_building();
1609  update_units();
1611  update_cma_tab();
1612  update_disabled();
1613  ui.icon->set_city(pcity->id);
1614  ui.upkeep->set_city(pcity->id);
1615  } else {
1617  ui.icon->set_city(-1);
1618  ui.upkeep->set_city(-1);
1619  }
1620 
1621  ui.production_combo_p->blockSignals(false);
1622  setUpdatesEnabled(true);
1623 
1624  auto scale = queen()->mapview_wdg->scale();
1625  ui.middleSpacer->changeSize(scale * get_citydlg_canvas_width(),
1626  scale * get_citydlg_canvas_height(),
1627  QSizePolicy::Expanding,
1628  QSizePolicy::Expanding);
1629 
1630  updateGeometry();
1631  update();
1632 }
1633 
1635 {
1636  cm_parameter params;
1637  if (!cma_is_city_under_agent(pcity, &params)) {
1638  if (ui.cma_table->currentRow() == -1 || cmafec_preset_num() == 0) {
1639  return;
1640  }
1641  params = *cmafec_preset_get_parameter(ui.cma_table->currentRow());
1642  }
1643 
1644  ui.governor->set_parameters(params);
1645 }
1646 
1651 {
1652  QFont f = QApplication::font();
1653  QFontMetrics fm(f);
1654  QString str;
1655  QStringList info_list;
1656  QTableWidgetItem *item;
1657  char buf[8];
1658  citizens nationality_i;
1659  int h;
1660  int i = 0;
1661 
1662  h = fm.height() + 6;
1663  ui.nationality_table->clear();
1664  ui.nationality_table->setRowCount(0);
1665  info_list.clear();
1666  info_list << _("#") << _("Flag") << _("Nation");
1667  ui.nationality_table->setHorizontalHeaderLabels(info_list);
1668 
1669  citizens_iterate(pcity, pslot, nationality)
1670  {
1671  ui.nationality_table->insertRow(i);
1672 
1673  for (int j = 0; j < ui.nationality_table->columnCount(); j++) {
1674  item = new QTableWidgetItem;
1675 
1676  switch (j) {
1677  case 0:
1678  nationality_i = citizens_nation_get(pcity, pslot);
1679 
1680  if (nationality_i == 0) {
1681  str = QStringLiteral("-");
1682  } else {
1683  fc_snprintf(buf, sizeof(buf), "%d", nationality_i);
1684  str = QString(buf);
1685  }
1686 
1687  item->setText(str);
1688  break;
1689 
1690  case 1: {
1691  auto sprite = get_nation_flag_sprite(
1693 
1694  if (sprite != nullptr) {
1695  item->setData(Qt::DecorationRole, sprite->scaledToHeight(h));
1696  } else {
1697  item->setText(QStringLiteral("FLAG MISSING"));
1698  }
1699  } break;
1700 
1701  case 2:
1702  item->setText(
1704  break;
1705 
1706  default:
1707  break;
1708  }
1709  ui.nationality_table->setItem(i, j, item);
1710  }
1711  i++;
1712  }
1714  ui.nationality_table->horizontalHeader()->setStretchLastSection(false);
1715  ui.nationality_table->resizeColumnsToContents();
1716  ui.nationality_table->resizeRowsToContents();
1717  ui.nationality_table->horizontalHeader()->setStretchLastSection(true);
1718 }
1719 
1724 {
1725  ui.info_wdg->update_labels(pcity);
1726  ui.info_icon_label->setCity(pcity);
1727  ui.info_icon_label->updateText();
1728 }
1729 
1733 void city_dialog::setup_ui(struct city *qcity)
1734 {
1735  if (pcity != qcity) {
1736  if (pcity) {
1738  }
1739  if (qcity) {
1740  refresh_city_mapcanvas(qcity, qcity->tile, true);
1741  }
1742  }
1743 
1744  pcity = qcity;
1745  ui.production_combo_p->blockSignals(true);
1746  refresh();
1747  ui.production_combo_p->blockSignals(false);
1748 }
1749 
1753 void city_dialog::dbl_click_p(QTableWidgetItem *item)
1754 {
1755  Q_UNUSED(item)
1756  struct worklist queue;
1757  city_get_queue(pcity, &queue);
1758 
1759  if (selected_row_p < 0 || selected_row_p > worklist_length(&queue)) {
1760  return;
1761  }
1762 
1764  city_set_queue(pcity, &queue);
1765 }
1766 
1771 {
1772  struct unit_list *units;
1773  char buf[256];
1774  int n;
1775 
1776  if (nullptr != client.conn.playing
1777  && city_owner(pcity) != client.conn.playing) {
1778  units = pcity->client.info_units_supported;
1779  } else {
1780  units = pcity->units_supported;
1781  }
1782 
1783  n = unit_list_size(units);
1784  fc_snprintf(buf, sizeof(buf), _("Supported units: %d"), n);
1785  ui.supp_units->setText(QString(buf));
1786 
1787  if (nullptr != client.conn.playing
1788  && city_owner(pcity) != client.conn.playing) {
1789  units = pcity->client.info_units_present;
1790  } else {
1791  units = pcity->tile->units;
1792  }
1793 
1794  // set direction of the expand/collapse arrow
1795  if (present_units_exp) {
1796  ui.present_units_exp_col_but->setArrowType(Qt::DownArrow);
1797  } else {
1798  ui.present_units_exp_col_but->setArrowType(Qt::UpArrow);
1799  }
1800 
1801  n = unit_list_size(units);
1802  ui.present_units_list->setLayoutDirection(Qt::LeftToRight);
1803  ui.present_units_list->set_units(units);
1804  ui.present_units_list->setVisible(n >= 0);
1805  fc_snprintf(buf, sizeof(buf), _("Present units: %d"), n);
1806  ui.present_units_label->setText(QString(buf));
1807 }
1808 
1813 {
1814  if (present_units_exp) {
1815  ui.present_units_group_box->setSizePolicy(QSizePolicy::MinimumExpanding,
1816  QSizePolicy::Minimum);
1817  ui.present_units_exp_col_but->setArrowType(Qt::UpArrow);
1818  ui.present_units_exp_col_but->setToolTip(
1819  _("Click to expand the present units list"));
1820  present_units_exp = false;
1821  } else {
1822  ui.present_units_group_box->setSizePolicy(QSizePolicy::MinimumExpanding,
1823  QSizePolicy::Expanding);
1824  ui.present_units_exp_col_but->setArrowType(Qt::DownArrow);
1825  ui.present_units_exp_col_but->setToolTip(
1826  _("Click to collapse the present units list"));
1827  present_units_exp = true;
1828  }
1829 }
1830 
1834 void city_dialog::item_selected(const QItemSelection &sl,
1835  const QItemSelection &ds)
1836 {
1837  Q_UNUSED(ds)
1838  QModelIndex index;
1839  QModelIndexList indexes = sl.indexes();
1840 
1841  if (indexes.isEmpty()) {
1842  return;
1843  }
1844 
1845  index = indexes.at(0);
1846  selected_row_p = index.row();
1848 }
1849 
1850 void city_dialog::get_city(bool next)
1851 {
1852  int size, i, j;
1853  struct city *other_pcity = nullptr;
1854 
1855  if (nullptr == client.conn.playing) {
1856  return;
1857  }
1858 
1859  size = city_list_size(client.conn.playing->cities);
1860 
1861  if (size == 1) {
1862  return;
1863  }
1864 
1865  for (i = 0; i < size; i++) {
1866  if (pcity == city_list_get(client.conn.playing->cities, i)) {
1867  break;
1868  }
1869  }
1870 
1871  for (j = 1; j < size; j++) {
1872  int k = next ? j : -j;
1873  other_pcity =
1874  city_list_get(client.conn.playing->cities, (i + k + size) % size);
1875  }
1876  queen()->mapview_wdg->center_on_tile(other_pcity->tile);
1877  setup_ui(other_pcity);
1878 }
1879 
1884 
1889 
1894 {
1895  char buf[32];
1896  QString str;
1898 
1899  get_city_dialog_production(pcity, buf, sizeof(buf));
1900  ui.production_combo_p->setRange(0, cost);
1901  ui.production_combo_p->set_pixmap(&pcity->production);
1902  if (pcity->shield_stock >= cost) {
1903  ui.production_combo_p->setValue(cost);
1904  } else {
1905  ui.production_combo_p->setValue(pcity->shield_stock);
1906  }
1907  ui.production_combo_p->setAlignment(Qt::AlignCenter);
1908  str = QString(buf);
1909  str = str.simplified();
1910 
1911  ui.production_combo_p->setFormat(
1912  QStringLiteral("(%p%) %2\n%1")
1914 
1915  ui.production_combo_p->updateGeometry();
1916 }
1917 
1922 {
1923  char buf[1024], buf2[1024];
1925  int value = pcity->client.buy_cost;
1926  hud_message_box *ask;
1927  int city_id = pcity->id;
1928 
1929  if (!can_client_issue_orders()) {
1930  return;
1931  }
1932 
1933  ask = new hud_message_box(queen()->city_overlay);
1934  fc_snprintf(buf2, ARRAY_SIZE(buf2),
1935  PL_("Treasury contains %d gold.", "Treasury contains %d gold.",
1936  client_player()->economic.gold),
1937  client_player()->economic.gold);
1938  fc_snprintf(buf, ARRAY_SIZE(buf),
1939  PL_("Buy %s for %d gold?", "Buy %s for %d gold?", value), name,
1940  value);
1941  ask->set_text_title(buf, buf2);
1942  ask->setStandardButtons(QMessageBox::Cancel | QMessageBox::Yes);
1943  ask->setDefaultButton(QMessageBox::Cancel);
1944  ask->button(QMessageBox::Yes)->setText(_("Yes Buy"));
1945  ask->setAttribute(Qt::WA_DeleteOnClose);
1946  connect(ask, &hud_message_box::accepted, this, [=]() {
1947  struct city *pcity = game_city_by_number(city_id);
1948 
1949  if (!pcity) {
1950  return;
1951  }
1952 
1954  });
1955  ask->show();
1956 }
1957 
1962 {
1963  QFont f = QApplication::font();
1964  QFontMetrics fm(f);
1965  QString str, tooltip;
1966  QTableWidgetItem *qitem;
1967  const QPixmap *sprite = nullptr;
1968  int h, cost, item, targets_used, col, upkeep;
1969  struct item items[MAX_NUM_PRODUCTION_TARGETS];
1970  struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
1971  struct worklist queue;
1972 
1973  cost = 0;
1974  upkeep = 0;
1975 
1976  h = fm.height() + 6;
1977  targets_used = collect_already_built_targets(targets, pcity);
1978  name_and_sort_items(targets, targets_used, items, false, pcity);
1979 
1980  for (item = 0; item < targets_used; item++) {
1981  struct universal target = items[item].item;
1982  fc_assert_action(VUT_IMPROVEMENT == target.kind, continue);
1983  upkeep += city_improvement_upkeep(pcity, target.value.building);
1984  }
1985 
1986  city_get_queue(pcity, &queue);
1987  ui.p_table_p->setRowCount(worklist_length(&queue));
1988 
1989  for (int i = 0; i < worklist_length(&queue); i++) {
1990  struct universal target = queue.entries[i];
1991 
1992  tooltip = QLatin1String("");
1993 
1994  if (VUT_UTYPE == target.kind) {
1995  str = utype_values_translation(target.value.utype);
1996  cost = utype_build_shield_cost(pcity, target.value.utype);
1997  tooltip = get_tooltip_unit(target.value.utype, true).trimmed();
1998  sprite = get_unittype_sprite(get_tileset(), target.value.utype,
1999  direction8_invalid());
2000  } else if (target.kind == VUT_IMPROVEMENT) {
2002  sprite = get_building_sprite(tileset, target.value.building);
2003  tooltip = get_tooltip_improvement(target.value.building, pcity, true)
2004  .trimmed();
2005 
2006  if (improvement_has_flag(target.value.building, IF_GOLD)) {
2007  cost = -1;
2008  } else {
2009  cost = impr_build_shield_cost(pcity, target.value.building);
2010  }
2011  }
2012 
2013  for (col = 0; col < 3; col++) {
2014  qitem = new QTableWidgetItem();
2015  qitem->setToolTip(tooltip);
2016 
2017  switch (col) {
2018  case 0:
2019  if (sprite) {
2020  qitem->setData(Qt::DecorationRole, sprite->scaledToHeight(h));
2021  }
2022  break;
2023 
2024  case 1:
2025  if (str.contains('[') && str.contains(']')) {
2026  int ii, ij;
2027 
2028  ii = str.lastIndexOf('[');
2029  ij = str.lastIndexOf(']');
2030  if (ij > ii) {
2031  str = str.remove(ii, ij - ii + 1);
2032  }
2033  }
2034  qitem->setText(str);
2035  break;
2036 
2037  case 2:
2038  qitem->setTextAlignment(Qt::AlignRight);
2039  qitem->setText(QString::number(cost));
2040  break;
2041  }
2042  ui.p_table_p->setItem(i, col, qitem);
2043  }
2044  }
2045 
2046  ui.p_table_p->horizontalHeader()->setStretchLastSection(false);
2047  ui.p_table_p->resizeColumnsToContents();
2048  ui.p_table_p->resizeRowsToContents();
2049  ui.p_table_p->horizontalHeader()->setStretchLastSection(true);
2050 
2051  ui.upkeep->refresh();
2052 
2053  ui.curr_impr->setText(QString(_("Improvements: upkeep %1")).arg(upkeep));
2054 }
2055 
2061 {
2062  production_widget *pw;
2063  int when = 1;
2064  pw = new production_widget(this, pcity, future_targets, when,
2066  show_buildings);
2067  pw->show();
2068 }
2069 
2075 {
2076  production_widget *pw;
2077  int when = 4;
2078  pw = new production_widget(this, pcity, future_targets, when,
2080  show_buildings);
2081  pw->show();
2082 }
2083 
2088 {
2089  struct worklist empty;
2090 
2091  if (!can_client_issue_orders()) {
2092  return;
2093  }
2094 
2095  worklist_init(&empty);
2096  city_set_worklist(pcity, &empty);
2097 }
2098 
2103 {
2104  QModelIndex index;
2105  struct worklist queue;
2106  struct universal *target;
2107 
2108  if (selected_row_p < 1 || selected_row_p >= ui.p_table_p->rowCount()) {
2109  return;
2110  }
2111 
2112  target = new universal;
2113  city_get_queue(pcity, &queue);
2114  worklist_peek_ith(&queue, target, selected_row_p);
2116  worklist_insert(&queue, target, selected_row_p - 1);
2117  city_set_queue(pcity, &queue);
2118  index = ui.p_table_p->model()->index(selected_row_p - 1, 0);
2119  ui.p_table_p->setCurrentIndex(index);
2120  delete target;
2121 }
2122 
2127 {
2128  QTableWidgetItem *item;
2129 
2130  if (selected_row_p < 0 || selected_row_p >= ui.p_table_p->rowCount()) {
2131  return;
2132  }
2133 
2134  item = ui.p_table_p->item(selected_row_p, 0);
2135  dbl_click_p(item);
2137 }
2138 
2143 {
2144  QModelIndex index;
2145  struct worklist queue;
2146  struct universal *target;
2147 
2148  if (selected_row_p < 0 || selected_row_p >= ui.p_table_p->rowCount() - 1) {
2149  return;
2150  }
2151 
2152  target = new universal;
2153  city_get_queue(pcity, &queue);
2154  worklist_peek_ith(&queue, target, selected_row_p);
2156  worklist_insert(&queue, target, selected_row_p + 1);
2157  city_set_queue(pcity, &queue);
2158  index = ui.p_table_p->model()->index(selected_row_p + 1, 0);
2159  ui.p_table_p->setCurrentIndex(index);
2160  delete target;
2161 }
2162 
2167 {
2168  hud_input_box *ask = new hud_input_box(king()->central_wdg);
2169  int city_id = pcity->id;
2170 
2171  ask->set_text_title_definput(_("What should we name new worklist?"),
2172  _("Save current worklist"),
2173  _("New worklist"));
2174  ask->setAttribute(Qt::WA_DeleteOnClose);
2175  connect(ask, &hud_message_box::accepted, [=]() {
2176  struct global_worklist *gw;
2177  struct worklist queue;
2178  QByteArray ask_bytes;
2179  QString text;
2180  struct city *pcity = game_city_by_number(city_id);
2181 
2182  ask_bytes = ask->input_edit.text().toLocal8Bit();
2183  text = ask_bytes.data();
2184  if (!text.isEmpty()) {
2185  ask_bytes = text.toLocal8Bit();
2186  gw = global_worklist_new(ask_bytes.data());
2187  city_get_queue(pcity, &queue);
2188  global_worklist_set(gw, &queue);
2189  }
2190  });
2191  ask->show();
2192 }
2193 
2198 {
2199  cm_parameter current;
2200  if (cma_is_city_under_agent(pcity, &current) && !(current == params)) {
2201  cma_changed();
2202  update_cma_tab();
2203  }
2204 }
2205 
2210 {
2211  QString buf;
2212 
2213  // Defeat keyboard shortcut mnemonics
2214  ui.lcity_name->setText(
2215  QString(city_name_get(pcity))
2216  .replace(QLatin1String("&"), QLatin1String("&&")));
2217 
2218  if (city_unhappy(pcity)) {
2219  // TRANS: city dialog title
2220  buf = QString(_("%1 - %2 citizens - DISORDER"))
2221  .arg(city_name_get(pcity),
2223  } else if (city_celebrating(pcity)) {
2224  // TRANS: city dialog title
2225  buf = QString(_("%1 - %2 citizens - celebrating"))
2226  .arg(city_name_get(pcity),
2228  } else if (city_happy(pcity)) {
2229  // TRANS: city dialog title
2230  buf = QString(_("%1 - %2 citizens - happy"))
2231  .arg(city_name_get(pcity),
2233  } else {
2234  // TRANS: city dialog title
2235  buf = QString(_("%1 - %2 citizens"))
2236  .arg(city_name_get(pcity),
2238  }
2239 
2240  setWindowTitle(buf);
2241 }
2242 
2247 void real_city_dialog_popup(struct city *pcity)
2248 {
2249  auto *widget = queen()->city_overlay;
2250  if (!queen()->city_overlay->isVisible()) {
2251  top_bar_show_map();
2253  }
2254  queen()->mapview_wdg->center_on_tile(pcity->tile);
2255 
2256  widget->setup_ui(pcity);
2257  widget->show();
2258  widget->resize(queen()->mapview_wdg->size());
2259 }
2260 
2265 {
2266  if (queen()) {
2267  queen()->city_overlay->hide();
2268  }
2269 }
2270 
2274 void real_city_dialog_refresh(struct city *pcity)
2275 {
2276  if (city_dialog_is_open(pcity)) {
2277  queen()->city_overlay->refresh();
2278  }
2279 }
2280 
2285 {
2286  QList<QLabel *> l;
2287 
2288  l = queen()->city_overlay->findChildren<QLabel *>();
2289 
2291 
2292  for (auto i : qAsConst(l)) {
2293  if (i->property(fonts::notify_label).isValid()) {
2294  i->setFont(f);
2295  }
2296  }
2297 }
2298 
2304 void refresh_unit_city_dialogs(struct unit *punit)
2305 {
2306  struct city *pcity_sup, *pcity_pre;
2307 
2308  pcity_sup = game_city_by_number(punit->homecity);
2309  pcity_pre = tile_city(punit->tile);
2310 
2311  real_city_dialog_refresh(pcity_sup);
2312  real_city_dialog_refresh(pcity_pre);
2313 }
2314 
2316 {
2317  // some checks not to iterate cities
2318  if (!queen()->city_overlay->isVisible()) {
2319  return nullptr;
2320  }
2322  return nullptr;
2323  }
2324 
2326  {
2327  if (city_dialog_is_open(pcity)) {
2328  return pcity;
2329  }
2330  }
2332  return nullptr;
2333 }
2334 
2338 bool city_dialog_is_open(struct city *pcity)
2339 {
2340  return queen()->city_overlay->pcity == pcity
2341  && queen()->city_overlay->isVisible();
2342 }
2343 
2348  QObject *parent,
2349  struct city *city)
2350  : QItemDelegate(parent), pd(sh)
2351 {
2352  item_height = sh.y();
2353  pcity = city;
2354 }
2355 
2359 void city_production_delegate::paint(QPainter *painter,
2360  const QStyleOptionViewItem &option,
2361  const QModelIndex &index) const
2362 {
2363  struct universal *target;
2364  QString name;
2365  QVariant qvar;
2366  QPixmap pix_scaled;
2367  QRect rect1;
2368  QRect rect2;
2369  const QPixmap *sprite;
2370  QPixmap *free_sprite = nullptr;
2371  bool useless = false;
2372  bool is_coinage = false;
2373  bool is_neutral = false;
2374  bool is_sea = false;
2375  bool is_flying = false;
2376  bool is_unit = true;
2377  QPixmap pix_dec(option.rect.width(), option.rect.height());
2378  QStyleOptionViewItem opt;
2379  QIcon icon = qApp->style()->standardIcon(QStyle::SP_DialogCancelButton);
2380  struct unit_class *pclass;
2381 
2382  if (!option.rect.isValid()) {
2383  return;
2384  }
2385 
2386  qvar = index.data();
2387 
2388  if (!qvar.isValid()) {
2389  return;
2390  }
2391 
2392  target = reinterpret_cast<universal *>(qvar.value<void *>());
2393 
2394  if (target == nullptr) {
2395  free_sprite = new QPixmap;
2396  *free_sprite = icon.pixmap(100, 100);
2397  sprite = free_sprite;
2398  name = _("Cancel");
2399  is_unit = false;
2400  } else if (VUT_UTYPE == target->kind) {
2402  is_neutral = utype_has_flag(target->value.utype, UTYF_CIVILIAN);
2403  pclass = utype_class(target->value.utype);
2404  if (!uclass_has_flag(pclass, UCF_TERRAIN_DEFENSE)
2405  && !utype_can_do_action_result(target->value.utype, ACTRES_FORTIFY)
2406  && !uclass_has_flag(pclass, UCF_ZOC)) {
2407  is_sea = true;
2408  }
2409 
2410  if ((utype_fuel(target->value.utype)
2411  && !uclass_has_flag(pclass, UCF_TERRAIN_DEFENSE)
2412  && !utype_can_do_action_result(target->value.utype, ACTRES_PILLAGE)
2413  && !utype_can_do_action_result(target->value.utype, ACTRES_FORTIFY)
2414  && !uclass_has_flag(pclass, UCF_ZOC))
2415  /* FIXME: Assumed to be flying since only missiles can do suicide
2416  * attacks in classic-like rulesets. This isn't true for all
2417  * rulesets. Not a high priority to fix since all is_flying and
2418  * is_sea is used for is to set a color. */
2419  || utype_is_consumed_by_action_result(ACTRES_ATTACK,
2420  target->value.utype)) {
2421  if (is_sea) {
2422  is_sea = false;
2423  }
2424  is_flying = true;
2425  }
2426 
2427  sprite = get_unittype_sprite(get_tileset(), target->value.utype,
2428  direction8_invalid());
2429  } else {
2430  is_unit = false;
2432  sprite = get_building_sprite(tileset, target->value.building);
2433  useless = is_improvement_redundant(pcity, target->value.building);
2434  is_coinage = improvement_has_flag(target->value.building, IF_GOLD);
2435  }
2436 
2437  if (sprite != nullptr) {
2438  pix_scaled =
2439  sprite->scaledToHeight(item_height - 2, Qt::SmoothTransformation);
2440 
2441  if (useless) {
2442  pixmap_put_x(&pix_scaled);
2443  }
2444  }
2445 
2446  opt = QItemDelegate::setOptions(index, option);
2447  painter->save();
2448  opt.displayAlignment = Qt::AlignLeft;
2449  opt.textElideMode = Qt::ElideMiddle;
2450  QItemDelegate::drawBackground(painter, opt, index);
2451  rect1 = option.rect;
2452  rect1.setWidth(pix_scaled.width() + 4);
2453  rect2 = option.rect;
2454  rect2.setLeft(option.rect.left() + rect1.width());
2455  rect2.setTop(rect2.top()
2456  + (rect2.height() - painter->fontMetrics().height()) / 2);
2457  QItemDelegate::drawDisplay(painter, opt, rect2, name);
2458 
2459  if (is_unit) {
2460  if (is_sea) {
2461  pix_dec.fill(QColor(0, 0, 255, 80));
2462  } else if (is_flying) {
2463  pix_dec.fill(QColor(220, 0, 0, 80));
2464  } else if (is_neutral) {
2465  pix_dec.fill(QColor(0, 120, 0, 40));
2466  } else {
2467  pix_dec.fill(QColor(0, 0, 150, 40));
2468  }
2469 
2470  QItemDelegate::drawDecoration(painter, option, option.rect, pix_dec);
2471  }
2472 
2473  if (is_coinage) {
2474  pix_dec.fill(QColor(255, 255, 0, 70));
2475  QItemDelegate::drawDecoration(painter, option, option.rect, pix_dec);
2476  }
2477 
2478  if (!pix_scaled.isNull()) {
2479  QItemDelegate::drawDecoration(painter, opt, rect1, pix_scaled);
2480  }
2481 
2482  drawFocus(painter, opt, option.rect);
2483 
2484  painter->restore();
2485 }
2486 
2491  const QStyleOptionViewItem &option,
2492  const QRect &rect) const
2493 {
2494  QPixmap pix(option.rect.width(), option.rect.height());
2495 
2496  if ((option.state & QStyle::State_MouseOver) == 0 || !rect.isValid()) {
2497  return;
2498  }
2499 
2500  pix.fill(QColor(50, 50, 50, 50));
2501  QItemDelegate::drawDecoration(painter, option, option.rect, pix);
2502 }
2503 
2507 QSize city_production_delegate::sizeHint(const QStyleOptionViewItem &option,
2508  const QModelIndex &index) const
2509 {
2510  Q_UNUSED(option)
2511  Q_UNUSED(index)
2512  QSize s;
2513 
2514  s.setWidth(pd.x());
2515  s.setHeight(pd.y());
2516  return s;
2517 }
2518 
2522 production_item::production_item(struct universal *ptarget, QObject *parent)
2523  : QObject()
2524 {
2525  setParent(parent);
2526  target = ptarget;
2527 }
2528 
2533 {
2534  // allocated as renegade in model
2535  delete target;
2536 }
2537 
2541 QVariant production_item::data() const
2542 {
2543  return QVariant::fromValue((void *) target);
2544 }
2545 
2550  bool su, bool sw, bool sb,
2551  QObject *parent)
2552  : QAbstractListModel(parent)
2553 {
2554  show_units = su;
2555  show_wonders = sw;
2556  show_buildings = sb;
2557  mcity = pcity;
2558  future_t = f;
2559  populate();
2560 }
2561 
2566 {
2567  qDeleteAll(city_target_list);
2568  city_target_list.clear();
2569 }
2570 
2574 QVariant city_production_model::data(const QModelIndex &index,
2575  int role) const
2576 {
2577  if (!index.isValid()) {
2578  return QVariant();
2579  }
2580 
2581  if (index.row() >= 0 && index.row() < rowCount() && index.column() >= 0
2582  && index.column() < columnCount()
2583  && (index.column() + index.row() * 3 < city_target_list.count())) {
2584  int r, c, t, new_index;
2585  r = index.row();
2586  c = index.column();
2587  t = r * 3 + c;
2588  new_index = t / 3 + rowCount() * c;
2589  // Exception, shift whole column
2590  if ((c == 2) && city_target_list.count() % 3 == 1) {
2591  new_index = t / 3 + rowCount() * c - 1;
2592  }
2593  if (role == Qt::ToolTipRole) {
2594  return get_tooltip(city_target_list[new_index]->data());
2595  }
2596 
2597  return city_target_list[new_index]->data();
2598  }
2599 
2600  return QVariant();
2601 }
2602 
2607 {
2608  production_item *pi;
2609  struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
2610  struct item items[MAX_NUM_PRODUCTION_TARGETS];
2611  struct universal *renegade, *renegate;
2612  int item, targets_used;
2613  QString str;
2615  QFontMetrics fm(f);
2616 
2617  sh.setY(fm.height() * 2);
2618  sh.setX(0);
2619 
2620  qDeleteAll(city_target_list);
2621  city_target_list.clear();
2622 
2623  targets_used =
2625  name_and_sort_items(targets, targets_used, items, false, mcity);
2626 
2627  for (item = 0; item < targets_used; item++) {
2628  if (future_t || can_city_build_now(mcity, &items[item].item)) {
2629  renegade = new universal(items[item].item);
2630 
2631  // renagade deleted in production_item destructor
2632  if (VUT_UTYPE == renegade->kind) {
2633  str = utype_name_translation(renegade->value.utype);
2634  sh.setX(qMax(sh.x(), fm.horizontalAdvance(str)));
2635 
2636  if (show_units) {
2637  pi = new production_item(renegade, this);
2638  city_target_list << pi;
2639  }
2640  } else {
2641  str = improvement_name_translation(renegade->value.building);
2642  sh.setX(qMax(sh.x(), fm.horizontalAdvance(str)));
2643 
2644  if ((is_wonder(renegade->value.building) && show_wonders)
2645  || (is_improvement(renegade->value.building) && show_buildings)
2646  || (improvement_has_flag(renegade->value.building, IF_GOLD))
2647  || (is_special_improvement(renegade->value.building)
2648  && show_buildings)) {
2649  pi = new production_item(renegade, this);
2650  city_target_list << pi;
2651  }
2652  }
2653  }
2654  }
2655 
2656  renegate = nullptr;
2657  pi = new production_item(renegate, this);
2658  city_target_list << pi;
2659  sh.setX(2 * sh.y() + sh.x());
2660  sh.setX(qMin(sh.x(), 250));
2661 }
2662 
2671 production_widget::production_widget(QWidget *parent, struct city *pcity,
2672  bool future, int when, int curr,
2673  bool show_units, bool buy,
2674  bool show_wonders, bool show_buildings)
2675  : QTableView()
2676 {
2677  Q_UNUSED(parent)
2678  QPoint pos, sh;
2679  auto temp = QGuiApplication::screens();
2680  int desk_width = temp[0]->availableGeometry().width();
2681  int desk_height = temp[0]->availableGeometry().height();
2682  fc_tt = new fc_tooltip(this);
2683  setAttribute(Qt::WA_DeleteOnClose);
2684  setWindowFlags(Qt::Popup);
2685  verticalHeader()->setVisible(false);
2686  horizontalHeader()->setVisible(false);
2687  setProperty("showGrid", false);
2688  curr_selection = curr;
2689  pw_city = pcity;
2690  buy_it = buy;
2691  when_change = when;
2692  list_model = new city_production_model(pw_city, future, show_units,
2693  show_wonders, show_buildings, this);
2694  sh = list_model->sh;
2695  c_p_d = new city_production_delegate(sh, this, pw_city);
2696  setItemDelegate(c_p_d);
2697  setModel(list_model);
2698  viewport()->installEventFilter(fc_tt);
2699  installEventFilter(this);
2700  connect(selectionModel(), &QItemSelectionModel::selectionChanged, this,
2702  resizeRowsToContents();
2703  resizeColumnsToContents();
2704  setFixedWidth(3 * sh.x() + 6);
2705  setFixedHeight(list_model->rowCount() * sh.y() + 6);
2706 
2707  if (width() > desk_width) {
2708  setFixedWidth(desk_width);
2709  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
2710  } else {
2711  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
2712  }
2713 
2714  if (height() > desk_height) {
2715  setFixedHeight(desk_height);
2716  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
2717  } else {
2718  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
2719  }
2720 
2721  pos = QCursor::pos();
2722 
2723  if (pos.x() + width() > desk_width) {
2724  pos.setX(desk_width - width());
2725  } else if (pos.x() - width() < 0) {
2726  pos.setX(0);
2727  }
2728 
2729  if (pos.y() + height() > desk_height) {
2730  pos.setY(desk_height - height());
2731  } else if (pos.y() - height() < 0) {
2732  pos.setY(0);
2733  }
2734 
2735  move(pos);
2736  setMouseTracking(true);
2737  setFocus();
2738 }
2739 
2744 {
2745  if (event->button() == Qt::RightButton) {
2746  close();
2747  return;
2748  }
2749 
2750  QAbstractItemView::mousePressEvent(event);
2751 }
2752 
2756 bool production_widget::eventFilter(QObject *obj, QEvent *ev)
2757 {
2758  QRect pw_rect;
2759  QPoint br;
2760 
2761  if (obj != this) {
2762  return false;
2763  }
2764 
2765  if (ev->type() == QEvent::MouseButtonPress) {
2766  pw_rect.setTopLeft(pos());
2767  br.setX(pos().x() + width());
2768  br.setY(pos().y() + height());
2769  pw_rect.setBottomRight(br);
2770 
2771  if (!pw_rect.contains(QCursor::pos())) {
2772  close();
2773  return true;
2774  }
2775  } else if (ev->type() == QEvent::KeyRelease) {
2776  auto key_event = dynamic_cast<QKeyEvent *>(ev);
2777  if (key_event && key_event->key() == Qt::Key_Escape) {
2778  close();
2779  return true;
2780  }
2781  }
2782 
2783  return false;
2784 }
2785 
2789 void production_widget::prod_selected(const QItemSelection &sl,
2790  const QItemSelection &ds)
2791 {
2792  Q_UNUSED(ds)
2793  Q_UNUSED(sl)
2794  QModelIndexList indexes = selectionModel()->selectedIndexes();
2795  QModelIndex index;
2796  QVariant qvar;
2797  struct worklist queue;
2798  struct universal *target;
2799 
2800  if (indexes.isEmpty() || client_is_observer()) {
2801  return;
2802  }
2803  index = indexes.at(0);
2804  qvar = index.data(Qt::UserRole);
2805  if (!qvar.isValid()) {
2806  return;
2807  }
2808  target = reinterpret_cast<universal *>(qvar.value<void *>());
2809  if (target != nullptr) {
2810  city_get_queue(pw_city, &queue);
2811  switch (when_change) {
2812  case 0: // Change current target
2814  if (city_can_buy(pw_city) && buy_it) {
2816  }
2817  break;
2818 
2819  case 1: /* Change current (selected on list)*/
2820  if (curr_selection < 0 || curr_selection > worklist_length(&queue)) {
2822  } else {
2824  worklist_insert(&queue, target, curr_selection);
2825  city_set_queue(pw_city, &queue);
2826  }
2827  break;
2828 
2829  case 2: // Insert before
2830  if (curr_selection < 0 || curr_selection > worklist_length(&queue)) {
2831  curr_selection = 0;
2832  }
2833  curr_selection--;
2834  curr_selection = qMax(0, curr_selection);
2835  worklist_insert(&queue, target, curr_selection);
2836  city_set_queue(pw_city, &queue);
2837  break;
2838 
2839  case 3: // Insert after
2840  if (curr_selection < 0 || curr_selection > worklist_length(&queue)) {
2841  city_queue_insert(pw_city, -1, target);
2842  break;
2843  }
2844  curr_selection++;
2845  worklist_insert(&queue, target, curr_selection);
2846  city_set_queue(pw_city, &queue);
2847  break;
2848 
2849  case 4: // Add last
2850  city_queue_insert(pw_city, -1, target);
2851  break;
2852 
2853  default:
2854  break;
2855  }
2856  }
2857  close();
2858  destroy();
2859 }
2860 
2865 {
2866  delete c_p_d;
2867  delete list_model;
2868  viewport()->removeEventFilter(fc_tt);
2869  removeEventFilter(this);
2870 }
#define BV_CLR_ALL(bv)
Definition: bitvector.h:62
#define BV_SET(bv, bit)
Definition: bitvector.h:44
#define BV_CLR(bv, bit)
Definition: bitvector.h:49
QRect zealous_crop_rect(QImage &p)
Return rectangle containing pure image (crops transparency)
Definition: canvas.cpp:81
void pixmap_copy(QPixmap *dest, const QPixmap *src, int src_x, int src_y, int dest_x, int dest_y, int width, int height)
/ \ *********** / _ \ | / \ | Copyright (c) 1996-2023 Freeciv21 and || || _______ Freeciv contributor...
Definition: canvas.cpp:38
citizens citizens_nation_get(const struct city *pcity, const struct player_slot *pslot)
Get the number of citizens with the given nationality.
Definition: citizens.cpp:65
#define citizens_iterate_end
Definition: citizens.h:44
#define citizens_iterate(_pcity, _pslot, _nationality)
Definition: citizens.h:37
int city_production_build_shield_cost(const struct city *pcity)
Return the number of shields it takes to build current city production.
Definition: city.cpp:701
int city_granary_size(int city_size)
Generalized formula used to calculate granary size.
Definition: city.cpp:2034
bool can_city_build_now(const struct city *pcity, const struct universal *target)
Returns whether city can immediately build given target, unit or improvement.
Definition: city.cpp:953
struct player * city_owner(const struct city *pcity)
Return the owner of the city.
Definition: city.cpp:1083
int city_improvement_upkeep(const struct city *pcity, const struct impr_type *b)
Return the upkeep (gold) needed each turn to upkeep the given improvement in the given city.
Definition: city.cpp:1202
bool is_city_option_set(const struct city *pcity, enum city_options option)
Returns TRUE iff the city has set the given option.
Definition: city.cpp:3304
int city_population(const struct city *pcity)
Returns how many thousand citizen live in this city.
Definition: city.cpp:1137
const char * city_name_get(const struct city *pcity)
Return the name of the city.
Definition: city.cpp:1077
bool city_unhappy(const struct city *pcity)
Return TRUE iff the city is unhappy.
Definition: city.cpp:1544
bool city_celebrating(const struct city *pcity)
cities celebrate only after consecutive happy turns
Definition: city.cpp:1564
const char * city_improvement_name_translation(const struct city *pcity, const struct impr_type *pimprove)
Return the extended name of the building.
Definition: city.cpp:635
int city_illness_calc(const struct city *pcity, int *ill_base, int *ill_size, int *ill_trade, int *ill_pollution)
Calculate city's illness in tenth of percent:
Definition: city.cpp:2746
int city_unit_unhappiness(const unit *punit, int *free_unhappy)
Query unhappiness caused by a given unit.
Definition: city.cpp:2921
bool city_happy(const struct city *pcity)
Return TRUE iff the city is happy.
Definition: city.cpp:1531
int city_turns_to_grow(const struct city *pcity)
Calculates the turns which are needed for the city to grow.
Definition: city.cpp:1897
citizens city_size_get(const struct city *pcity)
Get the city size.
Definition: city.cpp:1101
const char * city_production_name_translation(const struct city *pcity)
Return the extended name of the current production.
Definition: city.cpp:672
#define city_list_iterate(citylist, pcity)
Definition: city.h:482
citizen_category
Definition: city.h:239
#define MAX_CITY_SIZE
Definition: city.h:79
#define city_list_iterate_end
Definition: city.h:484
citizen_feeling
Definition: city.h:250
@ FEELING_EFFECT
Definition: city.h:253
@ FEELING_LUXURY
Definition: city.h:252
@ FEELING_FINAL
Definition: city.h:256
@ FEELING_LAST
Definition: city.h:257
@ FEELING_BASE
Definition: city.h:251
@ FEELING_NATIONALITY
Definition: city.h:254
@ FEELING_MARTIAL
Definition: city.h:255
void real_city_dialog_popup(struct city *pcity)
Pop up (or bring to the front) a dialog for the given city.
Definition: citydlg.cpp:2247
QString cut_helptext(const QString &text)
Remove some text from given text(help text) to show as tooltip.
Definition: optiondlg.cpp:87
struct city * is_any_city_dialog_open()
Definition: citydlg.cpp:2315
bool city_dialog_is_open(struct city *pcity)
Return whether the dialog for the given city is open.
Definition: citydlg.cpp:2338
void real_city_dialog_refresh(struct city *pcity)
Refresh (update) all data for the given city's dialog.
Definition: citydlg.cpp:2274
void city_font_update()
Updates city font.
Definition: citydlg.cpp:2284
void refresh_unit_city_dialogs(struct unit *punit)
Update city dialogs when the given unit's status changes.
Definition: citydlg.cpp:2304
QString split_text(const QString &text, bool cut)
Splits long text to 80 characters.
Definition: optiondlg.cpp:45
void popdown_city_dialog()
Closes the city overlay.
Definition: citydlg.cpp:2264
static void pixmap_put_x(QPixmap *pix)
Draws X on pixmap pointing its useless.
Definition: citydlg.cpp:468
#define CITIZENS_PER_ROW
Definition: citydlg.h:30
QString get_city_dialog_airlift_value(const struct city *pcity)
Return airlift capacity.
QString get_city_dialog_status_text(const struct city *pcity)
Return text describing the city's status: disorder/celebrating/...
int get_citydlg_canvas_height()
Return the height of the city dialog canvas.
QString get_city_dialog_culture_text(const struct city *pcity)
Return text describing the culture output.
QString get_city_dialog_output_text(const struct city *pcity, Output_type_id otype)
Return text describing the production output.
void get_city_dialog_production(struct city *pcity, char *buffer, size_t buffer_len)
Find the city dialog city production text for the given city, and place it into the buffer.
int city_set_worklist(struct city *pcity, const struct worklist *pworklist)
Set the worklist for a given city.
int get_city_citizen_types(struct city *pcity, enum citizen_feeling idx, enum citizen_category *categories)
Provide a list of all citizens in the city, in order.
int city_buy_production(struct city *pcity)
Buy the current production item in a given city.
bool city_queue_insert(struct city *pcity, int position, struct universal *item)
Insert an item into the city's queue.
bool city_queue_insert_worklist(struct city *pcity, int position, const struct worklist *worklist)
Insert the worklist into the city's queue at the given position.
QString get_city_dialog_growth_value(const struct city *pcity)
Return time until next growth.
bool city_set_queue(struct city *pcity, const struct worklist *pqueue)
Set the city current production and the worklist, like it should be.
QString get_city_dialog_size_text(const struct city *pcity)
Return text describing the city's citizens.
QString get_city_dialog_pollution_text(const struct city *pcity)
Return text describing the pollution output.
int city_change_production(struct city *pcity, struct universal *target)
Change the production of a given city.
void city_rotate_specialist(struct city *pcity, int citizen_index)
Rotate the given specialist citizen to the next type of citizen.
QString get_city_dialog_airlift_text(const struct city *pcity)
Return text describing airlift capacity.
int get_citydlg_canvas_width()
Return the width of the city dialog canvas.
void city_get_queue(struct city *pcity, struct worklist *pqueue)
Get the city current production and the worklist, like it should be.
QString get_city_dialog_illness_text(const struct city *pcity)
Return text describing the chance for a plague.
bool city_can_buy(const struct city *pcity)
Return TRUE iff the city can buy.
cityIconInfoLabel(QWidget *parent=0)
Definition: citydlg.cpp:482
struct city * pcity
Definition: citydlg.h:237
void setCity(struct city *pcity)
Definition: citydlg.cpp:492
QLabel labs[12]
Definition: citydlg.h:238
void setup_ui(struct city *qcity)
Setups whole city dialog, public function.
Definition: citydlg.cpp:1733
void worklist_up()
Move current item on worklist up.
Definition: citydlg.cpp:2102
void update_nation_table()
Updates nationality table in happiness tab.
Definition: citydlg.cpp:1650
void next_city()
Changes city_dialog to next city after pushing next city button.
Definition: citydlg.cpp:1883
bool show_wonders
Definition: citydlg.h:288
void buy()
Buy button.
Definition: citydlg.cpp:1921
void cma_double_clicked(int row, int column)
Double click on some row ( column is unused )
Definition: citydlg.cpp:1202
void update_disabled()
Updates buttons/widgets which should be enabled/disabled.
Definition: citydlg.cpp:1015
bool present_units_exp
Definition: citydlg.h:301
void update_buy_button()
Enables/disables buy buttons depending on gold.
Definition: citydlg.cpp:1488
int selected_row_p
Definition: citydlg.h:290
void update_building()
Updates building improvement/unit.
Definition: citydlg.cpp:1893
bool future_targets
Definition: citydlg.h:288
void save_worklist()
Save worklist.
Definition: citydlg.cpp:2166
void worklist_del()
Remove current item on worklist.
Definition: citydlg.cpp:2126
void clear_worklist()
Clears worklist in production page.
Definition: citydlg.cpp:2087
Ui::FormCityDlg ui
Definition: citydlg.h:286
city_label * lab_table[6]
Definition: citydlg.h:291
void showEvent(QShowEvent *event) override
Show event.
Definition: citydlg.cpp:1088
bool dont_focus
Definition: citydlg.h:300
void update_info_label()
Updates information label ( food, prod ...
Definition: citydlg.cpp:1723
bool eventFilter(QObject *obj, QEvent *event) override
Event filter for catching keybaord events.
Definition: citydlg.cpp:1105
city_dialog(QWidget *parent=0)
Constructor for city_dialog, sets layouts, policies ...
Definition: citydlg.cpp:833
void disband_state_changed(bool allow_disband)
Received signal about changed qcheckbox - allow disbanding city.
Definition: citydlg.cpp:1341
void update_citizens()
Redraws citizens for city_label (citizens_label)
Definition: citydlg.cpp:1537
void cma_context_menu(const QPoint p)
Context menu on governor tab in city worklist.
Definition: citydlg.cpp:1361
void worklist_down()
Move current item on worklist down.
Definition: citydlg.cpp:2142
void update_title()
Puts city name and people count on title.
Definition: citydlg.cpp:2209
void present_units_exp_col()
Slot to expand or collapse the present units list.
Definition: citydlg.cpp:1812
void dbl_click_p(QTableWidgetItem *item)
Double clicked item in worklist table in production tab.
Definition: citydlg.cpp:1753
void cma_remove()
Removes selected CMA.
Definition: citydlg.cpp:1315
void prev_city()
Changes city_dialog to previous city after pushing prev city button.
Definition: citydlg.cpp:1888
void city_rename()
City rename dialog input.
Definition: citydlg.cpp:1128
void refresh()
Various refresh after getting new info/reply from server.
Definition: citydlg.cpp:1597
void update_cma_tab()
Updates cma tab.
Definition: citydlg.cpp:1256
void get_city(bool next)
Definition: citydlg.cpp:1850
void display_worklist_menu(const QPoint)
Context menu on production tab in city worklist.
Definition: citydlg.cpp:1380
void show_targets()
Shows customized table widget with available items to produce Shows default targets in overview city ...
Definition: citydlg.cpp:2060
void cma_check_agent(const cm_parameter &params)
Triggers a governor update if the parameters changed.
Definition: citydlg.cpp:2197
void fill_citizens_pixmap(QPixmap *pixmap, QPainter *painter, const citizen_category *categories, int num_citizens)
Fill a pixmap with citizen sprites.
Definition: citydlg.cpp:1513
void cma_enable()
Enables cma slot, triggered by clicked button or changed cma.
Definition: citydlg.cpp:1179
bool show_buildings
Definition: citydlg.h:289
void update_sliders()
Definition: citydlg.cpp:1634
void update_improvements()
Updates list of improvements.
Definition: citydlg.cpp:1961
bool show_units
Definition: citydlg.h:288
~city_dialog() override
City dialog destructor.
Definition: citydlg.cpp:1059
struct city * pcity
Definition: citydlg.h:299
void change_production(bool next)
Changes production to next one or previous.
Definition: citydlg.cpp:972
void cma_selected(const QItemSelection &sl, const QItemSelection &ds)
CMA has been selected from list.
Definition: citydlg.cpp:1221
void hideEvent(QHideEvent *event) override
Hide event.
Definition: citydlg.cpp:1068
void item_selected(const QItemSelection &sl, const QItemSelection &ds)
Selection changed in production tab, in worklist tab.
Definition: citydlg.cpp:1834
void show_targets_worklist()
Shows customized table widget with available items to produce Shows customized targets in city produc...
Definition: citydlg.cpp:2074
void cma_changed()
Sliders moved and cma has been changed.
Definition: citydlg.cpp:1193
void update_units()
Updates layouts for supported and present units in city.
Definition: citydlg.cpp:1770
void save_cma()
Save cma dialog input.
Definition: citydlg.cpp:1158
QPixmap * citizen_pixmap
Definition: citydlg.h:287
void update_prod_buttons()
Update sensitivity of buttons in production tab.
Definition: citydlg.cpp:1030
QLabel * m_corruption
Definition: citydlg.h:274
QLabel * m_food
Definition: citydlg.h:273
QLabel * m_plague
Definition: citydlg.h:275
QLabel * m_gold
Definition: citydlg.h:273
QLabel * m_luxury
Definition: citydlg.h:273
QLabel * m_production
Definition: citydlg.h:273
QLabel * m_waste
Definition: citydlg.h:274
QLabel * m_pollution
Definition: citydlg.h:275
QLabel * m_airlift
Definition: citydlg.h:275
QLabel * m_science
Definition: citydlg.h:274
QLabel * m_granary
Definition: citydlg.h:274
QLabel * m_culture
Definition: citydlg.h:274
QLabel * m_trade
Definition: citydlg.h:273
QLabel * m_stolen
Definition: citydlg.h:275
void update_labels(struct city *ci_city)
Definition: citydlg.cpp:697
QLabel * m_size
Definition: citydlg.h:273
QLabel * m_plague_label
Definition: citydlg.h:275
QLabel * m_growth
Definition: citydlg.h:274
city_info(QWidget *parent=0)
Definition: citydlg.cpp:639
QSize sizeHint() const override
Definition: citydlg.cpp:632
city_label(QWidget *parent=0)
city_label is used only for showing citizens icons and was created only to catch mouse events
Definition: citydlg.cpp:572
void set_city(struct city *pcity)
Just sets target city for city_label.
Definition: citydlg.cpp:637
void mousePressEvent(QMouseEvent *event) override
Mouse handler for city_label.
Definition: citydlg.cpp:581
QSize minimumSizeHint() const override
Definition: citydlg.cpp:630
struct city * pcity
Definition: citydlg.h:255
QSize get_pixmap_size() const
Definition: citydlg.cpp:620
int type
Definition: citydlg.h:256
void set_type(int)
Definition: citydlg.cpp:577
city_production_delegate(QPoint sh, QObject *parent, struct city *city)
City item delegate constructor.
Definition: citydlg.cpp:2347
struct city * pcity
Definition: citydlg.h:139
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
City item delgate paint event.
Definition: citydlg.cpp:2359
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
Size hint for city item delegate.
Definition: citydlg.cpp:2507
void drawFocus(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect) const override
Draws focus for given item.
Definition: citydlg.cpp:2490
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Definition: citydlg.h:178
city_production_model(struct city *pcity, bool f, bool su, bool sw, bool sb, QObject *parent=0)
Constructor for city production model.
Definition: citydlg.cpp:2549
QList< production_item * > city_target_list
Definition: citydlg.h:189
int rowCount(const QModelIndex &index=QModelIndex()) const override
Definition: citydlg.h:173
void populate()
Fills model with data.
Definition: citydlg.cpp:2606
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Returns data from model.
Definition: citydlg.cpp:2574
struct city * mcity
Definition: citydlg.h:190
~city_production_model() override
Destructor for city production model.
Definition: citydlg.cpp:2565
QFont getFont(const QString &name, double zoom=1.0) const
Returns desired font.
Definition: fonts.cpp:57
static fcFont * instance()
Returns instance of fc_font.
Definition: fonts.cpp:34
static fcIcons * instance()
Returns instance of fc_icons.
Definition: icons.cpp:36
mr_menu * menu_bar
Definition: fc_client.h:127
void parameters_changed(const cm_parameter &params)
Signal emitted when the governor settings are changed.
static hIcon * i()
Definition: icons.cpp:205
void set_text_title_definput(const QString &s1, const QString &s2, const QString &def_input)
Sets text, title and default text and shows input box.
Definition: hudwidget.cpp:372
QLineEdit input_edit
Definition: hudwidget.h:118
void set_text_title(const QString &s1, const QString &s2)
Sets text and title and shows message box.
Definition: hudwidget.cpp:117
void center_on_tile(tile *tile, bool animate=true)
Centers the view on a tile.
Definition: view_map.cpp:197
void hide_all_fcwidgets()
Hides all fcwidgets (reports etc).
Definition: view_map.cpp:170
void show_all_fcwidgets()
Shows all fcwidgets (reports etc).
Definition: view_map.cpp:184
double scale
Definition: view_map.h:48
QAction * minimap_status
Definition: menu.h:185
city_dialog * city_overlay
Definition: page_game.h:83
map_view * mapview_wdg
Definition: page_game.h:81
struct universal * target
Definition: citydlg.h:159
~production_item() override
Production item destructor.
Definition: citydlg.cpp:2532
QVariant data() const
Returns stored data.
Definition: citydlg.cpp:2541
production_item(struct universal *ptarget, QObject *parent)
Production item constructor.
Definition: citydlg.cpp:2522
bool eventFilter(QObject *obj, QEvent *ev) override
Event filter for production widget.
Definition: citydlg.cpp:2756
void prod_selected(const QItemSelection &sl, const QItemSelection &ds)
Changed selection in production widget.
Definition: citydlg.cpp:2789
~production_widget() override
Destructor for production widget.
Definition: citydlg.cpp:2864
void mousePressEvent(QMouseEvent *event) override
Mouse press event for production widget.
Definition: citydlg.cpp:2743
city_production_model * list_model
Definition: citydlg.h:203
struct city * pw_city
Definition: citydlg.h:220
fc_tooltip * fc_tt
Definition: citydlg.h:224
city_production_delegate * c_p_d
Definition: citydlg.h:204
production_widget(QWidget *parent, struct city *pcity, bool future, int when, int curr, bool show_units, bool buy=false, bool show_wonders=true, bool show_buildings=true)
Constructor for production widget future - show future targets show_units - if to show units when - w...
Definition: citydlg.cpp:2671
progress_bar(QWidget *parent)
Custom progressbar constructor.
Definition: citydlg.cpp:236
QRegion reg
Definition: citydlg.h:118
void set_pixmap(struct universal *target)
Sets pixmap from given universal for custom progressbar.
Definition: citydlg.cpp:264
~progress_bar() override
Custom progressbar destructor.
Definition: citydlg.cpp:246
void create_region()
Creates region with diagonal lines.
Definition: citydlg.cpp:446
void resizeEvent(QResizeEvent *event) override
Custom progressbar resize event.
Definition: citydlg.cpp:255
QPixmap * pix
Definition: citydlg.h:117
void paintEvent(QPaintEvent *event) override
Paint event for custom progress bar.
Definition: citydlg.cpp:317
QFont * sfont
Definition: citydlg.h:119
void clicked()
bool m_oneliner
Definition: citydlg.h:88
std::vector< unit * > selected_playable_units() const
Finds the list of currently selected units.
Definition: citydlg.cpp:128
void activate()
Activates unit and closes city dialog.
Definition: citydlg.cpp:166
void set_units(unit_list *units)
Sets the list of units to be displayed.
Definition: citydlg.cpp:101
void contextMenuEvent(QContextMenuEvent *event) override
Reimplemented to provide the unit context menu.
Definition: citydlg.cpp:148
QPixmap create_unit_image(const unit *punit)
Creates the image to represent the given unit in the list.
Definition: citydlg.cpp:184
unit_list_widget(QWidget *parent=nullptr)
Constructor.
Definition: citydlg.cpp:70
bool m_show_upkeep
Definition: citydlg.h:89
QSize viewportSizeHint() const override
Reimplemented virtual method.
Definition: citydlg.cpp:84
std::vector< unit * > sorted(const unit_list *units)
Returns a version of units sorted in the way the user would like to see them.
Definition: unit_utils.cpp:87
bool client_is_global_observer()
Returns whether client is global observer.
struct player * client_player()
Either controlling or observing.
struct civclient client
bool can_client_issue_orders()
Returns TRUE iff the client can issue orders (such as giving unit commands).
bool client_is_observer()
Returns whether client is observer.
int collect_eventually_buildable_targets(struct universal *targets, struct city *pcity, bool advanced_tech)
Collect the cids of all targets which can be build by this city or in general.
Definition: climisc.cpp:701
void name_and_sort_items(struct universal *targets, int num_targets, struct item *items, bool show_cost, struct city *pcity)
Takes an array of compound ids (cids).
Definition: climisc.cpp:596
cid cid_encode(struct universal target)
Encode a CID for the target production.
Definition: climisc.cpp:446
int collect_already_built_targets(struct universal *targets, struct city *pcity)
Collect the cids of all improvements which are built in the given city.
Definition: climisc.cpp:806
struct universal cid_decode(cid id)
Decode the CID into a city_production structure.
Definition: climisc.cpp:478
#define MAX_NUM_PRODUCTION_TARGETS
Definition: climisc.h:73
int cid
Definition: climisc.h:21
void unit_focus_update()
If there is no unit currently in focus, or if the current unit in focus should not be in focus,...
Definition: control.cpp:718
void unit_focus_add(struct unit *punit)
Adds this unit to the list of units in focus.
Definition: control.cpp:534
void unit_focus_set(struct unit *punit)
Sets the focus unit directly.
Definition: control.cpp:479
int get_city_bonus(const struct city *pcity, enum effect_type effect_type, enum vision_layer vlayer)
Returns the effect bonus at a city.
Definition: effects.cpp:688
enum event_type event
Definition: events.cpp:68
class fc_client * king()
Return fc_client instance.
Definition: gui_main.cpp:58
unsigned char citizens
Definition: fc_types.h:305
@ O_SHIELD
Definition: fc_types.h:86
@ O_FOOD
Definition: fc_types.h:85
@ O_TRADE
Definition: fc_types.h:87
@ O_SCIENCE
Definition: fc_types.h:90
@ O_LUXURY
Definition: fc_types.h:89
@ O_GOLD
Definition: fc_types.h:88
#define PL_(String1, String2, n)
Definition: fcintl.h:54
#define _(String)
Definition: fcintl.h:50
struct unit * game_unit_by_number(int id)
Find unit out of all units in game: now uses fast idex method, instead of looking through all units o...
Definition: game.cpp:112
struct civ_game game
Definition: game.cpp:47
const char * population_to_text(int thousand_citizen)
Return a prettily formatted string containing the population text.
Definition: game.cpp:699
struct city * game_city_by_number(int id)
Often used function to get a city pointer from a city ID.
Definition: game.cpp:103
struct global_worklist * global_worklist_by_id(int id)
Returns the global worklist corresponding to this id.
bool global_worklist_set(struct global_worklist *pgwl, const struct worklist *pwl)
Sets the worklist.
int global_worklist_id(const struct global_worklist *pgwl)
Returns the id of the global worklist.
struct global_worklist * global_worklist_new(const char *name)
Creates a new global worklist form a normal worklist.
const char * global_worklist_name(const struct global_worklist *pgwl)
Return the name of the global worklist.
const struct worklist * global_worklist_get(const struct global_worklist *pgwl)
Returns the worklist of this global worklist or nullptr if it's not valid.
#define global_worklists_iterate(pgwl)
#define global_worklists_iterate_end
const char * cmafec_get_short_descr_of_city(const struct city *pcity)
Return short description of city governor preset.
Definition: governor.cpp:774
int cmafec_preset_num()
Returns the total number of presets.
Definition: governor.cpp:769
const struct cm_parameter * cmafec_preset_get_parameter(int idx)
Returns the indexed preset's parameter.
Definition: governor.cpp:738
bool cma_is_city_under_agent(const struct city *pcity, struct cm_parameter *parameter)
Check whether city is under governor control, and fill parameter if it is.
Definition: governor.cpp:632
char * cmafec_preset_get_descr(int idx)
Returns the indexed preset's description.
Definition: governor.cpp:725
void cma_put_city_under_agent(struct city *pcity, const struct cm_parameter *const parameter)
Put city under governor control.
Definition: governor.cpp:618
int cmafec_preset_get_index_of_parameter(const struct cm_parameter *const parameter)
Returns the index of the preset which matches the given parameter.
Definition: governor.cpp:752
void cmafec_preset_remove(int idx)
Removes a preset.
Definition: governor.cpp:709
void cma_release_city(struct city *pcity)
Release city from governor control.
Definition: governor.cpp:627
void cmafec_get_fe_parameter(struct city *pcity, struct cm_parameter *dest)
Return the front-end parameter for the given city.
Definition: governor.cpp:673
bool is_special_improvement(const struct impr_type *pimprove)
Returns TRUE if this is a "special" improvement.
bool is_improvement_redundant(const struct city *pcity, const struct impr_type *pimprove)
Returns TRUE if an improvement in a city is redundant, that is, the city wouldn't lose anything by lo...
bool is_improvement(const struct impr_type *pimprove)
Is this building a regular improvement?
int impr_build_shield_cost(const struct city *pcity, const struct impr_type *pimprove)
Returns the number of shields it takes to build this improvement.
bool is_wonder(const struct impr_type *pimprove)
Returns whether improvement is some kind of wonder.
bool improvement_has_flag(const struct impr_type *pimprove, enum impr_flag_id flag)
Return TRUE if the impr has this flag otherwise FALSE.
const char * improvement_name_translation(const struct impr_type *pimprove)
Return the (translated) name of the given improvement.
const char * name
Definition: inputfile.cpp:118
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert_action(condition, action)
Definition: log.h:104
const char *const default_font
Definition: fonts.h:18
const char *const notify_label
Definition: fonts.h:19
void add_quick_unit_actions(QMenu *menu, const std::vector< unit * > &units)
Adds a small set of common unit actions to a menu.
const char * nation_adjective_for_player(const struct player *pplayer)
Return the (translated) adjective for the given nation of a player.
Definition: nation.cpp:146
struct nation_type * nation_of_player(const struct player *pplayer)
Return the nation of a player.
Definition: nation.cpp:419
pageGame * queen()
Return game instandce.
Definition: page_game.cpp:557
struct player * player_slot_get_player(const struct player_slot *pslot)
Returns the team corresponding to the slot.
Definition: player.cpp:384
#define ARRAY_SIZE(x)
Definition: shared.h:79
#define MIN(x, y)
Definition: shared.h:49
size_t size
Definition: specvec.h:64
Definition: city.h:291
struct city::@15::@18 client
int surplus[O_LAST]
Definition: city.h:324
int food_stock
Definition: city.h:338
int pollution
Definition: city.h:340
int id
Definition: city.h:296
int waste[O_LAST]
Definition: city.h:325
struct universal production
Definition: city.h:368
int steal
Definition: city.h:383
citizens size
Definition: city.h:301
struct tile * tile
Definition: city.h:293
int shield_stock
Definition: city.h:339
int prod[O_LAST]
Definition: city.h:327
struct unit_list * units_supported
Definition: city.h:377
struct packet_game_info info
Definition: game.h:80
struct connection conn
Definition: client_main.h:89
struct player * playing
Definition: connection.h:142
Definition: mapimg.cpp:266
Definition: climisc.h:66
struct universal item
Definition: climisc.h:67
The base class for options.
Definition: options.cpp:209
struct city_list * cities
Definition: player.h:263
struct player_economic economic
Definition: player.h:266
struct unit_list * units
Definition: tile.h:50
Definition: unit.h:134
int upkeep[O_LAST]
Definition: unit.h:145
struct tile * tile
Definition: unit.h:136
int homecity
Definition: unit.h:142
enum universals_n kind
Definition: fc_types.h:740
universals_u value
Definition: fc_types.h:739
struct universal entries[MAX_LEN_WORKLIST]
Definition: worklist.h:25
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
struct advance * valid_advance_by_number(const Tech_type_id id)
Returns pointer when the advance "exists" in this game, returns nullptr otherwise.
Definition: tech.cpp:154
QString text_happiness_wonders(const struct city *pcity)
Describing wonders that affect happiness.
Definition: text.cpp:1490
const QString unit_description(const unit *punit)
Returns the unit description.
Definition: text.cpp:551
QString text_happiness_luxuries(const struct city *pcity)
Describing luxuries that affect happiness.
Definition: text.cpp:1949
QString text_happiness_cities(const struct city *pcity)
Describing city factors that affect happiness.
Definition: text.cpp:1754
QString text_happiness_buildings(const struct city *pcity)
Describe buildings that affect happiness (or rather, anything with a Make_Content effect).
Definition: text.cpp:1389
QString text_happiness_nationality(const struct city *pcity)
Describing nationality effects that affect happiness.
Definition: text.cpp:1427
QString text_happiness_units(const struct city *pcity)
Describe units that affect happiness.
Definition: text.cpp:1811
struct city * tile_city(const struct tile *ptile)
Return the city on this tile (or nullptr), checking for city center.
Definition: tile.cpp:72
int tileset_hex_width(const struct tileset *t)
Return the hex_width of the current tileset.
Definition: tilespec.cpp:345
int tileset_unit_width(const struct tileset *t)
Return the unit tile width of the current tileset.
Definition: tilespec.cpp:426
int tileset_unit_height(const struct tileset *t)
Return the unit tile height of the current tileset.
Definition: tilespec.cpp:434
const QPixmap * get_citizen_sprite(const struct tileset *t, enum citizen_category type, int citizen_index, const struct city *pcity)
Return a sprite for the given citizen.
Definition: tilespec.cpp:3337
int tileset_small_sprite_width(const struct tileset *t)
Return the small sprite width of the current tileset.
Definition: tilespec.cpp:495
const QPixmap * get_nation_flag_sprite(const struct tileset *t, const struct nation_type *pnation)
Return the sprite for the nation.
Definition: tilespec.cpp:3367
int tileset_unit_layout_offset_y(const struct tileset *t)
Offset to layout extra unit sprites, such as upkeep.
Definition: tilespec.cpp:485
const QPixmap * get_tech_sprite(const struct tileset *t, Tech_type_id tech)
Return the sprite for the technology/advance.
Definition: tilespec.cpp:3385
bool tileset_is_isometric(const struct tileset *t)
Return whether the current tileset is isometric.
Definition: tilespec.cpp:336
int tileset_small_sprite_height(const struct tileset *t)
Return the small sprite height of the current tileset.
Definition: tilespec.cpp:523
const QPixmap * get_unittype_sprite(const struct tileset *t, const struct unit_type *punittype, enum direction8 facing, const QColor &replace)
Return the sprite for the unit type (the base "unit" sprite).
Definition: tilespec.cpp:3416
struct tileset * get_tileset()
Returns the tileset.
Definition: tilespec.cpp:326
int tileset_unit_with_upkeep_height(const struct tileset *t)
Suitable canvas height for a unit icon that includes upkeep sprites.
Definition: tilespec.cpp:473
int tileset_hex_height(const struct tileset *t)
Return the hex_height of the current tileset.
Definition: tilespec.cpp:351
const QPixmap * get_building_sprite(const struct tileset *t, const struct impr_type *pimprove)
Return the sprite for the building/improvement.
Definition: tilespec.cpp:3394
QString get_tooltip_improvement(const impr_type *building, struct city *pcity, bool ext)
Returns improvement properties to append in tooltip ext is used to get extra info from help.
Definition: tooltips.cpp:82
QString get_tooltip(const QVariant &qvar)
Returns shortened help for given universal ( stored in qvar )
Definition: tooltips.cpp:215
QString get_tooltip_unit(const struct unit_type *utype, bool ext)
Returns unit properties to append in tooltip ext is used to get extra info from help.
Definition: tooltips.cpp:144
void top_bar_show_map()
Callback to show map.
Definition: top_bar.cpp:448
const struct unit_type * utype
Definition: fc_types.h:585
const struct impr_type * building
Definition: fc_types.h:579
#define unit_owner(_pu)
Definition: unit.h:370
const char * utype_values_translation(const struct unit_type *punittype)
Return string with translated unit name and list of its values.
Definition: unittype.cpp:1310
int utype_build_shield_cost(const struct city *pcity, const struct unit_type *punittype)
Returns the number of shields it takes to build this unit type.
Definition: unittype.cpp:1141
bool utype_is_consumed_by_action_result(enum action_result result, const struct unit_type *utype)
Returns TRUE iff performing an action with the specified action result will consume an actor unit of ...
Definition: unittype.cpp:947
bool utype_can_do_action_result(const struct unit_type *putype, enum action_result result)
Return TRUE iff units of the given type can do any enabler controlled action with the specified actio...
Definition: unittype.cpp:402
const char * utype_name_translation(const struct unit_type *punittype)
Return the (translated) name of the unit type.
Definition: unittype.cpp:1256
static bool uclass_has_flag(const struct unit_class *punitclass, enum unit_class_flag_id flag)
Definition: unittype.h:704
#define utype_class(_t_)
Definition: unittype.h:691
#define utype_fuel(ptype)
Definition: unittype.h:772
static bool utype_has_flag(const struct unit_type *punittype, int flag)
Definition: unittype.h:584
void refresh_city_mapcanvas(struct city *pcity, struct tile *ptile, bool full_refresh)
Refreshes a single city on the map canvas.
void put_unit_city_overlays(const unit *punit, QPixmap *pcanvas, int canvas_x, int canvas_y, const int *upkeep_cost, int happy_cost)
Draw food, gold, and shield upkeep values on the unit.
void update_map_canvas_visible()
Schedules an update of (only) the visible part of the map at the next unqueue_mapview_update().
void put_unit(const struct unit *punit, QPixmap *pcanvas, const QPoint &canvas_loc)
Draw the given unit onto the canvas store at the given location.
void worklist_init(struct worklist *pwl)
Initialize a worklist to be empty.
Definition: worklist.cpp:32
bool worklist_peek_ith(const struct worklist *pwl, struct universal *prod, int idx)
Fill in the id and is_unit values for the ith element in the worklist.
Definition: worklist.cpp:80
bool worklist_insert(struct worklist *pwl, const struct universal *prod, int idx)
Inserts the production at the location idx in the worklist, thus moving all subsequent entries down.
Definition: worklist.cpp:158
void worklist_remove(struct worklist *pwl, int idx)
Remove element from position idx.
Definition: worklist.cpp:113
int worklist_length(const struct worklist *pwl)
Returns the number of entries in the worklist.
Definition: worklist.cpp:51