added user presets
This commit is contained in:
@@ -72,6 +72,12 @@ type presetEntry struct {
|
|||||||
Path string
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type presetInfo struct {
|
||||||
|
Name string
|
||||||
|
Path string
|
||||||
|
Source string
|
||||||
|
}
|
||||||
|
|
||||||
func listEmbeddedPresets() ([]presetEntry, error) {
|
func listEmbeddedPresets() ([]presetEntry, error) {
|
||||||
entries, err := fs.ReadDir(embeddedPresets, "Presets")
|
entries, err := fs.ReadDir(embeddedPresets, "Presets")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -106,6 +112,102 @@ func loadEmbeddedPreset(path string) (*Settings, error) {
|
|||||||
return decodeSettingsJSON(raw)
|
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() {
|
func main() {
|
||||||
// Initialize the Fyne application and window
|
// Initialize the Fyne application and window
|
||||||
a := app.NewWithID("com.example.rpgcitymaker")
|
a := app.NewWithID("com.example.rpgcitymaker")
|
||||||
@@ -1651,26 +1753,38 @@ func main() {
|
|||||||
updateGenerateBtnState()
|
updateGenerateBtnState()
|
||||||
}
|
}
|
||||||
|
|
||||||
presetEntries, err := listEmbeddedPresets()
|
presetDir := filepath.Join(appConfigDir, "presets")
|
||||||
if err != nil {
|
var presetInfoByName map[string]presetInfo
|
||||||
log.Println("Error loading embedded presets:", err)
|
var suppressPresetApply bool
|
||||||
}
|
var removePresetBtn *widget.Button
|
||||||
presetNames := []string{"No Preset"}
|
|
||||||
presetPathByName := map[string]string{}
|
presetSelect := widget.NewSelect([]string{"No Preset"}, func(name string) {
|
||||||
for _, preset := range presetEntries {
|
if suppressPresetApply {
|
||||||
presetNames = append(presetNames, preset.Name)
|
|
||||||
presetPathByName[preset.Name] = preset.Path
|
|
||||||
}
|
|
||||||
presetSelect := widget.NewSelect(presetNames, func(name string) {
|
|
||||||
if name == "" || name == "No Preset" {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path, ok := presetPathByName[name]
|
if name == "" || name == "No Preset" {
|
||||||
|
if removePresetBtn != nil {
|
||||||
|
removePresetBtn.Disable()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
info, ok := presetInfoByName[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
applyingPreset = true
|
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 {
|
if err != nil {
|
||||||
applyingPreset = false
|
applyingPreset = false
|
||||||
dialog.ShowError(err, w)
|
dialog.ShowError(err, w)
|
||||||
@@ -1683,6 +1797,9 @@ func main() {
|
|||||||
applyingPreset = false
|
applyingPreset = false
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
if removePresetBtn != nil {
|
||||||
|
removePresetBtn.Enable()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
presetSelect.SetSelected("No Preset")
|
presetSelect.SetSelected("No Preset")
|
||||||
clearPresetSelection = func() {
|
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(
|
buildingsTab := container.NewTabItem("Buildings", container.NewVBox(
|
||||||
numBuildingsSlider,
|
numBuildingsSlider,
|
||||||
minBuildingSizeSlider,
|
minBuildingSizeSlider,
|
||||||
@@ -1705,6 +1937,7 @@ func main() {
|
|||||||
imageTab := container.NewTabItem("Image", container.NewVBox(
|
imageTab := container.NewTabItem("Image", container.NewVBox(
|
||||||
widget.NewLabel("Preset:"),
|
widget.NewLabel("Preset:"),
|
||||||
presetSelect,
|
presetSelect,
|
||||||
|
container.NewGridWithColumns(2, addPresetBtn, removePresetBtn),
|
||||||
widget.NewSeparator(),
|
widget.NewSeparator(),
|
||||||
widget.NewLabel("Width:"),
|
widget.NewLabel("Width:"),
|
||||||
widthEntry, widget.NewLabel("Height:"),
|
widthEntry, widget.NewLabel("Height:"),
|
||||||
|
|||||||
+9
-3
@@ -72,9 +72,10 @@ type Settings struct {
|
|||||||
BuildingComplexityRatio float64 `json:"building_complexity_ratio"`
|
BuildingComplexityRatio float64 `json:"building_complexity_ratio"`
|
||||||
|
|
||||||
// General settings
|
// General settings
|
||||||
Seed int64 `json:"seed"`
|
Seed int64 `json:"seed"`
|
||||||
LastExportPath string `json:"last_export_path"`
|
LastExportPath string `json:"last_export_path"`
|
||||||
ImageViewState int `json:"image_view_state"`
|
ImageViewState int `json:"image_view_state"`
|
||||||
|
HiddenPresets []string `json:"hidden_presets"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save saves the current settings to a JSON file in the user's config directory.
|
// Save saves the current settings to a JSON file in the user's config directory.
|
||||||
@@ -176,6 +177,7 @@ func LoadSettings() (*Settings, error) {
|
|||||||
BuildingComplexityRatio: 50,
|
BuildingComplexityRatio: 50,
|
||||||
LastExportPath: homeDir,
|
LastExportPath: homeDir,
|
||||||
ImageViewState: 0,
|
ImageViewState: 0,
|
||||||
|
HiddenPresets: []string{},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -332,4 +334,8 @@ func normalizeSettings(settings *Settings, rawKeys map[string]json.RawMessage) {
|
|||||||
}
|
}
|
||||||
settings.LastExportPath = homeDir
|
settings.LastExportPath = homeDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if settings.HiddenPresets == nil {
|
||||||
|
settings.HiddenPresets = []string{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user