From 8b6adfbcd443d0b0da18b17463c21b120f2d12b0 Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Mon, 19 Aug 2024 06:19:07 +0800 Subject: [PATCH 01/17] Modify function to conform to review feedback --- source/creator/core/settings.d | 6 ++++++ source/creator/viewport/package.d | 33 +++++++++++-------------------- source/creator/windows/settings.d | 10 ++++------ 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/source/creator/core/settings.d b/source/creator/core/settings.d index 217966de6..4a16e2cf6 100644 --- a/source/creator/core/settings.d +++ b/source/creator/core/settings.d @@ -24,6 +24,12 @@ string incSettingsPath() { void incSettingsLoad() { if (exists(incSettingsPath())) { settings = parseJSON(readText(incSettingsPath())); + } else { + // This code is used to configure default values for new users + // New users use MousePosition, old users keep ScreenCenter + // also see incGetViewportZoomMode() + settings["ViewportZoomMode"] = "MousePosition"; + settings["ViewportZoomSpeed"] = 5.0; } } diff --git a/source/creator/viewport/package.d b/source/creator/viewport/package.d index 5e6456d9a..38953484e 100644 --- a/source/creator/viewport/package.d +++ b/source/creator/viewport/package.d @@ -849,14 +849,14 @@ private { } // HANDLE ZOOM - string zoomMode = incGetCurrentViewportZoomMode(); - if (zoomMode == "legacy-zooming") - incViewportZoomLegacy(io, camera, uiScale); - else if (zoomMode == "normal") - incViewportZoomNew(io, camera, uiScale); + string zoomMode = incGetViewportZoomMode(); + if (zoomMode == "ScreenCenter") + incViewportZoomToCenter(io, camera, uiScale); + else if (zoomMode == "MousePosition") + incViewportZoomToMouse(io, camera, uiScale); } - void incViewportZoomNew(ImGuiIO* io, Camera camera, float uiScale) { + void incViewportZoomToMouse(ImGuiIO* io, Camera camera, float uiScale) { // This value changes the zoom speed float speed = incGetViewportZoomSpeed(); if (io.MouseWheel != 0) { @@ -886,7 +886,7 @@ private { } } - void incViewportZoomLegacy(ImGuiIO* io, Camera camera, float uiScale) { + void incViewportZoomToCenter(ImGuiIO* io, Camera camera, float uiScale) { float speed = incGetViewportZoomSpeed(); if (io.MouseWheel != 0) { incViewportZoom += (io.MouseWheel/50*speed)*incViewportZoom*uiScale; @@ -897,24 +897,13 @@ private { } } -string[] incGetViewportZoomModes() { - return ["normal", "legacy-zooming"]; -} - -string incGetCurrentViewportZoomMode() { +string incGetViewportZoomMode() { if (incSettingsCanGet("ViewportZoomMode")) return incSettingsGet!string("ViewportZoomMode"); else - return "normal"; + return "ScreenCenter"; } - -bool incSetCurrentViewportZoomMode(string select) { - string[] viewportZoomModes = incGetViewportZoomModes(); - - // Verify zoom mode conifg - if (viewportZoomModes.canFind(select) == -1) - return false; - +bool incSetViewportZoomMode(string select) { incSettingsSet("ViewportZoomMode", select); return true; } @@ -923,7 +912,7 @@ float incGetViewportZoomSpeed() { if (incSettingsCanGet("ViewportZoomSpeed")) return incSettingsGet!float("ViewportZoomSpeed"); else - return 5.0; + return 1.0; } bool incSetViewportZoomSpeed(float speed) { diff --git a/source/creator/windows/settings.d b/source/creator/windows/settings.d index 4255d37eb..f716b391e 100644 --- a/source/creator/windows/settings.d +++ b/source/creator/windows/settings.d @@ -190,13 +190,11 @@ protected: break; case SettingsPane.Viewport: beginSection(__("Viewport")); - string selected = incGetCurrentViewportZoomMode(); + string selected = incGetViewportZoomMode(); if(igBeginCombo(__("Zoom Mode"), selected.toStringz)) { - foreach (options; incGetViewportZoomModes()) { - if (igSelectable(options.toStringz)) { - incSetCurrentViewportZoomMode(options); - } - } + if (igSelectable(__("To Screen Center"), incSettingsGet!string("ViewportZoomMode") == "ScreenCenter")) incSetViewportZoomMode("ScreenCenter"); + if (igSelectable(__("To Mouse Position"), incSettingsGet!string("ViewportZoomMode") == "MousePosition")) incSetViewportZoomMode("MousePosition"); + igEndCombo(); } From ce2e3a00d5a0acf1aa069fe55d0393c686070cf6 Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Tue, 20 Aug 2024 08:40:16 +0800 Subject: [PATCH 02/17] Rename "Autosaves" Pane to "File Handling" to make it more versatile. --- source/creator/windows/settings.d | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/creator/windows/settings.d b/source/creator/windows/settings.d index f716b391e..c21a235e9 100644 --- a/source/creator/windows/settings.d +++ b/source/creator/windows/settings.d @@ -22,7 +22,7 @@ enum SettingsPane : string { LookAndFeel = "Look and Feel", Viewport = "Viewport", Accessibility = "Accessbility", - Autosaves = "Autosaves" + FileHandling = "FileHandling" } /** @@ -89,8 +89,8 @@ protected: settingsPane = SettingsPane.Accessibility; } - if (igSelectable(__("Autosaves"), settingsPane == SettingsPane.Autosaves)) { - settingsPane = SettingsPane.Autosaves; + if (igSelectable(__("File Handling"), settingsPane == SettingsPane.FileHandling)) { + settingsPane = SettingsPane.FileHandling; } igPopTextWrapPos(); } @@ -170,7 +170,7 @@ protected: incTooltip(_("Use the OpenDyslexic font for Latin text characters.")); endSection(); break; - case SettingsPane.Autosaves: + case SettingsPane.FileHandling: beginSection(__("Autosaves")); bool autosaveEnabled = incGetAutosaveEnabled(); if (igCheckbox(__("Enable Autosaves"), &autosaveEnabled)) { From 11888359691cf20361a8561396ee440ccf19d0c6 Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Tue, 20 Aug 2024 09:35:56 +0800 Subject: [PATCH 03/17] Fixed inconsistent display of "Zoom Mode" configuration --- source/creator/windows/settings.d | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/creator/windows/settings.d b/source/creator/windows/settings.d index c21a235e9..16a608f50 100644 --- a/source/creator/windows/settings.d +++ b/source/creator/windows/settings.d @@ -190,7 +190,12 @@ protected: break; case SettingsPane.Viewport: beginSection(__("Viewport")); - string selected = incGetViewportZoomMode(); + string[string] configShowing = [ + "ScreenCenter": "To Screen Center", + "MousePosition": "To Mouse Position" + ]; + + string selected = configShowing[incGetViewportZoomMode()]; if(igBeginCombo(__("Zoom Mode"), selected.toStringz)) { if (igSelectable(__("To Screen Center"), incSettingsGet!string("ViewportZoomMode") == "ScreenCenter")) incSetViewportZoomMode("ScreenCenter"); if (igSelectable(__("To Mouse Position"), incSettingsGet!string("ViewportZoomMode") == "MousePosition")) incSetViewportZoomMode("MousePosition"); From c8724e6a8d329da5f23296aeeaeca933d856a2d2 Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Tue, 20 Aug 2024 10:08:08 +0800 Subject: [PATCH 04/17] Refactor problematic code --- source/creator/io/package.d | 51 +++++++++++-------------------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/source/creator/io/package.d b/source/creator/io/package.d index 9931f040e..a608a10a1 100644 --- a/source/creator/io/package.d +++ b/source/creator/io/package.d @@ -73,6 +73,13 @@ private { } } +string incToDString(c_str cstr1) { + if (cstr1 !is null) { + return cast(string) cstr1.fromStringz; + } + return null; +} + string incShowImportDialog(const(TFD_Filter)[] filters, string title, bool multiple = false) { version (linux) { try { @@ -86,19 +93,11 @@ string incShowImportDialog(const(TFD_Filter)[] filters, string title, bool multi // FALLBACK: If xdg-desktop-portal is not available then try tinyfiledialogs. c_str filename = tinyfd_openFileDialog(title.toStringz, "", filters, multiple); - if (filename !is null) { - string file = cast(string) filename.fromStringz; - return file; - } - return null; + return incToDString(filename); } } else { c_str filename = tinyfd_openFileDialog(title.toStringz, "", filters, multiple); - if (filename !is null) { - string file = cast(string) filename.fromStringz; - return file; - } - return null; + return incToDString(filename); } } @@ -114,15 +113,11 @@ string incShowOpenFolderDialog(string title = "Open...") { // FALLBACK: If xdg-desktop-portal is not available then try tinyfiledialogs. c_str filename = tinyfd_selectFolderDialog(title.toStringz, null); - if (filename !is null) - return cast(string) filename.fromStringz; - return null; + return incToDString(filename); } } else { c_str filename = tinyfd_selectFolderDialog(title.toStringz, null); - if (filename !is null) - return cast(string) filename.fromStringz; - return null; + return incToDString(filename); } } @@ -138,19 +133,11 @@ string incShowOpenDialog(const(TFD_Filter)[] filters, string title = "Open...") // FALLBACK: If xdg-desktop-portal is not available then try tinyfiledialogs. c_str filename = tinyfd_openFileDialog(title.toStringz, "", filters, false); - if (filename !is null) { - string file = cast(string) filename.fromStringz; - return file; - } - return null; + return incToDString(filename); } } else { c_str filename = tinyfd_openFileDialog(title.toStringz, "", filters, false); - if (filename !is null) { - string file = cast(string) filename.fromStringz; - return file; - } - return null; + return incToDString(filename); } } @@ -166,19 +153,11 @@ string incShowSaveDialog(const(TFD_Filter)[] filters, string fname, string title // FALLBACK: If xdg-desktop-portal is not available then try tinyfiledialogs. c_str filename = tinyfd_saveFileDialog(title.toStringz, fname.toStringz, filters); - if (filename !is null) { - string file = cast(string) filename.fromStringz; - return file; - } - return null; + return incToDString(filename); } } else { c_str filename = tinyfd_saveFileDialog(title.toStringz, fname.toStringz, filters); - if (filename !is null) { - string file = cast(string) filename.fromStringz; - return file; - } - return null; + return incToDString(filename); } } From aeb8d873ef5bed16c8bea016ab77bede5760c1ec Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Tue, 20 Aug 2024 11:32:59 +0800 Subject: [PATCH 05/17] Allow user configuration to import preserve folder structure --- source/creator/core/settings.d | 7 +++- source/creator/io/kra.d | 33 +++++++++++++--- source/creator/io/package.d | 64 +++++++++++++++++++++++++++++++ source/creator/io/psd.d | 52 ++++++++++++++++++++++--- source/creator/panels/viewport.d | 7 +++- source/creator/windows/settings.d | 22 ++++++++++- 6 files changed, 170 insertions(+), 15 deletions(-) diff --git a/source/creator/core/settings.d b/source/creator/core/settings.d index 4a16e2cf6..3818a4b01 100644 --- a/source/creator/core/settings.d +++ b/source/creator/core/settings.d @@ -30,6 +30,11 @@ void incSettingsLoad() { // also see incGetViewportZoomMode() settings["ViewportZoomMode"] = "MousePosition"; settings["ViewportZoomSpeed"] = 5.0; + + // File Handling + // Always ask the user whether to preserve the folder structure during import + // also see incGetKeepLayerFolder() + settings["KeepLayerFolder"] = "Ask"; } } @@ -97,4 +102,4 @@ T incSettingsGet(T)(string name, T default_) { */ bool incSettingsCanGet(string name) { return (name in settings) !is null; -} \ No newline at end of file +} diff --git a/source/creator/io/kra.d b/source/creator/io/kra.d index d106eeb19..adbb4edf4 100644 --- a/source/creator/io/kra.d +++ b/source/creator/io/kra.d @@ -24,12 +24,7 @@ private { bool incImportShowKRADialog() { TFD_Filter[] filters = [{ ["*.kra"], "Krita Document (*.kra)" }]; string file = incShowImportDialog(filters, _("Import...")); - - if (file) { - incImportKRA(file, IncKRAImportSettings(false)); - return true; - } - return false; + return incAskImportKRA(file); } class IncKRALayer { @@ -142,8 +137,34 @@ struct IncKRAImportSettings { bool keepStructure = false; } +/** + Imports a KRA file with user prompt. + also see incAskImportPSD() +*/ +bool incAskImportKRA(string file) { + if (!file) + return false; + + // Note: currently KRA not supported Preserve layer structure, so we just skip the dialog + // until we have a proper implementation. + // switch (incImportKeepFolderStructPop()) { + switch ("NotPreserve") { + case "NotPreserve": + incImportKRA(file, IncKRAImportSettings(false)); + return true; + case "Preserve": + incImportKRA(file, IncKRAImportSettings(true)); + return true; + case "Cancel": + return false; + default: + throw new Exception("Invalid selection"); + } +} + /** Imports a KRA file. + Note: You should invoke incAskImportKRA for UI interaction. */ void incImportKRA(string file, IncKRAImportSettings settings = IncKRAImportSettings.init) { incNewProject(); diff --git a/source/creator/io/package.d b/source/creator/io/package.d index a608a10a1..30d60fc28 100644 --- a/source/creator/io/package.d +++ b/source/creator/io/package.d @@ -161,6 +161,30 @@ string incShowSaveDialog(const(TFD_Filter)[] filters, string fname, string title } } +string incMessageBox(string title, string message, string dialogType = "ok", string iconType = "info", int defaultButton = 0) { + // is necessary check on linux? + int result = tinyfd_messageBox( + title.toStringz, + message.toStringz, + dialogType.toStringz, + iconType.toStringz, + defaultButton + ); + + // tinyfd api may make confusion with the return value + // so we need to convert it to a more readable string + if (dialogType == "yesnocancel") { + switch (result) { + case 0: return "cancel"; + case 1: return "yes"; + case 2: return "no"; + default: assert(0); + } + } else { + throw new Exception("Not implemented"); + } +} + // // Reusable basic loaders // @@ -200,3 +224,43 @@ void incCreatePartsFromFiles(string[] files) { } } } + +string incGetKeepLayerFolder() { + if (incSettingsCanGet("KeepLayerFolder")) + return incSettingsGet!string("KeepLayerFolder"); + else + // also see incSettingsLoad() + // Preserve the original behavior for existing users + return "NotPreserve"; +} + +bool incSetKeepLayerFolder(string select) { + incSettingsSet("KeepLayerFolder", select); + return true; +} + +/** + Function for importing pop-up dialog + returns "Preserve" or "NotPreserve" or "Cancel" +*/ +string incImportKeepFolderStructPop() { + if (incGetKeepLayerFolder() == "Preserve") + return "Preserve"; + if (incGetKeepLayerFolder() == "NotPreserve") + return "NotPreserve"; + + string result = incMessageBox( + "Import File", + "Do you want to preserve the folder structure of the imported file? You can change this in the settings.", + "yesnocancel", + "info" + ); + + if (result == "yes") + return "Preserve"; + + if (result == "no") + return "NotPreserve"; + + return "Cancel"; +} \ No newline at end of file diff --git a/source/creator/io/psd.d b/source/creator/io/psd.d index 54338f32a..3bd6bcc2a 100644 --- a/source/creator/io/psd.d +++ b/source/creator/io/psd.d @@ -24,12 +24,7 @@ private { bool incImportShowPSDDialog() { TFD_Filter[] filters = [{ ["*.psd"], "Photoshop Document (*.psd)" }]; string file = incShowImportDialog(filters, _("Import...")); - - if (file) { - incImportPSD(file, IncPSDImportSettings(false)); - return true; - } - return false; + return incAskImportPSD(file); } class IncPSDLayer { @@ -142,8 +137,53 @@ struct IncPSDImportSettings { bool keepStructure = false; } +/** + Imports a PSD file with user prompt. + also see incAskImportKRA() +*/ +bool incAskImportPSD(string file) { + if (!file) + return false; + + switch (incImportKeepFolderStructPop()) { + case "NotPreserve": + incImportPSD(file, IncPSDImportSettings(false)); + return true; + case "Preserve": + incImportPSD(file, IncPSDImportSettings(true)); + return true; + case "Cancel": + return false; + default: + throw new Exception("Invalid selection"); + } +} + +/** + Imports a PSD file with user prompt. + also see incAskImportKRA() +*/ +bool incAskImportPSD(string file) { + if (!file) + return false; + + switch (incImportKeepFolderStructPop()) { + case "NotPreserve": + incImportPSD(file, IncPSDImportSettings(false)); + return true; + case "Preserve": + incImportPSD(file, IncPSDImportSettings(true)); + return true; + case "Cancel": + return false; + default: + throw new Exception("Invalid selection"); + } +} + /** Imports a PSD file. + Note: You should invoke incAskImportPSD for UI interaction. */ void incImportPSD(string file, IncPSDImportSettings settings = IncPSDImportSettings.init) { incNewProject(); diff --git a/source/creator/panels/viewport.d b/source/creator/panels/viewport.d index 7aebdbecd..ad2db4235 100644 --- a/source/creator/panels/viewport.d +++ b/source/creator/panels/viewport.d @@ -235,7 +235,12 @@ protected: // Allow dragging PSD in to main window case ".psd": - incImportPSD(file); + incAskImportPSD(file); + break mainLoop; + + // Allow dragging KRA in to main window + case ".kra": + incAskImportKRA(file); break mainLoop; default: diff --git a/source/creator/windows/settings.d b/source/creator/windows/settings.d index 16a608f50..63048d91d 100644 --- a/source/creator/windows/settings.d +++ b/source/creator/windows/settings.d @@ -10,6 +10,7 @@ import creator.viewport; import creator.widgets; import creator.core; import creator.core.i18n; +import creator.io; import creator.io.autosave; import std.string; import creator.utils.link; @@ -187,6 +188,25 @@ protected: incSetAutosaveFileLimit(saveFileLimit); } endSection(); + + // we mark PSD only until we have a proper implementation for kra + beginSection(__("Preserve Imported File Folder Structure (Currently PSD only)")); + string[string] configShowing = [ + "Ask": "Always Ask", + "Preserve": "Preserve", + "NotPreserve": "Not Preserve" + ]; + + string selected = configShowing[incGetKeepLayerFolder()]; + if(igBeginCombo(__("Preserve Folder Structure"), selected.toStringz)) { + if (igSelectable(__("Always Ask"), incSettingsGet!string("KeepLayerFolder") == "Ask")) incSetKeepLayerFolder("Ask"); + if (igSelectable(__("Preserve"), incSettingsGet!string("KeepLayerFolder") == "Preserve")) incSetKeepLayerFolder("Preserve"); + if (igSelectable(__("Not Preserve"), incSettingsGet!string("KeepLayerFolder") == "NotPreserve")) incSetKeepLayerFolder("NotPreserve"); + + igEndCombo(); + } + + endSection(); break; case SettingsPane.Viewport: beginSection(__("Viewport")); @@ -250,4 +270,4 @@ public: targetUIScale = incGetUIScale(); tmpUIScale = cast(int)(incGetUIScale()*100); } -} \ No newline at end of file +} From 255d4b7e3178da74d1a16f36e4960ed4226cc254 Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Tue, 20 Aug 2024 11:39:08 +0800 Subject: [PATCH 06/17] Update based on review feedback --- source/creator/windows/settings.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/creator/windows/settings.d b/source/creator/windows/settings.d index 63048d91d..d825fbf06 100644 --- a/source/creator/windows/settings.d +++ b/source/creator/windows/settings.d @@ -23,7 +23,7 @@ enum SettingsPane : string { LookAndFeel = "Look and Feel", Viewport = "Viewport", Accessibility = "Accessbility", - FileHandling = "FileHandling" + FileHandling = "File Handling" } /** From d2327a8f5c86967d9c7ae0f553c123c9305fd7ba Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Tue, 20 Aug 2024 13:35:39 +0800 Subject: [PATCH 07/17] Refactor incMessageBox() with enum args and return value --- source/creator/io/package.d | 96 ++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 27 deletions(-) diff --git a/source/creator/io/package.d b/source/creator/io/package.d index 30d60fc28..5b8c7f557 100644 --- a/source/creator/io/package.d +++ b/source/creator/io/package.d @@ -161,23 +161,33 @@ string incShowSaveDialog(const(TFD_Filter)[] filters, string fname, string title } } -string incMessageBox(string title, string message, string dialogType = "ok", string iconType = "info", int defaultButton = 0) { - // is necessary check on linux? - int result = tinyfd_messageBox( - title.toStringz, - message.toStringz, - dialogType.toStringz, - iconType.toStringz, - defaultButton - ); - - // tinyfd api may make confusion with the return value - // so we need to convert it to a more readable string - if (dialogType == "yesnocancel") { - switch (result) { - case 0: return "cancel"; - case 1: return "yes"; - case 2: return "no"; +enum DialogButton { + Cancel, Yes, No +} + +enum DialogType : c_str { + Ok = "ok", + OkCancel = "okcancel", + YesNo = "yesno", + YesNoCancel = "yesnocancel" +} + +enum IconType : c_str { + Info = "info", + Warning = "warning", + Error = "error", + Question = "question" +} + +// tinyfd api may make confusion with the button id +// 0 cancel/no, 1 ok/yes , 2 no in yesnocancel +// so we need to impelement incConvertToTinyfdButton() and incTinyfdToDialogButton() +int incConvertToTinyfdButton(DialogButton button, DialogType dialogType) { + if (dialogType == DialogType.YesNoCancel) { + switch (button) { + case DialogButton.Cancel: return 0; + case DialogButton.Yes: return 1; + case DialogButton.No: return 2; default: assert(0); } } else { @@ -185,6 +195,39 @@ string incMessageBox(string title, string message, string dialogType = "ok", str } } +DialogButton incTinyfdToDialogButton(int button, DialogType dialogType) { + if (dialogType == DialogType.YesNoCancel) { + switch (button) { + case 0: return DialogButton.Cancel; + case 1: return DialogButton.Yes; + case 2: return DialogButton.No; + default: assert(0); + } + } else { + throw new Exception("Not implemented"); + } +} + +// TODO: incConvertToTinyfdButton() / incTinyfdToDialogButton() unit test? + +DialogButton incMessageBox( + string title, string message, + DialogType dialogType = DialogType.Ok, + IconType iconType = IconType.Info, + DialogButton defaultButton = DialogButton.Cancel + ) { + // is necessary check on linux? or just using tinyfd_messageBox? + int result = tinyfd_messageBox( + title.toStringz, + message.toStringz, + dialogType, + iconType, + incConvertToTinyfdButton(defaultButton, dialogType), + ); + + return incTinyfdToDialogButton(result, dialogType); +} + // // Reusable basic loaders // @@ -249,18 +292,17 @@ string incImportKeepFolderStructPop() { if (incGetKeepLayerFolder() == "NotPreserve") return "NotPreserve"; - string result = incMessageBox( + DialogButton result = incMessageBox( "Import File", "Do you want to preserve the folder structure of the imported file? You can change this in the settings.", - "yesnocancel", - "info" + DialogType.YesNoCancel, + IconType.Question, ); - if (result == "yes") - return "Preserve"; - - if (result == "no") - return "NotPreserve"; - - return "Cancel"; + switch (result) { + case DialogButton.Cancel: return "Cancel"; + case DialogButton.Yes: return "Preserve"; + case DialogButton.No: return "NotPreserve"; + default: assert(0); + } } \ No newline at end of file From e6e628bbf85d3302510a4b42417cc7be15f1bffe Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Tue, 20 Aug 2024 13:58:30 +0800 Subject: [PATCH 08/17] refector incImportKeepFolderStructPop() with enum return value --- source/creator/io/kra.d | 8 ++++---- source/creator/io/package.d | 19 +++++++++++++------ source/creator/io/psd.d | 6 +++--- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/source/creator/io/kra.d b/source/creator/io/kra.d index adbb4edf4..6e26254a3 100644 --- a/source/creator/io/kra.d +++ b/source/creator/io/kra.d @@ -148,14 +148,14 @@ bool incAskImportKRA(string file) { // Note: currently KRA not supported Preserve layer structure, so we just skip the dialog // until we have a proper implementation. // switch (incImportKeepFolderStructPop()) { - switch ("NotPreserve") { - case "NotPreserve": + switch (AskKeepLayerFolder.NotPreserve) { + case AskKeepLayerFolder.NotPreserve: incImportKRA(file, IncKRAImportSettings(false)); return true; - case "Preserve": + case AskKeepLayerFolder.Preserve: incImportKRA(file, IncKRAImportSettings(true)); return true; - case "Cancel": + case AskKeepLayerFolder.Cancel: return false; default: throw new Exception("Invalid selection"); diff --git a/source/creator/io/package.d b/source/creator/io/package.d index 5b8c7f557..0f79605a0 100644 --- a/source/creator/io/package.d +++ b/source/creator/io/package.d @@ -282,15 +282,19 @@ bool incSetKeepLayerFolder(string select) { return true; } +enum AskKeepLayerFolder { + Preserve, NotPreserve, Cancel +} + /** Function for importing pop-up dialog returns "Preserve" or "NotPreserve" or "Cancel" */ -string incImportKeepFolderStructPop() { +AskKeepLayerFolder incImportKeepFolderStructPop() { if (incGetKeepLayerFolder() == "Preserve") - return "Preserve"; + return AskKeepLayerFolder.Preserve; if (incGetKeepLayerFolder() == "NotPreserve") - return "NotPreserve"; + return AskKeepLayerFolder.NotPreserve; DialogButton result = incMessageBox( "Import File", @@ -300,9 +304,12 @@ string incImportKeepFolderStructPop() { ); switch (result) { - case DialogButton.Cancel: return "Cancel"; - case DialogButton.Yes: return "Preserve"; - case DialogButton.No: return "NotPreserve"; + case DialogButton.Cancel: + return AskKeepLayerFolder.Cancel; + case DialogButton.Yes: + return AskKeepLayerFolder.Preserve; + case DialogButton.No: + return AskKeepLayerFolder.NotPreserve; default: assert(0); } } \ No newline at end of file diff --git a/source/creator/io/psd.d b/source/creator/io/psd.d index 3bd6bcc2a..df55f3f83 100644 --- a/source/creator/io/psd.d +++ b/source/creator/io/psd.d @@ -168,13 +168,13 @@ bool incAskImportPSD(string file) { return false; switch (incImportKeepFolderStructPop()) { - case "NotPreserve": + case AskKeepLayerFolder.NotPreserve: incImportPSD(file, IncPSDImportSettings(false)); return true; - case "Preserve": + case AskKeepLayerFolder.Preserve: incImportPSD(file, IncPSDImportSettings(true)); return true; - case "Cancel": + case AskKeepLayerFolder.Cancel: return false; default: throw new Exception("Invalid selection"); From 497eb856be3f7024ae16a129ec0bb546ddd965a3 Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Tue, 20 Aug 2024 14:02:46 +0800 Subject: [PATCH 09/17] rename incConvertToTinyfdButton() to incDialogButtonToTinyfd() --- source/creator/io/package.d | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/creator/io/package.d b/source/creator/io/package.d index 0f79605a0..800f312ec 100644 --- a/source/creator/io/package.d +++ b/source/creator/io/package.d @@ -181,8 +181,8 @@ enum IconType : c_str { // tinyfd api may make confusion with the button id // 0 cancel/no, 1 ok/yes , 2 no in yesnocancel -// so we need to impelement incConvertToTinyfdButton() and incTinyfdToDialogButton() -int incConvertToTinyfdButton(DialogButton button, DialogType dialogType) { +// so we need to impelement incDialogButtonToTinyfd() and incTinyfdToDialogButton() +int incDialogButtonToTinyfd(DialogButton button, DialogType dialogType) { if (dialogType == DialogType.YesNoCancel) { switch (button) { case DialogButton.Cancel: return 0; @@ -208,7 +208,7 @@ DialogButton incTinyfdToDialogButton(int button, DialogType dialogType) { } } -// TODO: incConvertToTinyfdButton() / incTinyfdToDialogButton() unit test? +// TODO: incDialogButtonToTinyfd() / incTinyfdToDialogButton() unit test? DialogButton incMessageBox( string title, string message, @@ -222,7 +222,7 @@ DialogButton incMessageBox( message.toStringz, dialogType, iconType, - incConvertToTinyfdButton(defaultButton, dialogType), + incDialogButtonToTinyfd(defaultButton, dialogType), ); return incTinyfdToDialogButton(result, dialogType); From ce17ff3db7454d0f211ee889d0b572ebac7452b6 Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Tue, 20 Aug 2024 15:26:03 +0800 Subject: [PATCH 10/17] reuse DialogButton enum in dialog.d --- source/creator/io/package.d | 38 ++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/source/creator/io/package.d b/source/creator/io/package.d index 800f312ec..ea67d2c6c 100644 --- a/source/creator/io/package.d +++ b/source/creator/io/package.d @@ -10,6 +10,7 @@ public import creator.io.kra; public import creator.io.inpexport; public import creator.io.videoexport; public import creator.io.imageexport; +import creator.widgets: DialogButtons; import tinyfiledialogs; public import tinyfiledialogs : TFD_Filter; @@ -161,10 +162,6 @@ string incShowSaveDialog(const(TFD_Filter)[] filters, string fname, string title } } -enum DialogButton { - Cancel, Yes, No -} - enum DialogType : c_str { Ok = "ok", OkCancel = "okcancel", @@ -182,12 +179,12 @@ enum IconType : c_str { // tinyfd api may make confusion with the button id // 0 cancel/no, 1 ok/yes , 2 no in yesnocancel // so we need to impelement incDialogButtonToTinyfd() and incTinyfdToDialogButton() -int incDialogButtonToTinyfd(DialogButton button, DialogType dialogType) { +int incDialogButtonToTinyfd(DialogButtons button, DialogType dialogType) { if (dialogType == DialogType.YesNoCancel) { switch (button) { - case DialogButton.Cancel: return 0; - case DialogButton.Yes: return 1; - case DialogButton.No: return 2; + case DialogButtons.Cancel: return 0; + case DialogButtons.Yes: return 1; + case DialogButtons.No: return 2; default: assert(0); } } else { @@ -195,12 +192,12 @@ int incDialogButtonToTinyfd(DialogButton button, DialogType dialogType) { } } -DialogButton incTinyfdToDialogButton(int button, DialogType dialogType) { +DialogButtons incTinyfdToDialogButton(int button, DialogType dialogType) { if (dialogType == DialogType.YesNoCancel) { switch (button) { - case 0: return DialogButton.Cancel; - case 1: return DialogButton.Yes; - case 2: return DialogButton.No; + case 0: return DialogButtons.Cancel; + case 1: return DialogButtons.Yes; + case 2: return DialogButtons.No; default: assert(0); } } else { @@ -209,12 +206,15 @@ DialogButton incTinyfdToDialogButton(int button, DialogType dialogType) { } // TODO: incDialogButtonToTinyfd() / incTinyfdToDialogButton() unit test? - -DialogButton incMessageBox( +/* +* incMessageBox provides a simple message box dialog +* also see `incDialog` and `incDialogButtonSelected` in `source/nijigenerate/widgets/dialog.d` We might be able to unify the function. +*/ +DialogButtons incMessageBox( string title, string message, DialogType dialogType = DialogType.Ok, IconType iconType = IconType.Info, - DialogButton defaultButton = DialogButton.Cancel + DialogButtons defaultButton = DialogButtons.Cancel ) { // is necessary check on linux? or just using tinyfd_messageBox? int result = tinyfd_messageBox( @@ -296,7 +296,7 @@ AskKeepLayerFolder incImportKeepFolderStructPop() { if (incGetKeepLayerFolder() == "NotPreserve") return AskKeepLayerFolder.NotPreserve; - DialogButton result = incMessageBox( + DialogButtons result = incMessageBox( "Import File", "Do you want to preserve the folder structure of the imported file? You can change this in the settings.", DialogType.YesNoCancel, @@ -304,11 +304,11 @@ AskKeepLayerFolder incImportKeepFolderStructPop() { ); switch (result) { - case DialogButton.Cancel: + case DialogButtons.Cancel: return AskKeepLayerFolder.Cancel; - case DialogButton.Yes: + case DialogButtons.Yes: return AskKeepLayerFolder.Preserve; - case DialogButton.No: + case DialogButtons.No: return AskKeepLayerFolder.NotPreserve; default: assert(0); } From c50feb576f8c9a7f0fe0a35c14bcee42d4e5df7e Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Sat, 24 Aug 2024 19:53:55 +0800 Subject: [PATCH 11/17] Implement class DialogHandler and remove incMessageBox() to avoid environmental issues --- source/creator/core/package.d | 3 +- source/creator/io/kra.d | 44 ++++--- source/creator/io/package.d | 142 ++++++++--------------- source/creator/io/psd.d | 40 ++++--- source/creator/viewport/vertex/package.d | 1 + source/creator/widgets/dialog.d | 50 ++++++++ 6 files changed, 160 insertions(+), 120 deletions(-) diff --git a/source/creator/core/package.d b/source/creator/core/package.d index ad0e58cb4..e1eaa71f6 100644 --- a/source/creator/core/package.d +++ b/source/creator/core/package.d @@ -22,7 +22,6 @@ import std.exception; import bindbc.sdl; import bindbc.opengl; import inochi2d; -import tinyfiledialogs; import std.string; import std.stdio; import std.conv; @@ -629,6 +628,8 @@ void incBeginLoopNoEv() { incRenderDialogs(); } incStatusUpdate(); + + incHandleDialogHandlers(); } void incSetDefaultLayout() { diff --git a/source/creator/io/kra.d b/source/creator/io/kra.d index 6e26254a3..4066b6794 100644 --- a/source/creator/io/kra.d +++ b/source/creator/io/kra.d @@ -142,23 +142,39 @@ struct IncKRAImportSettings { also see incAskImportPSD() */ bool incAskImportKRA(string file) { - if (!file) - return false; + if (!file) return false; // Note: currently KRA not supported Preserve layer structure, so we just skip the dialog // until we have a proper implementation. - // switch (incImportKeepFolderStructPop()) { - switch (AskKeepLayerFolder.NotPreserve) { - case AskKeepLayerFolder.NotPreserve: - incImportKRA(file, IncKRAImportSettings(false)); - return true; - case AskKeepLayerFolder.Preserve: - incImportKRA(file, IncKRAImportSettings(true)); - return true; - case AskKeepLayerFolder.Cancel: - return false; - default: - throw new Exception("Invalid selection"); + // KRALoadHandler handler = new KRALoadHandler(file); + // return incKeepStructDialog(handler); + + incImportKRA(file, IncKRAImportSettings(false)); + return true; +} + +class KRALoadHandler : ImportKeepHandler { + private string file; + + this(string file) { + super(); + this.file = file; + } + + override + bool load(AskKeepLayerFolder select) { + switch (select) { + case AskKeepLayerFolder.NotPreserve: + incImportKRA(file, IncKRAImportSettings(false)); + return true; + case AskKeepLayerFolder.Preserve: + incImportKRA(file, IncKRAImportSettings(true)); + return true; + case AskKeepLayerFolder.Cancel: + return false; + default: + throw new Exception("Invalid selection"); + } } } diff --git a/source/creator/io/package.d b/source/creator/io/package.d index ea67d2c6c..ffeb15b40 100644 --- a/source/creator/io/package.d +++ b/source/creator/io/package.d @@ -11,6 +11,7 @@ public import creator.io.inpexport; public import creator.io.videoexport; public import creator.io.imageexport; import creator.widgets: DialogButtons; +import creator.widgets.dialog; import tinyfiledialogs; public import tinyfiledialogs : TFD_Filter; @@ -162,72 +163,6 @@ string incShowSaveDialog(const(TFD_Filter)[] filters, string fname, string title } } -enum DialogType : c_str { - Ok = "ok", - OkCancel = "okcancel", - YesNo = "yesno", - YesNoCancel = "yesnocancel" -} - -enum IconType : c_str { - Info = "info", - Warning = "warning", - Error = "error", - Question = "question" -} - -// tinyfd api may make confusion with the button id -// 0 cancel/no, 1 ok/yes , 2 no in yesnocancel -// so we need to impelement incDialogButtonToTinyfd() and incTinyfdToDialogButton() -int incDialogButtonToTinyfd(DialogButtons button, DialogType dialogType) { - if (dialogType == DialogType.YesNoCancel) { - switch (button) { - case DialogButtons.Cancel: return 0; - case DialogButtons.Yes: return 1; - case DialogButtons.No: return 2; - default: assert(0); - } - } else { - throw new Exception("Not implemented"); - } -} - -DialogButtons incTinyfdToDialogButton(int button, DialogType dialogType) { - if (dialogType == DialogType.YesNoCancel) { - switch (button) { - case 0: return DialogButtons.Cancel; - case 1: return DialogButtons.Yes; - case 2: return DialogButtons.No; - default: assert(0); - } - } else { - throw new Exception("Not implemented"); - } -} - -// TODO: incDialogButtonToTinyfd() / incTinyfdToDialogButton() unit test? -/* -* incMessageBox provides a simple message box dialog -* also see `incDialog` and `incDialogButtonSelected` in `source/nijigenerate/widgets/dialog.d` We might be able to unify the function. -*/ -DialogButtons incMessageBox( - string title, string message, - DialogType dialogType = DialogType.Ok, - IconType iconType = IconType.Info, - DialogButtons defaultButton = DialogButtons.Cancel - ) { - // is necessary check on linux? or just using tinyfd_messageBox? - int result = tinyfd_messageBox( - title.toStringz, - message.toStringz, - dialogType, - iconType, - incDialogButtonToTinyfd(defaultButton, dialogType), - ); - - return incTinyfdToDialogButton(result, dialogType); -} - // // Reusable basic loaders // @@ -270,11 +205,11 @@ void incCreatePartsFromFiles(string[] files) { string incGetKeepLayerFolder() { if (incSettingsCanGet("KeepLayerFolder")) - return incSettingsGet!string("KeepLayerFolder"); + return incSettingsGet!string("KeepLayerFolder"); else - // also see incSettingsLoad() - // Preserve the original behavior for existing users - return "NotPreserve"; + // also see incSettingsLoad() + // Preserve the original behavior for existing users + return "NotPreserve"; } bool incSetKeepLayerFolder(string select) { @@ -286,30 +221,53 @@ enum AskKeepLayerFolder { Preserve, NotPreserve, Cancel } +const(char)* INC_KEEP_STRUCT_DIALOG_NAME = "ImportKeepFolderStructPopup"; + /** Function for importing pop-up dialog - returns "Preserve" or "NotPreserve" or "Cancel" */ -AskKeepLayerFolder incImportKeepFolderStructPop() { - if (incGetKeepLayerFolder() == "Preserve") - return AskKeepLayerFolder.Preserve; - if (incGetKeepLayerFolder() == "NotPreserve") - return AskKeepLayerFolder.NotPreserve; - - DialogButtons result = incMessageBox( - "Import File", - "Do you want to preserve the folder structure of the imported file? You can change this in the settings.", - DialogType.YesNoCancel, - IconType.Question, - ); - - switch (result) { - case DialogButtons.Cancel: - return AskKeepLayerFolder.Cancel; - case DialogButtons.Yes: - return AskKeepLayerFolder.Preserve; - case DialogButtons.No: - return AskKeepLayerFolder.NotPreserve; - default: assert(0); +bool incKeepStructDialog(ImportKeepHandler handler) { + if (incGetKeepLayerFolder() == "Preserve") { + handler.load(AskKeepLayerFolder.Preserve); + } else if (incGetKeepLayerFolder() == "NotPreserve") { + handler.load(AskKeepLayerFolder.NotPreserve); + } else { + incRegisterDialogHandler(handler); + + // Show dialog + incDialog( + INC_KEEP_STRUCT_DIALOG_NAME, + __("Import File"), + _("Do you want to preserve the folder structure of the imported file? You can change this in the settings."), + DialogLevel.Warning, + DialogButtons.Yes | DialogButtons.No | DialogButtons.Cancel + ); + } + + return true; +} + +class ImportKeepHandler : DialogHandler { + this () { + super(INC_KEEP_STRUCT_DIALOG_NAME); + } + + override + bool onClick(DialogButtons button) { + switch (button) { + case DialogButtons.Cancel: + return this.load(AskKeepLayerFolder.Cancel); + case DialogButtons.Yes: + return this.load(AskKeepLayerFolder.Preserve); + case DialogButtons.No: + return this.load(AskKeepLayerFolder.NotPreserve); + default: + throw new Exception("Invalid button"); + } + } + + bool load(AskKeepLayerFolder select) { + // override this + return false; } } \ No newline at end of file diff --git a/source/creator/io/psd.d b/source/creator/io/psd.d index df55f3f83..9f785e683 100644 --- a/source/creator/io/psd.d +++ b/source/creator/io/psd.d @@ -164,20 +164,34 @@ bool incAskImportPSD(string file) { also see incAskImportKRA() */ bool incAskImportPSD(string file) { - if (!file) - return false; + if (!file) return false; - switch (incImportKeepFolderStructPop()) { - case AskKeepLayerFolder.NotPreserve: - incImportPSD(file, IncPSDImportSettings(false)); - return true; - case AskKeepLayerFolder.Preserve: - incImportPSD(file, IncPSDImportSettings(true)); - return true; - case AskKeepLayerFolder.Cancel: - return false; - default: - throw new Exception("Invalid selection"); + PSDLoadHandler handler = new PSDLoadHandler(file); + return incKeepStructDialog(handler); +} + +class PSDLoadHandler : ImportKeepHandler { + private string file; + + this(string file) { + super(); + this.file = file; + } + + override + bool load(AskKeepLayerFolder select) { + switch (select) { + case AskKeepLayerFolder.NotPreserve: + incImportPSD(file, IncPSDImportSettings(false)); + return true; + case AskKeepLayerFolder.Preserve: + incImportPSD(file, IncPSDImportSettings(true)); + return true; + case AskKeepLayerFolder.Cancel: + return false; + default: + throw new Exception("Invalid selection"); + } } } diff --git a/source/creator/viewport/vertex/package.d b/source/creator/viewport/vertex/package.d index 1c5b6a755..690bb3ae8 100644 --- a/source/creator/viewport/vertex/package.d +++ b/source/creator/viewport/vertex/package.d @@ -179,6 +179,7 @@ void incViewportVertexConfirmBar() { } // In case of a warning popup preventing application. + // TODO: if incDialogButtonSelected does not work, we may implement a DialogHandler for this. if (incDialogButtonSelected("CONFIRM_VERTEX_APPLY") == DialogButtons.Yes) { incMeshEditApply(); } diff --git a/source/creator/widgets/dialog.d b/source/creator/widgets/dialog.d index f9973d833..9b8948c59 100644 --- a/source/creator/widgets/dialog.d +++ b/source/creator/widgets/dialog.d @@ -11,6 +11,8 @@ import creator.core.font; import bindbc.imgui; import inochi2d; import i18n; +import std.algorithm.iteration: filter; +import std.array; enum DialogLevel : size_t { Info = 0, @@ -192,6 +194,9 @@ void incDialog(const(char)* tag, const(char)* title, string body_, DialogLevel l /** Gets which button the user selected in the last dialog box with the selected tag. Returns NONE if the last dialog was *not* the looked for tag or if there's no dialogs open + + Note: We should using DialogHandler and incRegisterDialogHandler() instead of this function, + prevnting unexpected behavior */ DialogButtons incDialogButtonSelected(const(char)* tag) { if (entries.length == 0) return DialogButtons.NONE; @@ -208,9 +213,54 @@ void* incDialogButtonUserData(const(char)* tag) { return entries[0].userData; } +/** + DialogHandler is a class for handling dialog events +*/ +class DialogHandler { + private const(char)* tag; + + this (const(char)* tag) { + this.tag = tag; + } + + bool hasClicked() { + return incDialogButtonSelected(this.tag) != DialogButtons.NONE; + } + + bool onClick(DialogButtons button) { + // Override this + return false; + } +} + +/** + Register a dialog handler +*/ +void incRegisterDialogHandler(DialogHandler handler) { + dialogHandlers ~= handler; +} + +/** + Handle dialog handlers, it should be called by main loop + and should be called after incRenderDialogs() +*/ +void incHandleDialogHandlers() { + // check all dialog handlers + foreach (handler; dialogHandlers) { + if (!handler.hasClicked()) + continue; + + handler.onClick(incDialogButtonSelected(handler.tag)); + } + + // Remove all handlers that have been clicked + dialogHandlers = dialogHandlers.filter!(handler => !handler.hasClicked()).array; +} + private { Texture[] adaTextures; + DialogHandler[] dialogHandlers; DialogEntry[] entries; DialogEntry* findDialogEntry(const(char)* tag) { From e841c3af0c3b6053f61b71d42de7a46af75b7f16 Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Thu, 12 Sep 2024 03:11:37 +0800 Subject: [PATCH 12/17] Revert "Modify function to conform to review feedback" This reverts commit 8b6adfbcd443d0b0da18b17463c21b120f2d12b0. --- source/creator/core/settings.d | 6 ------ source/creator/viewport/package.d | 33 ++++++++++++++++++++----------- source/creator/windows/settings.d | 15 ++++++-------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/source/creator/core/settings.d b/source/creator/core/settings.d index 3818a4b01..11a82307f 100644 --- a/source/creator/core/settings.d +++ b/source/creator/core/settings.d @@ -24,12 +24,6 @@ string incSettingsPath() { void incSettingsLoad() { if (exists(incSettingsPath())) { settings = parseJSON(readText(incSettingsPath())); - } else { - // This code is used to configure default values for new users - // New users use MousePosition, old users keep ScreenCenter - // also see incGetViewportZoomMode() - settings["ViewportZoomMode"] = "MousePosition"; - settings["ViewportZoomSpeed"] = 5.0; // File Handling // Always ask the user whether to preserve the folder structure during import diff --git a/source/creator/viewport/package.d b/source/creator/viewport/package.d index 38953484e..5e6456d9a 100644 --- a/source/creator/viewport/package.d +++ b/source/creator/viewport/package.d @@ -849,14 +849,14 @@ private { } // HANDLE ZOOM - string zoomMode = incGetViewportZoomMode(); - if (zoomMode == "ScreenCenter") - incViewportZoomToCenter(io, camera, uiScale); - else if (zoomMode == "MousePosition") - incViewportZoomToMouse(io, camera, uiScale); + string zoomMode = incGetCurrentViewportZoomMode(); + if (zoomMode == "legacy-zooming") + incViewportZoomLegacy(io, camera, uiScale); + else if (zoomMode == "normal") + incViewportZoomNew(io, camera, uiScale); } - void incViewportZoomToMouse(ImGuiIO* io, Camera camera, float uiScale) { + void incViewportZoomNew(ImGuiIO* io, Camera camera, float uiScale) { // This value changes the zoom speed float speed = incGetViewportZoomSpeed(); if (io.MouseWheel != 0) { @@ -886,7 +886,7 @@ private { } } - void incViewportZoomToCenter(ImGuiIO* io, Camera camera, float uiScale) { + void incViewportZoomLegacy(ImGuiIO* io, Camera camera, float uiScale) { float speed = incGetViewportZoomSpeed(); if (io.MouseWheel != 0) { incViewportZoom += (io.MouseWheel/50*speed)*incViewportZoom*uiScale; @@ -897,13 +897,24 @@ private { } } -string incGetViewportZoomMode() { +string[] incGetViewportZoomModes() { + return ["normal", "legacy-zooming"]; +} + +string incGetCurrentViewportZoomMode() { if (incSettingsCanGet("ViewportZoomMode")) return incSettingsGet!string("ViewportZoomMode"); else - return "ScreenCenter"; + return "normal"; } -bool incSetViewportZoomMode(string select) { + +bool incSetCurrentViewportZoomMode(string select) { + string[] viewportZoomModes = incGetViewportZoomModes(); + + // Verify zoom mode conifg + if (viewportZoomModes.canFind(select) == -1) + return false; + incSettingsSet("ViewportZoomMode", select); return true; } @@ -912,7 +923,7 @@ float incGetViewportZoomSpeed() { if (incSettingsCanGet("ViewportZoomSpeed")) return incSettingsGet!float("ViewportZoomSpeed"); else - return 1.0; + return 5.0; } bool incSetViewportZoomSpeed(float speed) { diff --git a/source/creator/windows/settings.d b/source/creator/windows/settings.d index d825fbf06..b31ffad52 100644 --- a/source/creator/windows/settings.d +++ b/source/creator/windows/settings.d @@ -210,16 +210,13 @@ protected: break; case SettingsPane.Viewport: beginSection(__("Viewport")); - string[string] configShowing = [ - "ScreenCenter": "To Screen Center", - "MousePosition": "To Mouse Position" - ]; - - string selected = configShowing[incGetViewportZoomMode()]; + string selected = incGetCurrentViewportZoomMode(); if(igBeginCombo(__("Zoom Mode"), selected.toStringz)) { - if (igSelectable(__("To Screen Center"), incSettingsGet!string("ViewportZoomMode") == "ScreenCenter")) incSetViewportZoomMode("ScreenCenter"); - if (igSelectable(__("To Mouse Position"), incSettingsGet!string("ViewportZoomMode") == "MousePosition")) incSetViewportZoomMode("MousePosition"); - + foreach (options; incGetViewportZoomModes()) { + if (igSelectable(options.toStringz)) { + incSetCurrentViewportZoomMode(options); + } + } igEndCombo(); } From 7e8ffab605da9454ced7bf7f42a2622ceac2a61f Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Thu, 12 Sep 2024 03:15:16 +0800 Subject: [PATCH 13/17] Revert "Fixed inconsistent display of "Zoom Mode" configuration" This reverts commit 11888359691cf20361a8561396ee440ccf19d0c6. --- source/creator/io/psd.d | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/source/creator/io/psd.d b/source/creator/io/psd.d index 9f785e683..826866821 100644 --- a/source/creator/io/psd.d +++ b/source/creator/io/psd.d @@ -137,28 +137,6 @@ struct IncPSDImportSettings { bool keepStructure = false; } -/** - Imports a PSD file with user prompt. - also see incAskImportKRA() -*/ -bool incAskImportPSD(string file) { - if (!file) - return false; - - switch (incImportKeepFolderStructPop()) { - case "NotPreserve": - incImportPSD(file, IncPSDImportSettings(false)); - return true; - case "Preserve": - incImportPSD(file, IncPSDImportSettings(true)); - return true; - case "Cancel": - return false; - default: - throw new Exception("Invalid selection"); - } -} - /** Imports a PSD file with user prompt. also see incAskImportKRA() From 46cf10043bf840b7d34b8c6fcac3500d5db379d5 Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Sun, 25 Aug 2024 22:54:34 +0800 Subject: [PATCH 14/17] Clone `kra-d` git to fix kra import issue Note: run `dub upgrade` before build --- dub.sdl | 4 ++-- source/creator/io/kra.d | 9 ++------- source/creator/windows/settings.d | 3 +-- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/dub.sdl b/dub.sdl index e71a740b8..3563b7fe0 100644 --- a/dub.sdl +++ b/dub.sdl @@ -4,8 +4,8 @@ authors "Inochi2D Project" copyright "Copyright © 2020, Inochi2D Project" license "BSD 2-clause" dependency "psd-d" version="~>0.6.1" -dependency "inmath" version="~>1.0.5" -dependency "kra-d" version="~>0.5.5" +dependency "inmath" version="1.0.6" +dependency "kra-d" repository="git+https://github.com/Inochi2D/kra-d" version="6a0bd41" dependency "tinyfiledialogs" version="~>0.10.1" dependency "facetrack-d" version="~>0.7.6" dependency "bindbc-sdl" version="~>1.1.2" diff --git a/source/creator/io/kra.d b/source/creator/io/kra.d index 4066b6794..7c3ce84eb 100644 --- a/source/creator/io/kra.d +++ b/source/creator/io/kra.d @@ -144,13 +144,8 @@ struct IncKRAImportSettings { bool incAskImportKRA(string file) { if (!file) return false; - // Note: currently KRA not supported Preserve layer structure, so we just skip the dialog - // until we have a proper implementation. - // KRALoadHandler handler = new KRALoadHandler(file); - // return incKeepStructDialog(handler); - - incImportKRA(file, IncKRAImportSettings(false)); - return true; + KRALoadHandler handler = new KRALoadHandler(file); + return incKeepStructDialog(handler); } class KRALoadHandler : ImportKeepHandler { diff --git a/source/creator/windows/settings.d b/source/creator/windows/settings.d index b31ffad52..2961738d1 100644 --- a/source/creator/windows/settings.d +++ b/source/creator/windows/settings.d @@ -189,8 +189,7 @@ protected: } endSection(); - // we mark PSD only until we have a proper implementation for kra - beginSection(__("Preserve Imported File Folder Structure (Currently PSD only)")); + beginSection(__("Preserve Imported File Folder Structure")); string[string] configShowing = [ "Ask": "Always Ask", "Preserve": "Preserve", From fcddd84b70c5b70dff60a536a9f2f54b37993cba Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Wed, 4 Sep 2024 07:40:34 +0800 Subject: [PATCH 15/17] Duplicate Dialog return value avoids mistakes reuse reference --- source/creator/io/package.d | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/source/creator/io/package.d b/source/creator/io/package.d index ffeb15b40..d3a356989 100644 --- a/source/creator/io/package.d +++ b/source/creator/io/package.d @@ -90,16 +90,16 @@ string incShowImportDialog(const(TFD_Filter)[] filters, string title, bool multi op.multiple = multiple; auto promise = dpFileChooserOpenFile(getWindowHandle(), title, op); promise.await(); - return promise.uriFromPromise().decode; + return promise.uriFromPromise().decode.dup; } catch (Throwable ex) { // FALLBACK: If xdg-desktop-portal is not available then try tinyfiledialogs. c_str filename = tinyfd_openFileDialog(title.toStringz, "", filters, multiple); - return incToDString(filename); + return incToDString(filename).dup; } } else { c_str filename = tinyfd_openFileDialog(title.toStringz, "", filters, multiple); - return incToDString(filename); + return incToDString(filename).dup; } } @@ -110,16 +110,16 @@ string incShowOpenFolderDialog(string title = "Open...") { op.directory = true; auto promise = dpFileChooserOpenFile(getWindowHandle(), title, op); promise.await(); - return promise.uriFromPromise().decode; + return promise.uriFromPromise().decode.dup; } catch (Throwable _) { // FALLBACK: If xdg-desktop-portal is not available then try tinyfiledialogs. c_str filename = tinyfd_selectFolderDialog(title.toStringz, null); - return incToDString(filename); + return incToDString(filename).dup; } } else { c_str filename = tinyfd_selectFolderDialog(title.toStringz, null); - return incToDString(filename); + return incToDString(filename).dup; } } @@ -130,16 +130,16 @@ string incShowOpenDialog(const(TFD_Filter)[] filters, string title = "Open...") op.filters = tfdToFileFilter(filters); auto promise = dpFileChooserOpenFile(getWindowHandle(), title, op); promise.await(); - return promise.uriFromPromise().decode; + return promise.uriFromPromise().decode.dup; } catch (Throwable ex) { // FALLBACK: If xdg-desktop-portal is not available then try tinyfiledialogs. c_str filename = tinyfd_openFileDialog(title.toStringz, "", filters, false); - return incToDString(filename); + return incToDString(filename).dup; } } else { c_str filename = tinyfd_openFileDialog(title.toStringz, "", filters, false); - return incToDString(filename); + return incToDString(filename).dup; } } @@ -150,16 +150,16 @@ string incShowSaveDialog(const(TFD_Filter)[] filters, string fname, string title op.filters = tfdToFileFilter(filters); auto promise = dpFileChooserSaveFile(getWindowHandle(), title, op); promise.await(); - return promise.uriFromPromise().decode; + return promise.uriFromPromise().decode.dup; } catch (Throwable ex) { // FALLBACK: If xdg-desktop-portal is not available then try tinyfiledialogs. c_str filename = tinyfd_saveFileDialog(title.toStringz, fname.toStringz, filters); - return incToDString(filename); + return incToDString(filename).dup; } } else { c_str filename = tinyfd_saveFileDialog(title.toStringz, fname.toStringz, filters); - return incToDString(filename); + return incToDString(filename).dup; } } From 0bab131d92c134c0e45d1b712aa451f6a3d0ffe3 Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Thu, 12 Sep 2024 04:06:42 +0800 Subject: [PATCH 16/17] Update kra-d version --- dub.sdl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dub.sdl b/dub.sdl index 3563b7fe0..d388d03b1 100644 --- a/dub.sdl +++ b/dub.sdl @@ -5,7 +5,7 @@ copyright "Copyright © 2020, Inochi2D Project" license "BSD 2-clause" dependency "psd-d" version="~>0.6.1" dependency "inmath" version="1.0.6" -dependency "kra-d" repository="git+https://github.com/Inochi2D/kra-d" version="6a0bd41" +dependency "kra-d" version="~>0.5.6" dependency "tinyfiledialogs" version="~>0.10.1" dependency "facetrack-d" version="~>0.7.6" dependency "bindbc-sdl" version="~>1.1.2" From 09c8ef8c7966b31666ffdda8587e10eeeeb4915b Mon Sep 17 00:00:00 2001 From: "Lin, Yong Xiang" Date: Thu, 12 Sep 2024 04:16:20 +0800 Subject: [PATCH 17/17] Update inmath allow other 1.0.x series version --- dub.sdl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dub.sdl b/dub.sdl index d388d03b1..35d8cbc9a 100644 --- a/dub.sdl +++ b/dub.sdl @@ -4,7 +4,7 @@ authors "Inochi2D Project" copyright "Copyright © 2020, Inochi2D Project" license "BSD 2-clause" dependency "psd-d" version="~>0.6.1" -dependency "inmath" version="1.0.6" +dependency "inmath" version="~>1.0.6" dependency "kra-d" version="~>0.5.6" dependency "tinyfiledialogs" version="~>0.10.1" dependency "facetrack-d" version="~>0.7.6"