-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathsettings.go
305 lines (264 loc) · 9.44 KB
/
settings.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
package imgui
import (
"bufio"
"bytes"
"fmt"
"os"
"strings"
)
// LoadIniSettingsFromDisk Settings/.Ini Utilities
// - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini").
// - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually.
// - Important: default value "imgui.ini" is relative to current working dir! Most apps will want to lock this to an absolute path (e.g. same path as executables).
func LoadIniSettingsFromDisk(ini_filename string) {
var file_data_size uintptr = 0
var file_data = ImFileLoadToMemory(ini_filename, "rb", &file_data_size, 0)
if file_data == nil {
return
}
LoadIniSettingsFromMemory(file_data, (size_t)(file_data_size))
} // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename).
func LoadIniSettingsFromMemory(buf []byte, ini_size uintptr) {
var g = GImGui
IM_ASSERT(g.Initialized)
//IM_ASSERT(!g.WithinFrameScope && "Cannot be called between NewFrame() and EndFrame()");
//IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);
// Call pre-read handlers
// Some types will clear their data (e.g. dock information) some types will allow merge/override (window)
for handler_n := range g.SettingsHandlers {
if g.SettingsHandlers[handler_n].ReadInitFn != nil {
g.SettingsHandlers[handler_n].ReadInitFn(g, &g.SettingsHandlers[handler_n])
}
}
var reader = bufio.NewReader(bytes.NewReader(buf))
var entry_handler *ImGuiSettingsHandler
var entry_data any = nil
for {
line, err := reader.ReadString('\n')
if err != nil {
break
}
line = line[:len(line)-1]
if line == "" {
continue
}
if line[0] == '[' && line[len(line)-1] == ']' {
splits := strings.SplitN(line[1:len(line)-1], "][", 2)
if len(splits) == 2 {
var settings_type = splits[0]
var settings_id = splits[1]
entry_handler = FindSettingsHandler(settings_type)
if entry_handler != nil {
entry_data = entry_handler.ReadOpenFn(g, entry_handler, settings_id)
}
}
} else if entry_handler != nil {
entry_handler.ReadLineFn(g, entry_handler, entry_data, line)
}
}
g.SettingsLoaded = true
// Call post-read handlers
for handler_n := range g.SettingsHandlers {
if g.SettingsHandlers[handler_n].ApplyAllFn != nil {
g.SettingsHandlers[handler_n].ApplyAllFn(g, &g.SettingsHandlers[handler_n])
}
}
} // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source.
func SaveIniSettingsToDisk(ini_filename string) {
var g = GImGui
g.SettingsDirtyTimer = 0.0
if ini_filename == "" {
return
}
var ini_data_size size_t = 0
var ini_data = SaveIniSettingsToMemory(&ini_data_size)
os.WriteFile(ini_filename, ini_data, 0666)
} // this is automatically called (if io.IniFilename is not empty) a few seconds after any modification that should be reflected in the .ini file (and also by DestroyContext).
func SaveIniSettingsToMemory(out_size *uintptr) []byte {
var g = GImGui
g.SettingsDirtyTimer = 0.0
g.SettingsIniData = g.SettingsIniData[:0]
for handler_n := range g.SettingsHandlers {
var handler = &g.SettingsHandlers[handler_n]
handler.WriteAllFn(g, handler, &g.SettingsIniData)
}
if out_size != nil {
*out_size = (size_t)(len(g.SettingsIniData))
}
return g.SettingsIniData
} // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings.
// MarkIniSettingsDirty Settings
func MarkIniSettingsDirty() {
var g = GImGui
if g.SettingsDirtyTimer <= 0.0 {
g.SettingsDirtyTimer = g.IO.IniSavingRate
}
}
func MarkIniSettingsDirtyWindow(window *ImGuiWindow) {
var g = GImGui
if window.Flags&ImGuiWindowFlags_NoSavedSettings == 0 {
if g.SettingsDirtyTimer <= 0.0 {
g.SettingsDirtyTimer = g.IO.IniSavingRate
}
}
}
func ClearIniSettings() {
var g = GImGui
g.SettingsIniData = g.SettingsIniData[:0]
for handler_n := range g.SettingsHandlers {
if g.SettingsHandlers[handler_n].ClearAllFn != nil {
g.SettingsHandlers[handler_n].ClearAllFn(g, &g.SettingsHandlers[handler_n])
}
}
}
func CreateNewWindowSettings(name string) *ImGuiWindowSettings {
var g = GImGui
if index := strings.Index(name, "###"); index != -1 {
name = name[index:]
}
var settings ImGuiWindowSettings
settings.ID = ImHashStr(name, 0, 0)
settings.name = name
g.SettingsWindows = append(g.SettingsWindows, settings)
return &g.SettingsWindows[len(g.SettingsWindows)-1]
}
func FindWindowSettings(id ImGuiID) *ImGuiWindowSettings {
var g = GImGui
for i := range g.SettingsWindows {
settings := &g.SettingsWindows[i]
if settings.ID == id {
return settings
}
}
return nil
}
func FindOrCreateWindowSettings(name string) *ImGuiWindowSettings {
if settings := FindWindowSettings(ImHashStr(name, 0, 0)); settings != nil {
return settings
}
return CreateNewWindowSettings(name)
}
func FindSettingsHandler(name string) *ImGuiSettingsHandler {
var g = GImGui
var type_hash = ImHashStr(name, 0, 0)
for handler_n := range g.SettingsHandlers {
if g.SettingsHandlers[handler_n].TypeHash == type_hash {
return &g.SettingsHandlers[handler_n]
}
}
return nil
}
// UpdateSettings Called by NewFrame()
func UpdateSettings() {
// Load settings on first frame (if not explicitly loaded manually before)
var g = GImGui
if !g.SettingsLoaded {
IM_ASSERT(len(g.SettingsWindows) == 0)
if g.IO.IniFilename != "" {
LoadIniSettingsFromDisk(g.IO.IniFilename)
}
g.SettingsLoaded = true
}
// Save settings (with a delay after the last modification, so we don't spam disk too much)
if g.SettingsDirtyTimer > 0.0 {
g.SettingsDirtyTimer -= g.IO.DeltaTime
if g.SettingsDirtyTimer <= 0.0 {
if g.IO.IniFilename != "" {
SaveIniSettingsToDisk(g.IO.IniFilename)
} else {
g.IO.WantSaveIniSettings = true // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.
}
g.SettingsDirtyTimer = 0
}
}
}
// WindowSettingsHandler_ApplyAll Apply to existing windows (if any)
func WindowSettingsHandler_ApplyAll(ctx *ImGuiContext, _ *ImGuiSettingsHandler) {
var g = ctx
for i := range g.SettingsWindows {
settings := &g.SettingsWindows[i]
if settings.WantApply {
if window := FindWindowByID(settings.ID); window != nil {
ApplyWindowSettings(window, settings)
}
settings.WantApply = false
}
}
}
func ApplyWindowSettings(window *ImGuiWindow, settings *ImGuiWindowSettings) {
window.Pos = *ImFloorVec(&ImVec2{float(settings.Pos.x), float(settings.Pos.y)})
if settings.Size.x > 0 && settings.Size.y > 0 {
window.Size = *ImFloorVec(&ImVec2{float(settings.Size.x), float(settings.Size.y)})
window.SizeFull = *ImFloorVec(&ImVec2{float(settings.Size.x), float(settings.Size.y)})
}
window.Collapsed = settings.Collapsed
}
func WindowSettingsHandler_ClearAll(ctx *ImGuiContext, _ *ImGuiSettingsHandler) {
var g = ctx
for i := range g.Windows {
g.Windows[i].SettingsOffset = -1
}
g.SettingsWindows = g.SettingsWindows[:0]
}
func WindowSettingsHandler_ReadOpen(_ *ImGuiContext, _ *ImGuiSettingsHandler, name string) any {
var settings = FindOrCreateWindowSettings(name)
var id = settings.ID
*settings = ImGuiWindowSettings{} // Clear existing if recycling previous entry
settings.ID = id
settings.name = name
settings.WantApply = true
return settings
}
func WindowSettingsHandler_ReadLine(_ *ImGuiContext, _ *ImGuiSettingsHandler, entry any, line string) {
var settings = entry.(*ImGuiWindowSettings)
var x, y int
var i bool
if n, _ := fmt.Sscanf(line, "Pos=%v,%v", &x, &y); n == 2 {
settings.Pos = ImVec2ih{(short)(x), (short)(y)}
} else if n, _ := fmt.Sscanf(line, "Size=%v,%v", &x, &y); n == 2 {
settings.Size = ImVec2ih{(short)(x), (short)(y)}
} else if n, _ := fmt.Sscanf(line, "Collapsed=%v", &i); n == 1 {
settings.Collapsed = i
}
}
func WindowSettingsHandler_WriteAll(ctx *ImGuiContext, handler *ImGuiSettingsHandler, buf *ImGuiTextBuffer) {
// Gather data from windows that were active during this session
// (if a window wasn't opened in this session we preserve its settings)
var g = ctx
for i := range g.Windows {
var window = g.Windows[i]
if window.Flags&ImGuiWindowFlags_NoSavedSettings != 0 {
continue
}
var settings *ImGuiWindowSettings
if window.SettingsOffset != -1 {
settings = &g.SettingsWindows[window.SettingsOffset]
} else {
settings = FindOrCreateWindowSettings(window.Name)
}
if settings == nil {
settings = CreateNewWindowSettings(window.Name)
window.SettingsOffset = -1
for i := range g.SettingsWindows {
if settings == &g.SettingsWindows[i] {
window.SettingsOffset = int(i)
break
}
}
}
IM_ASSERT(settings.ID == window.ID)
settings.Pos = ImVec2ih{short(window.Pos.x), short(window.Pos.y)}
settings.Size = ImVec2ih{short(window.Size.x), short(window.Size.y)}
settings.Collapsed = window.Collapsed
}
// Write to text buffer
for i := range g.SettingsWindows {
settings := &g.SettingsWindows[i]
var settings_name = settings.GetName()
*buf = append(*buf, []byte(fmt.Sprintf("[%s][%s]\n", handler.TypeName, settings_name))...)
*buf = append(*buf, []byte(fmt.Sprintf("Pos=%d,%d\n", settings.Pos.x, settings.Pos.y))...)
*buf = append(*buf, []byte(fmt.Sprintf("Size=%d,%d\n", settings.Size.x, settings.Size.y))...)
*buf = append(*buf, []byte(fmt.Sprintf("Collapsed=%v\n", settings.Collapsed))...)
*buf = append(*buf, []byte("\n")...)
}
}