feat(gui): guiden "Opsæt mark" — markfanen får oversigt med resumé (klik på en linje = ret ét trin), trin-for-trin-guide på fælles guide-ramme (ADGuide/ADFieldGuide) og egen markflåde-visning (v1.31.0.0)
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
-- Smart Pickup — guiden "Opsæt mark" og fanen Markers knapper
|
||||
-- Henter det spil-afhængige (afgrøder der kan sås, slåafgrøder, halm, maskiner, marksiloer, siloer i nærheden)
|
||||
-- som `context` til ADFieldGuide og gemmer guidens resultat via ADFieldJobs. Selve trin-skærmen er fælles
|
||||
-- (gui/SmartPickupGuide.lua). Funktionerne lægges på SmartPickupFrame (indlæses efter SmartPickupFrame.lua).
|
||||
|
||||
-- lagervalget viser de nærmeste siloer (plus valgte, marksiloer og gæringssiloer)
|
||||
SmartPickupFrame.FIELD_STORE_ROWS = 8
|
||||
|
||||
function SmartPickupFrame:initFieldButtons(i18n)
|
||||
self.fieldStartButtonInfo = {inputAction = InputAction.MENU_ACTIVATE, text = i18n:getText("spu_field_button_start"), callback = function() self:onClickFieldStartStop() end}
|
||||
self.fieldSetupButtonInfo = {inputAction = InputAction.MENU_EXTRA_1, text = i18n:getText("spu_guide_field_open"), callback = function() self:onClickFieldSetup() end}
|
||||
self.fieldFleetButtonInfo = {inputAction = InputAction.MENU_EXTRA_2, text = i18n:getText("spu_guide_fleet_open"), callback = function() self:onClickFieldFleet(true) end}
|
||||
self.fieldFleetCloseButtonInfo = {inputAction = InputAction.MENU_EXTRA_2, text = i18n:getText("spu_guide_fleet_close"), callback = function() self:onClickFieldFleet(false) end}
|
||||
self.fieldButtons = {self.backButtonInfo, self.fieldStartButtonInfo, self.fieldSetupButtonInfo, self.fieldFleetButtonInfo}
|
||||
self.fieldFleetButtons = {self.backButtonInfo, self.fieldFleetCloseButtonInfo}
|
||||
end
|
||||
|
||||
function SmartPickupFrame:getFieldButtons()
|
||||
return self.fieldView == "fleet" and self.fieldFleetButtons or self.fieldButtons
|
||||
end
|
||||
|
||||
-- ---- context til ADFieldGuide ----
|
||||
|
||||
-- {[fieldId] = rigIds} for alle marker
|
||||
function SmartPickupFrame.rigIdsByField()
|
||||
local byField = {}
|
||||
for fieldId, field in pairs(ADFieldJobs.state.fields) do byField[fieldId] = field.plan ~= nil and field.plan.rigIds or {} end
|
||||
return byField
|
||||
end
|
||||
|
||||
local function fruitTypes()
|
||||
return g_fruitTypeManager ~= nil and g_fruitTypeManager.fruitTypes or {}
|
||||
end
|
||||
|
||||
-- Afgrøder der kan sås, slåafgrøder (navne) og afgrøder med halm (skår efter mejetærskeren).
|
||||
function SmartPickupFrame:fruitContext()
|
||||
local sowable, straw, mowable = {}, {}, {}
|
||||
for _, fruit in ipairs(fruitTypes()) do
|
||||
if fruit.allowsSeeding ~= false and fruit.fillType ~= nil and fruit.name ~= nil then
|
||||
table.insert(sowable, {name = fruit.name, title = tostring(fruit.fillType.title or fruit.name)})
|
||||
end
|
||||
local ok, hasStraw = pcall(function() return fruit.hasWindrow == true or fruit.windrowName ~= nil end)
|
||||
if ok and hasStraw and fruit.name ~= nil then straw[fruit.name] = true end
|
||||
end
|
||||
if ADFields ~= nil and g_fruitTypeManager ~= nil then
|
||||
for index in pairs(ADFields.getMowable()) do
|
||||
local fruit = g_fruitTypeManager:getFruitTypeByIndex(index)
|
||||
if fruit ~= nil and fruit.name ~= nil then mowable[fruit.name] = true end
|
||||
end
|
||||
end
|
||||
return sowable, mowable, straw
|
||||
end
|
||||
|
||||
-- Markens vare ud fra kladdens plan (ensilage -> skår, hø -> tørskår, høst -> afgrøden); nil på bar mark.
|
||||
local function fieldFillType(info, plan)
|
||||
if info.kind == "mowable" then
|
||||
return ADFieldModel.product(plan, "mowable") == "hay" and info.hay or info.windrow
|
||||
end
|
||||
if info.kind == "harvest" then return info.harvestFillType end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Siloer der tager markens vare: marksilo først, gæringssiloer, så de nærmeste (samme regel som før).
|
||||
function SmartPickupFrame:fieldStoreContext(adEnv, info, plan, chosenIds)
|
||||
local fillType = fieldFillType(info, plan)
|
||||
local farmId = g_currentMission:getFarmId()
|
||||
local fieldSilos, silosById = {}, {}
|
||||
for _, building in ipairs(ADFields.fieldSilos(adEnv, farmId, info)) do
|
||||
local markers = ADBuildings.getMarkers ~= nil and ADBuildings.getMarkers(building, "unload") or {}
|
||||
table.insert(fieldSilos, {id = building.id, name = tostring(building.name),
|
||||
text = markers[1] ~= nil and tostring(markers[1].name) or tostring(building.name)})
|
||||
silosById[building.id] = true
|
||||
end
|
||||
if fillType == nil then return nil, 0, fieldSilos end
|
||||
local chosen = {}
|
||||
for _, id in ipairs(chosenIds or {}) do chosen[id] = true end
|
||||
local fermenterIds = {}
|
||||
if info.kind == "mowable" and ADFieldModel.product(plan, "mowable") == "silage" then
|
||||
for _, building in ipairs(ADFieldJobs.getFermenters(adEnv, farmId, fillType, info.x, info.z)) do fermenterIds[building.id] = true end
|
||||
end
|
||||
local entries = {}
|
||||
for _, building in ipairs(ADBuildings.list(adEnv, farmId)) do
|
||||
local isSilo = building.kind == "silo" and ADRunsController.canStoreAt(adEnv, building, {{fillType = fillType, isPallet = false}})
|
||||
if chosen[building.id] or isSilo or fermenterIds[building.id] then
|
||||
local distance = nil
|
||||
local node = building.placeable ~= nil and building.placeable.rootNode or nil
|
||||
if node ~= nil and info.x ~= nil then
|
||||
local bx, _, bz = getWorldTranslation(node)
|
||||
distance = math.sqrt((bx - info.x) ^ 2 + (bz - info.z) ^ 2)
|
||||
end
|
||||
table.insert(entries, {id = building.id, building = building, distance = distance, chosen = chosen[building.id] == true,
|
||||
fieldSilo = silosById[building.id] == true, fermenter = fermenterIds[building.id] == true})
|
||||
end
|
||||
end
|
||||
local shown, hidden = ADFieldView.storeRows(entries, SmartPickupFrame.FIELD_STORE_ROWS)
|
||||
local stores = {}
|
||||
for _, entry in ipairs(shown) do
|
||||
local building = entry.building
|
||||
local markers = ADBuildings.getMarkers ~= nil and ADBuildings.getMarkers(building, "unload") or {}
|
||||
-- det der skelner rækkerne først (rækken afkorter bagfra): markør, afstand, art — så bygningens navn
|
||||
local label = (markers[1] ~= nil and tostring(markers[1].name) or tostring(building.name)) .. ", " .. ADFieldView.distanceText(entry.distance)
|
||||
if entry.fieldSilo then label = label .. " (" .. self.i18n:getText("spu_field_fieldSilo") .. ")" end
|
||||
if entry.fermenter then label = label .. " (" .. self.i18n:getText("spu_field_fermenter") .. ")" end
|
||||
if markers[1] ~= nil then label = label .. " — " .. tostring(building.name) end
|
||||
table.insert(stores, {id = building.id, text = label})
|
||||
end
|
||||
return stores, hidden, fieldSilos
|
||||
end
|
||||
|
||||
-- Markerne til trin 1 ("F22 — Hvede — Venter").
|
||||
function SmartPickupFrame:fieldPickList()
|
||||
local fields = {}
|
||||
for _, row in ipairs(ADFieldView.rows(ADFields.list(), ADFieldJobs.state.fields)) do
|
||||
local crop = ADFieldView.cropText(row.info, function(key) return self.i18n:getText(key) end)
|
||||
table.insert(fields, {id = row.info.id, text = string.format("F%d — %s — %s", row.info.id, crop, self:fieldStatusText(row.field, row.info, true))})
|
||||
end
|
||||
return fields
|
||||
end
|
||||
|
||||
-- context for en mark (info) med kladdens plan; info nil = trin 1 uden valgt mark.
|
||||
function SmartPickupFrame:fieldGuideContext(adEnv, info, plan, chosenStoreIds)
|
||||
local sowable, mowable, straw = self:fruitContext()
|
||||
local context = {info = info or {}, sowable = sowable, mowable = mowable, straw = straw,
|
||||
rigIdsByField = SmartPickupFrame.rigIdsByField(), fieldSilos = {}, storeHidden = 0, fields = self:fieldPickList(), rigs = {}}
|
||||
for _, rig in ipairs(ADFieldJobs.getRigs(adEnv)) do
|
||||
table.insert(context.rigs, {id = rig.id, role = rig.role, text = string.format("%s — %s", tostring(rig.label), self:roleText(rig.role))})
|
||||
end
|
||||
if info ~= nil then
|
||||
context.stores, context.storeHidden, context.fieldSilos = self:fieldStoreContext(adEnv, info, plan or {}, chosenStoreIds)
|
||||
end
|
||||
return context
|
||||
end
|
||||
|
||||
-- ---- hooks til den fælles guide-skærm ----
|
||||
|
||||
local function chosenStoreIds(guide)
|
||||
local ids = {}
|
||||
for _, id in ipairs(guide.draft.storeIds or {}) do table.insert(ids, id) end
|
||||
for _, id in ipairs(guide.draft.plan ~= nil and guide.draft.plan.storeBuildingIds or {}) do table.insert(ids, id) end
|
||||
return ids
|
||||
end
|
||||
|
||||
SmartPickupFrame.GUIDE_HOOKS = SmartPickupFrame.GUIDE_HOOKS or {}
|
||||
SmartPickupFrame.GUIDE_HOOKS.field = {
|
||||
model = ADFieldGuide,
|
||||
tab = SmartPickupFrame.TAB_FIELDS,
|
||||
cannotAdvanceKey = "spu_guide_pickField",
|
||||
heading = function(frame, guide)
|
||||
if guide.draft.fieldId == nil then return frame.i18n:getText("spu_guide_field_titleNone") end
|
||||
return string.format(frame.i18n:getText("spu_guide_field_title"), guide.draft.fieldId)
|
||||
end,
|
||||
context = function(frame, adEnv, guide)
|
||||
local fieldId = guide.draft.fieldId
|
||||
if fieldId == nil then return frame:fieldGuideContext(adEnv, nil) end
|
||||
local info = ADFields.getInfo(fieldId)
|
||||
-- marken er solgt/bygget over mens guiden var åben
|
||||
if info == nil or info.cultivable == false then return nil end
|
||||
return frame:fieldGuideContext(adEnv, info, guide.draft.plan, chosenStoreIds(guide))
|
||||
end,
|
||||
choose = function(frame, id, value)
|
||||
if id ~= "field" then return false end
|
||||
local info = ADFields.getInfo(value)
|
||||
if info == nil then return true end
|
||||
local field = ADFieldJobs.getField(value)
|
||||
frame.selectedFieldId = value
|
||||
frame.statusOverride = nil
|
||||
frame.guide = ADFieldGuide.pickField(frame.guide, field, frame:fieldGuideContext(frame.getAdEnv(), info, field.plan, field.plan.storeBuildingIds))
|
||||
return true
|
||||
end,
|
||||
canAdvance = function(guide) return guide.draft.fieldId ~= nil end,
|
||||
startKey = function() return "spu_guide_runAuto" end,
|
||||
-- mål-afgrøde kører altid automatisk: ingen "Gem uden at starte"
|
||||
showSaveOnly = function(guide) return (guide.draft.plan.targetFruit or "") == "" end,
|
||||
save = function(frame, guide, start) frame:saveFieldGuide(guide, start) end,
|
||||
afterRows = function(frame, adEnv, guide)
|
||||
if guide.step ~= "summary" or guide.draft.fieldId == nil then return end
|
||||
local info = guide.context.info
|
||||
if info ~= nil and info.markerId == nil then
|
||||
frame:addTextRow(" " .. string.format(frame.i18n:getText("spu_guide_noMarker"), guide.draft.fieldId))
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
-- Gem: mål-afgrøde (hvis ændret), planen, og faste maskiner (fjernes fra andre marker).
|
||||
function SmartPickupFrame:saveFieldGuide(guide, start)
|
||||
local result = ADFieldGuide.result(guide, start)
|
||||
if result.fieldId == nil then return end
|
||||
if result.targetChanged then ADFieldJobs.setTarget(result.fieldId, result.targetFruit) end
|
||||
ADFieldJobs.setPlan(result.fieldId, result.plan)
|
||||
local byField = SmartPickupFrame.rigIdsByField()
|
||||
for fieldId, ids in pairs(ADFieldGuide.applyRigs(byField, result.fieldId, result.rigIds)) do
|
||||
if table.concat(byField[fieldId] or {}, " ") ~= table.concat(ids, " ") then
|
||||
ADFieldJobs.setPlan(fieldId, {rigIds = ids})
|
||||
end
|
||||
end
|
||||
ADFieldJobs.log(result.fieldId, "guide gemt: mode=%s mål=%s faste=%s lager=%s", tostring(result.plan.mode), result.targetFruit ~= "" and result.targetFruit or "-",
|
||||
table.concat(result.rigIds, " "), table.concat(result.plan.storeBuildingIds or {}, " "))
|
||||
self.selectedFieldId = result.fieldId
|
||||
self.statusOverride = string.format(self.i18n:getText("spu_guide_saved"), result.fieldId)
|
||||
self.statusOverrideTicks = SmartPickupFrame.STATUS_OVERRIDE_TICKS
|
||||
end
|
||||
|
||||
-- ---- knapper og [Ret] ----
|
||||
|
||||
-- [Opsæt mark]: den valgte mark med de nuværende valg, ellers trin 1 (vælg mark).
|
||||
function SmartPickupFrame:onClickFieldSetup()
|
||||
self:safe(function(frame)
|
||||
local adEnv = frame.getAdEnv()
|
||||
if adEnv == nil then return end
|
||||
local info = frame.selectedFieldId ~= nil and ADFields.getInfo(frame.selectedFieldId) or nil
|
||||
frame.fieldView = nil
|
||||
if info == nil then
|
||||
frame:openGuide("field", ADFieldGuide.openPicker(frame:fieldGuideContext(adEnv, nil)))
|
||||
return
|
||||
end
|
||||
local field = ADFieldJobs.getField(info.id)
|
||||
frame:openGuide("field", ADFieldGuide.open(field, frame:fieldGuideContext(adEnv, info, field.plan, field.plan.storeBuildingIds)))
|
||||
end)
|
||||
end
|
||||
|
||||
-- [Ret] på en resumé-linje i fanens oversigt: kun det ene trin; [Gem] gemmer og går tilbage.
|
||||
function SmartPickupFrame:openFieldStep(fieldId, step)
|
||||
local adEnv = self.getAdEnv()
|
||||
local info = ADFields.getInfo(fieldId)
|
||||
if adEnv == nil or info == nil then return end
|
||||
local field = ADFieldJobs.getField(fieldId)
|
||||
local context = self:fieldGuideContext(adEnv, info, field.plan, field.plan.storeBuildingIds)
|
||||
self:openGuide("field", ADFieldGuide.open(field, context, {step = step, single = true, returnTo = "close"}))
|
||||
end
|
||||
|
||||
function SmartPickupFrame:onClickFieldFleet(show)
|
||||
self:safe(function(frame)
|
||||
frame.fieldView = show and "fleet" or nil
|
||||
frame:requestRebuild()
|
||||
end)
|
||||
end
|
||||
@@ -1,16 +1,12 @@
|
||||
-- Smart Pickup — fanen Marker
|
||||
-- Tabel over alle gårdens marker (Mark · Afgrøde · Plan · Kørsel · Status · Maskiner); klik på en række
|
||||
-- viser markens detaljer under tabellen: plan efter markens art (slåafgrøde, høst, bar), maskiner pr. trin,
|
||||
-- aflæsningsvogne, efter høst, såning, pleje, tving lager, jordtilstand. Nederst markflåden med flueben.
|
||||
-- Al logik ligger i ADFieldJobs/ADFieldWork/ADFieldModel/ADFieldView.
|
||||
-- Oversigt: tabel over alle gårdens marker (Mark · Afgrøde · Plan · Kørsel · Status · Maskiner); klik på en
|
||||
-- række viser markens resumé (én linje pr. emne — klik på en linje for at rette netop det trin), hele
|
||||
-- statusteksten og markøren. [Opsæt mark] åbner guiden (gui/SmartPickupFieldGuide.lua + SmartPickupGuide.lua),
|
||||
-- [Markflåde] viser den fælles markflåde. Al logik ligger i ADFieldJobs/ADFieldModel/ADFieldView/ADFieldGuide.
|
||||
-- Funktionerne lægges på SmartPickupFrame (indlæses efter SmartPickupFrame.lua).
|
||||
|
||||
SmartPickupFrame.FIELD_ROW_KINDS = {
|
||||
fieldProduct = true, fieldMode = true, fieldRake = true, fieldStore = true, fleetVehicle = true,
|
||||
fieldRigs = true, fieldUnloaders = true, fieldMulch = true, fieldLime = true, fieldSoil = true,
|
||||
fieldSow = true, fieldSowFruit = true, fieldRoll = true, fieldFertilize = true, fieldWeed = true,
|
||||
fieldTarget = true, fleetMode = true, fieldStraw = true, fieldRig = true,
|
||||
}
|
||||
-- Markflådens rækker (vehiclePrefab/ingredientPrefab) routes til onClickFieldRow.
|
||||
SmartPickupFrame.FIELD_ROW_KINDS = {fleetVehicle = true, fleetMode = true}
|
||||
SmartPickupFrame.ROLE_KEYS = {
|
||||
mower = "spu_field_role_mower", tedder = "spu_field_role_tedder", rake = "spu_field_role_rake",
|
||||
collector = "spu_field_role_collector", harvester = "spu_field_role_harvester", unloader = "spu_field_role_unloader",
|
||||
@@ -19,15 +15,6 @@ SmartPickupFrame.ROLE_KEYS = {
|
||||
weeder = "spu_field_role_weeder", fertilizer = "spu_field_role_fertilizer",
|
||||
baler = "spu_field_role_baler", baleCollector = "spu_field_role_baleCollector",
|
||||
}
|
||||
SmartPickupFrame.SOIL_VALUES = {"auto", "cultivate", "plow", "none"}
|
||||
-- simple Ja/Nej-valg på planen: rækketype -> plan-felt
|
||||
SmartPickupFrame.PLAN_TOGGLES = {
|
||||
fieldRake = "rake", fieldMulch = "mulch", fieldLime = "lime", fieldSow = "sow", fieldRoll = "roll",
|
||||
fieldFertilize = "fertilize", fieldWeed = "weed",
|
||||
}
|
||||
-- valg med flere muligheder: rækketype -> plan-felt
|
||||
SmartPickupFrame.PLAN_CHOICES = {fieldRigs = "rigs", fieldUnloaders = "unloaders", fieldSoil = "soil", fieldSowFruit = "sowFruit", fieldStraw = "straw"}
|
||||
SmartPickupFrame.STRAW_VALUES = {"chop", "collect", "bale"}
|
||||
|
||||
-- ---- tekster ----
|
||||
|
||||
@@ -95,18 +82,6 @@ function SmartPickupFrame:fieldStatusText(field, info, short)
|
||||
return text
|
||||
end
|
||||
|
||||
-- Hvad moden gør med marken frem mod mål-afgrøden (én linje under valget).
|
||||
function SmartPickupFrame:targetSummary(field, info)
|
||||
local target = self:fruitTitle(field.plan.targetFruit)
|
||||
if info.kind == "bare" then
|
||||
return string.format(self.i18n:getText("spu_field_target_bare"), target)
|
||||
end
|
||||
if info.fruitName == field.plan.targetFruit and info.kind == "mowable" then
|
||||
return string.format(self.i18n:getText("spu_field_target_keep"), target)
|
||||
end
|
||||
return string.format(self.i18n:getText("spu_field_target_switch"), tostring(info.cropTitle or "-"), target)
|
||||
end
|
||||
|
||||
function SmartPickupFrame:fruitTitle(name)
|
||||
local fruit = g_fruitTypeManager ~= nil and name ~= nil and name ~= "" and g_fruitTypeManager:getFruitTypeByName(name) or nil
|
||||
return fruit ~= nil and fruit.fillType ~= nil and tostring(fruit.fillType.title) or tostring(name)
|
||||
@@ -139,47 +114,15 @@ function SmartPickupFrame:fieldCells(row)
|
||||
}
|
||||
end
|
||||
|
||||
-- ---- rækker ----
|
||||
|
||||
-- Valg med flere muligheder (klon af productPrefab): values[i] er værdien for texts[i].
|
||||
function SmartPickupFrame:addChoiceRow(kind, title, texts, values, current)
|
||||
local row = self:addRow(self.productPrefab, {kind = kind, values = values})
|
||||
local option = row:getDescendantByName("option")
|
||||
option:setTexts(texts)
|
||||
local index = 1
|
||||
for position, value in ipairs(values) do
|
||||
if value == current then index = position end
|
||||
end
|
||||
option:setState(index, false)
|
||||
row:getDescendantByName("title"):setText(title)
|
||||
return option
|
||||
end
|
||||
|
||||
local function numberTexts(from, to)
|
||||
local texts, values = {}, {}
|
||||
for value = from, to do
|
||||
table.insert(texts, tostring(value))
|
||||
table.insert(values, value)
|
||||
end
|
||||
return texts, values
|
||||
end
|
||||
|
||||
-- Afgrøder der kan sås (første valg: samme som den høstede / ingen mål-afgrøde).
|
||||
function SmartPickupFrame:sowFruitChoices(firstKey)
|
||||
local texts, values = {self.i18n:getText(firstKey or "spu_field_sowSame")}, {""}
|
||||
for _, fruit in ipairs(g_fruitTypeManager ~= nil and g_fruitTypeManager.fruitTypes or {}) do
|
||||
if fruit.allowsSeeding ~= false and fruit.fillType ~= nil and fruit.name ~= nil then
|
||||
table.insert(texts, tostring(fruit.fillType.title or fruit.name))
|
||||
table.insert(values, fruit.name)
|
||||
end
|
||||
end
|
||||
return texts, values
|
||||
end
|
||||
|
||||
-- ---- opbygning ----
|
||||
|
||||
function SmartPickupFrame:fillFieldRows(adEnv)
|
||||
self.fieldRows = {}
|
||||
if self:hasGuideOn(SmartPickupFrame.TAB_FIELDS) and self:fillGuideRows(adEnv) then return end
|
||||
if self.fieldView == "fleet" then
|
||||
self:fillFleetRows(adEnv)
|
||||
return
|
||||
end
|
||||
local i18n = self.i18n
|
||||
local infos = ADFields.list()
|
||||
if #infos == 0 then
|
||||
@@ -201,161 +144,48 @@ function SmartPickupFrame:fillFieldRows(adEnv)
|
||||
end
|
||||
local selected = self.selectedFieldId ~= nil and ADFields.getInfo(self.selectedFieldId) or nil
|
||||
if selected ~= nil then
|
||||
self:fillFieldDetail(adEnv, selected)
|
||||
self:fillFieldOverview(adEnv, selected)
|
||||
end
|
||||
self:fillFleetRows(adEnv)
|
||||
end
|
||||
|
||||
-- lagervalget viser de nærmeste siloer (plus valgte, marksiloer og gæringssiloer)
|
||||
SmartPickupFrame.FIELD_STORE_ROWS = 8
|
||||
|
||||
function SmartPickupFrame:fillFieldDetail(adEnv, info)
|
||||
-- Den valgte marks resumé: én klikbar linje pr. emne ([Ret] åbner kun det trin), hele status, markør og
|
||||
-- advarsel om marksilo der ikke tømmes hjem.
|
||||
function SmartPickupFrame:fillFieldOverview(adEnv, info)
|
||||
local i18n = self.i18n
|
||||
local field = ADFieldJobs.getField(info.id)
|
||||
local plan = field.plan
|
||||
local yesNo = {i18n:getText("ui_no"), i18n:getText("ui_yes")}
|
||||
local crop = ADFieldView.cropText(info, function(key) return i18n:getText(key) end)
|
||||
self:addTextRow(string.format(i18n:getText("spu_field_section"), info.id, crop))
|
||||
-- hele statusteksten (tabellens celle afkorter den)
|
||||
self:addTextRow(" " .. i18n:getText("spu_guide_sum_hint"))
|
||||
local context = self:fieldGuideContext(adEnv, info, field.plan, field.plan.storeBuildingIds)
|
||||
local guide = ADFieldGuide.open(field, context)
|
||||
local getText = function(key) return i18n:getText(key) end
|
||||
local fieldId = info.id
|
||||
for _, line in ipairs(ADFieldGuide.summary(guide)) do
|
||||
local step = line.step
|
||||
self:addLinkRow(" " .. ADGuide.lineText(line, getText) .. i18n:getText("spu_guide_editSuffix"), function(frame)
|
||||
frame:openFieldStep(fieldId, step)
|
||||
end)
|
||||
end
|
||||
self:addTextRow(" " .. string.format(i18n:getText("spu_field_statusFull"), self:fieldStatusText(field, info)))
|
||||
local targetTexts, targetValues = self:sowFruitChoices("spu_field_target_none")
|
||||
self:addChoiceRow("fieldTarget", i18n:getText("spu_field_target"), targetTexts, targetValues, plan.targetFruit or "")
|
||||
local hasTarget = plan.targetFruit ~= nil and plan.targetFruit ~= ""
|
||||
if hasTarget then
|
||||
self:addTextRow(" " .. self:targetSummary(field, info))
|
||||
else
|
||||
self:addToggleRow("fieldMode", i18n:getText("spu_field_mode"), {i18n:getText("spu_field_mode_manual"), i18n:getText("spu_field_mode_auto")}, plan.mode == "auto")
|
||||
end
|
||||
local rigTexts, rigValues = numberTexts(1, ADFieldModel.MAX_RIGS)
|
||||
self:addChoiceRow("fieldRigs", i18n:getText("spu_field_rigs"), rigTexts, rigValues, plan.rigs or 1)
|
||||
-- græs-valgene (ensilage/hø, riv) også når målet er en slåafgrøde (fx græs på en kornmark)
|
||||
local targetMowable = false
|
||||
if hasTarget and ADFields ~= nil and g_fruitTypeManager ~= nil then
|
||||
local targetFruit = g_fruitTypeManager:getFruitTypeByName(plan.targetFruit)
|
||||
targetMowable = targetFruit ~= nil and ADFields.getMowable()[targetFruit.index] ~= nil
|
||||
end
|
||||
if info.kind == "mowable" or targetMowable then
|
||||
local isHay = ADFieldModel.product(plan, "mowable") == "hay"
|
||||
self:addToggleRow("fieldProduct", i18n:getText("spu_field_plan"), {i18n:getText("spu_field_plan_silage"), i18n:getText("spu_field_plan_hay")}, isHay)
|
||||
self:addToggleRow("fieldRake", i18n:getText("spu_field_rake"), yesNo, plan.rake == true)
|
||||
end
|
||||
-- klargøring: høst-/bare marker, og græsmarker der skal skifte til en anden mål-afgrøde
|
||||
if info.kind ~= "mowable" or (hasTarget and info.fruitName ~= plan.targetFruit) then
|
||||
if info.kind == "harvest" then
|
||||
local unloaderTexts, unloaderValues = numberTexts(1, ADFieldModel.MAX_UNLOADERS)
|
||||
self:addChoiceRow("fieldUnloaders", i18n:getText("spu_field_unloaders"), unloaderTexts, unloaderValues, plan.unloaders or 1)
|
||||
local strawTexts = {}
|
||||
for _, value in ipairs(SmartPickupFrame.STRAW_VALUES) do table.insert(strawTexts, i18n:getText("spu_field_straw_" .. value)) end
|
||||
self:addChoiceRow("fieldStraw", i18n:getText("spu_field_straw"), strawTexts, SmartPickupFrame.STRAW_VALUES, plan.straw or "chop")
|
||||
end
|
||||
self:addTextRow(i18n:getText(info.kind == "harvest" and "spu_field_section_after" or "spu_field_section_prep"))
|
||||
self:addToggleRow("fieldMulch", i18n:getText("spu_field_mulch"), yesNo, plan.mulch == true)
|
||||
local soilTexts = {}
|
||||
for _, value in ipairs(SmartPickupFrame.SOIL_VALUES) do table.insert(soilTexts, i18n:getText("spu_field_soil_" .. value)) end
|
||||
self:addChoiceRow("fieldSoil", i18n:getText("spu_field_soil"), soilTexts, SmartPickupFrame.SOIL_VALUES, plan.soil or "auto")
|
||||
if not hasTarget then
|
||||
self:addToggleRow("fieldSow", i18n:getText("spu_field_sow"), yesNo, plan.sow == true)
|
||||
if plan.sow then
|
||||
local fruitTexts, fruitValues = self:sowFruitChoices()
|
||||
self:addChoiceRow("fieldSowFruit", i18n:getText("spu_field_sowFruit"), fruitTexts, fruitValues, plan.sowFruit or "")
|
||||
end
|
||||
end
|
||||
if hasTarget or plan.sow then
|
||||
self:addToggleRow("fieldRoll", i18n:getText("spu_field_roll"), yesNo, plan.roll == true)
|
||||
end
|
||||
end
|
||||
self:addTextRow(i18n:getText("spu_field_section_care"))
|
||||
self:addToggleRow("fieldFertilize", i18n:getText("spu_field_fertilize"), yesNo, plan.fertilize ~= false)
|
||||
self:addToggleRow("fieldLime", i18n:getText("spu_field_lime"), yesNo, plan.lime ~= false)
|
||||
if info.kind ~= "mowable" then
|
||||
self:addToggleRow("fieldWeed", i18n:getText("spu_field_weed"), yesNo, plan.weed ~= false)
|
||||
end
|
||||
local soil = self:soilText(info)
|
||||
self:addTextRow(" " .. string.format(i18n:getText("spu_field_soilState"), soil ~= "" and soil or i18n:getText("spu_field_soilOk")))
|
||||
if info.markerId ~= nil then
|
||||
self:addTextRow(string.format(i18n:getText("spu_field_marker"), tostring(info.markerName), info.markerDistance or 0))
|
||||
else
|
||||
self:addTextRow(" " .. string.format(i18n:getText("spu_field_noMarker"), info.id))
|
||||
self:addTextRow(" " .. string.format(i18n:getText("spu_guide_noMarker"), info.id))
|
||||
end
|
||||
if field.mowWidth ~= nil then
|
||||
self:addTextRow(string.format(i18n:getText("spu_field_mowWidth"), field.mowWidth))
|
||||
end
|
||||
if field.plan.rake and field.windrowOffset ~= nil then
|
||||
self:addTextRow(string.format(i18n:getText("spu_field_windrowOffset"), math.abs(field.windrowOffset),
|
||||
i18n:getText(math.abs(field.windrowOffset) <= 0.05 and "spu_field_side_center" or (field.windrowOffset > 0 and "spu_field_side_left" or "spu_field_side_right"))))
|
||||
end
|
||||
self:fillFieldStoreRows(adEnv, info, field)
|
||||
self:addFieldSiloWarnings(context.fieldSilos)
|
||||
end
|
||||
|
||||
-- Tving lager: siloer der tager markens vare (skår/tørskår/høst); ved ensilage også gæringssiloer.
|
||||
function SmartPickupFrame:fillFieldStoreRows(adEnv, info, field)
|
||||
local i18n = self.i18n
|
||||
local product = ADFieldModel.product(field.plan, info.kind)
|
||||
local fillType
|
||||
if info.kind == "mowable" then
|
||||
fillType = product == "hay" and info.hay or info.windrow
|
||||
else
|
||||
fillType = info.harvestFillType
|
||||
end
|
||||
if fillType == nil then return end
|
||||
self:fillDedicatedRows(adEnv, field)
|
||||
self:addTextRow(i18n:getText("spu_field_section_store"))
|
||||
local chosen = {}
|
||||
for _, id in ipairs(field.plan.storeBuildingIds) do chosen[id] = true end
|
||||
local farmId = g_currentMission:getFarmId()
|
||||
local fieldSilos = {}
|
||||
for _, building in ipairs(ADFields.fieldSilos(adEnv, farmId, info)) do fieldSilos[building.id] = building end
|
||||
local fermenterIds = {}
|
||||
if info.kind == "mowable" and product == "silage" then
|
||||
for _, building in ipairs(ADFieldJobs.getFermenters(adEnv, farmId, fillType, info.x, info.z)) do fermenterIds[building.id] = true end
|
||||
end
|
||||
-- kandidater med markørnavn og afstand til marken (34 ens "Farma 500 + Obi 1000" kan ellers ikke skelnes)
|
||||
local entries = {}
|
||||
for _, building in ipairs(ADBuildings.list(adEnv, farmId)) do
|
||||
local isSilo = building.kind == "silo" and ADRunsController.canStoreAt(adEnv, building, {{fillType = fillType, isPallet = false}})
|
||||
if chosen[building.id] or isSilo or fermenterIds[building.id] then
|
||||
local distance = nil
|
||||
local node = building.placeable ~= nil and building.placeable.rootNode or nil
|
||||
if node ~= nil and info.x ~= nil then
|
||||
local bx, _, bz = getWorldTranslation(node)
|
||||
distance = math.sqrt((bx - info.x) ^ 2 + (bz - info.z) ^ 2)
|
||||
end
|
||||
table.insert(entries, {id = building.id, building = building, distance = distance, chosen = chosen[building.id] == true,
|
||||
fieldSilo = fieldSilos[building.id] ~= nil, fermenter = fermenterIds[building.id] == true})
|
||||
end
|
||||
end
|
||||
local storeRows, hiddenStores = ADFieldView.storeRows(entries, SmartPickupFrame.FIELD_STORE_ROWS)
|
||||
local count = #storeRows
|
||||
for _, entry in ipairs(storeRows) do
|
||||
local building = entry.building
|
||||
local row = self:addRow(self.ingredientPrefab, {kind = "fieldStore", buildingId = building.id})
|
||||
local markers = ADBuildings.getMarkers ~= nil and ADBuildings.getMarkers(building, "unload") or {}
|
||||
-- det der skelner rækkerne først (rækken afkorter bagfra): markør, afstand, art — så bygningens navn
|
||||
local label = (markers[1] ~= nil and tostring(markers[1].name) or tostring(building.name)) .. ", " .. ADFieldView.distanceText(entry.distance)
|
||||
if entry.fieldSilo then label = label .. " (" .. i18n:getText("spu_field_fieldSilo") .. ")" end
|
||||
if entry.fermenter then label = label .. " (" .. i18n:getText("spu_field_fermenter") .. ")" end
|
||||
if markers[1] ~= nil then label = label .. " — " .. tostring(building.name) end
|
||||
row:getDescendantByName("title"):setText(" " .. label)
|
||||
row:getDescendantByName("option"):setState(entry.chosen and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF, false)
|
||||
end
|
||||
if hiddenStores > 0 then
|
||||
self:addTextRow(" " .. string.format(i18n:getText("spu_field_storeHidden"), hiddenStores))
|
||||
end
|
||||
if count == 0 then
|
||||
self:addTextRow(" " .. i18n:getText("spu_field_noStore"))
|
||||
elseif #field.plan.storeBuildingIds == 0 then
|
||||
self:addTextRow(" " .. i18n:getText((info.kind == "mowable" and product == "silage") and "spu_field_storeAutoSilage" or "spu_field_storeAuto"))
|
||||
end
|
||||
-- marksiloer skal tømmes hjem af et udkørselsflow
|
||||
for id, building in pairs(fieldSilos) do
|
||||
-- Marksiloer skal tømmes hjem af et udkørselsflow.
|
||||
function SmartPickupFrame:addFieldSiloWarnings(fieldSilos)
|
||||
for _, silo in ipairs(fieldSilos or {}) do
|
||||
local emptied = false
|
||||
for _, run in ipairs(ADRunsController.store.runs) do
|
||||
for _, sourceId in ipairs(run.kind == "outbound" and run.sourceBuildingIds or {}) do
|
||||
if sourceId == id then emptied = true end
|
||||
if sourceId == silo.id then emptied = true end
|
||||
end
|
||||
end
|
||||
if not emptied then
|
||||
self:addTextRow(" " .. string.format(i18n:getText("spu_field_fieldSiloNotEmptied"), tostring(building.name)))
|
||||
self:addTextRow(" " .. string.format(self.i18n:getText("spu_field_fieldSiloNotEmptied"), tostring(silo.name or silo.text)))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -387,54 +217,14 @@ function SmartPickupFrame:rigDetails(rig)
|
||||
return #parts > 0 and (" — " .. table.concat(parts, " — ")) or ""
|
||||
end
|
||||
|
||||
-- {[fieldId] = rigIds} for alle marker
|
||||
local function rigIdsByField()
|
||||
local byField = {}
|
||||
for fieldId, field in pairs(ADFieldJobs.state.fields) do byField[fieldId] = field.plan ~= nil and field.plan.rigIds or {} end
|
||||
return byField
|
||||
end
|
||||
|
||||
-- "3 maskiner er faste på andre marker (F22, F90)"
|
||||
function SmartPickupFrame:addHiddenDedicatedRow(hidden, fields)
|
||||
if hidden <= 0 then return end
|
||||
local names = {}
|
||||
for _, fieldId in ipairs(fields) do table.insert(names, "F" .. tostring(fieldId)) end
|
||||
self:addTextRow(" " .. string.format(self.i18n:getText("spu_field_hiddenDedicated"), hidden, table.concat(names, ", ")))
|
||||
end
|
||||
|
||||
-- Faste maskiner til den valgte mark: en fast maskine bruges kun her, og marken venter på sin egen hellere
|
||||
-- end at låne en anden med samme opgave. Maskiner der er faste på en anden mark er markeret.
|
||||
function SmartPickupFrame:fillDedicatedRows(adEnv, field)
|
||||
local i18n = self.i18n
|
||||
self:addTextRow(i18n:getText("spu_field_section_dedicated"))
|
||||
local owner = {}
|
||||
for fieldId, other in pairs(ADFieldJobs.state.fields) do
|
||||
for _, id in ipairs(other.plan ~= nil and other.plan.rigIds or {}) do owner[id] = fieldId end
|
||||
end
|
||||
local rigs, hiddenRigs, hiddenFields = ADFieldFleet.visibleForField(ADFieldJobs.getRigs(adEnv), field.id, rigIdsByField())
|
||||
table.sort(rigs, function(a, b)
|
||||
local ma, mb = owner[a.id] == field.id, owner[b.id] == field.id
|
||||
if ma ~= mb then return ma end
|
||||
if a.role ~= b.role then return a.role < b.role end
|
||||
return ADFlowView.naturalLess(a.label, b.label)
|
||||
end)
|
||||
for _, rig in ipairs(rigs) do
|
||||
local row = self:addRow(self.vehiclePrefab, {kind = "fieldRig", vehicleId = rig.id})
|
||||
local elsewhere = owner[rig.id] ~= nil and owner[rig.id] ~= field.id
|
||||
and (" — " .. string.format(i18n:getText("spu_field_dedicatedElsewhere"), tostring(owner[rig.id]))) or ""
|
||||
row:getDescendantByName("title"):setText(string.format(" %s — %s%s", tostring(rig.label), self:roleText(rig.role), elsewhere))
|
||||
row:getDescendantByName("option"):setState(owner[rig.id] == field.id and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF, false)
|
||||
end
|
||||
self:addHiddenDedicatedRow(hiddenRigs, hiddenFields)
|
||||
end
|
||||
|
||||
-- Markflåden (egen visning): alle maskiner med flueben, "fast på F22", "i gang på F108", bredde-advarsler.
|
||||
function SmartPickupFrame:fillFleetRows(adEnv)
|
||||
local i18n = self.i18n
|
||||
self:addTextRow(i18n:getText("spu_field_section_fleet"))
|
||||
local useAll = ADFieldJobs.state.fleetMode ~= "ticked"
|
||||
self:addToggleRow("fleetMode", i18n:getText("spu_field_fleetAll"), {i18n:getText("ui_no"), i18n:getText("ui_yes")}, useAll)
|
||||
-- valgt mark: maskiner der er faste på en anden mark skjules (de kan ikke bruges her)
|
||||
local rigs, hiddenRigs, hiddenFields = ADFieldFleet.visibleForField(ADFieldJobs.getRigs(adEnv), self.selectedFieldId, rigIdsByField())
|
||||
local rigs = {}
|
||||
for _, rig in ipairs(ADFieldJobs.getRigs(adEnv)) do table.insert(rigs, rig) end
|
||||
table.sort(rigs, function(a, b)
|
||||
if a.role ~= b.role then return a.role < b.role end
|
||||
return ADFlowView.naturalLess(a.label, b.label)
|
||||
@@ -448,12 +238,15 @@ function SmartPickupFrame:fillFleetRows(adEnv)
|
||||
if #rigs == 0 then
|
||||
self:addTextRow(" " .. i18n:getText("spu_field_noRigs"))
|
||||
end
|
||||
self:addHiddenDedicatedRow(hiddenRigs, hiddenFields)
|
||||
end
|
||||
|
||||
-- ---- live ----
|
||||
|
||||
function SmartPickupFrame:refreshFieldRows(adEnv)
|
||||
if self:hasGuideOn(SmartPickupFrame.TAB_FIELDS) or self.fieldView == "fleet" then
|
||||
self:setStatusText(self.statusOverride or "")
|
||||
return
|
||||
end
|
||||
local rowsById = {}
|
||||
for _, row in ipairs(ADFieldView.rows(ADFields.list(), ADFieldJobs.state.fields)) do rowsById[row.info.id] = row end
|
||||
local working, total = 0, 0
|
||||
@@ -473,45 +266,15 @@ function SmartPickupFrame:refreshFieldRows(adEnv)
|
||||
self.fieldStartButtonInfo.disabled = selected == nil or info == nil or (not isWorking and info.markerId == nil)
|
||||
end
|
||||
|
||||
-- ---- klik ----
|
||||
-- ---- klik (markflåden) ----
|
||||
|
||||
function SmartPickupFrame:onClickFieldRow(state, data)
|
||||
self:safe(function(frame)
|
||||
local isOn = state == SmartPickupFrame.STATE_ON
|
||||
local id = frame.selectedFieldId
|
||||
if data.kind == "fleetVehicle" then
|
||||
ADFieldJobs.toggleFleet(data.vehicleId)
|
||||
elseif data.kind == "fleetMode" then
|
||||
ADFieldJobs.setFleetMode(isOn and "all" or "ticked")
|
||||
elseif id == nil then
|
||||
return
|
||||
elseif data.kind == "fieldTarget" then
|
||||
ADFieldJobs.setTarget(id, data.values ~= nil and data.values[state] or "")
|
||||
elseif SmartPickupFrame.PLAN_CHOICES[data.kind] ~= nil then
|
||||
local value = data.values ~= nil and data.values[state] or nil
|
||||
if value ~= nil then ADFieldJobs.setPlan(id, {[SmartPickupFrame.PLAN_CHOICES[data.kind]] = value}) end
|
||||
elseif data.kind == "fieldProduct" then
|
||||
ADFieldJobs.setPlan(id, {product = isOn and "hay" or "silage"})
|
||||
elseif data.kind == "fieldMode" then
|
||||
ADFieldJobs.setPlan(id, {mode = isOn and "auto" or "manual"})
|
||||
elseif SmartPickupFrame.PLAN_TOGGLES[data.kind] ~= nil then
|
||||
ADFieldJobs.setPlan(id, {[SmartPickupFrame.PLAN_TOGGLES[data.kind]] = isOn})
|
||||
elseif data.kind == "fieldRig" then
|
||||
-- fast på denne mark (og fjernes fra en anden mark)
|
||||
local byField = {}
|
||||
for fieldId, other in pairs(ADFieldJobs.state.fields) do byField[fieldId] = other.plan ~= nil and other.plan.rigIds or {} end
|
||||
local updated = ADFieldFleet.dedicate(byField, id, data.vehicleId, isOn)
|
||||
for fieldId, ids in pairs(updated) do
|
||||
local before = table.concat(byField[fieldId] or {}, " ")
|
||||
if before ~= table.concat(ids, " ") then ADFieldJobs.setPlan(fieldId, {rigIds = ids}) end
|
||||
end
|
||||
elseif data.kind == "fieldStore" then
|
||||
local ids = {}
|
||||
for _, buildingId in ipairs(ADFieldJobs.getField(id).plan.storeBuildingIds) do
|
||||
if buildingId ~= data.buildingId then table.insert(ids, buildingId) end
|
||||
end
|
||||
if isOn then table.insert(ids, data.buildingId) end
|
||||
ADFieldJobs.setPlan(id, {storeBuildingIds = ids})
|
||||
end
|
||||
frame:requestRebuild()
|
||||
end)
|
||||
|
||||
@@ -52,8 +52,9 @@ function SmartPickupFrame.new(i18n, getAdEnv)
|
||||
self.flowButtons = {self.backButtonInfo, self.startButtonInfo, self.newButtonInfo, self.renameButtonInfo, self.deleteButtonInfo}
|
||||
self.overviewButtons = {self.backButtonInfo, self.startAllButtonInfo, self.stopAllButtonInfo, self.newButtonInfo}
|
||||
-- Marker: Start nu / Stop for den valgte mark
|
||||
self.fieldStartButtonInfo = {inputAction = InputAction.MENU_ACTIVATE, text = i18n:getText("spu_field_button_start"), callback = function() self:onClickFieldStartStop() end}
|
||||
self.fieldButtons = {self.backButtonInfo, self.fieldStartButtonInfo}
|
||||
-- Marker: [Start nu/Stop], [Opsæt mark], [Markflåde] (gui/SmartPickupFieldGuide.lua); guidens knapper
|
||||
self:initFieldButtons(i18n)
|
||||
self:initGuideButtons(i18n)
|
||||
-- Egen reference til listen: fallback'en i refreshButtons skal kunne sende den igen.
|
||||
self.menuButtonInfo = self.overviewButtons
|
||||
self:setMenuButtonInfo(self.menuButtonInfo)
|
||||
@@ -197,6 +198,8 @@ end
|
||||
|
||||
function SmartPickupFrame:onFrameClose()
|
||||
self.frameOpen = false
|
||||
-- en åben guide kasseres (intet er gemt før [Gem])
|
||||
self:closeGuide()
|
||||
SmartPickupFrame:superClass().onFrameClose(self)
|
||||
end
|
||||
|
||||
@@ -243,6 +246,7 @@ function SmartPickupFrame:requestRebuild()
|
||||
end
|
||||
|
||||
function SmartPickupFrame:switchTab(tabIndex)
|
||||
if self.guide ~= nil and not self:hasGuideOn(tabIndex) then self:closeGuide() end
|
||||
self.currentTab = tabIndex
|
||||
for index, tab in ipairs(self.subCategoryTabs) do
|
||||
tab:setSelected(index == tabIndex)
|
||||
@@ -665,10 +669,12 @@ end
|
||||
-- sendes listen igen. Kaldes hvert sekund, så den må aldrig kaste.
|
||||
function SmartPickupFrame:refreshButtons()
|
||||
local wanted = self.flowButtons
|
||||
if self.currentTab == SmartPickupFrame.TAB_OVERVIEW then
|
||||
if self:hasGuideOn(self.currentTab) then
|
||||
wanted = self:getGuideButtons()
|
||||
elseif self.currentTab == SmartPickupFrame.TAB_OVERVIEW then
|
||||
wanted = self.overviewButtons
|
||||
elseif self.currentTab == SmartPickupFrame.TAB_FIELDS then
|
||||
wanted = self.fieldButtons
|
||||
wanted = self:getFieldButtons()
|
||||
end
|
||||
if self.menuButtonInfo ~= wanted then
|
||||
self.menuButtonInfo = wanted
|
||||
@@ -757,7 +763,9 @@ end
|
||||
function SmartPickupFrame:onClickIngredient(state, element)
|
||||
-- mål- og kilde-rækkerne deler prefab (og dermed onClick) med vare-rækkerne
|
||||
local data = self.rowData[element]
|
||||
if data ~= nil and data.kind == "target" then
|
||||
if data ~= nil and data.kind == "guideRow" then
|
||||
return self:onClickGuideRow(state, data)
|
||||
elseif data ~= nil and data.kind == "target" then
|
||||
return self:onClickTarget(state, element)
|
||||
elseif data ~= nil and data.kind == "source" then
|
||||
return self:onClickSource(state, element)
|
||||
@@ -806,6 +814,9 @@ function SmartPickupFrame:onClickVehicle(state, element)
|
||||
if clicked ~= nil and (clicked.kind == "fleetVehicle" or clicked.kind == "fieldRig") then
|
||||
return self:onClickFieldRow(state, clicked)
|
||||
end
|
||||
if clicked ~= nil and clicked.kind == "guideRow" then
|
||||
return self:onClickGuideRow(state, clicked)
|
||||
end
|
||||
self:safe(function(frame)
|
||||
local run, data = frame:getRun(), frame.rowData[element]
|
||||
-- kun flowets traktorrækker (de har et køretøj); alt andet ignoreres
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
-- Smart Pickup — fælles guide-skærm ("Opsæt mark" / "Opsæt flow")
|
||||
-- Ét trin ad gangen: overskrift, "Trin 3 af 7 — …", kort forklaring, valgene som rækker og bundknapperne
|
||||
-- Næste/Gem, Tilbage, Annullér (+ Gem uden at starte på oversigts-trinnet). Al logik ligger i ADGuide og
|
||||
-- trin-definitionerne (ADFieldGuide/ADFlowGuide); her tegnes kun rækkerne og klik routes.
|
||||
-- Hver guide registrerer sig i SmartPickupFrame.GUIDE_HOOKS[kind] = {
|
||||
-- model, tab, heading(frame, guide), context(frame, adEnv, guide) -> context|nil (nil = luk guiden),
|
||||
-- choose(frame, id, value) -> handled, save(frame, guide, start), startKey(guide), showSaveOnly(guide),
|
||||
-- canAdvance(guide), afterRows(frame, adEnv, guide) }
|
||||
-- Funktionerne lægges på SmartPickupFrame (indlæses efter SmartPickupFrame.lua).
|
||||
|
||||
SmartPickupFrame.GUIDE_HOOKS = SmartPickupFrame.GUIDE_HOOKS or {}
|
||||
|
||||
function SmartPickupFrame:initGuideButtons(i18n)
|
||||
self.guideNextButtonInfo = {inputAction = InputAction.MENU_ACTIVATE, text = i18n:getText("spu_guide_next"), callback = function() self:onClickGuideNext(true) end}
|
||||
self.guideSaveOnlyButtonInfo = {inputAction = InputAction.MENU_EXTRA_1, text = i18n:getText("spu_guide_saveOnly"), callback = function() self:onClickGuideNext(false) end}
|
||||
self.guidePrevButtonInfo = {inputAction = InputAction.MENU_EXTRA_2, text = i18n:getText("spu_guide_back"), callback = function() self:onClickGuideBack() end}
|
||||
self.guideCancelButtonInfo = {inputAction = InputAction.MENU_CANCEL, text = i18n:getText("spu_guide_cancel"), callback = function() self:onClickGuideCancel() end}
|
||||
self.guideButtons = {self.backButtonInfo, self.guideNextButtonInfo, self.guidePrevButtonInfo, self.guideCancelButtonInfo}
|
||||
self.guideSummaryButtons = {self.backButtonInfo, self.guideNextButtonInfo, self.guideSaveOnlyButtonInfo, self.guidePrevButtonInfo, self.guideCancelButtonInfo}
|
||||
end
|
||||
|
||||
function SmartPickupFrame:guideHooks()
|
||||
return self.guideKind ~= nil and SmartPickupFrame.GUIDE_HOOKS[self.guideKind] or nil
|
||||
end
|
||||
|
||||
-- Er der en åben guide på fanen?
|
||||
function SmartPickupFrame:hasGuideOn(tab)
|
||||
local hooks = self:guideHooks()
|
||||
return self.guide ~= nil and hooks ~= nil and hooks.tab == tab
|
||||
end
|
||||
|
||||
function SmartPickupFrame:openGuide(kind, guide)
|
||||
self.guideKind, self.guide = kind, guide
|
||||
self.statusOverride = nil
|
||||
self:requestRebuild()
|
||||
end
|
||||
|
||||
-- Kladden kasseres (Annullér, fanebyt, lukket menu).
|
||||
function SmartPickupFrame:closeGuide()
|
||||
self.guideKind, self.guide = nil, nil
|
||||
end
|
||||
|
||||
function SmartPickupFrame:guideText(label)
|
||||
return ADGuide.labelText(label, function(key) return self.i18n:getText(key) end)
|
||||
end
|
||||
|
||||
-- Klikbar tekstrække (ombrydes; alle linjer er klikbare). Handlingen køres fra update() (pendingClick).
|
||||
function SmartPickupFrame:addLinkRow(text, action)
|
||||
local first = nil
|
||||
for _, line in ipairs(ADFlowView.wrapText(text, SmartPickupFrame.TEXT_ROW_CHARS)) do
|
||||
local row = self:addRow(self.textPrefab, {kind = "text"})
|
||||
local title = row:getDescendantByName("title")
|
||||
title:setText(line)
|
||||
self:makeRowClickable(row, action)
|
||||
first = first or title
|
||||
end
|
||||
return first
|
||||
end
|
||||
|
||||
local function optionIndex(options, value)
|
||||
for index, option in ipairs(options) do
|
||||
if option.value == value then return index end
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
function SmartPickupFrame:addGuideRow(row)
|
||||
local data = {kind = "guideRow", row = row}
|
||||
if row.type == "choice" then
|
||||
local element = self:addRow(self.productPrefab, data)
|
||||
local option = element:getDescendantByName("option")
|
||||
local texts = {}
|
||||
for _, entry in ipairs(row.options) do table.insert(texts, self:guideText(entry.label)) end
|
||||
option:setTexts(texts)
|
||||
option:setState(optionIndex(row.options, row.value), false)
|
||||
element:getDescendantByName("title"):setText(self:guideText(row.title))
|
||||
elseif row.type == "toggle" or row.type == "check" then
|
||||
local element = self:addRow(self.ingredientPrefab, data)
|
||||
local option = element:getDescendantByName("option")
|
||||
if row.type == "toggle" then option:setTexts({self:guideText(row.off), self:guideText(row.on)}) end
|
||||
option:setState(row.value and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF, false)
|
||||
element:getDescendantByName("title"):setText((row.type == "check" and " " or "") .. self:guideText(row.title))
|
||||
elseif row.type == "link" then
|
||||
local text = row.label ~= nil and self:guideText(row.label)
|
||||
or (ADGuide.lineText(row.line, function(key) return self.i18n:getText(key) end) .. self.i18n:getText("spu_guide_editSuffix"))
|
||||
self:addLinkRow(" " .. text, function(frame) frame:onGuideLink(row) end)
|
||||
else
|
||||
self:addTextRow(self:guideText(row.label))
|
||||
end
|
||||
end
|
||||
|
||||
-- Tegner den åbne guide. false = guiden er lukket (fx marken findes ikke længere) — fanen viser oversigten.
|
||||
function SmartPickupFrame:fillGuideRows(adEnv)
|
||||
local hooks = self:guideHooks()
|
||||
if hooks == nil or self.guide == nil then return false end
|
||||
local context = hooks.context(self, adEnv, self.guide)
|
||||
if context == nil then
|
||||
self:closeGuide()
|
||||
self.statusOverride = self.i18n:getText("spu_guide_closed")
|
||||
self.statusOverrideTicks = SmartPickupFrame.STATUS_OVERRIDE_TICKS
|
||||
return false
|
||||
end
|
||||
self.guide = ADGuide.withContext(self.guide, context)
|
||||
local guide, model = self.guide, hooks.model
|
||||
self:addTextRow(hooks.heading(self, guide))
|
||||
local stepTitle = self.i18n:getText(model.stepKey(guide.step))
|
||||
local index, total = ADGuide.position(guide)
|
||||
local header
|
||||
if guide.single then
|
||||
header = string.format(self.i18n:getText("spu_guide_editStep"), stepTitle)
|
||||
elseif index ~= nil and total > 1 then
|
||||
header = string.format(self.i18n:getText("spu_guide_stepOf"), index, total, stepTitle)
|
||||
else
|
||||
header = string.format(self.i18n:getText("spu_guide_stepOne"), index or 1, stepTitle)
|
||||
end
|
||||
self:addTextRow(header)
|
||||
self:addTextRow(" " .. self.i18n:getText(model.hintKey(guide.step)))
|
||||
for _, row in ipairs(model.rows(guide)) do
|
||||
self:addGuideRow(row)
|
||||
end
|
||||
if hooks.afterRows ~= nil then hooks.afterRows(self, adEnv, guide) end
|
||||
return true
|
||||
end
|
||||
|
||||
-- ---- klik ----
|
||||
|
||||
function SmartPickupFrame:applyGuideChoice(id, value)
|
||||
local hooks = self:guideHooks()
|
||||
if hooks == nil or self.guide == nil then return end
|
||||
if hooks.choose ~= nil and hooks.choose(self, id, value) then return end
|
||||
self.guide = hooks.model.choose(self.guide, id, value)
|
||||
end
|
||||
|
||||
function SmartPickupFrame:onClickGuideRow(state, data)
|
||||
self:safe(function(frame)
|
||||
local row = data ~= nil and data.row or nil
|
||||
if row == nil or frame.guide == nil then return end
|
||||
local value
|
||||
if row.type == "choice" then
|
||||
local option = row.options[state]
|
||||
if option == nil then return end
|
||||
value = option.value
|
||||
elseif row.type == "toggle" then
|
||||
value = state == SmartPickupFrame.STATE_ON
|
||||
elseif row.type == "check" then
|
||||
value = {item = row.item, on = state == SmartPickupFrame.STATE_ON}
|
||||
else
|
||||
return
|
||||
end
|
||||
frame:applyGuideChoice(row.id, value)
|
||||
frame:requestRebuild()
|
||||
end)
|
||||
end
|
||||
|
||||
-- Klikbare linjer: [Ret] på oversigts-trinnet åbner ét trin; andre links er valg (fx mark i trin 1).
|
||||
function SmartPickupFrame:onGuideLink(row)
|
||||
if self.guide == nil then return end
|
||||
if row.id == "jump" then
|
||||
self.guide = ADGuide.jump(self.guide, row.value, "summary")
|
||||
else
|
||||
self:applyGuideChoice(row.id, row.value)
|
||||
end
|
||||
self:requestRebuild()
|
||||
end
|
||||
|
||||
local function finish(frame, hooks, guide, start)
|
||||
hooks.save(frame, guide, start)
|
||||
frame:closeGuide()
|
||||
frame:requestRebuild()
|
||||
end
|
||||
|
||||
-- Næste / Gem / Kør automatisk (start = true) og Gem uden at starte (start = false).
|
||||
function SmartPickupFrame:onClickGuideNext(start)
|
||||
self:safe(function(frame)
|
||||
local hooks, guide = frame:guideHooks(), frame.guide
|
||||
if hooks == nil or guide == nil then return end
|
||||
if hooks.canAdvance ~= nil and not hooks.canAdvance(guide) then
|
||||
frame:showOverride(frame.i18n:getText(hooks.cannotAdvanceKey or "spu_guide_cannotAdvance"))
|
||||
return
|
||||
end
|
||||
if guide.single and guide.returnTo == "close" then
|
||||
if start == false then return end
|
||||
return finish(frame, hooks, guide, nil)
|
||||
end
|
||||
if guide.step == "summary" and not guide.single then
|
||||
return finish(frame, hooks, guide, start)
|
||||
end
|
||||
if start == false then return end
|
||||
local nextGuide, event = ADGuide.next(guide)
|
||||
if event == "done" then return finish(frame, hooks, guide, true) end
|
||||
frame.guide = nextGuide
|
||||
frame:requestRebuild()
|
||||
end)
|
||||
end
|
||||
|
||||
function SmartPickupFrame:onClickGuideBack()
|
||||
self:safe(function(frame)
|
||||
if frame.guide == nil then return end
|
||||
local previous, event = ADGuide.back(frame.guide)
|
||||
if event == "cancel" then frame:closeGuide() else frame.guide = previous end
|
||||
frame:requestRebuild()
|
||||
end)
|
||||
end
|
||||
|
||||
function SmartPickupFrame:onClickGuideCancel()
|
||||
self:safe(function(frame)
|
||||
frame:closeGuide()
|
||||
frame:requestRebuild()
|
||||
end)
|
||||
end
|
||||
|
||||
-- Knapperne følger trinnet: Næste / OK (tilbage til oversigten) / Gem ([Ret] fra fanen) / Kør automatisk.
|
||||
function SmartPickupFrame:getGuideButtons()
|
||||
local hooks, guide = self:guideHooks(), self.guide
|
||||
local i18n = self.i18n
|
||||
local isSummary = guide.step == "summary" and not guide.single
|
||||
local key = "spu_guide_next"
|
||||
if guide.single then
|
||||
key = guide.returnTo == "close" and "spu_guide_save" or "spu_guide_ok"
|
||||
elseif isSummary then
|
||||
key = hooks.startKey ~= nil and hooks.startKey(guide) or "spu_guide_save"
|
||||
end
|
||||
self.guideNextButtonInfo.text = i18n:getText(key)
|
||||
self.guideNextButtonInfo.disabled = hooks.canAdvance ~= nil and not hooks.canAdvance(guide)
|
||||
if isSummary and (hooks.showSaveOnly == nil or hooks.showSaveOnly(guide)) then
|
||||
return self.guideSummaryButtons
|
||||
end
|
||||
return self.guideButtons
|
||||
end
|
||||
@@ -179,6 +179,9 @@ end
|
||||
|
||||
function SmartPickupFrame:onClickProduct(state, element)
|
||||
local clicked = self.rowData[element]
|
||||
if clicked ~= nil and clicked.kind == "guideRow" then
|
||||
return self:onClickGuideRow(state, clicked)
|
||||
end
|
||||
if clicked ~= nil and clicked.kind == "storageBuilding" then
|
||||
return self:safe(function(frame) frame:onClickStorageBuilding(state) end)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user