diff --git a/SessionZero.sln.DotSettings.user b/SessionZero.sln.DotSettings.user index 80cfb75..903dfe1 100644 --- a/SessionZero.sln.DotSettings.user +++ b/SessionZero.sln.DotSettings.user @@ -1,2 +1,3 @@  - ForceIncluded \ No newline at end of file + ForceIncluded + ForceIncluded \ No newline at end of file diff --git a/SzCore/DataObjects/SzCharacterTemplate.cs b/SzCore/DataObjects/SzCharacterTemplate.cs new file mode 100644 index 0000000..d2e68c1 --- /dev/null +++ b/SzCore/DataObjects/SzCharacterTemplate.cs @@ -0,0 +1,9 @@ +namespace SzCore.DataObjects; + +public class SzCharacterTemplate : ISzTemplate +{ + public string Name { get; set; } = ""; + public string Id { get; set; } = ""; + public string Description { get; set; } = ""; + public Dictionary TemplateFields { get; set; } = []; +} \ No newline at end of file diff --git a/SzCore/SzDataHandler.cs b/SzCore/SzDataHandler.cs index 9a3f962..fce4f10 100644 --- a/SzCore/SzDataHandler.cs +++ b/SzCore/SzDataHandler.cs @@ -7,6 +7,9 @@ public class SzDataHandler private readonly Dictionary _loadedDatasets = []; private readonly Dictionary _loadedTemplates = []; + public Dictionary LoadedDatasets => _loadedDatasets; + public Dictionary LoadedTemplates => _loadedTemplates; + public SzDataHandler() { } public void ClearCache() @@ -247,5 +250,18 @@ public class SzDataHandler await LoadDatasetAsync(id, ct); } } + + public async Task LoadAllDataObjectTemplatesAsync(CancellationToken ct = default) + { + _loadedTemplates.Clear(); + if (!Directory.Exists(SZ.LocalFileManager.TemplatesPath)) return; + + var dirs = Directory.GetDirectories(SZ.LocalFileManager.TemplatesPath); + foreach (var dir in dirs) + { + var id = Path.GetFileName(dir); + await LoadTemplateAsync(id, ct); + } + } #endregion } diff --git a/SzGui/ApplicationSettings.cs b/SzGui/ApplicationSettings.cs new file mode 100644 index 0000000..6cb2ca3 --- /dev/null +++ b/SzGui/ApplicationSettings.cs @@ -0,0 +1,81 @@ +using System.IO; +using Raylib_cs; +using Tomlyn; + +namespace SzGui; + +public static class ApplicationSettings +{ + private static Dictionary _settings = new(); + private static readonly string _filePath = "settings.toml"; + + public static Dictionary GetAllSettings() => _settings; + + public static void CreateInitialSettings() + { + CreateSetting("ShowStartup", false); + CreateSetting("BackgroundColor", Color.DarkGray); + SaveSettings(); + } + + public static T GetSettingValue(string settingName, T defaultValue = default!) + { + if (_settings.TryGetValue(settingName, out var value)) + { + try + { + if (typeof(T) == typeof(float) && value is double d) + return (T)(object)(float)d; + + return (T)Convert.ChangeType(value, typeof(T)); + } + catch { return defaultValue; } + } + return defaultValue; + } + + public static bool SetSettingValue(string settingName, object value) + { + if (!_settings.ContainsKey(settingName)) return false; + _settings[settingName] = value; + return true; + } + + public static bool CreateSetting(string name, object value) + { + return _settings.TryAdd(name, value); + } + + public static void SaveSettings() + { + try + { + var saveDict = new Dictionary(); + + foreach(var kvp in _settings) + { + if (kvp.Value is Color c) + saveDict[kvp.Key] = new int[] { c.R, c.G, c.B }; + else + saveDict[kvp.Key] = kvp.Value; + } + + var tomlString = Toml.FromModel(saveDict); + File.WriteAllText(_filePath, tomlString); + } + catch (Exception ex) { Console.WriteLine($"Save Error: {ex.Message}"); } + } + + public static void LoadSettings() + { + if (!File.Exists(_filePath)) { SaveSettings(); return; } + + try + { + var tomlString = File.ReadAllText(_filePath); + var loaded = Toml.ToModel>(tomlString); + if (loaded != null) _settings = loaded; + } + catch (Exception ex) { Console.WriteLine($"Load Error: {ex.Message}"); } + } +} \ No newline at end of file diff --git a/SzGui/Program.cs b/SzGui/Program.cs index 3b76925..bcf6be1 100644 --- a/SzGui/Program.cs +++ b/SzGui/Program.cs @@ -1,6 +1,12 @@ // See https://aka.ms/new-console-template for more information +using SzCore; +using SzCore.Defaults; using SzGui; -var app = new SzApp(); -app.Init(); \ No newline at end of file +DefaultLocalFileManager _fileManager = new(); +ISzLogger _logger = new SzLogger(); +ISzDatabaseHandler _databaseHandler = new SzDatabaseHandler(); + +SZ.Init(_fileManager, _logger, _databaseHandler); +SzApp.AppInstance.Init(); \ No newline at end of file diff --git a/SzGui/SzApp.cs b/SzGui/SzApp.cs index d1bfc47..e5bca2d 100644 --- a/SzGui/SzApp.cs +++ b/SzGui/SzApp.cs @@ -2,29 +2,51 @@ using System.Numerics; using ImGuiNET; using Raylib_cs; using rlImGui_cs; +using SzGui.Windows; namespace SzGui; public class SzApp { + public static readonly SzApp AppInstance = new(); + private SzApp() { } + + private List _activeWindows = new(); + + public void ActivateWindow(SzGuiWindowBase window) + { + if (_activeWindows.Any(w => w.GetType() == window.GetType())) + { + ImGui.SetWindowFocus(window.WindowName); + return; + } + + _activeWindows.Add(window); + } + public void Init() { + ApplicationSettings.LoadSettings(); + Raylib.SetConfigFlags(ConfigFlags.Msaa4xHint | ConfigFlags.VSyncHint | ConfigFlags.ResizableWindow); Raylib.InitWindow(1280, 800, "SessionZero"); rlImGui.Setup(true, true); ImGui.GetIO().ConfigWindowsMoveFromTitleBarOnly = true; - + + if (ApplicationSettings.GetSettingValue("ShowStartup")) ActivateWindow(new StartupWindow()); + while (!Raylib.WindowShouldClose()) { Raylib.BeginDrawing(); - Raylib.ClearBackground(new Color(0, 20, 50)); + Raylib.ClearBackground(Color.Gray); rlImGui.Begin(); + ImGui.PushStyleColor(ImGuiCol.WindowBg, new Vector4(0, 0, 0, 0)); ImGui.DockSpaceOverViewport(0); - - // ImGui.ShowDemoWindow(); - ImGui.ShowStyleEditor(); + ImGui.PopStyleColor(); + + HandleShortcuts(); DrawImGui(); rlImGui.End(); @@ -34,13 +56,72 @@ public class SzApp rlImGui.Shutdown(); Raylib.CloseWindow(); } + + private void HandleShortcuts() + { + var io = ImGui.GetIO(); + + if (io is { KeyCtrl: true, KeyAlt: true } && ImGui.IsKeyPressed(ImGuiKey.S)) + { + ActivateWindow(new SettingsWindow()); + } + + if (io is { KeyCtrl: true, KeyAlt: true } && ImGui.IsKeyPressed(ImGuiKey.Q)) + { + Raylib.CloseWindow(); + } + } + + private void UpdateImGuiTheme() + { + var c = ApplicationSettings.GetSettingValue("BackgroundColor"); + Vector4 styleColor = new Vector4(c.R / 255f, c.G / 255f, c.B / 255f, 1.0f); + ImGui.GetStyle().Colors[(int)ImGuiCol.WindowBg] = styleColor; + } private void DrawImGui() { - if(ImGui.Begin("SessionZero")) + DrawGlobalMenuBar(); + + for (int i = _activeWindows.Count - 1; i >= 0; i--) { - ImGui.TextUnformatted("Test: " + IconFonts.FontAwesome6.House); + _activeWindows[i].Draw(); + if (!_activeWindows[i].IsOpen) _activeWindows.RemoveAt(i); } - ImGui.End(); } + + private void DrawGlobalMenuBar() + { + if (ImGui.BeginMainMenuBar()) + { + if (ImGui.BeginMenu("File")) + { + if (ImGui.MenuItem("Exit", "Ctrl+Alt+Q")) Raylib.CloseWindow(); + ImGui.EndMenu(); + } + + if (ImGui.BeginMenu("Edit")) + { + if (ImGui.MenuItem("Settings", "Ctrl+Alt+S")) + { + ActivateWindow(new SettingsWindow()); + } + ImGui.EndMenu(); + } + + if (ImGui.BeginMenu("View")) + { + if (ImGui.MenuItem("Start window")) + { + ActivateWindow(new StartupWindow()); + } + ImGui.EndMenu(); + } + + if (ImGui.MenuItem("Library")) ActivateWindow(new SzLibraryWindow()); + + ImGui.EndMainMenuBar(); + } + } + } diff --git a/SzGui/SzDatabaseHandler.cs b/SzGui/SzDatabaseHandler.cs new file mode 100644 index 0000000..1aece7d --- /dev/null +++ b/SzGui/SzDatabaseHandler.cs @@ -0,0 +1,19 @@ +using SzCore; +using SzCore.DataObjects; + +namespace SzGui; + +public class SzDatabaseHandler : ISzDatabaseHandler +{ + public bool InternetAllowed { get; set; } + public Dictionary SzDbUrls { get; set; } + public Task TryRetrieveDatasetAsync(Guid uuid, CancellationToken ct = default) + { + return null; + } + + public Task TryRetrieveTemplateAsync(Guid uuid, CancellationToken ct = default) + { + return null; + } +} \ No newline at end of file diff --git a/SzGui/SzGui.csproj b/SzGui/SzGui.csproj index 16c9b9c..5df68a5 100644 --- a/SzGui/SzGui.csproj +++ b/SzGui/SzGui.csproj @@ -11,6 +11,7 @@ + diff --git a/SzGui/SzLogger.cs b/SzGui/SzLogger.cs new file mode 100644 index 0000000..c7c79eb --- /dev/null +++ b/SzGui/SzLogger.cs @@ -0,0 +1,23 @@ +using SzCore; + +namespace SzGui; + +public class SzLogger : ISzLogger +{ + public bool LogToFile { get; set; } + public string LogFilePath { get; set; } + public int LogFileMaxLines { get; set; } + public void Log(string text) + { + + } + + public void LogError(string text) + { + + } + + public void LogWarning(string text) + { + } +} \ No newline at end of file diff --git a/SzGui/Windows/DatasetCreatorWindow.cs b/SzGui/Windows/DatasetCreatorWindow.cs new file mode 100644 index 0000000..3ca54aa --- /dev/null +++ b/SzGui/Windows/DatasetCreatorWindow.cs @@ -0,0 +1,68 @@ +using ImGuiNET; +using SzCore; +using SzCore.DataObjects; + +namespace SzGui.Windows; + +public class DatasetCreatorWindow : SzGuiWindowBase +{ + private string _datasetName = ""; + private int _selectedTemplateIndex = 0; + private List _templateIds = new(); + + public DatasetCreatorWindow() + { + WindowName = "Create New Dataset"; + RefreshTemplates(); + } + + private void RefreshTemplates() + { + _ = SZ.DataHandler.LoadAllDataObjectTemplatesAsync(); + _templateIds = SZ.DataHandler.LoadedTemplates.Keys.ToList(); + } + + protected override void RenderContent() + { + ImGui.InputText("Dataset Name", ref _datasetName, 128); + + if (_templateIds.Count == 0) + { + ImGui.TextColored(new System.Numerics.Vector4(1, 0, 0, 1), "No templates loaded! Create a template first."); + if (ImGui.Button("Refresh Template List")) RefreshTemplates(); + } + else + { + string[] items = _templateIds.ToArray(); + ImGui.Combo("Template", ref _selectedTemplateIndex, items, items.Length); + + ImGui.Separator(); + + if (ImGui.Button("Create Dataset", new System.Numerics.Vector2(0, 30))) + { + if (!string.IsNullOrWhiteSpace(_datasetName)) + { + ExecuteCreation(); + } + } + } + } + + private async void ExecuteCreation() + { + string selectedId = _templateIds[_selectedTemplateIndex]; + + var result = await SZ.DataHandler.CreateDatasetAsync(_datasetName, selectedId); + + if (result.IsSuccess && result.Value != null) + { + await SZ.DataHandler.SaveDatasetAsync(result.Value); + + IsOpen = false; + } + else + { + Console.WriteLine($"Error creating dataset: {result.Error}"); + } + } +} \ No newline at end of file diff --git a/SzGui/Windows/NewObjectModal.cs b/SzGui/Windows/NewObjectModal.cs new file mode 100644 index 0000000..2949a56 --- /dev/null +++ b/SzGui/Windows/NewObjectModal.cs @@ -0,0 +1,44 @@ +using ImGuiNET; +using SzCore; +using SzCore.DataObjects; +using SzGui.Windows; + +public class NewObjectModal : SzGuiWindowBase +{ + private readonly SzDataset _dataset; + private string _objName = ""; + + public NewObjectModal(SzDataset dataset) + { + _dataset = dataset; + WindowName = $"Add Object to {dataset.Name}"; + } + + protected override void RenderContent() + { + ImGui.Text($"Creating object for template: {_dataset.DataObjectTemplateId}"); + ImGui.InputText("Object Name", ref _objName, 64); + + if (ImGui.Button("Create", new System.Numerics.Vector2(100, 0))) + { + Create(); + } + } + + private async void Create() + { + var templateResult = await SZ.DataHandler.LoadTemplateAsync(_dataset.DataObjectTemplateId); + + if (templateResult.IsSuccess) + { + var objResult = SZ.DataHandler.CreateDataObject(templateResult.Value!, _objName); + + if (objResult.IsSuccess) + { + _dataset.DataObjects.Add(objResult.Value!.Id, objResult.Value); + await SZ.DataHandler.SaveDatasetAsync(_dataset); + IsOpen = false; + } + } + } +} \ No newline at end of file diff --git a/SzGui/Windows/SettingsWindow.cs b/SzGui/Windows/SettingsWindow.cs new file mode 100644 index 0000000..4355acc --- /dev/null +++ b/SzGui/Windows/SettingsWindow.cs @@ -0,0 +1,76 @@ +using System.Numerics; +using ImGuiNET; + +namespace SzGui.Windows; + +public class SettingsWindow : SzGuiWindowBase +{ + private bool _settingsDirty = false; + + public SettingsWindow() => WindowName = "App Settings"; + + protected override void RenderContent() + { + ImGui.SeparatorText("Application Settings"); + + foreach (var setting in ApplicationSettings.GetAllSettings().ToList()) + { + string key = setting.Key; + object val = setting.Value; + bool changed = false; + + if (val is bool boolVal) + { + if (ImGui.Checkbox(key, ref boolVal)) + { + ApplicationSettings.SetSettingValue(key, boolVal); + changed = true; + } + } + else if (val is float floatVal || val is double) + { + float f = Convert.ToSingle(val); + if (ImGui.DragFloat(key, ref f, 0.01f)) + { + ApplicationSettings.SetSettingValue(key, f); + changed = true; + } + } + else if (val is string strVal) + { + if (ImGui.InputText(key, ref strVal, 256)) + { + ApplicationSettings.SetSettingValue(key, strVal); + changed = true; + } + } + + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip($"Internal Key: {key}"); + } + + if (changed) _settingsDirty = true; + } + + ImGui.Separator(); + + if (ImGui.Button("Save Changes")) + { + ApplicationSettings.SaveSettings(); + _settingsDirty = false; + } + + ImGui.SameLine(); + + if (ImGui.Button("Reload from Disk")) + { + ApplicationSettings.LoadSettings(); + } + + if (_settingsDirty) + { + ImGui.TextColored(new Vector4(1, 0.5f, 0, 1), "You have unsaved changes!"); + } + } +} diff --git a/SzGui/Windows/StartupWindow.cs b/SzGui/Windows/StartupWindow.cs new file mode 100644 index 0000000..f3bd1e2 --- /dev/null +++ b/SzGui/Windows/StartupWindow.cs @@ -0,0 +1,15 @@ +using ImGuiNET; + +namespace SzGui.Windows; + +public class StartupWindow : SzGuiWindowBase +{ + public StartupWindow() => WindowName = "Startup"; + + protected override void RenderContent() + { + ImGui.TextUnformatted("Welcome to SessionZero!"); + var testBttn = ImGui.Button(IconFonts.FontAwesome6.Gear + " Settings"); + if (testBttn) SzApp.AppInstance.ActivateWindow(new SettingsWindow()); + } +} \ No newline at end of file diff --git a/SzGui/Windows/SzDataObjectEditorWindow.cs b/SzGui/Windows/SzDataObjectEditorWindow.cs new file mode 100644 index 0000000..4b024c1 --- /dev/null +++ b/SzGui/Windows/SzDataObjectEditorWindow.cs @@ -0,0 +1,93 @@ +using ImGuiNET; +using System.Numerics; +using SzCore; +using SzCore.DataObjects; + +namespace SzGui.Windows; + +public class SzDataObjectEditorWindow : SzGuiWindowBase +{ + private readonly SzDataset _dataset; + private readonly SzDataObject _dataObject; + private bool _isDirty = false; + + public SzDataObjectEditorWindow(SzDataset dataset, SzDataObject dataObject) + { + _dataset = dataset; + _dataObject = dataObject; + WindowName = $"Editing: {dataObject.Name} ({dataset.Name})"; + } + + protected override void RenderContent() + { + ImGui.TextDisabled($"ID: {_dataObject.Id}"); + ImGui.SeparatorText("Fields"); + + foreach (var field in _dataObject.Fields.Values) + { + DrawFieldInput(field); + } + + ImGui.Separator(); + + if (ImGui.Button("Save Object", new Vector2(120, 30))) + { + Save(); + } + + if (_isDirty) + { + ImGui.SameLine(); + ImGui.TextColored(new Vector4(1, 0.5f, 0, 1), "Unsaved changes..."); + } + } + + private void DrawFieldInput(SzField field) + { + string label = $"{field.Id}##{field.Id}"; + string val = field.Value ?? ""; + + switch (field.FieldType) + { + case SzFieldType.Text: + if (ImGui.InputText(label, ref val, 1024)) + { + field.Value = val; + _isDirty = true; + } + break; + + case SzFieldType.Bool: + bool bVal = val.ToLower() == "true"; + if (ImGui.Checkbox(label, ref bVal)) + { + field.Value = bVal.ToString().ToLower(); + _isDirty = true; + } + break; + + case SzFieldType.Number: + // Handling numbers as strings in the DataObject, but using DragFloat for UX + float.TryParse(val, out float fVal); + if (ImGui.DragFloat(label, ref fVal)) + { + field.Value = fVal.ToString(); + _isDirty = true; + } + break; + + default: + ImGui.Text($"{field.Id}: {val} (Unsupported Type: {field.FieldType})"); + break; + } + } + + private async void Save() + { + var result = await SZ.DataHandler.SaveDatasetAsync(_dataset); + if (result.IsSuccess) + { + _isDirty = false; + } + } +} \ No newline at end of file diff --git a/SzGui/Windows/SzDataObjectTemplateEditorWindow.cs b/SzGui/Windows/SzDataObjectTemplateEditorWindow.cs new file mode 100644 index 0000000..ca179c0 --- /dev/null +++ b/SzGui/Windows/SzDataObjectTemplateEditorWindow.cs @@ -0,0 +1,137 @@ +using ImGuiNET; +using System.Numerics; +using SzCore; +using SzCore.DataObjects; + +namespace SzGui.Windows; + +public class SzDataObjectTemplateEditorWindow : SzGuiWindowBase +{ + private readonly ISzTemplate _template; + private string _name; + private string _type; + private string _description = ""; + private List _fields; + + // Split ID components + private string _baseId = ""; + private string _version = "1_0"; + + private string _newFieldId = ""; + private int _selectedTypeIndex = 0; + + public SzDataObjectTemplateEditorWindow(SzDataObjectTemplate template) + { + _template = template; + _name = template.Name; + _type = template.DataObjectType; + _fields = template.TemplateFields.Values.ToList(); + + if (template.Id.Contains('@')) + { + var parts = template.Id.Split('@'); + _baseId = parts[0]; + _version = parts[1]; + } + else + { + _baseId = template.Id; + } + + WindowName = $"Edit Template: {template.Id}"; + } + + protected override void RenderContent() + { + ImGui.SeparatorText("Metadata"); + + ImGui.InputText("Display Name", ref _name, 128); + ImGui.InputText("Object Type", ref _type, 128); + + ImGui.Spacing(); + + ImGui.Text("Internal Identity"); + ImGui.InputText("Base ID", ref _baseId, 64); + ImGui.SameLine(); + ImGui.Text("@"); + ImGui.SameLine(); + ImGui.SetNextItemWidth(100); + ImGui.InputText("Version", ref _version, 16); + + string fullIdPreview = $"{_baseId}@{_version}"; + ImGui.TextDisabled($"Final ID Preview: {fullIdPreview}"); + + ImGui.SeparatorText("Fields Configuration"); + + if (ImGui.BeginTable("TemplateFieldsTable", 3, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg)) + { + ImGui.TableSetupColumn("Field ID", ImGuiTableColumnFlags.WidthStretch); + ImGui.TableSetupColumn("Type", ImGuiTableColumnFlags.WidthFixed, 100); + ImGui.TableSetupColumn("Action", ImGuiTableColumnFlags.WidthFixed, 70); + ImGui.TableHeadersRow(); + + for (int i = 0; i < _fields.Count; i++) + { + ImGui.TableNextRow(); + ImGui.TableNextColumn(); + ImGui.TextUnformatted(_fields[i].Id); + + ImGui.TableNextColumn(); + ImGui.TextUnformatted(_fields[i].FieldType.ToString()); + + ImGui.TableNextColumn(); + if (ImGui.SmallButton($"Remove##{i}")) _fields.RemoveAt(i); + } + ImGui.EndTable(); + } + + ImGui.Spacing(); + ImGui.SeparatorText("Add New Field"); + + ImGui.InputText("Field ID", ref _newFieldId, 64); + string[] typeNames = Enum.GetNames(); + ImGui.Combo("Type", ref _selectedTypeIndex, typeNames, typeNames.Length); + + if (ImGui.Button("Add Field") && !string.IsNullOrWhiteSpace(_newFieldId)) + { + var result = SZ.DataHandler.CreateTemplateField(_newFieldId, (SzFieldType)_selectedTypeIndex); + if (result.IsSuccess) + { + _fields.Add(result.Value!); + _newFieldId = ""; + } + } + + ImGui.Separator(); + + bool isNewVersion = fullIdPreview != _template.Id; + if (isNewVersion) + { + ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.2f, 0.6f, 0.2f, 1.0f)); + if (ImGui.Button("Save as New Version", new Vector2(0, 30))) Save(fullIdPreview); + ImGui.PopStyleColor(); + } + else + { + if (ImGui.Button("Overwrite Template", new Vector2(0, 30))) Save(fullIdPreview); + } + } + + private async void Save(string finalId) + { + var result = SZ.DataHandler.CreateDataObjectTemplate( + _name, + _type, + _version, + finalId, + null, + _fields + ); + + if (result.IsSuccess && result.Value != null) + { + await SZ.DataHandler.SaveTemplateAsync(result.Value); + IsOpen = false; + } + } +} \ No newline at end of file diff --git a/SzGui/Windows/SzDatasetViewerWindow.cs b/SzGui/Windows/SzDatasetViewerWindow.cs new file mode 100644 index 0000000..70fa038 --- /dev/null +++ b/SzGui/Windows/SzDatasetViewerWindow.cs @@ -0,0 +1,57 @@ +using ImGuiNET; +using System.Numerics; +using SzCore; +using SzCore.DataObjects; + +namespace SzGui.Windows; + +public class SzDatasetViewerWindow : SzGuiWindowBase +{ + private readonly SzDataset _dataset; + + public SzDatasetViewerWindow(SzDataset dataset) + { + _dataset = dataset; + WindowName = $"Dataset: {dataset.Name} ({dataset.DataObjectTemplateId})"; + } + + protected override void RenderContent() + { + if (ImGui.Button("Add New Object")) + { + SzApp.AppInstance.ActivateWindow(new NewObjectModal(_dataset)); + } + + ImGui.Separator(); + + if (ImGui.BeginTable("ObjectTable", 2, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY)) + { + ImGui.TableSetupColumn("Object Name", ImGuiTableColumnFlags.WidthStretch); + ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 110); + ImGui.TableHeadersRow(); + + foreach (var dataObj in _dataset.DataObjects.Values.ToList()) + { + ImGui.TableNextRow(); + + ImGui.TableNextColumn(); + ImGui.TextUnformatted(dataObj.Name); + + ImGui.TableNextColumn(); + if (ImGui.SmallButton($"Edit##{dataObj.Id}")) + { + SzApp.AppInstance.ActivateWindow(new SzDataObjectEditorWindow(_dataset, dataObj)); + } + + ImGui.SameLine(); + + if (ImGui.SmallButton($"Delete##{dataObj.Id}")) + { + _dataset.DataObjects.Remove(dataObj.Id); + _ = SZ.DataHandler.SaveDatasetAsync(_dataset); + } + } + ImGui.EndTable(); + } + } +} \ No newline at end of file diff --git a/SzGui/Windows/SzGuiWindowBase.cs b/SzGui/Windows/SzGuiWindowBase.cs new file mode 100644 index 0000000..f9c0717 --- /dev/null +++ b/SzGui/Windows/SzGuiWindowBase.cs @@ -0,0 +1,22 @@ +using ImGuiNET; + +namespace SzGui.Windows; + +public abstract class SzGuiWindowBase +{ + public bool IsOpen = true; + public string WindowName { get; protected set; } = "Window"; + + public virtual void Draw() + { + if (!IsOpen) return; + + if (ImGui.Begin(WindowName, ref IsOpen, ImGuiWindowFlags.MenuBar)) + { + RenderContent(); + } + ImGui.End(); + } + + protected abstract void RenderContent(); +} \ No newline at end of file diff --git a/SzGui/Windows/SzLibraryWindow.cs b/SzGui/Windows/SzLibraryWindow.cs new file mode 100644 index 0000000..6d27f66 --- /dev/null +++ b/SzGui/Windows/SzLibraryWindow.cs @@ -0,0 +1,127 @@ +using ImGuiNET; +using SzCore; +using SzCore.DataObjects; + +namespace SzGui.Windows; + +public class SzLibraryWindow : SzGuiWindowBase +{ + public SzLibraryWindow() + { + WindowName = "SZ Library"; + RefreshData(); + } + + private Dictionary _loadedDatasets = []; + private Dictionary _loadedDataObjectTemplates = []; + + private async void RefreshData() + { + await SZ.DataHandler.LoadAllDatasetsAsync(); + await SZ.DataHandler.LoadAllDataObjectTemplatesAsync(); + + _loadedDatasets = SZ.DataHandler.LoadedDatasets; + _loadedDataObjectTemplates = SZ.DataHandler.LoadedTemplates.Values + .OfType() + .ToDictionary(t => t.Id, t => t); + } + + protected override void RenderContent() + { + if (ImGui.BeginMenuBar()) + { + if (ImGui.BeginMenu("Create")) + { + if (ImGui.MenuItem("New Template")) + { + SzApp.AppInstance.ActivateWindow(new SzTemplateCreatorWindow()); + } + + if (ImGui.MenuItem("New Dataset")) + { + SzApp.AppInstance.ActivateWindow(new DatasetCreatorWindow()); + } + ImGui.EndMenu(); + } + + // Added Refresh to the menu bar + if (ImGui.MenuItem("Refresh")) + { + RefreshData(); + } + + ImGui.EndMenuBar(); + } + + if (ImGui.CollapsingHeader("Data Object Templates", ImGuiTreeNodeFlags.DefaultOpen)) + { + if (ImGui.BeginTable("DataObjectTemplatesTable", 2, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg)) + { + ImGui.TableSetupColumn("Template ID", ImGuiTableColumnFlags.WidthStretch); + ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 120); + ImGui.TableHeadersRow(); + + foreach (var template in _loadedDataObjectTemplates) + { + ImGui.TableNextRow(); + ImGui.TableNextColumn(); + ImGui.TextUnformatted(template.Key); + + ImGui.TableNextColumn(); + + if (ImGui.SmallButton($"Edit##T_{template.Key}")) + { + SzApp.AppInstance.ActivateWindow(new SzDataObjectTemplateEditorWindow(template.Value)); + } + + ImGui.SameLine(); + + if (ImGui.SmallButton($"Delete##T_{template.Key}")) + { + _ = Task.Run(async () => { + await SZ.DataHandler.DeleteTemplateAsync(template.Key); + RefreshData(); + }); + } + } + ImGui.EndTable(); + } + } + + ImGui.Spacing(); + + if (ImGui.CollapsingHeader("Datasets", ImGuiTreeNodeFlags.DefaultOpen)) + { + if (ImGui.BeginTable("DatasetsTable", 2, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg)) + { + ImGui.TableSetupColumn("Dataset Name", ImGuiTableColumnFlags.WidthStretch); + ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 120); + ImGui.TableHeadersRow(); + + foreach (var datasetEntry in _loadedDatasets) + { + var dataset = datasetEntry.Value; + ImGui.TableNextRow(); + + ImGui.TableNextColumn(); + ImGui.TextUnformatted(dataset.Name); + + ImGui.TableNextColumn(); + if (ImGui.SmallButton($"Open##{dataset.Id}")) + { + SzApp.AppInstance.ActivateWindow(new SzDatasetViewerWindow(dataset)); + } + ImGui.SameLine(); + if (ImGui.SmallButton($"Delete##{dataset.Id}")) + { + _ = Task.Run(async () => { + await SZ.DataHandler.DeleteDatasetAsync(dataset.Id); + RefreshData(); + }); + } + } + ImGui.EndTable(); + } + } + } +} \ No newline at end of file diff --git a/SzGui/Windows/SzTemplateCreatorWindow.cs b/SzGui/Windows/SzTemplateCreatorWindow.cs new file mode 100644 index 0000000..846d578 --- /dev/null +++ b/SzGui/Windows/SzTemplateCreatorWindow.cs @@ -0,0 +1,66 @@ +using ImGuiNET; +using SzCore; +using SzCore.DataObjects; + +namespace SzGui.Windows; + +public class SzTemplateCreatorWindow : SzGuiWindowBase +{ + private string _name = ""; + private string _type = ""; + private List _fields = new(); + + private string _newFieldId = ""; + private int _selectedTypeIndex = 0; + + public SzTemplateCreatorWindow() => WindowName = "Template Creator"; + + protected override void RenderContent() + { + ImGui.InputText("Template Name", ref _name, 64); + ImGui.InputText("Object Type", ref _type, 64); + + ImGui.SeparatorText("Fields"); + + for (int i = 0; i < _fields.Count; i++) + { + ImGui.BulletText($"{_fields[i].Id} ({_fields[i].FieldType})"); + ImGui.SameLine(); + if (ImGui.Button($"Remove##{i}")) _fields.RemoveAt(i); + } + + ImGui.Separator(); + + ImGui.InputText("Field ID", ref _newFieldId, 64); + + string[] typeNames = Enum.GetNames(); + ImGui.Combo("Type", ref _selectedTypeIndex, typeNames, typeNames.Length); + + if (ImGui.Button("Add Field")) + { + var result = SZ.DataHandler.CreateTemplateField(_newFieldId, (SzFieldType)_selectedTypeIndex); + if (result.IsSuccess) + { + _fields.Add(result.Value!); + _newFieldId = ""; // Reset + } + } + + ImGui.Separator(); + + if (ImGui.Button("Save Template", new System.Numerics.Vector2(0, 30))) + { + Save(); + } + } + + private async void Save() + { + var result = SZ.DataHandler.CreateDataObjectTemplate(_name, _type, fields: _fields); + if (result.IsSuccess) + { + await SZ.DataHandler.SaveTemplateAsync(result.Value!); + IsOpen = false; + } + } +} \ No newline at end of file diff --git a/SzGui/imgui.ini b/SzGui/imgui.ini index 09d83fd..0c19bdd 100644 --- a/SzGui/imgui.ini +++ b/SzGui/imgui.ini @@ -1,23 +1,25 @@ [Window][Debug##Default] -Pos=1006,402 -Size=762,814 +Pos=637,781 +Size=776,368 Collapsed=0 [Window][SessionZero] Pos=0,0 -Size=3792,2067 +Size=1692,1377 Collapsed=0 -DockId=0x08BD597D,0 +DockId=0x00000001,1 [Window][Dear ImGui Demo] -Size=1894,2067 +Pos=0,0 +Size=1692,1377 Collapsed=0 -DockId=0x08BD597D,0 +DockId=0x00000001,0 [Window][Dear ImGui Style Editor] -Pos=96,60 -Size=692,1365 +Pos=1694,0 +Size=834,1377 Collapsed=0 +DockId=0x00000002,0 [Window][Example: Assets Browser] Pos=60,60 @@ -61,7 +63,7 @@ Size=300,409 [Window][WindowOverViewport_11111111] Pos=0,0 -Size=3792,2067 +Size=2528,1377 Collapsed=0 [Table][0xB6880529,2] @@ -74,6 +76,8 @@ Column 0 Width=4 Column 1 Weight=2.0000 [Docking][Data] -DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,0 Size=3792,2067 CentralNode=1 Selected=0x3C0097EB -DockSpace ID=0xC0DFADC4 Pos=0,38 Size=3840,2122 CentralNode=1 +DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,0 Size=2528,1377 Split=X Selected=0x5E5F7166 + DockNode ID=0x00000001 Parent=0x08BD597D SizeRef=1692,1377 CentralNode=1 Selected=0x5E5F7166 + DockNode ID=0x00000002 Parent=0x08BD597D SizeRef=834,1377 Selected=0x3EEA4247 +DockSpace ID=0xC0DFADC4 Pos=0,38 Size=3840,2122 CentralNode=1