Skip to content

Commit 2763c7a

Browse files
committed
Implement file dialog.
1 parent ae9d4c1 commit 2763c7a

13 files changed

Lines changed: 1069 additions & 85 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ if(NOT IS_RELEASE_BUILD AND NOT MSVC)
2626
# Memcheck is our silly little memory leak checker. It can be used in cases where ASan is not available or if it uses too much RAM.
2727
set(ENGINE_MEMCHECK_ENABLED ON CACHE BOOL "" FORCE)
2828
message(STATUS "Memcheck enabled.")
29-
add_link_options(LINKER:--wrap=malloc,--wrap=realloc,--wrap=calloc,--wrap=free,--wrap=strdup,--wrap=wcsdup,--wrap=scandir,--wrap=getline)
29+
add_link_options(LINKER:--wrap=malloc,--wrap=realloc,--wrap=calloc,--wrap=free,--wrap=strdup,--wrap=wcsdup,--wrap=scandir,--wrap=getline,--wrap=realpath)
3030
add_subdirectory(ext/memcheck ${DEPENDENCY_BUILD_DIR_NAME}/memcheck EXCLUDE_FROM_ALL)
3131
link_libraries(memcheck)
3232
link_libraries(m)

ext/memcheck

src/editor/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ set(PROJECT_SOURCES
1919
src/ui/property_inspector.h
2020
src/ui/filesystem_view.c
2121
src/ui/filesystem_view.h
22+
src/ui/file_dialog.c
23+
src/ui/file_dialog.h
2224
)
2325

2426
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})

src/editor/src/editor.c

Lines changed: 114 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
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>
@@ -14,10 +15,15 @@
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

2023
struct 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+
65119
static void
66120
editor_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-
103146
void
104147
editor_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+
202283
void
203284
editor_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

Comments
 (0)