Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/about/Authors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ Robert Heinrich rh73
Robert Janetzko robertjanetzko
Rocco Moretti roccomoretti
RocheLimit
Rodrigo Cardoso Buske robuske
rofl0r rofl0r
root
Rose RosaryMala
Expand Down
2 changes: 2 additions & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ Template for new versions:

## Lua

- `orders`: make work-order list geometry available to Lua overlays

## Removed

# 53.16-r1.1
Expand Down
68 changes: 4 additions & 64 deletions plugins/lua/orders.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ local _ENV = mkmodule('plugins.orders')
local dialogs = require('gui.dialogs')
local gui = require('gui')
local overlay = require('plugins.overlay')
local workOrderList = require('plugins.orders.work_order_list')
local textures = require('gui.textures')
local utils = require('utils')
local widgets = require('gui.widgets')
Expand Down Expand Up @@ -714,11 +715,6 @@ end
-- OrdersSearchOverlay
--

local ORDER_HEIGHT = 3
local TABS_WIDTH_THRESHOLD = 155
local LIST_START_Y_ONE_TABS_ROW = 8
local LIST_START_Y_TWO_TABS_ROWS = 10
local BOTTOM_MARGIN = 9
local ARROW_X = 10

local SELECTED_PEN = dfhack.pen.parse{fg=COLOR_BLACK, bg=COLOR_WHITE, bold=true}
Expand Down Expand Up @@ -756,63 +752,6 @@ local function concat_order_names()
return table.concat(names, "|")
end

local function getListStartY()
local rect = gui.get_interface_rect()

if rect.width >= TABS_WIDTH_THRESHOLD then
return LIST_START_Y_ONE_TABS_ROW
else
return LIST_START_Y_TWO_TABS_ROWS
end
end

local function getViewportSize()
local rect = gui.get_interface_rect()
local list_start_y = getListStartY()

local available_height = rect.height - list_start_y - BOTTOM_MARGIN
return math.floor(available_height / ORDER_HEIGHT)
end

local function getVisibleOrderIndices()
local orders = df.global.world.manager_orders.all
local scroll_pos = mi.info.work_orders.scroll_position_work_orders

if #orders == 0 then return 0, -1 end

local viewport_size = getViewportSize()
local viewport_start = scroll_pos
local viewport_end = scroll_pos + viewport_size - 1

-- Handle end-of-list case
if viewport_end >= #orders then
viewport_end = #orders - 1
viewport_start = math.max(0, viewport_end - viewport_size + 1)
end

return viewport_start, viewport_end
end

local function calculateOrderY(order_idx)
local orders = df.global.world.manager_orders.all

if #orders == 0 or order_idx < 0 or order_idx >= #orders then
return nil
end

local viewport_start, viewport_end = getVisibleOrderIndices()

-- Check if order is in viewport
if order_idx < viewport_start or order_idx > viewport_end then
return nil
end

local list_start_y = getListStartY()
local pos_in_viewport = order_idx - viewport_start

return list_start_y + (pos_in_viewport * ORDER_HEIGHT)
end

OrdersSearchOverlay = defclass(OrdersSearchOverlay, overlay.OverlayWidget)
OrdersSearchOverlay.ATTRS{
desc='Adds a search box to find and navigate to matching manager orders.',
Expand Down Expand Up @@ -952,7 +891,8 @@ function OrdersSearchOverlay:cycle_match(direction)

-- Scroll to the selected match only if not already visible
local order_idx = self.matched_indices[self.current_match_idx]
local viewport_start, viewport_end = getVisibleOrderIndices()
local viewport_start, viewport_end =
workOrderList.getVisibleOrderIndices()
if order_idx < viewport_start or order_idx > viewport_end then
mi.info.work_orders.scroll_position_work_orders = order_idx
end
Expand Down Expand Up @@ -1030,7 +970,7 @@ function OrdersSearchOverlay:render_highlights(dc)
self.matched_indices[self.current_match_idx] or nil

for _, match_order_idx in ipairs(self.matched_indices) do
local match_y = calculateOrderY(match_order_idx)
local match_y = workOrderList.getOrderY(match_order_idx)

if match_y then
local pen = (match_order_idx == selected_order_idx) and SELECTED_PEN or MATCH_PEN
Expand Down
90 changes: 90 additions & 0 deletions plugins/lua/orders/work_order_list.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
local _ENV = mkmodule('plugins.orders.work_order_list')

local gui = require('gui')

ORDER_HEIGHT = 3

local TABS_WIDTH_THRESHOLD = 155
local LIST_START_Y_ONE_TABS_ROW = 8
local LIST_START_Y_TWO_TABS_ROWS = 10
local BOTTOM_MARGIN = 9

---@param interface_width integer
---@return integer
local function calculateListStartY(interface_width)
if interface_width >= TABS_WIDTH_THRESHOLD then
return LIST_START_Y_ONE_TABS_ROW
end
return LIST_START_Y_TWO_TABS_ROWS
end

---@param interface_height integer
---@param list_start_y integer
---@return integer
local function calculateViewportSize(interface_height, list_start_y)
local available_height = interface_height - list_start_y - BOTTOM_MARGIN
return math.floor(available_height / ORDER_HEIGHT)
end

---@param order_count integer
---@param viewport_size integer
---@param requested_start integer
---@return integer viewport_start
---@return integer viewport_end
local function calculateVisibleOrderIndices(
order_count, viewport_size, requested_start)
if order_count == 0 then return 0, -1 end

local viewport_start = requested_start
local viewport_end = requested_start + viewport_size - 1

-- Handle end-of-list case
if viewport_end >= order_count then
viewport_end = order_count - 1
viewport_start = math.max(0, viewport_end - viewport_size + 1)
end
return viewport_start, viewport_end
end

---@return integer
function getListStartY()
return calculateListStartY(gui.get_interface_rect().width)
end

---@return integer
function getViewportSize()
return calculateViewportSize(
gui.get_interface_rect().height, getListStartY())
end

---@return integer viewport_start
---@return integer viewport_end
function getVisibleOrderIndices()
local order_count = #df.global.world.manager_orders.all
local requested_start = df.global.game.main_interface.info.work_orders
.scroll_position_work_orders
return calculateVisibleOrderIndices(
order_count, getViewportSize(), requested_start)
end

---@param order_idx integer
---@return integer|nil y
function getOrderY(order_idx)
local orders = df.global.world.manager_orders.all
if order_idx < 0 or order_idx >= #orders then return nil end

local viewport_start, viewport_end = getVisibleOrderIndices()

-- Check if order is in viewport
if order_idx < viewport_start or order_idx > viewport_end then return nil end

return getListStartY() + (order_idx - viewport_start) * ORDER_HEIGHT
end

unitTestHooks = {
calculateListStartY = calculateListStartY,
calculateViewportSize = calculateViewportSize,
calculateVisibleOrderIndices = calculateVisibleOrderIndices,
}

return _ENV
30 changes: 30 additions & 0 deletions test/plugins/orders.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
config.mode = 'fortress'
config.target = 'orders'

local workOrderList = require('plugins.orders.work_order_list')

local FILE_PATH_PATTERN = dfhack.getConfigPath() .. '/orders/%s.json'

local BACKUP_FILE_NAME = 'tmp-backup'
Expand Down Expand Up @@ -266,3 +268,31 @@ function test.list()
expect.eq(CR_OK, status)
expect.str_find(BACKUP_FILE_NAME:gsub('%-', '%%-'), output)
end

function test.work_order_list_geometry()
local hooks = workOrderList.unitTestHooks

expect.eq(10, hooks.calculateListStartY(154))
expect.eq(8, hooks.calculateListStartY(155))
expect.eq(4, hooks.calculateViewportSize(30, 8))

local viewport_start, viewport_end =
hooks.calculateVisibleOrderIndices(0, 4, 0)
expect.eq(0, viewport_start)
expect.eq(-1, viewport_end)

viewport_start, viewport_end =
hooks.calculateVisibleOrderIndices(10, 4, 2)
expect.eq(2, viewport_start)
expect.eq(5, viewport_end)

viewport_start, viewport_end =
hooks.calculateVisibleOrderIndices(10, 4, 8)
expect.eq(6, viewport_start)
expect.eq(9, viewport_end)

viewport_start, viewport_end =
hooks.calculateVisibleOrderIndices(10, 20, 8)
expect.eq(0, viewport_start)
expect.eq(9, viewport_end)
end