1// SuperTux
2// Copyright (C) 2015 Hume2 <teratux.mail@gmail.com>
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 3 of the License, or
7// (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, see <http://www.gnu.org/licenses/>.
16
17#include "editor/layers_widget.hpp"
18
19#include "editor/editor.hpp"
20#include "editor/layer_icon.hpp"
21#include "editor/object_menu.hpp"
22#include "editor/tip.hpp"
23#include "gui/menu_manager.hpp"
24#include "math/vector.hpp"
25#include "object/camera.hpp"
26#include "object/path_gameobject.hpp"
27#include "object/tilemap.hpp"
28#include "supertux/colorscheme.hpp"
29#include "supertux/menu/menu_storage.hpp"
30#include "supertux/moving_object.hpp"
31#include "supertux/resources.hpp"
32#include "supertux/sector.hpp"
33#include "video/drawing_context.hpp"
34#include "video/renderer.hpp"
35#include "video/video_system.hpp"
36#include "video/viewport.hpp"
37
38EditorLayersWidget::EditorLayersWidget(Editor& editor) :
39 m_editor(editor),
40 m_layer_icons(),
41 m_selected_tilemap(),
42 m_Ypos(448),
43 m_Width(512),
44 m_sector_text(),
45 m_sector_text_width(0),
46 m_hovered_item(HoveredItem::NONE),
47 m_hovered_layer(-1),
48 m_object_tip()
49{
50}
51
52void
53EditorLayersWidget::draw(DrawingContext& context)
54{
55
56 if (m_object_tip) {
57 auto position = get_layer_coords(m_hovered_layer);
58 m_object_tip->draw_up(context, position);
59 }
60
61 context.color().draw_filled_rect(Rectf(Vector(0, static_cast<float>(m_Ypos)),
62 Vector(static_cast<float>(m_Width), static_cast<float>(SCREEN_HEIGHT))),
63 Color(0.9f, 0.9f, 1.0f, 0.6f),
64 0.0f,
65 LAYER_GUI-10);
66
67 Rectf target_rect = Rectf(0, 0, 0, 0);
68 bool draw_rect = true;
69
70 switch (m_hovered_item)
71 {
72 case HoveredItem::SPAWNPOINTS:
73 target_rect = Rectf(Vector(0, static_cast<float>(m_Ypos)),
74 Vector(static_cast<float>(m_Xpos), static_cast<float>(SCREEN_HEIGHT)));
75 break;
76
77 case HoveredItem::SECTOR:
78 target_rect = Rectf(Vector(static_cast<float>(m_Xpos), static_cast<float>(m_Ypos)),
79 Vector(static_cast<float>(m_sector_text_width + m_Xpos), static_cast<float>(SCREEN_HEIGHT)));
80 break;
81
82 case HoveredItem::LAYERS:
83 {
84 Vector coords = get_layer_coords(m_hovered_layer);
85 target_rect = Rectf(coords, coords + Vector(32, 32));
86 }
87 break;
88
89 default:
90 draw_rect = false;
91 break;
92 }
93
94 if (draw_rect)
95 {
96 context.color().draw_filled_rect(target_rect, Color(0.9f, 0.9f, 1.0f, 0.6f), 0.0f,
97 LAYER_GUI-5);
98 }
99
100 if (!m_editor.is_level_loaded()) {
101 return;
102 }
103
104 context.color().draw_text(Resources::normal_font, m_sector_text,
105 Vector(35.0f, static_cast<float>(m_Ypos) + 5.0f),
106 ALIGN_LEFT, LAYER_GUI, ColorScheme::Menu::default_color);
107
108 int pos = 0;
109 for (const auto& layer_icon : m_layer_icons) {
110 if (layer_icon->is_valid()) {
111 layer_icon->draw(context, get_layer_coords(pos));
112 }
113 pos++;
114 }
115}
116
117void
118EditorLayersWidget::update(float dt_sec)
119{
120 auto it = m_layer_icons.begin();
121 while (it != m_layer_icons.end())
122 {
123 auto layer_icon = (*it).get();
124 if (!layer_icon->is_valid())
125 it = m_layer_icons.erase(it);
126 else
127 ++it;
128 }
129}
130
131bool
132EditorLayersWidget::on_mouse_button_up(const SDL_MouseButtonEvent& button)
133{
134 return false;
135}
136
137bool
138EditorLayersWidget::on_mouse_button_down(const SDL_MouseButtonEvent& button)
139{
140 if (button.button == SDL_BUTTON_LEFT)
141 {
142 switch (m_hovered_item)
143 {
144 case HoveredItem::SECTOR:
145 m_editor.disable_keyboard();
146 MenuManager::instance().set_menu(MenuStorage::EDITOR_SECTORS_MENU);
147 return true;
148
149 case HoveredItem::LAYERS:
150 if (m_hovered_layer >= m_layer_icons.size())
151 {
152 return false;
153 }
154 else
155 {
156 if (m_layer_icons[m_hovered_layer]->is_tilemap()) {
157 if (m_selected_tilemap) {
158 (static_cast<TileMap*>(m_selected_tilemap))->m_editor_active = false;
159 }
160 m_selected_tilemap = m_layer_icons[m_hovered_layer]->get_layer();
161 (static_cast<TileMap*>(m_selected_tilemap))->m_editor_active = true;
162 m_editor.edit_path((static_cast<TileMap*>(m_selected_tilemap))->get_path(),
163 m_selected_tilemap);
164 } else {
165 auto cam = dynamic_cast<Camera*>(m_layer_icons[m_hovered_layer]->get_layer());
166 if (cam) {
167 m_editor.edit_path(cam->get_path(), cam);
168 }
169 }
170 return true;
171 }
172
173 default:
174 return false;
175 }
176 }
177 else if (button.button == SDL_BUTTON_RIGHT)
178 {
179 if (m_hovered_item == HoveredItem::LAYERS && m_hovered_layer < m_layer_icons.size()) {
180 auto om = std::make_unique<ObjectMenu>(m_editor, m_layer_icons[m_hovered_layer]->get_layer());
181 m_editor.m_deactivate_request = true;
182 MenuManager::instance().push_menu(std::move(om));
183 return true;
184 } else {
185 return false;
186 }
187 }
188 else
189 {
190 return false;
191 }
192}
193
194bool
195EditorLayersWidget::on_mouse_motion(const SDL_MouseMotionEvent& motion)
196{
197 Vector mouse_pos = VideoSystem::current()->get_viewport().to_logical(motion.x, motion.y);
198 float x = mouse_pos.x - static_cast<float>(m_Xpos);
199 float y = mouse_pos.y - static_cast<float>(m_Ypos);
200 if (y < 0 || x > static_cast<float>(m_Width)) {
201 m_hovered_item = HoveredItem::NONE;
202 m_object_tip = nullptr;
203 return false;
204 }
205 if (x < 0) {
206 m_hovered_item = HoveredItem::SPAWNPOINTS;
207 m_object_tip = nullptr;
208 return true;
209 } else {
210 if (x <= static_cast<float>(m_sector_text_width)) {
211 m_hovered_item = HoveredItem::SECTOR;
212 m_object_tip = nullptr;
213 } else {
214 unsigned int new_hovered_layer = get_layer_pos(mouse_pos);
215 if (m_hovered_layer != new_hovered_layer || m_hovered_item != HoveredItem::LAYERS) {
216 m_hovered_layer = new_hovered_layer;
217 update_tip();
218 }
219 m_hovered_item = HoveredItem::LAYERS;
220 }
221 }
222
223 return true;
224}
225
226void
227EditorLayersWidget::resize()
228{
229 m_Ypos = SCREEN_HEIGHT - 32;
230 m_Width = SCREEN_WIDTH - 128;
231}
232
233void
234EditorLayersWidget::setup()
235{
236 resize();
237}
238
239void
240EditorLayersWidget::refresh()
241{
242 m_selected_tilemap = nullptr;
243 m_layer_icons.clear();
244
245 bool tsel = false;
246 for (auto& i : m_editor.get_sector()->get_objects())
247 {
248 auto* go = i.get();
249 auto* mo = dynamic_cast<MovingObject*>(go);
250 if (!mo && go->has_settings()) {
251 if (!dynamic_cast<PathGameObject*>(go)) {
252 add_layer(go);
253 }
254
255 auto tm = dynamic_cast<TileMap*>(go);
256 if (tm) {
257 if ( !tm->is_solid() || tsel ) {
258 tm->m_editor_active = false;
259 } else {
260 m_selected_tilemap = tm;
261 tm->m_editor_active = true;
262 tsel = true;
263 }
264 }
265 }
266 }
267
268 sort_layers();
269 refresh_sector_text();
270}
271
272void
273EditorLayersWidget::refresh_sector_text()
274{
275 m_sector_text = _("Sector") + ": " + m_editor.get_sector()->get_name();
276 m_sector_text_width = int(Resources::normal_font->get_text_width(m_sector_text)) + 6;
277}
278
279void
280EditorLayersWidget::sort_layers()
281{
282 std::sort(m_layer_icons.begin(), m_layer_icons.end(),
283 [](const std::unique_ptr<LayerIcon>& lhs, const std::unique_ptr<LayerIcon>& rhs) {
284 return lhs->get_zpos() < rhs->get_zpos();
285 });
286}
287
288void
289EditorLayersWidget::add_layer(GameObject* layer)
290{
291 auto icon = std::make_unique<LayerIcon>(layer);
292 int z_pos = icon->get_zpos();
293
294 // The icon is inserted to the correct position.
295 for (auto i = m_layer_icons.begin(); i != m_layer_icons.end(); ++i) {
296 const auto& li = i->get();
297 if (li->get_zpos() < z_pos) {
298 m_layer_icons.insert(i, move(icon));
299 return;
300 }
301 }
302
303 m_layer_icons.push_back(move(icon));
304}
305
306void
307EditorLayersWidget::update_tip()
308{
309 if ( m_hovered_layer >= m_layer_icons.size() ) {
310 m_object_tip = nullptr;
311 return;
312 }
313 m_object_tip = std::make_unique<Tip>(*m_layer_icons[m_hovered_layer]->get_layer());
314}
315
316Vector
317EditorLayersWidget::get_layer_coords(const int pos) const
318{
319 return Vector(static_cast<float>(pos * 35 + m_Xpos + m_sector_text_width),
320 static_cast<float>(m_Ypos));
321}
322
323int
324EditorLayersWidget::get_layer_pos(const Vector& coords) const
325{
326 return static_cast<int>((coords.x - static_cast<float>(m_Xpos) - static_cast<float>(m_sector_text_width)) / 35.0f);
327}
328
329/* EOF */
330