added user presets
This commit is contained in:
@@ -72,6 +72,12 @@ type presetEntry struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
type presetInfo struct {
|
||||
Name string
|
||||
Path string
|
||||
Source string
|
||||
}
|
||||
|
||||
func listEmbeddedPresets() ([]presetEntry, error) {
|
||||
entries, err := fs.ReadDir(embeddedPresets, "Presets")
|
||||
if err != nil {
|
||||
@@ -106,6 +112,102 @@ func loadEmbeddedPreset(path string) (*Settings, error) {
|
||||
return decodeSettingsJSON(raw)
|
||||
}
|
||||
|
||||
func listUserPresets(dir string) ([]presetEntry, error) {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return []presetEntry{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var presets []presetEntry
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
name := entry.Name()
|
||||
if !strings.HasSuffix(strings.ToLower(name), ".json") {
|
||||
continue
|
||||
}
|
||||
displayName := strings.TrimSuffix(name, filepath.Ext(name))
|
||||
presets = append(presets, presetEntry{
|
||||
Name: displayName,
|
||||
Path: filepath.Join(dir, name),
|
||||
})
|
||||
}
|
||||
sort.Slice(presets, func(i, j int) bool {
|
||||
return presets[i].Name < presets[j].Name
|
||||
})
|
||||
return presets, nil
|
||||
}
|
||||
|
||||
func buildPresetOptions(settings *Settings, userPresetDir string) ([]string, map[string]presetInfo) {
|
||||
hidden := map[string]bool{}
|
||||
for _, name := range settings.HiddenPresets {
|
||||
hidden[name] = true
|
||||
}
|
||||
|
||||
info := map[string]presetInfo{}
|
||||
var names []string
|
||||
|
||||
embedded, err := listEmbeddedPresets()
|
||||
if err != nil {
|
||||
log.Println("Error loading embedded presets:", err)
|
||||
} else {
|
||||
for _, preset := range embedded {
|
||||
if hidden[preset.Name] {
|
||||
continue
|
||||
}
|
||||
info[preset.Name] = presetInfo{
|
||||
Name: preset.Name,
|
||||
Path: preset.Path,
|
||||
Source: "embedded",
|
||||
}
|
||||
names = append(names, preset.Name)
|
||||
}
|
||||
}
|
||||
|
||||
userPresets, err := listUserPresets(userPresetDir)
|
||||
if err != nil {
|
||||
log.Println("Error loading user presets:", err)
|
||||
} else {
|
||||
for _, preset := range userPresets {
|
||||
if _, exists := info[preset.Name]; exists {
|
||||
continue
|
||||
}
|
||||
info[preset.Name] = presetInfo{
|
||||
Name: preset.Name,
|
||||
Path: preset.Path,
|
||||
Source: "user",
|
||||
}
|
||||
names = append(names, preset.Name)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(names)
|
||||
return append([]string{"No Preset"}, names...), info
|
||||
}
|
||||
|
||||
func savePresetToFile(path string, settings *Settings) error {
|
||||
raw, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var data map[string]any
|
||||
if err := json.Unmarshal(raw, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
delete(data, "seed")
|
||||
delete(data, "last_export_path")
|
||||
delete(data, "image_view_state")
|
||||
|
||||
pretty, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, pretty, 0644)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Initialize the Fyne application and window
|
||||
a := app.NewWithID("com.example.rpgcitymaker")
|
||||
@@ -1651,26 +1753,38 @@ func main() {
|
||||
updateGenerateBtnState()
|
||||
}
|
||||
|
||||
presetEntries, err := listEmbeddedPresets()
|
||||
if err != nil {
|
||||
log.Println("Error loading embedded presets:", err)
|
||||
}
|
||||
presetNames := []string{"No Preset"}
|
||||
presetPathByName := map[string]string{}
|
||||
for _, preset := range presetEntries {
|
||||
presetNames = append(presetNames, preset.Name)
|
||||
presetPathByName[preset.Name] = preset.Path
|
||||
}
|
||||
presetSelect := widget.NewSelect(presetNames, func(name string) {
|
||||
if name == "" || name == "No Preset" {
|
||||
presetDir := filepath.Join(appConfigDir, "presets")
|
||||
var presetInfoByName map[string]presetInfo
|
||||
var suppressPresetApply bool
|
||||
var removePresetBtn *widget.Button
|
||||
|
||||
presetSelect := widget.NewSelect([]string{"No Preset"}, func(name string) {
|
||||
if suppressPresetApply {
|
||||
return
|
||||
}
|
||||
path, ok := presetPathByName[name]
|
||||
if name == "" || name == "No Preset" {
|
||||
if removePresetBtn != nil {
|
||||
removePresetBtn.Disable()
|
||||
}
|
||||
return
|
||||
}
|
||||
info, ok := presetInfoByName[name]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
applyingPreset = true
|
||||
imported, err := loadEmbeddedPreset(path)
|
||||
var imported *Settings
|
||||
var err error
|
||||
if info.Source == "embedded" {
|
||||
imported, err = loadEmbeddedPreset(info.Path)
|
||||
} else {
|
||||
raw, readErr := os.ReadFile(info.Path)
|
||||
if readErr != nil {
|
||||
err = readErr
|
||||
} else {
|
||||
imported, err = decodeSettingsJSON(raw)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
applyingPreset = false
|
||||
dialog.ShowError(err, w)
|
||||
@@ -1683,6 +1797,9 @@ func main() {
|
||||
applyingPreset = false
|
||||
})
|
||||
})
|
||||
if removePresetBtn != nil {
|
||||
removePresetBtn.Enable()
|
||||
}
|
||||
})
|
||||
presetSelect.SetSelected("No Preset")
|
||||
clearPresetSelection = func() {
|
||||
@@ -1691,6 +1808,121 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
refreshPresetOptions := func(selectName string) {
|
||||
names, info := buildPresetOptions(settings, presetDir)
|
||||
presetInfoByName = info
|
||||
suppressPresetApply = true
|
||||
presetSelect.Options = names
|
||||
presetSelect.Refresh()
|
||||
|
||||
if selectName == "" {
|
||||
selectName = presetSelect.Selected
|
||||
}
|
||||
if _, ok := presetInfoByName[selectName]; !ok {
|
||||
selectName = "No Preset"
|
||||
}
|
||||
presetSelect.SetSelected(selectName)
|
||||
if removePresetBtn != nil {
|
||||
if selectName == "" || selectName == "No Preset" {
|
||||
removePresetBtn.Disable()
|
||||
} else {
|
||||
removePresetBtn.Enable()
|
||||
}
|
||||
}
|
||||
suppressPresetApply = false
|
||||
}
|
||||
|
||||
addPresetBtn := widget.NewButton("Add Preset", func() {
|
||||
nameEntry := widget.NewEntry()
|
||||
nameEntry.SetPlaceHolder("Preset Name")
|
||||
|
||||
content := container.NewVBox(
|
||||
widget.NewLabel("Preset Name:"),
|
||||
nameEntry,
|
||||
)
|
||||
|
||||
var addDialog *dialog.CustomDialog
|
||||
saveBtn := widget.NewButton("Save", func() {
|
||||
name := strings.TrimSpace(nameEntry.Text)
|
||||
if name == "" || name == "No Preset" {
|
||||
return
|
||||
}
|
||||
if strings.ContainsAny(name, "/\\") {
|
||||
dialog.ShowError(fmt.Errorf("preset name cannot contain path separators"), w)
|
||||
return
|
||||
}
|
||||
if _, exists := presetInfoByName[name]; exists {
|
||||
dialog.ShowError(fmt.Errorf("preset name already exists"), w)
|
||||
return
|
||||
}
|
||||
if err := os.MkdirAll(presetDir, 0755); err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
filePath := filepath.Join(presetDir, name+".json")
|
||||
if err := savePresetToFile(filePath, settings); err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
refreshPresetOptions(name)
|
||||
if addDialog != nil {
|
||||
addDialog.Hide()
|
||||
}
|
||||
})
|
||||
saveBtn.Disable()
|
||||
|
||||
nameEntry.OnChanged = func(text string) {
|
||||
if strings.TrimSpace(text) == "" {
|
||||
saveBtn.Disable()
|
||||
} else {
|
||||
saveBtn.Enable()
|
||||
}
|
||||
}
|
||||
|
||||
addDialog = dialog.NewCustom("Add Preset", "Cancel", content, w)
|
||||
addDialog.SetButtons([]fyne.CanvasObject{
|
||||
widget.NewButton("Cancel", func() {
|
||||
addDialog.Hide()
|
||||
}),
|
||||
saveBtn,
|
||||
})
|
||||
addDialog.Show()
|
||||
})
|
||||
|
||||
removePresetBtn = widget.NewButton("Remove Preset", func() {
|
||||
name := presetSelect.Selected
|
||||
if name == "" || name == "No Preset" {
|
||||
return
|
||||
}
|
||||
info, ok := presetInfoByName[name]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if info.Source == "embedded" {
|
||||
found := false
|
||||
for _, existing := range settings.HiddenPresets {
|
||||
if existing == name {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
settings.HiddenPresets = append(settings.HiddenPresets, name)
|
||||
if err := settings.Save(); err != nil {
|
||||
log.Println("Error saving hidden preset list:", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := os.Remove(info.Path); err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
}
|
||||
refreshPresetOptions("No Preset")
|
||||
})
|
||||
removePresetBtn.Disable()
|
||||
refreshPresetOptions("No Preset")
|
||||
|
||||
buildingsTab := container.NewTabItem("Buildings", container.NewVBox(
|
||||
numBuildingsSlider,
|
||||
minBuildingSizeSlider,
|
||||
@@ -1705,6 +1937,7 @@ func main() {
|
||||
imageTab := container.NewTabItem("Image", container.NewVBox(
|
||||
widget.NewLabel("Preset:"),
|
||||
presetSelect,
|
||||
container.NewGridWithColumns(2, addPresetBtn, removePresetBtn),
|
||||
widget.NewSeparator(),
|
||||
widget.NewLabel("Width:"),
|
||||
widthEntry, widget.NewLabel("Height:"),
|
||||
|
||||
Reference in New Issue
Block a user