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)
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 ***********************************************************************/
15 #include <fc_config.h>
20 #include <QApplication>
22 #include <QDialogButtonBox>
23 #include <QGridLayout>
24 #include <QHBoxLayout>
25 #include <QHeaderView>
28 #include <QPaintEvent>
29 #include <QRadioButton>
30 #include <QSpacerItem>
31 #include <QVBoxLayout>
44 #include "hudwidget.h"
46 #include "qtg_cxxside.h"
50 const char *calendar_text(void);
52 static QString
popup_terrain_info(struct tile
*ptile
);
54 /***************************************************************************
55 Returns true if player has any unit of unit_type
56 ***************************************************************************/
57 bool has_player_unit_type(Unit_type_id utype
)
59 unit_list_iterate(client
.conn
.playing
->units
, punit
) {
60 if (utype_number(punit
->utype
) == utype
) {
63 } unit_list_iterate_end
;
68 /****************************************************************************
69 Custom message box constructor
70 ****************************************************************************/
71 hud_message_box::hud_message_box(QWidget
*parent
): QMessageBox(parent
)
74 setWindowFlags(Qt::WindowStaysOnTopHint
| Qt::Dialog
75 | Qt::FramelessWindowHint
);
76 f_text
= *fc_font::instance()->get_font(fonts::default_font
);
77 f_title
= *fc_font::instance()->get_font(fonts::default_font
);
79 size
= f_text
.pointSize();
81 f_text
.setPointSize(size
* 4 / 3);
82 f_title
.setPointSize(size
* 3 / 2);
84 size
= f_text
.pixelSize();
85 f_text
.setPixelSize(size
* 4 / 3);
86 f_title
.setPointSize(size
* 3 / 2);
88 f_title
.setBold(true);
89 f_title
.setCapitalization(QFont::SmallCaps
);
90 fm_text
= new QFontMetrics(f_text
);
91 fm_title
= new QFontMetrics(f_title
);
98 /****************************************************************************
99 Custom message box destructor
100 ****************************************************************************/
101 hud_message_box::~hud_message_box()
106 /****************************************************************************
107 Key press event for hud message box
108 ****************************************************************************/
109 void hud_message_box::keyPressEvent(QKeyEvent
*event
)
111 if (event
->key() == Qt::Key_Escape
) {
116 QWidget::keyPressEvent(event
);
119 /****************************************************************************
120 Sets text and title and shows message box
121 ****************************************************************************/
122 void hud_message_box::set_text_title(QString s1
, QString s2
)
129 if (s1
.contains('\n')) {
131 i
= s1
.indexOf('\n');
133 cs2
= s1
.right(s1
.count() - i
);
135 w2
= qMax(fm_text
->width(cs1
), fm_text
->width(cs2
));
136 w
= qMax(w2
, fm_title
->width(s2
));
138 w
= qMax(fm_text
->width(s1
), fm_title
->width(s2
));
141 h
= mult
* (fm_text
->height() * 3 / 2) + 2 * fm_title
->height();
142 top
= 2 * fm_title
->height();
143 spacer
= new QSpacerItem(w
, 0, QSizePolicy::Minimum
,
144 QSizePolicy::Expanding
);
145 layout
= (QGridLayout
*)this->layout();
146 layout
->addItem(spacer
, layout
->rowCount(), 0, 1, layout
->columnCount());
147 spacer
= new QSpacerItem(0, h
, QSizePolicy::Expanding
,
148 QSizePolicy::Minimum
);
149 layout
->addItem(spacer
, 0, 0, 1, layout
->columnCount());
154 p
= QPoint((parentWidget()->width() - w
) / 2,
155 (parentWidget()->height() - h
) / 2);
156 p
= parentWidget()->mapToGlobal(p
);
163 /****************************************************************************
164 Timer event used to animate message box
165 ****************************************************************************/
166 void hud_message_box::timerEvent(QTimerEvent
*event
)
168 m_animate_step
= m_timer
.elapsed() / 40;
172 /****************************************************************************
173 Paint event for custom message box
174 ****************************************************************************/
175 void hud_message_box::paintEvent(QPaintEvent
*event
)
184 step
= m_animate_step
% 300;
191 rfull
= QRect(2 , 2, width() - 4 , height() - 4);
192 rx
= QRect(2 , 2, width() - 4 , top
);
193 ry
= QRect(2 , top
, width() - 4, height() - top
- 4);
195 c1
= QColor(palette().color(QPalette::Highlight
));
196 c2
= QColor(palette().color(QPalette::AlternateBase
));
197 step
= qMax(0, step
);
198 step
= qMin(255, step
);
202 g
= QLinearGradient(0 , 0, width(), height());
207 p
.fillRect(rx
, QColor(palette().color(QPalette::Highlight
)));
208 p
.fillRect(ry
, QColor(palette().color(QPalette::AlternateBase
)));
209 p
.fillRect(rfull
, g
);
211 p
.drawText((width() - fm_title
->width(title
)) / 2,
212 fm_title
->height() * 4 / 3, title
);
215 p
.drawText((width() - fm_text
->width(text
)) / 2,
216 2 * fm_title
->height() + fm_text
->height() * 4 / 3, text
);
218 p
.drawText((width() - fm_text
->width(cs1
)) / 2,
219 2 * fm_title
->height() + fm_text
->height() * 4 / 3, cs1
);
220 p
.drawText((width() - fm_text
->width(cs2
)) / 2,
221 2 * fm_title
->height() + fm_text
->height() * 8 / 3, cs2
);
227 /****************************************************************************
228 Hud text constructor takes text to display and time
229 ****************************************************************************/
230 hud_text::hud_text(QString s
, int time_secs
,
231 QWidget
*parent
) : QWidget(parent
)
238 setWindowFlags(Qt::WindowStaysOnTopHint
| Qt::FramelessWindowHint
);
239 f_text
= *fc_font::instance()->get_font(fonts::default_font
);
240 f_text
.setBold(true);
241 f_text
.setCapitalization(QFont::SmallCaps
);
242 size
= f_text
.pointSize();
244 f_text
.setPointSize(size
* 2);
246 size
= f_text
.pixelSize();
247 f_text
.setPixelSize(size
* 2);
249 fm_text
= new QFontMetrics(f_text
);
253 setAttribute(Qt::WA_TranslucentBackground
);
254 setAttribute(Qt::WA_ShowWithoutActivating
);
255 setAttribute(Qt::WA_TransparentForMouseEvents
);
256 setFocusPolicy(Qt::NoFocus
);
259 /****************************************************************************
261 ****************************************************************************/
262 void hud_text::show_me()
268 /****************************************************************************
269 Moves to top center parent widget and sets size new size
270 ****************************************************************************/
271 void hud_text::center_me()
276 if (bound_rect
.isEmpty() == false) {
277 setFixedSize(bound_rect
.width(), bound_rect
.height());
279 p
= QPoint((parentWidget()->width() - w
) / 2,
280 parentWidget()->height() / 20);
284 /****************************************************************************
285 Destructor for hud text
286 ****************************************************************************/
287 hud_text::~hud_text()
292 /****************************************************************************
293 Timer event, closes widget after timeout
294 ****************************************************************************/
295 void hud_text::timerEvent(QTimerEvent
*event
)
297 m_animate_step
= m_timer
.elapsed() / 40;
298 if (m_timer
.elapsed() > timeout
* 1000) {
305 /****************************************************************************
306 Paint event for custom hud_text
307 ****************************************************************************/
308 void hud_text::paintEvent(QPaintEvent
*event
)
317 if (m_timer
.elapsed() < timeout
* 500) {
318 opacity
= static_cast<float>(m_timer
.elapsed())/(timeout
* 300);
320 opacity
= static_cast<float>(5000 - m_timer
.elapsed())/(timeout
* 200);
322 opacity
= qMin(1.0f
, opacity
);
323 opacity
= qMax(0.0f
, opacity
);
324 rfull
= QRect(0 , 0, width(), height());
325 c1
= QColor(Qt::white
);
326 c2
= QColor(35, 35, 35, 175);
327 c1
.setAlphaF(c1
.alphaF() * opacity
);
328 c2
.setAlphaF(c2
.alphaF() * opacity
);
331 p
.drawRoundedRect(rfull
, height() / 6 , height() / 6);
334 p
.drawText(rfull
, Qt::AlignCenter
, text
, &bound_rect
);
339 /****************************************************************************
340 Custom input box constructor
341 ****************************************************************************/
342 hud_input_box::hud_input_box(QWidget
*parent
): QDialog(parent
)
346 setWindowFlags(Qt::WindowStaysOnTopHint
| Qt::Dialog
347 | Qt::FramelessWindowHint
);
349 f_text
= *fc_font::instance()->get_font(fonts::default_font
);
350 f_title
= *fc_font::instance()->get_font(fonts::default_font
);
352 size
= f_text
.pointSize();
354 f_text
.setPointSize(size
* 4 / 3);
355 f_title
.setPointSize(size
* 3 / 2);
357 size
= f_text
.pixelSize();
358 f_text
.setPixelSize(size
* 4 / 3);
359 f_title
.setPointSize(size
* 3 / 2);
361 f_title
.setBold(true);
362 f_title
.setCapitalization(QFont::SmallCaps
);
363 fm_text
= new QFontMetrics(f_text
);
364 fm_title
= new QFontMetrics(f_title
);
371 /****************************************************************************
372 Custom input box destructor
373 ****************************************************************************/
374 hud_input_box::~hud_input_box()
379 /****************************************************************************
380 Sets text, title and default text and shows input box
381 ****************************************************************************/
382 void hud_input_box::set_text_title_definput(QString s1
, QString s2
,
388 QDialogButtonBox
*button_box
;
391 button_box
= new QDialogButtonBox(QDialogButtonBox::Ok
392 | QDialogButtonBox::Cancel
,
393 Qt::Horizontal
, this);
394 layout
= new QVBoxLayout
;
395 if (s1
.contains('\n')) {
397 i
= s1
.indexOf('\n');
399 cs2
= s1
.right(s1
.count() - i
);
401 w2
= qMax(fm_text
->width(cs1
), fm_text
->width(cs2
));
402 w
= qMax(w2
, fm_title
->width(s2
));
404 w
= qMax(fm_text
->width(s1
), fm_title
->width(s2
));
407 h
= mult
* (fm_text
->height() * 3 / 2) + 2 * fm_title
->height();
408 top
= 2 * fm_title
->height();
410 spacer
= new QSpacerItem(w
, h
, QSizePolicy::Expanding
,
411 QSizePolicy::Minimum
);
412 layout
->addItem(spacer
);
413 layout
->addWidget(&input_edit
);
414 layout
->addWidget(button_box
);
415 input_edit
.setFont(f_text
);
416 input_edit
.setText(def_input
);
418 QObject::connect(button_box
, SIGNAL(accepted()), this, SLOT(accept()));
419 QObject::connect(button_box
, SIGNAL(rejected()), this, SLOT(reject()));
423 p
= QPoint((parentWidget()->width() - w
) / 2,
424 (parentWidget()->height() - h
) / 2);
425 p
= parentWidget()->mapToGlobal(p
);
427 input_edit
.activateWindow();
428 input_edit
.setFocus();
435 /****************************************************************************
436 Timer event used to animate input box
437 ****************************************************************************/
438 void hud_input_box::timerEvent(QTimerEvent
*event
)
440 m_animate_step
= m_timer
.elapsed() / 40;
445 /****************************************************************************
446 Paint event for custom input box
447 ****************************************************************************/
448 void hud_input_box::paintEvent(QPaintEvent
*event
)
460 step
= m_animate_step
% 300;
466 rx
= QRect(2 , 2, width() - 4 , top
);
467 ry
= QRect(2 , top
, width() - 4, height() - top
- 4);
469 c1
= QColor(palette().color(QPalette::Highlight
));
470 c2
= QColor(Qt::transparent
);
471 c3
= QColor(palette().color(QPalette::Highlight
)).lighter(145);
472 step
= qMax(0, step
);
473 step
= qMin(255, step
);
478 fstep
= static_cast<float>(step
) / 400;
479 g
= QLinearGradient(0 , 0, width(), height());
481 g
.setColorAt(fstep
, c3
);
485 p
.fillRect(rx
, QColor(palette().color(QPalette::Highlight
)));
486 p
.fillRect(ry
, QColor(palette().color(QPalette::AlternateBase
)));
489 p
.drawText((width() - fm_title
->width(title
)) / 2,
490 fm_title
->height() * 4 / 3, title
);
493 p
.drawText((width() - fm_text
->width(text
)) / 2,
494 2 * fm_title
->height() + fm_text
->height() * 4 / 3, text
);
496 p
.drawText((width() - fm_text
->width(cs1
)) / 2,
497 2 * fm_title
->height() + fm_text
->height() * 4 / 3, cs1
);
498 p
.drawText((width() - fm_text
->width(cs2
)) / 2,
499 2 * fm_title
->height() + fm_text
->height() * 8 / 3, cs2
);
505 /****************************************************************************
506 Constructor for hud_units (holds layout for whole uunits info)
507 ****************************************************************************/
508 hud_units::hud_units(QWidget
*parent
) : QFrame(parent
)
511 QVBoxLayout
*unit_lab
;
515 main_layout
= new QHBoxLayout
;
516 sp
= new QSpacerItem(50, 2);
517 vbox
= new QVBoxLayout
;
518 unit_lab
= new QVBoxLayout
;
519 unit_lab
->setContentsMargins(6, 9, 0, 3);
521 unit_lab
->addWidget(&unit_label
);
522 main_layout
->addLayout(unit_lab
);
523 main_layout
->addWidget(&tile_label
);
524 unit_icons
= new unit_actions(this, nullptr);
525 vbox
->addSpacerItem(sp
);
526 vbox
->addWidget(&text_label
);
527 vbox
->addWidget(unit_icons
);
528 main_layout
->addLayout(vbox
);
529 main_layout
->setSpacing(0);
530 main_layout
->setSpacing(3);
531 main_layout
->setContentsMargins(0, 0, 0, 0);
533 vbox
->setContentsMargins(0, 0, 0, 0);
534 setLayout(main_layout
);
535 mw
= new move_widget(this);
536 setFocusPolicy(Qt::ClickFocus
);
540 /****************************************************************************
542 ****************************************************************************/
543 hud_units::~hud_units()
548 /****************************************************************************
549 Move Event for hud_units, used to save position
550 ****************************************************************************/
551 void hud_units::moveEvent(QMoveEvent
*event
)
553 if (event
->pos().x() != 0) {
554 gui()->qt_settings
.unit_info_pos_x
= 1 + (event
->pos().x() * 1000)
555 / gui()->mapview_wdg
->width();
557 gui()->qt_settings
.unit_info_pos_x
= 0;
559 if (event
->pos().y() != 0) {
560 gui()->qt_settings
.unit_info_pos_y
= 1 + (event
->pos().y() * 1000)
561 / gui()->mapview_wdg
->height();
563 gui()->qt_settings
.unit_info_pos_y
= 0;
568 /****************************************************************************
569 Update possible action for given units
570 ****************************************************************************/
571 void hud_units::update_actions(unit_list
*punits
)
575 QFont font
= *fc_font::instance()->get_font(fonts::notify_label
);
585 struct canvas
*tile_pixmap
;
586 struct canvas
*unit_pixmap
;
588 struct player
*owner
;
591 punit
= head_of_units_in_focus();
592 if (punit
== nullptr) {
597 font
.setCapitalization(QFont::AllUppercase
);
599 setFixedHeight(parentWidget()->height() / 12);
600 text_label
.setFixedHeight((height() * 2) / 10);
601 move((gui()->mapview_wdg
->width()
602 * gui()->qt_settings
.unit_info_pos_x
) / 1000,
603 (gui()->mapview_wdg
->height()
604 * gui()->qt_settings
.unit_info_pos_y
) / 1000);
605 unit_icons
->setFixedHeight((height() * 8) / 10);
607 setUpdatesEnabled(false);
609 text_str
= QString(unit_name_translation(punit
));
610 owner
= punit
->owner
;
611 pcity
= player_city_by_number(owner
, punit
->homecity
);
613 text_str
= QString(("%1(%2)"))
614 .arg(unit_name_translation(punit
), city_name_get(pcity
));
616 text_str
= text_str
+ " ";
617 mp
= QString(move_points_text(punit
->moves_left
, false));
618 if (utype_fuel(unit_type_get(punit
))) {
619 mp
= mp
+ QString("(") + QString(move_points_text((
620 unit_type_get(punit
)->move_rate
621 * ((punit
->fuel
) - 1)
622 + punit
->moves_left
), false))
625 /* TRANS: MP = Movement points */
626 mp
= QString(_("MP: ")) + mp
;
627 text_str
= text_str
+ mp
+ " ";
628 text_str
+= QString(_("HP:%1/%2")).arg(
629 QString::number(punit
->hp
),
630 QString::number(unit_type_get(punit
)->hp
));
631 num
= unit_list_size(punit
->tile
->units
);
632 snum
= QString::number(unit_list_size(punit
->tile
->units
) - 1);
633 if (unit_list_size(get_units_in_focus()) > 1) {
634 text_str
= text_str
+ QString(_(" (Selected %1 units)"))
635 .arg(unit_list_size(get_units_in_focus()));
636 } else if (num
> 2) {
637 text_str
= text_str
+ QString(_(" +%1 units"))
638 .arg(snum
.toLocal8Bit().data());
639 } else if (num
== 2) {
640 text_str
= text_str
+ QString(_(" +1 unit"));
642 text_label
.setText(text_str
);
643 font
.setPixelSize((text_label
.height() * 9) / 10);
644 text_label
.setFont(font
);
645 fm
= new QFontMetrics(font
);
646 text_label
.setFixedWidth(fm
->width(text_str
) + 20);
649 unit_pixmap
= qtg_canvas_create(tileset_unit_width(tileset
),
650 tileset_unit_height(tileset
));
651 unit_pixmap
->map_pixmap
.fill(Qt::transparent
);
652 put_unit(punit
, unit_pixmap
, 1, 0, 0);
653 img
= unit_pixmap
->map_pixmap
.toImage();
654 crop
= zealous_crop_rect(img
);
655 cropped_img
= img
.copy(crop
);
656 img
= cropped_img
.scaledToHeight(height(), Qt::SmoothTransformation
);
657 pix
= QPixmap::fromImage(img
);
658 /* add transparent borders if image is too slim */
659 if (pix
.width() < tileset_unit_width(tileset
)) {
660 int px
= tileset_full_tile_width(tileset
);
661 pix2
= QPixmap(px
, pix
.height());
662 pix2
.fill(Qt::transparent
);
664 p
.drawPixmap(px
/ 2 - pix
.width() / 2, 0, pix
);
668 wwidth
= 2 * 3 + pix
.width();
669 unit_label
.setPixmap(pix
);
670 if (tileset_is_isometric(tileset
)) {
671 tile_pixmap
= qtg_canvas_create(tileset_full_tile_width(tileset
),
672 tileset_tile_height(tileset
) * 2);
674 tile_pixmap
= qtg_canvas_create(tileset_full_tile_width(tileset
),
675 tileset_tile_height(tileset
));
677 tile_pixmap
->map_pixmap
.fill(QColor(0 , 0 , 0 , 0));
678 put_terrain(punit
->tile
, tile_pixmap
, 1.0, 0, 0);
679 img
= tile_pixmap
->map_pixmap
.toImage();
680 crop
= zealous_crop_rect(img
);
681 cropped_img
= img
.copy(crop
);
682 if (cropped_img
.height() > height() - 5 ||
683 cropped_img
.height() < height() / 3) {
684 img
= cropped_img
.scaledToHeight(height() - 5,
685 Qt::SmoothTransformation
);
689 pix
= QPixmap::fromImage(img
);
690 tile_label
.setPixmap(pix
);
691 unit_label
.setToolTip(popup_info_text(punit
->tile
));
692 tile_label
.setToolTip(popup_terrain_info(punit
->tile
));
693 wwidth
= wwidth
+ pix
.width();
694 qtg_canvas_free(tile_pixmap
);
695 qtg_canvas_free(unit_pixmap
);
697 setFixedWidth(wwidth
+ qMax(unit_icons
->update_actions() * (height() * 8)
698 / 10, text_label
.width()));
700 setUpdatesEnabled(true);
707 /****************************************************************************
708 Custom label with extra mouse events
709 ****************************************************************************/
710 click_label::click_label() : QLabel()
712 connect(this, SIGNAL(left_clicked()), SLOT(on_clicked()));
715 /****************************************************************************
716 Mouse event for click_label
717 ****************************************************************************/
718 void click_label::mousePressEvent(QMouseEvent
*e
)
720 if (e
->button() == Qt::LeftButton
) {
725 /****************************************************************************
726 Centers on current unit
727 ****************************************************************************/
728 void click_label::on_clicked()
730 gui()->game_tab_widget
->setCurrentIndex(0);
731 request_center_focus_unit();
734 /****************************************************************************
735 Hud action constructor, used to show one action
736 ****************************************************************************/
737 hud_action::hud_action(QWidget
*parent
) : QWidget(parent
)
739 connect(this, SIGNAL(left_clicked()), SLOT(on_clicked()));
740 setFocusPolicy(Qt::ClickFocus
);
742 action_pixmap
= nullptr;
745 /****************************************************************************
746 Sets given pixmap for hud_action
747 ****************************************************************************/
748 void hud_action::set_pixmap(QPixmap
*p
)
753 /****************************************************************************
754 Custom painting for hud_action
755 ****************************************************************************/
756 void hud_action::paintEvent(QPaintEvent
*event
)
761 rx
= QRect(0, 0, width(), height());
762 ry
= QRect(0, 0, action_pixmap
->width(), action_pixmap
->height());
763 rz
= QRect(0, 0, width() - 1, height() - 3);
765 p
.setCompositionMode(QPainter::CompositionMode_Source
);
766 p
.setRenderHint(QPainter::SmoothPixmapTransform
);
767 p
.drawPixmap(rx
, *action_pixmap
, ry
);
768 p
.setPen(QColor(palette().color(QPalette::Text
)));
771 p
.setCompositionMode(QPainter::CompositionMode_DestinationOver
);
772 p
.fillRect(rx
, QColor(palette().color(QPalette::Highlight
)));
778 /****************************************************************************
779 Hud action destructor
780 ****************************************************************************/
781 hud_action::~hud_action()
784 delete action_pixmap
;
788 /****************************************************************************
789 Mouse press event for hud_action
790 ****************************************************************************/
791 void hud_action::mousePressEvent(QMouseEvent
*e
)
793 if (e
->button() == Qt::RightButton
) {
794 emit
right_clicked();
795 } else if (e
->button() == Qt::LeftButton
) {
800 /****************************************************************************
801 Leave event for hud_action, used to get status of pixmap higlight
802 ****************************************************************************/
803 void hud_action::leaveEvent(QEvent
*event
)
807 QWidget::leaveEvent(event
);
810 /****************************************************************************
811 Enter event for hud_action, used to get status of pixmap higlight
812 ****************************************************************************/
813 void hud_action::enterEvent(QEvent
*event
)
817 QWidget::enterEvent(event
);
820 /****************************************************************************
821 Right click event for hud_action
822 ****************************************************************************/
823 void hud_action::on_right_clicked()
827 /****************************************************************************
828 Left click event for hud_action
829 ****************************************************************************/
830 void hud_action::on_clicked()
832 gui()->menu_bar
->execute_shortcut(action_shortcut
);
835 /****************************************************************************
836 Units action contructor, holds possible hud_actions
837 ****************************************************************************/
838 unit_actions::unit_actions(QWidget
*parent
, unit
*punit
) : QWidget(parent
)
840 layout
= new QHBoxLayout(this);
841 layout
->setSpacing(3);
842 layout
->setContentsMargins(0, 0, 0, 0);
843 current_unit
= punit
;
845 setFocusPolicy(Qt::ClickFocus
);
850 /****************************************************************************
851 Destructor for unit_actions
852 ****************************************************************************/
853 unit_actions::~unit_actions()
860 /****************************************************************************
861 Initiazlizes layout ( layout needs to be changed after adding units )
862 ****************************************************************************/
863 void unit_actions::init_layout()
865 QSizePolicy
size_fixed_policy(QSizePolicy::MinimumExpanding
,
868 setSizePolicy(size_fixed_policy
);
869 layout
->setSpacing(0);
874 /****************************************************************************
875 Updates avaialable actions, returns actions count
876 ****************************************************************************/
877 int unit_actions::update_actions()
881 current_unit
= head_of_units_in_focus();
883 if (current_unit
== nullptr) {
890 setUpdatesEnabled(false);
893 foreach (a
, actions
) {
899 /* Create possible actions */
901 if (unit_can_build_city(current_unit
)) {
902 a
= new hud_action(this);
903 a
->action_shortcut
= SC_BUILDCITY
;
904 a
->set_pixmap(fc_icons::instance()->get_pixmap("home"));
909 if (can_unit_do_activity(current_unit
, ACTIVITY_MINE
)) {
910 struct terrain
*pterrain
= tile_terrain(unit_tile(current_unit
));
911 a
= new hud_action(this);
912 a
->action_shortcut
= SC_BUILDMINE
;
914 if (pterrain
->mining_result
!= T_NONE
915 && pterrain
->mining_result
!= pterrain
) {
916 if (!strcmp(terrain_rule_name(pterrain
), "Jungle")
917 || !strcmp(terrain_rule_name(pterrain
), "Plains")
918 || !strcmp(terrain_rule_name(pterrain
), "Grassland")
919 || !strcmp(terrain_rule_name(pterrain
), "Swamp")) {
920 a
->set_pixmap(fc_icons::instance()->get_pixmap("plantforest"));
922 a
->set_pixmap(fc_icons::instance()->get_pixmap("transform"));
925 a
->set_pixmap(fc_icons::instance()->get_pixmap("mine"));
929 if (can_unit_do_activity(current_unit
, ACTIVITY_IRRIGATE
)) {
930 struct terrain
*pterrain
= tile_terrain(unit_tile(current_unit
));
931 a
= new hud_action(this);
932 a
->action_shortcut
= SC_BUILDIRRIGATION
;
933 if (pterrain
->irrigation_result
!= T_NONE
934 && pterrain
->irrigation_result
!= pterrain
) {
935 if ((!strcmp(terrain_rule_name(pterrain
), "Forest") ||
936 !strcmp(terrain_rule_name(pterrain
), "Jungle"))) {
937 a
->set_pixmap(fc_icons::instance()->get_pixmap("chopchop"));
939 a
->set_pixmap(fc_icons::instance()->get_pixmap("transform"));
942 a
->set_pixmap(fc_icons::instance()->get_pixmap("irrigation"));
947 if (can_unit_do_activity(current_unit
, ACTIVITY_TRANSFORM
)) {
948 a
= new hud_action(this);
949 a
->action_shortcut
= SC_TRANSFORM
;
950 a
->set_pixmap(fc_icons::instance()->get_pixmap("transform"));
957 extra_type_by_cause_iterate(EC_ROAD
, pextra
) {
958 struct road_type
*proad
= extra_road_get(pextra
);
959 if (can_build_road(proad
, current_unit
, unit_tile(current_unit
))) {
963 extra_type_by_cause_iterate_end
;
965 a
= new hud_action(this);
966 a
->action_shortcut
= SC_BUILDROAD
;
967 a
->set_pixmap(fc_icons::instance()->get_pixmap("buildroad"));
972 a
= new hud_action(this);
973 a
->action_shortcut
= SC_GOTO
;
974 a
->set_pixmap(fc_icons::instance()->get_pixmap("goto"));
978 if (can_unit_do_activity(current_unit
, ACTIVITY_FORTIFYING
)) {
979 a
= new hud_action(this);
980 a
->action_shortcut
= SC_FORTIFY
;
981 a
->set_pixmap(fc_icons::instance()->get_pixmap("fortify"));
986 if (can_unit_do_activity(current_unit
, ACTIVITY_SENTRY
)) {
987 a
= new hud_action(this);
988 a
->action_shortcut
= SC_SENTRY
;
989 a
->set_pixmap(fc_icons::instance()->get_pixmap("sentry"));
993 if (unit_can_load(current_unit
)) {
994 a
= new hud_action(this);
995 a
->action_shortcut
= SC_LOAD
;
996 a
->set_pixmap(fc_icons::instance()->get_pixmap("load"));
1000 if (tile_city(unit_tile(current_unit
))) {
1001 if (can_unit_change_homecity_to(current_unit
,
1002 tile_city(unit_tile(current_unit
)))) {
1003 a
= new hud_action(this);
1004 a
->action_shortcut
= SC_SETHOME
;
1005 a
->set_pixmap(fc_icons::instance()->get_pixmap("set_homecity"));
1010 if (UU_OK
== unit_upgrade_test(current_unit
, FALSE
)) {
1011 a
= new hud_action(this);
1012 a
->action_shortcut
= SC_UPGRADE_UNIT
;
1013 a
->set_pixmap(fc_icons::instance()->get_pixmap("upgrade"));
1017 if (can_unit_do_autosettlers(current_unit
)) {
1018 a
= new hud_action(this);
1019 a
->action_shortcut
= SC_AUTOMATE
;
1020 a
->set_pixmap(fc_icons::instance()->get_pixmap("automate"));
1024 if (unit_has_type_flag(current_unit
, UTYF_PARATROOPERS
)) {
1025 a
= new hud_action(this);
1026 a
->action_shortcut
= SC_PARADROP
;
1027 a
->set_pixmap(fc_icons::instance()->get_pixmap("paradrop"));
1030 /* Clean pollution */
1031 if (can_unit_do_activity(current_unit
, ACTIVITY_POLLUTION
)) {
1032 a
= new hud_action(this);
1033 a
->action_shortcut
= SC_PARADROP
;
1034 a
->set_pixmap(fc_icons::instance()->get_pixmap("pollution"));
1038 if (unit_transported(current_unit
)
1039 && can_unit_unload(current_unit
, unit_transport_get(current_unit
))
1040 && can_unit_exist_at_tile(current_unit
, unit_tile(current_unit
))) {
1041 a
= new hud_action(this);
1042 a
->action_shortcut
= SC_UNLOAD
;
1043 a
->set_pixmap(fc_icons::instance()->get_pixmap("unload"));
1047 if (unit_has_type_flag(current_unit
, UTYF_NUCLEAR
)) {
1048 a
= new hud_action(this);
1049 a
->action_shortcut
= SC_NUKE
;
1050 a
->set_pixmap(fc_icons::instance()->get_pixmap("nuke"));
1055 a
= new hud_action(this);
1056 a
->action_shortcut
= SC_WAIT
;
1057 a
->set_pixmap(fc_icons::instance()->get_pixmap("wait"));
1061 a
= new hud_action(this);
1062 a
->action_shortcut
= SC_DONE_MOVING
;
1063 a
->set_pixmap(fc_icons::instance()->get_pixmap("done"));
1067 foreach (a
, actions
) {
1068 a
->setToolTip(gui()->menu_bar
->shortcut_2_menustring(a
->action_shortcut
));
1069 a
->setFixedHeight(height());
1070 a
->setFixedWidth(height());
1071 layout
->addWidget(a
);
1074 setFixedWidth(actions
.count() * height());
1075 setUpdatesEnabled(true);
1079 return actions
.count();
1082 /****************************************************************************
1083 Cleans layout - run it before layout initialization
1084 ****************************************************************************/
1085 void unit_actions::clear_layout()
1087 int i
= actions
.count();
1091 setUpdatesEnabled(false);
1092 for (j
= 0; j
< i
; j
++) {
1094 layout
->removeWidget(ui
);
1097 while (!actions
.empty()) {
1098 actions
.removeFirst();
1100 setUpdatesEnabled(true);
1103 /****************************************************************************
1104 Constructor for widget allowing loading units on transports
1105 ****************************************************************************/
1106 hud_unit_loader::hud_unit_loader(struct unit
*pcargo
, struct tile
*ptile
)
1108 setProperty("showGrid", "false");
1109 setProperty("selectionBehavior", "SelectRows");
1110 setEditTriggers(QAbstractItemView::NoEditTriggers
);
1111 setSelectionMode(QAbstractItemView::SingleSelection
);
1112 verticalHeader()->setVisible(false);
1113 horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents
);
1114 horizontalHeader()->setVisible(false);
1115 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff
);
1116 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff
);
1117 connect(selectionModel(),
1118 SIGNAL(selectionChanged(const QItemSelection
&,
1119 const QItemSelection
&)), this,
1120 SLOT(selection_changed(const QItemSelection
&,
1121 const QItemSelection
&)));
1127 /****************************************************************************
1128 Destructor for units loader
1129 ****************************************************************************/
1130 hud_unit_loader::~hud_unit_loader()
1135 /****************************************************************************
1136 Shows unit loader, adds possible tranportsand units to table
1137 Calculates table size
1138 ****************************************************************************/
1139 void hud_unit_loader::show_me()
1141 QTableWidgetItem
*new_item
;
1147 unit_list_iterate(qtile
->units
, ptransport
) {
1148 if (can_unit_transport(ptransport
, cargo
)
1149 && get_transporter_occupancy(ptransport
)
1150 < get_transporter_capacity(ptransport
)) {
1151 transports
.append(ptransport
);
1152 max_size
= qMax(max_size
, get_transporter_occupancy(ptransport
));
1154 } unit_list_iterate_end
;
1156 setRowCount(transports
.count());
1157 setColumnCount(max_size
+ 1);
1158 for (i
= 0 ; i
< transports
.count(); i
++) {
1160 spite
= get_unittype_sprite(tileset
, transports
.at(i
)->utype
,
1161 direction8_invalid(), true);
1162 str
= utype_rule_name(transports
.at(i
)->utype
);
1163 /* TRANS: MP - just movement points */
1165 + QString(move_points_text(transports
.at(i
)->moves_left
, false))
1167 new_item
= new QTableWidgetItem(QIcon(*spite
->pm
), str
);
1168 setItem(i
, 0, new_item
);
1170 unit_list_iterate(transports
.at(i
)->transporting
, tunit
) {
1171 spite
= get_unittype_sprite(tileset
, tunit
->utype
,
1172 direction8_invalid(), true);
1173 new_item
= new QTableWidgetItem(QIcon(*spite
->pm
), "");
1174 setItem(i
, j
, new_item
);
1176 } unit_list_iterate_end
;
1179 w
= verticalHeader()->width() + 4;
1180 for (i
= 0; i
< columnCount(); i
++) {
1181 w
+= columnWidth(i
);
1183 h
= horizontalHeader()->height() + 4;
1184 for (i
= 0; i
< rowCount(); i
++) {
1189 setWindowFlags(Qt::WindowStaysOnTopHint
| Qt::Dialog
1190 | Qt::FramelessWindowHint
);
1194 /****************************************************************************
1195 Selects given tranport and closes widget
1196 ****************************************************************************/
1197 void hud_unit_loader::selection_changed(const QItemSelection
& s1
,
1198 const QItemSelection
& s2
)
1202 curr_row
= s1
.indexes().at(0).row();
1203 request_unit_load(cargo
, transports
.at(curr_row
), qtile
);
1207 /****************************************************************************
1208 Constructor for unit_hud_selector
1209 ****************************************************************************/
1210 unit_hud_selector::unit_hud_selector(QWidget
*parent
) : QFrame(parent
)
1212 QHBoxLayout
*hbox
, *hibox
;
1213 Unit_type_id utype_id
;
1215 QVBoxLayout
*groupbox_layout
;
1218 struct unit
*punit
= head_of_units_in_focus();
1220 setWindowFlags(Qt::WindowStaysOnTopHint
| Qt::Dialog
1221 | Qt::FramelessWindowHint
);
1222 main_layout
= new QVBoxLayout(this);
1224 unit_sel_type
= new QComboBox();
1226 unit_type_iterate(utype
) {
1227 utype_id
= utype_index(utype
);
1228 if (has_player_unit_type(utype_id
)) {
1229 unit_sel_type
->addItem(utype_name_translation(utype
), utype_id
);
1232 unit_type_iterate_end
;
1236 i
= unit_sel_type
->findText(utype_name_translation(punit
->utype
));
1237 unit_sel_type
->setCurrentIndex(i
);
1239 no_name
= new QGroupBox();
1240 no_name
->setTitle(_("Unit type"));
1241 this_type
= new QRadioButton(_("Selected type"), no_name
);
1242 this_type
->setChecked(true);
1243 any_type
= new QRadioButton(_("All types"), no_name
);
1244 connect(unit_sel_type
, SIGNAL(currentIndexChanged(int)), this,
1245 SLOT(select_units(int)));
1246 connect(this_type
, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1247 connect(any_type
, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1248 groupbox_layout
= new QVBoxLayout
;
1249 groupbox_layout
->addWidget(unit_sel_type
);
1250 groupbox_layout
->addWidget(this_type
);
1251 groupbox_layout
->addWidget(any_type
);
1252 no_name
->setLayout(groupbox_layout
);
1253 hibox
= new QHBoxLayout
;
1254 hibox
->addWidget(no_name
);
1256 no_name
= new QGroupBox();
1257 no_name
->setTitle(_("Unit activity"));
1258 any_activity
= new QRadioButton(_("Any activity"), no_name
);
1259 any_activity
->setChecked(true);
1260 fortified
= new QRadioButton(_("Fortified"), no_name
);
1261 idle
= new QRadioButton(_("Idle"), no_name
);
1262 sentried
= new QRadioButton(_("Sentried"), no_name
);
1263 connect(any_activity
, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1264 connect(idle
, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1265 connect(fortified
, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1266 connect(sentried
, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1267 groupbox_layout
= new QVBoxLayout
;
1268 groupbox_layout
->addWidget(any_activity
);
1269 groupbox_layout
->addWidget(idle
);
1270 groupbox_layout
->addWidget(fortified
);
1271 groupbox_layout
->addWidget(sentried
);
1272 no_name
->setLayout(groupbox_layout
);
1273 hibox
->addWidget(no_name
);
1274 main_layout
->addLayout(hibox
);
1276 no_name
= new QGroupBox();
1277 no_name
->setTitle(_("Unit HP and MP"));
1278 any
= new QRadioButton(_("Any unit"), no_name
);
1279 full_hp
= new QRadioButton(_("Full HP"), no_name
);
1280 full_mp
= new QRadioButton(_("Full MP"), no_name
);
1281 full_hp_mp
= new QRadioButton(_("Full HP and MP"), no_name
);
1282 full_hp_mp
->setChecked(true);
1283 connect(any
, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1284 connect(full_hp
, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1285 connect(full_mp
, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1286 connect(full_hp_mp
, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1287 groupbox_layout
= new QVBoxLayout
;
1288 groupbox_layout
->addWidget(any
);
1289 groupbox_layout
->addWidget(full_hp
);
1290 groupbox_layout
->addWidget(full_mp
);
1291 groupbox_layout
->addWidget(full_hp_mp
);
1292 no_name
->setLayout(groupbox_layout
);
1293 hibox
= new QHBoxLayout
;
1294 hibox
->addWidget(no_name
);
1296 no_name
= new QGroupBox();
1297 no_name
->setTitle(_("Location"));
1298 everywhere
= new QRadioButton(_("Everywhere"), no_name
);
1299 this_tile
= new QRadioButton(_("Current tile"), no_name
);
1300 this_continent
= new QRadioButton(_("Current continent"), no_name
);
1301 main_continent
= new QRadioButton(_("Main continent"), no_name
);
1302 groupbox_layout
= new QVBoxLayout
;
1305 this_tile
->setChecked(true);
1307 this_tile
->setDisabled(true);
1308 this_continent
->setDisabled(true);
1309 main_continent
->setChecked(true);
1312 groupbox_layout
->addWidget(this_tile
);
1313 groupbox_layout
->addWidget(this_continent
);
1314 groupbox_layout
->addWidget(main_continent
);
1315 groupbox_layout
->addWidget(everywhere
);
1317 no_name
->setLayout(groupbox_layout
);
1318 hibox
->addWidget(no_name
);
1319 main_layout
->addLayout(hibox
);
1321 select
= new QPushButton(_("Select"));
1322 cancel
= new QPushButton(_("Cancel"));
1323 connect(everywhere
, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1324 connect(this_tile
, SIGNAL(toggled(bool)), this, SLOT(select_units(bool)));
1325 connect(this_continent
, SIGNAL(toggled(bool)), this,
1326 SLOT(select_units(bool)));
1327 connect(main_continent
, SIGNAL(toggled(bool)), this,
1328 SLOT(select_units(bool)));
1329 connect(select
, SIGNAL(clicked()), this, SLOT(uhs_select()));
1330 connect(cancel
, SIGNAL(clicked()), this, SLOT(uhs_cancel()));
1331 hbox
= new QHBoxLayout
;
1332 hbox
->addWidget(cancel
);
1333 hbox
->addWidget(select
);
1335 result_label
.setAlignment(Qt::AlignCenter
);
1336 main_layout
->addWidget(&result_label
, Qt::AlignHCenter
);
1337 main_layout
->addLayout(hbox
);
1338 setLayout(main_layout
);
1342 /****************************************************************************
1343 Shows and moves to center unit_hud_selector
1344 ****************************************************************************/
1345 void unit_hud_selector::show_me()
1349 p
= QPoint((parentWidget()->width() - sizeHint().width()) / 2,
1350 (parentWidget()->height() - sizeHint().height()) / 2);
1351 p
= parentWidget()->mapToGlobal(p
);
1358 /****************************************************************************
1359 Unit_hud_selector destructor
1360 ****************************************************************************/
1361 unit_hud_selector::~unit_hud_selector()
1366 /****************************************************************************
1367 Selects and closes widget
1368 ****************************************************************************/
1369 void unit_hud_selector::uhs_select()
1371 const struct player
*pplayer
;
1373 pplayer
= client_player();
1375 unit_list_iterate(pplayer
->units
, punit
) {
1376 if (activity_filter(punit
) && hp_filter(punit
)
1377 && island_filter(punit
) && type_filter(punit
)) {
1378 unit_focus_add(punit
);
1380 } unit_list_iterate_end
;
1384 /****************************************************************************
1385 Closes current widget
1386 ****************************************************************************/
1387 void unit_hud_selector::uhs_cancel()
1392 /****************************************************************************
1393 Shows number of selected units on label
1394 ****************************************************************************/
1395 void unit_hud_selector::select_units(int x
)
1398 const struct player
*pplayer
;
1400 pplayer
= client_player();
1402 unit_list_iterate(pplayer
->units
, punit
) {
1403 if (activity_filter(punit
) && hp_filter(punit
)
1404 && island_filter(punit
) && type_filter(punit
)) {
1407 } unit_list_iterate_end
;
1408 result_label
.setText(QString(PL_("%1 unit", "%1 units", num
)).arg(num
));
1411 /****************************************************************************
1412 Convinient slot for ez connect
1413 ****************************************************************************/
1414 void unit_hud_selector::select_units(bool x
)
1419 /****************************************************************************
1420 Key press event for unit_hud_selector
1421 ****************************************************************************/
1422 void unit_hud_selector::keyPressEvent(QKeyEvent
*event
)
1424 if ((event
->key() == Qt::Key_Return
)
1425 || (event
->key() == Qt::Key_Enter
)) {
1428 if (event
->key() == Qt::Key_Escape
) {
1432 QWidget::keyPressEvent(event
);
1435 /****************************************************************************
1437 ****************************************************************************/
1438 bool unit_hud_selector::activity_filter(struct unit
*punit
)
1440 if ((punit
->activity
== ACTIVITY_FORTIFIED
&& fortified
->isChecked())
1441 || (punit
->activity
== ACTIVITY_SENTRY
&& sentried
->isChecked())
1442 || (punit
->activity
== ACTIVITY_IDLE
&& idle
->isChecked())
1443 || any_activity
->isChecked()) {
1449 /****************************************************************************
1451 ****************************************************************************/
1452 bool unit_hud_selector::hp_filter(struct unit
*punit
)
1454 if ((any
->isChecked()
1455 || (full_mp
->isChecked()
1456 && punit
->moves_left
>= punit
->utype
->move_rate
)
1457 || (full_hp
->isChecked() && punit
->hp
>= punit
->utype
->hp
)
1458 || (full_hp_mp
->isChecked() && punit
->hp
>= punit
->utype
->hp
1459 && punit
->moves_left
>= punit
->utype
->move_rate
))) {
1465 /****************************************************************************
1467 ****************************************************************************/
1468 bool unit_hud_selector::island_filter(struct unit
*punit
)
1471 struct unit
*cunit
= head_of_units_in_focus();
1473 if (this_tile
->isChecked() && cunit
) {
1474 if (punit
->tile
== cunit
->tile
) {
1479 if (main_continent
->isChecked() && player_capital(client_player())) {
1480 island
= player_capital(client_player())->tile
->continent
;
1481 } else if (this_continent
->isChecked() && cunit
) {
1482 island
= cunit
->tile
->continent
;
1486 if (punit
->tile
->continent
== island
) {
1491 if (everywhere
->isChecked()) {
1497 /****************************************************************************
1499 ****************************************************************************/
1500 bool unit_hud_selector::type_filter(struct unit
*punit
)
1503 Unit_type_id utype_id
;
1505 if (this_type
->isChecked()) {
1506 qvar
= unit_sel_type
->currentData();
1507 utype_id
= qvar
.toInt();
1508 if (utype_id
== utype_index(punit
->utype
)) {
1514 if (any_type
->isChecked()) {
1520 /****************************************************************************
1521 Tooltip text for terrain information
1522 ****************************************************************************/
1523 QString
popup_terrain_info(struct tile
*ptile
)
1526 struct terrain
*terr
;
1528 terr
= ptile
->terrain
;
1529 ret
= QString(_("Terrain: %1\n")).arg(tile_get_info_text(ptile
, TRUE
, 0));
1530 ret
= ret
+ QString(_("Food/Prod/Trade: %1\n"))
1531 .arg(get_tile_output_text(ptile
));
1532 t
= get_infrastructure_text(ptile
->extras
);
1534 ret
= ret
+ QString(_("Infrastructure: %1\n")).arg(t
);
1536 ret
= ret
+ QString(_("Defence bonus: %1%")).arg(terr
->defense_bonus
);
1540 /****************************************************************************
1541 Shows new turn information with big font
1542 ****************************************************************************/
1543 void show_new_turn_info()
1547 QList
<hud_text
*> close_list
;
1548 struct research
*research
;
1551 if (client_has_player() == false
1552 || gui()->qt_settings
.show_new_turn_text
== false) {
1555 close_list
= gui()->mapview_wdg
->findChildren
<hud_text
*>();
1556 for (i
= 0; i
< close_list
.size(); ++i
) {
1557 close_list
.at(i
)->close();
1558 close_list
.at(i
)->deleteLater();
1560 research
= research_get(client_player());
1561 s
= QString(_("Year: %1 (Turn: %2)"))
1562 .arg(calendar_text()).arg(game
.info
.turn
) + "\n";
1563 s
= s
+ QString(nation_plural_for_player(client_player()));
1564 s
= s
+ " - " + QString(_("Population: %1"))
1565 .arg(population_to_text(civ_population(client
.conn
.playing
)));
1566 if (research
->researching
!= A_UNKNOWN
1567 && research
->researching
!= A_UNSET
1568 && research
->researching
!= A_NONE
) {
1569 s
= s
+ "\n" + QString(research_advance_name_translation(research
,
1570 research
->researching
)) +
1571 " (" + QString::number(research
->bulbs_researched
) + "/"
1572 + QString::number(research
->client
.researching_cost
) + ")";
1574 s
= s
+ "\n" + science_dialog_text() + "\n";
1575 s
= s
+ QString(_("Gold: %1 (+%2)"))
1576 .arg(client
.conn
.playing
->economic
.gold
)
1577 .arg(player_get_expected_income(client
.conn
.playing
));
1578 ht
= new hud_text(s
, 5, gui()->mapview_wdg
);