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
EditorLayersWidget(Editor & editor)38 EditorLayersWidget::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_scroll(0),
45 m_scroll_speed(0),
46 m_sector_text(),
47 m_sector_text_width(0),
48 m_hovered_item(HoveredItem::NONE),
49 m_hovered_layer(-1),
50 m_object_tip(),
51 m_has_mouse_focus(false)
52 {
53 }
54
55 void
draw(DrawingContext & context)56 EditorLayersWidget::draw(DrawingContext& context)
57 {
58
59 if (m_object_tip) {
60 auto position = get_layer_coords(m_hovered_layer);
61 m_object_tip->draw_up(context, position);
62 }
63
64 context.color().draw_filled_rect(Rectf(Vector(0, static_cast<float>(m_Ypos)),
65 Vector(static_cast<float>(m_Width), static_cast<float>(SCREEN_HEIGHT))),
66 Color(0.9f, 0.9f, 1.0f, 0.6f),
67 0.0f,
68 LAYER_GUI-10);
69
70 Rectf target_rect = Rectf(0, 0, 0, 0);
71 bool draw_rect = true;
72
73 switch (m_hovered_item)
74 {
75 case HoveredItem::SPAWNPOINTS:
76 target_rect = Rectf(Vector(0, static_cast<float>(m_Ypos)),
77 Vector(static_cast<float>(m_Xpos), static_cast<float>(SCREEN_HEIGHT)));
78 break;
79
80 case HoveredItem::SECTOR:
81 target_rect = Rectf(Vector(static_cast<float>(m_Xpos), static_cast<float>(m_Ypos)),
82 Vector(static_cast<float>(m_sector_text_width + m_Xpos), static_cast<float>(SCREEN_HEIGHT)));
83 break;
84
85 case HoveredItem::LAYERS:
86 {
87 Vector coords = get_layer_coords(m_hovered_layer);
88 target_rect = Rectf(coords, coords + Vector(32, 32));
89 }
90 break;
91
92 default:
93 draw_rect = false;
94 break;
95 }
96
97 if (draw_rect)
98 {
99 context.color().draw_filled_rect(target_rect, Color(0.9f, 0.9f, 1.0f, 0.6f), 0.0f,
100 LAYER_GUI-5);
101 }
102
103 if (!m_editor.is_level_loaded()) {
104 return;
105 }
106
107 context.color().draw_text(Resources::normal_font, m_sector_text,
108 Vector(35.0f, static_cast<float>(m_Ypos) + 5.0f),
109 ALIGN_LEFT, LAYER_GUI, ColorScheme::Menu::default_color);
110
111 int pos = 0;
112 for (const auto& layer_icon : m_layer_icons) {
113 if (layer_icon->is_valid()) {
114 if (pos * 35 >= m_scroll) {
115 layer_icon->draw(context, get_layer_coords(pos));
116 } else if ((pos + 1) * 35 >= m_scroll) {
117 layer_icon->draw(context, get_layer_coords(pos), 35 - (m_scroll - pos * 35));
118 }
119 }
120 pos++;
121 }
122 }
123
124 void
update(float dt_sec)125 EditorLayersWidget::update(float dt_sec)
126 {
127 auto it = m_layer_icons.begin();
128 while (it != m_layer_icons.end())
129 {
130 auto layer_icon = (*it).get();
131 if (!layer_icon->is_valid())
132 it = m_layer_icons.erase(it);
133 else
134 ++it;
135 }
136
137 if(m_scroll_speed < 0 && m_scroll > 0)
138 {
139 m_scroll -= 5;
140 }
141 else if (m_scroll_speed > 0 && m_scroll < (static_cast<int>(m_layer_icons.size()) - 1) * 35)
142 {
143 m_scroll += 5;
144 }
145 }
146
147 bool
on_mouse_button_up(const SDL_MouseButtonEvent & button)148 EditorLayersWidget::on_mouse_button_up(const SDL_MouseButtonEvent& button)
149 {
150 return false;
151 }
152
153 bool
on_mouse_button_down(const SDL_MouseButtonEvent & button)154 EditorLayersWidget::on_mouse_button_down(const SDL_MouseButtonEvent& button)
155 {
156 if (button.button == SDL_BUTTON_LEFT)
157 {
158 switch (m_hovered_item)
159 {
160 case HoveredItem::SECTOR:
161 m_editor.disable_keyboard();
162 MenuManager::instance().set_menu(MenuStorage::EDITOR_SECTORS_MENU);
163 return true;
164
165 case HoveredItem::LAYERS:
166 if (m_hovered_layer >= m_layer_icons.size())
167 {
168 return false;
169 }
170 else
171 {
172 if (m_layer_icons[m_hovered_layer]->is_tilemap()) {
173 if (m_selected_tilemap) {
174 m_selected_tilemap->m_editor_active = false;
175 }
176 m_selected_tilemap = static_cast<TileMap*>(m_layer_icons[m_hovered_layer]->get_layer());
177 m_selected_tilemap->m_editor_active = true;
178 m_editor.edit_path(m_selected_tilemap->get_path_gameobject(), m_selected_tilemap);
179 } else {
180 auto cam = dynamic_cast<Camera*>(m_layer_icons[m_hovered_layer]->get_layer());
181 if (cam) {
182 m_editor.edit_path(cam->get_path_gameobject(), cam);
183 }
184 }
185 return true;
186 }
187
188 default:
189 return false;
190 }
191 }
192 else if (button.button == SDL_BUTTON_RIGHT)
193 {
194 if (m_hovered_item == HoveredItem::LAYERS && m_hovered_layer < m_layer_icons.size()) {
195 auto om = std::make_unique<ObjectMenu>(m_editor, m_layer_icons[m_hovered_layer]->get_layer());
196 m_editor.m_deactivate_request = true;
197 MenuManager::instance().push_menu(std::move(om));
198 return true;
199 } else {
200 return false;
201 }
202 }
203 else
204 {
205 return false;
206 }
207 }
208
209 bool
on_mouse_motion(const SDL_MouseMotionEvent & motion)210 EditorLayersWidget::on_mouse_motion(const SDL_MouseMotionEvent& motion)
211 {
212 Vector mouse_pos = VideoSystem::current()->get_viewport().to_logical(motion.x, motion.y);
213 float x = mouse_pos.x - static_cast<float>(m_Xpos);
214 float y = mouse_pos.y - static_cast<float>(m_Ypos);
215 if (y < 0 || x > static_cast<float>(m_Width)) {
216 m_hovered_item = HoveredItem::NONE;
217 m_object_tip = nullptr;
218 m_has_mouse_focus = false;
219 m_scroll_speed = 0;
220 return false;
221 }
222
223 m_has_mouse_focus = true;
224
225 if (x < 0) {
226 m_hovered_item = HoveredItem::SPAWNPOINTS;
227 m_object_tip = nullptr;
228 return true;
229 } else {
230 if (x <= static_cast<float>(m_sector_text_width)) {
231 m_hovered_item = HoveredItem::SECTOR;
232 m_object_tip = nullptr;
233 } else {
234 // Scrolling
235 if (x < static_cast<float>(m_sector_text_width + 32)) {
236 m_scroll_speed = -1;
237 } else if (x > static_cast<float>(SCREEN_WIDTH - 160)) { // 160 = 128 + 32
238 m_scroll_speed = 1;
239 } else {
240 m_scroll_speed = 0;
241 }
242 unsigned int new_hovered_layer = get_layer_pos(mouse_pos);
243 if (m_hovered_layer != new_hovered_layer || m_hovered_item != HoveredItem::LAYERS) {
244 m_hovered_layer = new_hovered_layer;
245 update_tip();
246 }
247 m_hovered_item = HoveredItem::LAYERS;
248 }
249 }
250
251 return true;
252 }
253
254
255 bool
on_mouse_wheel(const SDL_MouseWheelEvent & wheel)256 EditorLayersWidget::on_mouse_wheel(const SDL_MouseWheelEvent& wheel)
257 {
258 if (m_has_mouse_focus)
259 {
260 if((wheel.x < 0 || wheel.y < 0) && !(wheel.x > 0 || wheel.y > 0))
261 {
262 if (m_scroll >= 16)
263 {
264 m_scroll -= 16;
265 }
266 else
267 {
268 m_scroll = 0;
269 }
270 }
271 else if ((wheel.x > 0 || wheel.y > 0) && !(wheel.x < 0 || wheel.y < 0))
272 {
273 if (m_scroll < (static_cast<int>(m_layer_icons.size()) - 1) * 35)
274 {
275 m_scroll += 16;
276 }
277 else
278 {
279 m_scroll = (static_cast<int>(m_layer_icons.size()) - 1) * 35;
280 }
281
282 }
283 }
284 return false;
285 }
286
287 bool
has_mouse_focus() const288 EditorLayersWidget::has_mouse_focus() const
289 {
290 return m_has_mouse_focus;
291 }
292
293 void
resize()294 EditorLayersWidget::resize()
295 {
296 m_Ypos = SCREEN_HEIGHT - 32;
297 m_Width = SCREEN_WIDTH - 128;
298 }
299
300 void
setup()301 EditorLayersWidget::setup()
302 {
303 resize();
304 }
305
306 void
refresh()307 EditorLayersWidget::refresh()
308 {
309 m_selected_tilemap = nullptr;
310 m_layer_icons.clear();
311
312 bool tsel = false;
313 for (auto& i : m_editor.get_sector()->get_objects())
314 {
315 auto* go = i.get();
316 auto* mo = dynamic_cast<MovingObject*>(go);
317 if (!mo && go->has_settings()) {
318 if (!dynamic_cast<PathGameObject*>(go)) {
319 add_layer(go);
320 }
321
322 auto tm = dynamic_cast<TileMap*>(go);
323 if (tm) {
324 if ( !tm->is_solid() || tsel ) {
325 tm->m_editor_active = false;
326 } else {
327 m_selected_tilemap = tm;
328 tm->m_editor_active = true;
329 tsel = true;
330 }
331 }
332 }
333 }
334
335 sort_layers();
336 refresh_sector_text();
337 }
338
339 void
refresh_sector_text()340 EditorLayersWidget::refresh_sector_text()
341 {
342 m_sector_text = _("Sector") + ": " + m_editor.get_sector()->get_name();
343 m_sector_text_width = int(Resources::normal_font->get_text_width(m_sector_text)) + 6;
344 }
345
346 void
sort_layers()347 EditorLayersWidget::sort_layers()
348 {
349 std::sort(m_layer_icons.begin(), m_layer_icons.end(),
350 [](const std::unique_ptr<LayerIcon>& lhs, const std::unique_ptr<LayerIcon>& rhs) {
351 return lhs->get_zpos() < rhs->get_zpos();
352 });
353 }
354
355 void
add_layer(GameObject * layer)356 EditorLayersWidget::add_layer(GameObject* layer)
357 {
358 auto icon = std::make_unique<LayerIcon>(layer);
359 int z_pos = icon->get_zpos();
360
361 // The icon is inserted to the correct position.
362 for (auto i = m_layer_icons.begin(); i != m_layer_icons.end(); ++i) {
363 const auto& li = i->get();
364 if (li->get_zpos() < z_pos) {
365 m_layer_icons.insert(i, move(icon));
366 return;
367 }
368 }
369
370 m_layer_icons.push_back(move(icon));
371 }
372
373 void
update_tip()374 EditorLayersWidget::update_tip()
375 {
376 if ( m_hovered_layer >= m_layer_icons.size() ) {
377 m_object_tip = nullptr;
378 return;
379 }
380 m_object_tip = std::make_unique<Tip>(*m_layer_icons[m_hovered_layer]->get_layer());
381 }
382
383 Vector
get_layer_coords(const int pos) const384 EditorLayersWidget::get_layer_coords(const int pos) const
385 {
386 return Vector(static_cast<float>(pos * 35 + m_Xpos + m_sector_text_width - m_scroll),
387 static_cast<float>(m_Ypos));
388 }
389
390 int
get_layer_pos(const Vector & coords) const391 EditorLayersWidget::get_layer_pos(const Vector& coords) const
392 {
393 return static_cast<int>((coords.x - static_cast<float>(m_Xpos - m_scroll) - static_cast<float>(m_sector_text_width)) / 35.0f);
394 }
395
396 /* EOF */
397