feat(gui): flow-tavle — faner Flows/Lagre, én række pr. flow, Fra/Til som bygninger med automatisk markør (v1.13.0.0)

This commit is contained in:
2026-09-23 18:19:27 +02:00
parent b202380d9c
commit d46ebbac04
8 changed files with 309 additions and 126 deletions
+45 -124
View File
@@ -10,10 +10,8 @@ SmartPickupFrame.REFRESH_INTERVAL_MS = 1000
SmartPickupFrame.STATUS_OVERRIDE_TICKS = 6
SmartPickupFrame.LOG_PREFIX = "ADSmartPickup: "
SmartPickupFrame.STATE_OFF, SmartPickupFrame.STATE_ON = 1, 2
SmartPickupFrame.TAB_OVERVIEW, SmartPickupFrame.TAB_SUPPLY, SmartPickupFrame.TAB_OUTBOUND, SmartPickupFrame.TAB_STORAGE = 1, 2, 3, 4
SmartPickupFrame.TAB_NAMES = {"spu_tab_overview", "spu_tab_supply", "spu_tab_outbound", "spu_tab_storage"}
-- Hver fane viser kun runs af sin egen slags; Oversigt og Lagre opretter forsynings-runs.
SmartPickupFrame.TAB_KIND = {"supply", "supply", "outbound", "supply"}
SmartPickupFrame.TAB_FLOWS, SmartPickupFrame.TAB_STORAGE = 1, 2
SmartPickupFrame.TAB_NAMES = {"spu_tab_flows", "spu_tab_storage"}
SmartPickupFrame.POLICIES = {"off", "store", "sell", "sellElseStore"}
-- Afvisningsgrunde der handler om VOGNEN (ikke run'ets opsætning): traktoren kan ikke vælges.
SmartPickupFrame.VEHICLE_BLOCKING_REASONS = {noTrailer = true, cannotCarry = true, needsAutoload = true}
@@ -34,7 +32,7 @@ function SmartPickupFrame.new(i18n, getAdEnv)
self.pendingRebuild = false
self.frameOpen = false
self.focusLost = false
self.currentTab = SmartPickupFrame.TAB_OVERVIEW
self.currentTab = SmartPickupFrame.TAB_FLOWS
self.subCategoryTabs = {}
self.backButtonInfo = {inputAction = InputAction.MENU_BACK}
self.startButtonInfo = {inputAction = InputAction.MENU_ACTIVATE, text = i18n:getText("spu_button_start"), callback = function() self:onClickStartStop() end}
@@ -121,9 +119,6 @@ function SmartPickupFrame.getStepIndex(steps, value, default)
return index
end
function SmartPickupFrame:getTabKind()
return SmartPickupFrame.TAB_KIND[self.currentTab] or "supply"
end
function SmartPickupFrame:getReturnBelowIndex(run)
local index = 1
@@ -246,13 +241,15 @@ function SmartPickupFrame:onClickTab(state)
self:switchTab(state)
end
-- De faste rækker hører til hver sin fane: Run + Wait-pulje er fælles, Varer/Ture/tærskel er
-- Forsyning, Sælg fra/Kør til lager/Saml op er Udkørsel. Oversigt viser ingen.
function SmartPickupFrame:setStaticRowsVisible(tab)
local isSupply, isOutbound = tab == SmartPickupFrame.TAB_SUPPLY, tab == SmartPickupFrame.TAB_OUTBOUND
-- 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
local hasRun = isFlows and run ~= nil
local isSupply, isOutbound = hasRun and run.kind ~= "outbound", hasRun and run.kind == "outbound"
local visibility = {
{self.runOption, isSupply or isOutbound},
{self.waitPoolOption, isSupply or isOutbound},
{self.runOption, isFlows},
{self.waitPoolOption, hasRun},
{self.loopsOption, isSupply}, {self.returnBelowOption, isSupply},
{self.sellAtOption, isOutbound}, {self.storeAboveOption, isOutbound},
}
@@ -264,15 +261,8 @@ function SmartPickupFrame:setStaticRowsVisible(tab)
end
end
-- Run'et der vises: kun runs af fanens slags; skifter fanen, vælges fanens første run.
function SmartPickupFrame:getRunsForTab()
local kind, result = self:getTabKind(), {}
for _, run in ipairs(ADRunsController.store.runs) do
if (run.kind or "supply") == kind then
table.insert(result, run)
end
end
return result
return ADRunsController.store.runs
end
function SmartPickupFrame:getRun()
@@ -298,7 +288,8 @@ function SmartPickupFrame:clearRows()
self.overviewRows = {}
self.productRows, self.outboundStatusRows = {}, {}
self.storageRows = {}
self.ingredientModeRowOption, self.collectRoundRowOption = nil, nil
self.boardRows = {}
self.ingredientModeRowOption, self.collectRoundRowOption, self.directionRowOption = nil, nil, nil
end
-- Ja/Nej-række som klon af ingredientPrefab (faste BinaryOption-elementer fra XML'en viser kun
@@ -351,14 +342,12 @@ end
function SmartPickupFrame:rebuild()
local adEnv = self.getAdEnv()
local store = ADRunsController.store
local tabRuns = self:getRunsForTab()
local selected = self.selectedRunId ~= nil and ADRuns.getRun(store, self.selectedRunId) or nil
if selected == nil or (selected.kind or "supply") ~= self:getTabKind() then
self.selectedRunId = tabRuns[1] ~= nil and tabRuns[1].id or nil
if self.selectedRunId == nil or ADRuns.getRun(store, self.selectedRunId) == nil then
self.selectedRunId = store.runs[1] ~= nil and store.runs[1].id or nil
end
self:clearRows()
local isOverview = self.currentTab == SmartPickupFrame.TAB_OVERVIEW
self:setStaticRowsVisible(self.currentTab)
local run = self:getRun()
self:setStaticRowsVisible(self.currentTab, run)
if self.currentTab == SmartPickupFrame.TAB_STORAGE then
if adEnv ~= nil then
self:fillStorageRows(adEnv)
@@ -370,39 +359,26 @@ function SmartPickupFrame:rebuild()
self:refreshLive()
return
end
if isOverview then
if adEnv ~= nil then
self:fillOverviewRows(adEnv)
end
self:addTextRow(self.i18n:getText("spu_waitPools"))
self:fillPoolRows(adEnv)
self.statusRow = self:addTextRow("")
self:colorRows()
self.boxLayout:invalidateLayout()
self:restoreFocusIfLost()
self:refreshLive()
return
end
self:fillRunOption(adEnv)
local run = self:getRun()
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 adEnv ~= nil then
self:fillBoardRows(adEnv)
end
if hasRun then
self:fillWaitPoolOption(adEnv, run)
if self.currentTab == SmartPickupFrame.TAB_OUTBOUND then
self:rebuildOutboundTab(adEnv, run)
else
self:rebuildSupplyTab(adEnv, run)
end
self:rebuildFlowDetail(adEnv, run)
self:addTextRow(self.i18n:getText("spu_section_vehicles"))
self:fillVehicleRows(adEnv, run)
self:addTextRow(self.i18n:getText("spu_section_status"))
end
self.statusRow = self:addTextRow("")
self:addTextRow(self.i18n:getText("spu_waitPools"))
self:fillPoolRows(adEnv)
self:colorRows()
self.boxLayout:invalidateLayout()
self:refreshLive()
@@ -498,7 +474,11 @@ function SmartPickupFrame:describeVehicle(adEnv, run, vehicle, isInRun)
if validation.ok then
table.insert(parts, "OK")
else
table.insert(parts, "X " .. self.i18n:getText("spu_reason_" .. tostring(validation.reason)))
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
@@ -535,6 +515,7 @@ function SmartPickupFrame:syncOptionsFromModel(adEnv, run)
if group == run.waitPoolGroup then poolIndex = index end
end
sync(self.waitPoolOption, poolIndex)
sync(self.directionRowOption, run.kind == "outbound" and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF)
if run.kind == "outbound" then
sync(self.sellAtOption, SmartPickupFrame.getStepIndex(self.sellAtSteps, run.sellAtPercent, ADRuns.DEFAULT_SELL_AT_PERCENT))
sync(self.storeAboveOption, SmartPickupFrame.getStepIndex(self.storeAboveSteps, run.storeAbovePercent, ADRuns.DEFAULT_STORE_ABOVE_PERCENT))
@@ -588,74 +569,6 @@ function SmartPickupFrame:describeActivity(adEnv, vehicle)
return string.format("%s: %s", label, string.format(self.i18n:getText("spu_activity_driving"), place))
end
-- Rækkerne klones bagest og flyttes derefter forrest i layoutet.
function SmartPickupFrame:fillOverviewRows(adEnv)
local rows = {}
local function add(text)
local title = self:addTextRow(text)
table.insert(rows, title.parent)
return title
end
self.overviewRows = {}
for _, run in ipairs(ADRunsController.store.runs) do
local status = ADRunsController.getRunStatus(adEnv, run)
local statusText = 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)
local header = add(string.format("%s — %s", run.name, statusText))
local entry = {run = run, header = header, vehicles = {}, targets = {}}
for _, vehicleId in ipairs(run.vehicleIds) do
local vehicle = ADRunsController.findVehicleById(adEnv, vehicleId)
if vehicle ~= nil then
table.insert(entry.vehicles, {vehicle = vehicle, title = add(" " .. self:describeActivity(adEnv, vehicle))})
end
end
if run.kind == "outbound" then
entry.outbound = add(" " .. self:describeOutboundOverview(adEnv, run))
else
for _, target in ipairs(ADRunsController.getTargetsLevels(adEnv, run)) do
table.insert(entry.targets, {wayPointId = target.wayPointId, title = add(" " .. self:describeTargetLevels(target))})
end
end
table.insert(self.overviewRows, entry)
end
-- forrest i layoutet: fjern de klonede rækker bagfra og sæt dem ind i rækkefølge først
local elements = self.boxLayout.elements
for index = #rows, 1, -1 do
for position = #elements, 1, -1 do
if elements[position] == rows[index] then
table.remove(elements, position)
break
end
end
table.insert(elements, 1, rows[index])
end
end
-- Opdateres hvert sekund uden genopbygning (kun tekster).
function SmartPickupFrame:refreshOverview(adEnv)
for _, entry in ipairs(self.overviewRows or {}) do
local status = ADRunsController.getRunStatus(adEnv, entry.run)
local statusText = 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)
entry.header:setText(string.format("%s — %s", entry.run.name, statusText))
for _, item in ipairs(entry.vehicles) do
item.title:setText(" " .. self:describeActivity(adEnv, item.vehicle))
end
if entry.outbound ~= nil then
entry.outbound:setText(" " .. self:describeOutboundOverview(adEnv, entry.run))
end
local byId = {}
for _, target in ipairs(ADRunsController.getTargetsLevels(adEnv, entry.run)) do
byId[target.wayPointId] = target
end
for _, item in ipairs(entry.targets) do
if byId[item.wayPointId] ~= nil then
item.title:setText(" " .. self:describeTargetLevels(byId[item.wayPointId]))
end
end
end
end
function SmartPickupFrame:fillPoolRows(adEnv)
if adEnv == nil then
return
@@ -697,7 +610,9 @@ function SmartPickupFrame:refreshLive()
self:setStatusText(self.i18n:getText("spu_status_noAd"))
return
end
self:refreshOverview(adEnv)
if self.currentTab == SmartPickupFrame.TAB_FLOWS then
self:refreshBoard(adEnv)
end
self:refreshStorageRows(adEnv)
local isRunning = false
if run ~= nil then
@@ -754,6 +669,10 @@ function SmartPickupFrame:onClickIngredient(state, element)
return self:onClickIngredientMode(state)
elseif data ~= nil and data.kind == "collectRound" then
return self:onClickCollectRound(state)
elseif data ~= nil and data.kind == "direction" then
return self:onClickDirection(state)
elseif data ~= nil and (data.kind == "sourceBuilding" or data.kind == "targetBuilding") then
return self:onClickBuilding(state, element)
end
self:safe(function(frame)
local run, data = frame:getRun(), frame.rowData[element]
@@ -811,7 +730,11 @@ function SmartPickupFrame:onClickStartStop()
started = started + 1
else
skipped = skipped + 1
table.insert(reasons, string.format("%s: %s", tostring(result.vehicle:getName()), frame.i18n:getText("spu_reason_" .. tostring(result.reason))))
local reasonText = frame.i18n:getText("spu_reason_" .. tostring(result.reason))
if result.reason == "noMarker" and result.missingBuilding ~= nil then
reasonText = string.format(reasonText, tostring(result.missingBuilding))
end
table.insert(reasons, string.format("%s: %s", tostring(result.vehicle:getName()), reasonText))
end
end
frame.statusOverride = string.format(frame.i18n:getText("spu_status_started"), started, skipped)
@@ -839,13 +762,11 @@ function SmartPickupFrame:onNewRunName(value, clickOk)
if not clickOk or value == nil or not value:match("%S") then
return
end
local kind = frame:getTabKind()
local run = ADRunsController.createRun(value, kind)
local run = ADRunsController.createRun(value, "supply")
frame.selectedRunId = run.id
frame.statusOverride = nil
local tab = kind == "outbound" and SmartPickupFrame.TAB_OUTBOUND or SmartPickupFrame.TAB_SUPPLY
frame.currentTab = tab
frame:switchTab(tab)
frame.currentTab = SmartPickupFrame.TAB_FLOWS
frame:switchTab(SmartPickupFrame.TAB_FLOWS)
end)
end