630 lines
17 KiB
Go
630 lines
17 KiB
Go
package calculator
|
|
|
|
import (
|
|
"errors"
|
|
"galaxy/calc"
|
|
"galaxy/client/widget/numeric"
|
|
"galaxy/util"
|
|
"slices"
|
|
"strconv"
|
|
"sync"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/lang"
|
|
"fyne.io/fyne/v2/widget"
|
|
)
|
|
|
|
type CalculatorOpt func(*Calculator)
|
|
type ShipClass struct {
|
|
Name string
|
|
Drive float64
|
|
Armament uint
|
|
Weapons float64
|
|
Shields float64
|
|
Cargo float64
|
|
}
|
|
type ShipClassFn func(string, float64, uint, float64, float64, float64)
|
|
|
|
type Calculator struct {
|
|
CanvasObject fyne.CanvasObject
|
|
|
|
playerDrivesTech float64
|
|
playerWeaponsTech float64
|
|
playerShieldsTech float64
|
|
playerCargoTech float64
|
|
|
|
shipDriveEntry *numeric.FloatEntry
|
|
shipWeaponsEntry *numeric.FloatEntry
|
|
shipArmamentEntry *numeric.IntEntry
|
|
shipShieldsEntry *numeric.FloatEntry
|
|
shipCargoEntry *numeric.FloatEntry
|
|
|
|
playerDrivesTechEntry *numeric.FloatEntry
|
|
playerWeaponsTechEntry *numeric.FloatEntry
|
|
playerShieldsTechEntry *numeric.FloatEntry
|
|
playerCargoTechEntry *numeric.FloatEntry
|
|
|
|
drivesTechOverride *widget.Check
|
|
weaponsTechOverride *widget.Check
|
|
shieldsTechOverride *widget.Check
|
|
cargoTechOverride *widget.Check
|
|
|
|
massEntry *numeric.FloatEntry
|
|
speedEntry *numeric.FloatEntry
|
|
attackEntry *numeric.FloatEntry
|
|
defenseEntry *numeric.FloatEntry
|
|
cargoLoadEntry *numeric.FloatEntry
|
|
planetMatEntry *numeric.FloatEntry
|
|
|
|
massOverride *widget.Check
|
|
speedOverride *widget.Check
|
|
attackOverride *widget.Check
|
|
defenseOverride *widget.Check
|
|
cargoLoadMaximize *widget.Check
|
|
planetMatOverride *widget.Check
|
|
|
|
planetLabel *widget.Label
|
|
planetMassProdLabel *widget.Label
|
|
planetShipsProdLabel *widget.Label
|
|
planetContainer fyne.CanvasObject
|
|
planetProdContainer fyne.CanvasObject
|
|
|
|
shipSelector *widget.SelectEntry
|
|
shipCreateButton *widget.Button
|
|
|
|
onCreateHandler ShipClassFn
|
|
loader ShipClassFn
|
|
knownClasses []ShipClass
|
|
|
|
validateMu sync.RWMutex
|
|
|
|
l, mat, res float64
|
|
|
|
Valid bool
|
|
}
|
|
|
|
func WithPlayerDrives(v float64) CalculatorOpt {
|
|
return func(c *Calculator) { c.playerDrivesTech = v }
|
|
}
|
|
|
|
func WithPlayerWeapons(v float64) CalculatorOpt {
|
|
return func(c *Calculator) { c.playerWeaponsTech = v }
|
|
}
|
|
|
|
func WithPlayerShields(v float64) CalculatorOpt {
|
|
return func(c *Calculator) { c.playerShieldsTech = v }
|
|
}
|
|
|
|
func WithPlayerCargo(v float64) CalculatorOpt {
|
|
return func(c *Calculator) { c.playerCargoTech = v }
|
|
}
|
|
|
|
func WithCreateHandler(f ShipClassFn) CalculatorOpt {
|
|
return func(c *Calculator) { c.onCreateHandler = f }
|
|
}
|
|
|
|
func NewCaclulator(opts ...CalculatorOpt) *Calculator {
|
|
c := &Calculator{}
|
|
|
|
c.shipCreateButton = widget.NewButton(lang.L("ship.action.create"), c.onCreateShipClassButton)
|
|
c.shipCreateButton.Disable()
|
|
c.loader = c.LoadShipClass
|
|
|
|
c.planetMatEntry = numeric.NewFloatEntry(10, c.onPlanetMatChange)
|
|
c.planetMatOverride = widget.NewCheck("", c.overridePlanetMat)
|
|
c.planetMatOverride.Disable()
|
|
c.planetLabel = widget.NewLabel("")
|
|
c.planetMassProdLabel = bareLabel("")
|
|
c.planetShipsProdLabel = bareLabel("")
|
|
c.planetProdContainer = container.NewHBox(
|
|
label(lang.L("planet.prod.mass")+":"),
|
|
fixedLabel(c.planetMassProdLabel, 80),
|
|
label(lang.L("planet.prod.ships")+":"),
|
|
fixedLabel(c.planetShipsProdLabel, 80),
|
|
)
|
|
c.planetProdContainer.Hide()
|
|
|
|
c.planetContainer = container.NewVBox(
|
|
widget.NewSeparator(),
|
|
container.NewHBox(c.planetLabel),
|
|
rowForItem(lang.L("planet.mat")+":", floatEntry(c.planetMatEntry, 100), c.planetMatOverride),
|
|
c.planetProdContainer,
|
|
)
|
|
c.planetContainer.Hide()
|
|
|
|
c.shipSelector = widget.NewSelectEntry(nil)
|
|
c.shipSelector.OnChanged = c.onShipSelectorChange
|
|
|
|
c.shipDriveEntry = numeric.NewFloatEntry(7, c.onShipDriveChange)
|
|
c.shipWeaponsEntry = numeric.NewFloatEntry(7, c.onShipWeaponsChange)
|
|
c.shipArmamentEntry = numeric.NewIntEntry(7, c.onShipArmamentChange)
|
|
c.shipShieldsEntry = numeric.NewFloatEntry(7, c.onShipShieldsChange)
|
|
c.shipCargoEntry = numeric.NewFloatEntry(7, c.onShipCargoChange)
|
|
|
|
c.playerDrivesTechEntry = numeric.NewFloatEntry(7, c.onDrivesTechChange)
|
|
c.playerWeaponsTechEntry = numeric.NewFloatEntry(7, c.onWeaponsTechChange)
|
|
c.playerShieldsTechEntry = numeric.NewFloatEntry(7, c.onShieldsTechChange)
|
|
c.playerCargoTechEntry = numeric.NewFloatEntry(7, c.onCargoTechChange)
|
|
|
|
c.massEntry = numeric.NewFloatEntry(7, c.onMassChange)
|
|
c.speedEntry = numeric.NewFloatEntry(7, c.onSpeedChange)
|
|
c.attackEntry = numeric.NewFloatEntry(7, c.onAttackChange)
|
|
c.defenseEntry = numeric.NewFloatEntry(7, c.onDefenseChange)
|
|
c.cargoLoadEntry = numeric.NewFloatEntry(7, c.onCargoLoadChange)
|
|
|
|
c.drivesTechOverride = widget.NewCheck("", c.overrideDrivesTech)
|
|
c.drivesTechOverride.Disable()
|
|
c.weaponsTechOverride = widget.NewCheck("", c.overrideWeaponsTech)
|
|
c.weaponsTechOverride.Disable()
|
|
c.shieldsTechOverride = widget.NewCheck("", c.overrideShieldsTech)
|
|
c.shieldsTechOverride.Disable()
|
|
c.cargoTechOverride = widget.NewCheck("", c.overrideCargoTech)
|
|
c.cargoTechOverride.Disable()
|
|
|
|
c.massOverride = widget.NewCheck("", c.overrideMass)
|
|
c.massOverride.Disable()
|
|
c.speedOverride = widget.NewCheck("", c.overrideSpeed)
|
|
c.speedOverride.Disable()
|
|
c.attackOverride = widget.NewCheck("", c.overrideAttack)
|
|
c.attackOverride.Disable()
|
|
c.defenseOverride = widget.NewCheck("", c.overrideDefense)
|
|
c.defenseOverride.Disable()
|
|
c.cargoLoadMaximize = widget.NewCheck(lang.L("label.max"), c.maximizeCargoLoad)
|
|
c.cargoLoadMaximize.SetChecked(true)
|
|
|
|
createShip := container.NewBorder(
|
|
nil, // top
|
|
nil, // bottom
|
|
nil, // left
|
|
c.shipCreateButton, // right
|
|
c.shipSelector, // center
|
|
)
|
|
|
|
c.CanvasObject = container.NewVBox(
|
|
container.NewPadded(createShip),
|
|
widget.NewSeparator(),
|
|
rowForTech(lang.L("tech.d")+":",
|
|
c.shipDriveEntry, floatEntry(c.playerDrivesTechEntry, 80), c.drivesTechOverride),
|
|
rowForWeapons(lang.L("tech.w")+":",
|
|
c.shipArmamentEntry, c.shipWeaponsEntry, floatEntry(c.playerWeaponsTechEntry, 80), c.weaponsTechOverride),
|
|
rowForTech(lang.L("tech.s")+":",
|
|
c.shipShieldsEntry, floatEntry(c.playerShieldsTechEntry, 80), c.shieldsTechOverride),
|
|
rowForTech(lang.L("tech.c")+":",
|
|
c.shipCargoEntry, floatEntry(c.playerCargoTechEntry, 80), c.cargoTechOverride),
|
|
widget.NewSeparator(),
|
|
rowForItem(lang.L("ship.load")+":",
|
|
floatEntry(c.cargoLoadEntry, 80), c.cargoLoadMaximize),
|
|
rowForItem(lang.L("ship.mass")+":",
|
|
floatEntry(c.massEntry, 80), c.massOverride),
|
|
rowForItem(lang.L("ship.speed")+":",
|
|
floatEntry(c.speedEntry, 80), c.speedOverride),
|
|
rowForItem(lang.L("ship.attack")+":",
|
|
floatEntry(c.attackEntry, 80), c.attackOverride),
|
|
rowForItem(lang.L("ship.defense")+":",
|
|
floatEntry(c.defenseEntry, 80), c.defenseOverride),
|
|
c.planetContainer,
|
|
)
|
|
|
|
c.Init(opts...)
|
|
|
|
return c
|
|
}
|
|
|
|
func (c *Calculator) Init(opts ...CalculatorOpt) {
|
|
for i := range opts {
|
|
opts[i](c)
|
|
}
|
|
|
|
c.playerDrivesTechEntry.SetOrigin(c.playerDrivesTech)
|
|
c.playerWeaponsTechEntry.SetOrigin(c.playerWeaponsTech)
|
|
c.playerShieldsTechEntry.SetOrigin(c.playerShieldsTech)
|
|
c.playerCargoTechEntry.SetOrigin(c.playerCargoTech)
|
|
|
|
c.CanvasObject.Show()
|
|
}
|
|
|
|
func (c *Calculator) Refresh() {
|
|
c.validate()
|
|
c.CanvasObject.Refresh()
|
|
}
|
|
|
|
func (c *Calculator) RegisterClasses(shipClass ...ShipClass) {
|
|
c.knownClasses = shipClass
|
|
names := make([]string, len(c.knownClasses))
|
|
for i := range c.knownClasses {
|
|
names[i] = c.knownClasses[i].Name
|
|
}
|
|
slices.Sort(names)
|
|
c.shipSelector = widget.NewSelectEntry(names)
|
|
c.shipSelector.OnChanged = c.onShipSelectorChange
|
|
}
|
|
|
|
func (c *Calculator) onCreateShipClassButton() {
|
|
if c.onCreateHandler == nil || !c.Valid {
|
|
return
|
|
}
|
|
}
|
|
|
|
func (c *Calculator) validate() {
|
|
fyne.Do(func() {
|
|
c.validateMu.Lock()
|
|
err := c.validateEntries()
|
|
c.Valid = err == nil
|
|
if err != nil {
|
|
} else {
|
|
}
|
|
c.shipClassNameValidate()
|
|
c.validateMu.Unlock()
|
|
})
|
|
}
|
|
|
|
func (c *Calculator) validateEntries() (err error) {
|
|
defer func() {
|
|
if err != nil {
|
|
c.cargoLoadEntry.Clear()
|
|
if !c.massOverride.Checked {
|
|
c.massEntry.Clear()
|
|
}
|
|
if !c.speedOverride.Checked {
|
|
c.speedEntry.Clear()
|
|
}
|
|
if !c.attackOverride.Checked {
|
|
c.attackEntry.Clear()
|
|
}
|
|
if !c.defenseOverride.Checked {
|
|
c.defenseEntry.Clear()
|
|
}
|
|
// c.planetProdContainer.Hide()
|
|
}
|
|
}()
|
|
drive, ok := c.shipDriveEntry.Value()
|
|
if !ok {
|
|
err = errors.New("Parameter Drive is not valid")
|
|
return
|
|
}
|
|
driveTech, ok := c.playerDrivesTechEntry.Value()
|
|
if !ok {
|
|
err = errors.New("Drive tech level is not valid")
|
|
return
|
|
}
|
|
armament, ok := c.shipArmamentEntry.Value()
|
|
if !ok {
|
|
err = errors.New("Parameter Armament is not valid")
|
|
return
|
|
}
|
|
weapons, ok := c.shipWeaponsEntry.Value()
|
|
if !ok {
|
|
err = errors.New("Parameter Weapons is not valid")
|
|
return
|
|
}
|
|
weaponsTech, ok := c.playerWeaponsTechEntry.Value()
|
|
if !ok {
|
|
err = errors.New("Weapons tech level is not valid")
|
|
return
|
|
}
|
|
shields, ok := c.shipShieldsEntry.Value()
|
|
if !ok {
|
|
err = errors.New("Parameter Shields is not valid")
|
|
return
|
|
}
|
|
shieldsTech, ok := c.playerShieldsTechEntry.Value()
|
|
if !ok {
|
|
err = errors.New("Shields tech level is not valid")
|
|
return
|
|
}
|
|
cargo, ok := c.shipCargoEntry.Value()
|
|
if !ok {
|
|
err = errors.New("Parameter Cargo is not valid")
|
|
return
|
|
}
|
|
cargoTech, ok := c.playerCargoTechEntry.Value()
|
|
if !ok {
|
|
err = errors.New("Cargo tech level is not valid")
|
|
return
|
|
}
|
|
|
|
err = calc.ValidateShipTypeValues(drive, armament, weapons, shields, cargo)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
var cargoLoad float64
|
|
if c.cargoLoadMaximize.Checked {
|
|
cargoLoad = calc.CargoCapacity(cargo, cargoTech)
|
|
c.cargoLoadEntry.SetOrigin(cargoLoad)
|
|
} else if cargoLoad, ok = c.cargoLoadEntry.Value(); !ok {
|
|
err = errors.New("Cargo load value is not valid")
|
|
return
|
|
}
|
|
|
|
emptyMass, ok := calc.EmptyMass(drive, weapons, uint(armament), shields, cargo)
|
|
if !ok {
|
|
err = errors.New("Unable to calculate empty mass (check armament and weapons)")
|
|
return
|
|
}
|
|
fullMass := calc.FullMass(emptyMass, cargoLoad)
|
|
speed := calc.Speed(calc.DriveEffective(drive, driveTech), fullMass)
|
|
effectiveAttack := calc.EffectiveAttack(weapons, weaponsTech)
|
|
effectiveDefense := calc.EffectiveDefence(shields, shieldsTech, fullMass)
|
|
|
|
c.massEntry.SetOrigin(emptyMass)
|
|
c.speedEntry.SetOrigin(speed)
|
|
c.attackEntry.SetOrigin(effectiveAttack)
|
|
c.defenseEntry.SetOrigin(effectiveDefense)
|
|
|
|
planetMat, ok := c.planetMatEntry.Value()
|
|
if !ok {
|
|
// c.planetProdContainer.Hide()
|
|
} else {
|
|
massProd := calc.PlanetProduceShipMass(c.l, planetMat, c.res)
|
|
c.planetMassProdLabel.SetText(strconv.FormatFloat(util.Fixed3(massProd), 'f', -1, 64))
|
|
ships := 0.
|
|
if emptyMass > 0 {
|
|
ships = massProd / emptyMass
|
|
}
|
|
c.planetShipsProdLabel.SetText(strconv.FormatFloat(util.Fixed3(ships), 'f', -1, 64))
|
|
c.planetProdContainer.Show()
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (c *Calculator) onOriginInputChange(cb *widget.Check, e *numeric.FloatEntry) {
|
|
if e == nil {
|
|
return
|
|
}
|
|
if cb != nil {
|
|
cb.Checked = e.Overriden()
|
|
if !cb.Checked {
|
|
cb.Disable()
|
|
} else {
|
|
cb.Enable()
|
|
}
|
|
}
|
|
c.onFloatEntryChange(e)
|
|
}
|
|
|
|
func (c *Calculator) onFloatEntryChange(e *numeric.FloatEntry) {
|
|
if e == nil {
|
|
return
|
|
}
|
|
e.Validate()
|
|
c.validate()
|
|
}
|
|
|
|
func (c *Calculator) onIntEntryChange(e *numeric.IntEntry) {
|
|
if e == nil {
|
|
return
|
|
}
|
|
e.Validate()
|
|
c.validate()
|
|
}
|
|
|
|
func (c *Calculator) overrideChecked(cb *widget.Check, e *numeric.FloatEntry) {
|
|
if cb == nil || e == nil {
|
|
return
|
|
}
|
|
if !cb.Checked {
|
|
e.Reset()
|
|
cb.Disable()
|
|
}
|
|
}
|
|
|
|
func (c *Calculator) onShipDriveChange(string) {
|
|
c.onFloatEntryChange(c.shipDriveEntry)
|
|
}
|
|
|
|
func (c *Calculator) onShipArmamentChange(string) {
|
|
defer c.onIntEntryChange(c.shipArmamentEntry)
|
|
if weapons, ok := c.shipWeaponsEntry.Value(); !ok || !c.shipWeaponsEntry.Valid {
|
|
return
|
|
} else if armament, ok := c.shipArmamentEntry.Value(); !ok || !c.shipArmamentEntry.Valid {
|
|
return
|
|
} else if armament > 0 && weapons == 0 {
|
|
c.shipWeaponsEntry.SetOrigin(1.0)
|
|
} else if armament == 0 && weapons > 0 {
|
|
c.shipWeaponsEntry.SetOrigin(0.0)
|
|
}
|
|
}
|
|
|
|
func (c *Calculator) onShipWeaponsChange(string) {
|
|
defer c.onFloatEntryChange(c.shipWeaponsEntry)
|
|
if weapons, ok := c.shipWeaponsEntry.Value(); !ok || !c.shipWeaponsEntry.Valid {
|
|
return
|
|
} else if armament, ok := c.shipArmamentEntry.Value(); !ok || !c.shipArmamentEntry.Valid {
|
|
return
|
|
} else if weapons > 0 && armament == 0 {
|
|
c.shipArmamentEntry.SetOrigin(1)
|
|
} else if weapons == 0 && armament > 0 {
|
|
c.shipArmamentEntry.SetOrigin(0)
|
|
}
|
|
}
|
|
|
|
func (c *Calculator) onShipShieldsChange(string) {
|
|
c.onFloatEntryChange(c.shipShieldsEntry)
|
|
}
|
|
|
|
func (c *Calculator) onShipCargoChange(string) {
|
|
c.onFloatEntryChange(c.shipCargoEntry)
|
|
}
|
|
|
|
func (c *Calculator) onDrivesTechChange(string) {
|
|
c.onOriginInputChange(c.drivesTechOverride, c.playerDrivesTechEntry)
|
|
}
|
|
|
|
func (c *Calculator) overrideDrivesTech(bool) {
|
|
c.overrideChecked(c.drivesTechOverride, c.playerDrivesTechEntry)
|
|
}
|
|
|
|
func (c *Calculator) onWeaponsTechChange(string) {
|
|
c.onOriginInputChange(c.weaponsTechOverride, c.playerWeaponsTechEntry)
|
|
}
|
|
|
|
func (c *Calculator) overrideWeaponsTech(bool) {
|
|
c.overrideChecked(c.weaponsTechOverride, c.playerWeaponsTechEntry)
|
|
}
|
|
|
|
func (c *Calculator) onShieldsTechChange(string) {
|
|
c.onOriginInputChange(c.shieldsTechOverride, c.playerShieldsTechEntry)
|
|
}
|
|
|
|
func (c *Calculator) overrideShieldsTech(bool) {
|
|
c.overrideChecked(c.shieldsTechOverride, c.playerShieldsTechEntry)
|
|
}
|
|
|
|
func (c *Calculator) onCargoTechChange(string) {
|
|
c.onOriginInputChange(c.cargoTechOverride, c.playerCargoTechEntry)
|
|
}
|
|
|
|
func (c *Calculator) overrideCargoTech(bool) {
|
|
c.overrideChecked(c.cargoTechOverride, c.playerCargoTechEntry)
|
|
}
|
|
|
|
func (c *Calculator) onCargoLoadChange(string) {
|
|
c.onFloatEntryChange(c.cargoLoadEntry)
|
|
}
|
|
|
|
func (c *Calculator) onMassChange(string) {
|
|
c.onOriginInputChange(c.massOverride, c.massEntry)
|
|
}
|
|
|
|
func (c *Calculator) overrideMass(bool) {
|
|
c.overrideChecked(c.massOverride, c.massEntry)
|
|
}
|
|
|
|
func (c *Calculator) onSpeedChange(string) {
|
|
c.onOriginInputChange(c.speedOverride, c.speedEntry)
|
|
}
|
|
|
|
func (c *Calculator) overrideSpeed(bool) {
|
|
c.overrideChecked(c.speedOverride, c.speedEntry)
|
|
}
|
|
|
|
func (c *Calculator) onAttackChange(string) {
|
|
c.onOriginInputChange(c.attackOverride, c.attackEntry)
|
|
}
|
|
|
|
func (c *Calculator) overrideAttack(bool) {
|
|
c.overrideChecked(c.attackOverride, c.attackEntry)
|
|
}
|
|
|
|
func (c *Calculator) onDefenseChange(string) {
|
|
c.onOriginInputChange(c.defenseOverride, c.defenseEntry)
|
|
}
|
|
|
|
func (c *Calculator) overrideDefense(bool) {
|
|
c.overrideChecked(c.defenseOverride, c.defenseEntry)
|
|
}
|
|
|
|
func (c *Calculator) maximizeCargoLoad(bool) {
|
|
c.validate()
|
|
}
|
|
|
|
func (c *Calculator) onPlanetMatChange(string) {
|
|
c.onOriginInputChange(c.planetMatOverride, c.planetMatEntry)
|
|
}
|
|
|
|
func (c *Calculator) overridePlanetMat(bool) {
|
|
c.overrideChecked(c.planetMatOverride, c.planetMatEntry)
|
|
}
|
|
|
|
func (c *Calculator) onShipSelectorChange(v string) {
|
|
i, ok := c.shipClassNameValidate()
|
|
if i < 0 || !ok || c.loader == nil {
|
|
return
|
|
}
|
|
c.loader(
|
|
c.knownClasses[i].Name,
|
|
c.knownClasses[i].Drive,
|
|
c.knownClasses[i].Armament,
|
|
c.knownClasses[i].Weapons,
|
|
c.knownClasses[i].Shields,
|
|
c.knownClasses[i].Cargo,
|
|
)
|
|
}
|
|
|
|
func (c *Calculator) shipClassNameValidate() (int, bool) {
|
|
var canCreateShip bool
|
|
defer func() {
|
|
if canCreateShip && c.Valid {
|
|
c.shipCreateButton.Enable()
|
|
} else {
|
|
c.shipCreateButton.Disable()
|
|
}
|
|
}()
|
|
name, canCreateShip := util.ValidateTypeName(c.shipSelector.Text)
|
|
if canCreateShip {
|
|
c.shipSelector.Text = name
|
|
}
|
|
i := slices.IndexFunc(c.knownClasses, func(v ShipClass) bool { return v.Name == name })
|
|
canCreateShip = canCreateShip && i < 0
|
|
return i, canCreateShip
|
|
}
|
|
|
|
func (c *Calculator) LoadShipClass(n string, D float64, A uint, W float64, S float64, C float64) {
|
|
c.shipDriveEntry.SetOrigin(D)
|
|
c.shipArmamentEntry.SetOrigin(int(A))
|
|
c.shipWeaponsEntry.SetOrigin(W)
|
|
c.shipShieldsEntry.SetOrigin(S)
|
|
c.shipCargoEntry.SetOrigin(C)
|
|
}
|
|
|
|
func rowForItem(l string, entry, override fyne.CanvasObject) fyne.CanvasObject {
|
|
i := []fyne.CanvasObject{label(l), entry}
|
|
if override != nil {
|
|
i = append(i, override)
|
|
}
|
|
return container.NewHBox(i...)
|
|
}
|
|
|
|
func rowForTech(l string, shipEntry, techEntry, btn fyne.CanvasObject) fyne.CanvasObject {
|
|
return container.NewHBox(
|
|
label(l),
|
|
floatEntry(shipEntry, 115),
|
|
widget.NewLabel("@"),
|
|
techEntry,
|
|
btn,
|
|
)
|
|
}
|
|
|
|
func rowForWeapons(l string, armamentEntry, weaponsEntry, techEntry, btn fyne.CanvasObject) fyne.CanvasObject {
|
|
return container.NewHBox(
|
|
label(l),
|
|
intEntry(armamentEntry, 35),
|
|
floatEntry(weaponsEntry, 75),
|
|
widget.NewLabel("@"),
|
|
techEntry,
|
|
btn,
|
|
)
|
|
}
|
|
|
|
func label(l string) fyne.CanvasObject {
|
|
return fixedLabel(bareLabel(l), 110)
|
|
}
|
|
|
|
func fixedLabel(w *widget.Label, width float32) fyne.CanvasObject {
|
|
s := container.NewHScroll(w)
|
|
s.SetMinSize(fyne.NewSize(width, 1))
|
|
return s
|
|
}
|
|
|
|
func bareLabel(l string) *widget.Label {
|
|
w := widget.NewLabelWithStyle(l, fyne.TextAlignTrailing, fyne.TextStyle{Monospace: true, Symbol: false})
|
|
w.Selectable = false
|
|
w.Truncation = fyne.TextTruncateOff
|
|
return w
|
|
}
|
|
|
|
func intEntry(content fyne.CanvasObject, width float32) fyne.CanvasObject {
|
|
s := container.NewHScroll(content)
|
|
s.SetMinSize(fyne.NewSize(width, 1))
|
|
return s
|
|
}
|
|
|
|
func floatEntry(content fyne.CanvasObject, width float32) fyne.CanvasObject {
|
|
s := container.NewHScroll(content)
|
|
s.SetMinSize(fyne.NewSize(width, 1))
|
|
return s
|
|
}
|