Multiply AI want for Great Wonders by 1.5
[freeciv.git] / client / gui-qt / fc_client.cpp
blobd9a78a6d9842b52b5d461f6fd187086b89f63a36
1 /**********************************************************************
2 Freeciv - Copyright (C) 1996-2005 - Freeciv Development Team
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 <QApplication>
20 #include <QComboBox>
21 #include <QFormLayout>
22 #include <QLineEdit>
23 #include <QMainWindow>
24 #include <QPainter>
25 #include <QResizeEvent>
26 #include <QScrollBar>
27 #include <QSettings>
28 #include <QSignalMapper>
29 #include <QSocketNotifier>
30 #include <QSpinBox>
31 #include <QStackedLayout>
32 #include <QStandardPaths>
33 #include <QStatusBar>
34 #include <QStyleFactory>
35 #include <QTabBar>
36 #include <QTextBlock>
37 #include <QTextCodec>
38 #include <QTextEdit>
40 // common
41 #include "game.h"
43 // client
44 #include "connectdlg_common.h"
46 // gui-qt
47 #include "fc_client.h"
48 #include "fonts.h"
49 #include "gui_main.h"
50 #include "optiondlg.h"
51 #include "sidebar.h"
52 #include "sprite.h"
54 fc_icons* fc_icons::m_instance = 0;
55 fc_font* fc_font::m_instance = 0;
56 extern "C" {
57 bool get_turn_done_button_state();
58 void real_science_report_dialog_update(void);
60 extern void write_shortcuts();
62 QString current_theme;
64 /****************************************************************************
65 Constructor
66 ****************************************************************************/
67 fc_client::fc_client() : QMainWindow()
69 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
70 /**
71 * Somehow freeciv-client-common asks to switch to page when all widgets
72 * haven't been created yet by Qt, even constructor finished job,
73 * so we null all Qt objects, so while switching we will know if they
74 * were created.
75 * After adding new QObjects null them here.
77 main_wdg = NULL;
78 connect_lan = NULL;
79 connect_metaserver = NULL;
80 central_layout = NULL;
81 output_window = NULL;
82 scenarios_view = NULL;
83 connect_host_edit = NULL;
84 connect_port_edit = NULL;
85 connect_login_edit = NULL;
86 connect_password_edit = NULL;
87 connect_confirm_password_edit = NULL;
88 button = NULL;
89 button_box = NULL;
90 server_notifier = NULL;
91 chat_line = NULL;
92 lan_widget = NULL;
93 wan_widget = NULL;
94 info_widget = NULL;
95 saves_load = NULL;
96 scenarios_load = NULL;
97 meta_scan_timer = NULL;
98 lan_scan_timer = NULL;
99 status_bar = NULL;
100 status_bar_label = NULL;
101 menu_bar = NULL;
102 mapview_wdg = NULL;
103 sidebar_wdg = nullptr;
104 msgwdg = NULL;
105 infotab = NULL;
106 central_wdg = NULL;
107 game_tab_widget = NULL;
108 start_players_tree = NULL;
109 unit_sel = NULL;
110 info_tile_wdg = NULL;
111 opened_dialog = NULL;
112 current_file = "";
113 status_bar_queue.clear();
114 quitting = false;
115 pre_vote = NULL;
116 x_vote = NULL;
117 gtd = NULL;
118 update_info_timer = nullptr;
119 game_layout = nullptr;
120 unitinfo_wdg = nullptr;
121 battlelog_wdg = nullptr;
122 interface_locked = false;
123 map_scale = 1.0f;
124 for (int i = 0; i <= PAGE_GAME; i++) {
125 pages_layout[i] = NULL;
126 pages[i] = NULL;
128 init();
131 /****************************************************************************
132 Initializes layouts for all pages
133 ****************************************************************************/
134 void fc_client::init()
136 fc_font::instance()->init_fonts();
137 read_settings();
138 QApplication::setFont(*fc_font::instance()->get_font(fonts::default_font));
139 QString path;
140 central_wdg = new QWidget;
141 central_layout = new QStackedLayout;
143 // General part not related to any single page
144 menu_bar = new mr_menu();
145 corner_wid = new fc_corner(this);
146 if (gui_options.gui_qt_show_titlebar == false) {
147 menu_bar->setCornerWidget(corner_wid);
149 setMenuBar(menu_bar);
150 status_bar = statusBar();
151 status_bar_label = new QLabel;
152 status_bar_label->setAlignment(Qt::AlignCenter);
153 status_bar->addWidget(status_bar_label, 1);
154 set_status_bar(_("Welcome to Freeciv"));
155 create_cursors();
156 switch_page_mapper = new QSignalMapper;
157 // PAGE_MAIN
158 pages[PAGE_MAIN] = new QWidget(central_wdg);
159 page = PAGE_MAIN;
160 create_main_page();
162 // PAGE_START
163 pages[PAGE_START] = new QWidget(central_wdg);
164 create_start_page();
166 // PAGE_SCENARIO
167 pages[PAGE_SCENARIO] = new QWidget(central_wdg);
168 create_scenario_page();
170 // PAGE_LOAD
171 pages[PAGE_LOAD] = new QWidget(central_wdg);
172 create_load_page();
174 // PAGE_NETWORK
175 pages[PAGE_NETWORK] = new QWidget(central_wdg);
176 create_network_page();
177 pages[PAGE_NETWORK]->setVisible(false);
179 // PAGE_GAME
180 gui_options.gui_qt_allied_chat_only = true;
181 path = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
182 if (path.isEmpty() == false) {
183 QSettings::setPath(QSettings::NativeFormat, QSettings::UserScope, path);
185 pages[PAGE_GAME] = new QWidget(central_wdg);
186 init_mapcanvas_and_overview();
187 create_game_page();
189 pages[PAGE_GAME + 1] = new QWidget(central_wdg);
190 create_loading_page();
192 pages_layout[PAGE_GAME]->setContentsMargins(0, 0, 0, 0);
194 pages[PAGE_MAIN]->setLayout(pages_layout[PAGE_MAIN]);
195 pages[PAGE_NETWORK]->setLayout(pages_layout[PAGE_NETWORK]);
196 pages[PAGE_LOAD]->setLayout(pages_layout[PAGE_LOAD]);
197 pages[PAGE_SCENARIO]->setLayout(pages_layout[PAGE_SCENARIO]);
198 pages[PAGE_START]->setLayout(pages_layout[PAGE_START]);
199 pages[PAGE_GAME]->setLayout(pages_layout[PAGE_GAME]);
200 pages[PAGE_GAME + 1]->setLayout(pages_layout[PAGE_GAME + 1]);
202 central_layout->addWidget(pages[PAGE_MAIN]);
203 central_layout->addWidget(pages[PAGE_NETWORK]);
204 central_layout->addWidget(pages[PAGE_LOAD]);
205 central_layout->addWidget(pages[PAGE_SCENARIO]);
206 central_layout->addWidget(pages[PAGE_START]);
207 central_layout->addWidget(pages[PAGE_GAME]);
208 central_layout->addWidget(pages[PAGE_GAME + 1]);
210 central_wdg->setLayout(central_layout);
211 setCentralWidget(central_wdg);
213 connect(switch_page_mapper, SIGNAL(mapped( int)),
214 this, SLOT(switch_page(int)));
215 resize(pages[PAGE_MAIN]->minimumSizeHint());
216 setVisible(true);
218 game_tab_widget->init();
219 chat_listener::listen();
223 /****************************************************************************
224 Destructor
225 ****************************************************************************/
226 fc_client::~fc_client()
228 status_bar_queue.clear();
232 /****************************************************************************
233 Main part of gui-qt
234 ****************************************************************************/
235 void fc_client::main(QApplication *qapp)
237 qRegisterMetaType<QTextCursor>("QTextCursor");
238 qRegisterMetaType<QTextBlock>("QTextBlock");
239 fc_allocate_ow_mutex();
240 real_output_window_append(_("This is Qt-client for Freeciv."), NULL, -1);
241 fc_release_ow_mutex();
242 chat_welcome_message(true);
244 set_client_state(C_S_DISCONNECTED);
246 startTimer(TIMER_INTERVAL);
247 connect(qapp, SIGNAL(aboutToQuit()), this, SLOT(closing()));
248 qapp->exec();
250 free_mapcanvas_and_overview();
251 tileset_free_tiles(tileset);
254 /****************************************************************************
255 Returns status if fc_client is being closed
256 ****************************************************************************/
257 bool fc_client::is_closing()
259 return quitting;
262 /****************************************************************************
263 Called when fc_client is going to quit
264 ****************************************************************************/
265 void fc_client::closing()
267 quitting = true;
270 /****************************************************************************
271 Slot to send fake chat messages. Do not use in new code.
272 ****************************************************************************/
273 void fc_client::send_fake_chat_message(const QString &message)
275 send_chat_message(message);
278 /****************************************************************************
279 Appends text to chat window
280 ****************************************************************************/
281 void fc_client::chat_message_received(const QString &message,
282 const struct text_tag_list *tags)
284 QTextCursor cursor;
285 QColor col = output_window->palette().color(QPalette::Text);
286 QString str = apply_tags(message, tags, col);
288 if (output_window != NULL) {
289 output_window->append(str);
290 output_window->verticalScrollBar()->setSliderPosition(
291 output_window->verticalScrollBar()->maximum());
295 /****************************************************************************
296 Return whether chatline should be active on page.
297 ****************************************************************************/
298 bool fc_client::chat_active_on_page(enum client_pages check)
300 if (check == PAGE_START || check == PAGE_GAME) {
301 return true;
304 return false;
307 /****************************************************************************
308 Switch from one client page to another.
309 Argument is int cause QSignalMapper doesn't want to work with enum
310 Because chat widget is in 2 layouts we need to switch between them here
311 (addWidget removes it from prevoius layout automatically)
312 ****************************************************************************/
313 void fc_client::switch_page(int new_pg)
315 char buf[256];
316 enum client_pages new_page;
317 int i_page;
319 new_page = static_cast<client_pages>(new_pg);
321 if ((new_page == PAGE_SCENARIO || new_page == PAGE_LOAD)
322 && !is_server_running()) {
323 current_file = "";
324 client_start_server_and_set_page(new_page);
325 return;
328 if (page == PAGE_NETWORK){
329 destroy_server_scans();
331 menuBar()->setVisible(false);
332 if (status_bar != nullptr) {
333 status_bar->setVisible(true);
335 QApplication::alert(gui()->central_wdg);
336 central_layout->setCurrentWidget(pages[new_pg]);
337 page = new_page;
338 i_page = new_page;
339 switch (i_page) {
340 case PAGE_MAIN:
341 break;
342 case PAGE_START:
343 pre_vote->hide();
344 voteinfo_gui_update();
345 break;
346 case PAGE_LOAD:
347 update_load_page();
348 break;
349 case PAGE_GAME:
350 if (gui_options.gui_qt_show_titlebar == false) {
351 setWindowFlags(Qt::Window | Qt::CustomizeWindowHint);
353 showMaximized();
354 /* For MS Windows, it might ingore first */
355 showMaximized();
356 gui()->infotab->chtwdg->update_widgets();
357 status_bar->setVisible(false);
358 if (gui_options.gui_qt_fullscreen){
359 gui()->showFullScreen();
360 gui()->game_tab_widget->showFullScreen();
362 menuBar()->setVisible(true);
363 mapview_wdg->setFocus();
364 center_on_something();
365 voteinfo_gui_update();
366 update_info_label();
367 minimapview_wdg->reset();
368 overview_size_changed();
369 update_sidebar_tooltips();
370 real_science_report_dialog_update();
371 show_new_turn_info();
372 break;
373 case PAGE_SCENARIO:
374 update_scenarios_page();
375 break;
376 case PAGE_NETWORK:
377 update_network_lists();
378 set_connection_state(LOGIN_TYPE);
379 connect_host_edit->setText(server_host);
380 fc_snprintf(buf, sizeof(buf), "%d", server_port);
381 connect_port_edit->setText(buf);
382 connect_login_edit->setText(user_name);
383 connect_password_edit->setDisabled(true);
384 connect_confirm_password_edit->setDisabled(true);
385 break;
386 case (PAGE_GAME + 1):
387 break;
388 default:
389 if (client.conn.used) {
390 disconnect_from_server();
392 set_client_page(PAGE_MAIN);
393 break;
397 /****************************************************************************
398 Returns currently open page
399 ****************************************************************************/
400 enum client_pages fc_client::current_page()
402 return page;
405 /****************************************************************************
406 Add notifier for server input
407 ****************************************************************************/
408 void fc_client::add_server_source(int sock)
410 server_notifier = new QSocketNotifier(sock, QSocketNotifier::Read);
412 connect(server_notifier, SIGNAL(activated(int)), this,
413 SLOT(server_input(int)));
416 /****************************************************************************
417 Event handler
418 ****************************************************************************/
419 bool fc_client::event(QEvent *event)
421 if (event->type() == QEvent::User) {
422 version_message_event vmevt =
423 dynamic_cast<version_message_event&>(*event);
424 set_status_bar(vmevt.get_message());
425 return true;
426 } else {
427 return QMainWindow::event(event);
431 /****************************************************************************
432 Closes main window
433 ****************************************************************************/
434 void fc_client::closeEvent(QCloseEvent *event) {
435 popup_quit_dialog();
436 event->ignore();
439 /****************************************************************************
440 Removes notifier
441 ****************************************************************************/
442 void fc_client::remove_server_source()
444 delete server_notifier;
447 /****************************************************************************
448 There is input from server
449 ****************************************************************************/
450 void fc_client::server_input(int sock)
452 #if defined(Q_WS_WIN)
453 server_notifier->setEnabled(false);
454 #endif
455 input_from_server(sock);
456 #if defined(Q_WS_WIN)
457 server_notifier->setEnabled(true);
458 #endif
461 /****************************************************************************
462 Timer event handling
463 ****************************************************************************/
464 void fc_client::timerEvent(QTimerEvent *event)
466 // Prevent current timer from repeating with possibly wrong interval
467 killTimer(event->timerId());
469 // Call timer callback in client common code and
470 // start new timer with correct interval
471 startTimer(real_timer_callback() * 1000);
474 /****************************************************************************
475 Quit App
476 ****************************************************************************/
477 void fc_client::quit()
479 QApplication *qapp = current_app();
481 if (qapp != nullptr) {
482 qapp->quit();
486 /****************************************************************************
487 Disconnect from server and return to MAIN PAGE
488 ****************************************************************************/
489 void fc_client::slot_disconnect()
491 if (client.conn.used) {
492 disconnect_from_server();
495 switch_page(PAGE_MAIN);
498 /****************************************************************************
499 User clicked Observe button in START_PAGE
500 ****************************************************************************/
501 void fc_client::slot_pregame_observe()
503 if (client_is_observer() || client_is_global_observer()) {
504 if (game.info.is_new_game) {
505 send_chat("/take -");
506 } else {
507 send_chat("/detach");
509 obs_button->setText(_("Don't Observe"));
510 } else {
511 send_chat("/observe");
512 obs_button->setText(_("Observe"));
516 /****************************************************************************
517 User clicked Start in START_PAGE
518 ****************************************************************************/
519 void fc_client::slot_pregame_start()
521 if (can_client_control()) {
522 dsend_packet_player_ready(&client.conn,
523 player_number(client_player()),
524 !client_player()->is_ready);
525 } else {
526 dsend_packet_player_ready(&client.conn, 0, TRUE);
531 /****************************************************************************
532 Finds not used index on game_view_tab and returns it
533 ****************************************************************************/
534 void fc_client::gimme_place(QWidget *widget, QString str)
536 QString x;
538 x = opened_repo_dlgs.key(widget);
540 if (x.isEmpty()) {
541 opened_repo_dlgs.insert(str, widget);
542 return;
544 log_error("Failed to find place for new tab widget");
545 return;
548 /****************************************************************************
549 Checks if given report is opened, if you create new report as tab on game
550 page, figure out some original string and put in in repodlg.h as comment to
551 that QWidget class.
552 ****************************************************************************/
553 bool fc_client::is_repo_dlg_open(QString str)
555 QWidget *w;
557 w = opened_repo_dlgs.value(str);
559 if (w == NULL) {
560 return false;
563 return true;
566 /****************************************************************************
567 Returns index on game tab page of given report dialog
568 ****************************************************************************/
569 int fc_client::gimme_index_of(QString str)
571 int i;
572 QWidget *w;
574 if (str == "MAP") {
575 return 0;
578 w = opened_repo_dlgs.value(str);
579 i = game_tab_widget->indexOf(w);
580 return i;
583 /****************************************************************************
584 Loads qt-specific options
585 ****************************************************************************/
586 void fc_client::read_settings()
588 QSettings s(QSettings::IniFormat, QSettings::UserScope,
589 "freeciv-qt-client");
590 if (s.contains("Fonts-set") == false) {
591 configure_fonts();
593 if (s.contains("Chat-fx-size")) {
594 qt_settings.chat_fwidth = s.value("Chat-fx-size").toFloat();
595 } else {
596 qt_settings.chat_fwidth = 0.2;
598 if (s.contains("Chat-fy-size")) {
599 qt_settings.chat_fheight = s.value("Chat-fy-size").toFloat();
600 } else {
601 qt_settings.chat_fheight = 0.4;
603 if (s.contains("Chat-fx-pos")) {
604 qt_settings.chat_fx_pos = s.value("Chat-fx-pos").toFloat();
605 } else {
606 qt_settings.chat_fx_pos = 0.0;
608 if (s.contains("Chat-fy-pos")) {
609 qt_settings.chat_fy_pos = s.value("Chat-fy-pos").toFloat();
610 } else {
611 qt_settings.chat_fy_pos = 0.6;
613 if (s.contains("unit_fx")) {
614 qt_settings.unit_info_pos_fx = s.value("unit_fx").toFloat();
615 } else {
616 qt_settings.unit_info_pos_fx = 0.33;
618 if (s.contains("unit_fy")) {
619 qt_settings.unit_info_pos_fy = s.value("unit_fy").toFloat();
620 } else {
621 qt_settings.unit_info_pos_fy = 0.88;
623 if (s.contains("minimap_x")) {
624 qt_settings.minimap_x = s.value("minimap_x").toFloat();
625 } else {
626 qt_settings.minimap_x = 0.84;
628 if (s.contains("minimap_y")) {
629 qt_settings.minimap_y = s.value("minimap_y").toFloat();
630 } else {
631 qt_settings.minimap_y = 0.79;
633 if (s.contains("minimap_width")) {
634 qt_settings.minimap_width = s.value("minimap_width").toFloat();
635 } else {
636 qt_settings.minimap_width = 0.15;
638 if (s.contains("minimap_height")) {
639 qt_settings.minimap_height = s.value("minimap_height").toFloat();
640 } else {
641 qt_settings.minimap_height = 0.2;
644 if (s.contains("City-dialog")) {
645 qt_settings.city_geometry = s.value("City-dialog").toByteArray();
647 if (s.contains("splitter1")) {
648 qt_settings.city_splitter1 = s.value("splitter1").toByteArray();
650 if (s.contains("splitter2")) {
651 qt_settings.city_splitter2 = s.value("splitter2").toByteArray();
653 if (s.contains("splitter3")) {
654 qt_settings.city_splitter3 = s.value("splitter3").toByteArray();
656 if (s.contains("new_turn_text")) {
657 qt_settings.show_new_turn_text = s.value("new_turn_text").toBool();
658 } else {
659 qt_settings.show_new_turn_text = true;
661 if (s.contains("show_battle_log")) {
662 qt_settings.show_battle_log = s.value("show_battle_log").toBool();
663 } else {
664 qt_settings.show_battle_log = false;
666 if (s.contains("battlelog_x")) {
667 qt_settings.battlelog_x = s.value("battlelog_x").toFloat();
668 } else {
669 qt_settings.battlelog_x = 0.0;
671 if (s.contains("minimap_y")) {
672 qt_settings.battlelog_y = s.value("battlelog_y").toFloat();
673 } else {
674 qt_settings.battlelog_y = 0.0;
676 qt_settings.player_repo_sort_col = -1;
677 qt_settings.city_repo_sort_col = -1;
679 if (qt_settings.chat_fx_pos < 0 || qt_settings.chat_fx_pos >= 1) {
680 qt_settings.chat_fx_pos = 0.0;
682 if (qt_settings.chat_fy_pos >= 1 || qt_settings.chat_fy_pos < 0) {
683 qt_settings.chat_fy_pos = 0.6;
685 if (qt_settings.chat_fwidth < 0.05 || qt_settings.chat_fwidth > 0.9) {
686 qt_settings.chat_fwidth = 0.2;
688 if (qt_settings.chat_fheight < 0.05 || qt_settings.chat_fheight > 0.9) {
689 qt_settings.chat_fheight = 0.33;
691 if (qt_settings.battlelog_x < 0.0) {
692 qt_settings.battlelog_x = 0.33;
694 if (qt_settings.battlelog_y < 0.0) {
695 qt_settings.battlelog_y = 0.0;
697 if (qt_settings.minimap_x < 0 || qt_settings.minimap_x > 1) {
698 qt_settings.chat_fx_pos = 0.84;
700 if (qt_settings.minimap_y < 0 || qt_settings.minimap_y > 1) {
701 qt_settings.chat_fx_pos = 0.79;
705 /****************************************************************************
706 Save qt-specific options
707 ****************************************************************************/
708 void fc_client::write_settings()
710 QSettings s(QSettings::IniFormat, QSettings::UserScope,
711 "freeciv-qt-client");
712 s.setValue("Fonts-set", true);
713 s.setValue("Chat-fx-size", qt_settings.chat_fwidth);
714 s.setValue("Chat-fy-size", qt_settings.chat_fheight);
715 s.setValue("Chat-fx-pos", qt_settings.chat_fx_pos);
716 s.setValue("Chat-fy-pos", qt_settings.chat_fy_pos);
717 s.setValue("City-dialog", qt_settings.city_geometry);
718 s.setValue("splitter1", qt_settings.city_splitter1);
719 s.setValue("splitter2", qt_settings.city_splitter2);
720 s.setValue("splitter3", qt_settings.city_splitter3);
721 s.setValue("unit_fx", qt_settings.unit_info_pos_fx);
722 s.setValue("unit_fy", qt_settings.unit_info_pos_fy);
723 s.setValue("minimap_x", qt_settings.minimap_x);
724 s.setValue("minimap_y", qt_settings.minimap_y);
725 s.setValue("minimap_width", qt_settings.minimap_width);
726 s.setValue("minimap_height", qt_settings.minimap_height);
727 s.setValue("battlelog_x", qt_settings.battlelog_x);
728 s.setValue("battlelog_y", qt_settings.battlelog_y);
729 s.setValue("new_turn_text", qt_settings.show_new_turn_text);
730 s.setValue("show_battle_log", qt_settings.show_battle_log);
731 write_shortcuts();
734 /****************************************************************************
735 Shows/closes unit selection widget
736 ****************************************************************************/
737 void fc_client::toggle_unit_sel_widget(struct tile *ptile)
739 if (unit_sel != NULL) {
740 unit_sel->close();
741 delete unit_sel;
742 unit_sel = new units_select(ptile, gui()->mapview_wdg);
743 unit_sel->show();
744 } else {
745 unit_sel = new units_select(ptile, gui()->mapview_wdg);
746 unit_sel->show();
750 /****************************************************************************
751 Update unit selection widget if open
752 ****************************************************************************/
753 void fc_client::update_unit_sel()
755 if (unit_sel != NULL){
756 unit_sel->update_units();
757 unit_sel->create_pixmap();
758 unit_sel->update();
762 /****************************************************************************
763 Closes unit selection widget.
764 ****************************************************************************/
765 void fc_client::popdown_unit_sel()
767 if (unit_sel != nullptr){
768 unit_sel->close();
769 delete unit_sel;
770 unit_sel = nullptr;
774 /****************************************************************************
775 Removes report dialog string from the list marking it as closed
776 ****************************************************************************/
777 void fc_client::remove_repo_dlg(QString str)
779 /* if app is closing opened_repo_dlg is already deleted */
780 if (is_closing() == false) {
781 opened_repo_dlgs.remove(str);
785 /****************************************************************************
786 Popups client options
787 ****************************************************************************/
788 void fc_client::popup_client_options()
790 option_dialog_popup(_("Set local options"), client_optset);
794 void fc_client::create_cursors(void)
796 enum cursor_type curs;
797 int cursor;
798 QPixmap *pix;
799 int hot_x, hot_y;
800 struct sprite *sprite;
801 int frame;
802 QCursor *c;
803 for (cursor = 0; cursor < CURSOR_LAST; cursor++) {
804 for (frame = 0; frame < NUM_CURSOR_FRAMES; frame++) {
805 curs = static_cast<cursor_type>(cursor);
806 sprite = get_cursor_sprite(tileset, curs, &hot_x, &hot_y, frame);
807 pix = sprite->pm;
808 c = new QCursor(*pix, hot_x, hot_y);
809 fc_cursors[cursor][frame] = c;
815 /****************************************************************************
816 Contructor for corner widget (used for menubar)
817 ****************************************************************************/
818 fc_corner::fc_corner(QMainWindow *qmw): QWidget()
820 QHBoxLayout *hb;
821 QPushButton *qpb;
822 int h;
823 QFont *f = fc_font::instance()->get_font(fonts::default_font);
825 if (f->pointSize() > 0) {
826 h = f->pointSize();
827 } else {
828 h = f->pixelSize();
830 mw = qmw;
831 hb = new QHBoxLayout();
832 qpb = new QPushButton(fc_icons::instance()->get_icon("cmin"), "");
833 qpb->setFixedSize(h, h);
834 connect(qpb, SIGNAL(clicked()), SLOT(minimize()));
835 hb->addWidget(qpb);
836 qpb = new QPushButton(fc_icons::instance()->get_icon("cmax"), "");
837 qpb->setFixedSize(h, h);
838 connect(qpb, SIGNAL(clicked()), SLOT(maximize()));
839 hb->addWidget(qpb);
840 qpb = new QPushButton(fc_icons::instance()->get_icon("cclose"), "");
841 qpb->setFixedSize(h, h);
842 connect(qpb, SIGNAL(clicked()), SLOT(close_fc()));
843 hb->addWidget(qpb);
844 setLayout(hb);
847 /****************************************************************************
848 Slot for closing freeciv via corner widget
849 ****************************************************************************/
850 void fc_corner::close_fc()
852 mw->close();
855 /****************************************************************************
856 Slot for maximizing freeciv window via corner widget
857 ****************************************************************************/
858 void fc_corner::maximize()
860 if (mw->isMaximized() == false) {
861 mw->showMaximized();
862 } else {
863 mw->showNormal();
867 /****************************************************************************
868 Slot for minimizing freeciv window via corner widget
869 ****************************************************************************/
870 void fc_corner::minimize()
872 mw->showMinimized();
875 /****************************************************************************
876 Game tab widget constructor
877 ****************************************************************************/
878 fc_game_tab_widget::fc_game_tab_widget(): QStackedWidget()
882 /****************************************************************************
883 Init default settings for game_tab_widget
884 ****************************************************************************/
885 void fc_game_tab_widget::init()
887 connect(this, SIGNAL(currentChanged(int)), SLOT(current_changed(int)));
891 /****************************************************************************
892 Icon provider constructor
893 ****************************************************************************/
894 fc_icons::fc_icons()
898 /****************************************************************************
899 Returns instance of fc_icons
900 ****************************************************************************/
901 fc_icons *fc_icons::instance()
903 if (!m_instance)
904 m_instance = new fc_icons;
905 return m_instance;
908 /****************************************************************************
909 Deletes fc_icons instance
910 ****************************************************************************/
911 void fc_icons::drop()
913 if (m_instance) {
914 delete m_instance;
915 m_instance = 0;
919 /****************************************************************************
920 Returns icon by given name
921 ****************************************************************************/
922 QIcon fc_icons::get_icon(const QString &id)
924 QIcon icon;
925 QString str;
927 str = QString("themes") + DIR_SEPARATOR + "gui-qt" + DIR_SEPARATOR;
928 /* Try custom icon from theme */
929 icon.addFile(fileinfoname(get_data_dirs(),
930 QString(str.toLocal8Bit().data() + current_theme
931 + DIR_SEPARATOR
932 + id + ".png").toLocal8Bit().data()));
933 str = str + "icons" + DIR_SEPARATOR;
934 /* Try icon from icons dir */
935 if (icon.isNull()) {
936 icon.addFile(fileinfoname(get_data_dirs(),
937 QString(str.toLocal8Bit().data()
938 + id + ".png").toLocal8Bit().data()));
940 return QIcon(icon);
943 /****************************************************************************
944 Returns pixmap by given name, pixmap needs to be deleted by someone else
945 ****************************************************************************/
946 QPixmap* fc_icons::get_pixmap(const QString &id)
948 QPixmap *pm;
949 bool status;
950 QString str;
952 pm = new QPixmap;
953 str = QString("themes") + DIR_SEPARATOR + "gui-qt" + DIR_SEPARATOR;
954 status = pm->load(fileinfoname(get_data_dirs(),
955 QString(str + current_theme
956 + DIR_SEPARATOR
957 + id + ".png").toLocal8Bit().data()));
959 if (status == false) {
960 str = str + "icons" + DIR_SEPARATOR;
961 pm->load(fileinfoname(get_data_dirs(), QString(str
962 + id + ".png").toLocal8Bit().data()));
964 return pm;
967 /****************************************************************************
968 Returns path for icon
969 ****************************************************************************/
970 QString fc_icons::get_path(const QString &id)
972 QString str;
974 str = QString("themes") + DIR_SEPARATOR + "gui-qt"
975 + DIR_SEPARATOR + "icons" + DIR_SEPARATOR;
976 return fileinfoname(get_data_dirs(),
977 QString(str + id + ".png").toLocal8Bit().data());
980 /****************************************************************************
981 Resize event for all game tab widgets
982 ****************************************************************************/
983 void fc_game_tab_widget::resizeEvent(QResizeEvent *event)
985 QSize size;
986 size = event->size();
987 if (C_S_RUNNING <= client_state()) {
988 gui()->sidebar_wdg->resize_me(size.width(), size.height());
989 map_canvas_resized(size.width(), size.height());
990 gui()->infotab->resize(qRound((size.width()
991 * gui()->qt_settings.chat_fwidth)),
992 qRound((size.height()
993 * gui()->qt_settings.chat_fheight)));
994 gui()->infotab->move(qRound((size.width()
995 * gui()->qt_settings.chat_fx_pos)),
996 qRound((size.height()
997 * gui()->qt_settings.chat_fy_pos)));
998 gui()->infotab->restore_chat();
999 gui()->minimapview_wdg->move(qRound(gui()->qt_settings.minimap_x
1000 * mapview.width),
1001 qRound(gui()->qt_settings.minimap_y
1002 * mapview.height));
1003 gui()->minimapview_wdg->resize(qRound(gui()->qt_settings.minimap_width
1004 * mapview.width),
1005 qRound(gui()->qt_settings.minimap_height
1006 * mapview.height));
1007 gui()->battlelog_wdg->move(qRound(gui()->qt_settings.battlelog_x
1008 * mapview.width),
1009 qRound(gui()->qt_settings.battlelog_y
1010 * mapview.height));
1011 gui()->x_vote->move(width() / 2 - gui()->x_vote->width() / 2, 0);
1012 gui()->update_sidebar_tooltips();
1013 side_disable_endturn(get_turn_done_button_state());
1014 gui()->mapview_wdg->resize(event->size().width(),size.height());
1015 gui()->unitinfo_wdg->update_actions(nullptr);
1017 event->setAccepted(true);
1020 /****************************************************************************
1021 Tab has been changed
1022 ****************************************************************************/
1023 void fc_game_tab_widget::current_changed(int index)
1025 QList<fc_sidewidget*> objs;
1026 fc_sidewidget *sw;
1028 if (gui()->is_closing()) {
1029 return;
1031 objs = gui()->sidebar_wdg->objects;
1033 foreach(sw, objs) {
1034 sw->update_final_pixmap();
1036 currentWidget()->hide();
1037 widget(index)->show();
1039 /* Set focus to map instead sidebar */
1040 if (gui()->mapview_wdg && gui()->current_page() == PAGE_GAME
1041 && index == 0) {
1042 gui()->mapview_wdg->setFocus();
1047 /****************************************************************************
1048 Pregame options contructor
1049 ****************************************************************************/
1050 pregame_options::pregame_options(QWidget *parent) : QWidget(parent)
1054 /****************************************************************************
1055 Init's layout and default values for options in START_PAGE
1056 ****************************************************************************/
1057 void pregame_options::init()
1059 QFormLayout *layout;
1060 QPushButton *qclient_options;
1061 QHBoxLayout *hbox = nullptr;
1062 QPushButton *but;
1063 int level;
1065 layout = new QFormLayout(this);
1066 nation = new QPushButton(this);
1067 qclient_options = new QPushButton(_("Client Options"));
1068 max_players = new QSpinBox(this);
1069 ailevel = new QComboBox(this);
1070 cruleset = new QComboBox(this);
1071 max_players->setRange(1, MAX_NUM_PLAYERS);
1073 // Text and icon set by update_buttons()
1074 connect(nation, &QPushButton::clicked,
1075 this, &pregame_options::pick_nation);
1076 connect(qclient_options, SIGNAL(clicked()), parentWidget(),
1077 SLOT(popup_client_options()));
1078 for (level = 0; level < AI_LEVEL_COUNT; level++) {
1079 if (is_settable_ai_level(static_cast<ai_level>(level))) {
1080 const char *level_name = ai_level_translated_name(
1081 static_cast<ai_level>(level));
1082 ailevel->addItem(level_name, level);
1085 ailevel->setCurrentIndex(-1);
1087 connect(max_players, SIGNAL(valueChanged(int)),
1088 SLOT(max_players_change(int)));
1089 connect(ailevel, SIGNAL(currentIndexChanged(int)),
1090 SLOT(ailevel_change(int)));
1091 connect(cruleset, SIGNAL(currentIndexChanged(int)),
1092 SLOT(ruleset_change(int)));
1094 but = new QPushButton;
1095 but->setText(_("More Game Options"));
1096 but->setIcon(fc_icons::instance()->get_icon("preferences-other"));
1097 QObject::connect(but, SIGNAL(clicked()), this,
1098 SLOT(popup_server_options()));
1100 layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
1101 layout->addRow(_("Nation:"), nation);
1102 layout->addRow(_("Rules:"), cruleset);
1104 hbox = new QHBoxLayout();
1105 hbox->addWidget(max_players);
1106 hbox->addWidget(ailevel);
1107 layout->addRow(_("Players:"), hbox);
1108 layout->addWidget(but);
1109 layout->addWidget(qclient_options);
1110 setLayout(layout);
1112 update_buttons();
1115 /****************************************************************************
1116 Update the ruleset list
1117 ****************************************************************************/
1118 void pregame_options::set_rulesets(int num_rulesets, char **rulesets)
1120 int i;
1121 int def_idx = -1;
1123 cruleset->clear();
1124 cruleset->blockSignals(true);
1125 for (i = 0; i < num_rulesets; i++){
1126 cruleset->addItem(rulesets[i], i);
1127 if (!strcmp("default", rulesets[i])) {
1128 def_idx = i;
1132 /* HACK: server should tell us the current ruleset. */
1133 cruleset->setCurrentIndex(def_idx);
1134 cruleset->blockSignals(false);
1137 /****************************************************************************
1138 Sets the value of the "aifill" option. Doesn't send the new value to the
1139 server
1140 ****************************************************************************/
1141 void pregame_options::set_aifill(int aifill)
1143 max_players->blockSignals(true);
1144 max_players->setValue(aifill);
1145 max_players->blockSignals(false);
1148 /****************************************************************************
1149 Updates the buttons whenever the game state has changed
1150 ****************************************************************************/
1151 void pregame_options::update_buttons()
1153 struct sprite *psprite = nullptr;
1154 QPixmap *pixmap = nullptr;
1155 const struct player *pplayer = client_player();
1157 // Update the "Select Nation" button
1158 if (pplayer != nullptr) {
1159 if (pplayer->nation != nullptr) {
1160 nation->setText(nation_adjective_for_player(pplayer));
1161 psprite = get_nation_shield_sprite(tileset, pplayer->nation);
1162 pixmap = psprite->pm;
1163 nation->setIconSize(pixmap->size());
1164 nation->setIcon(QIcon(*pixmap));
1165 } else {
1166 nation->setText(_("Random"));
1167 nation->setIcon(fc_icons::instance()->get_icon("flush-random"));
1172 /****************************************************************************
1173 Slot for changing aifill value
1174 ****************************************************************************/
1175 void pregame_options::max_players_change(int i)
1177 option_int_set(optset_option_by_name(server_optset, "aifill"), i);
1180 /****************************************************************************
1181 Slot for changing level of AI
1182 ****************************************************************************/
1183 void pregame_options::ailevel_change(int i)
1185 int k;
1186 const char *name;
1188 k = ailevel->currentData().toInt();
1189 name = ai_level_cmd(static_cast<ai_level>(k));
1190 send_chat_printf("/%s", name);
1193 /****************************************************************************
1194 Slot for changing ruleset
1195 ****************************************************************************/
1196 void pregame_options::ruleset_change(int i)
1198 if (!cruleset->currentText().isEmpty()) {
1199 set_ruleset(cruleset->currentText().toLocal8Bit().data());
1203 /****************************************************************************
1204 Slot for picking a nation
1205 ****************************************************************************/
1206 void pregame_options::pick_nation()
1208 popup_races_dialog(client_player());
1211 /****************************************************************************
1212 Popups client options
1213 ****************************************************************************/
1214 void pregame_options::popup_server_options()
1216 option_dialog_popup(_("Set server options"), server_optset);