Freeciv21
Develop your civilization from humble roots to a global empire
hudwidget.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 "hudwidget.h"
12 // Qt
13 #include <QComboBox>
14 #include <QDialogButtonBox>
15 #include <QGroupBox>
16 #include <QHeaderView>
17 #include <QKeyEvent>
18 #include <QPainter>
19 #include <QRadioButton>
20 #include <QVBoxLayout>
21 // common
22 #include "movement.h"
23 #include "nation.h"
24 #include "research.h"
25 #include "shortcuts.h"
26 #include "tile.h"
27 #include "tileset/tilespec.h"
28 #include "unit.h"
29 #include "unitlist.h"
30 // client
31 #include "calendar.h"
32 #include "canvas.h"
33 #include "client_main.h"
34 #include "fc_client.h"
35 #include "fonts.h"
36 #include "goto.h"
37 #include "icons.h"
38 #include "page_game.h"
39 #include "text.h"
40 #include "tileset/sprite.h"
41 #include "top_bar.h"
42 #include "views/view_map.h"
43 #include "views/view_map_common.h"
44 #include "widgets/decorations.h"
45 
46 static QString popup_terrain_info(struct tile *ptile);
47 
52 {
54  {
55  if (utype_number(punit->utype) == utype) {
56  return true;
57  }
58  }
60 
61  return false;
62 }
63 
67 hud_message_box::hud_message_box(QWidget *parent) : QMessageBox(parent)
68 {
69  setWindowFlag(Qt::FramelessWindowHint);
70 
73 
74  auto size = f_text.pointSize();
75  if (size > 0) {
76  f_text.setPointSize(size * 4 / 3);
77  f_title.setPointSize(size * 3 / 2);
78  } else {
79  size = f_text.pixelSize();
80  f_text.setPixelSize(size * 4 / 3);
81  f_title.setPointSize(size * 3 / 2);
82  }
83  f_title.setBold(true);
84  f_title.setCapitalization(QFont::SmallCaps);
85  fm_text = new QFontMetrics(f_text);
86  fm_title = new QFontMetrics(f_title);
87  top = 0;
88  m_animate_step = 0;
89  mult = 1;
90 }
91 
96 {
97  delete fm_text;
98  delete fm_title;
99 }
100 
105 {
106  if (event->key() == Qt::Key_Escape) {
107  close();
108  destroy();
109  event->accept();
110  }
111  QWidget::keyPressEvent(event);
112 }
113 
117 void hud_message_box::set_text_title(const QString &s1, const QString &s2)
118 {
119  QSpacerItem *spacer;
120  QGridLayout *layout;
121  int w, w2, h;
122 
123  if (s1.contains('\n')) {
124  int i;
125  i = s1.indexOf('\n');
126  cs1 = s1.left(i);
127  cs2 = s1.right(s1.count() - i);
128  mult = 2;
129  w2 = qMax(fm_text->horizontalAdvance(cs1),
130  fm_text->horizontalAdvance(cs2));
131  w = qMax(w2, fm_title->horizontalAdvance(s2));
132  } else {
133  w = qMax(fm_text->horizontalAdvance(s1),
134  fm_title->horizontalAdvance(s2));
135  }
136  w = w + 20;
137  h = mult * (fm_text->height() * 3 / 2) + 2 * fm_title->height();
138  top = 2 * fm_title->height();
139  spacer =
140  new QSpacerItem(w, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
141  layout = (QGridLayout *) this->layout();
142  layout->addItem(spacer, layout->rowCount(), 0, 1, layout->columnCount());
143  spacer =
144  new QSpacerItem(0, h, QSizePolicy::Expanding, QSizePolicy::Minimum);
145  layout->addItem(spacer, 0, 0, 1, layout->columnCount());
146 
147  text = s1;
148  title = s2;
149 
150  m_timer.start();
151  startTimer(45);
152 }
153 
158 {
159  m_animate_step = m_timer.elapsed() / 40;
160  update();
161 }
162 
167 {
168  QPainter p;
169  QRect rx, ry, rfull;
170  QLinearGradient g;
171  QColor c1;
172  QColor c2;
173  int step;
174 
175  step = m_animate_step % 300;
176  if (step > 150) {
177  step = step - 150;
178  step = 150 - step;
179  }
180  step = step + 30;
181 
182  rfull = QRect(2, 2, width() - 4, height() - 4);
183  rx = QRect(2, 2, width() - 4, top);
184  ry = QRect(2, top, width() - 4, height() - top - 4);
185 
186  c1 = QColor(palette().color(QPalette::Highlight));
187  c2 = QColor(palette().color(QPalette::AlternateBase));
188  step = qMax(0, step);
189  step = qMin(255, step);
190  c1.setAlpha(step);
191  c2.setAlpha(step);
192 
193  g = QLinearGradient(0, 0, width(), height());
194  g.setColorAt(0, c1);
195  g.setColorAt(1, c2);
196 
197  p.begin(this);
198  p.fillRect(rx, QColor(palette().color(QPalette::Highlight)));
199  p.fillRect(ry, QColor(palette().color(QPalette::AlternateBase)));
200  p.fillRect(rfull, g);
201  p.setFont(f_title);
202  p.drawText((width() - fm_title->horizontalAdvance(title)) / 2,
203  fm_title->height() * 4 / 3, title);
204  p.setFont(f_text);
205  if (mult == 1) {
206  p.drawText((width() - fm_text->horizontalAdvance(text)) / 2,
207  2 * fm_title->height() + fm_text->height() * 4 / 3, text);
208  } else {
209  p.drawText((width() - fm_text->horizontalAdvance(cs1)) / 2,
210  2 * fm_title->height() + fm_text->height() * 4 / 3, cs1);
211  p.drawText((width() - fm_text->horizontalAdvance(cs2)) / 2,
212  2 * fm_title->height() + fm_text->height() * 8 / 3, cs2);
213  }
214  p.end();
215  event->accept();
216 }
217 
221 hud_text::hud_text(const QString &s, int time_secs, QWidget *parent)
222  : QWidget(parent), text(s)
223 {
224  int size;
225 
226  timeout = time_secs;
227 
228  setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
230  f_text.setBold(true);
231  f_text.setCapitalization(QFont::SmallCaps);
232  size = f_text.pointSize();
233  if (size > 0) {
234  f_text.setPointSize(size * 2);
235  } else {
236  size = f_text.pixelSize();
237  f_text.setPixelSize(size * 2);
238  }
239  fm_text = new QFontMetrics(f_text);
240  m_animate_step = 0;
241  m_timer.start();
242  startTimer(46);
243  setAttribute(Qt::WA_TranslucentBackground);
244  setAttribute(Qt::WA_ShowWithoutActivating);
245  setAttribute(Qt::WA_TransparentForMouseEvents);
246  setFocusPolicy(Qt::NoFocus);
247 }
248 
253 {
254  show();
255  center_me();
256 }
257 
262 {
263  int w;
264  QPoint p;
265 
266  w = width();
267  if (!bound_rect.isEmpty()) {
268  setFixedSize(bound_rect.width(), bound_rect.height());
269  }
270  p = QPoint((parentWidget()->width() - w) / 2,
271  parentWidget()->height() / 20);
272  move(p);
273 }
274 
279 
283 void hud_text::timerEvent(QTimerEvent *event)
284 {
285  m_animate_step = m_timer.elapsed() / 40;
286  if (m_timer.elapsed() > timeout * 1000) {
287  close();
288  deleteLater();
289  }
290  update();
291 }
292 
296 void hud_text::paintEvent(QPaintEvent *event)
297 {
298  QPainter p;
299  QRect rfull;
300  QColor c1;
301  QColor c2;
302  float opacity;
303 
304  center_me();
305  if (m_timer.elapsed() < timeout * 500) {
306  opacity = static_cast<float>(m_timer.elapsed()) / (timeout * 300);
307  } else {
308  opacity = static_cast<float>(5000 - m_timer.elapsed()) / (timeout * 200);
309  }
310  opacity = qMin(1.0f, opacity);
311  opacity = qMax(0.0f, opacity);
312  rfull = QRect(0, 0, width(), height());
313  c1 = QColor(Qt::white);
314  c2 = QColor(35, 35, 35, 175);
315  c1.setAlphaF(c1.alphaF() * opacity);
316  c2.setAlphaF(c2.alphaF() * opacity);
317  p.begin(this);
318  p.setBrush(c2);
319  p.setPen(QColor(0, 0, 0, 0));
320  p.drawRoundedRect(rfull, height() / 6, height() / 6);
321  p.setFont(f_text);
322  p.setPen(c1);
323  p.drawText(rfull, Qt::AlignCenter, text, &bound_rect);
324 
325  p.end();
326 }
327 
331 hud_input_box::hud_input_box(QWidget *parent) : QDialog(parent)
332 {
333  int size;
334 
335  setWindowFlags(Qt::WindowStaysOnTopHint | Qt::Dialog
336  | Qt::FramelessWindowHint);
337 
340 
341  size = f_text.pointSize();
342  if (size > 0) {
343  f_text.setPointSize(size * 4 / 3);
344  f_title.setPointSize(size * 3 / 2);
345  } else {
346  size = f_text.pixelSize();
347  f_text.setPixelSize(size * 4 / 3);
348  f_title.setPointSize(size * 3 / 2);
349  }
350  f_title.setBold(true);
351  f_title.setCapitalization(QFont::SmallCaps);
352  fm_text = new QFontMetrics(f_text);
353  fm_title = new QFontMetrics(f_title);
354  top = 0;
355  m_animate_step = 0;
356  hide();
357  mult = 1;
358 }
359 
364 {
365  delete fm_text;
366  delete fm_title;
367 }
368 
373  const QString &s2,
374  const QString &def_input)
375 {
376  QSpacerItem *spacer;
377  QVBoxLayout *layout;
378  int w, w2, h;
379  QDialogButtonBox *button_box;
380  QPoint p;
381 
382  button_box = new QDialogButtonBox(
383  QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
384  layout = new QVBoxLayout;
385  if (s1.contains('\n')) {
386  int i;
387  i = s1.indexOf('\n');
388  cs1 = s1.left(i);
389  cs2 = s1.right(s1.count() - i);
390  mult = 2;
391  w2 = qMax(fm_text->horizontalAdvance(cs1),
392  fm_text->horizontalAdvance(cs2));
393  w = qMax(w2, fm_title->horizontalAdvance(s2));
394  } else {
395  w = qMax(fm_text->horizontalAdvance(s1),
396  fm_title->horizontalAdvance(s2));
397  }
398  w = w + 20;
399  h = mult * (fm_text->height() * 3 / 2) + 2 * fm_title->height();
400  top = 2 * fm_title->height();
401 
402  spacer =
403  new QSpacerItem(w, h, QSizePolicy::Expanding, QSizePolicy::Minimum);
404  layout->addItem(spacer);
405  layout->addWidget(&input_edit);
406  layout->addWidget(button_box);
407  input_edit.setFont(f_text);
408  input_edit.setText(def_input);
409  setLayout(layout);
410  QObject::connect(button_box, &QDialogButtonBox::accepted, this,
411  &QDialog::accept);
412  QObject::connect(button_box, &QDialogButtonBox::rejected, this,
413  &QDialog::reject);
414 
415  text = s1;
416  title = s2;
417  p = QPoint((parentWidget()->width() - w) / 2,
418  (parentWidget()->height() - h) / 2);
419  p = parentWidget()->mapToGlobal(p);
420  move(p);
421  input_edit.activateWindow();
422  input_edit.setFocus();
423  m_timer.start();
424  startTimer(41);
425  show();
426  update();
427 }
428 
433 {
434  m_animate_step = m_timer.elapsed() / 40;
435  update();
436 }
437 
442 {
443  QPainter p;
444  QRect rx, ry;
445  QLinearGradient g;
446  QColor c1;
447  QColor c2;
448  QColor c3;
449  int step;
450  float fstep;
451 
452  step = m_animate_step % 300;
453  if (step > 150) {
454  step = step - 150;
455  step = 150 - step;
456  }
457  step = step + 10;
458  rx = QRect(2, 2, width() - 4, top);
459  ry = QRect(2, top, width() - 4, height() - top - 4);
460 
461  c1 = QColor(palette().color(QPalette::Highlight));
462  c2 = QColor(Qt::transparent);
463  c3 = QColor(palette().color(QPalette::Highlight)).lighter(145);
464  step = qMax(0, step);
465  step = qMin(255, step);
466  c1.setAlpha(step);
467  c2.setAlpha(step);
468  c3.setAlpha(step);
469 
470  fstep = static_cast<float>(step) / 400;
471  g = QLinearGradient(0, 0, width(), height());
472  g.setColorAt(0, c2);
473  g.setColorAt(fstep, c3);
474  g.setColorAt(1, c2);
475 
476  p.begin(this);
477  p.fillRect(rx, QColor(palette().color(QPalette::Highlight)));
478  p.fillRect(ry, QColor(palette().color(QPalette::AlternateBase)));
479  p.fillRect(rx, g);
480  p.setFont(f_title);
481  p.drawText((width() - fm_title->horizontalAdvance(title)) / 2,
482  fm_title->height() * 4 / 3, title);
483  p.setFont(f_text);
484  if (mult == 1) {
485  p.drawText((width() - fm_text->horizontalAdvance(text)) / 2,
486  2 * fm_title->height() + fm_text->height() * 4 / 3, text);
487  } else {
488  p.drawText((width() - fm_text->horizontalAdvance(cs1)) / 2,
489  2 * fm_title->height() + fm_text->height() * 4 / 3, cs1);
490  p.drawText((width() - fm_text->horizontalAdvance(cs2)) / 2,
491  2 * fm_title->height() + fm_text->height() * 8 / 3, cs2);
492  }
493  p.end();
494  event->accept();
495 }
496 
500 hud_units::hud_units(QWidget *parent)
501  : QFrame(parent), ufont(nullptr), ul_units(nullptr),
502  current_tile(nullptr)
503 {
504  QVBoxLayout *vbox;
505  QVBoxLayout *unit_lab;
506  QSpacerItem *sp;
507  setParent(parent);
508 
509  main_layout = new QHBoxLayout;
510  sp = new QSpacerItem(50, 2);
511  vbox = new QVBoxLayout;
512  unit_lab = new QVBoxLayout;
513  unit_lab->setContentsMargins(6, 9, 0, 3);
514  vbox->setSpacing(0);
515  unit_lab->addWidget(&unit_label);
516  main_layout->addLayout(unit_lab);
517  main_layout->addWidget(&tile_label);
518  unit_icons = new unit_actions(this, nullptr);
519  vbox->addSpacerItem(sp);
520  vbox->addWidget(&text_label);
521  vbox->addWidget(unit_icons);
522  main_layout->addLayout(vbox);
523  main_layout->setSpacing(0);
524  main_layout->setSpacing(3);
525  main_layout->setContentsMargins(0, 0, 0, 0);
526  vbox->setSpacing(3);
527  vbox->setContentsMargins(0, 0, 0, 0);
528  setLayout(main_layout);
529  mw = new move_widget(this);
530  setFocusPolicy(Qt::ClickFocus);
531 }
532 
536 hud_units::~hud_units() = default;
537 
541 void hud_units::moveEvent(QMoveEvent *event)
542 {
544  static_cast<float>(event->pos().x()) / queen()->mapview_wdg->width();
546  static_cast<float>(event->pos().y()) / queen()->mapview_wdg->height();
547 }
548 
553 {
554  int num;
555  int wwidth;
556  int font_width;
557  int expanded_unit_width;
559  QFontMetrics *fm;
560  QImage cropped_img;
561  QImage img;
562  QPainter p;
563  QPixmap pix, pix2;
564  QRect crop, bounding_rect;
565  QString mp;
566  QString snum;
567  QString fraction1, fraction2;
568  QString text_str, move_pt_text;
569  QPixmap *tile_pixmap;
570  QPixmap *unit_pixmap;
571  struct city *pcity;
572  struct player *owner;
573  struct unit *punit;
574 
575  punit = head_of_units_in_focus();
576  if (punit == nullptr) {
577  hide();
578  return;
579  }
580 
581  font.setCapitalization(QFont::AllUppercase);
582  font.setBold(true);
583  setFixedHeight(parentWidget()->height() / 12);
584  text_label.setFixedHeight((height() * 2) / 10);
585 
586  move(qRound(queen()->mapview_wdg->width()
587  * king()->qt_settings.unit_info_pos_fx),
588  qRound((queen()->mapview_wdg->height()
589  * king()->qt_settings.unit_info_pos_fy)));
590  unit_icons->setFixedHeight((height() * 8) / 10);
591 
592  setUpdatesEnabled(false);
593 
594  owner = punit->owner;
595  pcity = player_city_by_number(owner, punit->homecity);
596  if (punit->name.isEmpty()) {
597  if (pcity == nullptr) {
598  // TRANS: <unit> #<unit id>
599  text_str = QString(_("%1 #%2"))
600  .arg(unit_name_translation(punit))
601  .arg(punit->id);
602  } else {
603  // TRANS: <unit> #<unit id> (<home city>)
604  text_str = QString(_("%1 #%2 (%3)"))
605  .arg(unit_name_translation(punit))
606  .arg(punit->id)
607  .arg(city_name_get(pcity));
608  }
609  } else {
610  if (pcity == nullptr) {
611  // TRANS: <unit> #<unit id> "<unit name>"
612  text_str = QString(_("%1 #%2 \"%3\""))
613  .arg(unit_name_translation(punit))
614  .arg(punit->id)
615  .arg(punit->name);
616  } else {
617  // TRANS: <unit> #<unit id> "<unit name>" (<home city>)
618  text_str = QString(_("%1 #%2 \"%3\" (%4)"))
619  .arg(unit_name_translation(punit))
620  .arg(punit->id)
621  .arg(punit->name)
622  .arg(city_name_get(pcity));
623  }
624  }
625  text_str = text_str + " ";
626  mp = QString(move_points_text(punit->moves_left, false));
627  if (utype_fuel(unit_type_get(punit))) {
628  // TRANS: T for turns
629  mp += " " + QString(_("(%1T)")).arg(punit->fuel - 1);
630  }
631  // TRANS: MP = Movement points
632  mp = QString(_("MP: ")) + mp;
633  text_str = text_str + mp + " ";
634  text_str += QString(_("HP:%1/%2"))
635  .arg(QString::number(punit->hp),
636  QString::number(unit_type_get(punit)->hp));
637  num = unit_list_size(punit->tile->units);
638  snum = QString::number(unit_list_size(punit->tile->units) - 1);
639  if (const auto n = get_units_in_focus().size(); n > 1) {
640  // TRANS: preserve leading space; always at least 2
641  text_str =
642  text_str
643  + QString(PL_(" (Selected %1 unit)", " (Selected %1 units)", n))
644  .arg(n);
645  } else if (num > 1) {
646  QByteArray ut_bytes;
647 
648  ut_bytes = snum.toLocal8Bit();
649  // TRANS: preserve leading space
650  text_str = text_str
651  + QString(PL_(" +%1 unit", " +%1 units", num - 1))
652  .arg(ut_bytes.data());
653  }
654  text_label.setTextFormat(Qt::PlainText);
655  text_label.setText(text_str);
656  font.setPixelSize((text_label.height() * 9) / 10);
657  text_label.setFont(font);
658  fm = new QFontMetrics(font);
659  text_label.setFixedWidth(fm->horizontalAdvance(text_str) + 20);
660  delete fm;
661 
662  unit_pixmap =
664  unit_pixmap->fill(Qt::transparent);
665  put_unit(punit, unit_pixmap, QPoint());
666  img = unit_pixmap->toImage();
667  crop = zealous_crop_rect(img);
668  cropped_img = img.copy(crop);
669  img = cropped_img.scaledToHeight(height(), Qt::SmoothTransformation);
670  expanded_unit_width = tileset_unit_width(tileset)
671  * ((height() + 0.0) / tileset_unit_height(tileset));
672  pix = QPixmap::fromImage(img);
673  /* add transparent borders if image is too slim, accounting for the
674  * scaledToHeight() we've applied */
675  if (pix.width() < expanded_unit_width) {
676  pix2 = QPixmap(expanded_unit_width, pix.height());
677  pix2.fill(Qt::transparent);
678  p.begin(&pix2);
679  p.drawPixmap(expanded_unit_width / 2 - pix.width() / 2, 0, pix);
680  p.end();
681  pix = pix2;
682  }
683  // Draw movement points
684  move_pt_text = move_points_text(punit->moves_left, false);
685  if (move_pt_text.contains('/')) {
686  fraction2 = move_pt_text.right(1);
687  move_pt_text.remove(move_pt_text.count() - 2, 2);
688  fraction1 = move_pt_text.right(1);
689  move_pt_text.remove(move_pt_text.count() - 1, 1);
690  }
691  crop = QRect(5, 5, pix.width() - 5, pix.height() - 5);
692  font.setCapitalization(QFont::Capitalize);
693  font.setPointSize((pix.height() * 2) / 5);
694  p.begin(&pix);
695  p.setFont(font);
696  p.setPen(Qt::white);
697  p.drawText(crop, Qt::AlignLeft | Qt::AlignBottom, move_pt_text,
698  &bounding_rect);
699 
700  bounding_rect.adjust(bounding_rect.width(), 0, bounding_rect.width() * 2,
701  0);
702  if (punit->fuel > 1) {
703  int fuel;
704 
705  font.setPointSize(pix.height() / 4);
706  p.setFont(font);
707  fuel = punit->fuel - 1;
708  fuel = fuel * punit->utype->move_rate / SINGLE_MOVE;
709  p.drawText(bounding_rect, Qt::AlignCenter,
710  QStringLiteral("+") + QString::number(fuel));
711  }
712 
713  if (move_pt_text.isEmpty()) {
714  move_pt_text = QStringLiteral(" ");
715  }
716  bounding_rect =
717  p.boundingRect(crop, Qt::AlignLeft | Qt::AlignBottom, move_pt_text);
718  font.setPointSize(pix.height() / 5);
719  fm = new QFontMetrics(font);
720  font_width = (fm->horizontalAdvance(move_pt_text) * 3) / 5;
721  delete fm;
722  p.setFont(font);
723  if (!fraction1.isNull()) {
724  int t = 2 * font.pointSize();
725 
726  crop = QRect(bounding_rect.right() - font_width, bounding_rect.top(), t,
727  (t / 5) * 4);
728  p.drawText(crop, Qt::AlignLeft | Qt::AlignBottom, fraction1);
729  crop = QRect(bounding_rect.right() - font_width,
730  (bounding_rect.bottom() + bounding_rect.top()) / 2, t,
731  (t / 5) * 4);
732  p.drawText(crop, Qt::AlignLeft | Qt::AlignTop, fraction2);
733  crop = QRect(bounding_rect.right() - font_width,
734  (bounding_rect.bottom() + bounding_rect.top()) / 2 - t / 16,
735  (t * 2) / 5, t / 8);
736  p.fillRect(crop, Qt::white);
737  }
738  p.end();
739  wwidth = 2 * 3 + pix.width();
740  unit_label.setPixmap(pix);
742  tile_pixmap = new QPixmap(tileset_full_tile_width(tileset),
744  } else {
745  tile_pixmap = new QPixmap(tileset_full_tile_width(tileset),
747  }
748  tile_pixmap->fill(QColor(0, 0, 0, 0));
749  put_terrain(punit->tile, tile_pixmap, QPoint());
750  img = tile_pixmap->toImage();
751  crop = zealous_crop_rect(img);
752  cropped_img = img.copy(crop);
753  img = cropped_img.scaledToHeight(height() - 5, Qt::SmoothTransformation);
754  pix = QPixmap::fromImage(img);
755  tile_label.setPixmap(pix);
756  unit_label.setToolTip(popup_info_text(punit->tile));
757  tile_label.setToolTip(popup_terrain_info(punit->tile));
758  wwidth = wwidth + pix.width();
759  delete tile_pixmap;
760  delete unit_pixmap;
761 
762  setFixedWidth(wwidth
763  + qMax(unit_icons->update_actions() * (height() * 8) / 10,
764  text_label.width()));
765  mw->put_to_corner();
766  setUpdatesEnabled(true);
767  updateGeometry();
768  update();
769 
770  show();
771 }
772 
777 {
778  connect(this, &click_label::left_clicked, this,
780 }
781 
785 void click_label::mousePressEvent(QMouseEvent *e)
786 {
787  if (e->button() == Qt::LeftButton) {
788  emit left_clicked();
789  }
790 }
791 
796 {
799 }
800 
804 hud_action::hud_action(QWidget *parent, const QIcon &icon,
805  shortcut_id shortcut)
806  : QWidget(parent), icon(icon), action_shortcut(shortcut)
807 {
808  connect(this, &hud_action::left_clicked, this, &hud_action::mouse_clicked);
809  setFocusPolicy(Qt::StrongFocus);
810  setMouseTracking(true);
811  focus = false;
812 }
813 
817 void hud_action::paintEvent(QPaintEvent *event)
818 {
819  QPainter p;
820 
821  p.begin(this);
822  p.setRenderHint(QPainter::SmoothPixmapTransform);
823  if (focus) {
824  p.fillRect(rect(), QColor(palette().color(QPalette::Highlight)));
825  }
826  icon.paint(&p, rect());
827  p.end();
828 }
829 
834 
838 void hud_action::mousePressEvent(QMouseEvent *e)
839 {
840  if (e->button() == Qt::RightButton) {
841  emit right_clicked();
842  } else if (e->button() == Qt::LeftButton) {
843  emit left_clicked();
844  }
845 }
846 
851 {
852  focus = true;
853  update();
854 }
855 
860 {
861  focus = false;
862  update();
863  QWidget::leaveEvent(event);
864 }
865 
870 {
871  focus = true;
872  update();
873  QWidget::enterEvent(event);
874 }
875 
880 
885 {
886  // Only works if there's an action in the menu!
888 }
889 
893 unit_actions::unit_actions(QWidget *parent, unit *punit) : QWidget(parent)
894 {
895  layout = new QHBoxLayout(this);
896  layout->setSpacing(3);
897  layout->setContentsMargins(0, 0, 0, 0);
898  current_unit = punit;
899  init_layout();
900  setFocusPolicy(Qt::ClickFocus);
901 }
902 
907 {
908  qDeleteAll(actions);
909  actions.clear();
910 }
911 
916 {
917  QSizePolicy size_fixed_policy(QSizePolicy::MinimumExpanding,
918  QSizePolicy::Fixed, QSizePolicy::Frame);
919  setSizePolicy(size_fixed_policy);
920  layout->setSpacing(0);
921  setLayout(layout);
922 }
923 
928 {
930 
931  if (current_unit == nullptr || client.conn.playing == nullptr) {
932  clear_layout();
933  hide();
934  return 0;
935  }
936  /* HACK prevent crash with active goto when leaving widget,
937  * just skip update because with active goto actions shouldn't change */
938  if (goto_is_active()) {
939  return actions.count();
940  }
941  hide();
942  clear_layout();
943  setUpdatesEnabled(false);
944 
945  for (auto *a : qAsConst(actions)) {
946  delete a;
947  }
948  qDeleteAll(actions);
949  actions.clear();
950 
951  // Create possible actions
952 
954  actions.append(new hud_action(
955  this, fcIcons::instance()->getIcon(QStringLiteral("home")),
956  SC_BUILDCITY));
957  }
958 
959  if (can_unit_do_activity(current_unit, ACTIVITY_MINE)) {
960  actions.append(new hud_action(
961  this, fcIcons::instance()->getIcon(QStringLiteral("mine")),
962  SC_BUILDMINE));
963  }
964 
965  if (can_unit_do_activity(current_unit, ACTIVITY_PLANT)) {
966  actions.append(new hud_action(
967  this, fcIcons::instance()->getIcon(QStringLiteral("plantforest")),
968  SC_PLANT));
969  }
970 
971  if (can_unit_do_activity(current_unit, ACTIVITY_IRRIGATE)) {
972  actions.append(new hud_action(
973  this, fcIcons::instance()->getIcon(QStringLiteral("irrigation")),
975  }
976 
977  if (can_unit_do_activity(current_unit, ACTIVITY_CULTIVATE)) {
978  actions.append(new hud_action(
979  this, fcIcons::instance()->getIcon(QStringLiteral("chopchop")),
980  SC_CULTIVATE));
981  }
982 
983  if (can_unit_do_activity(current_unit, ACTIVITY_TRANSFORM)) {
984  actions.append(new hud_action(
985  this, fcIcons::instance()->getIcon(QStringLiteral("transform")),
986  SC_TRANSFORM));
987  }
988 
989  // Road
990  {
991  bool ok = false;
992  extra_type_by_cause_iterate(EC_ROAD, pextra)
993  {
994  struct road_type *proad = extra_road_get(pextra);
996  ok = true;
997  }
998  }
1000  if (ok) {
1001  actions.append(new hud_action(
1002  this, fcIcons::instance()->getIcon(QStringLiteral("buildroad")),
1003  SC_BUILDROAD));
1004  }
1005  }
1006  // Goto
1007  actions.append(new hud_action(
1008  this, fcIcons::instance()->getIcon(QStringLiteral("goto")), SC_GOTO));
1009 
1010  if (can_unit_do_activity(current_unit, ACTIVITY_FORTIFYING)) {
1011  actions.append(new hud_action(
1012  this, fcIcons::instance()->getIcon(QStringLiteral("fortify")),
1013  SC_FORTIFY));
1014  }
1015 
1016  if (can_unit_do_activity(current_unit, ACTIVITY_SENTRY)) {
1017  actions.append(new hud_action(
1018  this, fcIcons::instance()->getIcon(QStringLiteral("sentry")),
1019  SC_SENTRY));
1020  }
1021 
1022  // Load
1023  if (unit_can_load(current_unit)) {
1024  actions.append(new hud_action(
1025  this, fcIcons::instance()->getIcon(QStringLiteral("load")),
1026  SC_LOAD));
1027  }
1028 
1029  // Set homecity
1033  actions.append(new hud_action(
1034  this, fcIcons::instance()->getIcon(QStringLiteral("set_homecity")),
1035  SC_SETHOME));
1036  }
1037  }
1038 
1039  // Upgrade
1040  if (UU_OK == unit_upgrade_test(current_unit, false)) {
1041  actions.append(new hud_action(
1042  this, fcIcons::instance()->getIcon(QStringLiteral("upgrade")),
1043  SC_UPGRADE_UNIT));
1044  }
1045 
1046  // Automate
1048  actions.append(new hud_action(
1049  this, fcIcons::instance()->getIcon(QStringLiteral("automate")),
1050  SC_AUTOMATE));
1051  }
1052 
1053  // Paradrop
1055  actions.append(new hud_action(
1056  this, fcIcons::instance()->getIcon(QStringLiteral("paradrop")),
1057  SC_PARADROP));
1058  }
1059 
1060  // Pillage
1061  if (can_unit_do_activity(current_unit, ACTIVITY_PILLAGE)) {
1062  actions.append(new hud_action(
1063  this, fcIcons::instance()->getIcon(QStringLiteral("pillage")),
1064  SC_PILLAGE));
1065  }
1066 
1067  // Clean pollution
1068  if (can_unit_do_activity(current_unit, ACTIVITY_POLLUTION)) {
1069  actions.append(new hud_action(
1070  this, fcIcons::instance()->getIcon(QStringLiteral("pollution")),
1071  SC_PARADROP));
1072  }
1073 
1074  // Unload
1078  unit_tile(current_unit))) {
1079  actions.append(new hud_action(
1080  this, fcIcons::instance()->getIcon(QStringLiteral("unload")),
1081  SC_UNLOAD));
1082  }
1083 
1084  // Nuke
1085  if (unit_can_do_action(current_unit, ACTION_NUKE)) {
1086  actions.append(new hud_action(
1087  this, fcIcons::instance()->getIcon(QStringLiteral("nuke")),
1088  SC_NUKE));
1089  }
1090 
1091  // Clean nuclear fallout
1092  if (can_unit_do_activity(current_unit, ACTIVITY_FALLOUT)) {
1093  actions.append(new hud_action(
1094  this, fcIcons::instance()->getIcon(QStringLiteral("fallout")),
1095  SC_FALLOUT));
1096  }
1097 
1098  // Wait
1099  actions.append(new hud_action(
1100  this, fcIcons::instance()->getIcon(QStringLiteral("wait")), SC_WAIT));
1101 
1102  // Done moving
1103  actions.append(new hud_action(
1104  this, fcIcons::instance()->getIcon(QStringLiteral("done")),
1105  SC_DONE_MOVING));
1106 
1107  for (auto *a : qAsConst(actions)) {
1108  const auto shortcut =
1109  fc_shortcuts::sc()->get_shortcut(a->action_shortcut);
1110  if (shortcut.is_valid()) {
1111  // TRANS: Action (shortcut)
1112  a->setToolTip(
1113  QString(_("%1 (%2)")).arg(shortcut.str).arg(shortcut.to_string()));
1114  } else {
1115  a->setToolTip(shortcut.str);
1116  }
1117 
1118  a->setFixedHeight(height());
1119  a->setFixedWidth(height());
1120  layout->addWidget(a);
1121  }
1122 
1123  setFixedWidth(actions.count() * height());
1124  setUpdatesEnabled(true);
1125  show();
1126  layout->update();
1127  updateGeometry();
1128  return actions.count();
1129 }
1130 
1135 {
1136  int i = actions.count();
1137  hud_action *ui;
1138  int j;
1139 
1140  setUpdatesEnabled(false);
1141  for (j = 0; j < i; j++) {
1142  ui = actions[j];
1143  layout->removeWidget(ui);
1144  delete ui;
1145  }
1146  while (!actions.empty()) {
1147  actions.removeFirst();
1148  }
1149  setUpdatesEnabled(true);
1150 }
1151 
1155 hud_unit_loader::hud_unit_loader(struct unit *pcargo, struct tile *ptile)
1156 {
1157  setShowGrid(false);
1158  setSelectionBehavior(QAbstractItemView::SelectRows);
1159  setEditTriggers(QAbstractItemView::NoEditTriggers);
1160  setSelectionMode(QAbstractItemView::SingleSelection);
1161  verticalHeader()->setVisible(false);
1162  horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
1163  horizontalHeader()->setVisible(false);
1164  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1165  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1166 
1167  connect(selectionModel(), &QItemSelectionModel::selectionChanged, this,
1169  cargo = pcargo;
1170  qtile = ptile;
1171 }
1172 
1177 
1183 {
1184  QTableWidgetItem *new_item;
1185  int max_size = 0;
1186  int i, j;
1187  int w, h;
1188 
1189  unit_list_iterate(qtile->units, ptransport)
1190  {
1191  if (can_unit_transport(ptransport, cargo)
1192  && get_transporter_occupancy(ptransport)
1193  < get_transporter_capacity(ptransport)) {
1194  transports.append(ptransport);
1195  max_size = qMax(max_size, get_transporter_occupancy(ptransport));
1196  }
1197  }
1199 
1200  setRowCount(transports.count() + 1);
1201  setColumnCount(max_size + 1);
1202  for (i = 0; i < transports.count(); i++) {
1203  auto sprite = get_unittype_sprite(tileset, transports.at(i)->utype,
1204  direction8_invalid());
1205  QString str = utype_rule_name(transports.at(i)->utype);
1206  // TRANS: MP - just movement points
1207  str += " ("
1208  + QString(move_points_text(transports.at(i)->moves_left, false))
1209  + _("MP") + ")";
1210  new_item = new QTableWidgetItem(QIcon(*sprite), str);
1211  setItem(i, 0, new_item);
1212  j = 1;
1213  unit_list_iterate(transports.at(i)->transporting, tunit)
1214  {
1215  sprite =
1216  get_unittype_sprite(tileset, tunit->utype, direction8_invalid());
1217  new_item = new QTableWidgetItem(QIcon(*sprite), QLatin1String(""));
1218  setItem(i, j, new_item);
1219  j++;
1220  }
1222  }
1223 
1224  // TRANS: Cancel loading unit into transport
1225  new_item =
1226  new QTableWidgetItem(QIcon::fromTheme("dialog-cancel"), _("Cancel"));
1227  setItem(transports.count(), 0, new_item);
1228 
1229  w = verticalHeader()->width() + 4;
1230  for (i = 0; i < columnCount(); i++) {
1231  w += columnWidth(i);
1232  }
1233  h = horizontalHeader()->height() + 4;
1234  for (i = 0; i < rowCount(); i++) {
1235  h += rowHeight(i);
1236  }
1237 
1238  resize(w, h);
1239  setWindowFlags(Qt::WindowStaysOnTopHint | Qt::Dialog
1240  | Qt::FramelessWindowHint);
1241  show();
1242 }
1243 
1247 void hud_unit_loader::selection_changed(const QItemSelection &s1,
1248  const QItemSelection &s2)
1249 {
1250  auto curr_row = s1.indexes().at(0).row();
1251  if (curr_row >= 0 && curr_row < transports.size()) {
1252  request_unit_load(cargo, transports[curr_row], qtile);
1253  }
1254  close();
1255 }
1256 
1260 QString popup_terrain_info(struct tile *ptile)
1261 {
1262  int movement_cost;
1263  struct terrain *terr;
1264  QString ret, t, move_text;
1265  bool has_road = false;
1266 
1267  terr = ptile->terrain;
1268  ret = QString(_("Terrain: %1\n")).arg(tile_get_info_text(ptile, true, 0));
1269  ret =
1270  ret
1271  + QString(_("Food/Prod/Trade: %1\n")).arg(get_tile_output_text(ptile));
1272  t = get_infrastructure_text(ptile->extras);
1273  if (t != QLatin1String("")) {
1274  ret = ret + QString(_("Infrastructure: %1\n")).arg(t);
1275  }
1276  ret = ret + QString(_("Defense bonus: %1%\n")).arg(terr->defense_bonus);
1277  movement_cost = terr->movement_cost;
1278 
1279  extra_type_by_cause_iterate(EC_ROAD, pextra)
1280  {
1281  struct road_type *proad = extra_road_get(pextra);
1282 
1283  if (tile_has_road(ptile, proad)) {
1284  if (proad->move_cost <= movement_cost) {
1285  has_road = true;
1286  move_text = move_points_text(proad->move_cost, true);
1287  movement_cost = proad->move_cost;
1288  }
1289  }
1290  }
1292 
1293  if (has_road) {
1294  ret = ret + QString(_("Movement cost: %1")).arg(move_text);
1295  } else {
1296  ret = ret + QString(_("Movement cost: %1")).arg(movement_cost);
1297  }
1298 
1299  return ret;
1300 }
1301 
1306 {
1307  QString s;
1308  hud_text *ht;
1309  QList<hud_text *> close_list;
1310  struct research *research;
1311  int i;
1312  char buf[25];
1313 
1314  if (!client_has_player() || !king()->qt_settings.show_new_turn_text) {
1315  return;
1316  }
1317  close_list = queen()->mapview_wdg->findChildren<hud_text *>();
1318  for (i = 0; i < close_list.size(); ++i) {
1319  close_list.at(i)->close();
1320  close_list.at(i)->deleteLater();
1321  }
1323  s = QString(_("Year: %1 (Turn: %2)"))
1324  .arg(calendar_text())
1325  .arg(game.info.turn)
1326  + "\n";
1327  s = s + QString(nation_plural_for_player(client_player()));
1328  s = s + " - "
1329  + QString(_("Population: %1"))
1332  && research->researching != A_NONE) {
1333  s = s + "\n"
1336  + " (" + QString::number(research->bulbs_researched) + "/"
1337  + QString::number(research->client.researching_cost) + ")";
1338  }
1339  s = s + "\n" + science_dialog_text() + "\n";
1340 
1341  /* Can't use QString().sprintf() as msys libintl.h defines sprintf() as a
1342  * macro */
1343  fc_snprintf(buf, sizeof(buf), "%+d",
1345 
1346  /* TRANS: current gold, then loss/gain per turn */
1347  s = s
1348  + QString(_("Gold: %1 (%2)"))
1350  .arg(buf);
1351  ht = new hud_text(s, 5, queen()->mapview_wdg);
1352  ht->show_me();
1353 }
1354 
1358 hud_unit_combat::hud_unit_combat(int attacker_unit_id, int defender_unit_id,
1359  int attacker_hp, int defender_hp,
1360  bool make_att_veteran,
1361  bool make_def_veteran, float scale,
1362  QWidget *parent)
1363  : QWidget(parent)
1364 {
1365  hud_scale = scale;
1366  att_hp = attacker_hp;
1367  def_hp = defender_hp;
1368 
1369  attacker = game_unit_by_number(attacker_unit_id);
1370  defender = game_unit_by_number(defender_unit_id);
1371  if (!attacker || !defender) {
1372  return;
1373  }
1376  att_veteran = make_att_veteran;
1377  def_veteran = make_def_veteran;
1380  if (defender_hp <= 0) {
1382  att_win = true;
1383  } else {
1385  def_win = true;
1386  }
1387  init_images();
1388 }
1389 
1394 {
1395  QImage crdimg, acrimg, at, dt;
1396  QRect dr, ar;
1397  QPainter p;
1398  int w;
1399 
1400  focus = false;
1401  w = 3 * hud_scale * tileset_unit_height(tileset) / 2;
1402  setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
1403  setFixedSize(2 * w, w);
1404  QPixmap defender_pixmap(tileset_unit_width(tileset),
1406  defender_pixmap.fill(Qt::transparent);
1407  if (defender != nullptr) {
1408  if (!redraw) {
1409  put_unit(defender, &defender_pixmap, QPoint());
1410  } else {
1411  defender_pixmap =
1412  *get_unittype_sprite(tileset, type_defender, direction8_invalid());
1413  }
1414  dimg = defender_pixmap.toImage();
1415  dr = zealous_crop_rect(dimg);
1416  crdimg = dimg.copy(dr);
1417  dimg = crdimg.scaledToHeight(w, Qt::SmoothTransformation);
1418  }
1419  if (dimg.width() < w) {
1420  dt = QImage(w, dimg.height(), QImage::Format_ARGB32_Premultiplied);
1421  dt.fill(Qt::transparent);
1422  p.begin(&dt);
1423  p.drawImage(w / 2 - dimg.width() / 2, 0, dimg);
1424  p.end();
1425  dimg = dt;
1426  }
1427  dimg = dimg.scaled(w, w, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1428  QPixmap attacker_pixmap(tileset_unit_width(tileset),
1430  attacker_pixmap.fill(Qt::transparent);
1431  if (attacker != nullptr) {
1432  if (!redraw) {
1433  put_unit(attacker, &attacker_pixmap, QPoint());
1434  } else {
1435  attacker_pixmap =
1436  *get_unittype_sprite(tileset, type_attacker, direction8_invalid());
1437  }
1438  aimg = attacker_pixmap.toImage();
1439  ar = zealous_crop_rect(aimg);
1440  acrimg = aimg.copy(ar);
1441  aimg = acrimg.scaledToHeight(w, Qt::SmoothTransformation);
1442  }
1443  if (aimg.width() < w) {
1444  at = QImage(w, dimg.height(), QImage::Format_ARGB32_Premultiplied);
1445  at.fill(Qt::transparent);
1446  p.begin(&at);
1447  p.drawImage(w / 2 - aimg.width() / 2, 0, aimg);
1448  p.end();
1449  aimg = at;
1450  }
1451  aimg = aimg.scaled(w, w, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1452 }
1453 
1458 {
1459  hud_scale = scale;
1460  init_images(true);
1461 }
1462 
1467 
1472 {
1473  fading = fade;
1474  update();
1475 }
1476 
1481 
1486 {
1487  QPainter p;
1488  QRect left, right;
1489  QColor c1, c2;
1490  QPen pen;
1492  QString ahploss, dhploss;
1493 
1494  // TRANS: HP - Hit Points
1495  ahploss = QString(_("%1 HP")).arg(-att_hp_loss);
1496  // TRANS: HP - Hit Points
1497  dhploss = QString(_("%1 HP")).arg(-def_hp_loss);
1498  f.setBold(true);
1499 
1500  if (def_hp == 0) {
1501  c1 = QColor(25, 125, 25, 175);
1502  c2 = QColor(125, 25, 25, 175);
1503  } else {
1504  c1 = QColor(125, 25, 25, 175);
1505  c2 = QColor(25, 125, 25, 175);
1506  }
1507  int w = 3 * tileset_unit_height(tileset) / 2 * hud_scale;
1508 
1509  left = QRect(0, 0, w, w);
1510  right = QRect(w, 0, w, w);
1511  pen = QPen(QColor(palette().color(QPalette::AlternateBase)), 2.0);
1512  p.begin(this);
1513  if (fading < 1.0) {
1514  p.setOpacity(fading);
1515  }
1516  if (focus) {
1517  p.fillRect(left, QColor(palette().color(QPalette::Highlight)));
1518  p.fillRect(right, QColor(palette().color(QPalette::Highlight)));
1519  c1.setAlpha(110);
1520  c2.setAlpha(110);
1521  }
1522  p.fillRect(left, c1);
1523  p.fillRect(right, c2);
1524  p.setPen(pen);
1525  p.drawRect(1, 1, width() - 2, height() - 2);
1526  p.drawImage(left, aimg);
1527  p.setFont(f);
1528  p.setPen(QColor(Qt::white));
1529  if (def_veteran) {
1530  // Gold for Veteran
1531  p.setPen(QColor(255, 215, 0, 255));
1532  p.drawText(right, Qt::AlignRight | Qt::AlignBottom | Qt::AlignAbsolute,
1533  _("V"));
1534  p.setPen(QColor(Qt::white));
1535  }
1536  if (att_veteran) {
1537  // Gold for Veteran
1538  p.setPen(QColor(255, 215, 0, 255));
1539  p.drawText(left, Qt::AlignRight | Qt::AlignBottom | Qt::AlignAbsolute,
1540  _("V"));
1541  p.setPen(QColor(Qt::white));
1542  }
1543  p.drawText(left, Qt::AlignHorizontal_Mask, ahploss);
1544  p.drawImage(right, dimg);
1545  p.drawText(right, Qt::AlignHorizontal_Mask, dhploss);
1546  if (def_win) {
1547  p.drawText(right, Qt::AlignBottom | Qt::AlignLeft | Qt::AlignAbsolute,
1548  _("Winner"));
1549  }
1550  if (att_win) {
1551  p.drawText(left, Qt::AlignBottom | Qt::AlignLeft | Qt::AlignAbsolute,
1552  _("Winner"));
1553  }
1554  p.end();
1555 }
1556 
1561 {
1563 }
1564 
1569 {
1570  focus = false;
1571  update();
1572 }
1573 
1578 {
1579  focus = true;
1580  update();
1581 }
1582 
1586 hud_battle_log::hud_battle_log(QWidget *parent) : QFrame(parent)
1587 {
1588  main_layout = new QVBoxLayout;
1589  mw = new move_widget(this);
1590 
1591  clw = new close_widget(this);
1592  clw->setFixedSize(12, 12);
1593 
1594  setContentsMargins(4, 4, 0, 0);
1595  sw = new scale_widget(QRubberBand::Rectangle, this);
1596  sw->show();
1597  scale = 1.0;
1598 }
1599 
1604 {
1605  delete sw;
1606  delete mw;
1607  delete clw;
1608 }
1609 
1614 {
1615  int w = 3 * tileset_unit_height(tileset) / 2 * scale;
1616 
1618  delete layout();
1619  main_layout = new QVBoxLayout;
1620  for (auto *hudc : qAsConst(lhuc)) {
1621  hudc->set_scale(scale);
1622  main_layout->addWidget(hudc);
1623  hudc->set_fading(1.0);
1624  }
1625  setFixedSize(2 * w + 15, lhuc.count() * w + 15);
1626  setLayout(main_layout);
1627 
1628  update();
1629  show();
1630  m_timer.restart();
1631  startTimer(50);
1632 }
1633 
1638 {
1639  scale = s;
1640  sw->scale = s;
1641 }
1642 
1647 {
1648  hud_unit_combat *hudc;
1649  int w = 3 * tileset_unit_height(tileset) / 2 * scale;
1650 
1651  delete layout();
1652  main_layout = new QVBoxLayout;
1653  lhuc.prepend(huc);
1654  while (lhuc.count() > 5) {
1655  hudc = lhuc.takeLast();
1656  delete hudc;
1657  }
1658  for (auto *hudc : qAsConst(lhuc)) {
1659  main_layout->addWidget(hudc);
1660  hudc->set_fading(1.0);
1661  }
1662  setFixedSize(2 * w + 15, lhuc.count() * w + 15);
1663  setLayout(main_layout);
1664 
1665  update();
1666  show();
1667  adjustSize();
1668  m_timer.restart();
1669  startTimer(50);
1670 }
1671 
1676 {
1677  if (scale != sw->scale) {
1678  scale = sw->scale;
1679  update_size();
1680  }
1681  clw->put_to_corner();
1682  mw->put_to_corner();
1683  sw->move(width() - sw->width() - 12, 0);
1684 }
1685 
1690 {
1691  QPoint p;
1692 
1693  p = pos();
1695  static_cast<float>(p.x()) / mapview.width;
1697  static_cast<float>(p.y()) / mapview.height;
1698  m_timer.restart();
1699 }
1700 
1705 {
1706  if (m_timer.elapsed() > 4000 && m_timer.elapsed() < 20000) {
1707  for (auto *hudc : qAsConst(lhuc)) {
1708  if (hudc->get_focus()) {
1709  m_timer.restart();
1710  for (auto *hupdate : qAsConst(lhuc)) {
1711  hupdate->set_fading(1.0);
1712  }
1713  return;
1714  }
1715  hudc->set_fading((20000.0 - m_timer.elapsed()) / 1000);
1716  }
1717  }
1718  if (m_timer.elapsed() >= 20000) {
1719  hide();
1720  }
1721 }
1722 
1727 {
1728  for (auto *hupdate : qAsConst(lhuc)) {
1729  hupdate->set_fading(1.0);
1730  }
1731  m_timer.restart();
1732  setVisible(true);
1733 }
const char * calendar_text()
Produce a statically allocated textual representation of the current calendar time.
Definition: calendar.cpp:137
QRect zealous_crop_rect(QImage &p)
Return rectangle containing pure image (crops transparency)
Definition: canvas.cpp:81
const char * city_name_get(const struct city *pcity)
Return the name of the city.
Definition: city.cpp:1077
void mousePressEvent(QMouseEvent *e) override
Mouse event for click_label.
Definition: hudwidget.cpp:785
void left_clicked()
void mouse_clicked()
Centers on current unit.
Definition: hudwidget.cpp:795
click_label()
Custom label with extra mouse events.
Definition: hudwidget.cpp:776
void put_to_corner()
Puts close widget to right top corner.
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
fc_settings qt_settings
Definition: fc_client.h:126
fc_shortcut get_shortcut(shortcut_id id) const
Returns shortcut for given id.
Definition: shortcuts.cpp:247
static fc_shortcuts * sc()
Returns given instance.
Definition: shortcuts.cpp:354
void invoke(shortcut_id id, map_view *mapview)
Invokes the action for a shortcut.
Definition: shortcuts.cpp:313
const QIcon icon
Definition: hudwidget.h:159
~hud_action() override
Hud action destructor.
Definition: hudwidget.cpp:833
void leaveEvent(QEvent *event) override
Leave event for hud_action, used to get status of pixmap higlight.
Definition: hudwidget.cpp:859
hud_action(QWidget *parent, const QIcon &icon, shortcut_id shortcut)
Hud action constructor, used to show one action.
Definition: hudwidget.cpp:804
void mousePressEvent(QMouseEvent *e) override
Mouse press event for hud_action.
Definition: hudwidget.cpp:838
void paintEvent(QPaintEvent *event) override
Custom painting for hud_action.
Definition: hudwidget.cpp:817
void enterEvent(QEvent *event) override
Enter event for hud_action, used to get status of pixmap higlight.
Definition: hudwidget.cpp:869
void right_clicked()
bool focus
Definition: hudwidget.h:160
void mouseMoveEvent(QMouseEvent *event) override
Mouse move event for hud_action, draw focus.
Definition: hudwidget.cpp:850
shortcut_id action_shortcut
Definition: hudwidget.h:165
void mouse_right_clicked()
Right click event for hud_action.
Definition: hudwidget.cpp:879
void left_clicked()
void mouse_clicked()
Left click event for hud_action.
Definition: hudwidget.cpp:884
void update_size()
Updates size when scale has changed.
Definition: hudwidget.cpp:1613
void moveEvent(QMoveEvent *event) override
Move event, saves current position.
Definition: hudwidget.cpp:1689
move_widget * mw
Definition: hudwidget.h:311
void timerEvent(QTimerEvent *event) override
Timer event.
Definition: hudwidget.cpp:1704
QElapsedTimer m_timer
Definition: hudwidget.h:312
void add_combat_info(hud_unit_combat *huc)
Adds combat information to battle log.
Definition: hudwidget.cpp:1646
~hud_battle_log() override
Hud battle log destructor.
Definition: hudwidget.cpp:1603
hud_battle_log(QWidget *parent)
Hud battle log contructor.
Definition: hudwidget.cpp:1586
QVBoxLayout * main_layout
Definition: hudwidget.h:291
void paintEvent(QPaintEvent *event) override
Paint event for hud battle log.
Definition: hudwidget.cpp:1675
close_widget * clw
Definition: hudwidget.h:310
scale_widget * sw
Definition: hudwidget.h:309
QList< hud_unit_combat * > lhuc
Definition: hudwidget.h:292
void set_scale(float s)
Set scale.
Definition: hudwidget.cpp:1637
void showEvent(QShowEvent *event) override
Show event, restart fading timer.
Definition: hudwidget.cpp:1726
QString cs1
Definition: hudwidget.h:131
int m_animate_step
Definition: hudwidget.h:125
QFont f_title
Definition: hudwidget.h:132
QElapsedTimer m_timer
Definition: hudwidget.h:111
QString cs2
Definition: hudwidget.h:131
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
QFontMetrics * fm_text
Definition: hudwidget.h:128
QFont f_text
Definition: hudwidget.h:130
hud_input_box(QWidget *parent)
Custom input box constructor.
Definition: hudwidget.cpp:331
void paintEvent(QPaintEvent *event) override
Paint event for custom input box.
Definition: hudwidget.cpp:441
void timerEvent(QTimerEvent *event) override
Timer event used to animate input box.
Definition: hudwidget.cpp:432
QLineEdit input_edit
Definition: hudwidget.h:118
QFontMetrics * fm_title
Definition: hudwidget.h:129
QString text
Definition: hudwidget.h:126
~hud_input_box() override
Custom input box destructor.
Definition: hudwidget.cpp:363
QString title
Definition: hudwidget.h:127
QFontMetrics * fm_text
Definition: hudwidget.h:70
QString title
Definition: hudwidget.h:69
QString text
Definition: hudwidget.h:68
QElapsedTimer m_timer
Definition: hudwidget.h:54
QString cs1
Definition: hudwidget.h:73
void set_text_title(const QString &s1, const QString &s2)
Sets text and title and shows message box.
Definition: hudwidget.cpp:117
hud_message_box(QWidget *parent)
Custom message box constructor.
Definition: hudwidget.cpp:67
int m_animate_step
Definition: hudwidget.h:67
void timerEvent(QTimerEvent *event) override
Timer event used to animate message box.
Definition: hudwidget.cpp:157
void keyPressEvent(QKeyEvent *event) override
Key press event for hud message box.
Definition: hudwidget.cpp:104
QFontMetrics * fm_title
Definition: hudwidget.h:71
~hud_message_box() override
Custom message box destructor.
Definition: hudwidget.cpp:95
QString cs2
Definition: hudwidget.h:73
void paintEvent(QPaintEvent *event) override
Paint event for custom message box.
Definition: hudwidget.cpp:166
QElapsedTimer m_timer
Definition: hudwidget.h:100
QString text
Definition: hudwidget.h:99
void paintEvent(QPaintEvent *event) override
Paint event for custom hud_text.
Definition: hudwidget.cpp:296
QFont f_text
Definition: hudwidget.h:102
int timeout
Definition: hudwidget.h:97
void timerEvent(QTimerEvent *event) override
Timer event, closes widget after timeout.
Definition: hudwidget.cpp:283
void center_me()
Moves to top center parent widget and sets size new size.
Definition: hudwidget.cpp:261
~hud_text() override
Destructor for hud text.
Definition: hudwidget.cpp:278
QRect bound_rect
Definition: hudwidget.h:96
void show_me()
Shows hud text.
Definition: hudwidget.cpp:252
QFontMetrics * fm_text
Definition: hudwidget.h:101
hud_text(const QString &s, int time_secs, QWidget *parent)
Hud text constructor takes text to display and time.
Definition: hudwidget.cpp:221
int m_animate_step
Definition: hudwidget.h:98
void set_fading(float fade)
Sets widget fading.
Definition: hudwidget.cpp:1471
void mousePressEvent(QMouseEvent *e) override
Mouse press event, centers on highlighted combat.
Definition: hudwidget.cpp:1560
hud_unit_combat(int attacker_unit_id, int defender_unit_id, int attacker_hp, int defender_hp, bool make_att_veteran, bool make_def_veteran, float scale, QWidget *parent)
Hud unit combat contructor, prepares images to show as result.
Definition: hudwidget.cpp:1358
struct unit * defender
Definition: hudwidget.h:274
void paintEvent(QPaintEvent *event) override
Paint event for hud_unit combat.
Definition: hudwidget.cpp:1485
void init_images(bool redraw=false)
Draws images of units to pixmaps for later use.
Definition: hudwidget.cpp:1393
struct unit * attacker
Definition: hudwidget.h:273
bool get_focus()
Returns true if widget has focus (used to prevent hiding parent)
Definition: hudwidget.cpp:1480
const struct unit_type * type_attacker
Definition: hudwidget.h:275
void set_scale(float scale)
Sets scale for images.
Definition: hudwidget.cpp:1457
struct tile * center_tile
Definition: hudwidget.h:277
void enterEvent(QEvent *event) override
Leave event for hud unit combat.
Definition: hudwidget.cpp:1577
~hud_unit_combat() override
Hud unit combat destructor.
const struct unit_type * type_defender
Definition: hudwidget.h:276
void leaveEvent(QEvent *event) override
Leave event for hud unit combat.
Definition: hudwidget.cpp:1568
hud_unit_loader(struct unit *pcargo, struct tile *ptile)
Constructor for widget allowing loading units on transports.
Definition: hudwidget.cpp:1155
~hud_unit_loader() override
Destructor for units loader.
struct tile * qtile
Definition: hudwidget.h:241
struct unit * cargo
Definition: hudwidget.h:240
QList< unit * > transports
Definition: hudwidget.h:230
void selection_changed(const QItemSelection &, const QItemSelection &)
Selects given tranport and closes widget.
Definition: hudwidget.cpp:1247
void show_me()
Shows unit loader, adds possible tranportsand units to table Calculates table size.
Definition: hudwidget.cpp:1182
QLabel text_label
Definition: hudwidget.h:207
hud_units(QWidget *parent)
Constructor for hud_units (holds layout for whole uunits info)
Definition: hudwidget.cpp:500
click_label unit_label
Definition: hudwidget.h:205
~hud_units() override
Hud_units destructor.
click_label tile_label
Definition: hudwidget.h:206
move_widget * mw
Definition: hudwidget.h:221
void update_actions()
Update possible action for given units.
Definition: hudwidget.cpp:552
QHBoxLayout * main_layout
Definition: hudwidget.h:209
unit_actions * unit_icons
Definition: hudwidget.h:210
void moveEvent(QMoveEvent *event) override
Move Event for hud_units, used to save position.
Definition: hudwidget.cpp:541
void center_on_tile(tile *tile, bool animate=true)
Centers the view on a tile.
Definition: view_map.cpp:197
void put_to_corner()
Puts move widget to left top corner.
Definition: decorations.cpp:99
map_view * mapview_wdg
Definition: page_game.h:81
unit_actions(QWidget *parent, unit *punit)
Units action contructor, holds possible hud_actions.
Definition: hudwidget.cpp:893
void clear_layout()
Cleans layout - run it before layout initialization.
Definition: hudwidget.cpp:1134
QList< hud_action * > actions
Definition: hudwidget.h:194
void init_layout()
Initiazlizes layout ( layout needs to be changed after adding units )
Definition: hudwidget.cpp:915
unit * current_unit
Definition: hudwidget.h:197
~unit_actions() override
Destructor for unit_actions.
Definition: hudwidget.cpp:906
int update_actions()
Updates avaialable actions, returns actions count.
Definition: hudwidget.cpp:927
QHBoxLayout * layout
Definition: hudwidget.h:193
bool client_has_player()
Either controlling or observing.
struct player * client_player()
Either controlling or observing.
struct civclient client
std::vector< unit * > & get_units_in_focus()
Returns list of units currently in focus.
Definition: control.cpp:169
void request_unit_load(struct unit *pcargo, struct unit *ptrans, struct tile *ptile)
Send a request to the server that the cargo be loaded into the transporter.
Definition: control.cpp:1934
void request_center_focus_unit()
Center to focus unit.
Definition: control.cpp:2254
struct unit * head_of_units_in_focus()
Return head of focus units list.
Definition: control.cpp:387
enum event_type event
Definition: events.cpp:68
#define extra_road_get(_e_)
Definition: extras.h:171
#define extra_type_by_cause_iterate_end
Definition: extras.h:307
#define extra_type_by_cause_iterate(_cause, _extra)
Definition: extras.h:299
class fc_client * king()
Return fc_client instance.
Definition: gui_main.cpp:58
int Unit_type_id
Definition: fc_types.h:299
#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 world wld
Definition: game.cpp:48
int civ_population(const struct player *pplayer)
Count the # of thousand citizen in a civilisation.
Definition: game.cpp:72
bool goto_is_active()
Is goto state active?
Definition: goto.cpp:302
static QString popup_terrain_info(struct tile *ptile)
Tooltip text for terrain information.
Definition: hudwidget.cpp:1260
bool has_player_unit_type(Unit_type_id utype)
Returns true if player has any unit of unit_type.
Definition: hudwidget.cpp:51
void show_new_turn_info()
Shows new turn information with big font.
Definition: hudwidget.cpp:1305
bool can_unit_exist_at_tile(const struct civ_map *nmap, const struct unit *punit, const struct tile *ptile)
Return TRUE iff the unit can "exist" at this location.
Definition: movement.cpp:267
bool unit_can_load(const struct unit *punit)
Return whether we can find a suitable transporter for given unit at current location.
Definition: movement.cpp:713
bool can_unit_transport(const struct unit *transporter, const struct unit *transported)
Return true iff transporter has ability to transport transported.
Definition: movement.cpp:684
const char * move_points_text(int mp, bool reduce)
Simple version of move_points_text_full() – render positive movement points as text without any prefi...
Definition: movement.cpp:856
#define SINGLE_MOVE
Definition: movement.h:17
const char *const default_font
Definition: fonts.h:18
const char *const notify_label
Definition: fonts.h:19
const char * nation_plural_for_player(const struct player *pplayer)
Return the (translated) plural noun of the given nation of a player.
Definition: nation.cpp:155
pageGame * queen()
Return game instandce.
Definition: page_game.cpp:557
int player_get_expected_income(const struct player *pplayer)
Return the expected net income of the player this turn.
Definition: player.cpp:1194
struct city * player_city_by_number(const struct player *pplayer, int city_id)
If the specified player owns the city with the specified id, return pointer to the city struct.
Definition: player.cpp:1113
struct research * research_get(const struct player *pplayer)
Returns the research structure associated with the player.
Definition: research.cpp:110
QString research_advance_name_translation(const struct research *presearch, Tech_type_id tech)
Store the translated name of the given tech (including A_FUTURE) in 'buf'.
Definition: research.cpp:257
bool can_build_road(struct road_type *proad, const struct unit *punit, const struct tile *ptile)
Tells if unit can build road on tile.
Definition: road.cpp:275
shortcut_id
Definition: shortcuts.h:33
@ SC_PARADROP
Definition: shortcuts.h:81
@ SC_UPGRADE_UNIT
Definition: shortcuts.h:62
@ SC_BUILDIRRIGATION
Definition: shortcuts.h:66
@ SC_BUILDCITY
Definition: shortcuts.h:69
@ SC_DONE_MOVING
Definition: shortcuts.h:56
@ SC_BUILDROAD
Definition: shortcuts.h:68
@ SC_CULTIVATE
Definition: shortcuts.h:67
@ SC_SENTRY
Definition: shortcuts.h:70
@ SC_NUKE
Definition: shortcuts.h:75
@ SC_SETHOME
Definition: shortcuts.h:63
@ SC_PLANT
Definition: shortcuts.h:65
@ SC_BUILDMINE
Definition: shortcuts.h:64
@ SC_TRANSFORM
Definition: shortcuts.h:74
@ SC_LOAD
Definition: shortcuts.h:76
@ SC_FALLOUT
Definition: shortcuts.h:94
@ SC_FORTIFY
Definition: shortcuts.h:71
@ SC_GOTO
Definition: shortcuts.h:72
@ SC_UNLOAD
Definition: shortcuts.h:77
@ SC_WAIT
Definition: shortcuts.h:73
@ SC_AUTOMATE
Definition: shortcuts.h:80
@ SC_PILLAGE
Definition: shortcuts.h:93
int step
Definition: specpq.h:83
size_t size
Definition: specvec.h:64
Definition: city.h:291
struct packet_game_info info
Definition: game.h:80
struct connection conn
Definition: client_main.h:89
struct player * playing
Definition: connection.h:142
float unit_info_pos_fx
Definition: fc_client.h:67
float unit_info_pos_fy
Definition: fc_client.h:68
float battlelog_scale
Definition: fc_client.h:73
float battlelog_x
Definition: fc_client.h:74
float battlelog_y
Definition: fc_client.h:75
Definition: mapimg.cpp:266
Definition: player.h:231
struct unit_list * units
Definition: player.h:264
struct player_economic economic
Definition: player.h:266
Tech_type_id researching
Definition: research.h:45
struct research::@71::@73 client
int bulbs_researched
Definition: research.h:46
Definition: road.h:54
int move_cost
Definition: road.h:57
int defense_bonus
Definition: terrain.h:186
int movement_cost
Definition: terrain.h:185
Definition: tile.h:42
bv_extras extras
Definition: tile.h:47
struct unit_list * units
Definition: tile.h:50
struct terrain * terrain
Definition: tile.h:49
int move_rate
Definition: unittype.h:481
Definition: unit.h:134
int moves_left
Definition: unit.h:147
int id
Definition: unit.h:141
int hp
Definition: unit.h:148
int fuel
Definition: unit.h:150
struct tile * tile
Definition: unit.h:136
QString name
Definition: unit.h:143
int homecity
Definition: unit.h:142
const struct unit_type * utype
Definition: unit.h:135
struct player * owner
Definition: unit.h:139
int height
int width
struct civ_map map
Definition: world_object.h:21
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
#define A_NONE
Definition: tech.h:36
#define A_UNSET
Definition: tech.h:41
#define A_UNKNOWN
Definition: tech.h:42
const char * get_infrastructure_text(bv_extras extras)
Return a (static) string with extra(s) name(s): eg: "Mine" eg: "Road/Farmland" This only includes "in...
Definition: terrain.cpp:394
const QString science_dialog_text()
Returns the text to display in the science dialog.
Definition: text.cpp:812
const QString popup_info_text(struct tile *ptile)
Text to popup on a middle-click in the mapview.
Definition: text.cpp:137
const QString get_tile_output_text(const struct tile *ptile)
Return a (static) string with a tile's food/prod/trade.
Definition: text.cpp:52
const char * tile_get_info_text(const struct tile *ptile, bool include_nuisances, int linebreaks)
Return a (static) string with tile name describing terrain and extras of some categories.
Definition: tile.cpp:799
bool tile_has_road(const struct tile *ptile, const struct road_type *proad)
Returns TRUE if the given tile has a road of given type on it.
Definition: tile.cpp:868
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_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
bool tileset_is_isometric(const struct tileset *t)
Return whether the current tileset is isometric.
Definition: tilespec.cpp:336
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
int tileset_tile_height(const struct tileset *t)
Return the tile height of the current tileset.
Definition: tilespec.cpp:383
int tileset_full_tile_width(const struct tileset *t)
Return the full tile width of the current tileset.
Definition: tilespec.cpp:394
void top_bar_show_map()
Callback to show map.
Definition: top_bar.cpp:448
int get_transporter_occupancy(const struct unit *ptrans)
Return how many units are in the transport.
Definition: unit.cpp:1647
enum unit_upgrade_result unit_upgrade_test(const struct unit *punit, bool is_free)
Tests if the unit could be updated.
Definition: unit.cpp:1826
bool can_unit_paradrop(const struct unit *punit)
Return whether the unit can be paradropped - that is, if the unit is in a friendly city or on an airb...
Definition: unit.cpp:772
bool unit_can_add_or_build_city(const struct unit *punit)
Return TRUE iff this unit can add to a current city or build a new city at its current location.
Definition: unit.cpp:399
bool can_unit_change_homecity_to(const struct unit *punit, const struct city *pcity)
Return TRUE iff the unit can change homecity to the given city.
Definition: unit.cpp:415
struct unit * unit_transport_get(const struct unit *pcargo)
Returns the transporter of the unit or nullptr if it is not transported.
Definition: unit.cpp:2189
bool can_unit_do_autosettlers(const struct unit *punit)
Return whether the unit can be put in auto-settler mode.
Definition: unit.cpp:548
bool unit_can_do_action(const struct unit *punit, const action_id act_id)
Return TRUE iff this unit can do the specified generalized (ruleset defined) action enabler controlle...
Definition: unit.cpp:309
int get_transporter_capacity(const struct unit *punit)
Return the number of units the transporter can hold (or 0).
Definition: unit.cpp:280
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
bool unit_transported(const struct unit *pcargo)
Returns TRUE iff the unit is transported.
Definition: unit.cpp:2176
bool can_unit_unload(const struct unit *pcargo, const struct unit *ptrans)
Return TRUE iff the given unit can be unloaded from its current transporter.
Definition: unit.cpp:720
#define unit_tile(_pu)
Definition: unit.h:371
@ UU_OK
Definition: unit.h:49
#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
const char * utype_rule_name(const struct unit_type *punittype)
Return the (untranslated) rule name of the unit type.
Definition: unittype.cpp:1274
Unit_type_id utype_number(const struct unit_type *punittype)
Return the unit type index.
Definition: unittype.cpp:91
const char * unit_name_translation(const struct unit *punit)
Return the (translated) name of the unit.
Definition: unittype.cpp:1265
#define utype_fuel(ptype)
Definition: unittype.h:772
struct view mapview
void put_terrain(struct tile *ptile, QPixmap *pcanvas, const QPoint &canvas_loc)
Draw the given tile terrain onto the canvas store at the given location.
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.