66#include <game/camera.h>
77#include <game_manager.h>
88#include <io/log.h>
9+ #include <io/filesystem.h>
910#include <misc/memory_usage.h>
1011#include <misc/wchar_funcs.h>
1112#include <render/font_manager.h>
1415#include <widget/widget.h>
1516#include <window.h>
1617#include <world.h>
18+ #include <ui/file_dialog.h>
1719#include <ui/editor_ui.h>
1820#include <ui/world_inspector.h>
21+ #include <ui/file_dialog.h>
1922
2023struct te_editor {
24+ // Not NULL if @ref game_world was loaded from a file (relative to the `res` directory).
25+ char * game_world_relative_path ;
26+
2127 // NULL if the game is not started yet.
2228 te_game_manager * game_manager ;
2329
@@ -33,6 +39,12 @@ struct te_editor {
3339 // Not NULL if exists.
3440 te_world * editor_world ;
3541
42+ // Not NULL if world for dialog widgets exists.
43+ te_world * dialog_world ;
44+
45+ // Not NULL if showing a file dialog.
46+ te_file_dialog * file_dialog ;
47+
3648 // Always valid.
3749 te_editor_ui * ui ;
3850
@@ -48,6 +60,9 @@ editor_create() {
4860 editor -> ui = editor_ui_create (editor );
4961 editor -> game_world_stats_widget = NULL ;
5062 editor -> game_world = NULL ;
63+ editor -> dialog_world = NULL ;
64+ editor -> file_dialog = NULL ;
65+ editor -> game_world_relative_path = NULL ;
5166 editor -> editor_world = NULL ;
5267 editor -> time_since_stats_update_sec = 10.0f ;
5368
@@ -59,9 +74,48 @@ editor_destroy(te_editor* editor) {
5974 editor_camera_destroy (editor -> editor_camera );
6075 editor_ui_destroy (editor -> ui );
6176
77+ free (editor -> game_world_relative_path );
78+
6279 free (editor );
6380}
6481
82+ static void
83+ destroy_game_world (te_editor * editor , te_game_manager * game_manager ) {
84+ if (editor -> file_dialog != NULL ) {
85+ file_dialog_destroy (editor -> file_dialog );
86+ editor -> file_dialog = NULL ;
87+
88+ game_manager_destroy_world (editor -> game_manager , editor -> dialog_world );
89+ editor -> dialog_world = NULL ;
90+ }
91+
92+ // Despawn editor camera because we manage its destruction manually.
93+ editor_camera_despawn (editor -> editor_camera , editor -> game_world );
94+
95+ // Destroy world.
96+ game_manager_destroy_world (game_manager , editor -> game_world );
97+ editor -> game_world = NULL ;
98+ editor -> game_world_stats_widget = NULL ;
99+ }
100+
101+ void
102+ editor_on_window_close (void * game_instance , struct te_game_manager * game_manager ) {
103+ te_editor * editor = game_instance ;
104+
105+ if (editor -> game_world != NULL ) {
106+ destroy_game_world (editor , game_manager );
107+ editor -> game_world = NULL ;
108+ }
109+
110+ if (editor -> file_dialog != NULL ) {
111+ file_dialog_destroy (editor -> file_dialog );
112+ editor -> file_dialog = NULL ;
113+
114+ game_manager_destroy_world (editor -> game_manager , editor -> dialog_world );
115+ editor -> dialog_world = NULL ;
116+ }
117+ }
118+
65119static void
66120editor_create_editor_world (te_editor * editor , struct te_game_manager * game_manager ) {
67121 editor -> editor_world = game_manager_create_world (game_manager , "editor world" );
@@ -89,28 +143,15 @@ editor_on_game_started(void* game_instance, te_game_manager* game_manager) {
89143 editor_create_game_world (editor , NULL );
90144}
91145
92- static void
93- prv_editor_destroy_game_world (te_editor * editor , te_game_manager * game_manager ) {
94- // Despawn editor camera because we manage its destruction manually.
95- editor_camera_despawn (editor -> editor_camera , editor -> game_world );
96-
97- // Destroy world.
98- game_manager_destroy_world (game_manager , editor -> game_world );
99- editor -> game_world = NULL ;
100- editor -> game_world_stats_widget = NULL ;
101- }
102-
103146void
104147editor_create_game_world (te_editor * editor , const char * relative_path_to_world ) {
105148 // Cleanup.
106149 editor_ui_reset (editor -> ui );
107150 if (editor -> game_world != NULL ) {
108- prv_editor_destroy_game_world (editor , editor -> game_manager );
151+ destroy_game_world (editor , editor -> game_manager );
109152 }
110153
111154 editor -> game_world = game_manager_create_world (editor -> game_manager , "game" );
112- editor_camera_spawn (editor -> editor_camera , editor -> game_world );
113-
114155 if (relative_path_to_world == NULL ) {
115156 // Prepare a sample scene.
116157 te_model * floor = model_create ();
@@ -127,6 +168,8 @@ editor_create_game_world(te_editor* editor, const char* relative_path_to_world)
127168 world_add_from_file (editor -> game_world , relative_path_to_world );
128169 }
129170
171+ editor_camera_spawn (editor -> editor_camera , editor -> game_world );
172+
130173 // Prepare stats widget.
131174 editor -> game_world_stats_widget = text_widget_create ();
132175 widget_set_relative_position (
@@ -199,14 +242,68 @@ editor_on_game_tick(void* game_instance, te_game_manager* game_manager, float de
199242 }
200243}
201244
245+ static void
246+ on_new_world_file_selected (void * custom , const char * path_to_file ) {
247+ te_editor * editor = custom ;
248+
249+ file_dialog_destroy (editor -> file_dialog );
250+ editor -> file_dialog = NULL ;
251+
252+ game_manager_destroy_world (editor -> game_manager , editor -> dialog_world );
253+ editor -> dialog_world = NULL ;
254+
255+ if (editor -> game_world == NULL ) {
256+ return ;
257+ }
258+
259+ char * relative_path = filesystem_convert_path_to_relative (path_to_file );
260+ if (relative_path == NULL ) {
261+ log_warn ("new world must be in the \"res\" directory" );
262+ return ;
263+ }
264+
265+ world_save_to_file (editor -> game_world , relative_path );
266+
267+ free (relative_path );
268+
269+ editor_ui_refresh_filesystem_view (editor -> ui );
270+ }
271+
272+ static void
273+ on_new_world_file_cancel (void * custom ) {
274+ te_editor * editor = custom ;
275+
276+ file_dialog_destroy (editor -> file_dialog );
277+ editor -> file_dialog = NULL ;
278+
279+ game_manager_destroy_world (editor -> game_manager , editor -> dialog_world );
280+ editor -> dialog_world = NULL ;
281+ }
282+
202283void
203284editor_on_keyboard_button_pressed (
204285 void * game_instance , struct te_game_manager * game_manager , enum te_keyboard_button button ,
205286 te_keyboard_modifiers modifiers ) {
206- (void )game_manager ;
207- (void )modifiers ;
208-
209287 te_editor * editor = game_instance ;
288+
289+ if (editor -> game_world != NULL && keyboard_modifiers_is_ctrl_pressed (& modifiers )
290+ && button == TE_KB_S ) {
291+ if (editor -> game_world_relative_path == NULL ) {
292+ // Create a new world for dialog widget to be displayed on top of both the editor and the game worlds.
293+ editor -> dialog_world = game_manager_create_world (game_manager , "dialog" );
294+ te_camera * camera = camera_create ();
295+ world_spawn_camera (editor -> dialog_world , camera );
296+ world_set_active_camera (editor -> dialog_world , camera );
297+
298+ editor -> file_dialog = file_dialog_create (
299+ editor -> dialog_world , editor , on_new_world_file_selected ,
300+ on_new_world_file_cancel , TE_FDM_SELECT_NEW_FILE );
301+ } else {
302+ world_save_to_file (editor -> game_world , editor -> game_world_relative_path );
303+ }
304+ return ;
305+ }
306+
210307 editor_camera_on_keyboard_button_pressed (editor -> editor_camera , button );
211308}
212309
@@ -389,12 +486,3 @@ editor_on_window_lost_focus(void* game_instance, struct te_game_manager* game_ma
389486
390487 editor_camera_enable_input (editor -> editor_camera , false);
391488}
392-
393- void
394- editor_on_window_close (void * game_instance , struct te_game_manager * game_manager ) {
395- te_editor * editor = game_instance ;
396-
397- if (editor -> game_world != NULL ) {
398- prv_editor_destroy_game_world (editor , game_manager );
399- }
400- }
0 commit comments