Skip to content

Commit 3e2b7e2

Browse files
committed
Consolidate search and highlight into single overlay
1 parent f8e9af5 commit 3e2b7e2

1 file changed

Lines changed: 86 additions & 104 deletions

File tree

plugins/lua/orders.lua

Lines changed: 86 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -714,9 +714,12 @@ end
714714
-- OrdersSearchOverlay
715715
--
716716

717-
local search_matched_indices = {}
718-
local search_current_match_idx = 0
719-
local order_names_checksum = nil
717+
local ORDER_HEIGHT = 3
718+
local TABS_WIDTH_THRESHOLD = 155
719+
local LIST_START_Y_ONE_TABS_ROW = 8
720+
local LIST_START_Y_TWO_TABS_ROWS = 10
721+
local BOTTOM_MARGIN = 9
722+
local ARROW_X = 10
720723

721724
local function perform_search(text)
722725
local matches = {}
@@ -750,6 +753,63 @@ local function calculate_order_names_checksum()
750753
return table.concat(names, "|")
751754
end
752755

756+
local function getListStartY()
757+
local rect = gui.get_interface_rect()
758+
759+
if rect.width >= TABS_WIDTH_THRESHOLD then
760+
return LIST_START_Y_ONE_TABS_ROW
761+
else
762+
return LIST_START_Y_TWO_TABS_ROWS
763+
end
764+
end
765+
766+
local function getViewportSize()
767+
local rect = gui.get_interface_rect()
768+
local list_start_y = getListStartY()
769+
770+
local available_height = rect.height - list_start_y - BOTTOM_MARGIN
771+
return math.floor(available_height / ORDER_HEIGHT)
772+
end
773+
774+
local function getVisibleOrderIndices()
775+
local orders = df.global.world.manager_orders.all
776+
local scroll_pos = mi.info.work_orders.scroll_position_work_orders
777+
778+
if #orders == 0 then return 0, -1 end
779+
780+
local viewport_size = getViewportSize()
781+
local viewport_start = scroll_pos
782+
local viewport_end = scroll_pos + viewport_size - 1
783+
784+
-- Handle end-of-list case
785+
if viewport_end >= #orders then
786+
viewport_end = #orders - 1
787+
viewport_start = math.max(0, viewport_end - viewport_size + 1)
788+
end
789+
790+
return viewport_start, viewport_end
791+
end
792+
793+
local function calculateOrderY(order_idx)
794+
local orders = df.global.world.manager_orders.all
795+
796+
if #orders == 0 or order_idx < 0 or order_idx >= #orders then
797+
return nil
798+
end
799+
800+
local viewport_start, viewport_end = getVisibleOrderIndices()
801+
802+
-- Check if order is in viewport
803+
if order_idx < viewport_start or order_idx > viewport_end then
804+
return nil
805+
end
806+
807+
local list_start_y = getListStartY()
808+
local pos_in_viewport = order_idx - viewport_start
809+
810+
return list_start_y + (pos_in_viewport * ORDER_HEIGHT)
811+
end
812+
753813
OrdersSearchOverlay = defclass(OrdersSearchOverlay, overlay.OverlayWidget)
754814
OrdersSearchOverlay.ATTRS{
755815
desc='Adds a search box to find and navigate to matching manager orders.',
@@ -827,22 +887,25 @@ function OrdersSearchOverlay:init()
827887
}
828888

829889
self.minimized = false
890+
self.matched_indices = {}
891+
self.current_match_idx = 0
892+
self.order_names_checksum = nil
830893
end
831894

832895
function OrdersSearchOverlay:overlay_onupdate()
833896
if self.minimized then return end
834897

835898
local new_checksum = calculate_order_names_checksum()
836-
if new_checksum ~= order_names_checksum then
837-
order_names_checksum = new_checksum
899+
if new_checksum ~= self.order_names_checksum then
900+
self.order_names_checksum = new_checksum
838901
self:update_filter()
839902
end
840903
end
841904

842905
function OrdersSearchOverlay:update_filter()
843906
local text = self.subviews.filter.text
844-
search_matched_indices = perform_search(text)
845-
search_current_match_idx = 0
907+
self.matched_indices = perform_search(text)
908+
self.current_match_idx = 0
846909

847910
if text == '' then
848911
self.subviews.main_panel.frame_title = 'Search'
@@ -867,46 +930,46 @@ function OrdersSearchOverlay:cycle_match(direction)
867930
local new_matches = perform_search(search_text)
868931

869932
if #new_matches == 0 then
870-
search_matched_indices = {}
871-
search_current_match_idx = 0
933+
self.matched_indices = {}
934+
self.current_match_idx = 0
872935
self.subviews.main_panel.frame_title = 'Search'
873936
return
874937
end
875938

876-
local new_match_idx = search_current_match_idx + direction
939+
local new_match_idx = self.current_match_idx + direction
877940

878941
if new_match_idx > #new_matches then
879942
new_match_idx = 1
880943
elseif new_match_idx < 1 then
881944
new_match_idx = #new_matches
882945
end
883946

884-
search_matched_indices = new_matches
885-
search_current_match_idx = new_match_idx
947+
self.matched_indices = new_matches
948+
self.current_match_idx = new_match_idx
886949

887950
-- Scroll to the selected match
888-
local order_idx = search_matched_indices[search_current_match_idx]
951+
local order_idx = self.matched_indices[self.current_match_idx]
889952
mi.info.work_orders.scroll_position_work_orders = order_idx
890953

891954
self.subviews.main_panel.frame_title = 'Search' .. self:get_match_text()
892955
end
893956

894957
function OrdersSearchOverlay:get_match_text()
895-
local total_matches = #search_matched_indices
958+
local total_matches = #self.matched_indices
896959

897960
if total_matches == 0 then
898961
return ''
899962
end
900963

901-
if search_current_match_idx == 0 then
964+
if self.current_match_idx == 0 then
902965
return string.format(': %d matches', total_matches)
903966
end
904967

905-
return string.format(': %d of %d', search_current_match_idx, total_matches)
968+
return string.format(': %d of %d', self.current_match_idx, total_matches)
906969
end
907970

908971
function OrdersSearchOverlay:has_matches()
909-
return #search_matched_indices > 0
972+
return #self.matched_indices > 0
910973
end
911974

912975
local function is_mouse_key(keys)
@@ -955,88 +1018,11 @@ end
9551018
function OrdersSearchOverlay:render(dc)
9561019
if mi.job_details.open then return end
9571020
OrdersSearchOverlay.super.render(self, dc)
1021+
self:render_highlights(dc)
9581022
end
9591023

960-
-- -------------------
961-
-- OrderHighlightOverlay
962-
-- -------------------
963-
964-
local ORDER_HEIGHT = 3
965-
local TABS_WIDTH_THRESHOLD = 155
966-
local LIST_START_Y_ONE_TABS_ROW = 8
967-
local LIST_START_Y_TWO_TABS_ROWS = 10
968-
local BOTTOM_MARGIN = 9
969-
local ARROW_X = 10
970-
971-
local function getListStartY()
972-
local rect = gui.get_interface_rect()
973-
974-
if rect.width >= TABS_WIDTH_THRESHOLD then
975-
return LIST_START_Y_ONE_TABS_ROW
976-
else
977-
return LIST_START_Y_TWO_TABS_ROWS
978-
end
979-
end
980-
981-
local function getViewportSize()
982-
local rect = gui.get_interface_rect()
983-
local list_start_y = getListStartY()
984-
985-
local available_height = rect.height - list_start_y - BOTTOM_MARGIN
986-
return math.floor(available_height / ORDER_HEIGHT)
987-
end
988-
989-
local function getVisibleOrderIndices()
990-
local orders = df.global.world.manager_orders.all
991-
local scroll_pos = mi.info.work_orders.scroll_position_work_orders
992-
993-
if #orders == 0 then return 0, -1 end
994-
995-
local viewport_size = getViewportSize()
996-
local viewport_start = scroll_pos
997-
local viewport_end = scroll_pos + viewport_size - 1
998-
999-
-- Handle end-of-list case
1000-
if viewport_end >= #orders then
1001-
viewport_end = #orders - 1
1002-
viewport_start = math.max(0, viewport_end - viewport_size + 1)
1003-
end
1004-
1005-
return viewport_start, viewport_end
1006-
end
1007-
1008-
local function calculateOrderY(order_idx)
1009-
local orders = df.global.world.manager_orders.all
1010-
1011-
if #orders == 0 or order_idx < 0 or order_idx >= #orders then
1012-
return nil
1013-
end
1014-
1015-
local viewport_start, viewport_end = getVisibleOrderIndices()
1016-
1017-
-- Check if order is in viewport
1018-
if order_idx < viewport_start or order_idx > viewport_end then
1019-
return nil
1020-
end
1021-
1022-
local list_start_y = getListStartY()
1023-
local pos_in_viewport = order_idx - viewport_start
1024-
1025-
return list_start_y + (pos_in_viewport * ORDER_HEIGHT)
1026-
end
1027-
1028-
OrderHighlightOverlay = defclass(OrderHighlightOverlay, overlay.OverlayWidget)
1029-
OrderHighlightOverlay.ATTRS{
1030-
desc='Shows arrows next to the work order found by orders.search',
1031-
default_enabled=true,
1032-
viewscreens='dwarfmode/Info/WORK_ORDERS/Default',
1033-
full_interface=true,
1034-
}
1035-
1036-
function OrderHighlightOverlay:render(dc)
1037-
OrderHighlightOverlay.super.render(self, dc)
1038-
1039-
if mi.job_details.open or #search_matched_indices == 0 then return end
1024+
function OrdersSearchOverlay:render_highlights(dc)
1025+
if #self.matched_indices == 0 then return end
10401026

10411027
local selected_pen = dfhack.pen.parse{
10421028
fg=COLOR_BLACK,
@@ -1050,16 +1036,13 @@ function OrderHighlightOverlay:render(dc)
10501036
bold=true,
10511037
}
10521038

1053-
-- Get the order index of the currently selected match
1054-
local selected_order_idx = search_current_match_idx > 0 and
1055-
search_matched_indices[search_current_match_idx] or nil
1039+
local selected_order_idx = self.current_match_idx > 0 and
1040+
self.matched_indices[self.current_match_idx] or nil
10561041

1057-
-- Draw highlights for all matching orders in viewport
1058-
for _, match_order_idx in ipairs(search_matched_indices) do
1042+
for _, match_order_idx in ipairs(self.matched_indices) do
10591043
local match_y = calculateOrderY(match_order_idx)
10601044

10611045
if match_y then
1062-
-- Use red pen for selected match, white for others
10631046
local pen = (match_order_idx == selected_order_idx) and selected_pen or match_pen
10641047

10651048
dc:seek(ARROW_X, match_y):string('|', pen)
@@ -1075,7 +1058,6 @@ OVERLAY_WIDGETS = {
10751058
recheck=RecheckOverlay,
10761059
importexport=OrdersOverlay,
10771060
search=OrdersSearchOverlay,
1078-
highlight=OrderHighlightOverlay,
10791061
skillrestrictions=SkillRestrictionOverlay,
10801062
laborrestrictions=LaborRestrictionsOverlay,
10811063
conditionsrightclick=ConditionsRightClickOverlay,

0 commit comments

Comments
 (0)