963 lines
42 KiB
Lua
963 lines
42 KiB
Lua
-- Smart Pickup — ESC-fane
|
||
-- Viser og redigerer runs og starter/stopper dem. Al logik ligger i ADRunsController;
|
||
-- her oversættes kun mellem GUI-elementer og run-felter. Alt kører i pcall så en GUI-fejl
|
||
-- aldrig tager spillet med sig.
|
||
|
||
SmartPickupFrame = {}
|
||
SmartPickupFrame._mt = Class(SmartPickupFrame, TabbedMenuFrameElement)
|
||
|
||
SmartPickupFrame.REFRESH_INTERVAL_MS = 1000
|
||
SmartPickupFrame.STATUS_OVERRIDE_TICKS = 6
|
||
SmartPickupFrame.MAX_STATUS_REASONS = 3
|
||
SmartPickupFrame.LOG_PREFIX = "ADSmartPickup: "
|
||
SmartPickupFrame.STATE_OFF, SmartPickupFrame.STATE_ON = 1, 2
|
||
SmartPickupFrame.TAB_OVERVIEW, SmartPickupFrame.TAB_FLOWS, SmartPickupFrame.TAB_FIELDS, SmartPickupFrame.TAB_MONTH, SmartPickupFrame.TAB_FIELDSILOS = 1, 2, 3, 4, 5
|
||
-- Måned-fanen genopbygges hvert N. sekund (ingen klikbare rækker, så fokus går ikke tabt)
|
||
SmartPickupFrame.MONTH_REBUILD_TICKS = 5
|
||
-- Marksilo-fanen har klikbare valg: genopbygges sjældnere, så fokus ikke rykker midt i et valg
|
||
SmartPickupFrame.FIELDSILO_REBUILD_TICKS = 30
|
||
-- Kæder-fanen (gui/SmartPickupChainTab.lua): klikbare forslag/pause, så genopbygning sjældent (som Marksiloer)
|
||
SmartPickupFrame.TAB_CHAINS = 10
|
||
SmartPickupFrame.CHAIN_REBUILD_TICKS = 30
|
||
-- Lagerfaner: én pr. bygningstype (indeks -> kind i ADSources.getFarmInventory)
|
||
SmartPickupFrame.TAB_NAMES = {"spu_tab_overview", "spu_tab_flows", "spu_tab_fields", "spu_tab_month", "spu_tab_fieldsilos", "spu_tab_factories", "spu_tab_silos", "spu_tab_barns", "spu_tab_sheds", "spu_tab_chains"}
|
||
SmartPickupFrame.TAB_KINDS = {[6] = "factory", [7] = "silo", [8] = "husbandry", [9] = "objectStorage"}
|
||
|
||
function SmartPickupFrame.getTabKind(tab)
|
||
return SmartPickupFrame.TAB_KINDS[tab]
|
||
end
|
||
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, autoloadOn = true}
|
||
|
||
function SmartPickupFrame.new(i18n, getAdEnv)
|
||
local self = SmartPickupFrame:superClass().new(nil, SmartPickupFrame._mt)
|
||
self.name = "SmartPickupFrame"
|
||
self.i18n = i18n
|
||
self.getAdEnv = getAdEnv
|
||
self.selectedRunId = nil
|
||
self.runIds, self.targetIds, self.poolGroups = {}, {}, {}
|
||
self.rowData = {} -- element -> {kind = "ingredient"|"vehicle", ...}
|
||
self.clonedRows = {}
|
||
self.panelRows = {}
|
||
self.refreshTimer = 0
|
||
self.statusOverride = nil
|
||
self.statusRow = nil -- Text-elementet i den klonede statusrække
|
||
self.needsRows = {}
|
||
self.pendingRebuild = false
|
||
self.frameOpen = false
|
||
self.focusLost = false
|
||
self.currentTab = SmartPickupFrame.TAB_OVERVIEW
|
||
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}
|
||
self.newButtonInfo = {inputAction = InputAction.MENU_EXTRA_1, text = i18n:getText("spu_button_new"), callback = function() self:onClickNew() end}
|
||
self.renameButtonInfo = {inputAction = InputAction.MENU_EXTRA_2, text = i18n:getText("spu_button_rename"), callback = function() self:onClickRename() end}
|
||
self.deleteButtonInfo = {inputAction = InputAction.MENU_CANCEL, text = i18n:getText("spu_button_delete"), callback = function() self:onClickDelete() end}
|
||
-- Oversigt: Start/Stop alle i stedet for knapperne der virker på ét valgt flow.
|
||
self.startAllButtonInfo = {inputAction = InputAction.MENU_ACTIVATE, text = i18n:getText("spu_button_startAll"), callback = function() self:onClickStartAll() end}
|
||
self.stopAllButtonInfo = {inputAction = InputAction.MENU_EXTRA_2, text = i18n:getText("spu_button_stopAll"), callback = function() self:onClickStopAll() end}
|
||
self.monthButtons = {self.backButtonInfo}
|
||
-- bygningsfanerne (Siloer/Stalde/Fabrikker/Palleskure): omdøb den valgte bygning
|
||
self.renameBuildingButtonInfo = {inputAction = InputAction.MENU_EXTRA_2, text = i18n:getText("spu_button_renameBuilding"), callback = function() self:onClickRenameBuilding() end}
|
||
self.storageButtons = {self.backButtonInfo, self.renameBuildingButtonInfo}
|
||
self.flowButtons = {self.backButtonInfo, self.startButtonInfo, self.newButtonInfo, self.renameButtonInfo, self.deleteButtonInfo}
|
||
-- Stop alt og parkér: flows + markarbejde + marksilo stoppes, køretøjer til parkering, pause til Start alle
|
||
self.stopParkButtonInfo = {inputAction = InputAction.MENU_CANCEL, text = i18n:getText("spu_button_stopPark"), callback = function() self:onClickStopAndPark() end}
|
||
self.overviewButtons = {self.backButtonInfo, self.startAllButtonInfo, self.stopAllButtonInfo, self.stopParkButtonInfo, self.newButtonInfo}
|
||
-- Marker: Start nu / Stop for den valgte mark
|
||
-- 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)
|
||
self:initEditPanelButtons(i18n)
|
||
-- Egen reference til listen: fallback'en i refreshButtons skal kunne sende den igen.
|
||
self.menuButtonInfo = self.overviewButtons
|
||
self:setMenuButtonInfo(self.menuButtonInfo)
|
||
return self
|
||
end
|
||
|
||
function SmartPickupFrame:delete()
|
||
SmartPickupFrame:superClass().delete(self)
|
||
end
|
||
|
||
function SmartPickupFrame:copyAttributes(src)
|
||
SmartPickupFrame:superClass().copyAttributes(self, src)
|
||
self.i18n, self.getAdEnv = src.i18n, src.getAdEnv
|
||
end
|
||
|
||
-- Prefabs skal ud af layoutet før de klones, ellers vises de selv som rækker.
|
||
function SmartPickupFrame:initialize()
|
||
for _, name in ipairs({"ingredientPrefab", "vehiclePrefab", "textPrefab", "productPrefab", "statPrefab", "gridPrefab", "flowPrefab", "flowListPrefab", "fieldPrefab", "fieldListPrefab", "monthPrefab", "kpiPrefab", "alertPrefab", "itemPrefab", "subPrefab"}) do
|
||
local prefab = self[name]
|
||
if prefab ~= nil then
|
||
prefab:unlinkElement()
|
||
FocusManager:removeElement(prefab)
|
||
end
|
||
end
|
||
if self.selectorPrefab ~= nil and self.subCategoryBox ~= nil and self.subCategoryPaging ~= nil then
|
||
self.selectorPrefab:unlinkElement()
|
||
FocusManager:removeElement(self.selectorPrefab)
|
||
for index, key in ipairs(SmartPickupFrame.TAB_NAMES) do
|
||
self.subCategoryPaging:addText(tostring(index))
|
||
local tab = self.selectorPrefab:clone(self.subCategoryBox)
|
||
FocusManager:loadElementFromCustomValues(tab)
|
||
tab:setText(self.i18n:getText(key))
|
||
local background = tab:getDescendantByName("background")
|
||
if background ~= nil then
|
||
background:setSize(tab.size[1], tab.size[2])
|
||
end
|
||
local tabIndex = index
|
||
tab.onClickCallback = function() self:switchTab(tabIndex) end
|
||
self.subCategoryTabs[index] = tab
|
||
end
|
||
self.subCategoryBox:invalidateLayout()
|
||
self.subCategoryPaging:setSize(self.subCategoryBox.maxFlowSize + 140 * g_pixelSizeScaledX)
|
||
end
|
||
local loopTexts = {self.i18n:getText("spu_loops_infinite")}
|
||
for loops = 1, ADRuns.MAX_LOOPS do
|
||
table.insert(loopTexts, tostring(loops))
|
||
end
|
||
self.loopsOption:setTexts(loopTexts)
|
||
self.returnBelowSteps = {}
|
||
local percentTexts = {}
|
||
for percent = ADRuns.MIN_RETURN_BELOW_PERCENT, ADRuns.MAX_RETURN_BELOW_PERCENT, 10 do
|
||
table.insert(self.returnBelowSteps, percent)
|
||
table.insert(percentTexts, string.format("%d %%", percent))
|
||
end
|
||
self.returnBelowOption:setTexts(percentTexts)
|
||
self.sellAtSteps, self.storeAboveSteps = {}, {}
|
||
local sellTexts, storeTexts = {}, {}
|
||
for percent = ADRuns.MIN_SELL_AT_PERCENT, ADRuns.MAX_SELL_AT_PERCENT, 5 do
|
||
table.insert(self.sellAtSteps, percent)
|
||
table.insert(sellTexts, string.format("%d %%", percent))
|
||
end
|
||
for percent = ADRuns.MIN_STORE_ABOVE_PERCENT, ADRuns.MAX_STORE_ABOVE_PERCENT, 5 do
|
||
table.insert(self.storeAboveSteps, percent)
|
||
table.insert(storeTexts, string.format("%d %%", percent))
|
||
end
|
||
if self.sellAtOption ~= nil then self.sellAtOption:setTexts(sellTexts) end
|
||
if self.storeAboveOption ~= nil then self.storeAboveOption:setTexts(storeTexts) end
|
||
end
|
||
|
||
-- Indeks i en trin-liste for en procent (største trin <= værdien).
|
||
function SmartPickupFrame.getStepIndex(steps, value, default)
|
||
local index = 1
|
||
for position, percent in ipairs(steps or {}) do
|
||
if percent <= (value or default) then
|
||
index = position
|
||
end
|
||
end
|
||
return index
|
||
end
|
||
|
||
|
||
function SmartPickupFrame:getReturnBelowIndex(run)
|
||
local index = 1
|
||
for position, percent in ipairs(self.returnBelowSteps or {}) do
|
||
if percent <= (run.returnBelowPercent or ADRuns.DEFAULT_RETURN_BELOW_PERCENT) then
|
||
index = position
|
||
end
|
||
end
|
||
return index
|
||
end
|
||
|
||
-- FocusManager har skiftet API mellem FS-versioner; her hentes det fokuserede element
|
||
-- så blødt som muligt, fordi det kun bruges til at opdage at fokus lige er slettet.
|
||
function SmartPickupFrame.getFocusedElement()
|
||
if FocusManager == nil then
|
||
return nil
|
||
end
|
||
if FocusManager.getFocusedElement ~= nil then
|
||
local ok, element = pcall(FocusManager.getFocusedElement, FocusManager)
|
||
if ok then
|
||
return element
|
||
end
|
||
end
|
||
local data = FocusManager.currentFocusData
|
||
if type(data) == "table" then
|
||
return data.focusElement
|
||
end
|
||
return nil
|
||
end
|
||
|
||
function SmartPickupFrame.isDescendantOf(element, ancestor)
|
||
while element ~= nil do
|
||
if element == ancestor then
|
||
return true
|
||
end
|
||
element = element.parent
|
||
end
|
||
return false
|
||
end
|
||
|
||
-- rebuild sletter de rækker der kan have fokus (fx vare-rækkerne når Varer skifter til
|
||
-- Auto); uden dette står fokus på et slettet element og tastatur/controller er død.
|
||
function SmartPickupFrame:restoreFocusIfLost()
|
||
if self.focusLost and self.frameOpen and self.boxLayout ~= nil then
|
||
FocusManager:setFocus(self.boxLayout)
|
||
end
|
||
self.focusLost = false
|
||
end
|
||
|
||
function SmartPickupFrame:onFrameOpen()
|
||
SmartPickupFrame:superClass().onFrameOpen(self)
|
||
self.statusOverride = nil
|
||
self.frameOpen = true
|
||
self.pendingRebuild = false
|
||
self:safe(self.rebuild)
|
||
-- Som AutoDrive's egne sider: fokus på selve listen, ikke på en enkelt række.
|
||
self:safe(function(frame)
|
||
FocusManager:setFocus(frame.boxLayout)
|
||
end)
|
||
end
|
||
|
||
function SmartPickupFrame:onFrameClose()
|
||
self.frameOpen = false
|
||
-- et åbent redigeringsvindue og en åben guide kasseres (intet er gemt før [Gem])
|
||
self:hideEditPanel()
|
||
self:closeGuide()
|
||
SmartPickupFrame:superClass().onFrameClose(self)
|
||
end
|
||
|
||
-- Genopbygning sker her og aldrig inde i et klik-callback: sletter man elementet midt i
|
||
-- dets egen klik-håndtering, hopper værdien frem og tilbage og fokus ryger.
|
||
function SmartPickupFrame:update(dt)
|
||
SmartPickupFrame:superClass().update(self, dt)
|
||
if self.pendingClick ~= nil then
|
||
local action = self.pendingClick
|
||
self.pendingClick = nil
|
||
self:safe(action)
|
||
elseif self.pendingRebuild then
|
||
self.pendingRebuild = false
|
||
self:safe(self.rebuild)
|
||
end
|
||
self.refreshTimer = self.refreshTimer + dt
|
||
if self.refreshTimer >= SmartPickupFrame.REFRESH_INTERVAL_MS then
|
||
self.refreshTimer = 0
|
||
self:safe(self.refreshLive)
|
||
end
|
||
end
|
||
|
||
function SmartPickupFrame:safe(fn, ...)
|
||
local ok, err = pcall(fn, self, ...)
|
||
if not ok then
|
||
Logging.warning(SmartPickupFrame.LOG_PREFIX .. "GUI-fejl: %s", tostring(err))
|
||
self.statusOverride = string.format(self.i18n:getText("spu_status_error"), tostring(err))
|
||
self:setStatusText(self.statusOverride)
|
||
end
|
||
end
|
||
|
||
function SmartPickupFrame:setStatusText(text)
|
||
if self.statusRow ~= nil then
|
||
self.statusRow:setText(text)
|
||
end
|
||
end
|
||
|
||
-- ESC-menuen kalder ikke altid update() på siden, så genopbygningen sker straks. De
|
||
-- elementer der udløser den (Run/Mål/Varer-tilstand, knapperne) er statiske og slettes
|
||
-- ikke af rebuild, så det er sikkert; pendingRebuild er kun bagstopper.
|
||
function SmartPickupFrame:requestRebuild()
|
||
self.pendingRebuild = false
|
||
self:safe(self.rebuild)
|
||
end
|
||
|
||
function SmartPickupFrame:switchTab(tabIndex)
|
||
if self.editPanelOpen then
|
||
self:closeGuide()
|
||
self:hideEditPanel()
|
||
end
|
||
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)
|
||
end
|
||
if self.subCategoryPaging ~= nil then
|
||
self.subCategoryPaging:setState(tabIndex, false)
|
||
end
|
||
self:requestRebuild()
|
||
self:safe(function(frame)
|
||
FocusManager:setFocus(frame.boxLayout)
|
||
end)
|
||
end
|
||
|
||
function SmartPickupFrame:onClickTab(state)
|
||
self:switchTab(state)
|
||
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)
|
||
-- 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 = {
|
||
{self.runOption, isFlows},
|
||
{self.waitPoolOption, hasRun},
|
||
{self.loopsOption, isSupply}, {self.returnBelowOption, isSupply},
|
||
{self.sellAtOption, isOutbound}, {self.storeAboveOption, isOutbound},
|
||
}
|
||
for _, entry in ipairs(visibility) do
|
||
local option = entry[1]
|
||
if option ~= nil and option.parent ~= nil then
|
||
option.parent:setVisible(entry[2])
|
||
end
|
||
end
|
||
end
|
||
|
||
-- Samme rækkefølge som tavlen: Ind til bygning først, så Ud fra bygning, hver efter navn.
|
||
function SmartPickupFrame:getRunsForTab()
|
||
if ADFlowView ~= nil then
|
||
return ADFlowView.orderedRuns(ADRunsController.store.runs)
|
||
end
|
||
return ADRunsController.store.runs
|
||
end
|
||
|
||
function SmartPickupFrame:getRun()
|
||
return self.selectedRunId ~= nil and ADRuns.getRun(ADRunsController.store, self.selectedRunId) or nil
|
||
end
|
||
|
||
-- ---- opbygning ----
|
||
|
||
-- addRow melder hver klonet række ind i FocusManager; uden afmelding her ville
|
||
-- FocusManager beholde slettede rækker og fokus-navigationen gå i stå.
|
||
function SmartPickupFrame:clearRows()
|
||
local focused = SmartPickupFrame.getFocusedElement()
|
||
for _, row in ipairs(self.clonedRows) do
|
||
if focused ~= nil and SmartPickupFrame.isDescendantOf(focused, row) then
|
||
self.focusLost = true
|
||
end
|
||
FocusManager:removeElement(row)
|
||
row:delete()
|
||
end
|
||
self.clonedRows, self.rowData = {}, {}
|
||
self.statusRow = nil
|
||
self.needsRows = {}
|
||
self.overviewRows = {}
|
||
self.productRows, self.outboundStatusRows = {}, {}
|
||
self.storageRows = {}
|
||
self.storageDetailRows = {}
|
||
self.itemView = 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
|
||
-- første valg grønt i FS25; klonede rækker virker begge veje). texts = {venstre, højre}.
|
||
function SmartPickupFrame:addToggleRow(kind, title, texts, isOn)
|
||
local row = self:addRow(self.ingredientPrefab, {kind = kind})
|
||
local option = row:getDescendantByName("option")
|
||
option:setTexts(texts)
|
||
option:setState(isOn and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF, false)
|
||
row:getDescendantByName("title"):setText(title)
|
||
return option
|
||
end
|
||
|
||
function SmartPickupFrame:addRow(prefab, data)
|
||
local layout = self.rowTarget or self.boxLayout
|
||
local row = prefab:clone(layout)
|
||
row.spuLayout = layout
|
||
FocusManager:loadElementFromCustomValues(row)
|
||
table.insert(layout == self.boxLayout and self.clonedRows or self.panelRows, row)
|
||
local option = row:getDescendantByName("option")
|
||
if option ~= nil then
|
||
option:setTexts({self.i18n:getText("ui_no"), self.i18n:getText("ui_yes")})
|
||
self.rowData[option] = data
|
||
end
|
||
return row
|
||
end
|
||
|
||
-- Rækker klonet ind i et andet layout (redigeringsvinduet) mens fn kører.
|
||
function SmartPickupFrame:withRowTarget(layout, fn)
|
||
local previous = self.rowTarget
|
||
self.rowTarget = layout
|
||
local ok, err = pcall(fn, self)
|
||
self.rowTarget = previous
|
||
if not ok then error(err, 0) end
|
||
end
|
||
|
||
function SmartPickupFrame:clearPanelRows()
|
||
local focused = SmartPickupFrame.getFocusedElement()
|
||
for _, row in ipairs(self.panelRows or {}) do
|
||
if focused ~= nil and SmartPickupFrame.isDescendantOf(focused, row) then
|
||
self.focusLost = true
|
||
end
|
||
FocusManager:removeElement(row)
|
||
row:delete()
|
||
end
|
||
self.panelRows = {}
|
||
end
|
||
|
||
-- Tekstrække uden valgmuligheder: sektionstitler, Wait-pulje-linjer og statuslinjen.
|
||
-- Tegn pr. tekstrække før teksten ombrydes (rækken afkorter med "..." ved ca. 70 tegn).
|
||
SmartPickupFrame.TEXT_ROW_CHARS = 90
|
||
|
||
-- Lange tekster fordeles på flere rækker i stedet for at blive afkortet. Returnerer første rækkes titel.
|
||
function SmartPickupFrame:addTextRow(text)
|
||
local first = nil
|
||
for _, line in ipairs(ADFlowView.wrapText(text, SmartPickupFrame.TEXT_ROW_CHARS)) do
|
||
local title = self:addRow(self.textPrefab, {kind = "text"}):getDescendantByName("title")
|
||
title:setText(line)
|
||
first = first or title
|
||
end
|
||
return first
|
||
end
|
||
|
||
-- AutoDrive farver hver række i onCreate; her sker det efter hver genopbygning,
|
||
-- fordi rækkerne først findes på det tidspunkt.
|
||
function SmartPickupFrame:colorRows()
|
||
self:colorLayout(self.boxLayout)
|
||
end
|
||
|
||
function SmartPickupFrame:colorLayout(layout)
|
||
local colors = InGameMenuSettingsFrame ~= nil and InGameMenuSettingsFrame.COLOR_ALTERNATING or nil
|
||
if colors == nil or layout == nil then
|
||
return
|
||
end
|
||
local unpackFn = table.unpack or unpack
|
||
local isEvenRow = false
|
||
for _, element in ipairs(layout.elements) do
|
||
if element.setImageColor ~= nil and colors[isEvenRow] ~= nil then
|
||
element:setImageColor(nil, unpackFn(colors[isEvenRow]))
|
||
end
|
||
isEvenRow = not isEvenRow
|
||
end
|
||
end
|
||
|
||
function SmartPickupFrame:rebuild()
|
||
local adEnv = self.getAdEnv()
|
||
local store = ADRunsController.store
|
||
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 run = self:getRun()
|
||
self:setStaticRowsVisible(self.currentTab, run)
|
||
if SmartPickupFrame.getTabKind(self.currentTab) ~= nil then
|
||
if adEnv ~= nil then
|
||
self:fillStorageRows(adEnv)
|
||
end
|
||
self.statusRow = self:addTextRow("")
|
||
self:colorRows()
|
||
self.boxLayout:invalidateLayout()
|
||
self:restoreFocusIfLost()
|
||
self:refreshLive()
|
||
return
|
||
end
|
||
if self.currentTab == SmartPickupFrame.TAB_FIELDS then
|
||
if adEnv ~= nil then
|
||
self:fillFieldRows(adEnv)
|
||
end
|
||
self.statusRow = self:addTextRow("")
|
||
self:colorRows()
|
||
self.boxLayout:invalidateLayout()
|
||
if self.editPanelOpen then self:fillEditPanel(adEnv) end
|
||
self:refreshLive()
|
||
self:restoreFocusIfLost()
|
||
return
|
||
end
|
||
if self.currentTab == SmartPickupFrame.TAB_FIELDSILOS then
|
||
if adEnv ~= nil then
|
||
self:fillFieldSiloRows(adEnv)
|
||
end
|
||
self.monthRebuildTicks = SmartPickupFrame.FIELDSILO_REBUILD_TICKS
|
||
self:colorRows()
|
||
self.boxLayout:invalidateLayout()
|
||
self:refreshButtons()
|
||
self:restoreFocusIfLost()
|
||
return
|
||
end
|
||
if self.currentTab == SmartPickupFrame.TAB_CHAINS then
|
||
if adEnv ~= nil then
|
||
self:fillChainRows(adEnv)
|
||
end
|
||
self.monthRebuildTicks = SmartPickupFrame.CHAIN_REBUILD_TICKS
|
||
self:colorRows()
|
||
self.boxLayout:invalidateLayout()
|
||
self:refreshButtons()
|
||
self:restoreFocusIfLost()
|
||
return
|
||
end
|
||
if self.currentTab == SmartPickupFrame.TAB_MONTH then
|
||
if adEnv ~= nil then
|
||
self:fillMonthRows(adEnv)
|
||
end
|
||
self.monthRebuildTicks = SmartPickupFrame.MONTH_REBUILD_TICKS
|
||
self:colorRows()
|
||
self.boxLayout:invalidateLayout()
|
||
self:refreshButtons()
|
||
self:restoreFocusIfLost()
|
||
return
|
||
end
|
||
if self.currentTab == SmartPickupFrame.TAB_OVERVIEW then
|
||
if adEnv ~= nil then
|
||
self:fillOverviewRows(adEnv)
|
||
end
|
||
self.statusRow = self:addTextRow("")
|
||
self:addTextRow(self.i18n:getText("spu_waitPools"))
|
||
self:fillPoolRows(adEnv)
|
||
self:colorRows()
|
||
self.boxLayout:invalidateLayout()
|
||
self:refreshLive()
|
||
self:restoreFocusIfLost()
|
||
return
|
||
end
|
||
if adEnv ~= nil then
|
||
self:fillFlowTabRows(adEnv)
|
||
end
|
||
self.statusRow = self:addTextRow("")
|
||
self:colorRows()
|
||
self.boxLayout:invalidateLayout()
|
||
if self.editPanelOpen then self:fillEditPanel(adEnv) end
|
||
self:refreshLive()
|
||
self:restoreFocusIfLost()
|
||
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
|
||
return string.format("%s: %s", target.name, self.i18n:getText("spu_needs_none"))
|
||
end
|
||
return string.format("%s: %s", target.name, self:formatLevels(target.levels))
|
||
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)
|
||
local function sync(option, wantedIndex)
|
||
if option ~= nil and wantedIndex ~= nil and SmartPickupFrame.getOptionState(option) ~= wantedIndex then
|
||
option:setState(wantedIndex, false)
|
||
end
|
||
end
|
||
local poolIndex = 1
|
||
for index, group in ipairs(self.poolGroups) do
|
||
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))
|
||
sync(self.collectRoundRowOption, run.collectRound and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF)
|
||
return
|
||
end
|
||
sync(self.ingredientModeRowOption, run.ingredientMode == "manual" and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF)
|
||
sync(self.loopsOption, run.loops + 1)
|
||
sync(self.returnBelowOption, self:getReturnBelowIndex(run))
|
||
end
|
||
|
||
-- "Silage 0/33.750 l · Straw 21.375/21.375 l" — mest trængende først.
|
||
-- Kompakte tal, så 4–5 varer kan stå på én række: 18.0k/27.8k
|
||
function SmartPickupFrame.formatCompact(liters)
|
||
if liters >= 1000000 then
|
||
return string.format("%.1fM", liters / 1000000)
|
||
elseif liters >= 1000 then
|
||
return string.format("%.1fk", liters / 1000)
|
||
end
|
||
return string.format("%d", liters)
|
||
end
|
||
|
||
function SmartPickupFrame:formatLevels(levels)
|
||
local parts = {}
|
||
for _, need in ipairs(levels) do
|
||
local title = g_fillTypeManager.getFillTypeTitleByIndex ~= nil and g_fillTypeManager:getFillTypeTitleByIndex(need.fillType) or g_fillTypeManager:getFillTypeNameByIndex(need.fillType)
|
||
table.insert(parts, string.format("%s %s/%s", tostring(title), SmartPickupFrame.formatCompact(need.level), SmartPickupFrame.formatCompact(need.capacity)))
|
||
end
|
||
return table.concat(parts, " · ")
|
||
end
|
||
|
||
-- ---- overblik (øverst): ét afsnit pr. run — status, traktorernes aktivitet, målets niveauer ----
|
||
|
||
function SmartPickupFrame:describeActivity(adEnv, vehicle)
|
||
local activity = ADRunsController.getVehicleActivity(adEnv, vehicle)
|
||
local label = ADRunsController.getVehicleLabel(adEnv, vehicle)
|
||
local fillTypeName = activity.fillType ~= nil and (g_fillTypeManager.getFillTypeTitleByIndex ~= nil and g_fillTypeManager:getFillTypeTitleByIndex(activity.fillType) or g_fillTypeManager:getFillTypeNameByIndex(activity.fillType)) or "?"
|
||
local place = tostring(activity.place or "?")
|
||
if activity.kind == "stopped" then
|
||
return string.format("%s: %s", label, self.i18n:getText("spu_activity_stopped"))
|
||
elseif activity.kind == "waiting" then
|
||
return string.format("%s: %s", label, string.format(self.i18n:getText("spu_activity_waiting"), place, g_i18n:formatNumber(activity.liters or 0, 0), fillTypeName))
|
||
elseif activity.kind == "loaded" then
|
||
return string.format("%s: %s", label, string.format(self.i18n:getText("spu_activity_loaded"), g_i18n:formatNumber(activity.liters or 0, 0), fillTypeName, place))
|
||
elseif activity.kind == "holding" then
|
||
return string.format("%s: %s", label, string.format(self.i18n:getText("spu_activity_holding"), place, tostring(activity.reason or "")))
|
||
end
|
||
if activity.fillType ~= nil then
|
||
return string.format("%s: %s", label, string.format(self.i18n:getText("spu_activity_empty"), place, fillTypeName))
|
||
end
|
||
return string.format("%s: %s", label, string.format(self.i18n:getText("spu_activity_driving"), place))
|
||
end
|
||
|
||
function SmartPickupFrame:fillPoolRows(adEnv)
|
||
if adEnv == nil then
|
||
return
|
||
end
|
||
local occupied = {}
|
||
for _, claim in ipairs(ADUnloadWait.getClaims()) do
|
||
occupied[claim.marker.group] = occupied[claim.marker.group] or {}
|
||
-- kun løbenummeret ("#31") — fulde navne klippes af i rækken
|
||
local label = ADRunsController.getVehicleLabel(adEnv, claim.vehicle)
|
||
table.insert(occupied[claim.marker.group], string.match(label, "%(#(%d+)%)") and ("#" .. string.match(label, "%(#(%d+)%)")) or label)
|
||
end
|
||
for _, pool in ipairs(ADRunsController.getWaitPools(adEnv)) do
|
||
local names = occupied[pool.group] or {}
|
||
local suffix = #names > 0 and (" (" .. table.concat(names, ", ") .. ")") or ""
|
||
self:addTextRow(string.format(self.i18n:getText("spu_waitPoolRow"), pool.group, pool.count, #names, suffix))
|
||
end
|
||
end
|
||
|
||
-- BinaryOption har :getState() i FS25, men feltet .state i ældre GUI-versioner.
|
||
function SmartPickupFrame.getOptionState(option)
|
||
return option.getState ~= nil and option:getState() or option.state
|
||
end
|
||
|
||
-- setMenuButtonInfoDirty findes i FS22/25's TabbedMenuFrameElement; mangler den,
|
||
-- sendes listen igen. Kaldes hvert sekund, så den må aldrig kaste.
|
||
function SmartPickupFrame:refreshButtons()
|
||
local wanted = self.flowButtons
|
||
if self.editPanelOpen then
|
||
wanted = self.guide ~= nil and self:panelGuideButtons() or self:getPanelButtons()
|
||
elseif 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:getFieldButtons()
|
||
elseif self.currentTab == SmartPickupFrame.TAB_MONTH or self.currentTab == SmartPickupFrame.TAB_FIELDSILOS
|
||
or self.currentTab == SmartPickupFrame.TAB_CHAINS then
|
||
wanted = self.monthButtons
|
||
elseif SmartPickupFrame.getTabKind(self.currentTab) ~= nil then
|
||
wanted = self.storageButtons
|
||
self.renameBuildingButtonInfo.disabled = self.storageDetailPlaceable == nil
|
||
end
|
||
if self.menuButtonInfo ~= wanted then
|
||
self.menuButtonInfo = wanted
|
||
self:setMenuButtonInfo(wanted)
|
||
end
|
||
if self.setMenuButtonInfoDirty ~= nil then
|
||
self:setMenuButtonInfoDirty()
|
||
else
|
||
self:setMenuButtonInfo(self.menuButtonInfo)
|
||
end
|
||
end
|
||
|
||
-- Status + Start/Stop-knappens tekst, kaldes hvert sekund.
|
||
function SmartPickupFrame:refreshLive()
|
||
local adEnv = self.getAdEnv()
|
||
local run = self:getRun()
|
||
if adEnv == nil then
|
||
self:setStatusText(self.i18n:getText("spu_status_noAd"))
|
||
return
|
||
end
|
||
if self.currentTab == SmartPickupFrame.TAB_MONTH or self.currentTab == SmartPickupFrame.TAB_FIELDSILOS
|
||
or self.currentTab == SmartPickupFrame.TAB_CHAINS then
|
||
self.monthRebuildTicks = (self.monthRebuildTicks or 0) - 1
|
||
if self.monthRebuildTicks <= 0 then self:requestRebuild() end
|
||
self:refreshButtons()
|
||
return
|
||
end
|
||
local isOverview = self.currentTab == SmartPickupFrame.TAB_OVERVIEW
|
||
if isOverview then
|
||
self:refreshOverview(adEnv)
|
||
end
|
||
if self.editPanelOpen then self:refreshEditPanel(adEnv) end
|
||
if self.currentTab == SmartPickupFrame.TAB_FIELDS then
|
||
self:refreshFieldRows(adEnv)
|
||
self.statusOverrideTicks = (self.statusOverrideTicks or 0) - 1
|
||
if self.statusOverrideTicks <= 0 then self.statusOverride = nil end
|
||
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
|
||
local running, total, activeRuns = 0, 0, 0
|
||
for _, anyRun in ipairs(ADRunsController.store.runs) do
|
||
local status = ADRunsController.getRunStatus(adEnv, anyRun)
|
||
running, total = running + status.running, total + status.total
|
||
if status.running > 0 then activeRuns = activeRuns + 1 end
|
||
end
|
||
local statusText = string.format(self.i18n:getText("spu_status_overview"), running, total, activeRuns, #ADRunsController.store.runs)
|
||
local queued = #(ADRunsController.startQueue or {})
|
||
if queued > 0 then
|
||
local totalQueued = ADRunsController.startQueueTotal or queued
|
||
statusText = string.format(self.i18n:getText("spu_status_starting"), totalQueued - queued, totalQueued)
|
||
elseif ADFieldJobs ~= nil and ADFieldJobs.state ~= nil and ADFieldJobs.state.paused then
|
||
statusText = self.i18n:getText("spu_status_paused")
|
||
end
|
||
self:setStatusText(self.statusOverride or statusText)
|
||
self.stopAllButtonInfo.disabled = running == 0
|
||
elseif SmartPickupFrame.getTabKind(self.currentTab) ~= nil then
|
||
-- lagerfanerne: ingen flow-status (in-game 29/9: 'Stoppet (1 traktorer)' fra det sidst valgte flow)
|
||
self:setStatusText(self.statusOverride or "")
|
||
elseif run ~= nil then
|
||
self:syncOptionsFromModel(adEnv, run)
|
||
if run.kind == "outbound" then
|
||
self:refreshOutboundRows(adEnv, run)
|
||
else
|
||
self:refreshNeedsRows(adEnv, run)
|
||
end
|
||
local status = ADRunsController.getRunStatus(adEnv, run)
|
||
isRunning = status.canStop == 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)
|
||
for option, data in pairs(self.rowData) do
|
||
-- kun run'ets egne traktorer opdateres live (alle valideres ved rebuild)
|
||
local isInRun = SmartPickupFrame.getOptionState(option) == SmartPickupFrame.STATE_ON
|
||
if data.kind == "vehicle" and data.row ~= nil and isInRun then
|
||
data.row:getDescendantByName("title"):setText(self:describeVehicle(adEnv, run, data.vehicle, true))
|
||
end
|
||
end
|
||
else
|
||
self:setStatusText(self.statusOverride or self.i18n:getText("spu_noRuns"))
|
||
end
|
||
-- Engangsbesked ("Startet 2, sprunget over 1: …", "flyttet fra ..."): står i
|
||
-- STATUS_OVERRIDE_TICKS opdateringer (sekunder), så man når at læse hvorfor.
|
||
self.statusOverrideTicks = (self.statusOverrideTicks or 0) - 1
|
||
if self.statusOverrideTicks <= 0 then
|
||
self.statusOverride = nil
|
||
end
|
||
self.startButtonInfo.text = self.i18n:getText(isRunning and "spu_button_stop" or "spu_button_start")
|
||
self.startButtonInfo.disabled = run == nil
|
||
self.renameButtonInfo.disabled = run == nil
|
||
self.deleteButtonInfo.disabled = run == nil
|
||
self:refreshButtons()
|
||
end
|
||
|
||
-- ---- callbacks fra XML (state = 1-baseret indeks; element = det klikkede element) ----
|
||
|
||
function SmartPickupFrame:onClickRun(state)
|
||
self.selectedRunId = self.runIds[state]
|
||
self.statusOverride = nil
|
||
self:requestRebuild()
|
||
end
|
||
|
||
function SmartPickupFrame:onClickIngredient(state, element)
|
||
-- guiderne og markflåden deler prefab (og dermed onClick) med vare-rækkerne
|
||
local data = self.rowData[element]
|
||
if data ~= nil and data.kind == "guideRow" then
|
||
return self:onClickGuideRow(state, data)
|
||
elseif data ~= nil and SmartPickupFrame.FIELDSILO_ROW_KINDS ~= nil and SmartPickupFrame.FIELDSILO_ROW_KINDS[data.kind] then
|
||
return self:onClickFieldSiloRow(state, data)
|
||
elseif data ~= nil and SmartPickupFrame.FIELD_ROW_KINDS[data.kind] then
|
||
return self:onClickFieldRow(state, data)
|
||
end
|
||
self:safe(function(frame)
|
||
local run, data = frame:getRun(), frame.rowData[element]
|
||
if run == nil or data == nil or data.kind ~= "ingredient" then return end
|
||
local names = {}
|
||
for _, name in ipairs(run.ingredients) do
|
||
if name ~= data.name then table.insert(names, name) end
|
||
end
|
||
if state == SmartPickupFrame.STATE_ON then
|
||
table.insert(names, data.name)
|
||
end
|
||
ADRunsController.updateRun(run.id, {ingredients = names})
|
||
end)
|
||
end
|
||
|
||
function SmartPickupFrame:onClickWaitPool(state)
|
||
self:safe(function(frame)
|
||
local run = frame:getRun()
|
||
if run == nil then return end
|
||
ADRunsController.updateRun(run.id, {waitPoolGroup = frame.poolGroups[state] or ""})
|
||
end)
|
||
end
|
||
|
||
function SmartPickupFrame:onClickVehicle(state, element)
|
||
local clicked = self.rowData[element]
|
||
-- markfanens maskinrækker (markflåden og markens faste maskiner) bruger samme række-type som flowets
|
||
-- traktorliste; de hører til markfanen (fieldRig blev før behandlet som flow-traktor og aldrig gemt)
|
||
if clicked ~= nil and clicked.kind == "fleetVehicle" 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
|
||
if run == nil or data == nil or data.locked or data.vehicle == nil then return end
|
||
if state == SmartPickupFrame.STATE_ON then
|
||
local previousRunId = ADRunsController.assignVehicle(run.id, data.vehicle)
|
||
if previousRunId ~= nil then
|
||
local previous = ADRuns.getRun(ADRunsController.store, previousRunId)
|
||
frame.statusOverride = string.format(frame.i18n:getText("spu_movedFrom"), previous ~= nil and previous.name or tostring(previousRunId))
|
||
frame.statusOverrideTicks = SmartPickupFrame.STATUS_OVERRIDE_TICKS
|
||
end
|
||
else
|
||
ADRunsController.unassignVehicle(data.vehicle)
|
||
end
|
||
frame:refreshLive()
|
||
end)
|
||
end
|
||
|
||
-- ---- knapper i bundlinjen ----
|
||
|
||
function SmartPickupFrame:onClickStartStop()
|
||
self:safe(function(frame)
|
||
local adEnv, run = frame.getAdEnv(), frame:getRun()
|
||
if adEnv == nil or run == nil then return end
|
||
frame:toggleRun(adEnv, run.id)
|
||
frame:requestRebuild()
|
||
end)
|
||
end
|
||
|
||
-- Start-resultater -> antal startet/sprunget over + "Traktor: grund"-liste til statuslinjen.
|
||
function SmartPickupFrame:summarizeStartResults(results)
|
||
local started, skipped, reasons = 0, 0, {}
|
||
for _, result in ipairs(results) do
|
||
if result.ok then
|
||
started = started + 1
|
||
else
|
||
skipped = skipped + 1
|
||
local reasonText = self.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(ADRuns.vehicleLabel(result.vehicle)), reasonText))
|
||
end
|
||
end
|
||
return started, skipped, reasons
|
||
end
|
||
|
||
function SmartPickupFrame:showOverride(text, reasons)
|
||
if reasons ~= nil and #reasons > 0 then
|
||
-- én statuslinje: højst MAX_STATUS_REASONS grunde, resten står i log.txt
|
||
local shown = {}
|
||
for index = 1, math.min(#reasons, SmartPickupFrame.MAX_STATUS_REASONS) do shown[index] = reasons[index] end
|
||
text = text .. " — " .. table.concat(shown, "; ")
|
||
if #reasons > #shown then text = text .. string.format(" (+%d)", #reasons - #shown) end
|
||
end
|
||
self.statusOverride = text
|
||
self.statusOverrideTicks = SmartPickupFrame.STATUS_OVERRIDE_TICKS
|
||
self:setStatusText(text)
|
||
end
|
||
|
||
function SmartPickupFrame:onClickStartAll()
|
||
self:safe(function(frame)
|
||
local adEnv = frame.getAdEnv()
|
||
if adEnv == nil then return end
|
||
-- pausen (Stop alt og parkér) ophæves; traktorerne startes én ad gangen med mellemrum
|
||
if ADFieldJobs ~= nil and ADFieldJobs.state ~= nil and ADFieldJobs.state.paused then ADFieldJobs.setPaused(false) end
|
||
local summary = ADRunsController.queueStartAll(adEnv)
|
||
local _, skipped, reasons = frame:summarizeStartResults(summary.skipped)
|
||
Logging.info(SmartPickupFrame.LOG_PREFIX .. "Start alle: %d traktorer i kø (én hvert %d. sekund), %d flows kørte allerede, %d sprunget over",
|
||
summary.queued, math.floor(ADRunsController.STAGGER_MS / 1000), summary.alreadyRunning, skipped)
|
||
frame:showOverride(string.format(frame.i18n:getText("spu_status_queuedAll"), summary.queued, math.floor(ADRunsController.STAGGER_MS / 1000), summary.alreadyRunning, skipped), reasons)
|
||
ADRunsController.save()
|
||
frame:requestRebuild()
|
||
end)
|
||
end
|
||
|
||
function SmartPickupFrame:onClickStopAndPark()
|
||
self:safe(function(frame)
|
||
local adEnv = frame.getAdEnv()
|
||
if adEnv == nil then return end
|
||
local summary = ADRunsController.stopAllAndPark(adEnv)
|
||
local text = string.format(frame.i18n:getText("spu_status_stopParked"), summary.stopped, summary.parked)
|
||
local notes = {}
|
||
if #summary.noPark > 0 then table.insert(notes, string.format(frame.i18n:getText("spu_status_noPark"), table.concat(summary.noPark, ", "))) end
|
||
if #summary.manual > 0 then table.insert(notes, string.format(frame.i18n:getText("spu_status_fetchManual"), table.concat(summary.manual, ", "))) end
|
||
frame:showOverride(text, notes)
|
||
ADRunsController.save()
|
||
frame:requestRebuild()
|
||
end)
|
||
end
|
||
|
||
function SmartPickupFrame:onClickStopAll()
|
||
self:safe(function(frame)
|
||
local adEnv = frame.getAdEnv()
|
||
if adEnv == nil then return end
|
||
local stopped = ADRunsController.stopAllRuns(adEnv)
|
||
Logging.info(SmartPickupFrame.LOG_PREFIX .. "Stop alle: %d traktorer stoppet", stopped)
|
||
frame:showOverride(string.format(frame.i18n:getText("spu_status_stoppedAll"), stopped))
|
||
ADRunsController.save()
|
||
frame:requestRebuild()
|
||
end)
|
||
end
|
||
|
||
-- Klik på en række i Oversigt: vælg flowet og hop til fanen Flows (kaldes fra update, aldrig inde i
|
||
-- rækkens eget mouseEvent — rækken slettes af genopbygningen).
|
||
function SmartPickupFrame:openFlow(runId)
|
||
if ADRuns.getRun(ADRunsController.store, runId) == nil then return end
|
||
self.selectedRunId = runId
|
||
self.statusOverride = nil
|
||
self:switchTab(SmartPickupFrame.TAB_FLOWS)
|
||
end
|
||
|
||
-- Nyt flow: guiden "Opsæt flow" (gui/SmartPickupFlowGuide.lua) — intet oprettes før [Gem].
|
||
function SmartPickupFrame:onClickNew()
|
||
self:onClickFlowNew()
|
||
end
|
||
|
||
-- Omdøb den valgte bygning i en bygningsfane (gemmes i ADSmartPickup_names.xml; tomt = butiksnavnet igen)
|
||
function SmartPickupFrame:onClickRenameBuilding()
|
||
self:safe(function(frame)
|
||
local placeable = frame.storageDetailPlaceable
|
||
if placeable == nil then return end
|
||
frame.renamingBuildingId = ADBuildings.getId(placeable)
|
||
local current = ADNames.forPlaceable(placeable) or (placeable.getName ~= nil and placeable:getName()) or ""
|
||
TextInputDialog.show(SmartPickupFrame.onRenameBuildingResult, frame, tostring(current), frame.i18n:getText("spu_renameBuildingTitle"), nil, 40, g_i18n:getText("button_ok"))
|
||
end)
|
||
end
|
||
|
||
function SmartPickupFrame:onRenameBuildingResult(value, clickOk)
|
||
self:safe(function(frame)
|
||
if not clickOk or frame.renamingBuildingId == nil then return end
|
||
ADNames.set(frame.renamingBuildingId, value)
|
||
frame.renamingBuildingId = nil
|
||
frame:requestRebuild()
|
||
end)
|
||
end
|
||
|
||
function SmartPickupFrame:onClickRename()
|
||
-- Dialogen kan kaste (fx manglende i18n-nøgle) — fang det som resten af GUI'et, i stedet
|
||
-- for at lade fejlen undslippe klik-callbacken uden statuslinje-besked.
|
||
self:safe(function(frame)
|
||
local run = frame:getRun()
|
||
if run == nil then return end
|
||
TextInputDialog.show(SmartPickupFrame.onRenameResult, frame, run.name, frame.i18n:getText("spu_renameTitle"), nil, 30, g_i18n:getText("button_ok"))
|
||
end)
|
||
end
|
||
|
||
function SmartPickupFrame:onRenameResult(value, clickOk)
|
||
self:safe(function(frame)
|
||
local run = frame:getRun()
|
||
if clickOk and run ~= nil and value ~= nil and value:match("%S") then
|
||
ADRunsController.updateRun(run.id, {name = value})
|
||
frame:requestRebuild()
|
||
end
|
||
end)
|
||
end
|
||
|
||
function SmartPickupFrame:onClickDelete()
|
||
-- Samme begrundelse som onClickRename: dialog-opkaldet skal ikke kunne undslippe uden om safe().
|
||
self:safe(function(frame)
|
||
local run = frame:getRun()
|
||
if run == nil then return end
|
||
YesNoDialog.show(SmartPickupFrame.onDeleteResult, frame, string.format(frame.i18n:getText("spu_deleteConfirm"), run.name), frame.i18n:getText("spu_button_delete"))
|
||
end)
|
||
end
|
||
|
||
function SmartPickupFrame:onDeleteResult(yes)
|
||
self:safe(function(frame)
|
||
local run = frame:getRun()
|
||
if yes and run ~= nil then
|
||
ADRunsController.deleteRun(run.id, frame.getAdEnv())
|
||
frame.selectedRunId = nil
|
||
frame:requestRebuild()
|
||
end
|
||
end)
|
||
end
|