717717local search_cursor_visible = false
718718local search_last_scroll_position = - 1
719719local order_count_at_highlight = 0
720+ local search_matched_indices = {}
721+ local search_current_match_idx = 0
720722
721723local function perform_search (text )
722724 local matches = {}
@@ -812,15 +814,12 @@ function OrdersSearchOverlay:init()
812814 minimized_panel ,
813815 }
814816
815- -- Initialize search state
816- self .matched_indices = {}
817- self .current_match_idx = 0
818817 self .minimized = false
819818end
820819
821820function OrdersSearchOverlay :update_filter (text )
822- self . matched_indices = perform_search (text )
823- self . current_match_idx = 0
821+ search_matched_indices = perform_search (text )
822+ search_current_match_idx = 0
824823 search_cursor_visible = false
825824
826825 if text == ' ' then
@@ -846,26 +845,26 @@ function OrdersSearchOverlay:cycle_match(direction)
846845 local new_matches = perform_search (search_text )
847846
848847 if # new_matches == 0 then
849- self . matched_indices = {}
850- self . current_match_idx = 0
848+ search_matched_indices = {}
849+ search_current_match_idx = 0
851850 search_cursor_visible = false
852851 self .subviews .main_panel .frame_title = ' Search'
853852 return
854853 end
855854
856- local new_match_idx = self . current_match_idx + direction
855+ local new_match_idx = search_current_match_idx + direction
857856
858857 if new_match_idx > # new_matches then
859858 new_match_idx = 1
860859 elseif new_match_idx < 1 then
861860 new_match_idx = # new_matches
862861 end
863862
864- self . matched_indices = new_matches
865- self . current_match_idx = new_match_idx
863+ search_matched_indices = new_matches
864+ search_current_match_idx = new_match_idx
866865
867866 -- Scroll to the selected match
868- local order_idx = self . matched_indices [ self . current_match_idx ]
867+ local order_idx = search_matched_indices [ search_current_match_idx ]
869868 mi .info .work_orders .scroll_position_work_orders = order_idx
870869 search_last_scroll_position = order_idx
871870 search_cursor_visible = true
@@ -875,21 +874,21 @@ function OrdersSearchOverlay:cycle_match(direction)
875874end
876875
877876function OrdersSearchOverlay :get_match_text ()
878- local total_matches = # self . matched_indices
877+ local total_matches = # search_matched_indices
879878
880879 if total_matches == 0 then
881880 return ' '
882881 end
883882
884- if self . current_match_idx == 0 then
883+ if search_current_match_idx == 0 then
885884 return string.format (' : %d matches' , total_matches )
886885 end
887886
888- return string.format (' : %d of %d' , self . current_match_idx , total_matches )
887+ return string.format (' : %d of %d' , search_current_match_idx , total_matches )
889888end
890889
891890function OrdersSearchOverlay :has_matches ()
892- return # self . matched_indices > 0
891+ return # search_matched_indices > 0
893892end
894893
895894local function is_mouse_key (keys )
@@ -969,31 +968,43 @@ local function getViewportSize()
969968 return math.floor (available_height / ORDER_HEIGHT )
970969end
971970
972- local function calculateSelectedOrderY ()
971+ local function getVisibleOrderIndices ()
973972 local orders = df .global .world .manager_orders .all
974973 local scroll_pos = mi .info .work_orders .scroll_position_work_orders
975974
976- if # orders == 0 or scroll_pos < 0 or scroll_pos >= # orders then
977- return nil
978- end
975+ if # orders == 0 then return 0 , - 1 end
979976
980- local list_start_y = getListStartY ()
981977 local viewport_size = getViewportSize ()
982-
983978 local viewport_start = scroll_pos
984979 local viewport_end = scroll_pos + viewport_size - 1
985980
986- -- Selected order tries to be at the top unless we're at the end of the list
981+ -- Handle end-of- list case
987982 if viewport_end >= # orders then
988983 viewport_end = # orders - 1
989984 viewport_start = math.max (0 , viewport_end - viewport_size + 1 )
990985 end
991986
992- local pos_in_viewport = scroll_pos - viewport_start
987+ return viewport_start , viewport_end
988+ end
989+
990+ local function calculateOrderY (order_idx )
991+ local orders = df .global .world .manager_orders .all
992+
993+ if # orders == 0 or order_idx < 0 or order_idx >= # orders then
994+ return nil
995+ end
996+
997+ local viewport_start , viewport_end = getVisibleOrderIndices ()
998+
999+ -- Check if order is in viewport
1000+ if order_idx < viewport_start or order_idx > viewport_end then
1001+ return nil
1002+ end
9931003
994- local selected_y = list_start_y + (pos_in_viewport * ORDER_HEIGHT )
1004+ local list_start_y = getListStartY ()
1005+ local pos_in_viewport = order_idx - viewport_start
9951006
996- return selected_y
1007+ return list_start_y + ( pos_in_viewport * ORDER_HEIGHT )
9971008end
9981009
9991010OrderHighlightOverlay = defclass (OrderHighlightOverlay , overlay .OverlayWidget )
@@ -1024,18 +1035,37 @@ function OrderHighlightOverlay:render(dc)
10241035 return
10251036 end
10261037
1027- -- Draw highlight arrows
1028- local selected_y = calculateSelectedOrderY ()
1029- if selected_y then
1030- local highlight_pen = dfhack .pen .parse {
1031- fg = COLOR_BLACK ,
1032- bg = COLOR_WHITE ,
1033- bold = true ,
1034- }
1035-
1036- dc :seek (ARROW_X , selected_y ):string (' |' , highlight_pen )
1037- dc :seek (ARROW_X , selected_y + 1 ):string (' >' , highlight_pen )
1038- dc :seek (ARROW_X , selected_y + 2 ):string (' |' , highlight_pen )
1038+ -- Draw highlight arrows for all matches in viewport
1039+ if # search_matched_indices == 0 then return end
1040+
1041+ local selected_pen = dfhack .pen .parse {
1042+ fg = COLOR_BLACK ,
1043+ bg = COLOR_RED ,
1044+ bold = true ,
1045+ }
1046+
1047+ local match_pen = dfhack .pen .parse {
1048+ fg = COLOR_BLACK ,
1049+ bg = COLOR_WHITE ,
1050+ bold = true ,
1051+ }
1052+
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
1056+
1057+ -- Draw highlights for all matching orders in viewport
1058+ for _ , match_order_idx in ipairs (search_matched_indices ) do
1059+ local match_y = calculateOrderY (match_order_idx )
1060+
1061+ if match_y then
1062+ -- Use red pen for selected match, white for others
1063+ local pen = (match_order_idx == selected_order_idx ) and selected_pen or match_pen
1064+
1065+ dc :seek (ARROW_X , match_y ):string (' |' , pen )
1066+ dc :seek (ARROW_X , match_y + 1 ):string (' >' , pen )
1067+ dc :seek (ARROW_X , match_y + 2 ):string (' |' , pen )
1068+ end
10391069 end
10401070end
10411071
0 commit comments