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 | |
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_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 | |
52 | void |
53 | EditorLayersWidget::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 | |
117 | void |
118 | EditorLayersWidget::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 | |
131 | bool |
132 | EditorLayersWidget::on_mouse_button_up(const SDL_MouseButtonEvent& button) |
133 | { |
134 | return false; |
135 | } |
136 | |
137 | bool |
138 | EditorLayersWidget::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 | |
194 | bool |
195 | EditorLayersWidget::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 | |
226 | void |
227 | EditorLayersWidget::resize() |
228 | { |
229 | m_Ypos = SCREEN_HEIGHT - 32; |
230 | m_Width = SCREEN_WIDTH - 128; |
231 | } |
232 | |
233 | void |
234 | EditorLayersWidget::setup() |
235 | { |
236 | resize(); |
237 | } |
238 | |
239 | void |
240 | EditorLayersWidget::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 | |
272 | void |
273 | EditorLayersWidget::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 | |
279 | void |
280 | EditorLayersWidget::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 | |
288 | void |
289 | EditorLayersWidget::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 | |
306 | void |
307 | EditorLayersWidget::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 | |
316 | Vector |
317 | EditorLayersWidget::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 | |
323 | int |
324 | EditorLayersWidget::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 | |