1 /*
2    Copyright (C) 2016 - 2018 by the Battle for Wesnoth Project https://www.wesnoth.org/
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY.
10 
11    See the COPYING file for more details.
12 */
13 
14 #pragma once
15 
16 #include "chat_events.hpp"
17 #include "chat_log.hpp"
18 #include "game_initialization/lobby_data.hpp"
19 #include "game_initialization/lobby_info.hpp"
20 #include "gui/widgets/container_base.hpp"
21 
22 #include <map>
23 #include <string>
24 
25 class config;
26 class wesnothd_connection;
27 
28 namespace gui2
29 {
30 
31 // ------------ WIDGET -----------{
32 
33 class listbox;
34 class multi_page;
35 class text_box;
36 
37 namespace implementation
38 {
39 	struct builder_chatbox;
40 }
41 
42 struct lobby_chat_window
43 {
lobby_chat_windowgui2::lobby_chat_window44 	lobby_chat_window(const std::string& name, bool whisper)
45 		: name(name), whisper(whisper), pending_messages(0)
46 	{
47 	}
48 
49 	std::string name;
50 	bool whisper;
51 	int pending_messages;
52 };
53 
54 class chatbox : public container_base, public events::chat_handler
55 {
56 	friend struct implementation::builder_chatbox;
57 
58 public:
59 	explicit chatbox(const implementation::builder_chatbox& builder);
60 
61 	/** See @ref styled_widget::set_active. */
set_active(const bool)62 	virtual void set_active(const bool /*active*/) override
63 	{
64 		/* DO NOTHING */
65 	}
66 
67 	/** See @ref styled_widget::get_active. */
get_active() const68 	virtual bool get_active() const override
69 	{
70 		return true;
71 	}
72 
73 	/** See @ref styled_widget::get_state. */
get_state() const74 	virtual unsigned get_state() const override
75 	{
76 		return 0;
77 	}
78 
79 	void send_to_server(const ::config& cfg) override;
80 
81 	/** @todo: remove */
set_active_window_changed_callback(const std::function<void (void)> & f)82 	void set_active_window_changed_callback(const std::function<void(void)>& f)
83 	{
84 		active_window_changed_callback_ = f;
85 	}
86 
set_lobby_info(mp::lobby_info & i)87 	void set_lobby_info(mp::lobby_info& i)
88 	{
89 		lobby_info_ = &i;
90 	}
91 
set_wesnothd_connection(wesnothd_connection & c)92 	void set_wesnothd_connection(wesnothd_connection& c)
93 	{
94 		wesnothd_connection_ = &c;
95 	}
96 
97 	void load_log(std::map<std::string, chatroom_log>& log, bool show_lobby);
98 
99 protected:
100 	/**
101 	 * Initializes the internal sub-widget pointers.
102 	 * Should be called after initializing the widget's grid.
103 	 */
104 	void finalize_setup();
105 
106 	/** Inherited form @ref chat_handler */
107 	virtual void user_relation_changed(const std::string& name) override;
108 
109 	/** Inherited form @ref chat_handler */
110 	virtual void add_chat_message(const time_t& time,
111 		const std::string& speaker,
112 		int side,
113 		const std::string& message,
114 		events::chat_handler::MESSAGE_TYPE type
115 		= events::chat_handler::MESSAGE_PRIVATE) override;
116 
117 	/** Inherited form @ref chat_handler */
118 	virtual void add_whisper_sent(const std::string& receiver,
119 		const std::string& message) override;
120 
121 	/** Inherited form @ref chat_handler */
122 	virtual void add_whisper_received(const std::string& sender,
123 		const std::string& message) override;
124 
125 	/** Inherited form @ref chat_handler */
126 	virtual void add_chat_room_message_sent(const std::string& room,
127 		const std::string& message) override;
128 
129 	/** Inherited form @ref chat_handler */
130 	virtual void add_chat_room_message_received(const std::string& room,
131 		const std::string& speaker,
132 		const std::string& message) override;
133 
134 private:
135 	listbox* roomlistbox_;
136 
137 	multi_page* chat_log_container_;
138 
139 	text_box* chat_input_;
140 
141 	std::vector<lobby_chat_window> open_windows_;
142 
143 	size_t active_window_;
144 
145 	std::function<void(void)> active_window_changed_callback_;
146 
147 	mp::lobby_info* lobby_info_;
148 
149 	wesnothd_connection* wesnothd_connection_;
150 
151 	std::map<std::string, chatroom_log>* log_;
152 
153 public:
154 	/** Static type getter that does not rely on the widget being constructed. */
155 	static const std::string& type();
156 
157 private:
158 	/** Inherited from styled_widget, implemented by REGISTER_WIDGET. */
159 	virtual const std::string& get_control_type() const override;
160 
161 	/** See @ref container_base::set_self_active. */
set_self_active(const bool)162 	virtual void set_self_active(const bool /*active*/) override
163 	{
164 		/* DO NOTHING */
165 	}
166 
167 	void chat_input_keypress_callback(const SDL_Keycode key);
168 
169 	void append_to_chatbox(const std::string& text, const bool force_scroll = false);
170 
171 	void append_to_chatbox(const std::string& text, size_t id, const bool force_scroll = false);
172 
173 	/** @returns true if the whisper window for "name" is the active window. */
174 	bool whisper_window_active(const std::string& name);
175 
176 	/** @returns true if the room window for "room" is the active window. */
177 	bool room_window_active(const std::string& room);
178 
179 	/** Mark the whisper window for "name" as having one more pending message. */
180 	void increment_waiting_whispers(const std::string& name);
181 
182 	/** Mark the room window for "room" as having one more pending message. */
183 	void increment_waiting_messages(const std::string& room);
184 
185 	/** Add a whisper message to the whisper window. */
186 	void add_whisper_window_whisper(const std::string& sender,
187 		const std::string& message);
188 
189 	/**
190 	 * Add a whisper message to the current window which is not the whisper window for "name".
191 	 */
192 	void add_active_window_whisper(const std::string& sender,
193 		const std::string& message,
194 		const bool force_scroll = false);
195 
196 	/** Add a message to the window for room "room". */
197 	void add_room_window_message(const std::string& room,
198 		const std::string& sender,
199 		const std::string& message);
200 
201 	/** Add a message to the window for room "room". */
202 	void add_active_window_message(const std::string& sender,
203 		const std::string& message,
204 		const bool force_scroll = false);
205 
206 	void close_window(size_t idx);
207 
208 public:
209 	/** Inherited form @ref chat_handler */
210 	virtual void send_chat_message(const std::string& message, bool allies_only) override;
211 
212 	/**
213 	 * Switch to the window given by a valid pointer (e.g. received from a call
214 	 * to *_window_open)
215 	 */
216 	void switch_to_window(lobby_chat_window* t);
217 
218 	void switch_to_window(size_t id);
219 
220 	void active_window_changed();
221 
222 	/**
223 	 * Get the room* corresponding to the currently active window, or nullptr
224 	 * if a whisper window is active at the moment
225 	 */
226 	mp::room_info* active_window_room();
227 
228 	/**
229 	 * Check if a room window for "room" is open, if open_new is true
230 	 * then it will be created if not found. If allow_close is false, the
231 	 * 'close' button will be disabled.
232 	 * @return valid ptr if the window was found or added, null otherwise
233 	 */
234 	lobby_chat_window* room_window_open(const std::string& room,
235 		const bool open_new, const bool allow_close = true);
236 
237 	/**
238 	 * Check if a whisper window for user "name" is open, if open_new is true
239 	 * then it will be created if not found.
240 	 * @return valid ptr if the window was found or added, null otherwise
241 	 */
242 	lobby_chat_window* whisper_window_open(const std::string& name, bool open_new);
243 
244 	/**
245 	 * Helper function to find and open a new window, used by *_window_open
246 	 */
247 	lobby_chat_window* find_or_create_window(const std::string& name, const bool whisper, const bool open_new, const bool allow_close, const std::string& initial_text);
248 
249 	void close_window_button_callback(std::string room_name, bool& handled, bool& halt);
250 
251 	void process_room_join(const ::config& data);
252 
253 	void process_room_part(const ::config& data);
254 
255 	void process_room_query_response(const ::config& data);
256 
257 	void process_message(const ::config& data, bool whisper = false);
258 
259 	void process_network_data(const ::config& data);
260 
261 private:
262 	void signal_handler_receive_keyboard_focus(const event::ui_event event);
263 };
264 
265 // }---------- DEFINITION ---------{
266 
267 struct chatbox_definition : public styled_widget_definition
268 {
269 	explicit chatbox_definition(const config& cfg);
270 
271 	struct resolution : public resolution_definition
272 	{
273 		explicit resolution(const config& cfg);
274 
275 		builder_grid_ptr grid;
276 	};
277 };
278 
279 // }---------- BUILDER -----------{
280 
281 namespace implementation
282 {
283 
284 struct builder_chatbox : public builder_styled_widget
285 {
286 public:
287 	explicit builder_chatbox(const config& cfg);
288 
289 	using builder_styled_widget::build;
290 
291 	widget* build() const;
292 
293 private:
294 };
295 
296 } // namespace implementation
297 
298 // }------------ END --------------
299 
300 } // namespace gui2
301