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 }