feat(gui): guiden "Opsæt flow" — Flows-fanen får tavle + resumé (klik = ret ét trin, Navn = omdøb) og trin-for-trin-guide på samme ramme som markguiden; Nyt flow oprettes først ved Gem (v1.32.0.0)
This commit is contained in:
@@ -0,0 +1,303 @@
|
||||
-- Smart Pickup — fanen Flows: tavle + resumé, og guiden "Opsæt flow"
|
||||
-- Tavlen øverst (én række pr. flow), det valgte flows resumé (klik på en linje = ret ét trin; Navn = omdøb)
|
||||
-- og status. [Opsæt flow] / [Nyt flow] åbner guiden på den fælles trin-skærm (gui/SmartPickupGuide.lua).
|
||||
-- Henter det spil-afhængige som `context` til ADFlowGuide og gemmer via ADRunsController.
|
||||
-- Funktionerne lægges på SmartPickupFrame (indlæses efter SmartPickupFrame.lua).
|
||||
|
||||
function SmartPickupFrame:initFlowButtons(i18n)
|
||||
self.flowSetupButtonInfo = {inputAction = InputAction.MENU_EXTRA_1, text = i18n:getText("spu_guide_flow_open"), callback = function() self:onClickFlowSetup() end}
|
||||
self.flowNewButtonInfo = {inputAction = InputAction.MENU_EXTRA_2, text = i18n:getText("spu_button_new"), callback = function() self:onClickFlowNew() end}
|
||||
-- Flows-fanen: [Start/Stop] [Opsæt flow] [Nyt flow] [Slet]; omdøb ligger på resuméets Navn-linje
|
||||
self.flowButtons = {self.backButtonInfo, self.startButtonInfo, self.flowSetupButtonInfo, self.flowNewButtonInfo, self.deleteButtonInfo}
|
||||
end
|
||||
|
||||
-- ---- traktor-tekst (også til guidens traktorliste) ----
|
||||
|
||||
-- "Fastrac 2135 4WS (#1) — 1.000.000 l — kan bære: Halm, TMR — OK" / "… — X ingen vogn".
|
||||
function SmartPickupFrame:describeVehicle(adEnv, run, vehicle, isInRun)
|
||||
local label = ADRunsController.getVehicleLabel(adEnv, vehicle)
|
||||
local validation = ADRunsController.validateVehicle(adEnv, run, vehicle)
|
||||
local parts = {label}
|
||||
if validation.isAutoload and validation.capacity == nil then
|
||||
table.insert(parts, self.i18n:getText("spu_capacity_pallets"))
|
||||
elseif validation.capacity ~= nil then
|
||||
table.insert(parts, string.format(self.i18n:getText("spu_capacity"), g_i18n:formatNumber(validation.capacity, 0)))
|
||||
local carriable = self:describeCarriable(adEnv, run, vehicle, validation.carriable)
|
||||
if carriable ~= nil then
|
||||
table.insert(parts, carriable)
|
||||
end
|
||||
end
|
||||
if validation.ok then
|
||||
table.insert(parts, "OK")
|
||||
else
|
||||
local reason = self.i18n:getText("spu_reason_" .. tostring(validation.reason))
|
||||
if validation.reason == "noMarker" and validation.missingBuilding ~= nil then
|
||||
reason = string.format(reason, tostring(validation.missingBuilding))
|
||||
end
|
||||
table.insert(parts, "X " .. reason)
|
||||
end
|
||||
return table.concat(parts, " — ")
|
||||
end
|
||||
|
||||
-- Hvilke af run'ets varer vognen kan bære (titler); nil når ingen.
|
||||
function SmartPickupFrame:describeCarriable(adEnv, run, vehicle, carriable)
|
||||
local canCarry = {}
|
||||
for _, fillType in ipairs(carriable or {}) do
|
||||
canCarry[fillType] = true
|
||||
end
|
||||
local titles = {}
|
||||
for _, fillType in ipairs(ADRunsController.getRunIngredients(adEnv, run, vehicle)) do
|
||||
if canCarry[fillType] then
|
||||
local title = g_fillTypeManager.getFillTypeTitleByIndex ~= nil and g_fillTypeManager:getFillTypeTitleByIndex(fillType) or nil
|
||||
table.insert(titles, tostring(title or g_fillTypeManager:getFillTypeNameByIndex(fillType)))
|
||||
end
|
||||
end
|
||||
if #titles == 0 then
|
||||
return nil
|
||||
end
|
||||
return string.format(self.i18n:getText("spu_canCarry"), table.concat(titles, ", "))
|
||||
end
|
||||
|
||||
-- ---- context til ADFlowGuide ----
|
||||
|
||||
local function trim(text)
|
||||
return (string.gsub(tostring(text or ""), "^%s+", ""))
|
||||
end
|
||||
|
||||
local function idSet(list)
|
||||
local set = {}
|
||||
for _, id in ipairs(list or {}) do set[id] = true end
|
||||
return set
|
||||
end
|
||||
|
||||
function SmartPickupFrame:flowBuildingContext(adEnv, draft, farmId)
|
||||
local isOut = draft.kind == "outbound"
|
||||
local role = isOut and "load" or "unload"
|
||||
local chosen = idSet(isOut and draft.sourceBuildingIds or draft.targetBuildingIds)
|
||||
local buildings, found = {}, {}
|
||||
for _, building in ipairs(ADBuildings.list(adEnv, farmId)) do
|
||||
local fits = (isOut and building.canBeSource) or (not isOut and building.canBeTarget)
|
||||
if fits or chosen[building.id] then
|
||||
local markers = ADBuildings.getMarkers ~= nil and ADBuildings.getMarkers(building, role) or {}
|
||||
found[building.id] = true
|
||||
table.insert(buildings, {id = building.id, name = tostring(building.name), label = markers[1] ~= nil and tostring(markers[1].name) or nil,
|
||||
hasMarker = markers[1] ~= nil, text = trim(self:describeBuilding(building, role))})
|
||||
end
|
||||
end
|
||||
-- valgte bygninger der ikke længere findes (solgt): kan fravælges
|
||||
for id in pairs(chosen) do
|
||||
if not found[id] then
|
||||
local gone = self.i18n:getText("spu_buildingGone")
|
||||
table.insert(buildings, {id = id, name = gone, hasMarker = false, text = gone})
|
||||
end
|
||||
end
|
||||
return buildings
|
||||
end
|
||||
|
||||
function SmartPickupFrame:flowStoreContext(adEnv, preview, farmId)
|
||||
local goods = ADRunsController.getStoreGoods(adEnv, preview)
|
||||
local chosen = idSet(preview.storeBuildingIds)
|
||||
local result = {}
|
||||
for _, building in ipairs(ADBuildings.list(adEnv, farmId)) do
|
||||
local isStoreKind = building.kind == "silo" or building.kind == "factory" or building.kind == "objectStorage"
|
||||
if isStoreKind and (chosen[building.id] or ADRunsController.canStoreAt(adEnv, building, goods)) then
|
||||
table.insert(result, {id = building.id, name = tostring(building.name), text = trim(self:describeBuilding(building, "unload"))})
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function SmartPickupFrame:flowVehicleContext(adEnv, preview)
|
||||
local result = {}
|
||||
for _, vehicle in ipairs(ADRunsController.getFarmVehicles(adEnv)) do
|
||||
local ok, entry = pcall(function()
|
||||
local text = self:describeVehicle(adEnv, preview, vehicle, false)
|
||||
local validation = ADRunsController.validateVehicle(adEnv, preview, vehicle)
|
||||
local other = ADRunsController.getRunForVehicle(vehicle)
|
||||
return {id = ADRunsController.getVehicleId(vehicle), text = text, label = ADRunsController.getVehicleLabel(adEnv, vehicle), otherRunId = other ~= nil and other.id or nil,
|
||||
otherRunName = other ~= nil and other.name or nil, blocked = SmartPickupFrame.VEHICLE_BLOCKING_REASONS[validation.reason] == true}
|
||||
end)
|
||||
if ok and entry.id ~= nil then table.insert(result, entry) end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- draft: kladden (eller selve run'et — samme feltnavne).
|
||||
function SmartPickupFrame:flowGuideContext(adEnv, draft)
|
||||
local farmId = g_currentMission:getFarmId()
|
||||
local preview = ADFlowGuide.previewRun(draft, function(buildingId, role)
|
||||
local building = ADBuildings.find(adEnv, farmId, buildingId)
|
||||
local ids = {}
|
||||
for _, marker in ipairs(building ~= nil and ADBuildings.getMarkers ~= nil and ADBuildings.getMarkers(building, role) or {}) do
|
||||
table.insert(ids, marker.id)
|
||||
end
|
||||
return ids
|
||||
end)
|
||||
local context = {buildings = self:flowBuildingContext(adEnv, draft, farmId), fillTypes = {}, products = {}, storeBuildings = {},
|
||||
waitPools = ADRunsController.getWaitPools(adEnv), vehicles = self:flowVehicleContext(adEnv, preview)}
|
||||
if draft.kind == "outbound" then
|
||||
for _, product in ipairs(ADRunsController.getRunProducts(adEnv, preview)) do
|
||||
local title = tostring(product.title)
|
||||
table.insert(context.products, {name = product.name, title = title,
|
||||
text = string.format("%s — %s l", title, SmartPickupFrame.formatCompact(product.available or 0))})
|
||||
end
|
||||
context.storeBuildings = self:flowStoreContext(adEnv, preview, farmId)
|
||||
else
|
||||
for _, fillType in ipairs(ADRunsController.getTargetAcceptedFillTypes(adEnv, preview)) do
|
||||
table.insert(context.fillTypes, {name = fillType.name, title = tostring(fillType.title)})
|
||||
end
|
||||
end
|
||||
return context
|
||||
end
|
||||
|
||||
-- ---- fanen: tavle + resumé ----
|
||||
|
||||
function SmartPickupFrame:fillFlowTabRows(adEnv)
|
||||
if self:hasGuideOn(SmartPickupFrame.TAB_FLOWS) and self:fillGuideRows(adEnv) then return end
|
||||
self:fillOverviewRows(adEnv)
|
||||
local run = self:getRun()
|
||||
if run ~= nil then self:fillFlowSummary(adEnv, run) end
|
||||
end
|
||||
|
||||
function SmartPickupFrame:fillFlowSummary(adEnv, run)
|
||||
local i18n = self.i18n
|
||||
self:addTextRow(string.format(i18n:getText("spu_guide_flow_section"), tostring(run.name)))
|
||||
self:addTextRow(" " .. i18n:getText("spu_guide_sum_hint"))
|
||||
local guide = ADFlowGuide.open(run, self:flowGuideContext(adEnv, run))
|
||||
local getText = function(key) return i18n:getText(key) end
|
||||
local runId = run.id
|
||||
for _, line in ipairs(ADFlowGuide.summary(guide)) do
|
||||
local step = line.step
|
||||
self:addLinkRow(" " .. ADGuide.lineText(line, getText) .. i18n:getText("spu_guide_editSuffix"), function(frame)
|
||||
if step == "name" then frame:onClickRename() else frame:openFlowStep(runId, step) end
|
||||
end)
|
||||
end
|
||||
local cells = self:flowCells(adEnv, run)
|
||||
self:addTextRow(" " .. string.format(i18n:getText("spu_field_statusFull"), tostring(cells[6])))
|
||||
end
|
||||
|
||||
-- Hvert sekund: tavlens celler, statuslinje og knapper.
|
||||
function SmartPickupFrame:refreshFlowTab(adEnv)
|
||||
local run = self:getRun()
|
||||
local isRunning = false
|
||||
if self:hasGuideOn(SmartPickupFrame.TAB_FLOWS) then
|
||||
self:setStatusText(self.statusOverride or "")
|
||||
else
|
||||
self:refreshOverview(adEnv)
|
||||
if run ~= nil then
|
||||
local status = ADRunsController.getRunStatus(adEnv, run)
|
||||
isRunning = status.isRunning == true
|
||||
local text = status.running > 0 and string.format(self.i18n:getText("spu_status_running"), status.running, status.total)
|
||||
or string.format(self.i18n:getText("spu_status_stopped"), status.total)
|
||||
self:setStatusText(self.statusOverride or text)
|
||||
else
|
||||
-- tavlen siger allerede "Ingen flows"
|
||||
self:setStatusText(self.statusOverride or "")
|
||||
end
|
||||
end
|
||||
self.startButtonInfo.text = self.i18n:getText(isRunning and "spu_button_stop" or "spu_button_start")
|
||||
self.startButtonInfo.disabled = run == nil
|
||||
self.flowSetupButtonInfo.disabled = run == nil
|
||||
self.deleteButtonInfo.disabled = run == nil
|
||||
end
|
||||
|
||||
-- ---- hooks til den fælles guide-skærm ----
|
||||
|
||||
SmartPickupFrame.GUIDE_HOOKS = SmartPickupFrame.GUIDE_HOOKS or {}
|
||||
SmartPickupFrame.GUIDE_HOOKS.flow = {
|
||||
model = ADFlowGuide,
|
||||
tab = SmartPickupFrame.TAB_FLOWS,
|
||||
heading = function(frame, guide)
|
||||
return string.format(frame.i18n:getText("spu_guide_flow_title"), tostring(guide.draft.name))
|
||||
end,
|
||||
context = function(frame, adEnv, guide)
|
||||
-- flowet er slettet mens guiden var åben
|
||||
if not guide.draft.isNew and ADRuns.getRun(ADRunsController.store, guide.draft.id) == nil then return nil end
|
||||
return frame:flowGuideContext(adEnv, guide.draft)
|
||||
end,
|
||||
choose = function(frame, id)
|
||||
if id ~= "rename" then return false end
|
||||
TextInputDialog.show(SmartPickupFrame.onGuideNameResult, frame, frame.guide.draft.name, frame.i18n:getText("spu_renameTitle"), nil, 30, g_i18n:getText("button_ok"))
|
||||
return true
|
||||
end,
|
||||
startKey = function() return "spu_guide_flow_start" end,
|
||||
save = function(frame, guide, start) frame:saveFlowGuide(guide, start) end,
|
||||
}
|
||||
|
||||
function SmartPickupFrame:onGuideNameResult(value, clickOk)
|
||||
self:safe(function(frame)
|
||||
if not clickOk or frame.guide == nil or frame.guideKind ~= "flow" then return end
|
||||
frame.guide = ADFlowGuide.choose(frame.guide, "name", value)
|
||||
frame:requestRebuild()
|
||||
end)
|
||||
end
|
||||
|
||||
-- Gem: nyt flow oprettes først nu; felterne via updateRun; traktorer tildeles/fjernes; markører findes.
|
||||
-- start = true: flowet startes bagefter ([Start flow]).
|
||||
function SmartPickupFrame:saveFlowGuide(guide, start)
|
||||
local adEnv = self.getAdEnv()
|
||||
local result = ADFlowGuide.result(guide)
|
||||
local runId = result.runId
|
||||
local oldIds = {}
|
||||
if result.isNew then
|
||||
runId = ADRunsController.createRun(result.name, result.kind).id
|
||||
else
|
||||
local existing = ADRuns.getRun(ADRunsController.store, runId)
|
||||
if existing == nil then return end
|
||||
oldIds = existing.vehicleIds
|
||||
end
|
||||
ADRunsController.updateRun(runId, result.changes)
|
||||
local added, removed = ADFlowGuide.vehicleChanges(oldIds, result.vehicleIds)
|
||||
for _, id in ipairs(removed) do
|
||||
local vehicle = adEnv ~= nil and ADRunsController.findVehicleById(adEnv, id) or nil
|
||||
if vehicle ~= nil then
|
||||
ADRunsController.unassignVehicle(vehicle)
|
||||
else
|
||||
ADRunsController.store = ADRuns.unassignVehicle(ADRunsController.store, id)
|
||||
end
|
||||
end
|
||||
for _, id in ipairs(added) do
|
||||
local vehicle = adEnv ~= nil and ADRunsController.findVehicleById(adEnv, id) or nil
|
||||
if vehicle ~= nil then ADRunsController.assignVehicle(runId, vehicle) end
|
||||
end
|
||||
ADRunsController.resolveMarkers(adEnv, ADRuns.getRun(ADRunsController.store, runId))
|
||||
self.selectedRunId = runId
|
||||
local saved = string.format(self.i18n:getText("spu_guide_flow_saved"), tostring(result.name))
|
||||
if start and adEnv ~= nil and not ADRunsController.getRunStatus(adEnv, ADRuns.getRun(ADRunsController.store, runId)).isRunning then
|
||||
local started, skipped, reasons = self:summarizeStartResults(ADRunsController.startRun(adEnv, runId))
|
||||
self:showOverride(saved .. " — " .. string.format(self.i18n:getText("spu_status_started"), started, skipped), reasons)
|
||||
else
|
||||
self:showOverride(saved)
|
||||
end
|
||||
ADRunsController.save()
|
||||
end
|
||||
|
||||
-- ---- knapper og [Ret] ----
|
||||
|
||||
function SmartPickupFrame:onClickFlowSetup()
|
||||
self:safe(function(frame)
|
||||
local adEnv, run = frame.getAdEnv(), frame:getRun()
|
||||
if adEnv == nil or run == nil then return end
|
||||
frame:openGuide("flow", ADFlowGuide.open(run, frame:flowGuideContext(adEnv, run)))
|
||||
end)
|
||||
end
|
||||
|
||||
-- [Nyt flow] (også fra fanen Oversigt): guiden på Flows-fanen; intet oprettes før [Gem].
|
||||
function SmartPickupFrame:onClickFlowNew()
|
||||
self:safe(function(frame)
|
||||
local adEnv = frame.getAdEnv()
|
||||
if adEnv == nil then return end
|
||||
local name = string.format(frame.i18n:getText("spu_newRunName"), #ADRunsController.store.runs + 1)
|
||||
local guide = ADFlowGuide.openNew(name, {})
|
||||
guide = ADGuide.withContext(guide, frame:flowGuideContext(adEnv, guide.draft))
|
||||
if frame.currentTab ~= SmartPickupFrame.TAB_FLOWS then frame:switchTab(SmartPickupFrame.TAB_FLOWS) end
|
||||
frame:openGuide("flow", guide)
|
||||
end)
|
||||
end
|
||||
|
||||
function SmartPickupFrame:openFlowStep(runId, step)
|
||||
local adEnv = self.getAdEnv()
|
||||
local run = ADRuns.getRun(ADRunsController.store, runId)
|
||||
if adEnv == nil or run == nil then return end
|
||||
self:openGuide("flow", ADFlowGuide.open(run, self:flowGuideContext(adEnv, run), {step = step, single = true, returnTo = "close"}))
|
||||
end
|
||||
@@ -1,7 +1,7 @@
|
||||
-- Smart Pickup — fanen Flows
|
||||
-- Tavle øverst: én tekstrække pr. flow (Vare · Fra → Til · Regel · Traktorer · Status), det valgte
|
||||
-- markeret med ">". Under tavlen: detail-blok for det valgte flow — Retning, Fra/Til som BYGNINGER
|
||||
-- (markøren findes automatisk), Varer, Regler, Vent ved, Traktorer, Status — og Wait-puljerne.
|
||||
-- Tavlen (én række pr. flow, det valgte markeret med ">") bruges af fanerne Oversigt og Flows; Flows-fanens
|
||||
-- resumé og guiden "Opsæt flow" ligger i gui/SmartPickupFlowGuide.lua. Her også bygnings-teksten og de
|
||||
-- gamle klik-callbacks for retning/bygninger.
|
||||
-- Funktionerne lægges på SmartPickupFrame (indlæses efter SmartPickupFrame.lua).
|
||||
|
||||
-- ---- tavlen ----
|
||||
@@ -137,86 +137,6 @@ function SmartPickupFrame:describeBuilding(building, role)
|
||||
return string.format(" %s — %s", building.name, table.concat(parts, " · "))
|
||||
end
|
||||
|
||||
-- Afkrydsning pr. bygning: kilder (udkørsel, role "load") eller mål (forsyning, role "unload").
|
||||
function SmartPickupFrame:fillBuildingRows(adEnv, run, role)
|
||||
if ADBuildings == nil then
|
||||
self:addTextRow(self.i18n:getText("spu_status_noAd"))
|
||||
return
|
||||
end
|
||||
local chosen = {}
|
||||
local ids = role == "load" and run.sourceBuildingIds or role == "store" and run.storeBuildingIds or run.targetBuildingIds
|
||||
local rowKind = role == "load" and "sourceBuilding" or role == "store" and "storeBuilding" or "targetBuilding"
|
||||
for _, id in ipairs(ids or {}) do chosen[id] = true end
|
||||
local count = 0
|
||||
-- kandidater i fast rækkefølge (navn, markør); uden markør kun med "Vis alle bygninger"
|
||||
local candidates = {}
|
||||
-- "Lager til": kun bygninger der kan tage flowets lagervarer (æg-paller -> palleskure der tager æg)
|
||||
local storeGoods = role == "store" and ADRunsController.getStoreGoods(adEnv, run) or nil
|
||||
for _, building in ipairs(ADBuildings.list(adEnv, g_currentMission:getFarmId())) do
|
||||
local isStoreKind = building.kind == "silo" or building.kind == "factory" or building.kind == "objectStorage"
|
||||
local fits = (role == "load" and building.canBeSource) or (role == "unload" and building.canBeTarget)
|
||||
or (role == "store" and isStoreKind and (chosen[building.id] or ADRunsController.canStoreAt(adEnv, building, storeGoods)))
|
||||
if fits then
|
||||
local markers = ADBuildings.getMarkers ~= nil and ADBuildings.getMarkers(building, role == "store" and "unload" or role) or {}
|
||||
table.insert(candidates, {id = building.id, name = building.name, label = markers[1] ~= nil and tostring(markers[1].name) or nil, hasMarker = markers[1] ~= nil, building = building})
|
||||
end
|
||||
end
|
||||
local shown = ADFlowView.buildingRows(candidates, chosen, self.showAllBuildings == true)
|
||||
local hiddenBuildings = ADFlowView.hiddenCount(candidates, shown)
|
||||
if hiddenBuildings > 0 or self.showAllBuildings then
|
||||
self:addToggleRow("showAllBuildings", string.format(self.i18n:getText("spu_showAllBuildings"), hiddenBuildings), {self.i18n:getText("ui_no"), self.i18n:getText("ui_yes")}, self.showAllBuildings == true)
|
||||
end
|
||||
for _, entry in ipairs(shown) do
|
||||
local building = entry.building
|
||||
count = count + 1
|
||||
local row = self:addRow(self.ingredientPrefab, {kind = rowKind, buildingId = building.id})
|
||||
row:getDescendantByName("title"):setText(self:describeBuilding(building, role == "store" and "unload" or role))
|
||||
row:getDescendantByName("option"):setState(chosen[building.id] and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF, false)
|
||||
end
|
||||
-- valgte bygninger der ikke længere findes (solgt)
|
||||
for _, id in ipairs(ids or {}) do
|
||||
if ADBuildings.find(adEnv, g_currentMission:getFarmId(), id) == nil then
|
||||
local row = self:addRow(self.ingredientPrefab, {kind = rowKind, buildingId = id})
|
||||
row:getDescendantByName("title"):setText(" " .. self.i18n:getText("spu_buildingGone"))
|
||||
row:getDescendantByName("option"):setState(SmartPickupFrame.STATE_ON, false)
|
||||
end
|
||||
end
|
||||
if count == 0 then
|
||||
self:addTextRow(self.i18n:getText("spu_noBuildings"))
|
||||
end
|
||||
end
|
||||
|
||||
function SmartPickupFrame:rebuildFlowDetail(adEnv, run)
|
||||
ADRunsController.resolveMarkers(adEnv, run)
|
||||
run = self:getRun()
|
||||
local isOut = run.kind == "outbound"
|
||||
self:addTextRow(string.format(self.i18n:getText("spu_section_flow"), run.name))
|
||||
self.directionRowOption = self:addToggleRow("direction", self.i18n:getText("spu_direction"), {self.i18n:getText("spu_direction_in"), self.i18n:getText("spu_direction_out")}, isOut)
|
||||
if isOut then
|
||||
self:addTextRow(self.i18n:getText("spu_section_from"))
|
||||
self:fillBuildingRows(adEnv, run, "load")
|
||||
self:addTextRow(self.i18n:getText("spu_section_products"))
|
||||
self:fillProductRows(adEnv, run)
|
||||
self:addTextRow(self.i18n:getText("spu_section_rules"))
|
||||
self.sellAtOption:setState(SmartPickupFrame.getStepIndex(self.sellAtSteps, run.sellAtPercent, ADRuns.DEFAULT_SELL_AT_PERCENT), false)
|
||||
self.storeAboveOption:setState(SmartPickupFrame.getStepIndex(self.storeAboveSteps, run.storeAbovePercent, ADRuns.DEFAULT_STORE_ABOVE_PERCENT), false)
|
||||
self.collectRoundRowOption = self:addToggleRow("collectRound", self.i18n:getText("spu_collectRound"), {self.i18n:getText("ui_no"), self.i18n:getText("ui_yes")}, run.collectRound == true)
|
||||
self:addTextRow(self.i18n:getText("spu_section_store"))
|
||||
self:fillBuildingRows(adEnv, run, "store")
|
||||
self:fillOutboundStatusRows(adEnv, run)
|
||||
else
|
||||
self:addTextRow(self.i18n:getText("spu_section_to"))
|
||||
self:fillBuildingRows(adEnv, run, "unload")
|
||||
self:addTextRow(self.i18n:getText("spu_section_targets"))
|
||||
self.ingredientModeRowOption = self:addToggleRow("ingredientMode", self.i18n:getText("spu_ingredientMode"), {self.i18n:getText("spu_mode_auto"), self.i18n:getText("spu_mode_manual")}, run.ingredientMode == "manual")
|
||||
self:fillIngredientRows(adEnv, run)
|
||||
self:fillNeedsRows(adEnv, run)
|
||||
self:addTextRow(self.i18n:getText("spu_section_rules"))
|
||||
self.loopsOption:setState(run.loops + 1, false)
|
||||
self.returnBelowOption:setState(self:getReturnBelowIndex(run), false)
|
||||
end
|
||||
end
|
||||
|
||||
-- ---- callbacks ----
|
||||
|
||||
function SmartPickupFrame:onClickDirection(state)
|
||||
|
||||
@@ -55,6 +55,8 @@ function SmartPickupFrame.new(i18n, getAdEnv)
|
||||
-- Marker: [Start nu/Stop], [Opsæt mark], [Markflåde] (gui/SmartPickupFieldGuide.lua); guidens knapper
|
||||
self:initFieldButtons(i18n)
|
||||
self:initGuideButtons(i18n)
|
||||
-- Flows: [Start/Stop] [Opsæt flow] [Nyt flow] [Slet] (gui/SmartPickupFlowGuide.lua)
|
||||
self:initFlowButtons(i18n)
|
||||
-- Egen reference til listen: fallback'en i refreshButtons skal kunne sende den igen.
|
||||
self.menuButtonInfo = self.overviewButtons
|
||||
self:setMenuButtonInfo(self.menuButtonInfo)
|
||||
@@ -267,7 +269,8 @@ end
|
||||
-- De faste rækker: Flow-vælger + Wait-pulje for alle flows; Ture/kør hjem for forsyning; Sælg fra/
|
||||
-- Kør til lager for udkørsel. Fanen Lagre viser ingen.
|
||||
function SmartPickupFrame:setStaticRowsVisible(tab, run)
|
||||
local isFlows = tab == SmartPickupFrame.TAB_FLOWS
|
||||
-- Flows-fanen bruger tavle + resumé + guide (v1.32); de faste XML-rækker vises ikke længere
|
||||
local isFlows = false
|
||||
local hasRun = isFlows and run ~= nil
|
||||
local isSupply, isOutbound = hasRun and run.kind ~= "outbound", hasRun and run.kind == "outbound"
|
||||
local visibility = {
|
||||
@@ -419,19 +422,8 @@ function SmartPickupFrame:rebuild()
|
||||
self:restoreFocusIfLost()
|
||||
return
|
||||
end
|
||||
self:fillRunOption(adEnv)
|
||||
local hasRun = run ~= nil and adEnv ~= nil
|
||||
for _, element in ipairs({self.waitPoolOption, self.loopsOption, self.returnBelowOption, self.sellAtOption, self.storeAboveOption}) do
|
||||
if element ~= nil then
|
||||
element:setDisabled(not hasRun)
|
||||
end
|
||||
end
|
||||
if hasRun then
|
||||
self:fillWaitPoolOption(adEnv, run)
|
||||
self:rebuildFlowDetail(adEnv, run)
|
||||
self:addTextRow(self.i18n:getText("spu_section_vehicles"))
|
||||
self:fillVehicleRows(adEnv, run)
|
||||
self:addTextRow(self.i18n:getText("spu_section_status"))
|
||||
if adEnv ~= nil then
|
||||
self:fillFlowTabRows(adEnv)
|
||||
end
|
||||
self.statusRow = self:addTextRow("")
|
||||
self:colorRows()
|
||||
@@ -440,25 +432,6 @@ function SmartPickupFrame:rebuild()
|
||||
self:restoreFocusIfLost()
|
||||
end
|
||||
|
||||
function SmartPickupFrame:fillRunOption(adEnv)
|
||||
local texts, index = {}, 1
|
||||
self.runIds = {}
|
||||
for position, run in ipairs(self:getRunsForTab()) do
|
||||
local status = adEnv ~= nil and ADRunsController.getRunStatus(adEnv, run) or {running = 0, total = #run.vehicleIds}
|
||||
table.insert(texts, string.format("%s (%d/%d)", run.name, status.running, status.total))
|
||||
table.insert(self.runIds, run.id)
|
||||
if run.id == self.selectedRunId then
|
||||
index = position
|
||||
end
|
||||
end
|
||||
if #texts == 0 then
|
||||
texts = {self.i18n:getText("spu_noRuns")}
|
||||
end
|
||||
self.runOption:setTexts(texts)
|
||||
self.runOption:setState(index, false)
|
||||
self.runOption:setDisabled(#self.runIds == 0)
|
||||
end
|
||||
|
||||
-- Overblik: "Cow 1 food: TMR 18.0k/27.8k · Silage 3.0k/…" (mest trængende først)
|
||||
function SmartPickupFrame:describeTargetLevels(target)
|
||||
if #target.levels == 0 then
|
||||
@@ -467,114 +440,6 @@ function SmartPickupFrame:describeTargetLevels(target)
|
||||
return string.format("%s: %s", target.name, self:formatLevels(target.levels))
|
||||
end
|
||||
|
||||
function SmartPickupFrame:fillWaitPoolOption(adEnv, run)
|
||||
local texts, index = {self.i18n:getText("spu_waitPool_all")}, 1
|
||||
self.poolGroups = {""}
|
||||
for _, pool in ipairs(ADRunsController.getWaitPools(adEnv)) do
|
||||
table.insert(texts, string.format("%s (%d)", pool.group, pool.count))
|
||||
table.insert(self.poolGroups, pool.group)
|
||||
if pool.group == run.waitPoolGroup then
|
||||
index = #texts
|
||||
end
|
||||
end
|
||||
self.waitPoolOption:setTexts(texts)
|
||||
self.waitPoolOption:setState(index, false)
|
||||
end
|
||||
|
||||
-- Traktorer: som standard flowets egne og de ledige der kan bruges; "Vis alle" tilføjer traktorer i andre
|
||||
-- flows og låste (vognen passer ikke) — de er tit mange og gør listen uoverskuelig.
|
||||
function SmartPickupFrame:fillVehicleRows(adEnv, run)
|
||||
local inRun = {}
|
||||
for _, id in ipairs(run.vehicleIds) do
|
||||
inRun[id] = true
|
||||
end
|
||||
local entries = {}
|
||||
for _, vehicle in ipairs(ADRunsController.getFarmVehicles(adEnv)) do
|
||||
local id = ADRunsController.getVehicleId(vehicle)
|
||||
local otherRun = ADRunsController.getRunForVehicle(vehicle)
|
||||
local state = "free"
|
||||
if inRun[id] then
|
||||
state = "in"
|
||||
elseif otherRun ~= nil and otherRun.id ~= run.id then
|
||||
state = "other"
|
||||
elseif SmartPickupFrame.VEHICLE_BLOCKING_REASONS[ADRunsController.validateVehicle(adEnv, run, vehicle).reason] then
|
||||
state = "blocked"
|
||||
end
|
||||
table.insert(entries, {id = id, label = ADRunsController.getVehicleLabel(adEnv, vehicle), state = state, vehicle = vehicle, otherRun = otherRun})
|
||||
end
|
||||
local rows = ADFlowView.vehicleRows(entries, self.showAllVehicles == true)
|
||||
local hidden = ADFlowView.hiddenCount(entries, rows)
|
||||
if hidden > 0 or self.showAllVehicles then
|
||||
self.showAllVehiclesOption = self:addToggleRow("showAllVehicles", string.format(self.i18n:getText("spu_showAllVehicles"), hidden), {self.i18n:getText("ui_no"), self.i18n:getText("ui_yes")}, self.showAllVehicles == true)
|
||||
end
|
||||
for _, entry in ipairs(rows) do
|
||||
local vehicle = entry.vehicle
|
||||
local row = self:addRow(self.vehiclePrefab, {kind = "vehicle", vehicle = vehicle, row = nil})
|
||||
local option, title = row:getDescendantByName("option"), row:getDescendantByName("title")
|
||||
self.rowData[option].row = row
|
||||
option:setState(entry.state == "in" and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF, false)
|
||||
if entry.state == "other" then
|
||||
-- én traktor = ét flow; rækken viser hvor den er
|
||||
option:setDisabled(true)
|
||||
self.rowData[option].locked = true
|
||||
title:setText(string.format("%s — %s", entry.label, string.format(self.i18n:getText("spu_inRun"), tostring(entry.otherRun.name))))
|
||||
else
|
||||
title:setText(self:describeVehicle(adEnv, run, vehicle, entry.state == "in"))
|
||||
if entry.state == "blocked" then
|
||||
option:setDisabled(true)
|
||||
self.rowData[option].locked = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- "Fastrac 2135 4WS (#1) — 1.000.000 l — ✔" / "… — ✖ ingen vogn"; reservationsnote fra Start bevares.
|
||||
-- "Fastrac 2135 4WS (#1) — 1.000.000 l — kan bære: Halm, TMR — ✔" / "… — ✖ ingen vogn".
|
||||
-- Vises for ALLE traktorer, så man kan se om vognen passer, før man siger Ja.
|
||||
function SmartPickupFrame:describeVehicle(adEnv, run, vehicle, isInRun)
|
||||
local label = ADRunsController.getVehicleLabel(adEnv, vehicle)
|
||||
local validation = ADRunsController.validateVehicle(adEnv, run, vehicle)
|
||||
local parts = {label}
|
||||
if validation.isAutoload and validation.capacity == nil then
|
||||
table.insert(parts, self.i18n:getText("spu_capacity_pallets"))
|
||||
elseif validation.capacity ~= nil then
|
||||
table.insert(parts, string.format(self.i18n:getText("spu_capacity"), g_i18n:formatNumber(validation.capacity, 0)))
|
||||
local carriable = self:describeCarriable(adEnv, run, vehicle, validation.carriable)
|
||||
if carriable ~= nil then
|
||||
table.insert(parts, carriable)
|
||||
end
|
||||
end
|
||||
if validation.ok then
|
||||
table.insert(parts, "OK")
|
||||
else
|
||||
local reason = self.i18n:getText("spu_reason_" .. tostring(validation.reason))
|
||||
if validation.reason == "noMarker" and validation.missingBuilding ~= nil then
|
||||
reason = string.format(reason, tostring(validation.missingBuilding))
|
||||
end
|
||||
table.insert(parts, "X " .. reason)
|
||||
end
|
||||
return table.concat(parts, " — ")
|
||||
end
|
||||
|
||||
-- Hvilke af run'ets varer vognen kan bære (titler); nil når ingen.
|
||||
function SmartPickupFrame:describeCarriable(adEnv, run, vehicle, carriable)
|
||||
local canCarry = {}
|
||||
for _, fillType in ipairs(carriable or {}) do
|
||||
canCarry[fillType] = true
|
||||
end
|
||||
local titles = {}
|
||||
for _, fillType in ipairs(ADRunsController.getRunIngredients(adEnv, run, vehicle)) do
|
||||
if canCarry[fillType] then
|
||||
local title = g_fillTypeManager.getFillTypeTitleByIndex ~= nil and g_fillTypeManager:getFillTypeTitleByIndex(fillType) or nil
|
||||
table.insert(titles, tostring(title or g_fillTypeManager:getFillTypeNameByIndex(fillType)))
|
||||
end
|
||||
end
|
||||
if #titles == 0 then
|
||||
return nil
|
||||
end
|
||||
return string.format(self.i18n:getText("spu_canCarry"), table.concat(titles, ", "))
|
||||
end
|
||||
|
||||
-- Felterne følger modellen: når et klik ikke er nået ind i run'et, springer feltet tilbage,
|
||||
-- og loggen ("run '…': waitPoolGroup=…") viser om klikket blev registreret.
|
||||
function SmartPickupFrame:syncOptionsFromModel(adEnv, run)
|
||||
@@ -706,6 +571,13 @@ function SmartPickupFrame:refreshLive()
|
||||
self:refreshButtons()
|
||||
return
|
||||
end
|
||||
if self.currentTab == SmartPickupFrame.TAB_FLOWS then
|
||||
self:refreshFlowTab(adEnv)
|
||||
self.statusOverrideTicks = (self.statusOverrideTicks or 0) - 1
|
||||
if self.statusOverrideTicks <= 0 then self.statusOverride = nil end
|
||||
self:refreshButtons()
|
||||
return
|
||||
end
|
||||
self:refreshStorageRows(adEnv)
|
||||
local isRunning = false
|
||||
if isOverview then
|
||||
@@ -919,26 +791,9 @@ function SmartPickupFrame:openFlow(runId)
|
||||
self:switchTab(SmartPickupFrame.TAB_FLOWS)
|
||||
end
|
||||
|
||||
-- Nyt run: navnet vælges FØR run'et oprettes (annulleres dialogen, oprettes intet).
|
||||
-- Forslaget tæller efter antal runs, ikke efter løbenummeret, så "Run 2" kan genbruges.
|
||||
-- Nyt flow: guiden "Opsæt flow" (gui/SmartPickupFlowGuide.lua) — intet oprettes før [Gem].
|
||||
function SmartPickupFrame:onClickNew()
|
||||
self:safe(function(frame)
|
||||
local suggestion = string.format(frame.i18n:getText("spu_newRunName"), #ADRunsController.store.runs + 1)
|
||||
TextInputDialog.show(SmartPickupFrame.onNewRunName, frame, suggestion, frame.i18n:getText("spu_renameTitle"), nil, 30, g_i18n:getText("button_ok"))
|
||||
end)
|
||||
end
|
||||
|
||||
function SmartPickupFrame:onNewRunName(value, clickOk)
|
||||
self:safe(function(frame)
|
||||
if not clickOk or value == nil or not value:match("%S") then
|
||||
return
|
||||
end
|
||||
local run = ADRunsController.createRun(value, "supply")
|
||||
frame.selectedRunId = run.id
|
||||
frame.statusOverride = nil
|
||||
frame.currentTab = SmartPickupFrame.TAB_FLOWS
|
||||
frame:switchTab(SmartPickupFrame.TAB_FLOWS)
|
||||
end)
|
||||
self:onClickFlowNew()
|
||||
end
|
||||
|
||||
function SmartPickupFrame:onClickRename()
|
||||
|
||||
@@ -103,7 +103,7 @@ function SmartPickupFrame:fillGuideRows(adEnv)
|
||||
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 stepTitle = self.i18n:getText(model.stepKey(guide.step, guide))
|
||||
local index, total = ADGuide.position(guide)
|
||||
local header
|
||||
if guide.single then
|
||||
@@ -114,7 +114,7 @@ function SmartPickupFrame:fillGuideRows(adEnv)
|
||||
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)))
|
||||
self:addTextRow(" " .. self.i18n:getText(model.hintKey(guide.step, guide)))
|
||||
for _, row in ipairs(model.rows(guide)) do
|
||||
self:addGuideRow(row)
|
||||
end
|
||||
@@ -140,6 +140,8 @@ function SmartPickupFrame:onClickGuideRow(state, data)
|
||||
local option = row.options[state]
|
||||
if option == nil then return end
|
||||
value = option.value
|
||||
-- valg pr. vare (fx politik): modellen skal vide hvilken
|
||||
if row.item ~= nil then value = {item = row.item, value = option.value} end
|
||||
elseif row.type == "toggle" then
|
||||
value = state == SmartPickupFrame.STATE_ON
|
||||
elseif row.type == "check" then
|
||||
|
||||
Reference in New Issue
Block a user