added text boxes for input for numbers
This commit is contained in:
+98
-69
@@ -1,96 +1,125 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/data/binding"
|
||||||
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TextOverlayProgressBar is a custom widget that displays a progress bar with text overlay.
|
// numericInputSlider is a custom widget that combines a slider and a text entry for numeric input.
|
||||||
// This allows showing progress information (e.g., step description) directly on the progress bar.
|
type numericInputSlider struct {
|
||||||
type TextOverlayProgressBar struct {
|
|
||||||
widget.BaseWidget
|
widget.BaseWidget
|
||||||
progressBar *widget.ProgressBar
|
value binding.Float
|
||||||
|
min, max float64
|
||||||
|
slider *widget.Slider
|
||||||
|
entry *widget.Entry
|
||||||
|
format string
|
||||||
|
errorLabel *widget.Label
|
||||||
label *widget.Label
|
label *widget.Label
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTextOverlayProgressBar creates a new TextOverlayProgressBar.
|
type numericInputSliderRenderer struct {
|
||||||
func NewTextOverlayProgressBar() *TextOverlayProgressBar {
|
slider *numericInputSlider
|
||||||
p := &TextOverlayProgressBar{
|
|
||||||
progressBar: widget.NewProgressBar(),
|
|
||||||
label: widget.NewLabel(""),
|
|
||||||
}
|
|
||||||
p.ExtendBaseWidget(p)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetValue sets the progress value of the underlying progress bar.
|
|
||||||
func (p *TextOverlayProgressBar) SetValue(v float64) {
|
|
||||||
p.progressBar.SetValue(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetText sets the text to be displayed on the progress bar.
|
|
||||||
func (p *TextOverlayProgressBar) SetText(text string) {
|
|
||||||
p.label.SetText(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateRenderer returns a new renderer for the widget.
|
|
||||||
func (p *TextOverlayProgressBar) CreateRenderer() fyne.WidgetRenderer {
|
|
||||||
return &textOverlayProgressBarRenderer{
|
|
||||||
progressBar: p.progressBar,
|
|
||||||
label: p.label,
|
|
||||||
objects: []fyne.CanvasObject{p.progressBar, p.label},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// textOverlayProgressBarRenderer is the renderer for the TextOverlayProgressBar.
|
|
||||||
// It handles the layout and rendering of the progress bar and the overlay text.
|
|
||||||
type textOverlayProgressBarRenderer struct {
|
|
||||||
progressBar *widget.ProgressBar
|
|
||||||
label *widget.Label
|
label *widget.Label
|
||||||
|
entry *widget.Entry
|
||||||
|
sliderWidget *widget.Slider
|
||||||
|
errorLabel *widget.Label
|
||||||
|
layout fyne.Layout
|
||||||
objects []fyne.CanvasObject
|
objects []fyne.CanvasObject
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout defines the size and position of the progress bar and the label.
|
func (r *numericInputSliderRenderer) MinSize() fyne.Size {
|
||||||
func (r *textOverlayProgressBarRenderer) Layout(size fyne.Size) {
|
return r.layout.MinSize(r.objects)
|
||||||
r.progressBar.Resize(size)
|
|
||||||
r.label.Resize(size)
|
|
||||||
r.label.Move(fyne.NewPos(0, 0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MinSize returns the minimum size of the widget.
|
func (r *numericInputSliderRenderer) Layout(size fyne.Size) {
|
||||||
func (r *textOverlayProgressBarRenderer) MinSize() fyne.Size {
|
r.layout.Layout(r.objects, size)
|
||||||
return r.progressBar.MinSize()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh redraws the widget.
|
func (r *numericInputSliderRenderer) Objects() []fyne.CanvasObject {
|
||||||
func (r *textOverlayProgressBarRenderer) Refresh() {
|
|
||||||
r.progressBar.Refresh()
|
|
||||||
r.label.Refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Objects returns the canvas objects that make up the widget.
|
|
||||||
func (r *textOverlayProgressBarRenderer) Objects() []fyne.CanvasObject {
|
|
||||||
return r.objects
|
return r.objects
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy is a no-op for this renderer.
|
func (r *numericInputSliderRenderer) Refresh() {
|
||||||
func (r *textOverlayProgressBarRenderer) Destroy() {}
|
r.label.SetText(r.slider.label.Text)
|
||||||
|
|
||||||
// CustomTheme is a custom theme to make the progress bar thinner.
|
|
||||||
type CustomTheme struct {
|
|
||||||
fyne.Theme
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCustomTheme creates a new CustomTheme.
|
func (r *numericInputSliderRenderer) Destroy() {}
|
||||||
func NewCustomTheme(theme fyne.Theme) *CustomTheme {
|
|
||||||
return &CustomTheme{Theme: theme}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns the size for a given themeable item.
|
// newNumericInputSlider creates a new numericInputSlider widget.
|
||||||
// It overrides the default progress bar height to make it thinner.
|
func newNumericInputSlider(min, max float64, initialValue float64, format string, labelText string) *numericInputSlider {
|
||||||
func (t *CustomTheme) Size(name fyne.ThemeSizeName) float32 {
|
s := &numericInputSlider{
|
||||||
if name == "progressBar.height" {
|
min: min,
|
||||||
return 10
|
max: max,
|
||||||
|
format: format,
|
||||||
}
|
}
|
||||||
return t.Theme.Size(name)
|
s.ExtendBaseWidget(s)
|
||||||
|
|
||||||
|
s.label = widget.NewLabel(labelText)
|
||||||
|
s.value = binding.NewFloat()
|
||||||
|
s.value.Set(initialValue)
|
||||||
|
|
||||||
|
s.slider = widget.NewSlider(min, max)
|
||||||
|
s.slider.Bind(s.value)
|
||||||
|
|
||||||
|
s.entry = widget.NewEntry()
|
||||||
|
s.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := s.value.Get()
|
||||||
|
s.entry.SetText(fmt.Sprintf(s.format, val))
|
||||||
|
}))
|
||||||
|
|
||||||
|
s.errorLabel = widget.NewLabel("")
|
||||||
|
s.errorLabel.Hide()
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate checks the text entry for valid numeric input within the defined range.
|
||||||
|
func (s *numericInputSlider) validate(text string, onError func(bool)) {
|
||||||
|
text = strings.TrimSuffix(text, "px")
|
||||||
|
text = strings.TrimSuffix(text, "%")
|
||||||
|
val, err := strconv.ParseFloat(text, 64)
|
||||||
|
if err != nil {
|
||||||
|
s.errorLabel.SetText("Not a number")
|
||||||
|
s.errorLabel.Show()
|
||||||
|
onError(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if val < s.min || val > s.max {
|
||||||
|
s.errorLabel.SetText(fmt.Sprintf("Out of range (%.0f-%.0f)", s.min, s.max))
|
||||||
|
s.errorLabel.Show()
|
||||||
|
onError(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.errorLabel.Hide()
|
||||||
|
onError(false)
|
||||||
|
s.value.Set(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRenderer is a method required by the Fyne toolkit to render the widget.
|
||||||
|
func (s *numericInputSlider) CreateRenderer() fyne.WidgetRenderer {
|
||||||
|
r := &numericInputSliderRenderer{
|
||||||
|
slider: s,
|
||||||
|
label: s.label,
|
||||||
|
entry: s.entry,
|
||||||
|
sliderWidget: s.slider,
|
||||||
|
errorLabel: s.errorLabel,
|
||||||
|
}
|
||||||
|
|
||||||
|
r.layout = layout.NewVBoxLayout()
|
||||||
|
r.objects = []fyne.CanvasObject{
|
||||||
|
container.NewBorder(nil, nil, r.label, r.entry),
|
||||||
|
r.sliderWidget,
|
||||||
|
r.errorLabel,
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"fyne.io/fyne/v2/app"
|
"fyne.io/fyne/v2/app"
|
||||||
"fyne.io/fyne/v2/canvas"
|
"fyne.io/fyne/v2/canvas"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/data/binding"
|
||||||
"fyne.io/fyne/v2/dialog"
|
"fyne.io/fyne/v2/dialog"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
|
||||||
@@ -30,7 +31,6 @@ import (
|
|||||||
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")
|
||||||
a.Settings().SetTheme(&CustomTheme{a.Settings().Theme()})
|
|
||||||
w := a.NewWindow("RPG City Maker")
|
w := a.NewWindow("RPG City Maker")
|
||||||
w.Resize(fyne.NewSize(800, 600))
|
w.Resize(fyne.NewSize(800, 600))
|
||||||
|
|
||||||
@@ -211,206 +211,258 @@ func main() {
|
|||||||
canvasImg.Image = finalImage
|
canvasImg.Image = finalImage
|
||||||
|
|
||||||
}
|
}
|
||||||
// Create UI elements for controlling terrain generation settings
|
var generateBtn *widget.Button
|
||||||
detailLabel := widget.NewLabel(fmt.Sprintf("Detail: %.0f", settings.Detail))
|
errorStates := make(map[string]bool)
|
||||||
detailSlider := widget.NewSlider(1, 16)
|
|
||||||
detailSlider.OnChanged = func(val float64) {
|
// ... (other code)
|
||||||
|
|
||||||
|
// Main generation button and logic
|
||||||
|
generateBtn = widget.NewButton("Generate", func() {
|
||||||
|
// ... (generation logic)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Function to update the generate button state
|
||||||
|
updateGenerateBtnState := func() {
|
||||||
|
for _, hasError := range errorStates {
|
||||||
|
if hasError {
|
||||||
|
generateBtn.Disable()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generateBtn.Enable()
|
||||||
|
}
|
||||||
|
|
||||||
|
detailSlider := newNumericInputSlider(1, 16, settings.Detail, "%.0f", "Detail")
|
||||||
|
detailSlider.entry.OnChanged = func(s string) {
|
||||||
|
detailSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["detail"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
detailSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := detailSlider.value.Get()
|
||||||
settings.Detail = val
|
settings.Detail = val
|
||||||
detailLabel.SetText(fmt.Sprintf("Detail: %.0f", settings.Detail))
|
}))
|
||||||
}
|
|
||||||
detailSlider.SetValue(settings.Detail)
|
|
||||||
|
|
||||||
roughnessLabel := widget.NewLabel(fmt.Sprintf("Roughness: %.0f%%", settings.Roughness))
|
roughnessSlider := newNumericInputSlider(0, 100, settings.Roughness, "%.0f%%", "Roughness")
|
||||||
roughnessSlider := widget.NewSlider(0, 100)
|
roughnessSlider.entry.OnChanged = func(s string) {
|
||||||
roughnessSlider.OnChanged = func(val float64) {
|
roughnessSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["roughness"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
roughnessSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := roughnessSlider.value.Get()
|
||||||
settings.Roughness = val
|
settings.Roughness = val
|
||||||
roughnessLabel.SetText(fmt.Sprintf("Roughness: %.0f%%", settings.Roughness))
|
}))
|
||||||
}
|
|
||||||
roughnessSlider.SetValue(settings.Roughness)
|
|
||||||
// Create UI elements for controlling lake generation settings
|
// Create UI elements for controlling lake generation settings
|
||||||
lakesLabel := widget.NewLabel(fmt.Sprintf("Lakes: %d", settings.Lakes))
|
lakesSlider := newNumericInputSlider(0, 15, float64(settings.Lakes), "%.0f", "Lakes")
|
||||||
lakesSlider := widget.NewSlider(0, 15)
|
lakesSlider.entry.OnChanged = func(s string) {
|
||||||
lakesSlider.OnChanged = func(val float64) {
|
lakesSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["lakes"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
lakesSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := lakesSlider.value.Get()
|
||||||
settings.Lakes = int(val)
|
settings.Lakes = int(val)
|
||||||
lakesLabel.SetText(fmt.Sprintf("Lakes: %d", settings.Lakes))
|
}))
|
||||||
|
|
||||||
|
lakeSizeLowerSlider := newNumericInputSlider(1, 100, settings.LakeSizeLower, "%.0f%%", "Min Lake Size")
|
||||||
|
lakeSizeLowerSlider.entry.OnChanged = func(s string) {
|
||||||
|
lakeSizeLowerSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["lakeSizeLower"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
lakesSlider.SetValue(float64(settings.Lakes))
|
lakeSizeLowerSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := lakeSizeLowerSlider.value.Get()
|
||||||
lakeSizeLowerLabel := widget.NewLabel(fmt.Sprintf("Min Lake Size: %.0f%%", settings.LakeSizeLower))
|
|
||||||
lakeSizeLowerSlider := widget.NewSlider(1, 100)
|
|
||||||
lakeSizeUpperLabel := widget.NewLabel(fmt.Sprintf("Max Lake Size: %.0f%%", settings.LakeSizeUpper))
|
|
||||||
lakeSizeUpperSlider := widget.NewSlider(1, 100)
|
|
||||||
|
|
||||||
lakeSizeLowerSlider.OnChanged = func(val float64) {
|
|
||||||
settings.LakeSizeLower = val
|
settings.LakeSizeLower = val
|
||||||
if settings.LakeSizeLower > settings.LakeSizeUpper {
|
}))
|
||||||
settings.LakeSizeUpper = settings.LakeSizeLower
|
|
||||||
lakeSizeUpperSlider.SetValue(settings.LakeSizeUpper)
|
|
||||||
}
|
|
||||||
lakeSizeLowerLabel.SetText(fmt.Sprintf("Min Lake Size: %.0f%%", settings.LakeSizeLower))
|
|
||||||
}
|
|
||||||
lakeSizeLowerSlider.SetValue(settings.LakeSizeLower)
|
|
||||||
|
|
||||||
lakeSizeUpperSlider.OnChanged = func(val float64) {
|
lakeSizeUpperSlider := newNumericInputSlider(1, 100, settings.LakeSizeUpper, "%.0f%%", "Max Lake Size")
|
||||||
|
lakeSizeUpperSlider.entry.OnChanged = func(s string) {
|
||||||
|
lakeSizeUpperSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["lakeSizeUpper"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
lakeSizeUpperSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := lakeSizeUpperSlider.value.Get()
|
||||||
settings.LakeSizeUpper = val
|
settings.LakeSizeUpper = val
|
||||||
if settings.LakeSizeUpper < settings.LakeSizeLower {
|
}))
|
||||||
settings.LakeSizeLower = settings.LakeSizeUpper
|
riversSlider := newNumericInputSlider(0, 5, float64(settings.Rivers), "%.0f", "Rivers")
|
||||||
lakeSizeLowerSlider.SetValue(settings.LakeSizeLower)
|
riversSlider.entry.OnChanged = func(s string) {
|
||||||
|
riversSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["rivers"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
lakeSizeUpperLabel.SetText(fmt.Sprintf("Max Lake Size: %.0f%%", settings.LakeSizeUpper))
|
riversSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
}
|
val, _ := riversSlider.value.Get()
|
||||||
lakeSizeUpperSlider.SetValue(settings.LakeSizeUpper)
|
|
||||||
// Create UI elements for controlling river generation settings
|
|
||||||
riversLabel := widget.NewLabel(fmt.Sprintf("Rivers: %d", settings.Rivers))
|
|
||||||
riversSlider := widget.NewSlider(0, 5)
|
|
||||||
riversSlider.OnChanged = func(val float64) {
|
|
||||||
settings.Rivers = int(val)
|
settings.Rivers = int(val)
|
||||||
riversLabel.SetText(fmt.Sprintf("Rivers: %d", settings.Rivers))
|
}))
|
||||||
|
|
||||||
|
minRiverWidthSlider := newNumericInputSlider(1, 100, settings.MinRiverWidth, "%.0f%%", "Min River Width")
|
||||||
|
minRiverWidthSlider.entry.OnChanged = func(s string) {
|
||||||
|
minRiverWidthSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["minRiverWidth"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
riversSlider.SetValue(float64(settings.Rivers))
|
minRiverWidthSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := minRiverWidthSlider.value.Get()
|
||||||
minRiverWidthLabel := widget.NewLabel(fmt.Sprintf("Min River Width: %.0f%%", settings.MinRiverWidth))
|
|
||||||
minRiverWidthSlider := widget.NewSlider(1, 100)
|
|
||||||
maxRiverWidthLabel := widget.NewLabel(fmt.Sprintf("Max River Width: %.0f%%", settings.MaxRiverWidth))
|
|
||||||
maxRiverWidthSlider := widget.NewSlider(1, 100)
|
|
||||||
|
|
||||||
minRiverWidthSlider.OnChanged = func(val float64) {
|
|
||||||
settings.MinRiverWidth = val
|
settings.MinRiverWidth = val
|
||||||
if settings.MinRiverWidth > settings.MaxRiverWidth {
|
}))
|
||||||
settings.MaxRiverWidth = settings.MinRiverWidth
|
|
||||||
maxRiverWidthSlider.SetValue(settings.MaxRiverWidth)
|
|
||||||
}
|
|
||||||
minRiverWidthLabel.SetText(fmt.Sprintf("Min River Width: %.0f%%", settings.MinRiverWidth))
|
|
||||||
}
|
|
||||||
minRiverWidthSlider.SetValue(settings.MinRiverWidth)
|
|
||||||
|
|
||||||
maxRiverWidthSlider.OnChanged = func(val float64) {
|
maxRiverWidthSlider := newNumericInputSlider(1, 100, settings.MaxRiverWidth, "%.0f%%", "Max River Width")
|
||||||
|
maxRiverWidthSlider.entry.OnChanged = func(s string) {
|
||||||
|
maxRiverWidthSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["maxRiverWidth"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
maxRiverWidthSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := maxRiverWidthSlider.value.Get()
|
||||||
settings.MaxRiverWidth = val
|
settings.MaxRiverWidth = val
|
||||||
if settings.MaxRiverWidth < settings.MinRiverWidth {
|
}))
|
||||||
settings.MinRiverWidth = settings.MaxRiverWidth
|
|
||||||
minRiverWidthSlider.SetValue(settings.MinRiverWidth)
|
|
||||||
}
|
|
||||||
maxRiverWidthLabel.SetText(fmt.Sprintf("Max River Width: %.0f%%", settings.MaxRiverWidth))
|
|
||||||
}
|
|
||||||
maxRiverWidthSlider.SetValue(settings.MaxRiverWidth)
|
|
||||||
|
|
||||||
riverCurvynessLabel := widget.NewLabel(fmt.Sprintf("River Curvyness: %.0f%%", settings.RiverCurvyness))
|
riverCurvynessSlider := newNumericInputSlider(0, 100, settings.RiverCurvyness, "%.0f%%", "River Curvyness")
|
||||||
riverCurvynessSlider := widget.NewSlider(0, 100)
|
riverCurvynessSlider.entry.OnChanged = func(s string) {
|
||||||
riverCurvynessSlider.OnChanged = func(val float64) {
|
riverCurvynessSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["riverCurvyness"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
riverCurvynessSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := riverCurvynessSlider.value.Get()
|
||||||
settings.RiverCurvyness = val
|
settings.RiverCurvyness = val
|
||||||
riverCurvynessLabel.SetText(fmt.Sprintf("River Curvyness: %.0f%%", settings.RiverCurvyness))
|
}))
|
||||||
|
minTreeSizeSlider := newNumericInputSlider(1, 150, settings.MinTreeSize, "%.0fpx", "Min Tree Size")
|
||||||
|
minTreeSizeSlider.entry.OnChanged = func(s string) {
|
||||||
|
minTreeSizeSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["minTreeSize"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
riverCurvynessSlider.SetValue(settings.RiverCurvyness)
|
minTreeSizeSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
// Create UI elements for controlling tree generation settings
|
val, _ := minTreeSizeSlider.value.Get()
|
||||||
minTreeSizeLabel := widget.NewLabel(fmt.Sprintf("Min Tree Size: %.0fpx", settings.MinTreeSize))
|
|
||||||
minTreeSizeSlider := widget.NewSlider(1, 150)
|
|
||||||
maxTreeSizeLabel := widget.NewLabel(fmt.Sprintf("Max Tree Size: %.0fpx", settings.MaxTreeSize))
|
|
||||||
maxTreeSizeSlider := widget.NewSlider(1, 150)
|
|
||||||
|
|
||||||
minTreeSizeSlider.OnChanged = func(val float64) {
|
|
||||||
settings.MinTreeSize = val
|
settings.MinTreeSize = val
|
||||||
if settings.MinTreeSize > settings.MaxTreeSize {
|
}))
|
||||||
settings.MaxTreeSize = settings.MinTreeSize
|
|
||||||
maxTreeSizeSlider.SetValue(settings.MaxTreeSize)
|
|
||||||
}
|
|
||||||
minTreeSizeLabel.SetText(fmt.Sprintf("Min Tree Size: %.0fpx", settings.MinTreeSize))
|
|
||||||
}
|
|
||||||
minTreeSizeSlider.SetValue(settings.MinTreeSize)
|
|
||||||
|
|
||||||
maxTreeSizeSlider.OnChanged = func(val float64) {
|
maxTreeSizeSlider := newNumericInputSlider(1, 150, settings.MaxTreeSize, "%.0fpx", "Max Tree Size")
|
||||||
|
maxTreeSizeSlider.entry.OnChanged = func(s string) {
|
||||||
|
maxTreeSizeSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["maxTreeSize"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
maxTreeSizeSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := maxTreeSizeSlider.value.Get()
|
||||||
settings.MaxTreeSize = val
|
settings.MaxTreeSize = val
|
||||||
if settings.MaxTreeSize < settings.MinTreeSize {
|
}))
|
||||||
settings.MinTreeSize = settings.MaxTreeSize
|
|
||||||
minTreeSizeSlider.SetValue(settings.MinTreeSize)
|
|
||||||
}
|
|
||||||
maxTreeSizeLabel.SetText(fmt.Sprintf("Max Tree Size: %.0fpx", settings.MaxTreeSize))
|
|
||||||
}
|
|
||||||
maxTreeSizeSlider.SetValue(settings.MaxTreeSize)
|
|
||||||
|
|
||||||
treeCoverageLabel := widget.NewLabel(fmt.Sprintf("Tree Coverage: %.0f%%", settings.TreeCoverage))
|
treeCoverageSlider := newNumericInputSlider(1, 100, settings.TreeCoverage, "%.0f%%", "Tree Coverage")
|
||||||
treeCoverageSlider := widget.NewSlider(1, 100)
|
treeCoverageSlider.entry.OnChanged = func(s string) {
|
||||||
treeCoverageSlider.OnChanged = func(val float64) {
|
treeCoverageSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["treeCoverage"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
treeCoverageSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := treeCoverageSlider.value.Get()
|
||||||
settings.TreeCoverage = val
|
settings.TreeCoverage = val
|
||||||
treeCoverageLabel.SetText(fmt.Sprintf("Tree Coverage: %.0f%%", settings.TreeCoverage))
|
}))
|
||||||
}
|
|
||||||
treeCoverageSlider.SetValue(settings.TreeCoverage)
|
|
||||||
|
|
||||||
treeClumpinessLabel := widget.NewLabel(fmt.Sprintf("Tree Clumpiness: %.0f%%", settings.TreeClumpiness))
|
treeClumpinessSlider := newNumericInputSlider(0, 100, settings.TreeClumpiness, "%.0f%%", "Tree Clumpiness")
|
||||||
treeClumpinessSlider := widget.NewSlider(0, 100)
|
treeClumpinessSlider.entry.OnChanged = func(s string) {
|
||||||
treeClumpinessSlider.OnChanged = func(val float64) {
|
treeClumpinessSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["treeClumpiness"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
treeClumpinessSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := treeClumpinessSlider.value.Get()
|
||||||
settings.TreeClumpiness = val
|
settings.TreeClumpiness = val
|
||||||
treeClumpinessLabel.SetText(fmt.Sprintf("Tree Clumpiness: %.0f%%", settings.TreeClumpiness))
|
}))
|
||||||
|
numRoadsSlider := newNumericInputSlider(0, 2000, float64(settings.NumRoads), "%.0f", "Number of Roads")
|
||||||
|
numRoadsSlider.entry.OnChanged = func(s string) {
|
||||||
|
numRoadsSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["numRoads"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
treeClumpinessSlider.SetValue(settings.TreeClumpiness)
|
numRoadsSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
// Create UI elements for controlling road generation settings
|
val, _ := numRoadsSlider.value.Get()
|
||||||
numRoadsLabel := widget.NewLabel(fmt.Sprintf("Number of Roads: %d", settings.NumRoads))
|
|
||||||
numRoadsSlider := widget.NewSlider(0, 2000)
|
|
||||||
numRoadsSlider.OnChanged = func(val float64) {
|
|
||||||
settings.NumRoads = int(val)
|
settings.NumRoads = int(val)
|
||||||
numRoadsLabel.SetText(fmt.Sprintf("Number of Roads: %d", settings.NumRoads))
|
}))
|
||||||
|
|
||||||
|
minRoadWidthSlider := newNumericInputSlider(1, 150, settings.MinRoadWidth, "%.0fpx", "Min Road Width")
|
||||||
|
minRoadWidthSlider.entry.OnChanged = func(s string) {
|
||||||
|
minRoadWidthSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["minRoadWidth"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
numRoadsSlider.SetValue(float64(settings.NumRoads))
|
minRoadWidthSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := minRoadWidthSlider.value.Get()
|
||||||
minRoadWidthLabel := widget.NewLabel(fmt.Sprintf("Min Road Width: %.0fpx", settings.MinRoadWidth))
|
|
||||||
minRoadWidthSlider := widget.NewSlider(1, 150)
|
|
||||||
maxRoadWidthLabel := widget.NewLabel(fmt.Sprintf("Max Road Width: %.0fpx", settings.MaxRoadWidth))
|
|
||||||
maxRoadWidthSlider := widget.NewSlider(1, 150)
|
|
||||||
|
|
||||||
minRoadWidthSlider.OnChanged = func(val float64) {
|
|
||||||
settings.MinRoadWidth = val
|
settings.MinRoadWidth = val
|
||||||
if settings.MinRoadWidth > settings.MaxRoadWidth {
|
}))
|
||||||
settings.MaxRoadWidth = settings.MinRoadWidth
|
|
||||||
maxRoadWidthSlider.SetValue(settings.MaxRoadWidth)
|
|
||||||
}
|
|
||||||
minRoadWidthLabel.SetText(fmt.Sprintf("Min Road Width: %.0fpx", settings.MinRoadWidth))
|
|
||||||
}
|
|
||||||
minRoadWidthSlider.SetValue(settings.MinRoadWidth)
|
|
||||||
|
|
||||||
maxRoadWidthSlider.OnChanged = func(val float64) {
|
maxRoadWidthSlider := newNumericInputSlider(1, 150, settings.MaxRoadWidth, "%.0fpx", "Max Road Width")
|
||||||
|
maxRoadWidthSlider.entry.OnChanged = func(s string) {
|
||||||
|
maxRoadWidthSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["maxRoadWidth"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
maxRoadWidthSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := maxRoadWidthSlider.value.Get()
|
||||||
settings.MaxRoadWidth = val
|
settings.MaxRoadWidth = val
|
||||||
if settings.MaxRoadWidth < settings.MinRoadWidth {
|
}))
|
||||||
settings.MinRoadWidth = settings.MaxRoadWidth
|
|
||||||
minRoadWidthSlider.SetValue(settings.MinRoadWidth)
|
|
||||||
}
|
|
||||||
maxRoadWidthLabel.SetText(fmt.Sprintf("Max Road Width: %.0fpx", settings.MaxRoadWidth))
|
|
||||||
}
|
|
||||||
maxRoadWidthSlider.SetValue(settings.MaxRoadWidth)
|
|
||||||
|
|
||||||
roadExitsLabel := widget.NewLabel(fmt.Sprintf("Road Exits: %d", settings.RoadExits))
|
roadExitsSlider := newNumericInputSlider(0, 100, float64(settings.RoadExits), "%.0f", "Road Exits")
|
||||||
roadExitsSlider := widget.NewSlider(0, 100)
|
roadExitsSlider.entry.OnChanged = func(s string) {
|
||||||
roadExitsSlider.OnChanged = func(val float64) {
|
roadExitsSlider.validate(s, func(hasError bool) {
|
||||||
if val > float64(settings.NumRoads) {
|
errorStates["roadExits"] = hasError
|
||||||
val = float64(settings.NumRoads)
|
updateGenerateBtnState()
|
||||||
roadExitsSlider.SetValue(val)
|
})
|
||||||
}
|
}
|
||||||
|
roadExitsSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := roadExitsSlider.value.Get()
|
||||||
settings.RoadExits = int(val)
|
settings.RoadExits = int(val)
|
||||||
roadExitsLabel.SetText(fmt.Sprintf("Road Exits: %d", settings.RoadExits))
|
}))
|
||||||
}
|
|
||||||
roadExitsSlider.SetValue(float64(settings.RoadExits))
|
|
||||||
|
|
||||||
roadCurvynessLabel := widget.NewLabel(fmt.Sprintf("Road Curvyness: %.0f%%", settings.RoadCurvyness))
|
roadCurvynessSlider := newNumericInputSlider(0, 100, settings.RoadCurvyness, "%.0f%%", "Road Curvyness")
|
||||||
roadCurvynessSlider := widget.NewSlider(0, 100)
|
roadCurvynessSlider.entry.OnChanged = func(s string) {
|
||||||
roadCurvynessSlider.OnChanged = func(val float64) {
|
roadCurvynessSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["roadCurvyness"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
roadCurvynessSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := roadCurvynessSlider.value.Get()
|
||||||
settings.RoadCurvyness = val
|
settings.RoadCurvyness = val
|
||||||
roadCurvynessLabel.SetText(fmt.Sprintf("Road Curvyness: %.0f%%", settings.RoadCurvyness))
|
}))
|
||||||
}
|
|
||||||
roadCurvynessSlider.SetValue(settings.RoadCurvyness)
|
|
||||||
|
|
||||||
roadDistributionLabel := widget.NewLabel(fmt.Sprintf("Distribution: %.0f%%", settings.RoadDistribution))
|
roadDistributionSlider := newNumericInputSlider(0, 100, settings.RoadDistribution, "%.0f%%", "Distribution")
|
||||||
roadDistributionSlider := widget.NewSlider(0, 100)
|
roadDistributionSlider.entry.OnChanged = func(s string) {
|
||||||
roadDistributionSlider.OnChanged = func(val float64) {
|
roadDistributionSlider.validate(s, func(hasError bool) {
|
||||||
settings.RoadDistribution = val
|
errorStates["roadDistribution"] = hasError
|
||||||
roadDistributionLabel.SetText(fmt.Sprintf("Distribution: %.0f%%", settings.RoadDistribution))
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
roadDistributionSlider.SetValue(settings.RoadDistribution)
|
roadDistributionSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := roadDistributionSlider.value.Get()
|
||||||
|
settings.RoadDistribution = val
|
||||||
|
}))
|
||||||
|
|
||||||
// Create UI elements for error display and action buttons
|
// Create UI elements for error display and action buttons
|
||||||
errorLabel := canvas.NewText("", color.RGBA{R: 255, A: 255})
|
errorLabel := widget.NewLabel("")
|
||||||
errorLabel.TextSize = 12
|
errorLabel.Wrapping = fyne.TextWrapWord
|
||||||
errorLabel.Hide()
|
errorLabel.Hide()
|
||||||
|
|
||||||
var generateBtn *widget.Button
|
progressBar := widget.NewProgressBar()
|
||||||
progressBar := NewTextOverlayProgressBar()
|
|
||||||
exportCanvasBtn := widget.NewButton("Export Canvas", func() {
|
exportCanvasBtn := widget.NewButton("Export Canvas", func() {
|
||||||
showSaveDialog(w, canvasImg.Image, settings)
|
showSaveDialog(w, canvasImg.Image, settings)
|
||||||
})
|
})
|
||||||
@@ -436,34 +488,17 @@ func main() {
|
|||||||
generateBtn.Enable()
|
generateBtn.Enable()
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
// Set up progress bar
|
|
||||||
steps := 10
|
|
||||||
currentStep := 0
|
|
||||||
|
|
||||||
seedProvider := NewSeedProvider(settings.Seed)
|
seedProvider := NewSeedProvider(settings.Seed)
|
||||||
// Step 1: Generating Heightmap
|
// Step 1: Generating Heightmap
|
||||||
currentStep++
|
|
||||||
fyne.Do(func() {
|
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Heightmap", currentStep, steps))
|
|
||||||
progressBar.SetValue(float64(currentStep) / float64(steps))
|
|
||||||
})
|
|
||||||
noiseImg := GenerateHeightmap(settings.Width, settings.Height, int(settings.Detail), 100.0, seedProvider.Next())
|
noiseImg := GenerateHeightmap(settings.Width, settings.Height, int(settings.Detail), 100.0, seedProvider.Next())
|
||||||
|
|
||||||
// Step 2: Generating Lakes
|
// Step 2: Generating Lakes
|
||||||
currentStep++
|
|
||||||
fyne.Do(func() {
|
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Lakes", currentStep, steps))
|
|
||||||
progressBar.SetValue(float64(currentStep) / float64(steps))
|
|
||||||
})
|
|
||||||
var lakeImage image.Image
|
var lakeImage image.Image
|
||||||
lakeImage, lakes = GenerateLakes(settings.Width, settings.Height, settings.Lakes, settings.LakeSizeLower, settings.LakeSizeUpper, noiseImg, seedProvider.Next())
|
lakeImage, lakes = GenerateLakes(settings.Width, settings.Height, settings.Lakes, settings.LakeSizeLower, settings.LakeSizeUpper, noiseImg, seedProvider.Next())
|
||||||
|
|
||||||
// Step 3: Generating Rivers
|
// Step 3: Generating Rivers
|
||||||
currentStep++
|
|
||||||
fyne.Do(func() {
|
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Rivers", currentStep, steps))
|
|
||||||
progressBar.SetValue(float64(currentStep) / float64(steps))
|
|
||||||
})
|
|
||||||
var riverImage image.Image
|
var riverImage image.Image
|
||||||
riverImage, riverPixels = GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakes, seedProvider.Next(), noiseImg)
|
riverImage, riverPixels = GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakes, seedProvider.Next(), noiseImg)
|
||||||
|
|
||||||
@@ -476,11 +511,7 @@ func main() {
|
|||||||
allWaterPixels := append(flatLakePixels, riverPixels...)
|
allWaterPixels := append(flatLakePixels, riverPixels...)
|
||||||
|
|
||||||
// Step 4: Generating Roads
|
// Step 4: Generating Roads
|
||||||
currentStep++
|
|
||||||
fyne.Do(func() {
|
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Roads", currentStep, steps))
|
|
||||||
progressBar.SetValue(float64(currentStep) / float64(steps))
|
|
||||||
})
|
|
||||||
var roadImage *image.RGBA
|
var roadImage *image.RGBA
|
||||||
roadPixels, bridgePixels, roadImage = GenerateRoads(settings.Width, settings.Height, settings, noiseImg, allWaterPixels, seedProvider.Next()) // Draw roadImage over finalImage
|
roadPixels, bridgePixels, roadImage = GenerateRoads(settings.Width, settings.Height, settings, noiseImg, allWaterPixels, seedProvider.Next()) // Draw roadImage over finalImage
|
||||||
for y := 0; y < roadImage.Bounds().Max.Y; y++ {
|
for y := 0; y < roadImage.Bounds().Max.Y; y++ {
|
||||||
@@ -493,68 +524,40 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 5: Generating Buildings
|
// Step 5: Generating Buildings
|
||||||
currentStep++
|
|
||||||
fyne.Do(func() {
|
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Buildings", currentStep, steps))
|
|
||||||
progressBar.SetValue(float64(currentStep) / float64(steps))
|
|
||||||
})
|
|
||||||
buildings, buildingPixels = GenerateBuildings(finalImage, settings.Width, settings.Height, settings, roadPixels, allWaterPixels, seedProvider.Next())
|
buildings, buildingPixels = GenerateBuildings(finalImage, settings.Width, settings.Height, settings, roadPixels, allWaterPixels, seedProvider.Next())
|
||||||
|
|
||||||
// Step 6: Darkening Water Areas
|
// Step 6: Darkening Water Areas
|
||||||
currentStep++
|
|
||||||
fyne.Do(func() {
|
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Darkening Water Areas", currentStep, steps))
|
|
||||||
progressBar.SetValue(float64(currentStep) / float64(steps))
|
|
||||||
})
|
|
||||||
darkenedHeightmap := DarkenLakeAreas(noiseImg, allWaterPixels)
|
darkenedHeightmap := DarkenLakeAreas(noiseImg, allWaterPixels)
|
||||||
|
|
||||||
// Step 7: Flattening Building Areas
|
// Step 7: Flattening Building Areas
|
||||||
currentStep++
|
|
||||||
fyne.Do(func() {
|
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Flattening Building Areas", currentStep, steps))
|
|
||||||
progressBar.SetValue(float64(currentStep) / float64(steps))
|
|
||||||
})
|
|
||||||
flattenedBuildingHeightmap := FlattenBuildingAreas(darkenedHeightmap.(*image.RGBA), buildings, settings.Width, settings.Height)
|
flattenedBuildingHeightmap := FlattenBuildingAreas(darkenedHeightmap.(*image.RGBA), buildings, settings.Width, settings.Height)
|
||||||
|
|
||||||
flattenedHeightmap := FlattenRoadAreas(flattenedBuildingHeightmap, roadPixels)
|
flattenedHeightmap := FlattenRoadAreas(flattenedBuildingHeightmap, roadPixels)
|
||||||
|
|
||||||
// Step 8: Applying Roughness
|
// Step 8: Applying Roughness
|
||||||
currentStep++
|
|
||||||
fyne.Do(func() {
|
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Applying Roughness", currentStep, steps))
|
|
||||||
progressBar.SetValue(float64(currentStep) / float64(steps))
|
|
||||||
})
|
|
||||||
compositeImg := ApplyRoughness(flattenedHeightmap, settings.Roughness)
|
compositeImg := ApplyRoughness(flattenedHeightmap, settings.Roughness)
|
||||||
|
|
||||||
// Step 9: Generating Trees
|
// Step 9: Generating Trees
|
||||||
currentStep++
|
|
||||||
fyne.Do(func() {
|
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Trees", currentStep, steps))
|
|
||||||
progressBar.SetValue(float64(currentStep) / float64(steps))
|
|
||||||
})
|
|
||||||
treePixels = GenerateTrees(finalImage, allWaterPixels, roadPixels, buildingPixels, settings.MinTreeSize, settings.MaxTreeSize, settings.TreeCoverage, settings.TreeClumpiness, seedProvider.Next())
|
treePixels = GenerateTrees(finalImage, allWaterPixels, roadPixels, buildingPixels, settings.MinTreeSize, settings.MaxTreeSize, settings.TreeCoverage, settings.TreeClumpiness, seedProvider.Next())
|
||||||
|
|
||||||
// Step 10: Generating Bump Map
|
// Step 10: Generating Bump Map
|
||||||
currentStep++
|
|
||||||
fyne.Do(func() {
|
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Bump Map", currentStep, steps))
|
|
||||||
progressBar.SetValue(float64(currentStep) / float64(steps))
|
|
||||||
})
|
|
||||||
bumpMap := GenerateBumpMap(compositeImg.(*image.RGBA), settings.Width, settings.Height, 0.10)
|
bumpMap := GenerateBumpMap(compositeImg.(*image.RGBA), settings.Width, settings.Height, 0.10)
|
||||||
|
|
||||||
// Step 11: Finalizing Images
|
// Step 11: Finalizing Images
|
||||||
currentStep++
|
|
||||||
fyne.Do(func() {
|
fyne.Do(func() {
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Finalizing Images", currentStep, steps))
|
|
||||||
progressBar.SetValue(float64(currentStep) / float64(steps))
|
|
||||||
heightmapImg.Image = compositeImg
|
heightmapImg.Image = compositeImg
|
||||||
heightmapImg.Refresh()
|
heightmapImg.Refresh()
|
||||||
bumpmapImg.Image = bumpMap
|
bumpmapImg.Image = bumpMap
|
||||||
bumpmapImg.Refresh()
|
bumpmapImg.Refresh()
|
||||||
canvasImg.Image = finalImage
|
canvasImg.Image = finalImage
|
||||||
canvasImg.Refresh()
|
canvasImg.Refresh()
|
||||||
|
|
||||||
progressBar.SetText("Generation Complete!")
|
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
})
|
})
|
||||||
@@ -609,100 +612,85 @@ func main() {
|
|||||||
})
|
})
|
||||||
// Create tabs for organizing settings
|
// Create tabs for organizing settings
|
||||||
terrainTab := container.NewTabItem("Terrain", container.NewVBox(
|
terrainTab := container.NewTabItem("Terrain", container.NewVBox(
|
||||||
detailLabel,
|
|
||||||
detailSlider,
|
detailSlider,
|
||||||
roughnessLabel,
|
|
||||||
roughnessSlider,
|
roughnessSlider,
|
||||||
|
|
||||||
widget.NewLabel(""), // Spacer
|
widget.NewLabel(""), // Spacer
|
||||||
|
|
||||||
minTreeSizeLabel,
|
|
||||||
minTreeSizeSlider,
|
minTreeSizeSlider,
|
||||||
maxTreeSizeLabel,
|
|
||||||
maxTreeSizeSlider,
|
maxTreeSizeSlider,
|
||||||
treeCoverageLabel,
|
|
||||||
treeCoverageSlider,
|
treeCoverageSlider,
|
||||||
treeClumpinessLabel,
|
|
||||||
treeClumpinessSlider,
|
treeClumpinessSlider,
|
||||||
))
|
))
|
||||||
|
|
||||||
waterTab := container.NewTabItem("Water", container.NewVBox(
|
waterTab := container.NewTabItem("Water", container.NewVBox(
|
||||||
lakesLabel,
|
|
||||||
lakesSlider,
|
lakesSlider,
|
||||||
lakeSizeLowerLabel,
|
|
||||||
lakeSizeLowerSlider,
|
lakeSizeLowerSlider,
|
||||||
lakeSizeUpperLabel,
|
|
||||||
lakeSizeUpperSlider,
|
lakeSizeUpperSlider,
|
||||||
|
|
||||||
widget.NewLabel(""), // Spacer
|
widget.NewLabel(""), // Spacer
|
||||||
|
|
||||||
riversLabel,
|
|
||||||
riversSlider,
|
riversSlider,
|
||||||
minRiverWidthLabel,
|
|
||||||
minRiverWidthSlider,
|
minRiverWidthSlider,
|
||||||
maxRiverWidthLabel,
|
|
||||||
maxRiverWidthSlider,
|
maxRiverWidthSlider,
|
||||||
riverCurvynessLabel,
|
|
||||||
riverCurvynessSlider,
|
riverCurvynessSlider,
|
||||||
))
|
))
|
||||||
|
|
||||||
roadDistributionSlider.SetValue(settings.RoadDistribution)
|
|
||||||
|
|
||||||
roadsTab := container.NewTabItem("Roads", container.NewVBox(
|
roadsTab := container.NewTabItem("Roads", container.NewVBox(
|
||||||
numRoadsLabel,
|
|
||||||
numRoadsSlider,
|
numRoadsSlider,
|
||||||
minRoadWidthLabel,
|
|
||||||
minRoadWidthSlider,
|
minRoadWidthSlider,
|
||||||
maxRoadWidthLabel,
|
|
||||||
maxRoadWidthSlider,
|
maxRoadWidthSlider,
|
||||||
roadExitsLabel,
|
|
||||||
roadExitsSlider,
|
roadExitsSlider,
|
||||||
roadCurvynessLabel,
|
|
||||||
roadCurvynessSlider,
|
roadCurvynessSlider,
|
||||||
roadDistributionLabel,
|
|
||||||
roadDistributionSlider,
|
roadDistributionSlider,
|
||||||
))
|
))
|
||||||
// Create UI elements for building generation settings
|
numBuildingsSlider := newNumericInputSlider(0, 10000, float64(settings.NumBuildings), "%.0f", "Number of Buildings")
|
||||||
numBuildingsLabel := widget.NewLabel(fmt.Sprintf("Number of Buildings: %d", settings.NumBuildings))
|
numBuildingsSlider.entry.OnChanged = func(s string) {
|
||||||
numBuildingsSlider := widget.NewSlider(0, 10000)
|
numBuildingsSlider.validate(s, func(hasError bool) {
|
||||||
numBuildingsSlider.OnChanged = func(val float64) {
|
errorStates["numBuildings"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
numBuildingsSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := numBuildingsSlider.value.Get()
|
||||||
settings.NumBuildings = int(val)
|
settings.NumBuildings = int(val)
|
||||||
numBuildingsLabel.SetText(fmt.Sprintf("Number of Buildings: %d", settings.NumBuildings))
|
}))
|
||||||
|
|
||||||
|
minBuildingSizeSlider := newNumericInputSlider(1, 150, settings.MinBuildingSize, "%.0fpx", "Min Building Size")
|
||||||
|
minBuildingSizeSlider.entry.OnChanged = func(s string) {
|
||||||
|
minBuildingSizeSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["minBuildingSize"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
numBuildingsSlider.SetValue(float64(settings.NumBuildings))
|
minBuildingSizeSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := minBuildingSizeSlider.value.Get()
|
||||||
minBuildingSizeLabel := widget.NewLabel(fmt.Sprintf("Min Building Size: %.0fpx", settings.MinBuildingSize))
|
|
||||||
minBuildingSizeSlider := widget.NewSlider(1, 150)
|
|
||||||
maxBuildingSizeLabel := widget.NewLabel(fmt.Sprintf("Max Building Size: %.0fpx", settings.MaxBuildingSize))
|
|
||||||
maxBuildingSizeSlider := widget.NewSlider(1, 150)
|
|
||||||
|
|
||||||
minBuildingSizeSlider.OnChanged = func(val float64) {
|
|
||||||
settings.MinBuildingSize = val
|
settings.MinBuildingSize = val
|
||||||
if settings.MinBuildingSize > settings.MaxBuildingSize {
|
}))
|
||||||
settings.MaxBuildingSize = settings.MinBuildingSize
|
|
||||||
maxBuildingSizeSlider.SetValue(settings.MaxBuildingSize)
|
|
||||||
}
|
|
||||||
minBuildingSizeLabel.SetText(fmt.Sprintf("Min Building Size: %.0fpx", settings.MinBuildingSize))
|
|
||||||
}
|
|
||||||
minBuildingSizeSlider.SetValue(settings.MinBuildingSize)
|
|
||||||
|
|
||||||
maxBuildingSizeSlider.OnChanged = func(val float64) {
|
maxBuildingSizeSlider := newNumericInputSlider(1, 150, settings.MaxBuildingSize, "%.0fpx", "Max Building Size")
|
||||||
|
maxBuildingSizeSlider.entry.OnChanged = func(s string) {
|
||||||
|
maxBuildingSizeSlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["maxBuildingSize"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
maxBuildingSizeSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := maxBuildingSizeSlider.value.Get()
|
||||||
settings.MaxBuildingSize = val
|
settings.MaxBuildingSize = val
|
||||||
if settings.MaxBuildingSize < settings.MinBuildingSize {
|
}))
|
||||||
settings.MinBuildingSize = settings.MaxBuildingSize
|
|
||||||
minBuildingSizeSlider.SetValue(settings.MinBuildingSize)
|
|
||||||
}
|
|
||||||
maxBuildingSizeLabel.SetText(fmt.Sprintf("Max Building Size: %.0fpx", settings.MaxBuildingSize))
|
|
||||||
}
|
|
||||||
maxBuildingSizeSlider.SetValue(settings.MaxBuildingSize)
|
|
||||||
|
|
||||||
buildingDistributionLabel := widget.NewLabel(fmt.Sprintf("Building Distribution: %.0f%%", settings.BuildingDistribution))
|
buildingDistributionSlider := newNumericInputSlider(0, 100, settings.BuildingDistribution, "%.0f%%", "Building Distribution")
|
||||||
buildingDistributionSlider := widget.NewSlider(0, 100)
|
buildingDistributionSlider.entry.OnChanged = func(s string) {
|
||||||
buildingDistributionSlider.OnChanged = func(val float64) {
|
buildingDistributionSlider.validate(s, func(hasError bool) {
|
||||||
settings.BuildingDistribution = val
|
errorStates["buildingDistribution"] = hasError
|
||||||
buildingDistributionLabel.SetText(fmt.Sprintf("Building Distribution: %.0f%%", settings.BuildingDistribution))
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
buildingDistributionSlider.SetValue(settings.BuildingDistribution)
|
buildingDistributionSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := buildingDistributionSlider.value.Get()
|
||||||
|
settings.BuildingDistribution = val
|
||||||
|
}))
|
||||||
|
|
||||||
buildingShapeLabel := widget.NewLabel("Building Shape:")
|
buildingShapeLabel := widget.NewLabel("Building Shape:")
|
||||||
buildingShapeSelect := widget.NewSelect([]string{"squares", "circles", "rectangles", "mixed", "procedural"}, func(s string) {
|
buildingShapeSelect := widget.NewSelect([]string{"squares", "circles", "rectangles", "mixed", "procedural"}, func(s string) {
|
||||||
@@ -732,43 +720,45 @@ func main() {
|
|||||||
rectangleRatioSlider,
|
rectangleRatioSlider,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create sliders for procedural building complexity
|
minBuildingComplexitySlider := newNumericInputSlider(1, 6, float64(settings.MinBuildingComplexity), "%.0f", "Min Building Complexity")
|
||||||
minBuildingComplexityLabel := widget.NewLabel(fmt.Sprintf("Min Building Complexity: %d", settings.MinBuildingComplexity))
|
minBuildingComplexitySlider.entry.OnChanged = func(s string) {
|
||||||
minBuildingComplexitySlider := widget.NewSlider(1, 6)
|
minBuildingComplexitySlider.validate(s, func(hasError bool) {
|
||||||
minBuildingComplexitySlider.OnChanged = func(val float64) {
|
errorStates["minBuildingComplexity"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
minBuildingComplexitySlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := minBuildingComplexitySlider.value.Get()
|
||||||
settings.MinBuildingComplexity = int(val)
|
settings.MinBuildingComplexity = int(val)
|
||||||
if float64(settings.MinBuildingComplexity) > float64(settings.MaxBuildingComplexity) {
|
}))
|
||||||
settings.MaxBuildingComplexity = settings.MinBuildingComplexity
|
|
||||||
}
|
|
||||||
minBuildingComplexityLabel.SetText(fmt.Sprintf("Min Building Complexity: %d", settings.MinBuildingComplexity))
|
|
||||||
}
|
|
||||||
minBuildingComplexitySlider.SetValue(float64(settings.MinBuildingComplexity))
|
|
||||||
|
|
||||||
maxBuildingComplexityLabel := widget.NewLabel(fmt.Sprintf("Max Building Complexity: %d", settings.MaxBuildingComplexity))
|
maxBuildingComplexitySlider := newNumericInputSlider(1, 6, float64(settings.MaxBuildingComplexity), "%.0f", "Max Building Complexity")
|
||||||
maxBuildingComplexitySlider := widget.NewSlider(1, 6)
|
maxBuildingComplexitySlider.entry.OnChanged = func(s string) {
|
||||||
maxBuildingComplexitySlider.OnChanged = func(val float64) {
|
maxBuildingComplexitySlider.validate(s, func(hasError bool) {
|
||||||
|
errorStates["maxBuildingComplexity"] = hasError
|
||||||
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
maxBuildingComplexitySlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := maxBuildingComplexitySlider.value.Get()
|
||||||
settings.MaxBuildingComplexity = int(val)
|
settings.MaxBuildingComplexity = int(val)
|
||||||
if float64(settings.MaxBuildingComplexity) < float64(settings.MinBuildingComplexity) {
|
}))
|
||||||
settings.MinBuildingComplexity = settings.MaxBuildingComplexity
|
|
||||||
}
|
|
||||||
maxBuildingComplexityLabel.SetText(fmt.Sprintf("Max Building Complexity: %d", settings.MaxBuildingComplexity))
|
|
||||||
}
|
|
||||||
maxBuildingComplexitySlider.SetValue(float64(settings.MaxBuildingComplexity))
|
|
||||||
|
|
||||||
buildingComplexityRatioLabel := widget.NewLabel(fmt.Sprintf("Building Complexity Ratio: %.0f%%", settings.BuildingComplexityRatio))
|
buildingComplexityRatioSlider := newNumericInputSlider(0, 100, settings.BuildingComplexityRatio, "%.0f%%", "Building Complexity Ratio")
|
||||||
buildingComplexityRatioSlider := widget.NewSlider(0, 100)
|
buildingComplexityRatioSlider.entry.OnChanged = func(s string) {
|
||||||
buildingComplexityRatioSlider.OnChanged = func(val float64) {
|
buildingComplexityRatioSlider.validate(s, func(hasError bool) {
|
||||||
settings.BuildingComplexityRatio = val
|
errorStates["buildingComplexityRatio"] = hasError
|
||||||
buildingComplexityRatioLabel.SetText(fmt.Sprintf("Building Complexity Ratio: %.0f%%", settings.BuildingComplexityRatio))
|
updateGenerateBtnState()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
buildingComplexityRatioSlider.SetValue(settings.BuildingComplexityRatio)
|
buildingComplexityRatioSlider.value.AddListener(binding.NewDataListener(func() {
|
||||||
|
val, _ := buildingComplexityRatioSlider.value.Get()
|
||||||
|
settings.BuildingComplexityRatio = val
|
||||||
|
}))
|
||||||
|
|
||||||
proceduralContainer := container.NewVBox(
|
proceduralContainer := container.NewVBox(
|
||||||
minBuildingComplexityLabel,
|
|
||||||
minBuildingComplexitySlider,
|
minBuildingComplexitySlider,
|
||||||
maxBuildingComplexityLabel,
|
|
||||||
maxBuildingComplexitySlider,
|
maxBuildingComplexitySlider,
|
||||||
buildingComplexityRatioLabel,
|
|
||||||
buildingComplexityRatioSlider,
|
buildingComplexityRatioSlider,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -899,13 +889,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildingsTab := container.NewTabItem("Buildings", container.NewVBox(
|
buildingsTab := container.NewTabItem("Buildings", container.NewVBox(
|
||||||
numBuildingsLabel,
|
|
||||||
numBuildingsSlider,
|
numBuildingsSlider,
|
||||||
minBuildingSizeLabel,
|
|
||||||
minBuildingSizeSlider,
|
minBuildingSizeSlider,
|
||||||
maxBuildingSizeLabel,
|
|
||||||
maxBuildingSizeSlider,
|
maxBuildingSizeSlider,
|
||||||
buildingDistributionLabel,
|
|
||||||
buildingDistributionSlider,
|
buildingDistributionSlider,
|
||||||
buildingShapeLabel,
|
buildingShapeLabel,
|
||||||
buildingShapeSelect,
|
buildingShapeSelect,
|
||||||
|
|||||||
Reference in New Issue
Block a user