webperimental: killstack decides stack protects.
[freeciv.git] / client / gui-qt / hudwidget.cpp
blob2a1bfe810cc89f19478d00264ef253acaa1929b8
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 // Qt
19 #include <QAction>
20 #include <QApplication>
21 #include <QComboBox>
22 #include <QDialogButtonBox>
23 #include <QGridLayout>
24 #include <QGroupBox>
25 #include <QHBoxLayout>
26 #include <QHeaderView>
27 #include <QLineEdit>
28 #include <QPainter>
29 #include <QPaintEvent>
30 #include <QRadioButton>
31 #include <QSpacerItem>
32 #include <QVBoxLayout>
34 // common
35 #include "movement.h"
36 #include "research.h"
37 #include "tile.h"
38 #include "unit.h"
39 #include "unitlist.h"
41 // client
42 #include "client_main.h"
43 #include "text.h"
45 // gui-qt
46 #include "fc_client.h"
47 #include "fonts.h"
48 #include "hudwidget.h"
49 #include "sprite.h"
51 extern "C" {
52 const char *calendar_text(void);
54 static QString popup_terrain_info(struct tile *ptile);
56 /***************************************************************************
57 Returns true if player has any unit of unit_type
58 ***************************************************************************/
59 bool has_player_unit_type(Unit_type_id utype)
61 unit_list_iterate(client.conn.playing->units, punit) {
62 if (utype_number(punit->utype) == utype) {
63 return true;
65 } unit_list_iterate_end;
67 return false;
70 /****************************************************************************
71 Custom message box constructor
72 ****************************************************************************/
73 hud_message_box::hud_message_box(QWidget *parent): QMessageBox(parent)
75 int size;
76 setWindowFlags(Qt::WindowStaysOnTopHint | Qt::Dialog
77 | Qt::FramelessWindowHint);
78 f_text = *fc_font::instance()->get_font(fonts::default_font);
79 f_title = *fc_font::instance()->get_font(fonts::default_font);
81 size = f_text.pointSize();
82 if (size > 0) {
83 f_text.setPointSize(size * 4 / 3);
84 f_title.setPointSize(size * 3 / 2);
85 } else {
86 size = f_text.pixelSize();
87 f_text.setPixelSize(size * 4 / 3);
88 f_title.setPointSize(size * 3 / 2);
90 f_title.setBold(true);
91 f_title.setCapitalization(QFont::SmallCaps);
92 fm_text = new QFontMetrics(f_text);
93 fm_title = new QFontMetrics(f_title);
94 top = 0;
95 m_animate_step = 0;
96 hide();
97 mult = 1;
100 /****************************************************************************
101 Custom message box destructor
102 ****************************************************************************/
103 hud_message_box::~hud_message_box()
105 delete fm_text;
106 delete fm_title;
108 /****************************************************************************
109 Key press event for hud message box
110 ****************************************************************************/
111 void hud_message_box::keyPressEvent(QKeyEvent *event)
113 if (event->key() == Qt::Key_Escape) {
114 close();
115 destroy();
116 event->accept();
118 QWidget::keyPressEvent(event);
121 /****************************************************************************
122 Sets text and title and shows message box
123 ****************************************************************************/
124 void hud_message_box::set_text_title(QString s1, QString s2)
126 QSpacerItem *spacer;
127 QGridLayout *layout;
128 int w, w2, h;
129 QPoint p;
131 if (s1.contains('\n')) {
132 int i;
133 i = s1.indexOf('\n');
134 cs1 = s1.left(i);
135 cs2 = s1.right(s1.count() - i);
136 mult = 2;
137 w2 = qMax(fm_text->width(cs1), fm_text->width(cs2));
138 w = qMax(w2, fm_title->width(s2));
139 } else {
140 w = qMax(fm_text->width(s1), fm_title->width(s2));
142 w = w + 20;
143 h = mult * (fm_text->height() * 3 / 2) + 2 * fm_title->height();
144 top = 2 * fm_title->height();
145 spacer = new QSpacerItem(w, 0, QSizePolicy::Minimum,
146 QSizePolicy::Expanding);
147 layout = (QGridLayout *)this->layout();
148 layout->addItem(spacer, layout->rowCount(), 0, 1, layout->columnCount());
149 spacer = new QSpacerItem(0, h, QSizePolicy::Expanding,
150 QSizePolicy::Minimum);
151 layout->addItem(spacer, 0, 0, 1, layout->columnCount());
153 text = s1;
154 title = s2;
156 p = QPoint((parentWidget()->width() - w) / 2,
157 (parentWidget()->height() - h) / 2);
158 p = parentWidget()->mapToGlobal(p);
159 move(p);
160 show();
161 m_timer.start();
162 startTimer(45);
165 /****************************************************************************
166 Timer event used to animate message box
167 ****************************************************************************/
168 void hud_message_box::timerEvent(QTimerEvent *event)
170 m_animate_step = m_timer.elapsed() / 40;
171 update();
174 /****************************************************************************
175 Paint event for custom message box
176 ****************************************************************************/
177 void hud_message_box::paintEvent(QPaintEvent *event)
179 QPainter p;
180 QRect rx, ry, rfull;
181 QLinearGradient g;
182 QColor c1;
183 QColor c2;
184 int step;
186 step = m_animate_step % 300;
187 if (step > 150) {
188 step = step - 150;
189 step = 150 - step;
191 step = step + 30;
193 rfull = QRect(2 , 2, width() - 4 , height() - 4);
194 rx = QRect(2 , 2, width() - 4 , top);
195 ry = QRect(2 , top, width() - 4, height() - top - 4);
197 c1 = QColor(palette().color(QPalette::Highlight));
198 c2 = QColor(palette().color(QPalette::AlternateBase));
199 step = qMax(0, step);
200 step = qMin(255, step);
201 c1.setAlpha(step);
202 c2.setAlpha(step);
204 g = QLinearGradient(0 , 0, width(), height());
205 g.setColorAt(0, c1);
206 g.setColorAt(1, c2);
208 p.begin(this);
209 p.fillRect(rx, QColor(palette().color(QPalette::Highlight)));
210 p.fillRect(ry, QColor(palette().color(QPalette::AlternateBase)));
211 p.fillRect(rfull, g);
212 p.setFont(f_title);
213 p.drawText((width() - fm_title->width(title)) / 2,
214 fm_title->height() * 4 / 3, title);
215 p.setFont(f_text);
216 if (mult == 1) {
217 p.drawText((width() - fm_text->width(text)) / 2,
218 2 * fm_title->height() + fm_text->height() * 4 / 3, text);
219 } else {
220 p.drawText((width() - fm_text->width(cs1)) / 2,
221 2 * fm_title->height() + fm_text->height() * 4 / 3, cs1);
222 p.drawText((width() - fm_text->width(cs2)) / 2,
223 2 * fm_title->height() + fm_text->height() * 8 / 3, cs2);
225 p.end();
226 event->accept();
229 /****************************************************************************
230 Hud text constructor takes text to display and time
231 ****************************************************************************/
232 hud_text::hud_text(QString s, int time_secs,
233 QWidget *parent) : QWidget(parent)
235 int size;
237 text = s;
238 timeout = time_secs;
240 setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
241 f_text = *fc_font::instance()->get_font(fonts::default_font);
242 f_text.setBold(true);
243 f_text.setCapitalization(QFont::SmallCaps);
244 size = f_text.pointSize();
245 if (size > 0) {
246 f_text.setPointSize(size * 2);
247 } else {
248 size = f_text.pixelSize();
249 f_text.setPixelSize(size * 2);
251 fm_text = new QFontMetrics(f_text);
252 m_animate_step = 0;
253 m_timer.start();
254 startTimer(46);
255 setAttribute(Qt::WA_TranslucentBackground);
256 setAttribute(Qt::WA_ShowWithoutActivating);
257 setAttribute(Qt::WA_TransparentForMouseEvents);
258 setFocusPolicy(Qt::NoFocus);
261 /****************************************************************************
262 Shows hud text
263 ****************************************************************************/
264 void hud_text::show_me()
266 show();
267 center_me();
270 /****************************************************************************
271 Moves to top center parent widget and sets size new size
272 ****************************************************************************/
273 void hud_text::center_me()
275 int w;
276 QPoint p;
277 w = width();
278 if (bound_rect.isEmpty() == false) {
279 setFixedSize(bound_rect.width(), bound_rect.height());
281 p = QPoint((parentWidget()->width() - w) / 2,
282 parentWidget()->height() / 20);
283 move(p);
286 /****************************************************************************
287 Destructor for hud text
288 ****************************************************************************/
289 hud_text::~hud_text()
291 delete fm_text;
294 /****************************************************************************
295 Timer event, closes widget after timeout
296 ****************************************************************************/
297 void hud_text::timerEvent(QTimerEvent *event)
299 m_animate_step = m_timer.elapsed() / 40;
300 if (m_timer.elapsed() > timeout * 1000) {
301 close();
302 deleteLater();
304 update();
307 /****************************************************************************
308 Paint event for custom hud_text
309 ****************************************************************************/
310 void hud_text::paintEvent(QPaintEvent *event)
312 QPainter p;
313 QRect rfull;
314 QColor c1;
315 QColor c2;
316 float opacity;
318 center_me();
319 if (m_timer.elapsed() < timeout * 500) {
320 opacity = static_cast<float>(m_timer.elapsed())/(timeout * 300);
321 } else {
322 opacity = static_cast<float>(5000 - m_timer.elapsed())/(timeout * 200);
324 opacity = qMin(1.0f, opacity);
325 opacity = qMax(0.0f, opacity);
326 rfull = QRect(0 , 0, width(), height());
327 c1 = QColor(Qt::white);
328 c2 = QColor(35, 35, 35, 175);
329 c1.setAlphaF(c1.alphaF() * opacity);
330 c2.setAlphaF(c2.alphaF() * opacity);
331 p.begin(this);
332 p.setBrush(c2);
333 p.setPen(QColor(0, 0, 0, 0));
334 p.drawRoundedRect(rfull, height() / 6 , height() / 6);
335 p.setFont(f_text);
336 p.setPen(c1);
337 p.drawText(rfull, Qt::AlignCenter, text, &bound_rect);
339 p.end();
342 /****************************************************************************
343 Custom input box constructor
344 ****************************************************************************/
345 hud_input_box::hud_input_box(QWidget *parent): QDialog(parent)
347 int size;
349 setWindowFlags(Qt::WindowStaysOnTopHint | Qt::Dialog
350 | Qt::FramelessWindowHint);
352 f_text = *fc_font::instance()->get_font(fonts::default_font);
353 f_title = *fc_font::instance()->get_font(fonts::default_font);
355 size = f_text.pointSize();
356 if (size > 0) {
357 f_text.setPointSize(size * 4 / 3);
358 f_title.setPointSize(size * 3 / 2);
359 } else {
360 size = f_text.pixelSize();
361 f_text.setPixelSize(size * 4 / 3);
362 f_title.setPointSize(size * 3 / 2);
364 f_title.setBold(true);
365 f_title.setCapitalization(QFont::SmallCaps);
366 fm_text = new QFontMetrics(f_text);
367 fm_title = new QFontMetrics(f_title);
368 top = 0;
369 m_animate_step = 0;
370 hide();
371 mult = 1;
374 /****************************************************************************
375 Custom input box destructor
376 ****************************************************************************/
377 hud_input_box::~hud_input_box()
379 delete fm_text;
380 delete fm_title;
382 /****************************************************************************
383 Sets text, title and default text and shows input box
384 ****************************************************************************/
385 void hud_input_box::set_text_title_definput(QString s1, QString s2,
386 QString def_input)
388 QSpacerItem *spacer;
389 QVBoxLayout *layout;
390 int w, w2, h;
391 QDialogButtonBox *button_box;
392 QPoint p;
394 button_box = new QDialogButtonBox(QDialogButtonBox::Ok
395 | QDialogButtonBox::Cancel,
396 Qt::Horizontal, this);
397 layout = new QVBoxLayout;
398 if (s1.contains('\n')) {
399 int i;
400 i = s1.indexOf('\n');
401 cs1 = s1.left(i);
402 cs2 = s1.right(s1.count() - i);
403 mult = 2;
404 w2 = qMax(fm_text->width(cs1), fm_text->width(cs2));
405 w = qMax(w2, fm_title->width(s2));
406 } else {
407 w = qMax(fm_text->width(s1), fm_title->width(s2));
409 w = w + 20;
410 h = mult * (fm_text->height() * 3 / 2) + 2 * fm_title->height();
411 top = 2 * fm_title->height();
413 spacer = new QSpacerItem(w, h, QSizePolicy::Expanding,
414 QSizePolicy::Minimum);
415 layout->addItem(spacer);
416 layout->addWidget(&input_edit);
417 layout->addWidget(button_box);
418 input_edit.setFont(f_text);
419 input_edit.setText(def_input);
420 setLayout(layout);
421 QObject::connect(button_box, SIGNAL(accepted()), this, SLOT(accept()));
422 QObject::connect(button_box, SIGNAL(rejected()), this, SLOT(reject()));
424 text = s1;
425 title = s2;
426 p = QPoint((parentWidget()->width() - w) / 2,
427 (parentWidget()->height() - h) / 2);
428 p = parentWidget()->mapToGlobal(p);
429 move(p);
430 input_edit.activateWindow();
431 input_edit.setFocus();
432 m_timer.start();
433 startTimer(41);
434 show();
435 update();
438 /****************************************************************************
439 Timer event used to animate input box
440 ****************************************************************************/
441 void hud_input_box::timerEvent(QTimerEvent *event)
443 m_animate_step = m_timer.elapsed() / 40;
444 update();
448 /****************************************************************************
449 Paint event for custom input box
450 ****************************************************************************/
451 void hud_input_box::paintEvent(QPaintEvent *event)
453 QPainter p;
454 QRect rx, ry;
455 QLinearGradient g;
456 QColor c1;
457 QColor c2;
458 QColor c3;
459 int step;
460 float fstep;
463 step = m_animate_step % 300;
464 if (step > 150) {
465 step = step - 150;
466 step = 150 - step;
468 step = step + 10;
469 rx = QRect(2 , 2, width() - 4 , top);
470 ry = QRect(2 , top, width() - 4, height() - top - 4);
472 c1 = QColor(palette().color(QPalette::Highlight));
473 c2 = QColor(Qt::transparent);
474 c3 = QColor(palette().color(QPalette::Highlight)).lighter(145);
475 step = qMax(0, step);
476 step = qMin(255, step);
477 c1.setAlpha(step);
478 c2.setAlpha(step);
479 c3.setAlpha(step);
481 fstep = static_cast<float>(step) / 400;
482 g = QLinearGradient(0 , 0, width(), height());
483 g.setColorAt(0, c2);
484 g.setColorAt(fstep, c3);
485 g.setColorAt(1, c2);
487 p.begin(this);
488 p.fillRect(rx, QColor(palette().color(QPalette::Highlight)));
489 p.fillRect(ry, QColor(palette().color(QPalette::AlternateBase)));
490 p.fillRect(rx, g);
491 p.setFont(f_title);
492 p.drawText((width() - fm_title->width(title)) / 2,
493 fm_title->height() * 4 / 3, title);
494 p.setFont(f_text);
495 if (mult == 1) {
496 p.drawText((width() - fm_text->width(text)) / 2,
497 2 * fm_title->height() + fm_text->height() * 4 / 3, text);
498 } else {
499 p.drawText((width() - fm_text->width(cs1)) / 2,
500 2 * fm_title->height() + fm_text->height() * 4 / 3, cs1);
501 p.drawText((width() - fm_text->width(cs2)) / 2,
502 2 * fm_title->height() + fm_text->height() * 8 / 3, cs2);
504 p.end();
505 event->accept();
508 /****************************************************************************
509 Constructor for hud_units (holds layout for whole uunits info)
510 ****************************************************************************/
511 hud_units::hud_units(QWidget *parent) : QFrame(parent)
513 QVBoxLayout *vbox;
514 QVBoxLayout *unit_lab;
515 QSpacerItem *sp;
516 setParent(parent);
518 main_layout = new QHBoxLayout;
519 sp = new QSpacerItem(50, 2);
520 vbox = new QVBoxLayout;
521 unit_lab = new QVBoxLayout;
522 unit_lab->setContentsMargins(6, 9, 0, 3);
523 vbox->setSpacing(0);
524 unit_lab->addWidget(&unit_label);
525 main_layout->addLayout(unit_lab);
526 main_layout->addWidget(&tile_label);
527 unit_icons = new unit_actions(this, nullptr);
528 vbox->addSpacerItem(sp);
529 vbox->addWidget(&text_label);
530 vbox->addWidget(unit_icons);
531 main_layout->addLayout(vbox);
532 main_layout->setSpacing(0);
533 main_layout->setSpacing(3);
534 main_layout->setContentsMargins(0, 0, 0, 0);
535 vbox->setSpacing(3);
536 vbox->setContentsMargins(0, 0, 0, 0);
537 setLayout(main_layout);
538 mw = new move_widget(this);
539 setFocusPolicy(Qt::ClickFocus);
543 /****************************************************************************
544 Hud_units destructor
545 ****************************************************************************/
546 hud_units::~hud_units()
551 /****************************************************************************
552 Move Event for hud_units, used to save position
553 ****************************************************************************/
554 void hud_units::moveEvent(QMoveEvent *event)
556 gui()->qt_settings.unit_info_pos_fx = static_cast<float>(event->pos().x())
557 / gui()->mapview_wdg->width();
558 gui()->qt_settings.unit_info_pos_fy = static_cast<float>(event->pos().y())
559 / gui()->mapview_wdg->height();
563 /****************************************************************************
564 Update possible action for given units
565 ****************************************************************************/
566 void hud_units::update_actions(unit_list *punits)
568 int num;
569 int wwidth;
570 int font_width;
571 QFont font = *fc_font::instance()->get_font(fonts::notify_label);
572 QFontMetrics *fm;
573 QImage cropped_img;
574 QImage img;
575 QPainter p;
576 QPixmap pix, pix2;
577 QRect crop, bounding_rect;
578 QString mp;
579 QString snum;
580 QString fraction1, fraction2;
581 QString text_str, move_pt_text;
582 struct canvas *tile_pixmap;
583 struct canvas *unit_pixmap;
584 struct city *pcity;
585 struct player *owner;
586 struct unit *punit;
588 punit = head_of_units_in_focus();
589 if (punit == nullptr) {
590 hide();
591 return;
594 font.setCapitalization(QFont::AllUppercase);
595 font.setBold(true);
596 setFixedHeight(parentWidget()->height() / 12);
597 text_label.setFixedHeight((height() * 2) / 10);
599 move(qRound(gui()->mapview_wdg->width()
600 * gui()->qt_settings.unit_info_pos_fx),
601 qRound((gui()->mapview_wdg->height()
602 * gui()->qt_settings.unit_info_pos_fy)));
603 unit_icons->setFixedHeight((height() * 8) / 10);
605 setUpdatesEnabled(false);
607 text_str = QString(unit_name_translation(punit));
608 owner = punit->owner;
609 pcity = player_city_by_number(owner, punit->homecity);
610 if (pcity != NULL) {
611 text_str = QString(("%1(%2)"))
612 .arg(unit_name_translation(punit), city_name_get(pcity));
614 text_str = text_str + " ";
615 mp = QString(move_points_text(punit->moves_left, false));
616 if (utype_fuel(unit_type_get(punit))) {
617 mp = mp + QString("(") + QString(move_points_text((
618 unit_type_get(punit)->move_rate
619 * ((punit->fuel) - 1)
620 + punit->moves_left), false))
621 + QString(")");
623 /* TRANS: MP = Movement points */
624 mp = QString(_("MP: ")) + mp;
625 text_str = text_str + mp + " ";
626 text_str += QString(_("HP:%1/%2")).arg(
627 QString::number(punit->hp),
628 QString::number(unit_type_get(punit)->hp));
629 num = unit_list_size(punit->tile->units);
630 snum = QString::number(unit_list_size(punit->tile->units) - 1);
631 if (unit_list_size(get_units_in_focus()) > 1) {
632 text_str = text_str + QString(_(" (Selected %1 units)"))
633 .arg(unit_list_size(get_units_in_focus()));
634 } else if (num > 2) {
635 text_str = text_str + QString(_(" +%1 units"))
636 .arg(snum.toLocal8Bit().data());
637 } else if (num == 2) {
638 text_str = text_str + QString(_(" +1 unit"));
640 text_label.setText(text_str);
641 font.setPixelSize((text_label.height() * 9) / 10);
642 text_label.setFont(font);
643 fm = new QFontMetrics(font);
644 text_label.setFixedWidth(fm->width(text_str) + 20);
645 delete fm;
647 unit_pixmap = qtg_canvas_create(tileset_unit_width(tileset),
648 tileset_unit_height(tileset));
649 unit_pixmap->map_pixmap.fill(Qt::transparent);
650 put_unit(punit, unit_pixmap, 1, 0, 0);
651 img = unit_pixmap->map_pixmap.toImage();
652 crop = zealous_crop_rect(img);
653 cropped_img = img.copy(crop);
654 img = cropped_img.scaledToHeight(height(), Qt::SmoothTransformation);
655 pix = QPixmap::fromImage(img);
656 /* add transparent borders if image is too slim */
657 if (pix.width() < tileset_unit_width(tileset)) {
658 int px = tileset_full_tile_width(tileset);
659 pix2 = QPixmap(px, pix.height());
660 pix2.fill(Qt::transparent);
661 p.begin(&pix2);
662 p.drawPixmap(px / 2 - pix.width() / 2, 0, pix);
663 p.end();
664 pix = pix2;
666 /* Draw movement points */
667 move_pt_text = move_points_text(punit->moves_left, false);
668 if (move_pt_text.contains('/')) {
669 fraction2 = move_pt_text.right(1);
670 move_pt_text.remove(move_pt_text.count() - 2, 2);
671 fraction1 = move_pt_text.right(1);
672 move_pt_text.remove(move_pt_text.count() - 1, 1);
674 crop = QRect(5, 5, pix.width() - 5, pix.height() - 5);
675 font.setCapitalization(QFont::Capitalize);
676 font.setPointSize((pix.height() * 2) / 5);
677 p.begin(&pix);
678 p.setFont(font);
679 p.setPen(Qt::white);
680 p.drawText(crop, Qt::AlignLeft | Qt::AlignBottom, move_pt_text);
681 if (move_pt_text.isEmpty()) {
682 move_pt_text = " ";
684 bounding_rect = p.boundingRect(crop, Qt::AlignLeft | Qt::AlignBottom,
685 move_pt_text);
686 font.setPointSize(pix.height() / 5);
687 fm = new QFontMetrics(font);
688 font_width = (fm->width(move_pt_text) * 3) / 5;
689 delete fm;
690 p.setFont(font);
691 if (fraction1.isNull() == false) {
692 int t = 2 * font.pointSize();
693 crop = QRect(bounding_rect.right() - font_width,
694 bounding_rect.top(), t, (t / 5) * 4);
695 p.drawText(crop, Qt::AlignLeft | Qt::AlignBottom, fraction1);
696 crop = QRect(bounding_rect.right() - font_width,
697 (bounding_rect.bottom() + bounding_rect.top()) / 2,
698 t, (t / 5) * 4);
699 p.drawText(crop, Qt::AlignLeft | Qt::AlignTop, fraction2);
700 crop = QRect(bounding_rect.right() - font_width,
701 (bounding_rect.bottom() + bounding_rect.top()) / 2 - t / 16,
702 (t * 2) / 5, t / 8);
703 p.fillRect(crop, Qt::white);
705 p.end();
706 wwidth = 2 * 3 + pix.width();
707 unit_label.setPixmap(pix);
708 if (tileset_is_isometric(tileset)) {
709 tile_pixmap = qtg_canvas_create(tileset_full_tile_width(tileset),
710 tileset_tile_height(tileset) * 2);
711 } else {
712 tile_pixmap = qtg_canvas_create(tileset_full_tile_width(tileset),
713 tileset_tile_height(tileset));
715 tile_pixmap->map_pixmap.fill(QColor(0 , 0 , 0 , 0));
716 put_terrain(punit->tile, tile_pixmap, 1.0, 0, 0);
717 img = tile_pixmap->map_pixmap.toImage();
718 crop = zealous_crop_rect(img);
719 cropped_img = img.copy(crop);
720 if (cropped_img.height() > height() - 5 ||
721 cropped_img.height() < height() / 3) {
722 img = cropped_img.scaledToHeight(height() - 5,
723 Qt::SmoothTransformation);
724 } else {
725 img = cropped_img;
727 pix = QPixmap::fromImage(img);
728 tile_label.setPixmap(pix);
729 unit_label.setToolTip(popup_info_text(punit->tile));
730 tile_label.setToolTip(popup_terrain_info(punit->tile));
731 wwidth = wwidth + pix.width();
732 qtg_canvas_free(tile_pixmap);
733 qtg_canvas_free(unit_pixmap);
735 setFixedWidth(wwidth + qMax(unit_icons->update_actions() * (height() * 8)
736 / 10, text_label.width()));
737 mw->put_to_corner();
738 setUpdatesEnabled(true);
739 updateGeometry();
740 update();
742 show();
745 /****************************************************************************
746 Custom label with extra mouse events
747 ****************************************************************************/
748 click_label::click_label() : QLabel()
750 connect(this, SIGNAL(left_clicked()), SLOT(on_clicked()));
753 /****************************************************************************
754 Mouse event for click_label
755 ****************************************************************************/
756 void click_label::mousePressEvent(QMouseEvent *e)
758 if (e->button() == Qt::LeftButton) {
759 emit left_clicked();
763 /****************************************************************************
764 Centers on current unit
765 ****************************************************************************/
766 void click_label::on_clicked()
768 gui()->game_tab_widget->setCurrentIndex(0);
769 request_center_focus_unit();
772 /****************************************************************************
773 Hud action constructor, used to show one action
774 ****************************************************************************/
775 hud_action::hud_action(QWidget *parent) : QWidget(parent)
777 connect(this, SIGNAL(left_clicked()), SLOT(on_clicked()));
778 setFocusPolicy(Qt::StrongFocus);
779 setMouseTracking(true);
780 focus = false;
781 action_pixmap = nullptr;
784 /****************************************************************************
785 Sets given pixmap for hud_action
786 ****************************************************************************/
787 void hud_action::set_pixmap(QPixmap *p)
789 action_pixmap = p;
792 /****************************************************************************
793 Custom painting for hud_action
794 ****************************************************************************/
795 void hud_action::paintEvent(QPaintEvent *event)
797 QRect rx, ry, rz;
798 QPainter p;
800 rx = QRect(0, 0, width(), height());
801 ry = QRect(0, 0, action_pixmap->width(), action_pixmap->height());
802 rz = QRect(0, 0, width() - 1, height() - 3);
803 p.begin(this);
804 p.setCompositionMode(QPainter::CompositionMode_Source);
805 p.setRenderHint(QPainter::SmoothPixmapTransform);
806 p.drawPixmap(rx, *action_pixmap, ry);
807 p.setPen(QColor(palette().color(QPalette::Text)));
808 p.drawRect(rz);
809 if (focus == true) {
810 p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
811 p.fillRect(rx, QColor(palette().color(QPalette::Highlight)));
813 p.end();
817 /****************************************************************************
818 Hud action destructor
819 ****************************************************************************/
820 hud_action::~hud_action()
822 if (action_pixmap) {
823 delete action_pixmap;
827 /****************************************************************************
828 Mouse press event for hud_action
829 ****************************************************************************/
830 void hud_action::mousePressEvent(QMouseEvent *e)
832 if (e->button() == Qt::RightButton) {
833 emit right_clicked();
834 } else if (e->button() == Qt::LeftButton) {
835 emit left_clicked();
839 /****************************************************************************
840 Mouse move event for hud_action, draw focus
841 ****************************************************************************/
842 void hud_action::mouseMoveEvent(QMouseEvent *event)
844 focus = true;
845 update();
847 /****************************************************************************
848 Leave event for hud_action, used to get status of pixmap higlight
849 ****************************************************************************/
850 void hud_action::leaveEvent(QEvent *event)
852 focus = false;
853 update();
854 QWidget::leaveEvent(event);
857 /****************************************************************************
858 Enter event for hud_action, used to get status of pixmap higlight
859 ****************************************************************************/
860 void hud_action::enterEvent(QEvent *event)
862 focus = true;
863 update();
864 QWidget::enterEvent(event);
867 /****************************************************************************
868 Right click event for hud_action
869 ****************************************************************************/
870 void hud_action::on_right_clicked()
874 /****************************************************************************
875 Left click event for hud_action
876 ****************************************************************************/
877 void hud_action::on_clicked()
879 gui()->menu_bar->execute_shortcut(action_shortcut);
882 /****************************************************************************
883 Units action contructor, holds possible hud_actions
884 ****************************************************************************/
885 unit_actions::unit_actions(QWidget *parent, unit *punit) : QWidget(parent)
887 layout = new QHBoxLayout(this);
888 layout->setSpacing(3);
889 layout->setContentsMargins(0, 0, 0, 0);
890 current_unit = punit;
891 init_layout();
892 setFocusPolicy(Qt::ClickFocus);
897 /****************************************************************************
898 Destructor for unit_actions
899 ****************************************************************************/
900 unit_actions::~unit_actions()
902 qDeleteAll(actions);
903 actions.clear();
907 /****************************************************************************
908 Initiazlizes layout ( layout needs to be changed after adding units )
909 ****************************************************************************/
910 void unit_actions::init_layout()
912 QSizePolicy size_fixed_policy(QSizePolicy::MinimumExpanding,
913 QSizePolicy::Fixed,
914 QSizePolicy::Frame);
915 setSizePolicy(size_fixed_policy);
916 layout->setSpacing(0);
917 setLayout(layout);
921 /****************************************************************************
922 Updates avaialable actions, returns actions count
923 ****************************************************************************/
924 int unit_actions::update_actions()
926 hud_action *a;
928 current_unit = head_of_units_in_focus();
930 if (current_unit == nullptr) {
931 clear_layout();
932 hide();
933 return 0;
935 hide();
936 clear_layout();
937 setUpdatesEnabled(false);
940 foreach (a, actions) {
941 delete a;
943 qDeleteAll(actions);
944 actions.clear();
946 /* Create possible actions */
948 if (unit_can_add_or_build_city(current_unit)) {
949 a = new hud_action(this);
950 a->action_shortcut = SC_BUILDCITY;
951 a->set_pixmap(fc_icons::instance()->get_pixmap("home"));
952 actions.append(a);
956 if (can_unit_do_activity(current_unit, ACTIVITY_MINE)) {
957 struct terrain *pterrain = tile_terrain(unit_tile(current_unit));
958 a = new hud_action(this);
959 a->action_shortcut = SC_BUILDMINE;
960 actions.append(a);
961 if (pterrain->mining_result != T_NONE
962 && pterrain->mining_result != pterrain) {
963 if (!strcmp(terrain_rule_name(pterrain), "Jungle")
964 || !strcmp(terrain_rule_name(pterrain), "Plains")
965 || !strcmp(terrain_rule_name(pterrain), "Grassland")
966 || !strcmp(terrain_rule_name(pterrain), "Swamp")) {
967 a->set_pixmap(fc_icons::instance()->get_pixmap("plantforest"));
968 } else {
969 a->set_pixmap(fc_icons::instance()->get_pixmap("transform"));
971 } else {
972 a->set_pixmap(fc_icons::instance()->get_pixmap("mine"));
976 if (can_unit_do_activity(current_unit, ACTIVITY_IRRIGATE)) {
977 struct terrain *pterrain = tile_terrain(unit_tile(current_unit));
978 a = new hud_action(this);
979 a->action_shortcut = SC_BUILDIRRIGATION;
980 if (pterrain->irrigation_result != T_NONE
981 && pterrain->irrigation_result != pterrain) {
982 if ((!strcmp(terrain_rule_name(pterrain), "Forest") ||
983 !strcmp(terrain_rule_name(pterrain), "Jungle"))) {
984 a->set_pixmap(fc_icons::instance()->get_pixmap("chopchop"));
985 } else {
986 a->set_pixmap(fc_icons::instance()->get_pixmap("transform"));
988 } else {
989 a->set_pixmap(fc_icons::instance()->get_pixmap("irrigation"));
991 actions.append(a);
994 if (can_unit_do_activity(current_unit, ACTIVITY_TRANSFORM)) {
995 a = new hud_action(this);
996 a->action_shortcut = SC_TRANSFORM;
997 a->set_pixmap(fc_icons::instance()->get_pixmap("transform"));
998 actions.append(a);
1001 /* Road */
1003 bool ok = false;
1004 extra_type_by_cause_iterate(EC_ROAD, pextra) {
1005 struct road_type *proad = extra_road_get(pextra);
1006 if (can_build_road(proad, current_unit, unit_tile(current_unit))) {
1007 ok = true;
1010 extra_type_by_cause_iterate_end;
1011 if (ok) {
1012 a = new hud_action(this);
1013 a->action_shortcut = SC_BUILDROAD;
1014 a->set_pixmap(fc_icons::instance()->get_pixmap("buildroad"));
1015 actions.append(a);
1018 /* Goto */
1019 a = new hud_action(this);
1020 a->action_shortcut = SC_GOTO;
1021 a->set_pixmap(fc_icons::instance()->get_pixmap("goto"));
1022 actions.append(a);
1025 if (can_unit_do_activity(current_unit, ACTIVITY_FORTIFYING)) {
1026 a = new hud_action(this);
1027 a->action_shortcut = SC_FORTIFY;
1028 a->set_pixmap(fc_icons::instance()->get_pixmap("fortify"));
1029 actions.append(a);
1033 if (can_unit_do_activity(current_unit, ACTIVITY_SENTRY)) {
1034 a = new hud_action(this);
1035 a->action_shortcut = SC_SENTRY;
1036 a->set_pixmap(fc_icons::instance()->get_pixmap("sentry"));
1037 actions.append(a);
1040 /* Load */
1041 if (unit_can_load(current_unit)) {
1042 a = new hud_action(this);
1043 a->action_shortcut = SC_LOAD;
1044 a->set_pixmap(fc_icons::instance()->get_pixmap("load"));
1045 actions.append(a);
1048 /* Set homecity */
1049 if (tile_city(unit_tile(current_unit))) {
1050 if (can_unit_change_homecity_to(current_unit,
1051 tile_city(unit_tile(current_unit)))) {
1052 a = new hud_action(this);
1053 a->action_shortcut = SC_SETHOME;
1054 a->set_pixmap(fc_icons::instance()->get_pixmap("set_homecity"));
1055 actions.append(a);
1059 /* Upgrade */
1060 if (UU_OK == unit_upgrade_test(current_unit, FALSE)) {
1061 a = new hud_action(this);
1062 a->action_shortcut = SC_UPGRADE_UNIT;
1063 a->set_pixmap(fc_icons::instance()->get_pixmap("upgrade"));
1064 actions.append(a);
1067 /* Automate */
1068 if (can_unit_do_autosettlers(current_unit)) {
1069 a = new hud_action(this);
1070 a->action_shortcut = SC_AUTOMATE;
1071 a->set_pixmap(fc_icons::instance()->get_pixmap("automate"));
1072 actions.append(a);
1075 /* Paradrop */
1076 if (can_unit_paradrop(current_unit)) {
1077 a = new hud_action(this);
1078 a->action_shortcut = SC_PARADROP;
1079 a->set_pixmap(fc_icons::instance()->get_pixmap("paradrop"));
1080 actions.append(a);
1083 /* Clean pollution */
1084 if (can_unit_do_activity(current_unit, ACTIVITY_POLLUTION)) {
1085 a = new hud_action(this);
1086 a->action_shortcut = SC_PARADROP;
1087 a->set_pixmap(fc_icons::instance()->get_pixmap("pollution"));
1088 actions.append(a);
1091 /* Unload */
1092 if (unit_transported(current_unit)
1093 && can_unit_unload(current_unit, unit_transport_get(current_unit))
1094 && can_unit_exist_at_tile(&(wld.map), current_unit,
1095 unit_tile(current_unit))) {
1096 a = new hud_action(this);
1097 a->action_shortcut = SC_UNLOAD;
1098 a->set_pixmap(fc_icons::instance()->get_pixmap("unload"));
1099 actions.append(a);
1102 /* Nuke */
1103 if (unit_can_do_action(current_unit, ACTION_NUKE)) {
1104 a = new hud_action(this);
1105 a->action_shortcut = SC_NUKE;
1106 a->set_pixmap(fc_icons::instance()->get_pixmap("nuke"));
1107 actions.append(a);
1110 /* Wait */
1111 a = new hud_action(this);
1112 a->action_shortcut = SC_WAIT;
1113 a->set_pixmap(fc_icons::instance()->get_pixmap("wait"));
1114 actions.append(a);
1116 /* Done moving */
1117 a = new hud_action(this);
1118 a->action_shortcut = SC_DONE_MOVING;
1119 a->set_pixmap(fc_icons::instance()->get_pixmap("done"));
1120 actions.append(a);
1123 foreach (a, actions) {
1124 a->setToolTip(gui()->menu_bar->shortcut_2_menustring(a->action_shortcut));
1125 a->setFixedHeight(height());
1126 a->setFixedWidth(height());
1127 layout->addWidget(a);
1130 setFixedWidth(actions.count() * height());
1131 setUpdatesEnabled(true);
1132 show();
1133 layout->update();
1134 updateGeometry();
1135 return actions.count();
1138 /****************************************************************************
1139 Cleans layout - run it before layout initialization
1140 ****************************************************************************/
1141 void unit_actions::clear_layout()
1143 int i = actions.count();
1144 hud_action *ui;
1145 int j;
1147 setUpdatesEnabled(false);
1148 for (j = 0; j < i; j++) {
1149 ui = actions[j];
1150 layout->removeWidget(ui);
1151 delete ui;
1153 while (!actions.empty()) {
1154 actions.removeFirst();
1156 setUpdatesEnabled(true);
1159 /****************************************************************************
1160 Constructor for widget allowing loading units on transports
1161 ****************************************************************************/
1162 hud_unit_loader::hud_unit_loader(struct unit *pcargo, struct tile *ptile)
1164 setProperty("showGrid", "false");
1165 setProperty("selectionBehavior", "SelectRows");
1166 setEditTriggers(QAbstractItemView::NoEditTriggers);
1167 setSelectionMode(QAbstractItemView::SingleSelection);
1168 verticalHeader()->setVisible(false);
1169 horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
1170 horizontalHeader()->setVisible(false);
1171 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1172 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1173 connect(selectionModel(),
1174 SIGNAL(selectionChanged(const QItemSelection &,
1175 const QItemSelection &)), this,
1176 SLOT(selection_changed(const QItemSelection &,
1177 const QItemSelection &)));
1178 cargo = pcargo;
1179 qtile = ptile;
1183 /****************************************************************************
1184 Destructor for units loader
1185 ****************************************************************************/
1186 hud_unit_loader::~hud_unit_loader()
1191 /****************************************************************************
1192 Shows unit loader, adds possible tranportsand units to table
1193 Calculates table size
1194 ****************************************************************************/
1195 void hud_unit_loader::show_me()
1197 QTableWidgetItem *new_item;
1198 int max_size = 0;
1199 int i, j;
1200 int w,h;
1201 sprite *spite;
1203 unit_list_iterate(qtile->units, ptransport) {
1204 if (can_unit_transport(ptransport, cargo)
1205 && get_transporter_occupancy(ptransport)
1206 < get_transporter_capacity(ptransport)) {
1207 transports.append(ptransport);
1208 max_size = qMax(max_size, get_transporter_occupancy(ptransport));
1210 } unit_list_iterate_end;
1212 setRowCount(transports.count());
1213 setColumnCount(max_size + 1);
1214 for (i = 0 ; i < transports.count(); i++) {
1215 QString str;
1216 spite = get_unittype_sprite(tileset, transports.at(i)->utype,
1217 direction8_invalid());
1218 str = utype_rule_name(transports.at(i)->utype);
1219 /* TRANS: MP - just movement points */
1220 str = str + " ("
1221 + QString(move_points_text(transports.at(i)->moves_left, false))
1222 + _("MP") + ")";
1223 new_item = new QTableWidgetItem(QIcon(*spite->pm), str);
1224 setItem(i, 0, new_item);
1225 j = 1;
1226 unit_list_iterate(transports.at(i)->transporting, tunit) {
1227 spite = get_unittype_sprite(tileset, tunit->utype,
1228 direction8_invalid());
1229 new_item = new QTableWidgetItem(QIcon(*spite->pm), "");
1230 setItem(i, j, new_item);
1231 j++;
1232 } unit_list_iterate_end;
1235 w = verticalHeader()->width() + 4;
1236 for (i = 0; i < columnCount(); i++) {
1237 w += columnWidth(i);
1239 h = horizontalHeader()->height() + 4;
1240 for (i = 0; i < rowCount(); i++) {
1241 h += rowHeight(i);
1244 resize(w, h);
1245 setWindowFlags(Qt::WindowStaysOnTopHint | Qt::Dialog
1246 | Qt::FramelessWindowHint);
1247 show();
1250 /****************************************************************************
1251 Selects given tranport and closes widget
1252 ****************************************************************************/
1253 void hud_unit_loader::selection_changed(const QItemSelection& s1,
1254 const QItemSelection& s2)
1256 int curr_row;
1258 curr_row = s1.indexes().at(0).row();
1259 request_unit_load(cargo, transports.at(curr_row), qtile);
1260 close();
1263 /****************************************************************************
1264 Constructor for unit_hud_selector
1265 ****************************************************************************/
1266 unit_hud_selector::unit_hud_selector(QWidget *parent) : QFrame(parent)
1268 QHBoxLayout *hbox, *hibox;
1269 Unit_type_id utype_id;
1270 QGroupBox *no_name;
1271 QVBoxLayout *groupbox_layout;
1273 hide();
1274 struct unit *punit = head_of_units_in_focus();
1276 setWindowFlags(Qt::WindowStaysOnTopHint | Qt::Dialog
1277 | Qt::FramelessWindowHint);
1278 main_layout = new QVBoxLayout(this);
1280 unit_sel_type = new QComboBox();
1282 unit_type_iterate(utype) {
1283 utype_id = utype_index(utype);
1284 if (has_player_unit_type(utype_id)) {
1285 unit_sel_type->addItem(utype_name_translation(utype), utype_id);
1288 unit_type_iterate_end;
1290 if (punit) {
1291 int i;
1292 i = unit_sel_type->findText(utype_name_translation(punit->utype));
1293 unit_sel_type->setCurrentIndex(i);
1295 no_name = new QGroupBox();
1296 no_name->setTitle(_("Unit type"));
1297 this_type = new QRadioButton(_("Selected type"), no_name);
1298 this_type->setChecked(true);
1299 any_type = new QRadioButton(_("All types"), no_name);
1300 connect(unit_sel_type, SIGNAL(currentIndexChanged(int)), this,
1301 SLOT(select_units(int)));
1302 connect(this_type, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1303 connect(any_type, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1304 groupbox_layout = new QVBoxLayout;
1305 groupbox_layout->addWidget(unit_sel_type);
1306 groupbox_layout->addWidget(this_type);
1307 groupbox_layout->addWidget(any_type);
1308 no_name->setLayout(groupbox_layout);
1309 hibox = new QHBoxLayout;
1310 hibox->addWidget(no_name);
1312 no_name = new QGroupBox();
1313 no_name->setTitle(_("Unit activity"));
1314 any_activity = new QRadioButton(_("Any activity"), no_name);
1315 any_activity->setChecked(true);
1316 fortified = new QRadioButton(_("Fortified"), no_name);
1317 idle = new QRadioButton(_("Idle"), no_name);
1318 sentried = new QRadioButton(_("Sentried"), no_name);
1319 connect(any_activity, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1320 connect(idle, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1321 connect(fortified, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1322 connect(sentried, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1323 groupbox_layout = new QVBoxLayout;
1324 groupbox_layout->addWidget(any_activity);
1325 groupbox_layout->addWidget(idle);
1326 groupbox_layout->addWidget(fortified);
1327 groupbox_layout->addWidget(sentried);
1328 no_name->setLayout(groupbox_layout);
1329 hibox->addWidget(no_name);
1330 main_layout->addLayout(hibox);
1332 no_name = new QGroupBox();
1333 no_name->setTitle(_("Unit HP and MP"));
1334 any = new QRadioButton(_("Any unit"), no_name);
1335 full_hp = new QRadioButton(_("Full HP"), no_name);
1336 full_mp = new QRadioButton(_("Full MP"), no_name);
1337 full_hp_mp = new QRadioButton(_("Full HP and MP"), no_name);
1338 full_hp_mp->setChecked(true);
1339 connect(any, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1340 connect(full_hp, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1341 connect(full_mp, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1342 connect(full_hp_mp, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1343 groupbox_layout = new QVBoxLayout;
1344 groupbox_layout->addWidget(any);
1345 groupbox_layout->addWidget(full_hp);
1346 groupbox_layout->addWidget(full_mp);
1347 groupbox_layout->addWidget(full_hp_mp);
1348 no_name->setLayout(groupbox_layout);
1349 hibox = new QHBoxLayout;
1350 hibox->addWidget(no_name);
1352 no_name = new QGroupBox();
1353 no_name->setTitle(_("Location"));
1354 everywhere = new QRadioButton(_("Everywhere"), no_name);
1355 this_tile = new QRadioButton(_("Current tile"), no_name);
1356 this_continent = new QRadioButton(_("Current continent"), no_name);
1357 main_continent = new QRadioButton(_("Main continent"), no_name);
1358 groupbox_layout = new QVBoxLayout;
1360 if (punit) {
1361 this_tile->setChecked(true);
1362 } else {
1363 this_tile->setDisabled(true);
1364 this_continent->setDisabled(true);
1365 main_continent->setChecked(true);
1368 groupbox_layout->addWidget(this_tile);
1369 groupbox_layout->addWidget(this_continent);
1370 groupbox_layout->addWidget(main_continent);
1371 groupbox_layout->addWidget(everywhere);
1373 no_name->setLayout(groupbox_layout);
1374 hibox->addWidget(no_name);
1375 main_layout->addLayout(hibox);
1377 select = new QPushButton(_("Select"));
1378 cancel = new QPushButton(_("Cancel"));
1379 connect(everywhere, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1380 connect(this_tile, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1381 connect(this_continent, SIGNAL(toggled(bool)), this,
1382 SLOT(select_units(bool)));
1383 connect(main_continent, SIGNAL(toggled(bool)), this,
1384 SLOT(select_units(bool)));
1385 connect(select, SIGNAL(clicked()), this, SLOT(uhs_select()));
1386 connect(cancel, SIGNAL(clicked()), this, SLOT(uhs_cancel()));
1387 hbox = new QHBoxLayout;
1388 hbox->addWidget(cancel);
1389 hbox->addWidget(select);
1391 result_label.setAlignment(Qt::AlignCenter);
1392 main_layout->addWidget(&result_label, Qt::AlignHCenter);
1393 main_layout->addLayout(hbox);
1394 setLayout(main_layout);
1398 /****************************************************************************
1399 Shows and moves to center unit_hud_selector
1400 ****************************************************************************/
1401 void unit_hud_selector::show_me()
1403 QPoint p;
1405 p = QPoint((parentWidget()->width() - sizeHint().width()) / 2,
1406 (parentWidget()->height() - sizeHint().height()) / 2);
1407 p = parentWidget()->mapToGlobal(p);
1408 move(p);
1409 setVisible(true);
1410 show();
1411 select_units();
1414 /****************************************************************************
1415 Unit_hud_selector destructor
1416 ****************************************************************************/
1417 unit_hud_selector::~unit_hud_selector()
1422 /****************************************************************************
1423 Selects and closes widget
1424 ****************************************************************************/
1425 void unit_hud_selector::uhs_select()
1427 const struct player *pplayer;
1429 pplayer = client_player();
1431 unit_list_iterate(pplayer->units, punit) {
1432 if (activity_filter(punit) && hp_filter(punit)
1433 && island_filter(punit) && type_filter(punit)) {
1434 unit_focus_add(punit);
1436 } unit_list_iterate_end;
1437 close();
1440 /****************************************************************************
1441 Closes current widget
1442 ****************************************************************************/
1443 void unit_hud_selector::uhs_cancel()
1445 close();
1448 /****************************************************************************
1449 Shows number of selected units on label
1450 ****************************************************************************/
1451 void unit_hud_selector::select_units(int x)
1453 int num = 0;
1454 const struct player *pplayer;
1456 pplayer = client_player();
1458 unit_list_iterate(pplayer->units, punit) {
1459 if (activity_filter(punit) && hp_filter(punit)
1460 && island_filter(punit) && type_filter(punit)) {
1461 num++;
1463 } unit_list_iterate_end;
1464 result_label.setText(QString(PL_("%1 unit", "%1 units", num)).arg(num));
1467 /****************************************************************************
1468 Convinient slot for ez connect
1469 ****************************************************************************/
1470 void unit_hud_selector::select_units(bool x)
1472 select_units(0);
1475 /****************************************************************************
1476 Key press event for unit_hud_selector
1477 ****************************************************************************/
1478 void unit_hud_selector::keyPressEvent(QKeyEvent *event)
1480 if ((event->key() == Qt::Key_Return)
1481 || (event->key() == Qt::Key_Enter)) {
1482 uhs_select();
1484 if (event->key() == Qt::Key_Escape) {
1485 close();
1486 event->accept();
1488 QWidget::keyPressEvent(event);
1491 /****************************************************************************
1492 Filter by activity
1493 ****************************************************************************/
1494 bool unit_hud_selector::activity_filter(struct unit *punit)
1496 if ((punit->activity == ACTIVITY_FORTIFIED && fortified->isChecked())
1497 || (punit->activity == ACTIVITY_SENTRY && sentried->isChecked())
1498 || (punit->activity == ACTIVITY_IDLE && idle->isChecked())
1499 || any_activity->isChecked()) {
1500 return true;
1502 return false;
1505 /****************************************************************************
1506 Filter by hp/mp
1507 ****************************************************************************/
1508 bool unit_hud_selector::hp_filter(struct unit *punit)
1510 if ((any->isChecked()
1511 || (full_mp->isChecked()
1512 && punit->moves_left >= punit->utype->move_rate)
1513 || (full_hp->isChecked() && punit->hp >= punit->utype->hp)
1514 || (full_hp_mp->isChecked() && punit->hp >= punit->utype->hp
1515 && punit->moves_left >= punit->utype->move_rate))) {
1516 return true;
1518 return false;
1521 /****************************************************************************
1522 Filter by location
1523 ****************************************************************************/
1524 bool unit_hud_selector::island_filter(struct unit *punit)
1526 int island = -1;
1527 struct unit *cunit = head_of_units_in_focus();
1529 if (this_tile->isChecked() && cunit) {
1530 if (punit->tile == cunit->tile) {
1531 return true;
1535 if (main_continent->isChecked() && player_capital(client_player())) {
1536 island = player_capital(client_player())->tile->continent;
1537 } else if (this_continent->isChecked() && cunit) {
1538 island = cunit->tile->continent;
1541 if (island > -1) {
1542 if (punit->tile->continent == island) {
1543 return true;
1547 if (everywhere->isChecked()) {
1548 return true;
1550 return false;
1553 /****************************************************************************
1554 Filter by type
1555 ****************************************************************************/
1556 bool unit_hud_selector::type_filter(struct unit *punit)
1558 QVariant qvar;
1559 Unit_type_id utype_id;
1561 if (this_type->isChecked()) {
1562 qvar = unit_sel_type->currentData();
1563 utype_id = qvar.toInt();
1564 if (utype_id == utype_index(punit->utype)) {
1565 return true;
1566 } else {
1567 return false;
1570 if (any_type->isChecked()) {
1571 return true;
1573 return false;
1576 /****************************************************************************
1577 Tooltip text for terrain information
1578 ****************************************************************************/
1579 QString popup_terrain_info(struct tile *ptile)
1581 int movement_cost;
1582 struct terrain *terr;
1583 QString ret, t, move_text;
1584 bool has_road = false;
1586 terr = ptile->terrain;
1587 ret = QString(_("Terrain: %1\n")).arg(tile_get_info_text(ptile, TRUE, 0));
1588 ret = ret + QString(_("Food/Prod/Trade: %1\n"))
1589 .arg(get_tile_output_text(ptile));
1590 t = get_infrastructure_text(ptile->extras);
1591 if (t != "") {
1592 ret = ret + QString(_("Infrastructure: %1\n")).arg(t);
1594 ret = ret + QString(_("Defense bonus: %1%\n")).arg(terr->defense_bonus);
1595 movement_cost = terr->movement_cost;
1597 extra_type_by_cause_iterate(EC_ROAD, pextra) {
1598 struct road_type *proad = extra_road_get(pextra);
1600 if (tile_has_road(ptile, proad)) {
1601 if (proad->move_cost <= movement_cost) {
1602 has_road = true;
1603 move_text = move_points_text(proad->move_cost, TRUE);
1604 movement_cost = proad->move_cost;
1607 } extra_type_by_cause_iterate_end;
1609 if (has_road == true) {
1610 ret = ret + QString(_("Movement cost: %1")).arg(move_text);
1611 } else {
1612 ret = ret + QString(_("Movement cost: %1")).arg(movement_cost);
1615 return ret;
1618 /****************************************************************************
1619 Shows new turn information with big font
1620 ****************************************************************************/
1621 void show_new_turn_info()
1623 QString s;
1624 hud_text *ht;
1625 QList<hud_text *> close_list;
1626 struct research *research;
1627 int i;
1629 if (client_has_player() == false
1630 || gui()->qt_settings.show_new_turn_text == false) {
1631 return;
1633 close_list = gui()->mapview_wdg->findChildren<hud_text *>();
1634 for (i = 0; i < close_list.size(); ++i) {
1635 close_list.at(i)->close();
1636 close_list.at(i)->deleteLater();
1638 research = research_get(client_player());
1639 s = QString(_("Year: %1 (Turn: %2)"))
1640 .arg(calendar_text()).arg(game.info.turn) + "\n";
1641 s = s + QString(nation_plural_for_player(client_player()));
1642 s = s + " - " + QString(_("Population: %1"))
1643 .arg(population_to_text(civ_population(client.conn.playing)));
1644 if (research->researching != A_UNKNOWN
1645 && research->researching != A_UNSET
1646 && research->researching != A_NONE) {
1647 s = s + "\n" + QString(research_advance_name_translation(research,
1648 research->researching)) +
1649 " (" + QString::number(research->bulbs_researched) + "/"
1650 + QString::number(research->client.researching_cost) + ")";
1652 s = s + "\n" + science_dialog_text() + "\n";
1653 s = s + QString(_("Gold: %1 (+%2)"))
1654 .arg(client.conn.playing->economic.gold)
1655 .arg(player_get_expected_income(client.conn.playing));
1656 ht = new hud_text(s, 5, gui()->mapview_wdg);
1657 ht->show_me();
1660 /****************************************************************************
1661 Hud unit combat contructor, prepares images to show as result
1662 ****************************************************************************/
1663 hud_unit_combat::hud_unit_combat(int attacker_unit_id, int defender_unit_id,
1664 int attacker_hp, int defender_hp,
1665 bool make_winner_veteran,
1666 QWidget *parent) : QWidget(parent)
1668 QImage crdimg, acrimg, at, dt;
1669 QRect dr, ar;
1670 QPainter p;
1671 struct canvas *defender_pixmap;
1672 struct canvas *attacker_pixmap;
1673 int w;
1675 w = 3 * tileset_unit_height(tileset) / 2;
1676 att_hp = attacker_hp;
1677 def_hp = defender_hp;
1679 winner_veteran = make_winner_veteran;
1680 attacker = game_unit_by_number(attacker_unit_id);
1681 defender = game_unit_by_number(defender_unit_id);
1682 att_hp_loss = attacker->hp - att_hp;
1683 def_hp_loss = defender->hp - def_hp;
1684 if (defender_hp == 0) {
1685 winner = attacker;
1686 winner_tile = attacker->tile;
1687 } else {
1688 winner = defender;
1689 winner_tile = defender->tile;
1691 setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
1692 setFixedSize(2 * w, w);
1693 focus = false;
1695 defender_pixmap = qtg_canvas_create(tileset_unit_width(tileset),
1696 tileset_unit_height(tileset));
1697 defender_pixmap->map_pixmap.fill(Qt::transparent);
1698 if (defender != nullptr) {
1699 put_unit(defender, defender_pixmap, 1.0, 0, 0);
1700 dimg = defender_pixmap->map_pixmap.toImage();
1701 dr = zealous_crop_rect(dimg);
1702 crdimg = dimg.copy(dr);
1703 dimg = crdimg.scaledToHeight(w, Qt::SmoothTransformation);
1705 if (dimg.width() < w) {
1706 dt = QImage(w, dimg.height(), QImage::Format_ARGB32_Premultiplied);
1707 dt.fill(Qt::transparent);
1708 p.begin(&dt);
1709 p.drawImage(w / 2 - dimg.width() / 2, 0, dimg);
1710 p.end();
1711 dimg = dt;
1713 dimg = dimg.scaled(w, w, Qt::IgnoreAspectRatio,
1714 Qt::SmoothTransformation);
1715 attacker_pixmap = qtg_canvas_create(tileset_unit_width(tileset),
1716 tileset_unit_height(tileset));
1717 attacker_pixmap->map_pixmap.fill(Qt::transparent);
1718 if (attacker != nullptr) {
1719 put_unit(attacker, attacker_pixmap, 1, 0, 0);
1720 aimg = attacker_pixmap->map_pixmap.toImage();
1721 ar = zealous_crop_rect(aimg);
1722 acrimg = aimg.copy(ar);
1723 aimg = acrimg.scaledToHeight(w, Qt::SmoothTransformation);
1725 if (aimg.width() < w) {
1726 at = QImage(w, dimg.height(), QImage::Format_ARGB32_Premultiplied);
1727 at.fill(Qt::transparent);
1728 p.begin(&at);
1729 p.drawImage(w / 2 - aimg.width() / 2, 0, aimg);
1730 p.end();
1731 aimg = at;
1733 aimg = aimg.scaled(w, w, Qt::IgnoreAspectRatio,
1734 Qt::SmoothTransformation);
1737 /****************************************************************************
1738 Hud unit combat destructor
1739 ****************************************************************************/
1740 hud_unit_combat::~hud_unit_combat()
1744 /****************************************************************************
1745 Sets widget fading
1746 ****************************************************************************/
1747 void hud_unit_combat::set_fading(float fade)
1749 fading = fade;
1750 update();
1753 /****************************************************************************
1754 Returns true if widget has focus (used to prevent hiding parent)
1755 ****************************************************************************/
1756 bool hud_unit_combat::get_focus()
1758 return focus;
1761 /****************************************************************************
1762 Paint event for hud_unit combat
1763 ****************************************************************************/
1764 void hud_unit_combat::paintEvent(QPaintEvent *event)
1766 QPainter p;
1767 QRect left, right;
1768 QColor c1, c2;
1769 QPen pen;
1770 QFont f = *fc_font::instance()->get_font(fonts::default_font);
1771 QString ahploss, dhploss;
1772 if (att_hp_loss > 0) {
1773 ahploss = "-" + QString::number(att_hp_loss);
1774 } else {
1775 ahploss = "0";
1777 if (def_hp_loss > 0) {
1778 dhploss = "-" + QString::number(def_hp_loss);
1779 } else {
1780 dhploss = "0";
1782 f.setBold(true);
1784 if (def_hp == 0) {
1785 c1 = QColor(25, 125, 25, 175);
1786 c2 = QColor(125, 25, 25, 175);
1787 } else {
1788 c1 = QColor(125, 25, 25, 175);
1789 c2 = QColor(25, 125, 25, 175);
1791 int w = 3 * tileset_unit_height(tileset) / 2;
1793 left = QRect(0 , 0, w , w);
1794 right = QRect(w, 0, w , w);
1795 pen = QPen(QColor(palette().color(QPalette::AlternateBase)), 2.0);
1796 p.begin(this);
1797 if (fading < 1.0) {
1798 p.setOpacity(fading);
1800 if (focus == true) {
1801 p.fillRect(left, QColor(palette().color(QPalette::Highlight)));
1802 p.fillRect(right, QColor(palette().color(QPalette::Highlight)));
1803 c1.setAlpha(110);
1804 c2.setAlpha(110);
1806 p.fillRect(left, c1);
1807 p.fillRect(right, c2);
1808 p.setPen(pen);
1809 p.drawRect(1, 1, width() - 2 , height() - 2);
1810 p.drawImage(left, aimg);
1811 p.setFont(f);
1812 p.setPen(QColor(Qt::white));
1813 if (winner == defender && winner_veteran) {
1814 p.drawText(right, Qt::AlignHCenter | Qt::AlignJustify
1815 | Qt::AlignAbsolute, "*");
1817 if (winner == attacker && winner_veteran) {
1818 p.drawText(left, Qt::AlignHCenter | Qt::AlignJustify
1819 | Qt::AlignAbsolute, "*");
1821 p.drawText(left, Qt::AlignHorizontal_Mask, ahploss);
1822 p.drawImage(right, dimg);
1823 p.drawText(right, Qt::AlignHorizontal_Mask, dhploss);
1824 p.end();
1827 /****************************************************************************
1828 Mouse press event, centers on highlighted combat
1829 ****************************************************************************/
1830 void hud_unit_combat::mousePressEvent(QMouseEvent *e)
1832 center_tile_mapcanvas(winner_tile);
1835 /****************************************************************************
1836 Leave event for hud unit combat. Stops showing highlight.
1837 ****************************************************************************/
1838 void hud_unit_combat::leaveEvent(QEvent *event)
1840 focus = false;
1841 update();
1844 /****************************************************************************
1845 Leave event for hud unit combat. Shows highlight.
1846 ****************************************************************************/
1847 void hud_unit_combat::enterEvent(QEvent *event)
1849 focus = true;
1850 update();
1853 /****************************************************************************
1854 Hud battle log contructor
1855 ****************************************************************************/
1856 hud_battle_log::hud_battle_log(QWidget *parent) : QWidget(parent)
1858 setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
1859 main_layout = new QVBoxLayout;
1860 mw = new move_widget(this);
1861 setContentsMargins(0, 0, 0, 0);
1862 main_layout->setContentsMargins(0, 0, 0, 0);
1865 /****************************************************************************
1866 Hud battle log destructor
1867 ****************************************************************************/
1868 hud_battle_log::~hud_battle_log()
1872 /****************************************************************************
1873 Adds comabt information to battle log
1874 ****************************************************************************/
1875 void hud_battle_log::add_combat_info(hud_unit_combat *huc)
1877 hud_unit_combat *hudc;
1878 int w = 3 * tileset_unit_height(tileset) / 2;
1880 delete layout();
1881 main_layout = new QVBoxLayout;
1882 lhuc.prepend(huc);
1883 while (lhuc.count() > 5) {
1884 hudc = lhuc.takeLast();
1885 delete hudc;
1887 foreach (hudc, lhuc) {
1888 main_layout->addWidget(hudc);
1889 hudc->set_fading(1.0);
1891 setFixedSize(2 * w + 10, lhuc.count() * w + 10);
1892 setLayout(main_layout);
1894 update();
1895 show();
1896 m_timer.restart();
1897 startTimer(50);
1900 /****************************************************************************
1901 Paint event for hud battle log
1902 ****************************************************************************/
1903 void hud_battle_log::paintEvent(QPaintEvent *event)
1905 mw->put_to_corner();
1908 /****************************************************************************
1909 Move event, saves current position
1910 ****************************************************************************/
1911 void hud_battle_log::moveEvent(QMoveEvent *event)
1913 QPoint p;
1914 p = pos();
1915 gui()->qt_settings.battlelog_x = static_cast<float>(p.x()) / mapview.width;
1916 gui()->qt_settings.battlelog_y = static_cast<float>(p.y())
1917 / mapview.height;
1920 /****************************************************************************
1921 Timer event. Starts/stops fading
1922 ****************************************************************************/
1923 void hud_battle_log::timerEvent(QTimerEvent *event)
1925 hud_unit_combat *hudc;
1926 hud_unit_combat *hupdate;
1927 if (m_timer.elapsed() > 4000 && m_timer.elapsed() < 5000) {
1928 foreach (hudc, lhuc) {
1929 if (hudc->get_focus() == true) {
1930 m_timer.restart();
1931 foreach (hupdate, lhuc) {
1932 hupdate->set_fading(1.0);
1934 return;
1936 hudc->set_fading((5000.0 - m_timer.elapsed()) / 1000);
1939 if (m_timer.elapsed() >= 5000) {
1940 hide();
1944 /****************************************************************************
1945 Show event, restart fading timer
1946 ****************************************************************************/
1947 void hud_battle_log::showEvent(QShowEvent *event)
1949 hud_unit_combat *hupdate;
1950 foreach (hupdate, lhuc) {
1951 hupdate->set_fading(1.0);
1953 m_timer.restart();
1954 setVisible(true);