1 /* 2 Copyright © 2020, Inochi2D Project 3 Distributed under the 2-Clause BSD License, see LICENSE file. 4 5 Authors: Luna Nielsen 6 */ 7 module creator.windows.settings; 8 import creator.windows; 9 import creator.widgets; 10 import creator.core; 11 import creator.core.i18n; 12 import std.string; 13 import creator.utils.link; 14 import i18n; 15 import inmath; 16 17 bool incIsSettingsOpen; 18 19 enum SettingsPane : string { 20 LookAndFeel = "Look and Feel", 21 Viewport = "Viewport", 22 Accessibility = "Accessbility" 23 } 24 25 /** 26 Settings window 27 */ 28 class SettingsWindow : Window { 29 private: 30 bool generalTabOpen = true; 31 bool otherTabOpen = true; 32 bool changesRequiresRestart; 33 34 int tmpUIScale; 35 float targetUIScale; 36 37 SettingsPane settingsPane = SettingsPane.LookAndFeel; 38 39 void beginSection(const(char)* title) { 40 incBeginCategory(title, IncCategoryFlags.NoCollapse); 41 incDummy(ImVec2(0, 4)); 42 } 43 44 void endSection() { 45 incDummy(ImVec2(0, 4)); 46 incEndCategory(); 47 } 48 protected: 49 override 50 void onBeginUpdate() { 51 flags |= ImGuiWindowFlags.NoSavedSettings; 52 incIsSettingsOpen = true; 53 54 ImVec2 wpos = ImVec2( 55 igGetMainViewport().Pos.x+(igGetMainViewport().Size.x/2), 56 igGetMainViewport().Pos.y+(igGetMainViewport().Size.y/2), 57 ); 58 59 ImVec2 uiSize = ImVec2( 60 512, 61 256+128 62 ); 63 64 igSetNextWindowPos(wpos, ImGuiCond.Appearing, ImVec2(0.5, 0.5)); 65 igSetNextWindowSize(uiSize, ImGuiCond.Appearing); 66 igSetNextWindowSizeConstraints(uiSize, ImVec2(float.max, float.max)); 67 super.onBeginUpdate(); 68 } 69 70 override 71 void onUpdate() { 72 float availX = incAvailableSpace().x; 73 74 // Sidebar 75 if (igBeginChild("SettingsSidebar", ImVec2(availX/3.5, -28), true)) { 76 igPushTextWrapPos(128); 77 if (igSelectable(__("Look and Feel"), settingsPane == SettingsPane.LookAndFeel)) { 78 settingsPane = SettingsPane.LookAndFeel; 79 } 80 81 if (igSelectable(__("Viewport"), settingsPane == SettingsPane.Viewport)) { 82 settingsPane = SettingsPane.Viewport; 83 } 84 85 if (igSelectable(__("Accessbility"), settingsPane == SettingsPane.Accessibility)) { 86 settingsPane = SettingsPane.Accessibility; 87 } 88 igPopTextWrapPos(); 89 } 90 igEndChild(); 91 92 // Nice spacing 93 igSameLine(0, 4); 94 95 // Contents 96 if (igBeginChild("SettingsContent", ImVec2(0, -28), true)) { 97 availX = incAvailableSpace().x; 98 99 // Start settings panel elements 100 igPushItemWidth(availX/2); 101 switch(settingsPane) { 102 case SettingsPane.LookAndFeel: 103 104 beginSection(__("Look and Feel")); 105 if(igBeginCombo(__("Color Theme"), incGetDarkMode() ? __("Dark") : __("Light"))) { 106 if (igSelectable(__("Dark"), incGetDarkMode())) incSetDarkMode(true); 107 if (igSelectable(__("Light"), !incGetDarkMode())) incSetDarkMode(false); 108 109 igEndCombo(); 110 } 111 112 import std.string : toStringz; 113 if(igBeginCombo(__("Language"), incLocaleCurrentName().toStringz)) { 114 if (igSelectable("English")) { 115 incLocaleSet(null); 116 changesRequiresRestart = true; 117 } 118 foreach(entry; incLocaleGetEntries()) { 119 if (igSelectable(entry.humanNameC)) { 120 incLocaleSet(entry.code); 121 changesRequiresRestart = true; 122 } 123 } 124 igEndCombo(); 125 } 126 127 version (UseUIScaling) { 128 version(OSX) { 129 130 // macOS follows Retina scaling. 131 } else { 132 if (igInputInt(__("UI Scale"), &tmpUIScale, 25, 50, ImGuiInputTextFlags.EnterReturnsTrue)) { 133 tmpUIScale = clamp(tmpUIScale, 100, 200); 134 incSetUIScale(cast(float)tmpUIScale/100.0); 135 } 136 } 137 } 138 endSection(); 139 140 beginSection(__("Undo History")); 141 int maxHistory = cast(int)incActionGetUndoHistoryLength(); 142 if (igDragInt(__("Max Undo History"), &maxHistory, 1, 1, 1000, "%d")) { 143 incActionSetUndoHistoryLength(maxHistory); 144 } 145 endSection(); 146 147 version(linux) { 148 beginSection(__("Linux Tweaks")); 149 bool disableCompositor = incSettingsGet!bool("DisableCompositor"); 150 if (igCheckbox(__("Disable Compositor"), &disableCompositor)) { 151 incSettingsSet("DisableCompositor", disableCompositor); 152 } 153 endSection(); 154 } 155 break; 156 case SettingsPane.Accessibility: 157 beginSection(__("Accessibility")); 158 bool disableCompositor = incSettingsGet!bool("useOpenDyslexic"); 159 if (igCheckbox(__("Use OpenDyslexic Font"), &disableCompositor)) { 160 incSettingsSet("useOpenDyslexic", disableCompositor); 161 changesRequiresRestart = true; 162 } 163 incTooltip("Use the OpenDyslexic font for Latin text characters."); 164 endSection(); 165 break; 166 default: 167 incLabelOver(_("No settings for this category."), ImVec2(0, 0), true); 168 break; 169 } 170 igPopItemWidth(); 171 } 172 igEndChild(); 173 174 // Bottom buttons 175 if (igBeginChild("SettingsButtons", ImVec2(0, 0), false, ImGuiWindowFlags.NoScrollbar)) { 176 if (changesRequiresRestart) { 177 igPushTextWrapPos(256+128); 178 incTextColored( 179 ImVec4(0.8, 0.2, 0.2, 1), 180 _("Inochi Creator needs to be restarted for some changes to take effect.") 181 ); 182 igPopTextWrapPos(); 183 igSameLine(0, 0); 184 } 185 incDummy(ImVec2(-64, 0)); 186 igSameLine(0, 0); 187 188 if (igButton(__("Done"), ImVec2(64, 24))) { 189 this.close(); 190 } 191 } 192 igEndChild(); 193 } 194 195 override 196 void onClose() { 197 incSettingsSave(); 198 incIsSettingsOpen = false; 199 } 200 201 public: 202 this() { 203 super(_("Settings")); 204 targetUIScale = incGetUIScale(); 205 tmpUIScale = cast(int)(incGetUIScale()*100); 206 } 207 }