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)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
15 #include <fc_config.h>
19 #include <QApplication>
21 #include <QFormLayout>
23 #include <QMainWindow>
25 #include <QResizeEvent>
28 #include <QSignalMapper>
29 #include <QSocketNotifier>
31 #include <QStackedLayout>
32 #include <QStandardPaths>
34 #include <QStyleFactory>
44 #include "connectdlg_common.h"
47 #include "fc_client.h"
50 #include "optiondlg.h"
54 fc_icons
* fc_icons::m_instance
= 0;
55 fc_font
* fc_font::m_instance
= 0;
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 /****************************************************************************
66 ****************************************************************************/
67 fc_client::fc_client() : QMainWindow()
69 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
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
75 * After adding new QObjects null them here.
79 connect_metaserver
= NULL
;
80 central_layout
= 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
;
90 server_notifier
= NULL
;
96 scenarios_load
= NULL
;
97 meta_scan_timer
= NULL
;
98 lan_scan_timer
= NULL
;
100 status_bar_label
= NULL
;
103 sidebar_wdg
= nullptr;
107 game_tab_widget
= NULL
;
108 start_players_tree
= NULL
;
110 info_tile_wdg
= NULL
;
111 opened_dialog
= NULL
;
113 status_bar_queue
.clear();
118 update_info_timer
= nullptr;
119 game_layout
= nullptr;
120 unitinfo_wdg
= nullptr;
121 battlelog_wdg
= nullptr;
122 interface_locked
= false;
124 for (int i
= 0; i
<= PAGE_GAME
; i
++) {
125 pages_layout
[i
] = NULL
;
131 /****************************************************************************
132 Initializes layouts for all pages
133 ****************************************************************************/
134 void fc_client::init()
136 fc_font::instance()->init_fonts();
138 QApplication::setFont(*fc_font::instance()->get_font(fonts::default_font
));
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"));
156 switch_page_mapper
= new QSignalMapper
;
158 pages
[PAGE_MAIN
] = new QWidget(central_wdg
);
163 pages
[PAGE_START
] = new QWidget(central_wdg
);
167 pages
[PAGE_SCENARIO
] = new QWidget(central_wdg
);
168 create_scenario_page();
171 pages
[PAGE_LOAD
] = new QWidget(central_wdg
);
175 pages
[PAGE_NETWORK
] = new QWidget(central_wdg
);
176 create_network_page();
177 pages
[PAGE_NETWORK
]->setVisible(false);
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();
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());
218 game_tab_widget
->init();
219 chat_listener::listen();
223 /****************************************************************************
225 ****************************************************************************/
226 fc_client::~fc_client()
228 status_bar_queue
.clear();
232 /****************************************************************************
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()));
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()
262 /****************************************************************************
263 Called when fc_client is going to quit
264 ****************************************************************************/
265 void fc_client::closing()
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
)
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
) {
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
)
316 enum client_pages new_page
;
319 new_page
= static_cast<client_pages
>(new_pg
);
321 if ((new_page
== PAGE_SCENARIO
|| new_page
== PAGE_LOAD
)
322 && !is_server_running()) {
324 client_start_server_and_set_page(new_page
);
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
]);
344 voteinfo_gui_update();
350 if (gui_options
.gui_qt_show_titlebar
== false) {
351 setWindowFlags(Qt::Window
| Qt::CustomizeWindowHint
);
354 /* For MS Windows, it might ingore first */
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();
367 minimapview_wdg
->reset();
368 overview_size_changed();
369 update_sidebar_tooltips();
370 real_science_report_dialog_update();
371 show_new_turn_info();
374 update_scenarios_page();
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);
386 case (PAGE_GAME
+ 1):
389 if (client
.conn
.used
) {
390 disconnect_from_server();
392 set_client_page(PAGE_MAIN
);
397 /****************************************************************************
398 Returns currently open page
399 ****************************************************************************/
400 enum client_pages
fc_client::current_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 /****************************************************************************
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());
427 return QMainWindow::event(event
);
431 /****************************************************************************
433 ****************************************************************************/
434 void fc_client::closeEvent(QCloseEvent
*event
) {
439 /****************************************************************************
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);
455 input_from_server(sock
);
456 #if defined(Q_WS_WIN)
457 server_notifier
->setEnabled(true);
461 /****************************************************************************
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 /****************************************************************************
476 ****************************************************************************/
477 void fc_client::quit()
479 QApplication
*qapp
= current_app();
481 if (qapp
!= nullptr) {
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 -");
507 send_chat("/detach");
509 obs_button
->setText(_("Don't Observe"));
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
);
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
)
538 x
= opened_repo_dlgs
.key(widget
);
541 opened_repo_dlgs
.insert(str
, widget
);
544 log_error("Failed to find place for new tab widget");
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
552 ****************************************************************************/
553 bool fc_client::is_repo_dlg_open(QString str
)
557 w
= opened_repo_dlgs
.value(str
);
566 /****************************************************************************
567 Returns index on game tab page of given report dialog
568 ****************************************************************************/
569 int fc_client::gimme_index_of(QString str
)
578 w
= opened_repo_dlgs
.value(str
);
579 i
= game_tab_widget
->indexOf(w
);
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) {
593 if (s
.contains("Chat-fx-size")) {
594 qt_settings
.chat_fwidth
= s
.value("Chat-fx-size").toFloat();
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();
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();
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();
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();
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();
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();
626 qt_settings
.minimap_x
= 0.84;
628 if (s
.contains("minimap_y")) {
629 qt_settings
.minimap_y
= s
.value("minimap_y").toFloat();
631 qt_settings
.minimap_y
= 0.79;
633 if (s
.contains("minimap_width")) {
634 qt_settings
.minimap_width
= s
.value("minimap_width").toFloat();
636 qt_settings
.minimap_width
= 0.15;
638 if (s
.contains("minimap_height")) {
639 qt_settings
.minimap_height
= s
.value("minimap_height").toFloat();
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();
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();
664 qt_settings
.show_battle_log
= false;
666 if (s
.contains("battlelog_x")) {
667 qt_settings
.battlelog_x
= s
.value("battlelog_x").toFloat();
669 qt_settings
.battlelog_x
= 0.0;
671 if (s
.contains("minimap_y")) {
672 qt_settings
.battlelog_y
= s
.value("battlelog_y").toFloat();
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
);
734 /****************************************************************************
735 Shows/closes unit selection widget
736 ****************************************************************************/
737 void fc_client::toggle_unit_sel_widget(struct tile
*ptile
)
739 if (unit_sel
!= NULL
) {
742 unit_sel
= new units_select(ptile
, gui()->mapview_wdg
);
745 unit_sel
= new units_select(ptile
, gui()->mapview_wdg
);
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();
762 /****************************************************************************
763 Closes unit selection widget.
764 ****************************************************************************/
765 void fc_client::popdown_unit_sel()
767 if (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
;
800 struct sprite
*sprite
;
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
);
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()
823 QFont
*f
= fc_font::instance()->get_font(fonts::default_font
);
825 if (f
->pointSize() > 0) {
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()));
836 qpb
= new QPushButton(fc_icons::instance()->get_icon("cmax"), "");
837 qpb
->setFixedSize(h
, h
);
838 connect(qpb
, SIGNAL(clicked()), SLOT(maximize()));
840 qpb
= new QPushButton(fc_icons::instance()->get_icon("cclose"), "");
841 qpb
->setFixedSize(h
, h
);
842 connect(qpb
, SIGNAL(clicked()), SLOT(close_fc()));
847 /****************************************************************************
848 Slot for closing freeciv via corner widget
849 ****************************************************************************/
850 void fc_corner::close_fc()
855 /****************************************************************************
856 Slot for maximizing freeciv window via corner widget
857 ****************************************************************************/
858 void fc_corner::maximize()
860 if (mw
->isMaximized() == false) {
867 /****************************************************************************
868 Slot for minimizing freeciv window via corner widget
869 ****************************************************************************/
870 void fc_corner::minimize()
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 ****************************************************************************/
898 /****************************************************************************
899 Returns instance of fc_icons
900 ****************************************************************************/
901 fc_icons
*fc_icons::instance()
904 m_instance
= new fc_icons
;
908 /****************************************************************************
909 Deletes fc_icons instance
910 ****************************************************************************/
911 void fc_icons::drop()
919 /****************************************************************************
920 Returns icon by given name
921 ****************************************************************************/
922 QIcon
fc_icons::get_icon(const QString
&id
)
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
932 + id
+ ".png").toLocal8Bit().data()));
933 str
= str
+ "icons" + DIR_SEPARATOR
;
934 /* Try icon from icons dir */
936 icon
.addFile(fileinfoname(get_data_dirs(),
937 QString(str
.toLocal8Bit().data()
938 + id
+ ".png").toLocal8Bit().data()));
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
)
953 str
= QString("themes") + DIR_SEPARATOR
+ "gui-qt" + DIR_SEPARATOR
;
954 status
= pm
->load(fileinfoname(get_data_dirs(),
955 QString(str
+ current_theme
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()));
967 /****************************************************************************
968 Returns path for icon
969 ****************************************************************************/
970 QString
fc_icons::get_path(const QString
&id
)
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
)
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
1001 qRound(gui()->qt_settings
.minimap_y
1003 gui()->minimapview_wdg
->resize(qRound(gui()->qt_settings
.minimap_width
1005 qRound(gui()->qt_settings
.minimap_height
1007 gui()->battlelog_wdg
->move(qRound(gui()->qt_settings
.battlelog_x
1009 qRound(gui()->qt_settings
.battlelog_y
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
;
1028 if (gui()->is_closing()) {
1031 objs
= gui()->sidebar_wdg
->objects
;
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
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;
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
);
1115 /****************************************************************************
1116 Update the ruleset list
1117 ****************************************************************************/
1118 void pregame_options::set_rulesets(int num_rulesets
, char **rulesets
)
1124 cruleset
->blockSignals(true);
1125 for (i
= 0; i
< num_rulesets
; i
++){
1126 cruleset
->addItem(rulesets
[i
], i
);
1127 if (!strcmp("default", rulesets
[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
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
));
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
)
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
);