Freeciv21
Develop your civilization from humble roots to a global empire
view_units.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-License-Identifier: GPL-3.0-or-later
3  * SPDX-FileCopyrightText: Freeciv21 and Freeciv contributors
4  * SPDX-FileCopyrightText: James Robertson <jwrober@gmail.com>
5  * SPDX-FileCopyrightText: Tobias Rehbein <tobias.rehbein@web.de>
6  */
7 
12 // client
13 #include "views/view_units.h"
14 #include "canvas.h"
15 #include "client_main.h"
16 #include "fc_client.h"
17 #include "goto.h"
18 #include "hudwidget.h"
19 #include "page_game.h"
20 #include "repodlgs_common.h"
21 #include "tileset/sprite.h"
22 #include "top_bar.h"
23 #include "turn_done_button.h"
24 #include "views/view_map.h"
25 #include "views/view_map_common.h"
26 
27 // common
28 #include "movement.h"
29 #include "text.h"
30 #include "unittype.h"
31 
32 /****************************
33  * units_view class functions
34  ****************************/
35 
40 {
41  ui.setupUi(this);
42 
43  QFont font = ui.units_table->horizontalHeader()->font();
44  font.setWeight(QFont::Bold);
45  ui.units_table->horizontalHeader()->setFont(font);
46  ui.uwt_table->horizontalHeader()->setFont(font);
47 
48  // Configure the units table
49  QStringList slist;
50  slist << _("Type") << _("Name") << _("★ Upgradable")
51  << _("⚒ In Progress") << _("⚔ Active") << _("Shield Upkeep")
52  << _("Food Upkeep") << _("Gold Upkeep");
53  ui.units_label->setText(QString(_("Units:")));
54  ui.units_table->setColumnCount(slist.count());
55  ui.units_table->setHorizontalHeaderLabels(slist);
56  ui.units_table->setSortingEnabled(false);
57  ui.units_table->setAlternatingRowColors(true);
58  ui.upg_but->setText(_("Upgrade"));
59  ui.upg_but->setToolTip(_("Upgrade selected unit."));
60  ui.upg_but->setDisabled(true);
61  ui.find_but->setText(_("Find Nearest"));
62  ui.find_but->setToolTip(_("Center the map on the nearest unit in relation "
63  "to where the map is now."));
64  ui.find_but->setDisabled(true);
65  ui.disband_but->setText(_("Disband All"));
66  ui.disband_but->setToolTip(_("Disband all of the selected unit."));
67  ui.disband_but->setDisabled(true);
68 
69  // Configure the unitwaittime table
70  slist.clear();
71  slist << _("Type") << _("Name") << _("Location") << _("Time Left")
72  << _("Id");
73  ui.uwt_table->setColumnCount(slist.count());
74  ui.uwt_table->setColumnHidden(4, true);
75  ui.uwt_table->setHorizontalHeaderLabels(slist);
76  ui.uwt_table->setSortingEnabled(true);
77  ui.uwt_table->setAlternatingRowColors(true);
78  ui.uwt_label->setText("Units Waiting:");
79 
80  // Configure the splitter
81  // Configuring the splitter to distribute its children equally, is more
82  // complicated than one might expect. We need to set the child widgets
83  // sizes to the same value, using the QSplitters setSizes method. As QT
84  // will still enforce the minimum size policy, we have to base this value
85  // on the maximum minimum size of the children.
86  auto equalHeight = std::max(ui.units_widget->minimumSizeHint().height(),
87  ui.uwt_widget->minimumSizeHint().height());
88  ui.splitter->setSizes({equalHeight, equalHeight});
89 
90  // Add shield icon for shield upkeep column
91  const QPixmap *spr =
93  "citybar.shields", "", "", false);
94  ui.units_table->horizontalHeaderItem(5)->setIcon(crop_sprite(spr));
95 
96  // Add food icon for food upkeep column
97  spr = tiles_lookup_sprite_tag_alt(tileset, LOG_VERBOSE, "upkeep.food",
98  "citybar.food", "", "", false);
99  ui.units_table->horizontalHeaderItem(6)->setIcon(crop_sprite(spr));
100 
101  // Add gold icon for gold upkeep column
102  spr = tiles_lookup_sprite_tag_alt(tileset, LOG_VERBOSE, "upkeep.gold",
103  "citybar.trade", "", "", false);
104  ui.units_table->horizontalHeaderItem(7)->setIcon(crop_sprite(spr));
105 
106  connect(ui.upg_but, &QAbstractButton::pressed, this,
108  connect(ui.find_but, &QAbstractButton::pressed, this,
110  connect(ui.disband_but, &QAbstractButton::pressed, this,
112  connect(ui.units_table->selectionModel(),
113  &QItemSelectionModel::selectionChanged, this,
115  setLayout(ui.units_layout);
116  queen()->gimmePlace(this, QStringLiteral("UNI"));
117  index = queen()->addGameTab(this);
118 }
119 
123 units_view::~units_view() { queen()->removeRepoDlg(QStringLiteral("UNI")); }
124 
128 void units_view::init() { queen()->game_tab_widget->setCurrentIndex(index); }
129 
134 {
135  QTimer *timer = new QTimer(this);
136  connect(timer, &QTimer::timeout, this, &units_view::update_waiting);
137  timer->start(1000);
138 
139  update_units();
140  update_waiting();
141 }
142 
147 {
148  // used to set the height of the unit sprite
149  QFont f = QApplication::font();
150  QFontMetrics fm(f);
151  int h = fm.height() + 24;
152 
153  auto unit_entries = get_units_view_data();
154 
155  // Variables for the nested loops
156  int total_count = 0; // Sum of unit type
157  int upg_count = 0; // Sum of upgradable
158  int in_progress = 0; // Sum of in progress by unit type
159  int total_gold = 0; // Sum of gold upkeep
160  int total_shield = 0; // Sum of shield upkeep
161  int total_food = 0; // Sum of food upkeep
162  int max_row = ui.units_table->rowCount(); // Max rows in the table widget
163 
164  // Remove "footer" rows from units table
165  if (max_row >= 1) {
166  max_row--;
167  ui.units_table->removeRow(max_row);
168  }
169 
170  // Keep tab of all unit types currently in the table. This is used to
171  // update already existing rows in the table. After updating a unit type
172  // the corresponding entry is removed from the map. Once all unit types,
173  // used by the player, have been processed the remaining unit types can be
174  // removed from the units table.
175  std::map<cid, QTableWidgetItem *> unittypes_in_table;
176  for (int r = 0; r < ui.units_table->rowCount(); r++) {
177  QTableWidgetItem *item = ui.units_table->item(r, 0);
178 
179  bool ok = false;
180  cid key = (cid) item->data(Qt::UserRole).toInt(&ok);
181  fc_assert_action(ok == true, continue);
182  unittypes_in_table[key] = ui.units_table->item(r, 0);
183  }
184 
185  for (int i = 0; i < unit_entries.size(); i++) {
186  const unit_view_entry &entry = unit_entries[i];
187  const struct unit_type *putype = entry.type;
188  cid id = cid_encode_unit(putype);
189 
190  auto existing_row_for_unittype = unittypes_in_table.find(id);
191  bool new_row = existing_row_for_unittype == unittypes_in_table.end();
192  int current_row = max_row;
193  if (new_row) {
194  ui.units_table->insertRow(max_row);
195  } else {
196  current_row = existing_row_for_unittype->second->row();
197  }
198 
199  for (int j = 0; j < 8; j++) {
200  QTableWidgetItem *item = new QTableWidgetItem;
201  switch (j) {
202  case 0:
203  // Unit type image sprite
204  {
205  auto sprite =
206  get_unittype_sprite(tileset, putype, direction8_invalid())
207  ->scaledToHeight(h);
208  QLabel *lbl = new QLabel;
209  lbl->setPixmap(QPixmap(sprite));
210  lbl->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
211  ui.units_table->setCellWidget(current_row, j, lbl);
212  }
213  item->setData(Qt::UserRole, id);
214  break;
215  case 1:
216  // Unit type name
217  item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
218  item->setText(utype_name_translation(putype));
219  break;
220  case 2:
221  // Is Upgradable
222  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
223  if (entry.upg) {
224  item->setData(Qt::DisplayRole, "★");
225  upg_count++;
226  } else {
227  item->setData(Qt::DisplayRole, "-");
228  }
229  break;
230  case 3:
231  // # In Progress
232  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
233  item->setData(Qt::DisplayRole, entry.in_prod);
234  in_progress += entry.in_prod;
235  break;
236  case 4:
237  // # Active
238  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
239  item->setData(Qt::DisplayRole, entry.count);
240  total_count += entry.count;
241  break;
242  case 5:
243  // Shield upkeep
244  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
245  if (entry.shield_cost == 0) {
246  item->setText("-");
247  } else {
248  item->setData(Qt::DisplayRole, entry.shield_cost);
249  }
250  total_shield += entry.shield_cost;
251  break;
252  case 6:
253  // Food upkeep
254  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
255  if (entry.food_cost == 0) {
256  item->setText("-");
257  } else {
258  item->setData(Qt::DisplayRole, entry.food_cost);
259  }
260  total_food += entry.food_cost;
261  break;
262  case 7:
263  // Gold upkeep
264  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
265  if (entry.gold_cost == 0) {
266  item->setText("-");
267  } else {
268  item->setData(Qt::DisplayRole, entry.gold_cost);
269  }
270  total_gold += entry.gold_cost;
271  break;
272  }
273  ui.units_table->setItem(current_row, j, item);
274  }
275 
276  if (new_row) {
277  max_row++;
278  } else {
279  unittypes_in_table.erase(id);
280  }
281  }
282 
283  // Remove rows no longer needed in the table.
284  for (const auto &[_, value] : unittypes_in_table) {
285  ui.units_table->removeRow(value->row());
286  max_row--;
287  }
288 
289  // Add a "footer" to the table showing the totals.
290  ui.units_table->setRowCount(max_row);
291  ui.units_table->insertRow(max_row);
292  for (int j = 0; j < 8; j++) {
293  QTableWidgetItem *item_totals = new QTableWidgetItem;
294  switch (j) {
295  case 1:
296  // Unit type name
297  item_totals->setTextAlignment(Qt::AlignRight);
298  item_totals->setText(_("--------------------\nTotals:"));
299  break;
300  case 2:
301  // Upgradable
302  item_totals->setTextAlignment(Qt::AlignCenter);
303  item_totals->setText(QString(_("------\n%1")).arg(upg_count));
304  break;
305  case 3:
306  // In Progress
307  item_totals->setTextAlignment(Qt::AlignCenter);
308  item_totals->setText(QString(_("------\n%1")).arg(in_progress));
309  break;
310  case 4:
311  item_totals->setTextAlignment(Qt::AlignCenter);
312  item_totals->setText(QString(_("------\n%1")).arg(total_count));
313  break;
314  case 5:
315  item_totals->setTextAlignment(Qt::AlignCenter);
316  item_totals->setText(QString(_("------\n%1")).arg(total_shield));
317  break;
318  case 6:
319  item_totals->setTextAlignment(Qt::AlignCenter);
320  item_totals->setText(QString(_("------\n%1")).arg(total_food));
321  break;
322  case 7:
323  item_totals->setTextAlignment(Qt::AlignCenter);
324  item_totals->setText(QString(_("------\n%1")).arg(total_gold));
325  break;
326  }
327  ui.units_table->setItem(max_row, j, item_totals);
328  }
329 
330  if (max_row == 0) {
331  ui.units_widget->setHidden(true);
332  } else {
333  ui.units_widget->setHidden(false);
334  ui.units_table->resizeRowsToContents();
335  ui.units_table->resizeColumnsToContents();
336  ui.units_table->horizontalHeader()->resizeSections(
337  QHeaderView::ResizeToContents);
338  ui.units_table->verticalHeader()->setSectionResizeMode(
339  QHeaderView::ResizeToContents);
340  }
341 
342  update_buttons(ui.units_table->selectionModel()->selection());
343 }
344 
349 {
350  // used to set the height of the unit sprite
351  QFont f = QApplication::font();
352  QFontMetrics fm(f);
353  int h = fm.height() + 24;
354 
355  auto unit_entries = get_units_waiting_data();
356 
357  max_row = ui.uwt_table->rowCount();
358 
359  // Remember all units initially in the table. This allows us to distinguish
360  // between known units we need to update and new units we need to add to
361  // the table. As we remove all updated units from this map, the remaining
362  // items are the units we need to remove from the table.
364  for (int r = 0; r < max_row; r++) {
365  QTableWidgetItem *item = ui.uwt_table->item(r, 4);
366  ids_in_table[item->text()] = item;
367  }
368 
369  for (int i = 0; i < unit_entries.size(); i++) {
370  const unit_waiting_entry &entry = unit_entries[i];
371  const struct unit_type *putype = entry.type;
372  cid id = cid_encode_unit(putype);
373  QString unit_id = QString("%1").arg(entry.id);
374  QString unit_waittime = format_simple_duration(abs(entry.timer));
375 
376  if (!ids_in_table.contains(unit_id)) {
377  // Create a new row for the unit
378  ui.uwt_table->insertRow(max_row);
379  for (int j = 0; j < 5; j++) {
380  auto item = new QTableWidgetItem;
381  switch (j) {
382  case 0:
383  // Unit type image sprite
384  {
385  auto sprite =
386  get_unittype_sprite(tileset, putype, direction8_invalid())
387  ->scaledToHeight(h);
388  QLabel *lbl = new QLabel;
389  lbl->setPixmap(QPixmap(sprite));
390  lbl->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
391  ui.uwt_table->setCellWidget(i, j, lbl);
392  }
393  item->setData(Qt::UserRole, id);
394  break;
395  case 1:
396  // Unit type name
397  item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
398  item->setText(utype_name_translation(putype));
399  break;
400  case 2:
401  // # Location
402  item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
403  item->setText(QString(_("%1")).arg(entry.city_name));
404  break;
405  case 3:
406  // # Time Left
407  item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
408  item->setText(QString(_("%1")).arg(unit_waittime));
409  break;
410  case 4:
411  // # Id
412  item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
413  item->setText(QString("%1").arg(unit_id));
414  break;
415  }
416  ui.uwt_table->setItem(max_row, j, item);
417  }
418  max_row++;
419  } else {
420  // Unit is already in table, update the corresponding row.
421  int row = ids_in_table[unit_id]->row();
422  ui.uwt_table->item(row, 3)->setText(unit_waittime);
423  ids_in_table.remove(unit_id);
424  }
425  }
426 
427  // Delete units initially in the table, but not waiting anymore.
428  for (int i = 0; i < ids_in_table.values().size(); i++) {
429  int row = ids_in_table.values()[i]->row();
430  ui.uwt_table->removeRow(row);
431  max_row--;
432  }
433 
434  if (max_row == 0) {
435  ui.uwt_widget->setHidden(true);
436  } else {
437  ui.uwt_widget->setHidden(false);
438  ui.uwt_table->setRowCount(max_row);
439  ui.uwt_table->resizeRowsToContents();
440  ui.uwt_table->resizeColumnsToContents();
441  ui.uwt_table->horizontalHeader()->resizeSections(
442  QHeaderView::ResizeToContents);
443  ui.uwt_table->verticalHeader()->setSectionResizeMode(
444  QHeaderView::ResizeToContents);
445  }
446 }
447 
451 void units_view::selection_changed(const QItemSelection &sl,
452  const QItemSelection &ds)
453 {
454  update_buttons(sl);
455 }
456 
461 void units_view::update_buttons(const QItemSelection &sl)
462 {
463  QTableWidgetItem *itm;
464  QVariant qvar;
465  struct universal selected;
466  QString upg;
467 
468  ui.upg_but->setDisabled(true);
469  ui.disband_but->setDisabled(true);
470  ui.find_but->setDisabled(true);
471 
472  if (sl.isEmpty()) {
473  return;
474  }
475 
476  curr_row = sl.indexes().at(0).row();
477  max_row = ui.units_table->rowCount() - 1;
478  if (curr_row >= 0 && curr_row <= max_row) {
479  itm = ui.units_table->item(curr_row, 0);
480  qvar = itm->data(Qt::UserRole);
481  uid = qvar.toInt();
482  selected = cid_decode(uid);
483  counter = ui.units_table->item(curr_row, 4)->text().toInt();
484  if (counter > 0) {
485  ui.disband_but->setDisabled(false);
486  ui.find_but->setDisabled(false);
487  }
488  upg = ui.units_table->item(curr_row, 2)->text();
489  if (upg != "-") {
490  ui.upg_but->setDisabled(false);
491  }
492  if (curr_row == max_row) {
493  ui.upg_but->setDisabled(true);
494  }
495  }
496 }
497 
502 {
503  struct universal selected;
504  QString buf;
505  hud_message_box *ask = new hud_message_box(king()->central_wdg);
506  Unit_type_id utype;
507 
508  selected = cid_decode(uid);
509  utype = utype_number(selected.value.utype);
510  buf = QString(_("Do you really wish to disband every %1 (%2 total)?"))
512  QString::number(counter));
513 
514  ask->set_text_title(buf, _("Disband Units?"));
515  ask->setStandardButtons(QMessageBox::Cancel | QMessageBox::Yes);
516  ask->setDefaultButton(QMessageBox::Cancel);
517  ask->button(QMessageBox::Yes)->setText(_("Yes Disband"));
518  ask->setAttribute(Qt::WA_DeleteOnClose);
519  connect(ask, &hud_message_box::accepted, [=]() {
520  struct unit_type *putype = utype_by_number(utype);
521  char buf[1024];
522  hud_message_box *result;
523 
524  if (putype) {
525  disband_all_units(putype, false, buf, sizeof(buf));
526  result = new hud_message_box(king()->central_wdg);
527  result->set_text_title(buf, _("Disband Results"));
528  result->setStandardButtons(QMessageBox::Ok);
529  result->setAttribute(Qt::WA_DeleteOnClose);
530  result->show();
531  }
532  });
533  ask->show();
534 }
535 
540 {
541  struct universal selected;
542  struct tile *ptile;
543  struct unit *punit;
544  const struct unit_type *utype;
545 
546  selected = cid_decode(uid);
547  utype = selected.value.utype;
548 
549  ptile = get_center_tile_mapcanvas();
550  if ((punit = find_nearest_unit(utype, ptile))) {
551  queen()->mapview_wdg->center_on_tile(punit->tile);
552 
553  if (ACTIVITY_IDLE == punit->activity
554  || ACTIVITY_SENTRY == punit->activity) {
555  if (can_unit_do_activity(punit, ACTIVITY_IDLE)) {
557  }
558  }
559  }
560 
561  // Show map
562  queen()->game_tab_widget->setCurrentIndex(0);
563 }
564 
569 {
570  struct universal selected = cid_decode(uid);
571  const struct unit_type *utype = selected.value.utype;
572  Unit_type_id type = utype_number(utype);
573  const struct unit_type *upgrade =
575  int price = unit_upgrade_price(client_player(), utype, upgrade);
576 
577  QString b = QString::asprintf(PL_("Treasury contains %d gold.",
578  "Treasury contains %d gold.",
579  client_player()->economic.gold),
580  client_player()->economic.gold);
581  QString c = QString::asprintf(PL_("Upgrade as many %s to %s as possible "
582  "for %d gold each?\n%s",
583  "Upgrade as many %s to %s as possible "
584  "for %d gold each?\n%s",
585  price),
586  utype_name_translation(utype),
587  utype_name_translation(upgrade), price,
588  b.toUtf8().data());
589 
590  hud_message_box *ask = new hud_message_box(king()->central_wdg);
591  ask->set_text_title(c, _("Upgrade Obsolete Units?"));
592  ask->setStandardButtons(QMessageBox::Cancel | QMessageBox::Yes);
593  ask->setDefaultButton(QMessageBox::Cancel);
594  ask->button(QMessageBox::Yes)->setText(_("Yes Upgrade"));
595  ask->setAttribute(Qt::WA_DeleteOnClose);
596  connect(ask, &hud_message_box::accepted,
597  [=]() { dsend_packet_unit_type_upgrade(&client.conn, type); });
598  ask->show();
599 }
600 
601 /****************************************
602  * Helper functions related to units view
603  ****************************************/
604 
608 struct unit *find_nearest_unit(const struct unit_type *utype,
609  struct tile *ptile)
610 {
611  struct unit *best_candidate = NULL;
612  int best_dist = FC_INFINITY, dist;
613 
614  players_iterate(pplayer)
615  {
616  if (client_has_player() && pplayer != client_player()) {
617  continue;
618  }
619 
620  unit_list_iterate(pplayer->units, punit)
621  {
622  if (utype == unit_type_get(punit)
623  && FOCUS_AVAIL == punit->client.focus_status
624  && 0 < punit->moves_left && !punit->done_moving
625  && punit->ssa_controller == SSA_NONE) {
626  dist = sq_map_distance(unit_tile(punit), ptile);
627  if (dist < best_dist) {
628  best_candidate = punit;
629  best_dist = dist;
630  }
631  }
632  }
634  }
636 
637  return best_candidate;
638 }
639 
643 std::vector<unit_view_entry> get_units_view_data()
644 {
645  auto entries = std::vector<unit_view_entry>();
646 
647  players_iterate(pplayer)
648  {
649  if (client_has_player() && pplayer != client_player()) {
650  continue;
651  }
652 
653  unit_type_iterate(unittype)
654  {
655  int count = 0; // Count of active unit type
656  int in_progress = 0; // Count of being produced
657  int gold_cost = 0; // Gold upkeep
658  int food_cost = 0; // Food upkeep
659  int shield_cost = 0; // Shield upkeep
660  bool upgradable = false; // Unit type is upgradable
661 
662  unit_list_iterate(pplayer->units, punit)
663  {
664  if (unit_type_get(punit) == unittype) {
665  count++;
666  upgradable =
668  && nullptr != can_upgrade_unittype(client_player(), unittype);
669 
670  // Only units with a home city have upkeep
671  if (punit->homecity != 0) {
672  gold_cost += punit->upkeep[O_GOLD];
673  food_cost += punit->upkeep[O_FOOD];
674  shield_cost += punit->upkeep[O_SHIELD];
675  }
676  }
677  }
679 
680  city_list_iterate(pplayer->cities, pcity)
681  {
682  if (pcity->production.value.utype == unittype
683  && pcity->production.kind == VUT_UTYPE) {
684  in_progress++;
685  }
686  }
688 
689  // Skip unused unit types
690  if (count == 0 && in_progress == 0) {
691  continue;
692  }
693 
694  entries.push_back({.type = unittype,
695  .count = count,
696  .in_prod = in_progress,
697  .food_cost = food_cost,
698  .gold_cost = gold_cost,
699  .shield_cost = shield_cost,
700  .upg = upgradable});
701  }
703  }
705 
706  std::sort(
707  entries.begin(), entries.end(), [](const auto &lhs, const auto &rhs) {
708  return QString::localeAwareCompare(utype_name_translation(lhs.type),
709  utype_name_translation(rhs.type))
710  < 0;
711  });
712  return entries;
713 }
714 
718 std::vector<unit_waiting_entry> get_units_waiting_data()
719 {
720  if (nullptr == client.conn.playing) {
721  return {};
722  }
723 
724  auto entries = std::vector<unit_waiting_entry>();
725 
727  {
728  int pcity_near_dist = 0; // Init distance
729  struct city *pcity_near = get_nearest_city(punit, &pcity_near_dist);
730 
731  if (!can_unit_move_now(punit) && punit->ssa_controller == SSA_NONE) {
732  entries.push_back(
733  {.type = punit->utype,
734  .timer = time(nullptr) - punit->action_timestamp,
735  .city_name = get_nearest_city_text(pcity_near, pcity_near_dist),
736  .id = punit->id});
737  }
738  }
740 
741  std::sort(
742  entries.begin(), entries.end(), [](const auto &lhs, const auto &rhs) {
743  return QString::localeAwareCompare(utype_name_translation(lhs.type),
744  utype_name_translation(rhs.type))
745  < 0;
746  });
747 
748  return entries;
749 }
750 
751 /************************************
752  * Functions for connecting to the UI
753  ************************************/
754 
758 void units_view_dialog_update(void *unused)
759 {
760  int i;
761  units_view *uv;
762  QWidget *w;
763 
764  if (queen()->isRepoDlgOpen(QStringLiteral("UNI"))) {
765  i = queen()->gimmeIndexOf(QStringLiteral("UNI"));
766  if (queen()->game_tab_widget->currentIndex() == i) {
767  w = queen()->game_tab_widget->widget(i);
768  uv = reinterpret_cast<units_view *>(w);
769  if (uv) {
770  uv->update_view();
771  }
772  }
773  }
775 }
776 
781 {
782  int i;
783  units_view *uv;
784  QWidget *w;
785 
786  if (!queen()->isRepoDlgOpen(QStringLiteral("UNI"))) {
787  uv = new units_view;
788  uv->init();
789  uv->update_view();
790  } else {
791  i = queen()->gimmeIndexOf(QStringLiteral("UNI"));
792  fc_assert(i != -1);
793  w = queen()->game_tab_widget->widget(i);
794  if (w->isVisible()) {
796  return;
797  }
798  uv = reinterpret_cast<units_view *>(w);
799  uv->init();
800  uv->update_view();
801  queen()->game_tab_widget->setCurrentWidget(uv);
802  }
803 }
804 
809 {
810  int i;
811  units_view *uv;
812  QWidget *w;
813 
814  if (queen()->isRepoDlgOpen(QStringLiteral("UNI"))) {
815  i = queen()->gimmeIndexOf(QStringLiteral("UNI"));
816  fc_assert(i != -1);
817  w = queen()->game_tab_widget->widget(i);
818  uv = reinterpret_cast<units_view *>(w);
819  uv->deleteLater();
820  }
821 }
QPixmap crop_sprite(const QPixmap *sprite)
Helper function to crop a sprite.
Definition: canvas.cpp:115
#define city_list_iterate(citylist, pcity)
Definition: city.h:482
#define city_list_iterate_end
Definition: city.h:484
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
int gimmeIndexOf(const QString &str)
Returns index on game tab page of given report dialog.
Definition: page_game.cpp:706
int addGameTab(QWidget *widget)
Inserts tab widget to game view page.
Definition: page_game.cpp:670
map_view * mapview_wdg
Definition: page_game.h:81
void removeRepoDlg(const QString &str)
Removes report dialog string from the list marking it as closed.
Definition: page_game.cpp:723
void updateSidebarTooltips()
Updates top bar tooltips.
Definition: page_game.cpp:340
void gimmePlace(QWidget *widget, const QString &str)
Finds not used index on game_view_tab and returns it.
Definition: page_game.cpp:690
fc_game_tab_widget * game_tab_widget
Definition: page_game.h:72
Table widget to display units view (F2)
Definition: view_units.h:54
void update_buttons(const QItemSelection &sl)
Updates the buttons according to the item selection sl in the units table.
Definition: view_units.cpp:461
void init()
Initializes place in tab for units view.
Definition: view_units.cpp:128
void disband_units()
Disband selected units.
Definition: view_units.cpp:501
void update_waiting()
Function to load the units waiting table.
Definition: view_units.cpp:348
Ui::FormUnitsView ui
Definition: view_units.h:70
int max_row
Definition: view_units.h:67
int curr_row
Definition: view_units.h:66
void update_view()
Refresh all widgets for units view.
Definition: view_units.cpp:133
void update_units()
Updates the units table.
Definition: view_units.cpp:146
void find_nearest()
Find nearest selected unit, closest units view when button is clicked.
Definition: view_units.cpp:539
int counter
Definition: view_units.h:69
units_view()
Constructor for units view.
Definition: view_units.cpp:39
void upgrade_units()
Upgrade selected units.
Definition: view_units.cpp:568
void selection_changed(const QItemSelection &sl, const QItemSelection &ds)
Action for selection changed in units view.
Definition: view_units.cpp:451
~units_view()
Destructor for units view.
Definition: view_units.cpp:123
bool client_has_player()
Either controlling or observing.
struct player * client_player()
Either controlling or observing.
struct civclient client
struct city * get_nearest_city(const struct unit *punit, int *sq_dist)
Find city nearest to given unit and optionally return squared city distance Parameter sq_dist may be ...
Definition: climisc.cpp:980
struct universal cid_decode(cid id)
Decode the CID into a city_production structure.
Definition: climisc.cpp:478
cid cid_encode_unit(const struct unit_type *punittype)
Encode a CID for the target unit type.
Definition: climisc.cpp:456
int cid
Definition: climisc.h:21
void unit_focus_set_and_select(struct unit *punit)
The only difference is that here we draw the "cross".
Definition: control.cpp:563
class fc_client * king()
Return fc_client instance.
Definition: gui_main.cpp:58
int Unit_type_id
Definition: fc_types.h:299
@ O_SHIELD
Definition: fc_types.h:86
@ O_FOOD
Definition: fc_types.h:85
@ O_GOLD
Definition: fc_types.h:88
#define PL_(String1, String2, n)
Definition: fcintl.h:54
#define _(String)
Definition: fcintl.h:50
bool can_unit_move_now(const struct unit *punit)
Returns if unit can move now.
Definition: goto.cpp:56
constexpr auto LOG_VERBOSE
Definition: log.h:26
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_action(condition, action)
Definition: log.h:104
int sq_map_distance(const struct tile *tile0, const struct tile *tile1)
Return squared distance between two tiles.
Definition: map.cpp:610
pageGame * queen()
Return game instandce.
Definition: page_game.cpp:557
#define players_iterate_end
Definition: player.h:520
#define players_iterate(_pplayer)
Definition: player.h:514
void disband_all_units(const struct unit_type *punittype, bool in_cities_only, char *message, size_t message_sz)
Disband all supported units of the given type.
#define FC_INFINITY
Definition: shared.h:32
size_t size
Definition: specvec.h:64
Definition: city.h:291
struct connection conn
Definition: client_main.h:89
struct player * playing
Definition: connection.h:142
enum entry_type type
Definition: climisc.h:66
struct unit_list * units
Definition: player.h:264
Definition: tile.h:42
Structure of data for the Units View.
Definition: view_units.h:25
Structure of unit waiting data for the Units View.
Definition: view_units.h:36
Definition: unit.h:134
enum unit_activity activity
Definition: unit.h:154
struct tile * tile
Definition: unit.h:136
const struct unit_type * utype
Definition: unit.h:135
universals_u value
Definition: fc_types.h:739
const QString get_nearest_city_text(struct city *pcity, int sq_dist)
Returns the text describing the city and its distance.
Definition: text.cpp:522
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
QPixmap * tiles_lookup_sprite_tag_alt(struct tileset *t, QtMsgType level, const char *tag, const char *alt, const char *what, const char *name, bool scale)
Lookup sprite to match tag, or else to match alt if don't find, or else return nullptr,...
Definition: tilespec.cpp:2724
void top_bar_show_map()
Callback to show map.
Definition: top_bar.cpp:448
QString format_simple_duration(int seconds)
Formats a duration without switching to "until hh::mm" when more than one hour in the future.
const struct unit_type * utype
Definition: fc_types.h:585
bool can_unit_do_activity(const struct unit *punit, enum unit_activity activity)
Return TRUE iff the unit can do the given untargeted activity at its current location.
Definition: unit.cpp:806
#define unit_tile(_pu)
Definition: unit.h:371
@ FOCUS_AVAIL
Definition: unit.h:46
#define unit_list_iterate(unitlist, punit)
Definition: unitlist.h:25
#define unit_list_iterate_end
Definition: unitlist.h:27
const struct unit_type * unit_type_get(const struct unit *punit)
Return the unit type for this unit.
Definition: unittype.cpp:114
struct unit_type * utype_by_number(const Unit_type_id id)
Return a pointer for the unit type struct for the given unit type id.
Definition: unittype.cpp:103
const struct unit_type * can_upgrade_unittype(const struct player *pplayer, const struct unit_type *punittype)
Return whether this player can upgrade this unit type (to any other unit type).
Definition: unittype.cpp:1379
const char * utype_name_translation(const struct unit_type *punittype)
Return the (translated) name of the unit type.
Definition: unittype.cpp:1256
Unit_type_id utype_number(const struct unit_type *punittype)
Return the unit type index.
Definition: unittype.cpp:91
int unit_upgrade_price(const struct player *pplayer, const struct unit_type *from, const struct unit_type *to)
Return the cost (gold) of upgrading a single unit of the specified type to the new type.
Definition: unittype.cpp:1407
#define unit_type_iterate(_p)
Definition: unittype.h:785
#define unit_type_iterate_end
Definition: unittype.h:791
struct tile * get_center_tile_mapcanvas()
Finds the current center tile of the mapcanvas.
std::vector< unit_waiting_entry > get_units_waiting_data()
Returns an array of units subject to unitwaittime.
Definition: view_units.cpp:718
std::vector< unit_view_entry > get_units_view_data()
Returns an array of units data.
Definition: view_units.cpp:643
void units_view_dialog_update(void *unused)
Update the units view.
Definition: view_units.cpp:758
void popdown_units_view()
Closes units view.
Definition: view_units.cpp:808
struct unit * find_nearest_unit(const struct unit_type *utype, struct tile *ptile)
Function to help us find the nearest unit.
Definition: view_units.cpp:608
void units_view_dialog_popup()
Display the unis view.
Definition: view_units.cpp:780