Instant preset switch, silent lock, fractional zoom

- Preset combobox now loads preset instantly on selection (no OK needed)
- Lock file silently prevents duplicate instances (no alert popup)
- Zoom supports fractional levels (0.125x, 0.25x, 0.5x) for large tilesets
- All zoom handlers use zoomStep() with predefined level table
This commit is contained in:
Cidwel Highwind 2026-04-03 21:16:07 +02:00
parent 673e114753
commit c6b4ff17e1
1 changed files with 38 additions and 24 deletions

View File

@ -618,6 +618,23 @@ initPresets()
---------------------------------------------------------------------- ----------------------------------------------------------------------
-- Helpers -- Helpers
---------------------------------------------------------------------- ----------------------------------------------------------------------
-- Zoom levels: fractional for large tilesets, integer for normal
local ZOOM_LEVELS = { 0.125, 0.25, 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
local function zoomStep(currentZoom, delta)
-- Find closest level
local bestIdx = 1
local bestDist = math.huge
for i, z in ipairs(ZOOM_LEVELS) do
local dist = math.abs(z - currentZoom)
if dist < bestDist then bestDist = dist; bestIdx = i end
end
local newIdx = bestIdx + delta
if newIdx < 1 then newIdx = 1 end
if newIdx > #ZOOM_LEVELS then newIdx = #ZOOM_LEVELS end
return ZOOM_LEVELS[newIdx]
end
local function clamp(v, lo, hi) local function clamp(v, lo, hi)
return math.max(lo, math.min(hi, v)) return math.max(lo, math.min(hi, v))
end end
@ -1629,7 +1646,22 @@ openMainDialog = function()
-- Presets section -- Presets section
-------------------------------------------------------- --------------------------------------------------------
d:separator{ text = "Presets" } d:separator{ text = "Presets" }
d:combobox{ id = "presetSelect", option = S.currentPreset, options = getAllPresetNames() } d:combobox{ id = "presetSelect", option = S.currentPreset, options = getAllPresetNames(),
onchange = function()
local selected = d.data.presetSelect
if selected and selected ~= S.currentPreset then
savePreset(S.currentPreset)
loadPreset(selected)
S.currentPreset = selected
local currentFile = app.sprite and app.sprite.filename or ""
if currentFile ~= "" then filePresetMap[currentFile] = selected end
saveMaster()
d:close()
if mainDlg then pcall(function() mainDlg:close() end) end
openMainDialog()
end
end
}
d:button{ id = "presetNew", text = "New", onclick = function() d:button{ id = "presetNew", text = "New", onclick = function()
local nd = Dialog{ title = "New Preset" } local nd = Dialog{ title = "New Preset" }
nd:entry{ id = "name", label = "Name:", text = "" } nd:entry{ id = "name", label = "Name:", text = "" }
@ -1841,24 +1873,7 @@ openMainDialog = function()
local plv = d.data.previewLayoutValue local plv = d.data.previewLayoutValue
if plv < 1 then plv = 1 elseif plv > 20 then plv = 20 end if plv < 1 then plv = 1 elseif plv > 20 then plv = 20 end
S.previewLayoutValue = plv S.previewLayoutValue = plv
-- Check if preset changed via combobox
local selectedPreset = d.data.presetSelect
local presetChanged = false
if selectedPreset and selectedPreset ~= S.currentPreset then
savePreset(S.currentPreset) -- Save current first
loadPreset(selectedPreset) -- Load new
S.currentPreset = selectedPreset
local currentFile = app.sprite and app.sprite.filename or ""
if currentFile ~= "" then filePresetMap[currentFile] = selectedPreset end
presetChanged = true
end
saveAll() saveAll()
if presetChanged then
dlg:close()
openMainDialog()
-- Preview title will be stale but avoids repositioning window
return
end
dlg:repaint() dlg:repaint()
end end
end end
@ -2113,7 +2128,7 @@ openMainDialog = function()
end, end,
onwheel = function(ev) onwheel = function(ev)
local dz = ev.deltaY < 0 and 1 or -1 local dz = ev.deltaY < 0 and 1 or -1
S.sourceZoom = math.max(1, math.min(10, S.sourceZoom + dz)) S.sourceZoom = zoomStep(S.sourceZoom, dz)
clampScroll() clampScroll()
dlg:repaint() dlg:repaint()
end end
@ -2288,7 +2303,7 @@ openMainDialog = function()
end, end,
onwheel = function(ev) onwheel = function(ev)
local dz = ev.deltaY < 0 and 1 or -1 local dz = ev.deltaY < 0 and 1 or -1
S.sourceZoom = math.max(1, math.min(10, S.sourceZoom + dz)) S.sourceZoom = zoomStep(S.sourceZoom, dz)
clampScroll() clampScroll()
dlg:repaint() dlg:repaint()
end end
@ -2755,7 +2770,7 @@ openMainDialog = function()
end, end,
onwheel = function(ev) onwheel = function(ev)
local dz = ev.deltaY < 0 and 1 or -1 local dz = ev.deltaY < 0 and 1 or -1
local newZoom = math.max(1, math.min(10, S.gbZoomSrc + dz)) local newZoom = zoomStep(S.gbZoomSrc, dz)
S.gbZoomSrc = newZoom S.gbZoomSrc = newZoom
S.gbZoomOpt = newZoom S.gbZoomOpt = newZoom
dlg:repaint() dlg:repaint()
@ -3055,7 +3070,7 @@ openMainDialog = function()
end, end,
onwheel = function(ev) onwheel = function(ev)
local dz = ev.deltaY < 0 and 1 or -1 local dz = ev.deltaY < 0 and 1 or -1
local newZoom = math.max(1, math.min(10, S.gbZoomOpt + dz)) local newZoom = zoomStep(S.gbZoomOpt, dz)
S.gbZoomOpt = newZoom S.gbZoomOpt = newZoom
S.gbZoomSrc = newZoom S.gbZoomSrc = newZoom
dlg:repaint() dlg:repaint()
@ -3257,11 +3272,10 @@ local function run()
app.alert("No sprite is open.") app.alert("No sprite is open.")
return return
end end
-- Check if already running via lock file -- Check if already running via lock file - silently ignore
local lockF = io.open(LOCK_FILE, "r") local lockF = io.open(LOCK_FILE, "r")
if lockF then if lockF then
lockF:close() lockF:close()
app.alert("AniPhallow is already running.")
return return
end end
-- Create lock file -- Create lock file