From f64959e2c3e97d3108168fed54816b6bce8ef54a Mon Sep 17 00:00:00 2001 From: masterdraco Date: Tue, 29 Sep 2026 17:52:23 +0200 Subject: [PATCH] =?UTF-8?q?fix(gui):=20review=20=E2=80=94=20vinduets=20pla?= =?UTF-8?q?cering=20(st=C3=B8rrelse=20f=C3=B8r=20position,=20genanvendes?= =?UTF-8?q?=20hvert=20sekund,=20profil=20uden=20midt-anker),=20fokus=20ved?= =?UTF-8?q?=20sletning=20af=20vinduets=20r=C3=A6kker,=20ESC=20via=20reques?= =?UTF-8?q?tClose,=20[Start]=20kr=C3=A6ver=20mark=C3=B8r,=20for=C3=A6ldet?= =?UTF-8?q?=20r=C3=B8d=20status,=20markvindue=20uden=20Slet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FS25_ADSmartPickup/adFieldView.lua | 5 ++ .../gui/SmartPickupEditPanel.lua | 59 +++++++++++++++---- .../gui/SmartPickupFieldTab.lua | 11 +++- .../gui/SmartPickupFlowGuide.lua | 2 + FS25_ADSmartPickup/gui/SmartPickupFrame.lua | 6 +- FS25_ADSmartPickup/gui/guiProfiles.xml | 7 ++- tests/test_fieldStatus.lua | 4 ++ 7 files changed, 79 insertions(+), 15 deletions(-) diff --git a/FS25_ADSmartPickup/adFieldView.lua b/FS25_ADSmartPickup/adFieldView.lua index f2398e4..5de24bc 100644 --- a/FS25_ADSmartPickup/adFieldView.lua +++ b/FS25_ADSmartPickup/adFieldView.lua @@ -97,3 +97,8 @@ function ADFieldView.fieldStatus(s) if s.reasonKey ~= nil then return "waiting" end return "stopped" end + +-- Må [Start]/[Stop] trykkes? Stop altid når marken arbejder; Start kræver en markør. +function ADFieldView.canStart(s) + return s.working == true or s.hasMarker == true +end diff --git a/FS25_ADSmartPickup/gui/SmartPickupEditPanel.lua b/FS25_ADSmartPickup/gui/SmartPickupEditPanel.lua index 4453530..3be64c7 100644 --- a/FS25_ADSmartPickup/gui/SmartPickupEditPanel.lua +++ b/FS25_ADSmartPickup/gui/SmartPickupEditPanel.lua @@ -14,9 +14,16 @@ function SmartPickupFrame:initEditPanelButtons(i18n) self.panelStartButtonInfo = {inputAction = InputAction.MENU_ACTIVATE, text = i18n:getText("spu_button_start"), callback = function() self:onClickPanelStartStop() end} self.panelDeleteButtonInfo = {inputAction = InputAction.MENU_CANCEL, text = i18n:getText("spu_button_delete"), callback = function() self:onClickPanelDelete() end} self.panelButtons = {self.panelCloseButtonInfo, self.panelStartButtonInfo, self.panelDeleteButtonInfo} + self.panelButtonsNoDelete = {self.panelCloseButtonInfo, self.panelStartButtonInfo} self.panelGuideButtonCache = setmetatable({}, {__mode = "k"}) end +-- Vinduets knaplinje (uden Slet for arter der ikke kan slettes). +function SmartPickupFrame:getPanelButtons() + local hooks = self:editPanelHooks() + return (hooks ~= nil and hooks.canDelete) and self.panelButtons or self.panelButtonsNoDelete +end + function SmartPickupFrame:editPanelHooks() return self.editPanelOpen and SmartPickupFrame.EDIT_PANEL_KINDS[self.editPanelKind] or nil end @@ -35,23 +42,33 @@ function SmartPickupFrame:panelGuideButtons() return cached end --- Vinduet dækker listens flade; panelet er centreret i den (absolutte koordinater, y opad). +-- Sæt størrelse FØR position: setSize kan genberegne den absolutte position ud fra forælderen (review 29/9). +-- -> true hvis elementet flyttede sig. +local function place(element, x, y, w, h) + if w ~= nil then element:setSize(w, h) end + local pos = element.absPosition + local moved = pos == nil or math.abs(pos[1] - x) > 1e-6 or math.abs(pos[2] - y) > 1e-6 + element:setAbsolutePosition(x, y) + return moved +end + +-- Vinduet dækker listens flade; panelet er centreret i den (absolutte koordinater, y opad). Kaldes ved åbning, +-- ved hver opbygning og hvert sekund, så en layout-gennemgang i menuen ikke flytter det væk. function SmartPickupFrame:layoutEditPanel() local box = self.boxLayout if box == nil or box.absPosition == nil or box.absSize == nil then return end local x, y, w, h = box.absPosition[1], box.absPosition[2], box.absSize[1], box.absSize[2] - self.editBackdrop:setAbsolutePosition(x, y) - self.editBackdrop:setSize(w, h) + place(self.editBackdrop, x, y, w, h) local pw, ph = w * SmartPickupFrame.EDIT_PANEL_WIDTH, h * SmartPickupFrame.EDIT_PANEL_HEIGHT local px, py = x + (w - pw) / 2, y + (h - ph) / 2 - self.editPanel:setAbsolutePosition(px, py) - self.editPanel:setSize(pw, ph) + place(self.editPanel, px, py, pw, ph) local header = SmartPickupFrame.EDIT_PANEL_HEADER_PX * g_pixelSizeScaledY local margin = 20 * g_pixelSizeScaledX - self.editTitle:setAbsolutePosition(px + margin, py + ph - header * 0.45) - self.editStatus:setAbsolutePosition(px + margin, py + ph - header * 0.85) - self.editLayout:setAbsolutePosition(px, py) - self.editLayout:setSize(pw, ph - header) + place(self.editTitle, px + margin, py + ph - header * 0.45) + place(self.editStatus, px + margin, py + ph - header * 0.85) + if place(self.editLayout, px, py, pw, ph - header) then + self.editLayout:invalidateLayout() + end end function SmartPickupFrame:openEditPanel(kind, id) @@ -108,9 +125,12 @@ function SmartPickupFrame:refreshEditPanel(adEnv) local hooks = self:editPanelHooks() if hooks == nil or adEnv == nil then return end if not hooks.exists(self, self.editPanelId) then + self.statusOverride = self.i18n:getText("spu_panel_gone") + self.statusOverrideTicks = SmartPickupFrame.STATUS_OVERRIDE_TICKS self:closeEditPanel() return end + self:layoutEditPanel() local status = hooks.status(self, adEnv, self.editPanelId) self.editStatus:setText(tostring(status.text or "")) local color = ADFlowView.LEVEL_COLORS[status.level] or ADFlowView.LEVEL_COLORS.stopped @@ -118,10 +138,29 @@ function SmartPickupFrame:refreshEditPanel(adEnv) self.editStatus:setTextColor(color[1], color[2], color[3], color[4]) end self.panelStartButtonInfo.text = hooks.startStopText(self, adEnv, self.editPanelId) - self.panelDeleteButtonInfo.disabled = not hooks.canDelete + self.panelStartButtonInfo.disabled = hooks.canStart ~= nil and not hooks.canStart(self, self.editPanelId) +end + +-- ESC mens vinduet er åbent: menuen spørger requestClose; vinduet lukkes (trin først), menuen bliver. +-- Kalder spillet OGSÅ knappens callback for samme tryk, må det ikke lukke to trin (panelClosedAt). +SmartPickupFrame.PANEL_ESC_DEBOUNCE_MS = 250 + +function SmartPickupFrame:requestClose(callback) + if self.editPanelOpen then + self:onClickPanelClose() + return false + end + if g_time ~= nil and self.panelClosedAt ~= nil and g_time - self.panelClosedAt < SmartPickupFrame.PANEL_ESC_DEBOUNCE_MS then + return false + end + return SmartPickupFrame:superClass().requestClose(self, callback) end function SmartPickupFrame:onClickPanelClose() + if g_time ~= nil and self.panelClosedAt ~= nil and g_time - self.panelClosedAt < SmartPickupFrame.PANEL_ESC_DEBOUNCE_MS then + return + end + self.panelClosedAt = g_time self:safe(function(frame) -- et åbent [Edit]-trin lukkes først (kladden kasseres som ved Annullér) if frame.guide ~= nil then diff --git a/FS25_ADSmartPickup/gui/SmartPickupFieldTab.lua b/FS25_ADSmartPickup/gui/SmartPickupFieldTab.lua index 132b642..c94bf29 100644 --- a/FS25_ADSmartPickup/gui/SmartPickupFieldTab.lua +++ b/FS25_ADSmartPickup/gui/SmartPickupFieldTab.lua @@ -168,6 +168,14 @@ function SmartPickupFrame:refreshFieldLevels() end end +-- [Start] kræver en markør (Stop/Overtag altid muligt når marken arbejder). +function SmartPickupFrame:fieldCanStart(id) + local field, info = ADFieldJobs.getField(id), ADFields.getInfo(id) + if field == nil or info == nil then return false end + return ADFieldView.canStart({hasMarker = info.markerId ~= nil, + working = ADFieldModel.isWorking(field) or ADFieldJobs.awaitingPlayer(id) ~= nil}) +end + function SmartPickupFrame:fieldLevel(id) local field, info = ADFieldJobs.getField(id), ADFields.getInfo(id) if field == nil or info == nil then return "stopped" end @@ -371,7 +379,7 @@ end -- Start/Stop/Overtag for én mark (rækkens felt, vinduets knap og knaplinjen). function SmartPickupFrame:toggleField(id) self:safe(function(frame) - if id == nil then return end + if id == nil or not frame:fieldCanStart(id) then return end local field = ADFieldJobs.getField(id) if ADFieldJobs.awaitingPlayer(id) ~= nil then -- manuel transport: overtag nu (skærebordet tjekkes stadig) @@ -411,5 +419,6 @@ SmartPickupFrame.EDIT_PANEL_KINDS.field = { end, startStopText = function(frame, adEnv, id) return frame:fieldActionText(id, true) end, startStop = function(frame, id) frame:toggleField(id) end, + canStart = function(frame, id) return frame:fieldCanStart(id) end, delete = function() end, } diff --git a/FS25_ADSmartPickup/gui/SmartPickupFlowGuide.lua b/FS25_ADSmartPickup/gui/SmartPickupFlowGuide.lua index 7e92103..e74d934 100644 --- a/FS25_ADSmartPickup/gui/SmartPickupFlowGuide.lua +++ b/FS25_ADSmartPickup/gui/SmartPickupFlowGuide.lua @@ -239,6 +239,8 @@ end function SmartPickupFrame:flowLevel(adEnv, run) local row = ADRunsController.getFlowRow(adEnv, run) local status = ADRunsController.getRunStatus(adEnv, run) + -- en gammel afvisning gælder ikke længere når flowet kører (fx startet fra Oversigt bagefter) + if row.running > 0 and self.lastStartFailed ~= nil then self.lastStartFailed[run.id] = nil end 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}) diff --git a/FS25_ADSmartPickup/gui/SmartPickupFrame.lua b/FS25_ADSmartPickup/gui/SmartPickupFrame.lua index c1b8212..a38cff1 100644 --- a/FS25_ADSmartPickup/gui/SmartPickupFrame.lua +++ b/FS25_ADSmartPickup/gui/SmartPickupFrame.lua @@ -376,7 +376,11 @@ function SmartPickupFrame:withRowTarget(layout, fn) 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 @@ -600,7 +604,7 @@ end function SmartPickupFrame:refreshButtons() local wanted = self.flowButtons if self.editPanelOpen then - wanted = self.guide ~= nil and self:panelGuideButtons() or self.panelButtons + 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 diff --git a/FS25_ADSmartPickup/gui/guiProfiles.xml b/FS25_ADSmartPickup/gui/guiProfiles.xml index 883a2f8..0e9873d 100644 --- a/FS25_ADSmartPickup/gui/guiProfiles.xml +++ b/FS25_ADSmartPickup/gui/guiProfiles.xml @@ -54,13 +54,14 @@ - + + + - + - diff --git a/tests/test_fieldStatus.lua b/tests/test_fieldStatus.lua index 456a430..ad7cdbd 100644 --- a/tests/test_fieldStatus.lua +++ b/tests/test_fieldStatus.lua @@ -18,5 +18,9 @@ check("regn", V.fieldStatus({hasMarker = true, working = true, reasonKey = "spu_ check("venter på spilleren (høster)", V.fieldStatus({hasMarker = true, awaiting = true}), "waiting") check("start bestilt", V.fieldStatus({hasMarker = true, startRequested = true}), "waiting") check("i ro", V.fieldStatus({hasMarker = true}), "stopped") +-- Start må ikke bestilles på en mark uden markør (knappen var før deaktiveret; review 29/9) +check("kan starte: med markør", V.canStart({hasMarker = true, working = false}), true) +check("kan starte: uden markør -> nej", V.canStart({hasMarker = false, working = false}), false) +check("kan stoppe: uden markør men i gang", V.canStart({hasMarker = false, working = true}), true) print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) os.exit(failures == 0 and 0 or 1)