Added translator comment about government overthrown message.
[freeciv.git] / client / gui-qt / dialogs.cpp
blobfed71da6cc2527c082873ed065bc7dcdebc98548
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 <QComboBox>
20 #include <QHeaderView>
21 #include <QImage>
22 #include <QMessageBox>
23 #include <QRadioButton>
24 #include <QRect>
25 #include <QTableWidgetItem>
26 #include <QTextEdit>
28 // utility
29 #include "astring.h"
31 // common
32 #include "actions.h"
33 #include "city.h"
34 #include "game.h"
35 #include "government.h"
36 #include "improvement.h"
37 #include "movement.h"
38 #include "nation.h"
39 #include "research.h"
41 // client
42 #include "audio.h"
43 #include "control.h"
44 #include "helpdata.h"
45 #include "packhand.h"
46 #include "text.h"
47 #include "tilespec.h"
49 // gui-qt
50 #include "dialogs.h"
51 #include "hudwidget.h"
52 #include "qtg_cxxside.h"
53 #include "sprite.h"
55 /* Locations for non action enabler controlled buttons. */
56 #define BUTTON_MOVE ACTION_COUNT
57 #define BUTTON_WAIT BUTTON_MOVE + 1
58 #define BUTTON_CANCEL BUTTON_MOVE + 2
59 #define BUTTON_COUNT BUTTON_MOVE + 3
61 extern void popdown_all_spaceships_dialogs();
62 extern void popdown_players_report();
63 extern void popdown_economy_report();
64 extern void popdown_units_report();
65 extern void popdown_science_report();
66 extern void popdown_city_report();
67 extern void popdown_endgame_report();
69 static void act_sel_keep_moving(QVariant data1, QVariant data2);
70 static void diplomat_incite(QVariant data1, QVariant data2);
71 static void spy_request_sabotage_list(QVariant data1, QVariant data2);
72 static void spy_sabotage(QVariant data1, QVariant data2);
73 static void spy_steal(QVariant data1, QVariant data2);
74 static void spy_steal_something(QVariant data1, QVariant data2);
75 static void diplomat_steal(QVariant data1, QVariant data2);
76 static void spy_poison(QVariant data1, QVariant data2);
77 static void spy_steal_gold(QVariant data1, QVariant data2);
78 static void diplomat_embassy(QVariant data1, QVariant data2);
79 static void spy_sabotage_unit(QVariant data1, QVariant data2);
80 static void diplomat_investigate(QVariant data1, QVariant data2);
81 static void diplomat_sabotage(QVariant data1, QVariant data2);
82 static void diplomat_bribe(QVariant data1, QVariant data2);
83 static void caravan_marketplace(QVariant data1, QVariant data2);
84 static void caravan_establish_trade(QVariant data1, QVariant data2);
85 static void caravan_help_build(QVariant data1, QVariant data2);
86 static void keep_moving(QVariant data1, QVariant data2);
87 static void pillage_something(QVariant data1, QVariant data2);
88 static void action_entry(choice_dialog *cd,
89 gen_action act,
90 const struct act_prob *act_probs,
91 QString custom,
92 QVariant data1, QVariant data2);
95 static bool is_showing_pillage_dialog = false;
96 static races_dialog* race_dialog;
97 static bool is_race_dialog_open = false;
99 /* Information used in action selection follow up questions. Can't be
100 * stored in the action selection dialog since it is closed before the
101 * follow up question is asked. */
102 static bool is_more_user_input_needed = FALSE;
104 /* Don't remove a unit's action decision want or move on to the next actor
105 unit that wants a decision in the current unit selection. */
106 static bool did_not_decide = false;
108 qdef_act* qdef_act::m_instance = 0;
110 /**********************************************************************
111 Initialize a mapping between an action and the function to call if
112 the action's button is pushed.
113 **********************************************************************/
114 static const QHash<enum gen_action, pfcn_void> af_map_init(void)
116 QHash<enum gen_action, pfcn_void> action_function;
118 /* Unit acting against a city target. */
119 action_function[ACTION_ESTABLISH_EMBASSY] = diplomat_embassy;
120 action_function[ACTION_SPY_INVESTIGATE_CITY] = diplomat_investigate;
121 action_function[ACTION_SPY_POISON] = spy_poison;
122 action_function[ACTION_SPY_STEAL_GOLD] = spy_steal_gold;
123 action_function[ACTION_SPY_SABOTAGE_CITY] = diplomat_sabotage;
124 action_function[ACTION_SPY_TARGETED_SABOTAGE_CITY] =
125 spy_request_sabotage_list;
126 action_function[ACTION_SPY_STEAL_TECH] = diplomat_steal;
127 action_function[ACTION_SPY_TARGETED_STEAL_TECH] = spy_steal;
128 action_function[ACTION_SPY_INCITE_CITY] = diplomat_incite;
129 action_function[ACTION_TRADE_ROUTE] = caravan_establish_trade;
130 action_function[ACTION_MARKETPLACE] = caravan_marketplace;
131 action_function[ACTION_HELP_WONDER] = caravan_help_build;
133 /* Unit acting against a unit target. */
134 action_function[ACTION_SPY_BRIBE_UNIT] = diplomat_bribe;
135 action_function[ACTION_SPY_SABOTAGE_UNIT] = spy_sabotage_unit;
137 return action_function;
140 /* Mapping from an action to the function to call when its button is
141 * pushed. */
142 static const QHash<enum gen_action, pfcn_void> af_map = af_map_init();
144 /***************************************************************************
145 Constructor for selecting nations
146 ***************************************************************************/
147 races_dialog::races_dialog(struct player *pplayer,
148 QWidget *parent) : QDialog(parent)
150 int i;
151 QGridLayout *qgroupbox_layout;
152 QGroupBox *no_name;
153 QTableWidgetItem *item;
154 QPixmap *pix;
155 QHeaderView *header;
156 QSize size;
157 QString title;
158 QLabel *ns_label;
160 setAttribute(Qt::WA_DeleteOnClose);
161 is_race_dialog_open = true;
162 main_layout = new QGridLayout;
163 selected_nation_tabs = new QTableWidget;
164 nation_tabs = new QTableWidget();
165 styles = new QTableWidget;
166 ok_button = new QPushButton;
167 qnation_set = new QComboBox;
168 ns_label = new QLabel;
169 tplayer = pplayer;
171 selected_nation = -1;
172 selected_style = -1;
173 selected_sex = -1;
174 setWindowTitle(_("Select Nation"));
175 selected_nation_tabs->setRowCount(0);
176 selected_nation_tabs->setColumnCount(1);
177 selected_nation_tabs->setSelectionMode(QAbstractItemView::SingleSelection);
178 selected_nation_tabs->verticalHeader()->setVisible(false);
179 selected_nation_tabs->horizontalHeader()->setVisible(false);
180 selected_nation_tabs->setProperty("showGrid", "true");
181 selected_nation_tabs->setEditTriggers(QAbstractItemView::NoEditTriggers);
182 selected_nation_tabs->setShowGrid(false);
183 selected_nation_tabs->setAlternatingRowColors(true);
185 nation_tabs->setRowCount(0);
186 nation_tabs->setColumnCount(1);
187 nation_tabs->setSelectionMode(QAbstractItemView::SingleSelection);
188 nation_tabs->verticalHeader()->setVisible(false);
189 nation_tabs->horizontalHeader()->setVisible(false);
190 nation_tabs->setProperty("showGrid", "true");
191 nation_tabs->setEditTriggers(QAbstractItemView::NoEditTriggers);
192 nation_tabs->setShowGrid(false);
193 ns_label->setText(_("Nation Set:"));
194 styles->setRowCount(0);
195 styles->setColumnCount(2);
196 styles->setSelectionMode(QAbstractItemView::SingleSelection);
197 styles->verticalHeader()->setVisible(false);
198 styles->horizontalHeader()->setVisible(false);
199 styles->setProperty("showGrid", "false");
200 styles->setProperty("selectionBehavior", "SelectRows");
201 styles->setEditTriggers(QAbstractItemView::NoEditTriggers);
202 styles->setShowGrid(false);
204 qgroupbox_layout = new QGridLayout;
205 no_name = new QGroupBox(parent);
206 leader_name = new QComboBox(no_name);
207 is_male = new QRadioButton(no_name);
208 is_female = new QRadioButton(no_name);
210 leader_name->setEditable(true);
211 qgroupbox_layout->addWidget(leader_name, 1, 0, 1, 2);
212 qgroupbox_layout->addWidget(is_male, 2, 1);
213 qgroupbox_layout->addWidget(is_female, 2, 0);
214 is_female->setText(_("Female"));
215 is_male->setText(_("Male"));
216 no_name->setLayout(qgroupbox_layout);
218 description = new QTextEdit;
219 description->setReadOnly(true);
220 description->setText(_("Choose nation"));
221 no_name->setTitle(_("Your leader name"));
224 * Fill styles, no need to update them later
227 styles_iterate(pstyle) {
228 i = basic_city_style_for_style(pstyle);
230 if (i >= 0) {
231 item = new QTableWidgetItem;
232 styles->insertRow(i);
233 pix = get_sample_city_sprite(tileset, i)->pm;
234 item->setData(Qt::DecorationRole, *pix);
235 item->setData(Qt::UserRole, style_number(pstyle));
236 size.setWidth(pix->width());
237 size.setHeight(pix->height());
238 item->setSizeHint(size);
239 styles->setItem(i, 0, item);
240 item = new QTableWidgetItem;
241 item->setText(style_name_translation(pstyle));
242 styles->setItem(i, 1, item);
244 } styles_iterate_end;
246 header = styles->horizontalHeader();
247 header->setSectionResizeMode(QHeaderView::Stretch);
248 header->resizeSections(QHeaderView::ResizeToContents);
249 header = styles->verticalHeader();
250 header->resizeSections(QHeaderView::ResizeToContents);
251 nation_sets_iterate(pset) {
252 qnation_set->addItem(nation_set_name_translation(pset),
253 nation_set_rule_name(pset));
254 } nation_sets_iterate_end;
255 /* create nation sets */
256 refresh();
258 connect(styles->selectionModel(),
259 SIGNAL(selectionChanged(const QItemSelection &,
260 const QItemSelection &)),
261 SLOT(style_selected(const QItemSelection &,
262 const QItemSelection &)));
263 connect(selected_nation_tabs->selectionModel(),
264 SIGNAL(selectionChanged(const QItemSelection &,
265 const QItemSelection &)),
266 SLOT(nation_selected(const QItemSelection &,
267 const QItemSelection &)));
268 connect(leader_name, SIGNAL(currentIndexChanged(int)),
269 SLOT(leader_selected(int)));
270 connect(leader_name->lineEdit(), SIGNAL(returnPressed()),
271 SLOT(ok_pressed()));
272 connect(qnation_set, SIGNAL(currentIndexChanged(int)),
273 SLOT(nationset_changed(int)));
274 connect(nation_tabs->selectionModel(),
275 SIGNAL(selectionChanged(const QItemSelection &,
276 const QItemSelection &)),
277 SLOT(group_selected(const QItemSelection &,
278 const QItemSelection &)));
280 ok_button = new QPushButton;
281 ok_button->setText(_("Cancel"));
282 connect(ok_button, SIGNAL(pressed()), SLOT(cancel_pressed()));
283 main_layout->addWidget(ok_button, 8, 2, 1, 1);
284 random_button = new QPushButton;
285 random_button->setText(_("Random"));
286 connect(random_button, SIGNAL(pressed()), SLOT(random_pressed()));
287 main_layout->addWidget(random_button, 8, 0, 1, 1);
288 ok_button = new QPushButton;
289 ok_button->setText(_("Ok"));
290 connect(ok_button, SIGNAL(pressed()), SLOT(ok_pressed()));
291 main_layout->addWidget(ok_button, 8, 3, 1, 1);
292 main_layout->addWidget(no_name, 0, 3, 2, 1);
293 if (nation_set_count() > 1) {
294 main_layout->addWidget(ns_label, 0, 0, 1, 1);
295 main_layout->addWidget(qnation_set, 0, 1, 1, 1);
296 main_layout->addWidget(nation_tabs, 1, 0, 5, 2);
297 } else {
298 main_layout->addWidget(nation_tabs, 0, 0, 6, 2);
300 main_layout->addWidget(styles, 2, 3, 4, 1);
301 main_layout->addWidget(description, 6, 0, 2, 4);
302 main_layout->addWidget(selected_nation_tabs, 0, 2, 6, 1);
304 setLayout(main_layout);
305 set_index(-99);
307 if (C_S_RUNNING == client_state()) {
308 title = _("Edit Nation");
309 } else if (NULL != pplayer && pplayer == client.conn.playing) {
310 title = _("What Nation Will You Be?");
311 } else {
312 title = _("Pick Nation");
315 update_nationset_combo();
316 setWindowTitle(title);
319 /***************************************************************************
320 Destructor for races dialog
321 ***************************************************************************/
322 races_dialog::~races_dialog()
324 ::is_race_dialog_open = false;
327 /***************************************************************************
328 Sets first index to call update of nation list
329 ***************************************************************************/
330 void races_dialog::refresh()
332 struct nation_group *group;
333 QTableWidgetItem *item;
334 QHeaderView *header;
335 int i;
336 int count;
338 nation_tabs->clearContents();
339 nation_tabs->setRowCount(0);
340 nation_tabs->insertRow(0);
341 item = new QTableWidgetItem;
342 item->setText(_("All nations"));
343 item->setData(Qt::UserRole, -99);
344 nation_tabs->setItem(0, 0, item);
346 for (i = 1; i < nation_group_count() + 1; i++) {
347 group = nation_group_by_number(i - 1);
348 if (is_nation_group_hidden(group)) {
349 continue;
351 count = 0;
352 /* checking if group is empty */
353 nations_iterate(pnation) {
354 if (!is_nation_playable(pnation)
355 || !is_nation_pickable(pnation)
356 || !nation_is_in_group(pnation, group)) {
357 continue;
359 count ++;
360 } nations_iterate_end;
361 if (count == 0) {
362 continue;
364 nation_tabs->insertRow(i);
365 item = new QTableWidgetItem;
366 item->setData(Qt::UserRole, i - 1);
367 item->setText(nation_group_name_translation(group));
368 nation_tabs->setItem(i, 0, item);
370 header = nation_tabs->horizontalHeader();
371 header->resizeSections(QHeaderView::Stretch);
372 header = nation_tabs->verticalHeader();
373 header->resizeSections(QHeaderView::ResizeToContents);
374 set_index(-99);
377 /***************************************************************************
378 Updates nation_set combo ( usually called from option change )
379 ***************************************************************************/
380 void races_dialog::update_nationset_combo()
382 struct option *popt;
383 struct nation_set *s;
385 popt = optset_option_by_name(server_optset, "nationset");
386 if (popt) {
387 s = nation_set_by_setting_value(option_str_get(popt));
388 qnation_set->setCurrentIndex(nation_set_index(s));
389 qnation_set->setToolTip(nation_set_description(s));
393 /***************************************************************************
394 Selected group of nation
395 ***************************************************************************/
396 void races_dialog::group_selected(const QItemSelection &sl,
397 const QItemSelection &ds)
399 QModelIndexList indexes = sl.indexes();
400 QModelIndex index ;
402 if (indexes.isEmpty()) {
403 return;
405 index = indexes.at(0);
406 set_index(index.row());
410 /***************************************************************************
411 Sets new nations' group by current current selection,
412 index is used only when there is no current selection.
413 ***************************************************************************/
414 void races_dialog::set_index(int index)
416 QTableWidgetItem *item;
417 QPixmap *pix;
418 QFont f;
419 struct nation_group *group;
420 int i;
421 struct sprite *s;
422 QHeaderView *header;
423 selected_nation_tabs->clearContents();
424 selected_nation_tabs->setRowCount(0);
426 last_index = 0;
427 i = nation_tabs->currentRow();
428 if (i != -1) {
429 item = nation_tabs->item(i, 0);
430 index = item->data(Qt::UserRole).toInt();
433 group = nation_group_by_number(index);
434 i = 0;
435 nations_iterate(pnation) {
436 if (!is_nation_playable(pnation)
437 || !is_nation_pickable(pnation)) {
438 continue;
440 if (!nation_is_in_group(pnation, group) && index != -99) {
441 continue;
443 item = new QTableWidgetItem;
444 selected_nation_tabs->insertRow(i);
445 s = get_nation_flag_sprite(tileset, pnation);
446 if (pnation->player) {
447 f = item->font();
448 f.setStrikeOut(true);
449 item->setFont(f);
451 pix = s->pm;
452 item->setData(Qt::DecorationRole, *pix);
453 item->setData(Qt::UserRole, nation_number(pnation));
454 item->setText(nation_adjective_translation(pnation));
455 selected_nation_tabs->setItem(i, 0, item);
456 } nations_iterate_end;
458 selected_nation_tabs->sortByColumn(0, Qt::AscendingOrder);
459 header = selected_nation_tabs->horizontalHeader();
460 header->resizeSections(QHeaderView::Stretch);
461 header = selected_nation_tabs->verticalHeader();
462 header->resizeSections(QHeaderView::ResizeToContents);
465 /***************************************************************************
466 Sets selected nation and updates style and leaders selector
467 ***************************************************************************/
468 void races_dialog::nation_selected(const QItemSelection &selected,
469 const QItemSelection &deselcted)
471 char buf[4096];
472 QModelIndex index ;
473 QVariant qvar,qvar2;
474 QModelIndexList indexes = selected.indexes();
475 QString str;
476 QTableWidgetItem *item;
477 int style, ind;
479 if (indexes.isEmpty()) {
480 return;
483 index = indexes.at(0);
484 if (indexes.isEmpty()){
485 return;
487 qvar = index.data(Qt::UserRole);
488 selected_nation = qvar.toInt();
490 helptext_nation(buf, sizeof(buf), nation_by_number(selected_nation), NULL);
491 description->setText(buf);
492 leader_name->clear();
493 if (client.conn.playing == tplayer) {
494 leader_name->addItem(client.conn.playing->name, true);
496 nation_leader_list_iterate(nation_leaders(nation_by_number
497 (selected_nation)), pleader) {
498 str = QString::fromUtf8(nation_leader_name(pleader));
499 leader_name->addItem(str, nation_leader_is_male(pleader));
500 } nation_leader_list_iterate_end;
503 * select style for nation
506 style = style_number(style_of_nation(nation_by_number(selected_nation)));
507 qvar = qvar.fromValue<int>(style);
508 item = new QTableWidgetItem;
510 for (ind = 0; ind < styles->rowCount(); ind++) {
511 item = styles->item(ind, 0);
513 if (item->data(Qt::UserRole) == qvar) {
514 styles->selectRow(ind);
519 /***************************************************************************
520 Sets selected style
521 ***************************************************************************/
522 void races_dialog::style_selected(const QItemSelection &selected,
523 const QItemSelection &deselcted)
525 QModelIndex index ;
526 QVariant qvar;
527 QModelIndexList indexes = selected.indexes();
529 if (indexes.isEmpty()) {
530 return;
533 index = indexes.at(0);
534 qvar = index.data(Qt::UserRole);
535 selected_style = qvar.toInt();
538 /***************************************************************************
539 Sets selected leader
540 ***************************************************************************/
541 void races_dialog::leader_selected(int index)
543 if (leader_name->itemData(index).toBool()) {
544 is_male->setChecked(true);
545 is_female->setChecked(false);
546 selected_sex=0;
547 } else {
548 is_male->setChecked(false);
549 is_female->setChecked(true);
550 selected_sex=1;
554 /***************************************************************************
555 Button accepting all selection has been pressed, closes dialog if
556 everything is ok
557 ***************************************************************************/
558 void races_dialog::ok_pressed()
561 if (selected_nation == -1) {
562 return;
565 if (selected_sex == -1) {
566 output_window_append(ftc_client, _("You must select your sex."));
567 return;
570 if (selected_style == -1) {
571 output_window_append(ftc_client, _("You must select your style."));
572 return;
575 if (leader_name->currentText().length() == 0) {
576 output_window_append(ftc_client, _("You must type a legal name."));
577 return;
580 if (nation_by_number(selected_nation)->player != NULL) {
581 output_window_append(ftc_client,
582 _("Nation has been chosen by other player"));
583 return;
585 dsend_packet_nation_select_req(&client.conn, player_number(tplayer),
586 selected_nation, selected_sex,
587 leader_name->currentText().toUtf8().data(),
588 selected_style);
589 close();
590 deleteLater();
593 /***************************************************************************
594 Constructor for notify dialog
595 ***************************************************************************/
596 notify_dialog::notify_dialog(const char *caption, const char *headline,
597 const char *lines, QWidget *parent)
598 : fcwidget()
600 int x, y;
601 QString qlines;
603 setAttribute(Qt::WA_DeleteOnClose);
604 setCursor(Qt::ArrowCursor);
605 setParent(parent);
606 setFrameStyle(QFrame::Box);
607 cw = new close_widget(this);
608 cw->put_to_corner();
610 qcaption = QString(caption);
611 qheadline = QString(headline);
612 qlines = QString(lines);
613 qlist = qlines.split("\n");
614 small_font = *fc_font::instance()->get_font("gui_qt_font_notify_label");
615 x = 0;
616 y = 0;
617 calc_size(x, y);
618 resize(x, y);
619 gui()->mapview_wdg->find_place(gui()->mapview_wdg->width() - x - 4, 4,
620 x, y, x, y, 0);
621 move(x, y);
622 was_destroyed = false;
626 /***************************************************************************
627 Starts new copy of notify dialog and closes current one
628 ***************************************************************************/
629 void notify_dialog::restart()
631 QString s, q;
632 int i;
634 for (i = 0; i < qlist.size(); ++i) {
635 s = qlist.at(i);
636 q = q + s;
637 if (i < qlist.size() - 1) {
638 q = q + QChar('\n');
641 popup_notify_dialog(qcaption.toLocal8Bit().data(),
642 qheadline.toLocal8Bit().data(),
643 q.toLocal8Bit().data());
644 close();
645 destroy();
648 /***************************************************************************
649 Calculates size of notify dialog
650 ***************************************************************************/
651 void notify_dialog::calc_size(int &x, int &y)
653 QFontMetrics fm(small_font);
654 int i;
655 QStringList str_list;
657 str_list = qlist;
658 str_list << qcaption << qheadline;
660 for (i = 0; i < str_list.count(); i++) {
661 x = qMax(x, fm.width(str_list.at(i)));
662 y = y + 3 + fm.height();
664 x = x + 15;
668 /***************************************************************************
669 Paint Event for notify dialog
670 ***************************************************************************/
671 void notify_dialog::paintEvent(QPaintEvent * paint_event)
673 QPainter painter(this);
674 QPainterPath path;
675 QPen pen;
676 QFontMetrics fm(small_font);
677 int i;
679 pen.setWidth(1);
680 pen.setColor(palette().color(QPalette::Text));
681 painter.setFont(small_font);
682 painter.setPen(pen);
683 painter.drawText(10, fm.height() + 3, qcaption);
684 painter.drawText(10, 2 * fm.height() + 6, qheadline);
685 for (i = 0; i < qlist.count(); i++) {
686 painter.drawText(10, 3 + (fm.height() + 3) * (i + 3), qlist[i]);
688 cw->put_to_corner();
691 /**************************************************************************
692 Called when mouse button was pressed, just to close on right click
693 **************************************************************************/
694 void notify_dialog::mousePressEvent(QMouseEvent *event)
696 cursor = event->globalPos() - geometry().topLeft();
697 if (event->button() == Qt::RightButton){
698 was_destroyed = true;
699 close();
703 /**************************************************************************
704 Called when mouse button was pressed and moving around
705 **************************************************************************/
706 void notify_dialog::mouseMoveEvent(QMouseEvent *event)
708 move(event->globalPos() - cursor);
709 setCursor(Qt::SizeAllCursor);
712 /**************************************************************************
713 Called when mouse button unpressed. Restores cursor.
714 **************************************************************************/
715 void notify_dialog::mouseReleaseEvent(QMouseEvent *event)
717 setCursor(Qt::ArrowCursor);
720 /***************************************************************************
721 Called when close button was pressed
722 ***************************************************************************/
723 void notify_dialog::update_menu()
725 was_destroyed = true;
726 destroy();
729 /***************************************************************************
730 Destructor for notify dialog, notice that somehow object is not destroyed
731 immediately, so it can be still visible for parent, check boolean
732 was_destroyed if u suspect it could not be destroyed yet
733 ***************************************************************************/
734 notify_dialog::~notify_dialog()
736 was_destroyed = true;
737 destroy();
740 /****************************************************************************
741 Default actions provider constructor
742 ****************************************************************************/
743 qdef_act::qdef_act()
745 vs_city = -1;
746 vs_unit = -1;
749 /****************************************************************************
750 Returns instance of qdef_act
751 ****************************************************************************/
752 qdef_act *qdef_act::action()
754 if (!m_instance)
755 m_instance = new qdef_act;
756 return m_instance;
759 /****************************************************************************
760 Deletes qdef_act instance
761 ****************************************************************************/
762 void qdef_act::drop()
764 if (m_instance) {
765 delete m_instance;
766 m_instance = 0;
770 /****************************************************************************
771 Sets default action vs city
772 ****************************************************************************/
773 void qdef_act::vs_city_set(int i)
775 vs_city = i;
778 /****************************************************************************
779 Sets default action vs unit
780 ****************************************************************************/
781 void qdef_act::vs_unit_set(int i)
783 vs_unit = i;
786 /****************************************************************************
787 Returns default action vs city
788 ****************************************************************************/
789 int qdef_act::vs_city_get()
791 return vs_city;
794 /****************************************************************************
795 Returns default action vs unit
796 ****************************************************************************/
797 int qdef_act::vs_unit_get()
799 return vs_unit;
802 /***************************************************************************
803 Button canceling all selections has been pressed.
804 ***************************************************************************/
805 void races_dialog::cancel_pressed()
807 delete this;
810 /***************************************************************************
811 Sets random nation
812 ***************************************************************************/
813 void races_dialog::random_pressed()
815 dsend_packet_nation_select_req(&client.conn,player_number(tplayer),-1,
816 false, "", 0);
817 delete this;
820 /***************************************************************************
821 Notify goto dialog constructor
822 ***************************************************************************/
823 notify_goto::notify_goto(const char *headline, const char *lines,
824 const struct text_tag_list *tags, tile *ptile,
825 QWidget *parent): QMessageBox(parent)
827 QString qlines;
828 setAttribute(Qt::WA_DeleteOnClose);
829 goto_but = this->addButton(_("Goto Location"), QMessageBox::ActionRole);
830 goto_but->setIcon(fc_icons::instance()->get_icon("go-up"));
831 inspect_but = this->addButton(_("Inspect City"), QMessageBox::ActionRole);
832 inspect_but->setIcon(fc_icons::instance()->get_icon("plus"));
834 close_but = this->addButton(QMessageBox::Close);
835 gtile = ptile;
836 if (!gtile) {
837 goto_but->setVisible(false);
838 inspect_but->setVisible(false);
839 } else {
840 struct city *pcity = tile_city(gtile);
841 inspect_but->setVisible(NULL != pcity
842 && city_owner(pcity) == client.conn.playing);
844 setWindowTitle(headline);
845 qlines = lines;
846 qlines.replace("\n", " ");
847 setText(qlines);
848 connect(goto_but, SIGNAL(pressed()), SLOT(goto_tile()));
849 connect(inspect_but, SIGNAL(pressed()), SLOT(inspect_city()));
850 connect(close_but, SIGNAL(pressed()), SLOT(close()));
851 show();
854 /***************************************************************************
855 Clicked goto tile in notify goto dialog
856 ***************************************************************************/
857 void notify_goto::goto_tile()
859 center_tile_mapcanvas(gtile);
860 close();
863 /***************************************************************************
864 Clicked inspect city in notify goto dialog
865 ***************************************************************************/
866 void notify_goto::inspect_city()
868 struct city *pcity = tile_city(gtile);
869 if (pcity) {
870 qtg_real_city_dialog_popup(pcity);
872 close();
875 /***************************************************************************
876 User changed nation_set
877 ***************************************************************************/
878 void races_dialog::nationset_changed(int index)
880 QString rule_name;
881 char *rn;
882 struct option *poption = optset_option_by_name(server_optset, "nationset");
883 rule_name = qnation_set->currentData().toString();
884 rn = rule_name.toLocal8Bit().data();
885 if (nation_set_by_setting_value(option_str_get(poption))
886 != nation_set_by_rule_name(rn)) {
887 option_str_set(poption, rn);
891 /**************************************************************************
892 Popup a dialog to display information about an event that has a
893 specific location. The user should be given the option to goto that
894 location.
895 **************************************************************************/
896 void popup_notify_goto_dialog(const char *headline, const char *lines,
897 const struct text_tag_list *tags,
898 struct tile *ptile)
900 notify_goto *ask = new notify_goto(headline, lines, tags, ptile,
901 gui()->central_wdg);
902 ask->show();
905 /**************************************************************************
906 Popup a dialog to display connection message from server.
907 **************************************************************************/
908 void popup_connect_msg(const char *headline, const char *message)
910 QMessageBox msg(gui()->central_wdg);
912 msg.setText(message);
913 msg.setStandardButtons(QMessageBox::Ok);
914 msg.setWindowTitle(headline);
915 msg.exec();
919 /**************************************************************************
920 Popup a generic dialog to display some generic information.
921 **************************************************************************/
922 void popup_notify_dialog(const char *caption, const char *headline,
923 const char *lines)
925 notify_dialog *nd = new notify_dialog(caption, headline, lines,
926 gui()->mapview_wdg);
927 nd->show();
930 /**************************************************************************
931 Popup the nation selection dialog.
932 **************************************************************************/
933 void popup_races_dialog(struct player *pplayer)
935 if (!is_race_dialog_open) {
936 race_dialog = new races_dialog(pplayer, gui()->central_wdg);
937 is_race_dialog_open = true;
938 race_dialog->show();
940 race_dialog->showNormal();
943 /**************************************************************************
944 Close the nation selection dialog. This should allow the user to
945 (at least) select a unit to activate.
946 **************************************************************************/
947 void popdown_races_dialog(void)
949 if (is_race_dialog_open){
950 race_dialog->close();
951 is_race_dialog_open = false;
955 /**************************************************************************
956 Popup a dialog window to select units on a particular tile.
957 **************************************************************************/
958 void unit_select_dialog_popup(struct tile *ptile)
960 if(ptile != NULL && (unit_list_size(ptile->units) > 1
961 || (unit_list_size(ptile->units) == 1 && tile_city(ptile)))) {
962 gui()->toggle_unit_sel_widget(ptile);
966 /**************************************************************************
967 Update the dialog window to select units on a particular tile.
968 **************************************************************************/
969 void unit_select_dialog_update_real(void)
971 gui()->update_unit_sel();
974 /**************************************************************************
975 Updates nationset combobox
976 **************************************************************************/
977 void update_nationset_combo()
979 if (is_race_dialog_open) {
980 race_dialog->update_nationset_combo();
984 /**************************************************************************
985 The server has changed the set of selectable nations.
986 **************************************************************************/
987 void races_update_pickable(bool nationset_change)
989 if (is_race_dialog_open){
990 race_dialog->refresh();
994 /**************************************************************************
995 In the nation selection dialog, make already-taken nations unavailable.
996 This information is contained in the packet_nations_used packet.
997 **************************************************************************/
998 void races_toggles_set_sensitive(void)
1000 if (is_race_dialog_open) {
1001 race_dialog->refresh();
1005 /**************************************************************************
1006 Popup a dialog asking if the player wants to start a revolution.
1007 **************************************************************************/
1008 void popup_revolution_dialog(struct government *government)
1010 hud_message_box ask(gui()->central_wdg);
1011 int ret;
1013 if (0 > client.conn.playing->revolution_finishes) {
1014 ask.setStandardButtons(QMessageBox::Cancel | QMessageBox::Ok);
1015 ask.setDefaultButton(QMessageBox::Cancel);
1016 ask.set_text_title(_("You say you wanna revolution?"),
1017 _("Revolution!"));
1018 ret = ask.exec();
1020 switch (ret) {
1021 case QMessageBox::Cancel:
1022 break;
1023 case QMessageBox::Ok:
1024 revolution_response(government);
1025 break;
1027 } else {
1028 revolution_response(government);
1032 /**************************************************************************
1033 Constructor for choice_dialog_button_data
1034 **************************************************************************/
1035 Choice_dialog_button::Choice_dialog_button(const QString title,
1036 pfcn_void func_in,
1037 QVariant data1_in,
1038 QVariant data2_in)
1039 : QPushButton(title)
1041 func = func_in;
1042 data1 = data1_in;
1043 data2 = data2_in;
1046 /**************************************************************************
1047 Get the function to call when the button is pressed.
1048 **************************************************************************/
1049 pfcn_void Choice_dialog_button::getFunc()
1051 return func;
1054 /**************************************************************************
1055 Get the first piece of data to feed the function when the button is
1056 pressed.
1057 **************************************************************************/
1058 QVariant Choice_dialog_button::getData1()
1060 return data1;
1063 /**************************************************************************
1064 Get the second piece of data to feed the function when the button is
1065 pressed.
1066 **************************************************************************/
1067 QVariant Choice_dialog_button::getData2()
1069 return data2;
1072 /**************************************************************************
1073 Sets the first piece of data
1074 **************************************************************************/
1075 void Choice_dialog_button::setData1(QVariant wariat)
1077 data1 = wariat;
1080 /**************************************************************************
1081 Sets the second piece of data
1082 **************************************************************************/
1083 void Choice_dialog_button::setData2(QVariant wariat)
1085 data2 = wariat;
1088 /***************************************************************************
1089 Constructor for choice_dialog
1090 ***************************************************************************/
1091 choice_dialog::choice_dialog(const QString title, const QString text,
1092 QWidget *parent,
1093 void (*run_on_close_in)(int)): QWidget(parent)
1095 QLabel *l = new QLabel(text);
1097 setProperty("themed_choice", true);
1098 signal_mapper = new QSignalMapper(this);
1099 layout = new QVBoxLayout(this);
1100 run_on_close = run_on_close_in;
1102 layout->addWidget(l);
1103 setWindowFlags(Qt::Dialog);
1104 setWindowTitle(title);
1105 setAttribute(Qt::WA_DeleteOnClose);
1106 gui()->set_diplo_dialog(this);
1108 unit_id = IDENTITY_NUMBER_ZERO;
1109 target_id[ATK_CITY] = IDENTITY_NUMBER_ZERO;
1110 target_id[ATK_UNIT] = IDENTITY_NUMBER_ZERO;
1112 targeted_unit = nullptr;
1113 /* No buttons are added yet. */
1114 for (int i = 0; i < BUTTON_COUNT; i++) {
1115 action_button_map << NULL;
1119 /***************************************************************************
1120 Destructor for choice dialog
1121 ***************************************************************************/
1122 choice_dialog::~choice_dialog()
1124 buttons_list.clear();
1125 action_button_map.clear();
1126 delete signal_mapper;
1127 gui()->set_diplo_dialog(NULL);
1129 if (run_on_close) {
1130 run_on_close(unit_id);
1131 run_on_close = NULL;
1135 /***************************************************************************
1136 Sets layout for choice dialog
1137 ***************************************************************************/
1138 void choice_dialog::set_layout()
1141 targeted_unit = game_unit_by_number(target_id[ATK_UNIT]);
1143 if ((game_unit_by_number(unit_id)) && targeted_unit
1144 && unit_list_size(targeted_unit->tile->units) > 1) {
1145 struct canvas *pix;
1146 QPushButton *next, *prev;
1147 unit_skip = new QHBoxLayout;
1148 next = new QPushButton();
1149 next->setIcon(fc_icons::instance()->get_icon("city-right"));
1150 next->setIconSize(QSize(32, 32));
1151 next->setFixedSize(QSize(36, 36));
1152 prev = new QPushButton();
1153 prev->setIcon(fc_icons::instance()->get_icon("city-left"));
1154 prev->setIconSize(QSize(32, 32));
1155 prev->setFixedSize(QSize(36, 36));
1156 target_unit_button = new QPushButton;
1157 pix = qtg_canvas_create(tileset_unit_width(tileset),
1158 tileset_unit_height(tileset));
1159 pix->map_pixmap.fill(Qt::transparent);
1160 put_unit(targeted_unit, pix, 1.0, 0, 0);
1161 target_unit_button->setIcon(QIcon(pix->map_pixmap));
1162 qtg_canvas_free(pix);
1163 target_unit_button->setIconSize(QSize(96, 96));
1164 target_unit_button->setFixedSize(QSize(100, 100));
1165 unit_skip->addStretch(100);
1166 unit_skip->addWidget(prev, Qt::AlignCenter);
1167 unit_skip->addWidget(target_unit_button, Qt::AlignCenter);
1168 unit_skip->addWidget(next, Qt::AlignCenter);
1169 layout->addLayout(unit_skip);
1170 unit_skip->addStretch(100);
1171 connect(prev, SIGNAL(clicked()), SLOT(prev_unit()));
1172 connect(next, SIGNAL(clicked()), SLOT(next_unit()));
1175 connect(signal_mapper, SIGNAL(mapped(const int &)),
1176 this, SLOT(execute_action(const int &)));
1177 setLayout(layout);
1180 /***************************************************************************
1181 Adds new action for choice dialog
1182 ***************************************************************************/
1183 void choice_dialog::add_item(QString title, pfcn_void func, QVariant data1,
1184 QVariant data2, QString tool_tip = "",
1185 const int button_id = -1)
1187 Choice_dialog_button *button = new Choice_dialog_button(title, func,
1188 data1, data2);
1189 connect(button, SIGNAL(clicked()), signal_mapper, SLOT(map()));
1190 signal_mapper->setMapping(button, buttons_list.count());
1191 buttons_list.append(button);
1193 if (!tool_tip.isEmpty()) {
1194 button->setToolTip(tool_tip);
1197 if (0 <= button_id) {
1198 /* The id is valid. */
1199 action_button_map[button_id] = button;
1202 layout->addWidget(button);
1205 /***************************************************************************
1206 Shows choice dialog
1207 ***************************************************************************/
1208 void choice_dialog::show_me()
1210 QPoint p;
1212 p = mapFromGlobal(QCursor::pos());
1213 p.setY(p.y()-this->height());
1214 p.setX(p.x()-this->width());
1215 move(p);
1216 show();
1219 /***************************************************************************
1220 Returns layout in choice dialog
1221 ***************************************************************************/
1222 QVBoxLayout *choice_dialog::get_layout()
1224 return layout;
1227 /**************************************************************************
1228 Get the button with the given identity.
1229 **************************************************************************/
1230 Choice_dialog_button *choice_dialog::get_identified_button(const int id)
1232 if (id < 0) {
1233 fc_assert_msg(0 <= id, "Invalid button ID.");
1234 return NULL;
1237 return action_button_map[id];
1240 /***************************************************************************
1241 Try to pick up default unit action
1242 ***************************************************************************/
1243 bool try_default_unit_action(QVariant q1, QVariant q2)
1245 int action;
1246 pfcn_void func;
1248 action = qdef_act::action()->vs_unit_get();
1249 if (action == -1) {
1250 return false;
1252 func = af_map[static_cast<gen_action>(action)];
1254 func(q1, q2);
1255 return true;
1258 /***************************************************************************
1259 Try to pick up default city action
1260 ***************************************************************************/
1261 bool try_default_city_action(QVariant q1, QVariant q2)
1263 int action;
1264 pfcn_void func;
1266 action = qdef_act::action()->vs_city_get();
1267 if (action == -1) {
1268 return false;
1270 func = af_map[static_cast<gen_action>(action)];
1271 func(q1, q2);
1272 return true;
1275 /***************************************************************************
1276 Focus next target
1277 ***************************************************************************/
1278 void choice_dialog::next_unit()
1280 struct tile *ptile;
1281 struct unit *new_target = nullptr;
1282 bool break_next = false;
1283 bool first = true;
1284 struct canvas *pix;
1286 if (targeted_unit == nullptr) {
1287 return;
1290 ptile = targeted_unit->tile;
1292 unit_list_iterate(ptile->units, ptgt) {
1293 if (first) {
1294 new_target = ptgt;
1295 first = false;
1297 if (break_next == true) {
1298 new_target = ptgt;
1299 break;
1301 if (ptgt == targeted_unit) {
1302 break_next = true;
1304 } unit_list_iterate_end;
1305 targeted_unit = new_target;
1306 pix = qtg_canvas_create(tileset_unit_width(tileset),
1307 tileset_unit_height(tileset));
1308 pix->map_pixmap.fill(Qt::transparent);
1309 put_unit(targeted_unit, pix, 1.0, 0, 0);
1310 target_unit_button->setIcon(QIcon(pix->map_pixmap));
1311 qtg_canvas_free(pix);
1312 switch_target();
1315 /***************************************************************************
1316 Focus previous target
1317 ***************************************************************************/
1318 void choice_dialog::prev_unit()
1320 struct tile *ptile;
1321 struct unit *new_target = nullptr;
1322 struct canvas *pix;
1323 if (targeted_unit == nullptr) {
1324 return;
1327 ptile = targeted_unit->tile;
1328 unit_list_iterate(ptile->units, ptgt) {
1329 if ((ptgt == targeted_unit) && new_target != nullptr) {
1330 break;
1332 new_target = ptgt;
1333 } unit_list_iterate_end;
1334 targeted_unit = new_target;
1335 pix = qtg_canvas_create(tileset_unit_width(tileset),
1336 tileset_unit_height(tileset));
1337 pix->map_pixmap.fill(Qt::transparent);
1338 put_unit(targeted_unit, pix, 1.0, 0, 0);
1339 target_unit_button->setIcon(QIcon(pix->map_pixmap));
1340 qtg_canvas_free(pix);
1341 switch_target();
1344 /***************************************************************************
1345 Update dialog for new target (targeted_unit)
1346 ***************************************************************************/
1347 void choice_dialog::update_dialog(const struct act_prob *act_probs)
1349 if (targeted_unit == nullptr) {
1350 return;
1352 unit_skip->setParent(nullptr);
1353 action_selection_refresh(game_unit_by_number(unit_id), nullptr,
1354 targeted_unit, targeted_unit->tile, act_probs);
1355 layout->addLayout(unit_skip);
1358 /***************************************************************************
1359 Switches target unit
1360 ***************************************************************************/
1361 void choice_dialog::switch_target()
1363 if (targeted_unit == nullptr) {
1364 return;
1366 unit_skip->setParent(nullptr);
1367 dsend_packet_unit_get_actions(&client.conn,
1368 unit_id,
1369 targeted_unit->id,
1370 IDENTITY_NUMBER_ZERO,
1371 targeted_unit->tile->index,
1372 TRUE);
1373 layout->addLayout(unit_skip);
1377 /***************************************************************************
1378 Run chosen action and close dialog
1379 ***************************************************************************/
1380 void choice_dialog::execute_action(const int action)
1382 Choice_dialog_button *button = buttons_list.at(action);
1383 pfcn_void func = button->getFunc();
1385 func(button->getData1(), button->getData2());
1386 close();
1389 /**************************************************************************
1390 Put the button in the stack and temporarily remove it. When
1391 unstack_all_buttons() is called all buttons in the stack will be added
1392 to the end of the dialog.
1394 Can be used to place a button below existing buttons or below buttons
1395 added while it was in the stack.
1396 **************************************************************************/
1397 void choice_dialog::stack_button(Choice_dialog_button *button)
1399 /* Store the data in the stack. */
1400 last_buttons_stack.append(button);
1402 /* Temporary remove the button so it will end up below buttons added
1403 * before unstack_all_buttons() is called. */
1404 layout->removeWidget(button);
1406 /* The old mappings may not be valid after reinsertion. */
1407 signal_mapper->removeMappings(button);
1409 /* Synchronize the list with the layout. */
1410 buttons_list.removeAll(button);
1413 /**************************************************************************
1414 Put all the buttons in the stack back to the dialog. They will appear
1415 after any other buttons. See stack_button()
1416 **************************************************************************/
1417 void choice_dialog::unstack_all_buttons()
1419 while (!last_buttons_stack.isEmpty()) {
1420 Choice_dialog_button *button = last_buttons_stack.takeLast();
1422 /* Restore mapping. */
1423 signal_mapper->setMapping(button, buttons_list.count());
1425 /* Reinsert the button below the other buttons. */
1426 buttons_list.append(button);
1427 layout->addWidget(button);
1431 /***************************************************************************
1432 Action enter market place for choice dialog
1433 ***************************************************************************/
1434 static void caravan_marketplace(QVariant data1, QVariant data2)
1436 int actor_unit_id = data1.toInt();
1437 int target_city_id = data2.toInt();
1439 if (NULL != game_unit_by_number(actor_unit_id)
1440 && NULL != game_city_by_number(target_city_id)) {
1441 request_do_action(ACTION_MARKETPLACE, actor_unit_id,
1442 target_city_id, 0);
1446 /***************************************************************************
1447 Action establish trade for choice dialog
1448 ***************************************************************************/
1449 static void caravan_establish_trade(QVariant data1, QVariant data2)
1451 int actor_unit_id = data1.toInt();
1452 int target_city_id = data2.toInt();
1454 if (NULL != game_unit_by_number(actor_unit_id)
1455 && NULL != game_city_by_number(target_city_id)) {
1456 request_do_action(ACTION_TRADE_ROUTE, actor_unit_id,
1457 target_city_id, 0);
1461 /***************************************************************************
1462 Action help build wonder for choice dialog
1463 ***************************************************************************/
1464 static void caravan_help_build(QVariant data1, QVariant data2)
1466 int caravan_id = data1.toInt();
1467 int caravan_target_id = data2.toInt();
1469 if (NULL != game_unit_by_number(caravan_id)
1470 && NULL != game_city_by_number(caravan_target_id)) {
1471 request_do_action(ACTION_HELP_WONDER,
1472 caravan_id, caravan_target_id, 0);
1476 /***************************************************************************
1477 Delay selection of what action to take.
1478 ***************************************************************************/
1479 static void act_sel_wait(QVariant data1, QVariant data2)
1481 key_unit_wait();
1484 /***************************************************************************
1485 Empty action for choice dialog (just do nothing)
1486 ***************************************************************************/
1487 static void keep_moving(QVariant data1, QVariant data2)
1490 /***************************************************************************
1491 Starts revolution with targeted government as target or anarchy otherwise
1492 ***************************************************************************/
1493 void revolution_response(struct government *government)
1495 if (!government) {
1496 start_revolution();
1497 } else {
1498 set_government_choice(government);
1502 /**************************************************************************
1503 Move the queue of diplomats that need user input forward unless the
1504 current diplomat will need more input.
1505 **************************************************************************/
1506 static void diplomat_queue_handle_primary(int actor_unit_id)
1508 if (!is_more_user_input_needed) {
1509 /* The client isn't waiting for information for any unanswered follow
1510 * up questions. */
1512 struct unit *actor_unit;
1514 if ((actor_unit = game_unit_by_number(actor_unit_id))) {
1515 /* The action selection dialog wasn't closed because the actor unit
1516 * was lost. */
1518 /* The probabilities didn't just disappear, right? */
1519 fc_assert_action(actor_unit->client.act_prob_cache,
1520 client_unit_init_act_prob_cache(actor_unit));
1522 FC_FREE(actor_unit->client.act_prob_cache);
1525 /* The action selection process is over, at least for now. */
1526 action_selection_no_longer_in_progress(actor_unit_id);
1528 if (did_not_decide) {
1529 /* The action selection dialog was closed but the player didn't
1530 * decide what the unit should do. */
1532 /* Reset so the next action selection dialog does the right thing. */
1533 did_not_decide = false;
1534 } else {
1535 /* An action, or no action at all, was selected. */
1536 action_decision_clear_want(actor_unit_id);
1537 action_selection_next_in_focus(actor_unit_id);
1542 /**************************************************************************
1543 Move the queue of diplomats that need user input forward since the
1544 current diplomat got the extra input that was required.
1545 **************************************************************************/
1546 static void diplomat_queue_handle_secondary(int actor_id)
1548 /* Stop waiting. Move on to the next queued diplomat. */
1549 is_more_user_input_needed = FALSE;
1550 diplomat_queue_handle_primary(actor_id);
1553 /**************************************************************************
1554 Returns a string with how many shields remains of the current production.
1555 This is useful as custom information on the help build wonder button.
1556 ***************************************************************************/
1557 static QString city_prod_remaining(struct city *target_city)
1559 if (target_city == nullptr
1560 || city_owner(target_city) != client.conn.playing) {
1561 /* Can't give remaining production for a foreign or non existing
1562 * city. */
1563 return "";
1566 return QString(_("%1 remaining")).arg(
1567 impr_build_shield_cost(target_city->production.value.building)
1568 - target_city->shield_stock);
1571 /**************************************************************************
1572 Popup a dialog that allows the player to select what action a unit
1573 should take.
1574 **************************************************************************/
1575 void popup_action_selection(struct unit *actor_unit,
1576 struct city *target_city,
1577 struct unit *target_unit,
1578 struct tile *target_tile,
1579 const struct act_prob *act_probs)
1581 struct astring title = ASTRING_INIT, text = ASTRING_INIT;
1582 choice_dialog *cd;
1583 qtiles caras;
1584 QVariant qv1, qv2;
1585 pfcn_void func;
1586 struct city *actor_homecity;
1587 int unit_act;
1588 int city_act;
1590 unit_act = qdef_act::action()->vs_unit_get();
1591 city_act = qdef_act::action()->vs_city_get();
1593 foreach (caras, gui()->trade_gen.lines) {
1594 if (caras.autocaravan == actor_unit) {
1595 int i;
1596 if (nullptr != game_unit_by_number(actor_unit->id)
1597 && nullptr != game_city_by_number(target_city->id)) {
1598 request_do_action(ACTION_TRADE_ROUTE, actor_unit->id,
1599 target_city->id, 0);
1600 client_unit_init_act_prob_cache(actor_unit);
1601 diplomat_queue_handle_primary(actor_unit->id);
1602 i = gui()->trade_gen.lines.indexOf(caras);
1603 gui()->trade_gen.lines.takeAt(i);
1604 return;
1608 if (target_city
1609 && try_default_city_action(actor_unit->id, target_city->id)
1610 && action_prob_possible(act_probs[static_cast<gen_action>(unit_act)])) {
1611 diplomat_queue_handle_primary(actor_unit->id);
1612 return;
1615 if (target_unit
1616 && try_default_unit_action(actor_unit->id, target_unit->id)
1617 && action_prob_possible(act_probs[static_cast<gen_action>(city_act)])) {
1618 diplomat_queue_handle_primary(actor_unit->id);
1619 return;
1621 /* Could be caused by the server failing to reply to a request for more
1622 * information or a bug in the client code. */
1623 fc_assert_msg(!is_more_user_input_needed,
1624 "Diplomat queue problem. Is another diplomat window open?");
1626 /* No extra input is required as no action has been chosen yet. */
1627 is_more_user_input_needed = FALSE;
1629 actor_homecity = game_city_by_number(actor_unit->homecity);
1631 astr_set(&title,
1632 /* TRANS: %s is a unit name, e.g., Spy */
1633 _("Choose Your %s's Strategy"),
1634 unit_name_translation(actor_unit));
1636 if (target_city && actor_homecity) {
1637 astr_set(&text,
1638 _("Your %s from %s reaches the city of %s.\nWhat now?"),
1639 unit_name_translation(actor_unit),
1640 city_name_get(actor_homecity),
1641 city_name_get(target_city));
1642 } else if (target_city) {
1643 astr_set(&text,
1644 _("Your %s has arrived at %s.\nWhat is your command?"),
1645 unit_name_translation(actor_unit),
1646 city_name_get(target_city));
1647 } else if (target_unit) {
1648 astr_set(&text,
1649 /* TRANS: Your Spy is ready to act against Roman Freight. */
1650 _("Your %s is ready to act against %s %s."),
1651 unit_name_translation(actor_unit),
1652 nation_adjective_for_player(unit_owner(target_unit)),
1653 unit_name_translation(target_unit));
1654 } else {
1655 fc_assert_msg(target_unit || target_city,
1656 "No target unit or target city specified.");
1658 astr_set(&text,
1659 /* TRANS: %s is a unit name, e.g., Diplomat, Spy */
1660 _("Your %s is waiting for your command."),
1661 unit_name_translation(actor_unit));
1664 cd = gui()->get_diplo_dialog();
1665 if ((cd != nullptr) && cd->targeted_unit != nullptr) {
1666 cd->update_dialog(act_probs);
1667 return;
1669 cd = new choice_dialog(astr_str(&title), astr_str(&text),
1670 gui()->game_tab_widget,
1671 diplomat_queue_handle_primary);
1672 qv1 = actor_unit->id;
1674 cd->unit_id = actor_unit->id;
1676 if (target_city) {
1677 cd->target_id[ATK_CITY] = target_city->id;
1678 } else {
1679 cd->target_id[ATK_CITY] = IDENTITY_NUMBER_ZERO;
1682 if (target_unit) {
1683 cd->target_id[ATK_UNIT] = target_unit->id;
1684 } else {
1685 cd->target_id[ATK_UNIT] = IDENTITY_NUMBER_ZERO;
1688 /* Unit acting against a city */
1690 /* Set the correct target for the following actions. */
1691 qv2 = cd->target_id[ATK_CITY];
1693 action_iterate(act) {
1694 if (action_id_get_actor_kind(act) == AAK_UNIT
1695 && action_id_get_target_kind(act) == ATK_CITY) {
1696 action_entry(cd,
1697 (enum gen_action)act,
1698 act_probs,
1699 act == ACTION_HELP_WONDER ?
1700 city_prod_remaining(target_city) : "",
1701 qv1, qv2);
1703 } action_iterate_end;
1705 /* Unit acting against another unit */
1707 /* Set the correct target for the following actions. */
1708 qv2 = cd->target_id[ATK_UNIT];
1710 action_iterate(act) {
1711 if (action_id_get_actor_kind(act) == AAK_UNIT
1712 && action_id_get_target_kind(act) == ATK_UNIT) {
1713 action_entry(cd,
1714 (enum gen_action)act,
1715 act_probs,
1717 qv1, qv2);
1719 } action_iterate_end;
1721 if (unit_can_move_to_tile(actor_unit, target_tile, FALSE)
1722 || (is_military_unit(actor_unit) || is_attack_unit(actor_unit))
1723 || (can_unit_bombard(actor_unit) && !is_ocean_tile(target_tile))
1724 || (!target_city && unit_has_type_flag(actor_unit, UTYF_CAPTURER))) {
1725 qv2 = target_tile->index;
1727 func = act_sel_keep_moving;
1728 cd->add_item(QString(_("Keep moving")), func, qv1, qv2,
1729 "", BUTTON_MOVE);
1732 func = act_sel_wait;
1733 cd->add_item(QString(_("&Wait")), func, qv1, qv2,
1734 "", BUTTON_WAIT);
1736 func = keep_moving;
1737 cd->add_item(QString(_("Do nothing")), func, qv1, qv2,
1738 "", BUTTON_CANCEL);
1740 cd->set_layout();
1741 cd->show_me();
1743 /* Give follow up questions access to action probabilities. */
1744 client_unit_init_act_prob_cache(actor_unit);
1745 action_iterate(act) {
1746 actor_unit->client.act_prob_cache[act] = act_probs[act];
1747 } action_iterate_end;
1749 astr_free(&title);
1750 astr_free(&text);
1753 /**********************************************************************
1754 Show the user the action if it is enabled.
1755 **********************************************************************/
1756 static void action_entry(choice_dialog *cd,
1757 gen_action act,
1758 const struct act_prob *act_probs,
1759 QString custom,
1760 QVariant data1, QVariant data2)
1762 QString title;
1763 QString tool_tip;
1765 if (act == ACTION_SPY_SABOTAGE_CITY
1766 && action_prob_possible(
1767 act_probs[ACTION_SPY_TARGETED_SABOTAGE_CITY])) {
1768 /* The player can select Sabotage City from the target selection dialog
1769 * of Targeted Sabotage City. */
1770 return;
1773 if (act == ACTION_SPY_STEAL_TECH
1774 && action_prob_possible(
1775 act_probs[ACTION_SPY_TARGETED_STEAL_TECH])) {
1776 /* The player can select Steal Tech from the target selection dialog of
1777 * Targeted Steal Tech. */
1778 return;
1781 /* Don't show disabled actions. */
1782 if (!action_prob_possible(act_probs[act])) {
1783 return;
1786 title = QString(action_prepare_ui_name(act, "&",
1787 act_probs[act],
1788 custom != "" ?
1789 custom.toUtf8().data() :
1790 NULL));
1792 tool_tip = QString(action_get_tool_tip(act, act_probs[act]));
1794 cd->add_item(title, af_map[act], data1, data2, tool_tip, act);
1797 /**********************************************************************
1798 Update an existing button.
1799 **********************************************************************/
1800 static void action_entry_update(Choice_dialog_button *button,
1801 gen_action act,
1802 const struct act_prob *act_probs,
1803 QString custom,
1804 QVariant data1, QVariant data2)
1806 QString title;
1807 QString tool_tip;
1809 /* An action that just became impossible has its button disabled.
1810 * An action that became possible again must be reenabled. */
1811 button->setEnabled(action_prob_possible(act_probs[act]));
1812 button->setData1(data1);
1813 button->setData2(data2);
1814 /* The probability may have changed. */
1815 title = QString(action_prepare_ui_name(act, "&",
1816 act_probs[act],
1817 custom != "" ?
1818 custom.toUtf8().data() :
1819 NULL));
1821 tool_tip = QString(action_get_tool_tip(act, act_probs[act]));
1823 button->setText(title);
1824 button->setToolTip(tool_tip);
1827 /***************************************************************************
1828 Action bribe unit for choice dialog
1829 ***************************************************************************/
1830 static void diplomat_bribe(QVariant data1, QVariant data2)
1832 int diplomat_id = data1.toInt();
1833 int diplomat_target_id = data2.toInt();
1835 if (NULL != game_unit_by_number(diplomat_id)
1836 && NULL != game_unit_by_number(diplomat_target_id)) {
1837 /* Wait for the server's reply before moving on to the next queued diplomat. */
1838 is_more_user_input_needed = TRUE;
1840 request_action_details(ACTION_SPY_BRIBE_UNIT, diplomat_id,
1841 diplomat_target_id);
1845 /***************************************************************************
1846 Action sabotage unit for choice dialog
1847 ***************************************************************************/
1848 static void spy_sabotage_unit(QVariant data1, QVariant data2)
1850 int diplomat_id = data1.toInt();
1851 int diplomat_target_id = data2.toInt();
1853 request_do_action(ACTION_SPY_SABOTAGE_UNIT, diplomat_id,
1854 diplomat_target_id, 0);
1857 /***************************************************************************
1858 Action steal tech with spy for choice dialog
1859 ***************************************************************************/
1860 static void spy_steal(QVariant data1, QVariant data2)
1862 QString str;
1863 QVariant qv1, qv2;
1864 pfcn_void func;
1865 int diplomat_id = data1.toInt();
1866 int diplomat_target_id = data2.toInt();
1867 struct unit *actor_unit = game_unit_by_number(diplomat_id);
1868 struct city *pvcity = game_city_by_number(diplomat_target_id);
1869 struct player *pvictim = NULL;
1870 choice_dialog *cd;
1871 QList<QVariant> actor_and_target;
1873 /* Wait for the player's reply before moving on to the next queued diplomat. */
1874 is_more_user_input_needed = TRUE;
1876 if (pvcity) {
1877 pvictim = city_owner(pvcity);
1879 cd = gui()->get_diplo_dialog();
1880 if (cd != NULL) {
1881 cd->close();
1883 struct astring stra = ASTRING_INIT;
1884 cd = new choice_dialog(_("Steal"), _("Steal Technology"),
1885 gui()->game_tab_widget,
1886 diplomat_queue_handle_secondary);
1888 /* Put both actor and target city in qv1 since qv2 is taken */
1889 actor_and_target.append(diplomat_id);
1890 actor_and_target.append(diplomat_target_id);
1891 qv1 = QVariant::fromValue(actor_and_target);
1893 struct player *pplayer = client.conn.playing;
1894 if (pvictim) {
1895 const struct research *presearch = research_get(pplayer);
1896 const struct research *vresearch = research_get(pvictim);
1898 advance_index_iterate(A_FIRST, i) {
1899 if (research_invention_gettable(presearch, i,
1900 game.info.tech_steal_allow_holes)
1901 && research_invention_state(vresearch, i) == TECH_KNOWN
1902 && research_invention_state(presearch, i) != TECH_KNOWN) {
1903 func = spy_steal_something;
1904 str = research_advance_name_translation(presearch, i);
1905 cd->add_item(str, func, qv1, i);
1907 } advance_index_iterate_end;
1909 if (action_prob_possible(
1910 actor_unit->client.act_prob_cache[ACTION_SPY_STEAL_TECH])) {
1911 astr_set(&stra, _("At %s's Discretion"),
1912 unit_name_translation(actor_unit));
1913 func = spy_steal_something;
1914 str = astr_str(&stra);
1915 cd->add_item(str, func, qv1, A_UNSET);
1918 cd->set_layout();
1919 cd->show_me();
1921 astr_free(&stra);
1924 /***************************************************************************
1925 Action steal given tech for choice dialog
1926 ***************************************************************************/
1927 static void spy_steal_something(QVariant data1, QVariant data2)
1929 int diplomat_id = data1.toList().at(0).toInt();
1930 int diplomat_target_id = data1.toList().at(1).toInt();
1932 if (NULL != game_unit_by_number(diplomat_id)
1933 && NULL != game_city_by_number(diplomat_target_id)) {
1934 if (data2.toInt() == A_UNSET) {
1935 /* This is the untargeted version. */
1936 request_do_action(ACTION_SPY_STEAL_TECH, diplomat_id,
1937 diplomat_target_id, data2.toInt());
1938 } else {
1939 /* This is the targeted version. */
1940 request_do_action(ACTION_SPY_TARGETED_STEAL_TECH, diplomat_id,
1941 diplomat_target_id, data2.toInt());
1946 /***************************************************************************
1947 Action request sabotage list for choice dialog
1948 ***************************************************************************/
1949 static void spy_request_sabotage_list(QVariant data1, QVariant data2)
1951 int diplomat_id = data1.toInt();
1952 int diplomat_target_id = data2.toInt();
1954 if (NULL != game_unit_by_number(diplomat_id)
1955 && NULL != game_city_by_number(diplomat_target_id)) {
1956 /* Wait for the server's reply before moving on to the next queued diplomat. */
1957 is_more_user_input_needed = TRUE;
1959 request_action_details(ACTION_SPY_TARGETED_SABOTAGE_CITY, diplomat_id,
1960 diplomat_target_id);
1964 /***************************************************************************
1965 Action poison city for choice dialog
1966 ***************************************************************************/
1967 static void spy_poison(QVariant data1, QVariant data2)
1969 int diplomat_id = data1.toInt();
1970 int diplomat_target_id = data2.toInt();
1972 if (NULL != game_unit_by_number(diplomat_id)
1973 && NULL != game_city_by_number(diplomat_target_id)) {
1974 request_do_action(ACTION_SPY_POISON,
1975 diplomat_id, diplomat_target_id, 0);
1979 /***************************************************************************
1980 Action steal gold for choice dialog
1981 ***************************************************************************/
1982 static void spy_steal_gold(QVariant data1, QVariant data2)
1984 int diplomat_id = data1.toInt();
1985 int diplomat_target_id = data2.toInt();
1987 if (NULL != game_unit_by_number(diplomat_id)
1988 && NULL != game_city_by_number(diplomat_target_id)) {
1989 request_do_action(ACTION_SPY_STEAL_GOLD,
1990 diplomat_id, diplomat_target_id, 0);
1994 /***************************************************************************
1995 Action establish embassy for choice dialog
1996 ***************************************************************************/
1997 static void diplomat_embassy(QVariant data1, QVariant data2)
1999 int diplomat_id = data1.toInt();
2000 int diplomat_target_id = data2.toInt();
2002 if (NULL != game_unit_by_number(diplomat_id)
2003 && NULL != game_city_by_number(diplomat_target_id)) {
2004 request_do_action(ACTION_ESTABLISH_EMBASSY, diplomat_id,
2005 diplomat_target_id, 0);
2009 /***************************************************************************
2010 Action investigate city for choice dialog
2011 ***************************************************************************/
2012 static void diplomat_investigate(QVariant data1, QVariant data2)
2014 int diplomat_id = data1.toInt();
2015 int diplomat_target_id = data2.toInt();
2017 if (NULL != game_city_by_number(diplomat_target_id)
2018 && NULL != game_unit_by_number(diplomat_id)) {
2019 request_do_action(ACTION_SPY_INVESTIGATE_CITY, diplomat_id,
2020 diplomat_target_id, 0);
2024 /***************************************************************************
2025 Action sabotage for choice dialog
2026 ***************************************************************************/
2027 static void diplomat_sabotage(QVariant data1, QVariant data2)
2029 int diplomat_id = data1.toInt();
2030 int diplomat_target_id = data2.toInt();
2032 if (NULL != game_unit_by_number(diplomat_id)
2033 && NULL != game_city_by_number(diplomat_target_id)) {
2034 request_do_action(ACTION_SPY_SABOTAGE_CITY, diplomat_id,
2035 diplomat_target_id, B_LAST + 1);
2039 /***************************************************************************
2040 Action steal with diplomat for choice dialog
2041 ***************************************************************************/
2042 static void diplomat_steal(QVariant data1, QVariant data2)
2044 int diplomat_id = data1.toInt();
2045 int diplomat_target_id = data2.toInt();
2047 if (NULL != game_unit_by_number(diplomat_id)
2048 && NULL != game_city_by_number(diplomat_target_id)) {
2049 request_do_action(ACTION_SPY_STEAL_TECH, diplomat_id,
2050 diplomat_target_id, A_UNSET);
2054 /***************************************************************************
2055 Action incite revolt for choice dialog
2056 ***************************************************************************/
2057 static void diplomat_incite(QVariant data1, QVariant data2)
2059 int diplomat_id = data1.toInt();
2060 int diplomat_target_id = data2.toInt();
2062 if (NULL != game_unit_by_number(diplomat_id)
2063 && NULL != game_city_by_number(diplomat_target_id)) {
2064 /* Wait for the server's reply before moving on to the next queued diplomat. */
2065 is_more_user_input_needed = TRUE;
2067 request_action_details(ACTION_SPY_INCITE_CITY, diplomat_id,
2068 diplomat_target_id);
2072 /***************************************************************************
2073 Action keep moving with actor unit for choice dialog
2074 ***************************************************************************/
2075 static void act_sel_keep_moving(QVariant data1, QVariant data2)
2077 struct unit *punit;
2078 struct tile *ptile;
2079 int diplomat_id = data1.toInt();
2080 int diplomat_target_id = data2.toInt();
2082 if ((punit = game_unit_by_number(diplomat_id))
2083 && (ptile = index_to_tile(diplomat_target_id))
2084 && !same_pos(unit_tile(punit), ptile)) {
2085 request_unit_non_action_move(punit, ptile);
2089 /**************************************************************************
2090 Popup a window asking a diplomatic unit if it wishes to incite the
2091 given enemy city.
2092 **************************************************************************/
2093 void popup_incite_dialog(struct unit *actor, struct city *tcity, int cost)
2095 char buf[1024];
2096 char buf2[1024];
2097 int ret;
2098 int diplomat_id = actor->id;
2099 int diplomat_target_id = tcity->id;
2101 /* Should be set before sending request to the server. */
2102 fc_assert(is_more_user_input_needed);
2104 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
2105 "Treasury contains %d gold.",
2106 client_player()->economic.gold),
2107 client_player()->economic.gold);
2109 if (INCITE_IMPOSSIBLE_COST == cost) {
2110 hud_message_box incite_impossible(gui()->central_wdg);
2112 fc_snprintf(buf2, ARRAY_SIZE(buf2),
2113 _("You can't incite a revolt in %s."), city_name_get(tcity));
2114 incite_impossible.set_text_title(QString(buf2), "!");
2115 incite_impossible.setStandardButtons(QMessageBox::Ok);
2116 incite_impossible.exec();
2117 } else if (cost <= client_player()->economic.gold) {
2118 hud_message_box ask(gui()->central_wdg);
2120 fc_snprintf(buf2, ARRAY_SIZE(buf2),
2121 PL_("Incite a revolt for %d gold?\n%s",
2122 "Incite a revolt for %d gold?\n%s", cost), cost, buf);
2123 ask.setStandardButtons(QMessageBox::Cancel | QMessageBox::Ok);
2124 ask.setDefaultButton(QMessageBox::Cancel);
2125 ask.set_text_title(QString(buf2), _("Incite a Revolt!"));
2126 ret = ask.exec();
2127 switch (ret) {
2128 case QMessageBox::Cancel:
2129 break;
2130 case QMessageBox::Ok:
2131 request_do_action(ACTION_SPY_INCITE_CITY, diplomat_id,
2132 diplomat_target_id, 0);
2133 break;
2135 } else {
2136 hud_message_box too_much(gui()->central_wdg);
2138 fc_snprintf(buf2, ARRAY_SIZE(buf2),
2139 PL_("Inciting a revolt costs %d gold.\n%s",
2140 "Inciting a revolt costs %d gold.\n%s", cost), cost,
2141 buf);
2142 too_much.set_text_title(QString(buf2), "!");
2143 too_much.setStandardButtons(QMessageBox::Ok);
2144 too_much.exec();
2147 diplomat_queue_handle_secondary(diplomat_id);
2150 /**************************************************************************
2151 Popup a dialog asking a diplomatic unit if it wishes to bribe the
2152 given enemy unit.
2153 **************************************************************************/
2154 void popup_bribe_dialog(struct unit *actor, struct unit *tunit, int cost)
2156 hud_message_box ask(gui()->central_wdg);
2157 int ret;
2158 QString str;
2159 char buf[1024];
2160 char buf2[1024];
2161 int diplomat_id = actor->id;
2162 int diplomat_target_id = tunit->id;
2164 /* Should be set before sending request to the server. */
2165 fc_assert(is_more_user_input_needed);
2167 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
2168 "Treasury contains %d gold.",
2169 client_player()->economic.gold),
2170 client_player()->economic.gold);
2172 if (cost <= client_player()->economic.gold) {
2173 fc_snprintf(buf2, ARRAY_SIZE(buf2), PL_("Bribe unit for %d gold?\n%s",
2174 "Bribe unit for %d gold?\n%s",
2175 cost), cost, buf);
2176 ask.set_text_title(QString(buf2), QString(_("Bribe Enemy Unit")));
2177 ask.setStandardButtons(QMessageBox::Cancel | QMessageBox::Ok);
2178 ask.setDefaultButton(QMessageBox::Cancel);
2179 ret = ask.exec();
2180 switch (ret) {
2181 case QMessageBox::Cancel:
2182 break;
2183 case QMessageBox::Ok:
2184 request_do_action(ACTION_SPY_BRIBE_UNIT, diplomat_id,
2185 diplomat_target_id, 0);
2186 break;
2187 default:
2188 break;
2190 } else {
2191 fc_snprintf(buf2, ARRAY_SIZE(buf2),
2192 PL_("Bribing the unit costs %d gold.\n%s",
2193 "Bribing the unit costs %d gold.\n%s", cost), cost, buf);
2194 ask.set_text_title(QString(buf2), _("Traitors Demand Too Much!"));
2195 ask.exec();
2198 diplomat_queue_handle_secondary(diplomat_id);
2201 /***************************************************************************
2202 Action pillage for choice dialog
2203 ***************************************************************************/
2204 static void pillage_something(QVariant data1, QVariant data2)
2206 int punit_id;
2207 int what;
2208 struct unit *punit;
2209 struct extra_type *target;
2211 what = data1.toInt();
2212 punit_id = data2.toInt();
2213 punit = game_unit_by_number(punit_id);
2214 if (punit) {
2215 target = extra_by_number(what);
2216 request_new_unit_activity_targeted(punit, ACTIVITY_PILLAGE, target);
2218 ::is_showing_pillage_dialog = false;
2221 /***************************************************************************
2222 Action sabotage with spy for choice dialog
2223 ***************************************************************************/
2224 static void spy_sabotage(QVariant data1, QVariant data2)
2226 int diplomat_id = data1.toList().at(0).toInt();
2227 int diplomat_target_id = data1.toList().at(1).toInt();
2229 if (NULL != game_unit_by_number(diplomat_id)
2230 && NULL != game_city_by_number(diplomat_target_id)) {
2231 if (data2.toInt() == B_LAST) {
2232 /* This is the untargeted version. */
2233 request_do_action(ACTION_SPY_SABOTAGE_CITY, diplomat_id,
2234 diplomat_target_id, data2.toInt() + 1);
2235 } else {
2236 /* This is the targeted version. */
2237 request_do_action(ACTION_SPY_TARGETED_SABOTAGE_CITY, diplomat_id,
2238 diplomat_target_id, data2.toInt() + 1);
2243 /**************************************************************************
2244 Popup a dialog asking a diplomatic unit if it wishes to sabotage the
2245 given enemy city.
2246 **************************************************************************/
2247 void popup_sabotage_dialog(struct unit *actor, struct city *tcity)
2250 QString str;
2251 QVariant qv1, qv2;
2252 int diplomat_id = actor->id;
2253 int diplomat_target_id = tcity->id;
2254 pfcn_void func;
2255 choice_dialog *cd = new choice_dialog(_("Sabotage"),
2256 _("Select Improvement to Sabotage"),
2257 gui()->game_tab_widget,
2258 diplomat_queue_handle_secondary);
2259 int nr = 0;
2260 struct astring stra = ASTRING_INIT;
2261 QList<QVariant> actor_and_target;
2263 /* Should be set before sending request to the server. */
2264 fc_assert(is_more_user_input_needed);
2266 /* Put both actor and target city in qv1 since qv2 is taken */
2267 actor_and_target.append(diplomat_id);
2268 actor_and_target.append(diplomat_target_id);
2269 qv1 = QVariant::fromValue(actor_and_target);
2271 func = spy_sabotage;
2272 cd->add_item(QString(_("City Production")), func, qv1, -1);
2273 city_built_iterate(tcity, pimprove) {
2274 if (pimprove->sabotage > 0) {
2275 func = spy_sabotage;
2276 str = city_improvement_name_translation(tcity, pimprove);
2277 qv2 = nr;
2278 cd->add_item(str, func, qv1, improvement_number(pimprove));
2279 nr++;
2281 } city_built_iterate_end;
2283 if (action_prob_possible(
2284 actor->client.act_prob_cache[ACTION_SPY_SABOTAGE_CITY])) {
2285 astr_set(&stra, _("At %s's Discretion"),
2286 unit_name_translation(actor));
2287 func = spy_sabotage;
2288 str = astr_str(&stra);
2289 cd->add_item(str, func, qv1, B_LAST);
2292 cd->set_layout();
2293 cd->show_me();
2294 astr_free(&stra);
2297 /**************************************************************************
2298 Popup a dialog asking the unit which improvement they would like to
2299 pillage.
2300 **************************************************************************/
2301 void popup_pillage_dialog(struct unit *punit, bv_extras extras)
2303 QString str;
2304 QVariant qv1, qv2;
2305 pfcn_void func;
2306 choice_dialog *cd;
2307 struct extra_type *tgt;
2309 if (is_showing_pillage_dialog){
2310 return;
2312 cd = new choice_dialog(_("What To Pillage"), _("Select what to pillage:"),
2313 gui()->game_tab_widget);
2314 qv2 = punit->id;
2315 while ((tgt = get_preferred_pillage(extras))) {
2316 int what;
2318 what = extra_index(tgt);
2319 BV_CLR(extras, what);
2321 func = pillage_something;
2322 str = extra_name_translation(tgt);
2323 qv1 = what;
2324 cd->add_item(str, func, qv1, qv2);
2326 cd->set_layout();
2327 cd->show_me();
2330 /***************************************************************************
2331 Disband Message box contructor
2332 ***************************************************************************/
2333 disband_box::disband_box(struct unit_list *punits,
2334 QWidget *parent) : hud_message_box(parent)
2336 QString str;
2337 QPushButton *pb;
2339 setAttribute(Qt::WA_DeleteOnClose);
2340 setModal(false);
2341 cpunits = unit_list_new();
2342 unit_list_iterate(punits, punit) {
2343 unit_list_append(cpunits, punit);
2344 } unit_list_iterate_end;
2346 str = QString(PL_("Are you sure you want to disband that %1 unit?",
2347 "Are you sure you want to disband those %1 units?",
2348 unit_list_size(punits))).arg(unit_list_size(punits));
2349 pb = addButton(_("Yes"), QMessageBox::AcceptRole);
2350 addButton(_("No"), QMessageBox::RejectRole);
2351 setDefaultButton(QMessageBox::Cancel);
2352 set_text_title(str, _("Disband units"));
2353 connect(pb, SIGNAL(clicked()), this, SLOT(disband_clicked()));
2356 /***************************************************************************
2357 Clicked Yes in disband box
2358 ***************************************************************************/
2359 void disband_box::disband_clicked()
2361 unit_list_iterate(cpunits, punit) {
2362 if (!unit_has_type_flag(punit, UTYF_UNDISBANDABLE)) {
2363 request_unit_disband(punit);
2365 } unit_list_iterate_end;
2368 /***************************************************************************
2369 Destructor for disband box
2370 ***************************************************************************/
2371 disband_box::~disband_box()
2373 unit_list_destroy(cpunits);
2376 /****************************************************************************
2377 Pops up a dialog to confirm disband of the unit(s).
2378 ****************************************************************************/
2379 void popup_disband_dialog(struct unit_list *punits)
2381 disband_box *ask = new disband_box(punits, gui()->central_wdg);
2382 ask->show();
2385 /**************************************************************************
2386 Ruleset (modpack) has suggested loading certain tileset. Confirm from
2387 user and load.
2388 **************************************************************************/
2389 void popup_tileset_suggestion_dialog(void)
2391 hud_message_box ask(gui()->central_wdg);
2392 QString text;
2393 QString title;
2394 QPushButton *ok_button;
2396 title = QString(_("Modpack suggests using %1 tileset."))
2397 .arg(game.control.preferred_tileset);
2398 text = QString("It might not work with other tilesets.\n"
2399 "You are currently using tileset %1.")
2400 .arg(tileset_basename(tileset));
2401 ask.addButton(_("Keep current tileset"), QMessageBox::ActionRole);
2402 ok_button = ask.addButton(_("Load tileset"), QMessageBox::ActionRole);
2403 ask.set_text_title(text, title);
2404 ask.exec();
2405 if (ask.clickedButton() == ok_button) {
2406 tilespec_reread(game.control.preferred_tileset, FALSE);
2410 /****************************************************************
2411 Ruleset (modpack) has suggested loading certain soundset. Confirm from
2412 user and load.
2413 *****************************************************************/
2414 void popup_soundset_suggestion_dialog(void)
2416 hud_message_box ask(gui()->central_wdg);
2417 QString text;
2418 QString title;
2419 QPushButton *ok_button;
2421 title = QString(_("Modpack suggests using %1 soundset."))
2422 .arg(game.control.preferred_soundset);
2423 text = QString("It might not work with other tilesets.\n"
2424 "You are currently using soundset %1.")
2425 .arg(sound_set_name);
2426 ask.addButton(_("Keep current soundset"), QMessageBox::ActionRole);
2427 ok_button = ask.addButton(_("Load soundset"), QMessageBox::ActionRole);
2428 ask.set_text_title(text, title);
2429 ask.exec();
2430 if (ask.clickedButton() == ok_button) {
2431 audio_restart(game.control.preferred_soundset, music_set_name);
2435 /****************************************************************
2436 Ruleset (modpack) has suggested loading certain musicset. Confirm from
2437 user and load.
2438 *****************************************************************/
2439 void popup_musicset_suggestion_dialog(void)
2441 hud_message_box ask(gui()->central_wdg);
2442 QString text;
2443 QString title;
2444 QPushButton *ok_button;
2446 title = QString(_("Modpack suggests using %1 musicset."))
2447 .arg(game.control.preferred_musicset);
2448 text = QString("It might not work with other tilesets.\n"
2449 "You are currently using musicset %1.")
2450 .arg(music_set_name);
2451 ask.addButton(_("Keep current musicset"), QMessageBox::ActionRole);
2452 ok_button = ask.addButton(_("Load musicset"), QMessageBox::ActionRole);
2453 ask.set_text_title(text, title);
2454 ask.exec();
2455 if (ask.clickedButton() == ok_button) {
2456 audio_restart(sound_set_name, game.control.preferred_musicset);
2460 /**************************************************************************
2461 Tileset (modpack) has suggested loading certain theme. Confirm from
2462 user and load.
2463 **************************************************************************/
2464 bool popup_theme_suggestion_dialog(const char *theme_name)
2466 /* PORTME */
2467 return false;
2470 /**************************************************************************
2471 Restarts all notify dialogs
2472 **************************************************************************/
2473 void restart_notify_dialogs()
2475 QList<notify_dialog *> nd_list;
2476 int i;
2478 nd_list = gui()->mapview_wdg->findChildren<notify_dialog *>();
2479 for (i = 0; i < nd_list.count(); i++) {
2480 nd_list[i]->restart();
2481 delete nd_list[i];
2485 /**************************************************************************
2486 This function is called when the client disconnects or the game is
2487 over. It should close all dialog windows for that game.
2488 **************************************************************************/
2489 void popdown_all_game_dialogs(void)
2491 int i;
2492 QList <choice_dialog *> cd_list;
2493 QList <notify_dialog *> nd_list;
2495 cd_list = gui()->game_tab_widget->findChildren <choice_dialog *>();
2496 for (i = 0; i < cd_list.count(); i++) {
2497 cd_list[i]->close();
2499 nd_list = gui()->game_tab_widget->findChildren <notify_dialog *>();
2500 for (i = 0; i < nd_list.count(); i++) {
2501 nd_list[i]->close();
2504 popdown_help_dialog();
2505 popdown_players_report();
2506 popdown_all_spaceships_dialogs();
2507 popdown_economy_report();
2508 popdown_units_report();
2509 popdown_science_report();
2510 popdown_city_report();
2511 popdown_endgame_report();
2512 gui()->popdown_unit_sel();
2515 /**************************************************************************
2516 Returns the id of the actor unit currently handled in action selection
2517 dialog when the action selection dialog is open.
2518 Returns IDENTITY_NUMBER_ZERO if no action selection dialog is open.
2519 **************************************************************************/
2520 int action_selection_actor_unit(void)
2522 choice_dialog *cd = gui()->get_diplo_dialog();
2524 if (cd != NULL) {
2525 return cd->unit_id;
2526 } else {
2527 return IDENTITY_NUMBER_ZERO;
2531 /**************************************************************************
2532 Returns id of the target city of the actions currently handled in action
2533 selection dialog when the action selection dialog is open and it has a
2534 city target. Returns IDENTITY_NUMBER_ZERO if no action selection dialog
2535 is open or no city target is present in the action selection dialog.
2536 **************************************************************************/
2537 int action_selection_target_city(void)
2539 choice_dialog *cd = gui()->get_diplo_dialog();
2541 if (cd != NULL) {
2542 return cd->target_id[ATK_CITY];
2543 } else {
2544 return IDENTITY_NUMBER_ZERO;
2548 /**************************************************************************
2549 Returns id of the target unit of the actions currently handled in action
2550 selection dialog when the action selection dialog is open and it has a
2551 unit target. Returns IDENTITY_NUMBER_ZERO if no action selection dialog
2552 is open or no unit target is present in the action selection dialog.
2553 **************************************************************************/
2554 int action_selection_target_unit(void)
2556 choice_dialog *cd = gui()->get_diplo_dialog();
2558 if (cd != NULL) {
2559 return cd->target_id[ATK_UNIT];
2560 } else {
2561 return IDENTITY_NUMBER_ZERO;
2565 /**************************************************************************
2566 Updates the action selection dialog with new information.
2567 **************************************************************************/
2568 void action_selection_refresh(struct unit *actor_unit,
2569 struct city *target_city,
2570 struct unit *target_unit,
2571 struct tile *target_tile,
2572 const struct act_prob *act_probs)
2574 choice_dialog *asd;
2575 Choice_dialog_button *keep_moving_button;
2576 Choice_dialog_button *wait_button;
2577 QVariant qv1, qv2;
2579 asd = gui()->get_diplo_dialog();
2580 if (asd == NULL) {
2581 fc_assert_msg(asd != NULL,
2582 "The action selection dialog should have been open");
2583 return;
2586 if (actor_unit->id != action_selection_actor_unit()) {
2587 fc_assert_msg(actor_unit->id == action_selection_actor_unit(),
2588 "The action selection dialog is for another actor unit.");
2591 /* Put the actor id in qv1. */
2592 qv1 = actor_unit->id;
2594 keep_moving_button = asd->get_identified_button(BUTTON_CANCEL);
2595 if (keep_moving_button != NULL) {
2596 /* Temporary remove the Keep moving button so it won't end up above
2597 * any added buttons. */
2598 asd->stack_button(keep_moving_button);
2601 wait_button = asd->get_identified_button(BUTTON_WAIT);
2602 if (wait_button != NULL) {
2603 /* Temporary remove the Wait button so it won't end up above
2604 * any added buttons. */
2605 asd->stack_button(wait_button);
2608 action_iterate(act) {
2609 QString custom;
2611 if (action_id_get_actor_kind(act) != AAK_UNIT) {
2612 /* Not relevant. */
2613 continue;
2616 if (action_prob_possible(act_probs[act])
2617 && act == ACTION_HELP_WONDER) {
2618 /* Add information about how far along the wonder is. */
2619 custom = city_prod_remaining(target_city);
2620 } else {
2621 custom = "";
2624 /* Put the target id in qv2. */
2625 switch (action_id_get_target_kind(act)) {
2626 case ATK_UNIT:
2627 if (target_unit != NULL) {
2628 qv2 = target_unit->id;
2629 } else {
2630 fc_assert_msg(!action_prob_possible(act_probs[act])
2631 || target_unit != NULL,
2632 "Action enabled against non existing unit!");
2634 qv2 = IDENTITY_NUMBER_ZERO;
2636 break;
2637 case ATK_CITY:
2638 if (target_city != NULL) {
2639 qv2 = target_city->id;
2640 } else {
2641 fc_assert_msg(!action_prob_possible(act_probs[act])
2642 || target_city != NULL,
2643 "Action enabled against non existing city!");
2645 qv2 = IDENTITY_NUMBER_ZERO;
2647 break;
2648 case ATK_COUNT:
2649 fc_assert_msg(ATK_COUNT != action_id_get_target_kind(act),
2650 "Bad target kind");
2651 continue;
2654 if (asd->get_identified_button(act)) {
2655 /* Update the existing button. */
2656 action_entry_update(asd->get_identified_button(act),
2657 (enum gen_action)act, act_probs, custom,
2658 qv1, qv2);
2659 } else {
2660 /* Add the button (unless its probability is 0). */
2661 action_entry(asd, (enum gen_action)act, act_probs, custom,
2662 qv1, qv2);
2664 } action_iterate_end;
2666 if (keep_moving_button != NULL || wait_button != NULL) {
2667 /* Reinsert the "Keep moving" button below any potential
2668 * buttons recently added. */
2669 asd->unstack_all_buttons();
2673 /****************************************************************
2674 Closes the action selection dialog
2675 ****************************************************************/
2676 void action_selection_close(void)
2678 choice_dialog *cd;
2680 cd = gui()->get_diplo_dialog();
2681 if (cd != NULL){
2682 did_not_decide = true;
2683 cd->close();
2687 /****************************************************************
2688 Player has gained a new tech.
2689 *****************************************************************/
2690 void show_tech_gained_dialog(Tech_type_id tech)
2694 /****************************************************************
2695 Show tileset error dialog.
2696 *****************************************************************/
2697 void show_tileset_error(const char *msg)
2699 QMessageBox ask(gui()->central_wdg);
2700 char buf[1024];
2702 fc_snprintf(buf, sizeof(buf),
2703 _("Tileset problem, it's probably incompatible with the"
2704 " ruleset:\n%s\nProgram will now exit."), msg);
2705 ask.setText(buf);
2706 ask.setStandardButtons(QMessageBox::Ok);
2707 ask.setWindowTitle(_("Tileset error"));
2708 ask.exec();
2709 gui()->quit();
2713 /****************************************************************
2714 Popup dialog for upgrade units
2715 *****************************************************************/
2716 void popup_upgrade_dialog(struct unit_list *punits)
2718 char buf[512];
2719 hud_message_box ask(gui()->central_wdg);
2720 int ret;
2721 QString title;
2723 if (!punits || unit_list_size(punits) == 0) {
2724 return;
2726 if (!get_units_upgrade_info(buf, sizeof(buf), punits)) {
2727 title = _("Upgrade Unit!");
2728 ask.setStandardButtons(QMessageBox::Ok);
2729 } else {
2730 title = _("Upgrade Obsolete Units");
2731 ask.setStandardButtons(QMessageBox::Cancel | QMessageBox::Ok);
2732 ask.setDefaultButton(QMessageBox::Cancel);
2734 ask.set_text_title(QString(buf), title);
2735 ret = ask.exec();
2737 switch (ret) {
2738 case QMessageBox::Cancel:
2739 return;
2740 break;
2741 case QMessageBox::Ok:
2742 unit_list_iterate(punits, punit) {
2743 request_unit_upgrade(punit);
2745 unit_list_iterate_end;
2746 break;
2750 /****************************************************************
2751 Contructor for units_select
2752 *****************************************************************/
2753 units_select::units_select(tile *ptile, QWidget *parent)
2755 QPoint p, final_p;
2757 setParent(parent);
2758 utile = ptile;
2759 pix = NULL;
2760 show_line = 0;
2761 highligh_num = -1;
2762 ufont.setItalic(true);
2763 info_font = *fc_font::instance()->get_font(fonts::notify_label);
2764 update_units();
2765 h_pix = NULL;
2766 create_pixmap();
2767 p = mapFromGlobal(QCursor::pos());
2768 cw = new close_widget(this);
2769 setMouseTracking(true);
2770 final_p.setX(p.x());
2771 final_p.setY(p.y());
2772 if (p.x() + width() > parentWidget()->width()) {
2773 final_p.setX(parentWidget()->width() - width());
2775 if (p.y() - height() < 0) {
2776 final_p.setY(height());
2778 move(final_p.x(), final_p.y() - height());
2779 setFocus();
2780 QTimer::singleShot(10, this, SLOT(update_img()));
2782 /****************************************************************
2783 Destructor for unit select
2784 *****************************************************************/
2785 units_select::~units_select()
2787 delete h_pix;
2788 delete pix;
2789 delete cw;
2792 /****************************************************************
2793 Create pixmap of whole widget except borders (pix)
2794 *****************************************************************/
2795 void units_select::create_pixmap()
2797 int a;
2798 int rate, f;
2799 int x, y, i;
2800 QFontMetrics fm(info_font);
2801 QImage cropped_img;
2802 QImage img;
2803 QList <QPixmap*>pix_list;
2804 QPainter p;
2805 QPen pen;
2806 QPixmap pixc;
2807 QPixmap *pixp;
2808 QPixmap *tmp_pix;
2809 QRect crop;
2810 QString str;
2811 struct canvas *unit_pixmap;
2812 struct unit *punit;
2814 if (pix != NULL) {
2815 delete pix;
2816 pix = NULL;
2819 update_units();
2820 if (unit_list.count() > 0) {
2821 punit = unit_list.at(0);
2822 if (tileset_is_isometric(tileset) == false) {
2823 item_size.setWidth(tileset_unit_width(tileset));
2824 item_size.setHeight(tileset_unit_width(tileset));
2825 } else {
2826 item_size.setWidth(tileset_unit_width(tileset) * 0.7);
2827 item_size.setHeight(tileset_unit_width(tileset) * 0.7);
2829 more = false;
2830 if (h_pix != nullptr) {
2831 delete h_pix;
2833 h_pix = new QPixmap(item_size.width(), item_size.height());
2834 h_pix->fill(palette().color(QPalette::HighlightedText));
2835 if (unit_list.size() < 5) {
2836 row_count = 1;
2837 pix = new QPixmap((unit_list.size()) * item_size.width(),
2838 item_size.height());
2839 } else if (unit_list.size() < 9) {
2840 row_count = 2;
2841 pix = new QPixmap(4 * item_size.width(), 2 * item_size.height());
2842 } else {
2843 row_count = 3;
2844 if (unit_list_size(utile->units) > unit_list.size() - 1) {
2845 more = true;
2847 pix = new QPixmap(4 * item_size.width(), 3 * item_size.height());
2849 pix->fill(Qt::transparent);
2850 foreach(punit, unit_list) {
2851 unit_pixmap = qtg_canvas_create(tileset_unit_width(tileset),
2852 tileset_unit_height(tileset));
2853 unit_pixmap->map_pixmap.fill(Qt::transparent);
2854 put_unit(punit, unit_pixmap, 1.0, 0, 0);
2855 img = unit_pixmap->map_pixmap.toImage();
2856 crop = zealous_crop_rect(img);
2857 cropped_img = img.copy(crop);
2858 if (tileset_is_isometric(tileset) == false) {
2859 img = cropped_img.scaled(tileset_unit_width(tileset),
2860 tileset_unit_width(tileset),
2861 Qt::KeepAspectRatio,
2862 Qt::SmoothTransformation);
2863 } else {
2864 img = cropped_img.scaled(tileset_unit_width(tileset) * 0.7,
2865 tileset_unit_width(tileset) * 0.7,
2866 Qt::KeepAspectRatio,
2867 Qt::SmoothTransformation);
2869 pixc = QPixmap::fromImage(img);
2870 pixp = new QPixmap(pixc);
2871 pix_list.push_back(pixp);
2872 qtg_canvas_free(unit_pixmap);
2874 a = qMin(item_size.width() / 4, 12);
2875 x = 0, y = -item_size.height(), i = -1;
2876 p.begin(pix);
2877 ufont.setPixelSize(a);
2878 p.setFont(ufont);
2879 pen.setColor(palette().color(QPalette::Text));
2880 p.setPen(pen);
2882 while (!pix_list.isEmpty()) {
2883 tmp_pix = pix_list.takeFirst();
2884 i++;
2885 if (i % 4 == 0) {
2886 x = 0;
2887 y = y + item_size.height();
2889 punit = unit_list.at(i);
2890 Q_ASSERT(punit != NULL);
2891 rate = unit_type_get(punit)->move_rate;
2892 f = ((punit->fuel) - 1);
2893 if (i == highligh_num) {
2894 p.drawPixmap(x, y, *h_pix);
2895 p.drawPixmap(x, y, *tmp_pix);
2896 } else {
2897 p.drawPixmap(x, y, *tmp_pix);
2899 str = QString(move_points_text(punit->moves_left, false));
2900 if (utype_fuel(unit_type_get(punit))) {
2901 str = str + "(" + QString(move_points_text((rate * f)
2902 + punit->moves_left, false)) + ")";
2904 /* TRANS: MP = Movement points */
2905 str = QString(_("MP:")) + str;
2906 p.drawText(x, y + item_size.height() - 4, str);
2908 x = x + item_size.width();
2909 delete tmp_pix;
2911 p.end();
2912 setFixedWidth(pix->width() + 20);
2913 setFixedHeight(pix->height() + 2 * (fm.height() + 6));
2914 qDeleteAll(pix_list.begin(), pix_list.end());
2918 /****************************************************************
2919 Event for mouse moving around units_select
2920 *****************************************************************/
2921 void units_select::mouseMoveEvent(QMouseEvent *event)
2923 int a, b;
2924 int old_h;
2925 QFontMetrics fm(info_font);
2927 old_h = highligh_num;
2928 highligh_num = -1;
2929 if (event->x() > width() - 11
2930 || event->y() > height() - fm.height() - 5
2931 || event->y() < fm.height() + 3 || event->x() < 11) {
2932 /** do nothing if mouse is on border, just skip next if */
2933 } else if (row_count > 0) {
2934 a = (event->x() - 10) / item_size.width();
2935 b = (event->y() - fm.height() - 3) / item_size.height();
2936 highligh_num = b * 4 + a;
2938 if (old_h != highligh_num) {
2939 create_pixmap();
2940 update();
2944 /****************************************************************
2945 Mouse pressed event for units_select.
2946 Left Button - chooses units
2947 Right Button - closes widget
2948 *****************************************************************/
2949 void units_select::mousePressEvent(QMouseEvent *event)
2951 struct unit *punit;
2952 if (event->button() == Qt::RightButton) {
2953 was_destroyed = true;
2954 close();
2955 destroy();
2957 if (event->button() == Qt::LeftButton && highligh_num != -1) {
2958 update_units();
2959 if (highligh_num >= unit_list.count()) {
2960 return;
2962 punit = unit_list.at(highligh_num);
2963 unit_focus_set(punit);
2964 was_destroyed = true;
2965 close();
2966 destroy();
2970 /****************************************************************
2971 Update image, because in constructor theme colors
2972 are uninitialized in QPainter
2973 *****************************************************************/
2974 void units_select::update_img()
2976 create_pixmap();
2977 update();
2980 /****************************************************************
2981 Redirected paint event
2982 *****************************************************************/
2983 void units_select::paint(QPainter *painter, QPaintEvent *event)
2985 QFontMetrics fm(info_font);
2986 int h, i;
2987 int *f_size;
2988 QPen pen;
2989 QString str, str2;
2990 struct unit *punit;
2991 int point_size = info_font.pointSize();
2992 int pixel_size = info_font.pixelSize();
2994 if (point_size < 0) {
2995 f_size = &pixel_size;
2996 } else {
2997 f_size = &point_size;
2999 if (highligh_num != -1 && highligh_num < unit_list.count()) {
3000 punit = unit_list.at(highligh_num);
3001 /* TRANS: HP - hit points */
3002 str2 = QString(_("%1 HP:%2/%3")).arg(QString(unit_activity_text(punit)),
3003 QString::number(punit->hp),
3004 QString::number(unit_type_get(punit)->hp));
3006 str = QString(PL_("%1 unit", "%1 units",
3007 unit_list_size(utile->units)))
3008 .arg(unit_list_size(utile->units));
3009 for (i = *f_size; i > 4; i--) {
3010 if (point_size < 0) {
3011 info_font.setPixelSize(i);
3012 } else {
3013 info_font.setPointSize(i);
3015 QFontMetrics qfm(info_font);
3016 if (10 + qfm.width(str2) < width()) {
3017 break;
3020 h = fm.height();
3021 if (pix != NULL) {
3022 painter->drawPixmap(10, h + 3, *pix);
3023 pen.setColor(palette().color(QPalette::Text));
3024 painter->setPen(pen);
3025 painter->setFont(info_font);
3026 painter->drawText(10, h, str);
3027 if (highligh_num != -1 && highligh_num < unit_list.count()) {
3028 painter->drawText(10, height() - 5, str2);
3031 if (point_size < 0) {
3032 info_font.setPixelSize(*f_size);
3033 } else {
3034 info_font.setPointSize(*f_size);
3036 cw->put_to_corner();
3038 /****************************************************************
3039 Paint event, redirects to paint(...)
3040 *****************************************************************/
3041 void units_select::paintEvent(QPaintEvent *event)
3043 QPainter painter;
3045 painter.begin(this);
3046 paint(&painter, event);
3047 painter.end();
3050 /****************************************************************
3051 Function from abstract fcwidget to update menu, its not needed
3052 cause widget is easy closable via right mouse click
3053 *****************************************************************/
3054 void units_select::update_menu()
3056 was_destroyed = true;
3057 close();
3058 destroy();
3061 /****************************************************************
3062 Updates unit list on tile
3063 *****************************************************************/
3064 void units_select::update_units()
3066 int i = 1;
3067 struct unit_list *punit_list;
3069 if (utile == NULL) {
3070 struct unit *punit = head_of_units_in_focus();
3071 if (punit) {
3072 utile = unit_tile(punit);
3075 unit_list.clear();
3076 if (utile != nullptr) {
3077 punit_list = utile->units;
3078 if (punit_list != nullptr) {
3079 unit_list_iterate(utile->units, punit) {
3080 if (i > show_line * 4)
3081 unit_list.push_back(punit);
3082 i++;
3083 } unit_list_iterate_end;
3086 if (unit_list.count() == 0) {
3087 close();
3091 /****************************************************************
3092 Close event for units_select, restores focus to map
3093 *****************************************************************/
3094 void units_select::closeEvent(QCloseEvent* event)
3096 gui()->mapview_wdg->setFocus();
3097 QWidget::closeEvent(event);
3100 /****************************************************************
3101 Mouse wheel event for units_select
3102 *****************************************************************/
3103 void units_select::wheelEvent(QWheelEvent *event)
3105 int nr;
3107 if (more == false && utile == NULL) {
3108 return;
3110 nr = qCeil(static_cast<qreal>(unit_list_size(utile->units)) / 4) - 3;
3111 if (event->delta() < 0) {
3112 show_line++;
3113 show_line = qMin(show_line, nr);
3114 } else {
3115 show_line--;
3116 show_line = qMax(0, show_line);
3118 update_units();
3119 create_pixmap();
3120 update();
3121 event->accept();
3124 /****************************************************************
3125 Keyboard handler for units_select
3126 *****************************************************************/
3127 void units_select::keyPressEvent(QKeyEvent *event)
3129 if (event->key() == Qt::Key_Escape) {
3130 was_destroyed = true;
3131 close();
3132 destroy();
3134 QWidget::keyPressEvent(event);
3138 /***************************************************************************
3139 Set current diplo dialog
3140 ***************************************************************************/
3141 void fc_client::set_diplo_dialog(choice_dialog *widget)
3143 opened_dialog = widget;
3146 /***************************************************************************
3147 Get current diplo dialog
3148 ***************************************************************************/
3149 choice_dialog *fc_client::get_diplo_dialog()
3151 return opened_dialog;
3154 /****************************************************************
3155 Give a warning when user is about to edit scenario with manually
3156 set properties.
3157 *****************************************************************/
3158 bool qtg_handmade_scenario_warning()
3160 /* Just tell the client common code to handle this. */
3161 return false;
3164 /****************************************************************
3165 Unit wants to get into some transport on given tile.
3166 *****************************************************************/
3167 bool qtg_request_transport(struct unit *pcargo, struct tile *ptile)
3169 int tcount;
3170 hud_unit_loader *hul;
3171 struct unit_list *potential_transports = unit_list_new();
3172 struct unit *best_transport = transporter_for_unit(pcargo);
3174 unit_list_iterate(ptile->units, ptransport) {
3175 if (can_unit_transport(ptransport, pcargo)
3176 && get_transporter_occupancy(ptransport) < get_transporter_capacity(ptransport)) {
3177 unit_list_append(potential_transports, ptransport);
3179 } unit_list_iterate_end;
3181 tcount = unit_list_size(potential_transports);
3183 if (tcount == 0) {
3184 fc_assert(best_transport == NULL);
3185 unit_list_destroy(potential_transports);
3187 return false; /* Unit was not handled here. */
3188 } else if (tcount == 1) {
3189 /* There's exactly one potential transport - use it automatically */
3190 fc_assert(unit_list_get(potential_transports, 0) == best_transport);
3191 request_unit_load(pcargo, unit_list_get(potential_transports, 0), ptile);
3193 unit_list_destroy(potential_transports);
3195 return true;
3198 hul = new hud_unit_loader(pcargo, ptile);
3199 hul->show_me();
3200 return true;
3203 /***************************************************************************
3204 Popup detailed information about battle or save information for
3205 some kind of statistics
3206 ***************************************************************************/
3207 void qtg_popup_combat_info(int attacker_unit_id, int defender_unit_id,
3208 int attacker_hp, int defender_hp,
3209 bool make_winner_veteran)