added file open/save dialog GUI logic

This commit is contained in:
myT 2024-03-29 01:06:49 +01:00
parent 14f9d18075
commit d1c19fbe2a
2 changed files with 168 additions and 3 deletions

View file

@ -1,6 +1,6 @@
/* /*
=========================================================================== ===========================================================================
Copyright (C) 2022-2023 Gian 'myT' Schellenbaum Copyright (C) 2022-2024 Gian 'myT' Schellenbaum
This file is part of Challenge Quake 3 (CNQ3). This file is part of Challenge Quake 3 (CNQ3).
@ -99,6 +99,161 @@ void ToggleBooleanWithShortcut(bool& value, ImGuiKey key)
} }
} }
struct FileDialog
{
char folder[MAX_QPATH];
char fileName[MAX_QPATH];
char filePath[MAX_QPATH];
char extension[MAX_QPATH];
const char* dialogName;
char** filePaths;
int fileCount;
int selectedFileIndex;
bool saveMode;
};
static FileDialog saveFile;
static FileDialog openFile;
static bool PathHasExtension(const char* path, const char* extension)
{
Q_assert(extension[0] == '.');
const int pathLength = strlen(path);
const int extLength = strlen(extension);
if(extLength >= pathLength)
{
return false;
}
return Q_stricmpn(path + pathLength - extLength, extension, extLength) == 0;
}
static void OpenFileDialog(FileDialog& dialog, const char* folder, const char* extension)
{
if(ImGui::IsPopupOpen(dialog.dialogName))
{
return;
}
dialog.fileName[0] = '\0';
Q_strncpyz(dialog.folder, folder, sizeof(dialog.folder));
Q_strncpyz(dialog.extension, extension, sizeof(dialog.extension));
dialog.filePaths = FS_ListFiles(folder, extension, &dialog.fileCount);
dialog.selectedFileIndex = -1;
ImGui::OpenPopup(dialog.dialogName);
}
static bool DoFileDialog(FileDialog& dialog)
{
bool success = false;
if(ImGui::BeginPopupModal(dialog.dialogName, NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
if(BeginTable("Files", 1))
{
for(int i = 0; i < dialog.fileCount; i++)
{
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
if(ImGui::Selectable(dialog.filePaths[i], i == dialog.selectedFileIndex,
ImGuiSelectableFlags_DontClosePopups))
{
dialog.selectedFileIndex = i;
Q_strncpyz(dialog.fileName, dialog.filePaths[i], sizeof(dialog.fileName));
}
}
ImGui::EndTable();
}
if(dialog.saveMode)
{
if(ImGui::InputText("File path", dialog.fileName, sizeof(dialog.fileName)))
{
dialog.selectedFileIndex = -1;
}
if(ImGui::Button("Save") &&
dialog.fileName[0] != '\0' &&
dialog.fileName[0] != '.')
{
if(!PathHasExtension(dialog.fileName, dialog.extension))
{
const int lastCharIndex = strlen(dialog.fileName) - 1;
if(dialog.fileName[lastCharIndex] == '.')
{
dialog.fileName[lastCharIndex] = '\0';
}
Q_strcat(dialog.fileName, sizeof(dialog.fileName), dialog.extension);
}
Com_sprintf(dialog.filePath, sizeof(dialog.filePath),
"%s/%s", dialog.folder, dialog.fileName);
FS_FreeFileList(dialog.filePaths);
dialog.filePaths = NULL;
ImGui::CloseCurrentPopup();
success = true;
}
}
else
{
if(ImGui::Button("Open") &&
dialog.selectedFileIndex >= 0 &&
dialog.selectedFileIndex < dialog.fileCount)
{
Com_sprintf(dialog.filePath, sizeof(dialog.filePath),
"%s/%s", dialog.folder, dialog.filePaths[dialog.selectedFileIndex]);
FS_FreeFileList(dialog.filePaths);
dialog.filePaths = NULL;
ImGui::CloseCurrentPopup();
success = true;
}
}
ImGui::SameLine();
if(ImGui::Button("Cancel"))
{
FS_FreeFileList(dialog.filePaths);
dialog.filePaths = NULL;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
return success;
}
void OpenSaveFileDialog(const char* folder, const char* extension)
{
Q_assert(extension[0] == '.');
OpenFileDialog(saveFile, folder, extension);
}
bool SaveFileDialog()
{
return DoFileDialog(saveFile);
}
const char* GetSaveFileDialogPath()
{
return saveFile.filePath;
}
void OpenOpenFileDialog(const char* folder, const char* extension)
{
Q_assert(extension[0] == '.');
OpenFileDialog(openFile, folder, extension);
}
bool OpenFileDialog()
{
return DoFileDialog(openFile);
}
const char* GetOpenFileDialogPath()
{
return openFile.filePath;
}
struct MainMenuItem struct MainMenuItem
{ {
GUI_MainMenu::Id menu; GUI_MainMenu::Id menu;
@ -235,7 +390,7 @@ static void ImGUI_ApplyTheme()
colors[ImGuiCol_NavHighlight] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); colors[ImGuiCol_NavHighlight] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 0.00f, 0.00f, 0.70f); colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 0.00f, 0.00f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(1.00f, 0.00f, 0.00f, 0.20f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(1.00f, 0.00f, 0.00f, 0.20f);
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(1.00f, 0.00f, 0.00f, 0.35f); colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.00f, 0.00f, 0.10f, 0.35f);
const ImVec4 hover(0.49f, 0.75f, 0.75f, 0.35f); const ImVec4 hover(0.49f, 0.75f, 0.75f, 0.35f);
const ImVec4 active(0.49f, 1.00f, 1.00f, 0.55f); const ImVec4 active(0.49f, 1.00f, 1.00f, 0.55f);
@ -454,6 +609,10 @@ void CL_IMGUI_Init()
{ {
keyMap[K_F1 + i] = ImGuiKey_F1 + i; keyMap[K_F1 + i] = ImGuiKey_F1 + i;
} }
saveFile.saveMode = true;
saveFile.dialogName = "Save file";
openFile.dialogName = "Open file";
} }
void CL_IMGUI_Frame() void CL_IMGUI_Frame()

View file

@ -1,6 +1,6 @@
/* /*
=========================================================================== ===========================================================================
Copyright (C) 2022-2023 Gian 'myT' Schellenbaum Copyright (C) 2022-2024 Gian 'myT' Schellenbaum
This file is part of Challenge Quake 3 (CNQ3). This file is part of Challenge Quake 3 (CNQ3).
@ -36,6 +36,12 @@ void TableRow2(const char* item0, int item1);
void TableRow2(const char* item0, float item1, const char* format = "%g"); void TableRow2(const char* item0, float item1, const char* format = "%g");
bool IsShortcutPressed(ImGuiKey key); bool IsShortcutPressed(ImGuiKey key);
void ToggleBooleanWithShortcut(bool& value, ImGuiKey key); void ToggleBooleanWithShortcut(bool& value, ImGuiKey key);
void OpenSaveFileDialog(const char* folder, const char* extension);
bool SaveFileDialog(); // true when the user clicked the save button
const char* GetSaveFileDialogPath();
void OpenOpenFileDialog(const char* folder, const char* extension);
bool OpenFileDialog(); // true when the user clicked the open button
const char* GetOpenFileDialogPath();
#define MAIN_MENU_LIST(M) \ #define MAIN_MENU_LIST(M) \
M(Tools, "Tools") \ M(Tools, "Tools") \