1 #include "InGameMenu.h"
2
3 #include "ClientUI.h"
4 #include "CUIControls.h"
5 #include "OptionsWnd.h"
6 #include "SaveFileDialog.h"
7 #include "TextBrowseWnd.h"
8 #include "../client/human/HumanClientApp.h"
9 #include "../network/Networking.h"
10 #include "../util/i18n.h"
11 #include "../util/GameRules.h"
12 #include "../util/OptionsDB.h"
13 #include "../util/Directories.h"
14 #include "../util/Logger.h"
15
16 #include <GG/Button.h>
17 #include <GG/Clr.h>
18 #include <GG/dialogs/ThreeButtonDlg.h>
19
20 #include <boost/filesystem/operations.hpp>
21
22 namespace {
23 const GG::X IN_GAME_OPTIONS_WIDTH(150);
24 const GG::Y IN_GAME_OPTIONS_HEIGHT(310);
25 }
26
InGameMenu()27 InGameMenu::InGameMenu():
28 CUIWnd(UserString("GAME_MENU_WINDOW_TITLE"),
29 GG::INTERACTIVE | GG::MODAL)
30 {}
31
CompleteConstruction()32 void InGameMenu::CompleteConstruction() {
33 CUIWnd::CompleteConstruction();
34
35 m_save_btn = Wnd::Create<CUIButton>(UserString("GAME_MENU_SAVE"));
36 if (HumanClientApp::GetApp()->SinglePlayerGame())
37 m_load_or_concede_btn = Wnd::Create<CUIButton>(UserString("GAME_MENU_LOAD"));
38 else
39 m_load_or_concede_btn = Wnd::Create<CUIButton>(UserString("GAME_MENU_CONCEDE"));
40 m_options_btn = Wnd::Create<CUIButton>(UserString("INTRO_BTN_OPTIONS"));
41 m_resign_btn = Wnd::Create<CUIButton>(UserString("GAME_MENU_RESIGN"));
42 m_done_btn = Wnd::Create<CUIButton>(UserString("DONE"));
43
44 AttachChild(m_save_btn);
45 AttachChild(m_load_or_concede_btn);
46 AttachChild(m_options_btn);
47 AttachChild(m_resign_btn);
48 AttachChild(m_done_btn);
49
50 m_save_btn->LeftClickedSignal.connect(boost::bind(&InGameMenu::Save, this));
51 if (HumanClientApp::GetApp()->SinglePlayerGame()) {
52 m_load_or_concede_btn->LeftClickedSignal.connect(boost::bind(&InGameMenu::Load, this));
53 } else {
54 m_load_or_concede_btn->LeftClickedSignal.connect(boost::bind(&InGameMenu::Concede, this));
55 }
56 m_options_btn->LeftClickedSignal.connect(boost::bind(&InGameMenu::Options, this));
57 m_resign_btn->LeftClickedSignal.connect(boost::bind(&InGameMenu::Resign, this));
58 m_done_btn->LeftClickedSignal.connect(boost::bind(&InGameMenu::Done, this));
59
60 if (!HumanClientApp::GetApp()->CanSaveNow()) {
61 m_save_btn->Disable();
62 m_save_btn->SetBrowseModeTime(GetOptionsDB().Get<int>("ui.tooltip.delay"));
63 m_save_btn->SetBrowseInfoWnd(GG::Wnd::Create<TextBrowseWnd>(
64 UserString("BUTTON_DISABLED"),
65 UserString("SAVE_DISABLED_BROWSE_TEXT"),
66 GG::X(400)
67 ));
68 }
69
70 if (!HumanClientApp::GetApp()->SinglePlayerGame() &&
71 !GetGameRules().Get<bool>("RULE_ALLOW_CONCEDE"))
72 {
73 m_load_or_concede_btn->Disable();
74 m_load_or_concede_btn->SetBrowseModeTime(GetOptionsDB().Get<int>("ui.tooltip.delay"));
75 m_load_or_concede_btn->SetBrowseInfoWnd(GG::Wnd::Create<TextBrowseWnd>(
76 UserString("BUTTON_DISABLED"),
77 UserString("ERROR_CONCEDE_DISABLED"),
78 GG::X(400)
79 ));
80 }
81
82 ResetDefaultPosition();
83 DoLayout();
84 }
85
~InGameMenu()86 InGameMenu::~InGameMenu()
87 {}
88
CalculatePosition() const89 GG::Rect InGameMenu::CalculatePosition() const {
90 const GG::X H_MAINMENU_MARGIN(40); //horizontal empty space
91 const GG::Y V_MAINMENU_MARGIN(40); //vertical empty space
92
93 // Calculate window width and height
94 GG::Pt new_size(ButtonWidth() + H_MAINMENU_MARGIN,
95 5.75 * ButtonCellHeight() + V_MAINMENU_MARGIN); // 9 rows + 0.75 before exit button
96
97 // This wnd determines its own position.
98 GG::Pt new_ul((HumanClientApp::GetApp()->AppWidth() - new_size.x) / 2,
99 (HumanClientApp::GetApp()->AppHeight() - new_size.y) / 2);
100
101 return GG::Rect(new_ul, new_ul + new_size);
102 }
103
ButtonWidth() const104 GG::X InGameMenu::ButtonWidth() const {
105 const GG::X MIN_BUTTON_WIDTH(160);
106 GG::X button_width(0); //width of the buttons
107
108 button_width = std::max(button_width, m_save_btn->MinUsableSize().x);
109 button_width = std::max(button_width, m_load_or_concede_btn->MinUsableSize().x);
110 button_width = std::max(button_width, m_options_btn->MinUsableSize().x);
111 button_width = std::max(button_width, m_resign_btn->MinUsableSize().x);
112 button_width = std::max(button_width, m_done_btn->MinUsableSize().x);
113 button_width = std::max(MIN_BUTTON_WIDTH, button_width);
114
115 return button_width;
116 }
117
ButtonCellHeight() const118 GG::Y InGameMenu::ButtonCellHeight() const {
119 const GG::Y MIN_BUTTON_HEIGHT(40);
120 return std::max(MIN_BUTTON_HEIGHT, m_done_btn->MinUsableSize().y);
121 }
122
DoLayout()123 void InGameMenu::DoLayout() {
124 // place buttons
125 GG::Pt button_ul(GG::X(15), GG::Y(12));
126 GG::Pt button_lr(ButtonWidth(), m_done_btn->MinUsableSize().y);
127
128 button_lr += button_ul;
129
130 GG::Y button_cell_height = ButtonCellHeight();
131
132 m_save_btn->SizeMove(button_ul, button_lr);
133 button_ul.y += GG::Y(button_cell_height);
134 button_lr.y += GG::Y(button_cell_height);
135 m_load_or_concede_btn->SizeMove(button_ul, button_lr);
136 button_ul.y += GG::Y(button_cell_height);
137 button_lr.y += GG::Y(button_cell_height);
138 m_resign_btn->SizeMove(button_ul, button_lr);
139 button_ul.y += GG::Y(button_cell_height);
140 button_lr.y += GG::Y(button_cell_height);
141 m_options_btn->SizeMove(button_ul, button_lr);
142 button_ul.y += GG::Y(button_cell_height) * 1.75;
143 button_lr.y += GG::Y(button_cell_height) * 1.75;
144 m_done_btn->SizeMove(button_ul, button_lr);
145 }
146
KeyPress(GG::Key key,std::uint32_t key_code_point,GG::Flags<GG::ModKey> mod_keys)147 void InGameMenu::KeyPress(GG::Key key, std::uint32_t key_code_point,
148 GG::Flags<GG::ModKey> mod_keys)
149 {
150 // Same behaviour as if "done" was pressed
151 if (key == GG::GGK_RETURN || key == GG::GGK_KP_ENTER || key == GG::GGK_ESCAPE )
152 Done();
153 }
154
Save()155 void InGameMenu::Save() {
156 DebugLogger() << "InGameMenu::Save";
157
158 HumanClientApp* app = HumanClientApp::GetApp();
159 if (!app)
160 return;
161 if (!app->CanSaveNow()) {
162 ErrorLogger() << "InGameMenu::Save aborting; Client app can't save now";
163 return;
164 }
165
166 // send order changes could be made when player decide to save game
167 app->SendPartialOrders();
168
169 try {
170 // When saving in multiplayer, you cannot see the old saves or
171 // browse directories, only give a save file name.
172 DebugLogger() << "... running save file dialog";
173 auto filename = ClientUI::GetClientUI()->GetFilenameWithSaveFileDialog(
174 SaveFileDialog::Purpose::Save,
175 app->SinglePlayerGame() ? SaveFileDialog::SaveType::SinglePlayer : SaveFileDialog::SaveType::MultiPlayer);
176
177 if (!filename.empty()) {
178 if (!app->CanSaveNow()) {
179 ErrorLogger() << "InGameMenu::Save aborting; Client app can't save now";
180 throw std::runtime_error(UserString("UNABLE_TO_SAVE_NOW_TRY_AGAIN"));
181 }
182 DebugLogger() << "... initiating save to " << filename ;
183 app->SaveGame(filename);
184 CloseClicked();
185 }
186
187 } catch (const std::exception& e) {
188 ErrorLogger() << "Exception thrown attempting save: " << e.what();
189 ClientUI::MessageBox(e.what(), true);
190 }
191 }
192
Load()193 void InGameMenu::Load() {
194 Hide();
195 HumanClientApp::GetApp()->LoadSinglePlayerGame();
196 CloseClicked();
197 }
198
Options()199 void InGameMenu::Options() {
200 auto options_wnd = GG::Wnd::Create<OptionsWnd>(true);
201 options_wnd->Run();
202 }
203
Concede()204 void InGameMenu::Concede() {
205 // show confirmation dialog
206 std::shared_ptr<GG::Font> font = ClientUI::GetFont();
207 auto prompt = GG::GUI::GetGUI()->GetStyleFactory()->NewThreeButtonDlg(
208 GG::X(200), GG::Y(75), UserString("GAME_MENU_REALLY_CONCEDE"), font,
209 ClientUI::CtrlColor(), ClientUI::CtrlBorderColor(), ClientUI::CtrlColor(), ClientUI::TextColor(),
210 2, UserString("YES"), UserString("CANCEL"));
211 prompt->Run();
212 if (prompt->Result() == 0) {
213 // send ELIMINATE_SELF message
214 HumanClientApp::GetApp()->EliminateSelf();
215 CloseClicked();
216 }
217 }
218
Resign()219 void InGameMenu::Resign() {
220 // send order changes could be made when player decides to disconnect
221 HumanClientApp::GetApp()->SendPartialOrders();
222
223 HumanClientApp::GetApp()->ResetToIntro(false);
224 CloseClicked();
225 }
226
Done()227 void InGameMenu::Done()
228 { m_done = true; }
229