@@ -9,22 +9,14 @@ local common = reqscript('internal/caravan/common')
99local gui = require (' gui' )
1010local overlay = require (' plugins.overlay' )
1111local predicates = reqscript (' internal/caravan/predicates' )
12+ local utils = require (' utils' )
1213local widgets = require (' gui.widgets' )
1314
1415trader_selected_state = trader_selected_state or {}
1516broker_selected_state = broker_selected_state or {}
1617handle_ctrl_click_on_render = handle_ctrl_click_on_render or false
1718handle_shift_click_on_render = handle_shift_click_on_render or false
1819
19- local GOODFLAG = {
20- UNCONTAINED_UNSELECTED = 0 ,
21- UNCONTAINED_SELECTED = 1 ,
22- CONTAINED_UNSELECTED = 2 ,
23- CONTAINED_SELECTED = 3 ,
24- CONTAINER_COLLAPSED_UNSELECTED = 4 ,
25- CONTAINER_COLLAPSED_SELECTED = 5 ,
26- }
27-
2820local trade = df .global .game .main_interface .trade
2921
3022-- -------------------
@@ -39,50 +31,13 @@ Trade.ATTRS {
3931 resize_min = {w = 48 , h = 40 },
4032}
4133
42- local TOGGLE_MAP = {
43- [GOODFLAG .UNCONTAINED_UNSELECTED ] = GOODFLAG .UNCONTAINED_SELECTED ,
44- [GOODFLAG .UNCONTAINED_SELECTED ] = GOODFLAG .UNCONTAINED_UNSELECTED ,
45- [GOODFLAG .CONTAINED_UNSELECTED ] = GOODFLAG .CONTAINED_SELECTED ,
46- [GOODFLAG .CONTAINED_SELECTED ] = GOODFLAG .CONTAINED_UNSELECTED ,
47- [GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED ] = GOODFLAG .CONTAINER_COLLAPSED_SELECTED ,
48- [GOODFLAG .CONTAINER_COLLAPSED_SELECTED ] = GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED ,
49- }
50-
51- local TARGET_MAP = {
52- [true ]= {
53- [GOODFLAG .UNCONTAINED_UNSELECTED ] = GOODFLAG .UNCONTAINED_SELECTED ,
54- [GOODFLAG .UNCONTAINED_SELECTED ] = GOODFLAG .UNCONTAINED_SELECTED ,
55- [GOODFLAG .CONTAINED_UNSELECTED ] = GOODFLAG .CONTAINED_SELECTED ,
56- [GOODFLAG .CONTAINED_SELECTED ] = GOODFLAG .CONTAINED_SELECTED ,
57- [GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED ] = GOODFLAG .CONTAINER_COLLAPSED_SELECTED ,
58- [GOODFLAG .CONTAINER_COLLAPSED_SELECTED ] = GOODFLAG .CONTAINER_COLLAPSED_SELECTED ,
59- },
60- [false ]= {
61- [GOODFLAG .UNCONTAINED_UNSELECTED ] = GOODFLAG .UNCONTAINED_UNSELECTED ,
62- [GOODFLAG .UNCONTAINED_SELECTED ] = GOODFLAG .UNCONTAINED_UNSELECTED ,
63- [GOODFLAG .CONTAINED_UNSELECTED ] = GOODFLAG .CONTAINED_UNSELECTED ,
64- [GOODFLAG .CONTAINED_SELECTED ] = GOODFLAG .CONTAINED_UNSELECTED ,
65- [GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED ] = GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED ,
66- [GOODFLAG .CONTAINER_COLLAPSED_SELECTED ] = GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED ,
67- },
68- }
69-
70- local TARGET_REVMAP = {
71- [GOODFLAG .UNCONTAINED_UNSELECTED ] = false ,
72- [GOODFLAG .UNCONTAINED_SELECTED ] = true ,
73- [GOODFLAG .CONTAINED_UNSELECTED ] = false ,
74- [GOODFLAG .CONTAINED_SELECTED ] = true ,
75- [GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED ] = false ,
76- [GOODFLAG .CONTAINER_COLLAPSED_SELECTED ] = true ,
77- }
78-
7934local function get_entry_icon (data )
80- if TARGET_REVMAP [ trade .goodflag [data .list_idx ][data .item_idx ]] then
35+ if trade .goodflag [data .list_idx ][data .item_idx ]. selected then
8136 return common .ALL_PEN
8237 end
8338end
8439
85- local function sort_noop (a , b )
40+ local function sort_noop ()
8641 -- this function is used as a marker and never actually gets called
8742 error (' sort_noop should not be called' )
8843end
@@ -375,7 +330,7 @@ function Trade:cache_choices(list_idx, trade_bins)
375330 local parent_data
376331 for item_idx , item in ipairs (trade .good [list_idx ]) do
377332 local goodflag = goodflags [item_idx ]
378- if goodflag ~= GOODFLAG . CONTAINED_UNSELECTED and goodflag ~= GOODFLAG . CONTAINED_SELECTED then
333+ if not goodflag . contained then
379334 parent_data = nil
380335 end
381336 local is_banned , is_risky = common .scan_banned (item , self .risky_items )
@@ -487,11 +442,13 @@ end
487442
488443local function toggle_item_base (choice , target_value )
489444 local goodflag = trade .goodflag [choice .data .list_idx ][choice .data .item_idx ]
490- local goodflag_map = target_value == nil and TOGGLE_MAP or TARGET_MAP [target_value ]
491- trade .goodflag [choice .data .list_idx ][choice .data .item_idx ] = goodflag_map [goodflag ]
492- target_value = TARGET_REVMAP [trade .goodflag [choice .data .list_idx ][choice .data .item_idx ]]
445+ if target_value == nil then
446+ target_value = not goodflag .selected
447+ end
448+ local prev_value = goodflag .selected
449+ goodflag .selected = target_value
493450 if choice .data .update_container_fn then
494- choice .data .update_container_fn (TARGET_REVMAP [ goodflag ] , target_value )
451+ choice .data .update_container_fn (prev_value , target_value )
495452 end
496453 return target_value
497454end
@@ -591,39 +548,40 @@ local function set_height(list_idx, delta)
591548 trade .i_height [list_idx ] - page_height ))
592549end
593550
594- local function select_shift_clicked_container_items (new_state , old_state , list_idx )
551+ local function flags_match (goodflag1 , goodflag2 )
552+ return goodflag1 .selected == goodflag2 .selected and
553+ goodflag1 .contained == goodflag2 .contained and
554+ goodflag1 .container_collapsed == goodflag2 .container_collapsed and
555+ goodflag1 .filtered_off == goodflag2 .filtered_off
556+ end
557+
558+ local function select_shift_clicked_container_items (new_state , old_state_fn , list_idx )
595559 -- if ctrl is also held, collapse the container too
596560 local also_collapse = dfhack .internal .getModifiers ().ctrl
597- local collapsed_item_count , collapsing_container , in_container = 0 , false , false
561+ local collapsed_item_count , collapsing_container , in_target_container = 0 , false , false
598562 for k , goodflag in ipairs (new_state ) do
599- if in_container then
600- if goodflag <= GOODFLAG .UNCONTAINED_SELECTED
601- or goodflag >= GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED then
602- break
603- end
604-
605- new_state [k ] = GOODFLAG .CONTAINED_SELECTED
606-
563+ if in_target_container then
564+ if not goodflag .contained then break end
565+ goodflag .selected = true
607566 if collapsing_container then
608567 collapsed_item_count = collapsed_item_count + 1
609568 end
610569 goto continue
611570 end
612571
613- if goodflag == old_state [k ] then goto continue end
572+ local old_goodflag = old_state_fn (k )
573+ if flags_match (goodflag , old_goodflag ) then goto continue end
614574 local is_container = df .item_binst :is_instance (trade .good [list_idx ][k ])
615575 if not is_container then goto continue end
616576
617577 -- deselect the container itself
618- if also_collapse or
619- old_state [k ] == GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED or
620- old_state [k ] == GOODFLAG .CONTAINER_COLLAPSED_SELECTED then
621- collapsing_container = goodflag == GOODFLAG .UNCONTAINED_SELECTED
622- new_state [k ] = GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED
623- else
624- new_state [k ] = GOODFLAG .UNCONTAINED_UNSELECTED
578+ goodflag .selected = false
579+
580+ if also_collapse or old_goodflag .container_collapsed then
581+ goodflag .container_collapsed = true
582+ collapsing_container = not old_goodflag .container_collapsed
625583 end
626- in_container = true
584+ in_target_container = true
627585
628586 :: continue::
629587 end
@@ -633,37 +591,27 @@ local function select_shift_clicked_container_items(new_state, old_state, list_i
633591 end
634592end
635593
636- local CTRL_CLICK_STATE_MAP = {
637- [GOODFLAG .UNCONTAINED_UNSELECTED ] = GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED ,
638- [GOODFLAG .UNCONTAINED_SELECTED ] = GOODFLAG .CONTAINER_COLLAPSED_SELECTED ,
639- [GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED ] = GOODFLAG .UNCONTAINED_UNSELECTED ,
640- [GOODFLAG .CONTAINER_COLLAPSED_SELECTED ] = GOODFLAG .UNCONTAINED_SELECTED ,
641- }
642-
643594-- collapses uncollapsed containers and restores the selection state for the container
644595-- and contained items
645- local function toggle_ctrl_clicked_containers (new_state , old_state , list_idx )
646- local toggled_item_count , in_container , is_collapsing = 0 , false , false
596+ local function toggle_ctrl_clicked_containers (new_state , old_state_fn , list_idx )
597+ local toggled_item_count , in_target_container , is_collapsing = 0 , false , false
647598 for k , goodflag in ipairs (new_state ) do
648- if in_container then
649- if goodflag <= GOODFLAG .UNCONTAINED_SELECTED
650- or goodflag >= GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED then
651- break
652- end
599+ local old_goodflag = old_state_fn (k )
600+ if in_target_container then
601+ if not goodflag .contained then break end
653602 toggled_item_count = toggled_item_count + 1
654- new_state [ k ] = old_state [ k ]
603+ utils . assign ( goodflag , old_goodflag )
655604 goto continue
656605 end
657606
658- if goodflag == old_state [k ] then goto continue end
659- local is_contained = goodflag == GOODFLAG .CONTAINED_UNSELECTED or goodflag == GOODFLAG .CONTAINED_SELECTED
660- if is_contained then goto continue end
607+ if flags_match (goodflag , old_goodflag ) or goodflag .contained then goto continue end
661608 local is_container = df .item_binst :is_instance (trade .good [list_idx ][k ])
662609 if not is_container then goto continue end
663610
664- new_state [k ] = CTRL_CLICK_STATE_MAP [old_state [k ]]
665- in_container = true
666- is_collapsing = goodflag == GOODFLAG .UNCONTAINED_UNSELECTED or goodflag == GOODFLAG .UNCONTAINED_SELECTED
611+ goodflag .selected = old_goodflag .selected
612+ goodflag .container_collapsed = not old_goodflag .container_collapsed
613+ in_target_container = true
614+ is_collapsing = goodflag .container_collapsed
667615
668616 :: continue::
669617 end
@@ -696,27 +644,17 @@ end
696644local function collapseContainers (item_list , list_idx )
697645 local num_items_collapsed = 0
698646 for k , goodflag in ipairs (item_list ) do
699- if goodflag == GOODFLAG .CONTAINED_UNSELECTED
700- or goodflag == GOODFLAG .CONTAINED_SELECTED then
701- goto continue
702- end
647+ if goodflag .contained then goto continue end
703648
704649 local item = trade .good [list_idx ][k ]
705650 local is_container = df .item_binst :is_instance (item )
706651 if not is_container then goto continue end
707652
708- local collapsed_this_container = false
709- if goodflag == GOODFLAG .UNCONTAINED_SELECTED then
710- item_list [k ] = GOODFLAG .CONTAINER_COLLAPSED_SELECTED
711- collapsed_this_container = true
712- elseif goodflag == GOODFLAG .UNCONTAINED_UNSELECTED then
713- item_list [k ] = GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED
714- collapsed_this_container = true
715- end
716-
717- if collapsed_this_container then
653+ if not goodflag .container_collapsed then
654+ goodflag .container_collapsed = true
718655 num_items_collapsed = num_items_collapsed + # dfhack .items .getContainedItems (item )
719656 end
657+
720658 :: continue::
721659 end
722660
@@ -736,8 +674,14 @@ local function collapseEverything()
736674end
737675
738676local function copyGoodflagState ()
739- trader_selected_state = copyall (trade .goodflag [0 ])
740- broker_selected_state = copyall (trade .goodflag [1 ])
677+ -- utils.clone will return a lua table, with indices offset by 1
678+ -- we'll use getSavedGoodflag to map the index back to the original value
679+ trader_selected_state = utils .clone (trade .goodflag [0 ], true )
680+ broker_selected_state = utils .clone (trade .goodflag [1 ], true )
681+ end
682+
683+ local function getSavedGoodflag (saved_state , k )
684+ return saved_state [k + 1 ]
741685end
742686
743687TradeOverlay = defclass (TradeOverlay , overlay .OverlayWidget )
@@ -798,12 +742,12 @@ end
798742function TradeOverlay :onRenderBody (dc )
799743 if handle_shift_click_on_render then
800744 handle_shift_click_on_render = false
801- select_shift_clicked_container_items (trade .goodflag [0 ], trader_selected_state , 0 )
802- select_shift_clicked_container_items (trade .goodflag [1 ], broker_selected_state , 1 )
745+ select_shift_clicked_container_items (trade .goodflag [0 ], curry ( getSavedGoodflag , trader_selected_state ) , 0 )
746+ select_shift_clicked_container_items (trade .goodflag [1 ], curry ( getSavedGoodflag , broker_selected_state ) , 1 )
803747 elseif handle_ctrl_click_on_render then
804748 handle_ctrl_click_on_render = false
805- toggle_ctrl_clicked_containers (trade .goodflag [0 ], trader_selected_state , 0 )
806- toggle_ctrl_clicked_containers (trade .goodflag [1 ], broker_selected_state , 1 )
749+ toggle_ctrl_clicked_containers (trade .goodflag [0 ], curry ( getSavedGoodflag , trader_selected_state ) , 0 )
750+ toggle_ctrl_clicked_containers (trade .goodflag [1 ], curry ( getSavedGoodflag , broker_selected_state ) , 1 )
807751 end
808752end
809753
@@ -915,12 +859,10 @@ function for_selected_item(list_idx, fn)
915859 local in_selected_container = false
916860 for item_idx , item in ipairs (trade .good [list_idx ]) do
917861 local goodflag = goodflags [item_idx ]
918- if goodflag == GOODFLAG .UNCONTAINED_SELECTED or goodflag == GOODFLAG .CONTAINER_COLLAPSED_SELECTED then
919- in_selected_container = true
920- elseif goodflag == GOODFLAG .UNCONTAINED_UNSELECTED or goodflag == GOODFLAG .CONTAINER_COLLAPSED_UNSELECTED then
921- in_selected_container = false
862+ if not goodflag .contained then
863+ in_selected_container = goodflag .selected
922864 end
923- if in_selected_container or TARGET_REVMAP [ goodflag ] then
865+ if in_selected_container or goodflag . selected then
924866 if fn (item_idx , item ) then
925867 return
926868 end
954896function Ethics :deselect_transgressions ()
955897 local goodflags = trade .goodflag [1 ]
956898 for _ ,choice in ipairs (self .choices ) do
957- local goodflag = goodflags [choice .data .item_idx ]
958- if TARGET_REVMAP [goodflag ] then
959- goodflags [choice .data .item_idx ] = TOGGLE_MAP [goodflag ]
960- end
899+ goodflags [choice .data .item_idx ].selected = false
961900 end
962901 self :rescan ()
963902end
0 commit comments