1 /*
2  * Copyright (C) 2002-2020 by the Widelands Development Team
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  *
18  */
19 
20 #ifndef WL_WUI_INTERACTIVE_BASE_H
21 #define WL_WUI_INTERACTIVE_BASE_H
22 
23 #include <memory>
24 
25 #include "graphic/toolbar_imageset.h"
26 #include "io/profile.h"
27 #include "logic/editor_game_base.h"
28 #include "logic/map.h"
29 #include "logic/path.h"
30 #include "sound/note_sound.h"
31 #include "ui_basic/box.h"
32 #include "ui_basic/dropdown.h"
33 #include "ui_basic/unique_window.h"
34 #include "wui/chat_overlay.h"
35 #include "wui/debugconsole.h"
36 #include "wui/mapview.h"
37 #include "wui/minimap.h"
38 #include "wui/quicknavigation.h"
39 
40 class UniqueWindowHandler;
41 
42 struct WorkareaPreview {
43 	Widelands::Coords coords;
44 	const WorkareaInfo* info;
45 	std::map<Widelands::TCoords<>, uint32_t> data;
46 };
47 
48 enum class RoadBuildingType { kRoad, kWaterway };
49 
50 /**
51  * This is used to represent the code that InteractivePlayer and
52  * EditorInteractive share.
53  */
54 class InteractiveBase : public UI::Panel, public DebugConsole::Handler {
55 public:
56 	enum {
57 		dfShowCensus = 1,         ///< show census report on buildings
58 		dfShowStatistics = 2,     ///< show statistics report on buildings
59 		dfShowSoldierLevels = 4,  ///< show level information above soldiers
60 		dfShowWorkareaOverlap =
61 		   8,         ///< highlight overlapping workareas when placing a constructionsite
62 		dfDebug = 16  ///< general debugging info
63 	};
64 
65 	/// A build help overlay, i.e. small, big, mine, port ...
66 	struct BuildhelpOverlay {
67 		const Image* pic = nullptr;
68 		Vector2i hotspot = Vector2i::zero();
69 	};
70 
71 	// Manages all UniqueWindows.
72 	UniqueWindowHandler& unique_windows();
73 
74 	InteractiveBase(Widelands::EditorGameBase&, Section& global_s);
75 	~InteractiveBase() override;
76 
egbase()77 	Widelands::EditorGameBase& egbase() const {
78 		return egbase_;
79 	}
80 
81 	void show_workarea(const WorkareaInfo& workarea_info, Widelands::Coords coords);
82 	void show_workarea(const WorkareaInfo& workarea_info,
83 	                   Widelands::Coords coords,
84 	                   std::map<Widelands::TCoords<>, uint32_t>& extra_data);
85 	void hide_workarea(const Widelands::Coords& coords, bool is_additional);
86 
87 	bool has_expedition_port_space(const Widelands::Coords&) const;
get_expedition_port_spaces()88 	std::map<Widelands::Ship*, Widelands::Coords>& get_expedition_port_spaces() {
89 		return expedition_port_spaces_;
90 	}
91 
92 	//  point of view for drawing
93 	virtual Widelands::Player* get_player() const = 0;
94 
95 	void think() override;
96 	double average_fps() const;
97 	bool handle_key(bool down, SDL_Keysym code) override;
98 	virtual void postload();
99 
get_sel_pos()100 	const Widelands::NodeAndTriangle<>& get_sel_pos() const {
101 		return sel_.pos;
102 	}
103 
104 	// Returns true if the buildhelp is currently displayed.
105 	bool buildhelp() const;
106 
107 	// Sets if the buildhelp should be displayed and then calls rebuild_showhide_menu
108 	void show_buildhelp(bool t);
109 
110 	/**
111 	 * sel_triangles determines whether the mouse pointer selects triangles.
112 	 * (False meas that it selects nodes.)
113 	 */
get_sel_triangles()114 	bool get_sel_triangles() const {
115 		return sel_.triangles;
116 	}
set_sel_triangles(const bool yes)117 	void set_sel_triangles(const bool yes) {
118 		sel_.triangles = yes;
119 	}
120 
get_sel_radius()121 	uint32_t get_sel_radius() const {
122 		return sel_.radius;
123 	}
124 	virtual void set_sel_pos(Widelands::NodeAndTriangle<>);
set_sel_freeze(const bool yes)125 	void set_sel_freeze(const bool yes) {
126 		sel_.freeze = yes;
127 	}
128 	void set_sel_radius(uint32_t);
129 
130 	//  display flags
131 	uint32_t get_display_flags() const;
132 	void set_display_flags(uint32_t flags);
133 	bool get_display_flag(uint32_t flag);
134 	void set_display_flag(uint32_t flag, bool on);
135 
136 	//  road building
in_road_building_mode()137 	bool in_road_building_mode() const {
138 		return road_building_mode_ != nullptr;
139 	}
in_road_building_mode(RoadBuildingType t)140 	bool in_road_building_mode(RoadBuildingType t) const {
141 		return road_building_mode_ && (road_building_mode_->type == t);
142 	}
143 	void start_build_road(Widelands::Coords start, Widelands::PlayerNumber player, RoadBuildingType);
144 	void abort_build_road();
145 	void finish_build_road();
146 	bool append_build_road(Widelands::Coords field);
147 	Widelands::Coords get_build_road_start() const;
148 	Widelands::Coords get_build_road_end() const;
149 	Widelands::CoordPath get_build_road_path() const;
150 
cleanup_for_load()151 	virtual void cleanup_for_load() {
152 	}
153 
154 	/**
155 	 * Log a message to be displayed on screen
156 	 */
157 	void log_message(const std::string& message) const;
log_message(const char * message)158 	void log_message(const char* message) const {
159 		log_message(std::string(message));
160 	}
161 
162 	void toggle_minimap();
163 	// Toggles the buildhelp and calls rebuild_showhide_menu
164 	void toggle_buildhelp();
165 
166 	// Returns the list of landmarks that have been mapped to the keys 0-9
167 	const QuickNavigation::Landmark* landmarks();
168 
169 	// Sets the landmark for the keyboard 'key' to 'point'
170 	void set_landmark(size_t key, const MapView::View& view);
171 
map_view()172 	MapView* map_view() {
173 		return &map_view_;
174 	}
175 
176 protected:
177 	// For referencing the items in mapviewmenu_
178 	enum class MapviewMenuEntry { kMinimap, kIncreaseZoom, kDecreaseZoom, kResetZoom };
179 
180 	// Adds the mapviewmenu_ to the toolbar
181 	void add_mapview_menu(MiniMapType minimap_type);
182 	// Rebuilds the mapviewmenu_ according to current view settings
183 	void rebuild_mapview_menu();
184 	// Takes the appropriate action when an item in the mapviewmenu_ is selected
185 	void mapview_menu_selected(MapviewMenuEntry entry);
186 
187 	/// Adds a toolbar button to the toolbar
188 	/// \param image_basename:      File path for button image starting from 'images' and without
189 	///                             file extension
190 	/// \param name:                Internal name of the button
191 	/// \param tooltip:             The button tooltip
192 	/// \param window:              The window that's associated with this button.
193 	/// \param bind_default_toggle: If true, the button will toggle with its 'window'.
194 	UI::Button* add_toolbar_button(const std::string& image_basename,
195 	                               const std::string& name,
196 	                               const std::string& tooltip_text,
197 	                               UI::UniqueWindow::Registry* window = nullptr,
198 	                               bool bind_default_toggle = false);
199 
200 	void hide_minimap();
201 
202 	void mainview_move();
203 
204 	void draw_overlay(RenderTarget&) override;
205 	/**
206 	 * Will blit the 'image' on the given 'pos', offset by 'hotspot' and scaled according to the
207 	 * given zoom 'scale'.
208 	 * */
209 	void blit_overlay(RenderTarget* dst,
210 	                  const Vector2i& pos,
211 	                  const Image* image,
212 	                  const Vector2i& hotspot,
213 	                  float scale);
214 	/**
215 	 * Will blit the 'image' on the given 'field', offset by 'hotspot' and scaled according to the
216 	 * given zoom 'scale'.
217 	 * */
218 	void blit_field_overlay(RenderTarget* dst,
219 	                        const FieldsToDraw::Field& field,
220 	                        const Image* image,
221 	                        const Vector2i& hotspot,
222 	                        float scale);
223 
224 	void draw_bridges(RenderTarget* dst,
225 	                  const FieldsToDraw::Field* f,
226 	                  uint32_t gametime,
227 	                  float scale) const;
228 	void draw_road_building(FieldsToDraw::Field&);
229 
230 	void unset_sel_picture();
231 	void set_sel_picture(const Image* image);
get_sel_picture()232 	const Image* get_sel_picture() {
233 		return sel_.pic;
234 	}
235 
236 	// Sets the toolbar's position to the bottom middle and configures its background images
237 	void finalize_toolbar();
238 
chat_overlay()239 	ChatOverlay* chat_overlay() {
240 		return chat_overlay_;
241 	}
242 
toolbar()243 	UI::Box* toolbar() {
244 		return &toolbar_.box;
245 	}
246 
247 	// Returns the information which overlay text should currently be drawn.
248 	// Returns InfoToDraw::kNone if not 'show'
249 	InfoToDraw get_info_to_draw(bool show) const;
250 
251 	// Returns the current overlays for the work area previews.
252 	Workareas get_workarea_overlays(const Widelands::Map& map);
253 	static WorkareasEntry get_workarea_overlay(const Widelands::Map&, const WorkareaPreview&);
254 
255 	// Returns the 'BuildhelpOverlay' for 'caps' or nullptr if there is no help
256 	// to be displayed on this field.
257 	const BuildhelpOverlay* get_buildhelp_overlay(Widelands::NodeCaps caps) const;
258 
259 	// Overlays displayed while a road or waterway is under construction.
260 	struct RoadBuildingMode {
RoadBuildingModeRoadBuildingMode261 		RoadBuildingMode(Widelands::PlayerNumber p, Widelands::Coords s, RoadBuildingType t)
262 		   : player(p), path(s), type(t), work_area(nullptr) {
263 		}
264 		const Widelands::PlayerNumber player;
265 		Widelands::CoordPath path;
266 		const RoadBuildingType type;
267 		std::unique_ptr<WorkareaInfo> work_area;
268 		std::map<Widelands::Coords, std::vector<uint8_t>> overlay_road_previews;
269 		std::map<Widelands::Coords, const Image*> overlay_steepness_indicators;
270 	};
271 	std::map<Widelands::Coords, std::vector<uint8_t>> road_building_preview_overlays() const;
272 	std::map<Widelands::Coords, const Image*> road_building_steepness_overlays() const;
273 
274 	/// Returns true if there is a workarea preview being shown at the given coordinates.
275 	/// If 'map' is 0, checks only if the given coords are the center of a workarea;
276 	/// otherwise checks if the coords are within any workarea.
277 	bool has_workarea_preview(const Widelands::Coords& coords,
278 	                          const Widelands::Map* map = nullptr) const;
279 
280 	/// Returns true if the current player is allowed to hear sounds from map objects on this field
281 	virtual bool player_hears_field(const Widelands::Coords& coords) const = 0;
282 
283 	void set_toolbar_imageset(const ToolbarImageset& imageset);
284 
285 #ifndef NDEBUG  //  only in debug builds
286 	UI::UniqueWindow::Registry debugconsole_;
287 #endif
288 
289 private:
290 	void play_sound_effect(const NoteSound& note) const;
291 	void resize_chat_overlay();
292 	void road_building_add_overlay();
293 	void road_building_remove_overlay();
294 	void cmd_map_object(const std::vector<std::string>& args);
295 	void cmd_lua(const std::vector<std::string>& args);
296 
297 	// Rebuilds the subclass' showhidemenu_ according to current map settings
298 	virtual void rebuild_showhide_menu() = 0;
299 
300 	struct SelData {
301 		SelData(const bool Freeze = false,
302 		        const bool Triangles = false,
303 		        const Widelands::NodeAndTriangle<>& Pos =
304 		           Widelands::NodeAndTriangle<>{
305 		              Widelands::Coords(0, 0),
306 		              Widelands::TCoords<>(Widelands::Coords(0, 0), Widelands::TriangleIndex::D)},
307 		        const uint32_t Radius = 0,
308 		        const Image* Pic = nullptr)
freezeSelData309 		   : freeze(Freeze), triangles(Triangles), pos(Pos), radius(Radius), pic(Pic) {
310 		}
311 		bool freeze;     // don't change sel, even if mouse moves
312 		bool triangles;  //  otherwise nodes
313 		Widelands::NodeAndTriangle<> pos;
314 		uint32_t radius;
315 		const Image* pic;
316 	} sel_;
317 
318 	bool buildhelp_;
319 	MapView map_view_;
320 	ChatOverlay* chat_overlay_;
321 
322 	/// A horizontal menu bar embellished with background graphics
323 	struct Toolbar : UI::Panel {
324 		Toolbar(UI::Panel* parent);
325 
326 		/// Sets the actual size and position of the toolbar
327 		void finalize();
328 		void draw(RenderTarget& dst) override;
329 		void change_imageset(const ToolbarImageset& images);
330 
331 		/// A row of buttons and dropdown menus
332 		UI::Box box;
333 
334 	private:
335 		/// The set of background images
336 		ToolbarImageset imageset;
337 		/// How often the left and right images get repeated, calculated from the width of the box
338 		int repeat;
339 	} toolbar_;
340 
341 	// Map View menu on the toolbar
342 	UI::Dropdown<MapviewMenuEntry> mapviewmenu_;
343 	// No unique_ptr on purpose: 'minimap_' is a UniqueWindow, its parent will
344 	// delete it.
345 	MiniMap* minimap_;
346 	MiniMap::Registry minimap_registry_;
347 	QuickNavigation quick_navigation_;
348 
349 	// The currently enabled work area previews
350 	std::unordered_set<std::unique_ptr<WorkareaPreview>> workarea_previews_;
351 	std::unique_ptr<Workareas> workareas_cache_;
352 
353 	std::map<Widelands::Ship*, Widelands::Coords> expedition_port_spaces_;
354 
355 	std::unique_ptr<Notifications::Subscriber<GraphicResolutionChanged>>
356 	   graphic_resolution_changed_subscriber_;
357 	std::unique_ptr<Notifications::Subscriber<NoteSound>> sound_subscriber_;
358 	std::unique_ptr<Notifications::Subscriber<Widelands::NoteShip>> shipnotes_subscriber_;
359 	Widelands::EditorGameBase& egbase_;
360 	uint32_t display_flags_;
361 	uint32_t lastframe_;        //  system time (milliseconds)
362 	uint32_t frametime_;        //  in millseconds
363 	uint32_t avg_usframetime_;  //  in microseconds!
364 
365 	std::unique_ptr<RoadBuildingMode> road_building_mode_;
366 
367 	std::unique_ptr<UniqueWindowHandler> unique_window_handler_;
368 	BuildhelpOverlay buildhelp_overlays_[Widelands::Field::Buildhelp_None];
369 };
370 
371 #endif  // end of include guard: WL_WUI_INTERACTIVE_BASE_H
372