From 9435db929d0732b133a6991fb490ecfc65b6f235 Mon Sep 17 00:00:00 2001 From: masterdraco Date: Tue, 29 Sep 2026 17:43:52 +0200 Subject: [PATCH] =?UTF-8?q?feat(flows):=20Flows-fanen=20som=20farvet=20lis?= =?UTF-8?q?te=20med=20Start/Stop=20pr.=20r=C3=A6kke;=20klik=20=C3=A5bner?= =?UTF-8?q?=20redigeringsvinduet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gui/SmartPickupFlowGuide.lua | 158 ++++++++++++++---- FS25_ADSmartPickup/gui/SmartPickupFlowTab.lua | 1 + FS25_ADSmartPickup/gui/SmartPickupFrame.lua | 17 +- FS25_ADSmartPickup/gui/SmartPickupFrame.xml | 9 + FS25_ADSmartPickup/l10n/l10n_da.xml | 5 + FS25_ADSmartPickup/l10n/l10n_en.xml | 5 + 6 files changed, 143 insertions(+), 52 deletions(-) diff --git a/FS25_ADSmartPickup/gui/SmartPickupFlowGuide.lua b/FS25_ADSmartPickup/gui/SmartPickupFlowGuide.lua index 9348083..7e92103 100644 --- a/FS25_ADSmartPickup/gui/SmartPickupFlowGuide.lua +++ b/FS25_ADSmartPickup/gui/SmartPickupFlowGuide.lua @@ -8,7 +8,8 @@ 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} + -- v1.58: listen har Start/Stop pr. række; Opsæt/Slet ligger i redigeringsvinduet + self.flowButtons = {self.backButtonInfo, self.flowNewButtonInfo} end -- ---- traktor-tekst (også til guidens traktorliste) ---- @@ -160,33 +161,94 @@ end -- Flows: det valgte flow øverst (indstillinger som "ret"-linjer + status), derunder en kort liste til at vælge -- et andet flow. Tavlen med alle flows står i Oversigt (in-game 27/9: de to faner så ens ud). function SmartPickupFrame:fillFlowTabRows(adEnv) - if self:hasGuideOn(SmartPickupFrame.TAB_FLOWS) and self:fillGuideRows(adEnv) then return end - self.overviewRows = {} - local run = self:getRun() - if run == nil then - self:addTextRow(self.i18n:getText("spu_noRuns")) + if not self.editPanelOpen and self:hasGuideOn(SmartPickupFrame.TAB_FLOWS) and self:fillGuideRows(adEnv) then return end + self.flowListRows = {} + local i18n = self.i18n + if #ADRunsController.store.runs == 0 then + self:addTextRow(i18n:getText("spu_noRuns")) return end - self:fillFlowSummary(adEnv, run) - self:addTextRow(self.i18n:getText("spu_flow_pickOther")) + self:addTextRow(i18n:getText("spu_flowList_hint")) for _, group in ipairs(ADFlowView.boardGroups(ADRunsController.store.runs)) do - for _, other in ipairs(group.runs) do - if other.id ~= run.id then - local cells = self:flowCells(adEnv, other) - local otherId = other.id - self:addLinkRow(string.format(" %s — %s", tostring(other.name), tostring(cells[6] or "")), function(frame) - frame.selectedRunId = otherId - frame.statusOverride = nil + self:addTextRow(i18n:getText(group.kind == "outbound" and "spu_board_outbound" or "spu_board_supply")) + for _, run in ipairs(group.runs) do + local row = self:addRow(self.flowListPrefab, {kind = "flowList"}) + local entry = {runId = run.id, row = row, dot = row:getDescendantByName("dot"), + cells = {row:getDescendantByName("c1"), row:getDescendantByName("c2"), row:getDescendantByName("c3"), + row:getDescendantByName("c4"), row:getDescendantByName("c5")}} + local runId = run.id + local actionCell = entry.cells[5] + self:makeRowClickable(row, function(frame) + -- klik på [Start]/[Stop]-feltet = handling (kun dette flow); ellers åbn redigeringsvinduet + if frame.lastClickX ~= nil and actionCell.absPosition ~= nil and frame.lastClickX >= actionCell.absPosition[1] then + frame:toggleRun(frame.getAdEnv(), runId) frame:requestRebuild() - end) - end + else + frame.selectedRunId = runId + frame:openEditPanel("flow", runId) + end + end) + table.insert(self.flowListRows, entry) + end + end + self:refreshFlowListRows(adEnv) +end + +-- Listens celler, prik og statusfarve (hvert sekund og efter opbygning). +function SmartPickupFrame:refreshFlowListRows(adEnv) + local unpackFn = table.unpack or unpack + for _, entry in ipairs(self.flowListRows or {}) do + local run = ADRuns.getRun(ADRunsController.store, entry.runId) + if run ~= nil then + local cells = self:flowCells(adEnv, run) + local color = ADFlowView.LEVEL_COLORS[self:flowLevel(adEnv, run)] + local canStop = ADRunsController.getRunStatus(adEnv, run).canStop + entry.cells[1]:setText(tostring(run.name)) + entry.cells[2]:setText(tostring(cells[2])) + entry.cells[3]:setText(tostring(cells[5])) + entry.cells[4]:setText(tostring(cells[6])) + entry.cells[5]:setText(self.i18n:getText(canStop and "spu_flowList_stop" or "spu_flowList_start")) + if entry.dot ~= nil and entry.dot.setImageColor ~= nil then entry.dot:setImageColor(nil, unpackFn(color)) end + if entry.cells[4].setTextColor ~= nil then entry.cells[4]:setTextColor(unpackFn(color)) end end end end +-- Start/Stop for ét flow (rækkens felt og vinduets knap). Husker om sidste start blev helt afvist (rød). +function SmartPickupFrame:toggleRun(adEnv, runId) + local run = ADRuns.getRun(ADRunsController.store, runId) + if adEnv == nil or run == nil then return end + self.lastStartFailed = self.lastStartFailed or {} + if ADRunsController.getRunStatus(adEnv, run).canStop then + ADRunsController.stopRun(adEnv, run.id) + self.lastStartFailed[run.id] = nil + self.statusOverride = nil + else + local started, skipped, reasons = self:summarizeStartResults(ADRunsController.startRun(adEnv, run.id)) + self.lastStartFailed[run.id] = started == 0 and skipped > 0 + local text = string.format(self.i18n:getText("spu_status_started"), started, skipped) + self:showOverride(text, reasons) + -- statuslinjen kan ligge uden for skærmen: sprunget over vises også som besked i højre side + if skipped > 0 and ADFieldJobs ~= nil and ADFieldJobs.notify ~= nil then + ADFieldJobs.notify(string.format("%s: %s — %s", tostring(run.name), text, table.concat(reasons, "; ")), started == 0) + end + end + ADRunsController.save() +end + +function SmartPickupFrame:flowLevel(adEnv, run) + local row = ADRunsController.getFlowRow(adEnv, run) + local status = ADRunsController.getRunStatus(adEnv, run) + return ADFlowView.flowStatus({running = row.running, total = row.total, stopped = run.stopped == true, + canStop = status.canStop == true, warning = row.warning, reason = row.reason, + lastStartFailed = (self.lastStartFailed or {})[run.id] == true}) +end + function SmartPickupFrame:fillFlowSummary(adEnv, run) local i18n = self.i18n - self:addTextRow(string.format(i18n:getText("spu_guide_flow_section"), tostring(run.name))) + if not self.editPanelOpen then + self:addTextRow(string.format(i18n:getText("spu_guide_flow_section"), tostring(run.name))) + end 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 @@ -199,31 +261,53 @@ function SmartPickupFrame:fillFlowSummary(adEnv, run) end local cells = self:flowCells(adEnv, run) self:addTextRow(" " .. string.format(i18n:getText("spu_field_statusFull"), tostring(cells[6]))) + self:addLinkRow(" " .. i18n:getText("spu_guide_flow_open"), function(frame) + frame.selectedRunId = runId + frame:onClickFlowSetup() + end) end +-- Redigeringsvinduet for et flow (gui/SmartPickupEditPanel.lua). +SmartPickupFrame.EDIT_PANEL_KINDS = SmartPickupFrame.EDIT_PANEL_KINDS or {} +SmartPickupFrame.EDIT_PANEL_KINDS.flow = { + canDelete = true, + exists = function(frame, id) return ADRuns.getRun(ADRunsController.store, id) ~= nil end, + title = function(frame, id) + local run = ADRuns.getRun(ADRunsController.store, id) + return string.format(frame.i18n:getText("spu_panel_flowTitle"), tostring(run ~= nil and run.name or "?")) + end, + fill = function(frame, adEnv, id) + local run = ADRuns.getRun(ADRunsController.store, id) + if run ~= nil then frame:fillFlowSummary(adEnv, run) end + end, + status = function(frame, adEnv, id) + local run = ADRuns.getRun(ADRunsController.store, id) + return {text = tostring(frame:flowCells(adEnv, run)[6]), level = frame:flowLevel(adEnv, run)} + end, + startStopText = function(frame, adEnv, id) + local run = ADRuns.getRun(ADRunsController.store, id) + return frame.i18n:getText(ADRunsController.getRunStatus(adEnv, run).canStop and "spu_button_stop" or "spu_button_start") + end, + startStop = function(frame, id) frame:toggleRun(frame.getAdEnv(), id) end, + delete = function(frame, id) + frame.selectedRunId = id + frame:onClickDelete() + 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 + if not self.editPanelOpen and 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.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) - else - -- tavlen siger allerede "Ingen flows" - self:setStatusText(self.statusOverride or "") - end + return 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 + self:refreshFlowListRows(adEnv) + local running, total = 0, 0 + for _, run in ipairs(ADRunsController.store.runs) do + total = total + 1 + if ADRunsController.getRunStatus(adEnv, run).running > 0 then running = running + 1 end + end + self:setStatusText(self.statusOverride or string.format(self.i18n:getText("spu_flowList_status"), running, total)) end -- ---- hooks til den fælles guide-skærm ---- diff --git a/FS25_ADSmartPickup/gui/SmartPickupFlowTab.lua b/FS25_ADSmartPickup/gui/SmartPickupFlowTab.lua index 112a807..a663e5f 100644 --- a/FS25_ADSmartPickup/gui/SmartPickupFlowTab.lua +++ b/FS25_ADSmartPickup/gui/SmartPickupFlowTab.lua @@ -85,6 +85,7 @@ function SmartPickupFrame:makeRowClickable(row, action) local blockedByPanel = frame.editPanelOpen and layout == frame.boxLayout if not used and not eventUsed and not blockedByPanel and isUp and button == MOUSE_LEFT and (element.getIsVisible == nil or element:getIsVisible()) and isInside(element, posX, posY) and isInside(layout, posX, posY) then + frame.lastClickX = posX frame.pendingClick = action return true end diff --git a/FS25_ADSmartPickup/gui/SmartPickupFrame.lua b/FS25_ADSmartPickup/gui/SmartPickupFrame.lua index 52ca61c..d17f4fa 100644 --- a/FS25_ADSmartPickup/gui/SmartPickupFrame.lua +++ b/FS25_ADSmartPickup/gui/SmartPickupFrame.lua @@ -86,7 +86,7 @@ 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", "fieldPrefab", "kpiPrefab", "alertPrefab", "itemPrefab", "subPrefab"}) do + for _, name in ipairs({"ingredientPrefab", "vehiclePrefab", "textPrefab", "productPrefab", "statPrefab", "gridPrefab", "flowPrefab", "flowListPrefab", "fieldPrefab", "kpiPrefab", "alertPrefab", "itemPrefab", "subPrefab"}) do local prefab = self[name] if prefab ~= nil then prefab:unlinkElement() @@ -785,20 +785,7 @@ function SmartPickupFrame:onClickStartStop() self:safe(function(frame) local adEnv, run = frame.getAdEnv(), frame:getRun() if adEnv == nil or run == nil then return end - if ADRunsController.getRunStatus(adEnv, run).canStop then - ADRunsController.stopRun(adEnv, run.id) - frame.statusOverride = nil - else - local started, skipped, reasons = frame:summarizeStartResults(ADRunsController.startRun(adEnv, run.id)) - local text = string.format(frame.i18n:getText("spu_status_started"), started, skipped) - frame:showOverride(text, reasons) - -- statuslinjen ligger nederst i den rullende liste: sprunget over vises også som besked i højre side - -- (in-game 29/9: Start på Milk Store 'gjorde ingenting' — begge traktorer afvist, grunden sås ikke) - if skipped > 0 and ADFieldJobs ~= nil and ADFieldJobs.notify ~= nil then - ADFieldJobs.notify(string.format("%s: %s — %s", tostring(run.name), text, table.concat(reasons, "; ")), started == 0) - end - end - ADRunsController.save() + frame:toggleRun(adEnv, run.id) frame:requestRebuild() end) end diff --git a/FS25_ADSmartPickup/gui/SmartPickupFrame.xml b/FS25_ADSmartPickup/gui/SmartPickupFrame.xml index d2bcf9c..5ee6a65 100644 --- a/FS25_ADSmartPickup/gui/SmartPickupFrame.xml +++ b/FS25_ADSmartPickup/gui/SmartPickupFrame.xml @@ -89,6 +89,15 @@ + + + + + + + + + diff --git a/FS25_ADSmartPickup/l10n/l10n_da.xml b/FS25_ADSmartPickup/l10n/l10n_da.xml index 0e71106..77c7bef 100644 --- a/FS25_ADSmartPickup/l10n/l10n_da.xml +++ b/FS25_ADSmartPickup/l10n/l10n_da.xml @@ -254,6 +254,11 @@ + + + + + diff --git a/FS25_ADSmartPickup/l10n/l10n_en.xml b/FS25_ADSmartPickup/l10n/l10n_en.xml index d492ba8..a0f8ac0 100644 --- a/FS25_ADSmartPickup/l10n/l10n_en.xml +++ b/FS25_ADSmartPickup/l10n/l10n_en.xml @@ -254,6 +254,11 @@ + + + + +