Skip to content

Labor Control Overlay #1463

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
26 changes: 26 additions & 0 deletions docs/zSelectLockLabors.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Select Lock Overlay
===================

This is a DFHack overlay plugin for Dwarf Fortress that simulates the selection and locking of multiple units within the **Work Details** screen. It provides a simple UI interface to batch-toggle units' labor assignments, either by selecting, locking, or both.

Features
--------

- **Overlay Interface**: Integrated directly into the `LABOR/WORK_DETAILS` viewscreen.
- **Action Modes**: Choose between `Select only`, `Lock only`, or `Select + Lock`.
- **Batch Processing**: Specify how many entries to affect and apply actions with one click.
- **Non-Intrusive**: Uses DFHack GUI input simulation to trigger existing functionality.

Usage
-----

Once the plugin is loaded and you're in the `Work Details` screen (e.g., `y` -> `Work Details`), the overlay will automatically appear.

1. Use the **Mode** dropdown to select what action(s) to simulate:
- `Select only`: Just toggles unit selection.
- `Lock only`: Just toggles the lock status.
- `Select + Lock`: Toggles both selection and lock.

2. Adjust the number of entries to apply actions to (default is 7).

3. Press the **RUN** button (or the hotkey defined for it) to execute the actions.
98 changes: 98 additions & 0 deletions zSelectLockLabors.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
--@module=true
local gui = require('gui')
local widgets = require('gui.widgets')
local overlay = require('plugins.overlay')

local SelectLockOverlay = defclass(nil, overlay.OverlayWidget)
SelectLockOverlay.ATTRS {
desc = 'Simulate selection and locking of multiple units.',
viewscreens = {'dwarfmode/Info/LABOR/WORK_DETAILS/Default'},
default_enabled = true,
default_pos = {x = -70, y = 10},
frame = {w = 25, h = 6, r = 1, t = 1, transparent = false},
}

local function simulate_actions(self, count)
gui.simulateInput(dfhack.gui.getCurViewscreen(), 'STANDARDSCROLL_RIGHT')

local function step(i)
if i > count then
for _ = 1, count do
gui.simulateInput(dfhack.gui.getCurViewscreen(), 'STANDARDSCROLL_UP')
gui.simulateInput(dfhack.gui.getCurViewscreen(), 'CONTEXT_SCROLL_UP')
end
self.is_running = false
return
end

if self.action_mode ~= 'lock' then
gui.simulateInput(dfhack.gui.getCurViewscreen(), 'SELECT')
end
if self.action_mode ~= 'select' then
gui.simulateInput(dfhack.gui.getCurViewscreen(), 'UNITLIST_SPECIALIZE')
end
--This line is keyboard arrow down
gui.simulateInput(dfhack.gui.getCurViewscreen(), 'STANDARDSCROLL_DOWN')
--CONTEXT_SCROLL_DOWN helps with consistency. Otherwise the program will miss some units. Line below is scroll wheel down
gui.simulateInput(dfhack.gui.getCurViewscreen(), 'CONTEXT_SCROLL_DOWN')

dfhack.timeout(3, 'frames', function() step(i + 1) end)
end

step(1)
end

function SelectLockOverlay:init()
self.action_mode = 'both'
self.entry_count = 7
self.is_running = false
self:addviews{
widgets.Panel{
frame_style = gui.MEDIUM_FRAME,
frame_background = gui.CLEAR_PEN,
subviews = {
widgets.CycleHotkeyLabel{
view_id = 'action_mode',
frame = {l = 1, t = 1},
label = 'Mode',
option_gap = 2,
options = {
{label = 'Select only', value = 'select'},
{label = 'Lock only', value = 'lock'},
{label = 'Select + Lock', value = 'both'},
},
initial_option = 'both',
on_change = function(val) self.action_mode = val end,
},
widgets.EditField{
numeric = true,
frame = {l = 1, t = 2},
key = 'CUSTOM_CTRL_N',
auto_focus = false,
text = '7',
on_change = function(val)
local num = tonumber(val)
self.entry_count = (num and num > 0 and math.floor(num)) or 7
end,
},
widgets.HotkeyLabel{
view_id = 'run_button',
frame = {l = 1, t = 3},
label = 'RUN',
on_activate = function()
if self.is_running then return end
self.is_running = true
simulate_actions(self, self.entry_count)
end,
enabled = function() return not self.is_running end,
},
},
},
}
end

OVERLAY_WIDGETS = {
select_lock_overlay = SelectLockOverlay,
}

return {}