4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file tracerestrict_gui.cpp GUI code for Trace Restrict
12 * This is largely based on the programmable signals patch's GUI
16 #include "tracerestrict.h"
17 #include "command_func.h"
18 #include "window_func.h"
19 #include "strings_func.h"
20 #include "string_func.h"
21 #include "viewport_func.h"
22 #include "textbuf_gui.h"
23 #include "company_func.h"
24 #include "tilehighlight_func.h"
25 #include "widgets/dropdown_func.h"
26 #include "widgets/dropdown_type.h"
30 #include "depot_map.h"
32 #include "station_base.h"
33 #include "waypoint_base.h"
34 #include "depot_base.h"
36 #include "cargotype.h"
38 #include "company_base.h"
39 #include "vehicle_base.h"
40 #include "vehicle_gui.h"
41 #include "vehicle_gui_base.h"
43 #include "sortlist_type.h"
44 #include "table/sprites.h"
45 #include "core/geometry_func.hpp"
47 #include "safeguards.h"
49 extern uint
ConvertSpeedToDisplaySpeed(uint speed
);
50 extern uint
ConvertDisplaySpeedToSpeed(uint speed
);
53 enum TraceRestrictWindowWidgets
{
55 TR_WIDGET_INSTRUCTION_LIST
,
58 TR_WIDGET_SEL_TOP_LEFT_2
,
59 TR_WIDGET_SEL_TOP_LEFT
,
60 TR_WIDGET_SEL_TOP_LEFT_AUX
,
61 TR_WIDGET_SEL_TOP_MIDDLE
,
62 TR_WIDGET_SEL_TOP_RIGHT
,
70 TR_WIDGET_TYPE_NONCOND
,
75 TR_WIDGET_VALUE_DROPDOWN
,
77 TR_WIDGET_VALUE_SIGNAL
,
78 TR_WIDGET_LEFT_AUX_DROPDOWN
,
85 TR_WIDGET_GOTO_SIGNAL
,
90 TR_WIDGET_COPY_APPEND
,
95 /** Selection mappings for NWID_SELECTION selectors */
131 * drop down list string array, and corresponding integer values
133 * value_array *must* be at least as long as string_array,
134 * where the length of string_array is defined as the offset
135 * of the first INVALID_STRING_ID
137 struct TraceRestrictDropDownListSet
{
138 const StringID
*string_array
;
139 const uint
*value_array
;
142 static const StringID _program_insert_str
[] = {
143 STR_TRACE_RESTRICT_CONDITIONAL_IF
,
144 STR_TRACE_RESTRICT_CONDITIONAL_ELIF
,
145 STR_TRACE_RESTRICT_CONDITIONAL_ORIF
,
146 STR_TRACE_RESTRICT_CONDITIONAL_ELSE
,
147 STR_TRACE_RESTRICT_PF_DENY
,
148 STR_TRACE_RESTRICT_PF_PENALTY
,
149 STR_TRACE_RESTRICT_RESERVE_THROUGH
,
150 STR_TRACE_RESTRICT_LONG_RESERVE
,
151 STR_TRACE_RESTRICT_WAIT_AT_PBS
,
152 STR_TRACE_RESTRICT_SLOT_OP
,
155 static const uint32 _program_insert_else_hide_mask
= 8; ///< disable bitmask for else
156 static const uint32 _program_insert_or_if_hide_mask
= 4; ///< disable bitmask for orif
157 static const uint32 _program_insert_else_if_hide_mask
= 2; ///< disable bitmask for elif
158 static const uint32 _program_wait_pbs_hide_mask
= 0x100; ///< disable bitmask for wait at PBS
159 static const uint32 _program_slot_hide_mask
= 0x200; ///< disable bitmask for slot
160 static const uint _program_insert_val
[] = {
161 TRIT_COND_UNDEFINED
, // if block
162 TRIT_COND_UNDEFINED
| (TRCF_ELSE
<< 16), // elif block
163 TRIT_COND_UNDEFINED
| (TRCF_OR
<< 16), // orif block
164 TRIT_COND_ENDIF
| (TRCF_ELSE
<< 16), // else block
165 TRIT_PF_DENY
, // deny
166 TRIT_PF_PENALTY
, // penalty
167 TRIT_RESERVE_THROUGH
, // reserve through
168 TRIT_LONG_RESERVE
, // long reserve
169 TRIT_WAIT_AT_PBS
, // wait at PBS signal
170 TRIT_SLOT
, // slot operation
173 /** insert drop down list strings and values */
174 static const TraceRestrictDropDownListSet _program_insert
= {
175 _program_insert_str
, _program_insert_val
,
178 static const StringID _deny_value_str
[] = {
179 STR_TRACE_RESTRICT_PF_DENY
,
180 STR_TRACE_RESTRICT_PF_ALLOW
,
183 static const uint _deny_value_val
[] = {
188 /** value drop down list for deny types strings and values */
189 static const TraceRestrictDropDownListSet _deny_value
= {
190 _deny_value_str
, _deny_value_val
,
193 static const StringID _reserve_through_value_str
[] = {
194 STR_TRACE_RESTRICT_RESERVE_THROUGH
,
195 STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL
,
198 static const uint _reserve_through_value_val
[] = {
203 static const StringID _long_reserve_value_str
[] = {
204 STR_TRACE_RESTRICT_LONG_RESERVE
,
205 STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL
,
208 static const uint _long_reserve_value_val
[] = {
213 /** value drop down list for reserve through types strings and values */
214 static const TraceRestrictDropDownListSet _reserve_through_value
= {
215 _reserve_through_value_str
, _reserve_through_value_val
,
218 /** value drop down list for long reserve types strings and values */
219 static const TraceRestrictDropDownListSet _long_reserve_value
= {
220 _long_reserve_value_str
, _long_reserve_value_val
,
223 static const StringID _wait_at_pbs_value_str
[] = {
224 STR_TRACE_RESTRICT_WAIT_AT_PBS
,
225 STR_TRACE_RESTRICT_WAIT_AT_PBS_CANCEL
,
228 static const uint _wait_at_pbs_value_val
[] = {
233 /** value drop down list for wait at PBS types strings and values */
234 static const TraceRestrictDropDownListSet _wait_at_pbs_value
= {
235 _wait_at_pbs_value_str
, _wait_at_pbs_value_val
,
238 static const StringID _direction_value_str
[] = {
239 STR_TRACE_RESTRICT_DIRECTION_FRONT
,
240 STR_TRACE_RESTRICT_DIRECTION_BACK
,
241 STR_TRACE_RESTRICT_DIRECTION_NE
,
242 STR_TRACE_RESTRICT_DIRECTION_SE
,
243 STR_TRACE_RESTRICT_DIRECTION_SW
,
244 STR_TRACE_RESTRICT_DIRECTION_NW
,
247 static const uint _direction_value_val
[] = {
256 /** value drop down list for direction type strings and values */
257 static const TraceRestrictDropDownListSet _direction_value
= {
258 _direction_value_str
, _direction_value_val
,
262 * Get index of @p value in @p list_set
263 * if @p value is not present, assert if @p missing_ok is false, otherwise return -1
265 static int GetDropDownListIndexByValue(const TraceRestrictDropDownListSet
*list_set
, uint value
, bool missing_ok
)
267 const StringID
*string_array
= list_set
->string_array
;
268 const uint
*value_array
= list_set
->value_array
;
270 for (; *string_array
!= INVALID_STRING_ID
; string_array
++, value_array
++) {
271 if (*value_array
== value
) {
272 return value_array
- list_set
->value_array
;
275 assert(missing_ok
== true);
280 * Get StringID correspoding to @p value, in @list_set
281 * @p value must be present
283 static StringID
GetDropDownStringByValue(const TraceRestrictDropDownListSet
*list_set
, uint value
)
285 return list_set
->string_array
[GetDropDownListIndexByValue(list_set
, value
, false)];
288 typedef uint TraceRestrictGuiItemType
;
290 static TraceRestrictGuiItemType
GetItemGuiType(TraceRestrictItem item
)
292 TraceRestrictItemType type
= GetTraceRestrictType(item
);
293 if (IsTraceRestrictTypeAuxSubtype(type
)) {
294 return type
| (GetTraceRestrictAuxField(item
) << 16);
301 static TraceRestrictItemType
ItemTypeFromGuiType(TraceRestrictGuiItemType type
)
303 return static_cast<TraceRestrictItemType
>(type
& 0xFFFF);
307 * Return the appropriate type dropdown TraceRestrictDropDownListSet for the given item type @p type
309 static const TraceRestrictDropDownListSet
*GetTypeDropDownListSet(TraceRestrictGuiItemType type
, uint32
*hide_mask
= nullptr)
311 static const StringID str_action
[] = {
312 STR_TRACE_RESTRICT_PF_DENY
,
313 STR_TRACE_RESTRICT_PF_PENALTY
,
314 STR_TRACE_RESTRICT_RESERVE_THROUGH
,
315 STR_TRACE_RESTRICT_LONG_RESERVE
,
316 STR_TRACE_RESTRICT_WAIT_AT_PBS
,
317 STR_TRACE_RESTRICT_SLOT_OP
,
320 static const uint val_action
[] = {
323 TRIT_RESERVE_THROUGH
,
328 static const TraceRestrictDropDownListSet set_action
= {
329 str_action
, val_action
,
332 static const StringID str_cond
[] = {
333 STR_TRACE_RESTRICT_VARIABLE_TRAIN_LENGTH
,
334 STR_TRACE_RESTRICT_VARIABLE_MAX_SPEED
,
335 STR_TRACE_RESTRICT_VARIABLE_CURRENT_ORDER
,
336 STR_TRACE_RESTRICT_VARIABLE_NEXT_ORDER
,
337 STR_TRACE_RESTRICT_VARIABLE_LAST_VISITED_STATION
,
338 STR_TRACE_RESTRICT_VARIABLE_CARGO
,
339 STR_TRACE_RESTRICT_VARIABLE_ENTRY_DIRECTION
,
340 STR_TRACE_RESTRICT_VARIABLE_PBS_ENTRY_SIGNAL
,
341 STR_TRACE_RESTRICT_VARIABLE_TRAIN_GROUP
,
342 STR_TRACE_RESTRICT_VARIABLE_TRAIN_SLOT
,
343 STR_TRACE_RESTRICT_VARIABLE_SLOT_OCCUPANCY
,
344 STR_TRACE_RESTRICT_VARIABLE_SLOT_OCCUPANCY_REMAINING
,
345 STR_TRACE_RESTRICT_VARIABLE_UNDEFINED
,
348 static const uint val_cond
[] = {
349 TRIT_COND_TRAIN_LENGTH
,
351 TRIT_COND_CURRENT_ORDER
,
352 TRIT_COND_NEXT_ORDER
,
353 TRIT_COND_LAST_STATION
,
355 TRIT_COND_ENTRY_DIRECTION
,
356 TRIT_COND_PBS_ENTRY_SIGNAL
,
357 TRIT_COND_TRAIN_GROUP
,
358 TRIT_COND_TRAIN_IN_SLOT
,
359 TRIT_COND_SLOT_OCCUPANCY
| (TRSOCAF_OCCUPANTS
<< 16),
360 TRIT_COND_SLOT_OCCUPANCY
| (TRSOCAF_REMAINING
<< 16),
363 static const TraceRestrictDropDownListSet set_cond
= {
367 bool is_conditional
= IsTraceRestrictTypeConditional(ItemTypeFromGuiType(type
));
369 if (hide_mask
!= nullptr) {
373 return is_conditional
? &set_cond
: &set_action
;
377 * Get a TraceRestrictDropDownListSet of the sorted cargo list
379 static const TraceRestrictDropDownListSet
*GetSortedCargoTypeDropDownListSet()
381 static StringID cargo_list_str
[NUM_CARGO
+ 1];
382 static uint cargo_list_id
[NUM_CARGO
];
383 static const TraceRestrictDropDownListSet cargo_list
= {
384 cargo_list_str
, cargo_list_id
,
387 for (size_t i
= 0; i
< _sorted_standard_cargo_specs_size
; ++i
) {
388 const CargoSpec
*cs
= _sorted_cargo_specs
[i
];
389 cargo_list_str
[i
] = cs
->name
;
390 cargo_list_id
[i
] = cs
->Index();
392 cargo_list_str
[_sorted_standard_cargo_specs_size
] = INVALID_STRING_ID
;
398 * Get a DropDownList of the group list
400 static DropDownList
*GetGroupDropDownList(Owner owner
, GroupID group_id
, int &selected
)
402 typedef GUIList
<const Group
*> GUIGroupList
;
403 extern int CDECL
GroupNameSorter(const Group
* const *a
, const Group
* const *b
);
409 if (g
->owner
== owner
&& g
->vehicle_type
== VEH_TRAIN
&& g
->statistics
.num_vehicle
!= 0) {
415 list
.Sort(&GroupNameSorter
);
417 DropDownList
*dlist
= new DropDownList();
420 if (group_id
== DEFAULT_GROUP
) selected
= DEFAULT_GROUP
;
421 *dlist
->Append() = new DropDownListStringItem(STR_GROUP_DEFAULT_TRAINS
, DEFAULT_GROUP
, false);
423 for (uint i
= 0; i
< list
.Length(); ++i
) {
424 const Group
*g
= list
[i
];
425 if (group_id
== g
->index
) selected
= group_id
;
426 DropDownListParamStringItem
*item
= new DropDownListParamStringItem(STR_GROUP_NAME
, g
->index
, false);
427 item
->SetParam(0, g
->index
);
428 *dlist
->Append() = item
;
434 /** Sort slots by their name */
435 static int CDECL
SlotNameSorter(const TraceRestrictSlot
* const *a
, const TraceRestrictSlot
* const *b
)
437 int r
= strnatcmp((*a
)->name
.c_str(), (*b
)->name
.c_str()); // Sort by name (natural sorting).
438 if (r
== 0) return (*a
)->index
- (*b
)->index
;
443 * Get a DropDownList of the group list
445 DropDownList
*GetSlotDropDownList(Owner owner
, TraceRestrictSlotID slot_id
, int &selected
)
447 GUIList
<const TraceRestrictSlot
*> list
;
449 const TraceRestrictSlot
*slot
;
450 FOR_ALL_TRACE_RESTRICT_SLOTS(slot
) {
451 if (slot
->owner
== owner
) {
452 *list
.Append() = slot
;
456 if (list
.Length() == 0) return nullptr;
459 list
.Sort(&SlotNameSorter
);
461 DropDownList
*dlist
= new DropDownList();
464 for (uint i
= 0; i
< list
.Length(); ++i
) {
465 const TraceRestrictSlot
*s
= list
[i
];
466 if (slot_id
== s
->index
) selected
= slot_id
;
467 DropDownListParamStringItem
*item
= new DropDownListParamStringItem(STR_TRACE_RESTRICT_SLOT_NAME
, s
->index
, false);
468 item
->SetParam(0, s
->index
);
469 *dlist
->Append() = item
;
475 static const StringID _cargo_cond_ops_str
[] = {
476 STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_CARGO_EQUALS
,
477 STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_CARGO_NOT_EQUALS
,
480 static const uint _cargo_cond_ops_val
[] = {
484 /** cargo conditional operators dropdown list set */
485 static const TraceRestrictDropDownListSet _cargo_cond_ops
= {
486 _cargo_cond_ops_str
, _cargo_cond_ops_val
,
489 static const StringID _slot_op_cond_ops_str
[] = {
490 STR_TRACE_RESTRICT_SLOT_ACQUIRE_WAIT
,
491 STR_TRACE_RESTRICT_SLOT_TRY_ACQUIRE
,
492 STR_TRACE_RESTRICT_SLOT_RELEASE_FRONT
,
493 STR_TRACE_RESTRICT_SLOT_RELEASE_BACK
,
496 static const uint _slot_op_cond_ops_val
[] = {
499 TRSCOF_RELEASE_FRONT
,
502 /** cargo conditional operators dropdown list set */
503 static const TraceRestrictDropDownListSet _slot_op_cond_ops
= {
504 _slot_op_cond_ops_str
, _slot_op_cond_ops_val
,
508 * Get the StringID for a given CargoID @p cargo, or STR_NEWGRF_INVALID_CARGO
510 static StringID
GetCargoStringByID(CargoID cargo
)
512 const CargoSpec
*cs
= CargoSpec::Get(cargo
);
513 return cs
->IsValid() ? cs
->name
: STR_NEWGRF_INVALID_CARGO
;
517 * Get the StringID for a given item type @p type
519 static StringID
GetTypeString(TraceRestrictItem item
)
521 TraceRestrictGuiItemType type
= GetItemGuiType(item
);
522 return GetDropDownStringByValue(GetTypeDropDownListSet(type
), type
);
526 * Get the conditional operator field drop down list set for a given type property set @p properties
528 static const TraceRestrictDropDownListSet
*GetCondOpDropDownListSet(TraceRestrictTypePropertySet properties
)
530 static const StringID str_long
[] = {
531 STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_EQUALS
,
532 STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_NOT_EQUALS
,
533 STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_LESS_THAN
,
534 STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_LESS_EQUALS
,
535 STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_MORE_THAN
,
536 STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_MORE_EQUALS
,
539 static const uint val_long
[] = {
547 static const TraceRestrictDropDownListSet set_long
= {
551 static const StringID str_short
[] = {
552 STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_EQUALS
,
553 STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_NOT_EQUALS
,
556 static const uint val_short
[] = {
560 static const TraceRestrictDropDownListSet set_short
= {
561 str_short
, val_short
,
564 if (properties
.value_type
== TRVT_CARGO_ID
) return &_cargo_cond_ops
;
566 switch (properties
.cond_type
) {
581 * Return true if item type field @p type is an integer value type
583 static bool IsIntegerValueType(TraceRestrictValueType type
)
596 * Convert integer values or custom penalty values between internal units and display units
598 static uint
ConvertIntegerValue(TraceRestrictValueType type
, uint in
, bool to_display
)
606 ? ConvertSpeedToDisplaySpeed(in
) * 10 / 16
607 : ConvertDisplaySpeedToSpeed(in
) * 16 / 10;
609 case TRVT_PF_PENALTY
:
618 /** String values for TraceRestrictCondFlags, value gives offset into array */
619 static const StringID _program_cond_type
[] = {
620 STR_TRACE_RESTRICT_CONDITIONAL_IF
, // TRCF_DEFAULT
621 STR_TRACE_RESTRICT_CONDITIONAL_ELIF
, // TRCF_ELSE
622 STR_TRACE_RESTRICT_CONDITIONAL_ORIF
, // TRCF_OR
625 /** condition flags field drop down value types */
626 enum CondFlagsDropDownType
{
627 CFDDT_ELSE
= 0, ///< This is an else block
628 CFDDT_ELIF
= TRCF_ELSE
, ///< This is an else-if block
629 CFDDT_ORIF
= TRCF_OR
, ///< This is an or-if block
632 static const uint32 _condflags_dropdown_else_hide_mask
= 1; ///< disable bitmask for CFDDT_ELSE
633 static const uint32 _condflags_dropdown_else_if_hide_mask
= 6; ///< disable bitmask for CFDDT_ELIF and CFDDT_ORIF
635 static const StringID _condflags_dropdown_str
[] = {
636 STR_TRACE_RESTRICT_CONDITIONAL_ELSE
,
637 STR_TRACE_RESTRICT_CONDITIONAL_ELIF
,
638 STR_TRACE_RESTRICT_CONDITIONAL_ORIF
,
641 static const uint _condflags_dropdown_val
[] = {
646 /** condition flags dropdown list set */
647 static const TraceRestrictDropDownListSet _condflags_dropdown
= {
648 _condflags_dropdown_str
, _condflags_dropdown_val
,
651 static const StringID _pf_penalty_dropdown_str
[] = {
652 STR_TRACE_RESTRICT_PF_VALUE_SMALL
,
653 STR_TRACE_RESTRICT_PF_VALUE_MEDIUM
,
654 STR_TRACE_RESTRICT_PF_VALUE_LARGE
,
655 STR_TRACE_RESTRICT_PF_VALUE_CUSTOM
,
658 static const uint _pf_penalty_dropdown_val
[] = {
662 TRPPPI_END
, // this is a placeholder for "custom"
664 /** Pathfinder penalty dropdown set */
665 static const TraceRestrictDropDownListSet _pf_penalty_dropdown
= {
666 _pf_penalty_dropdown_str
, _pf_penalty_dropdown_val
,
669 static uint
GetPathfinderPenaltyDropdownIndex(TraceRestrictItem item
)
671 switch (static_cast<TraceRestrictPathfinderPenaltyAuxField
>(GetTraceRestrictAuxField(item
))) {
675 case TRPPAF_PRESET
: {
676 uint16 index
= GetTraceRestrictValue(item
);
677 assert(index
< TRPPPI_END
);
686 /** Common function for drawing an ordinary conditional instruction */
687 static void DrawInstructionStringConditionalCommon(TraceRestrictItem item
, const TraceRestrictTypePropertySet
&properties
)
689 assert(GetTraceRestrictCondFlags(item
) <= TRCF_OR
);
690 SetDParam(0, _program_cond_type
[GetTraceRestrictCondFlags(item
)]);
691 SetDParam(1, GetTypeString(GetTraceRestrictType(item
)));
692 SetDParam(2, GetDropDownStringByValue(GetCondOpDropDownListSet(properties
), GetTraceRestrictCondOp(item
)));
695 /** Common function for drawing an integer conditional instruction */
696 static void DrawInstructionStringConditionalIntegerCommon(TraceRestrictItem item
, const TraceRestrictTypePropertySet
&properties
)
698 DrawInstructionStringConditionalCommon(item
, properties
);
699 SetDParam(3, GetTraceRestrictValue(item
));
702 /** Common function for drawing an integer conditional instruction with an invalid value */
703 static void DrawInstructionStringConditionalInvalidValue(TraceRestrictItem item
, const TraceRestrictTypePropertySet
&properties
, StringID
&instruction_string
, bool selected
)
705 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_UNDEFINED
;
706 DrawInstructionStringConditionalCommon(item
, properties
);
707 SetDParam(3, selected
? STR_TRACE_RESTRICT_WHITE
: STR_EMPTY
);
711 * Draws an instruction in the programming GUI
712 * @param prog The program (may be nullptr)
713 * @param item The instruction to draw
714 * @param index The instruction index
715 * @param y Y position for drawing
716 * @param selected True, if the order is selected
717 * @param indent How many levels the instruction is indented
718 * @param left Left border for text drawing
719 * @param right Right border for text drawing
721 static void DrawInstructionString(const TraceRestrictProgram
*prog
, TraceRestrictItem item
, int index
, int y
, bool selected
, int indent
, int left
, int right
)
723 StringID instruction_string
= INVALID_STRING_ID
;
725 TraceRestrictTypePropertySet properties
= GetTraceRestrictTypeProperties(item
);
727 if (IsTraceRestrictConditional(item
)) {
728 if (GetTraceRestrictType(item
) == TRIT_COND_ENDIF
) {
729 if (GetTraceRestrictCondFlags(item
) & TRCF_ELSE
) {
730 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_ELSE
;
732 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_ENDIF
;
734 } else if (GetTraceRestrictType(item
) == TRIT_COND_UNDEFINED
) {
735 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_COMPARE_UNDEFINED
;
736 SetDParam(0, _program_cond_type
[GetTraceRestrictCondFlags(item
)]);
737 SetDParam(1, selected
? STR_TRACE_RESTRICT_WHITE
: STR_EMPTY
);
739 switch (properties
.value_type
) {
741 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_COMPARE_INTEGER
;
742 DrawInstructionStringConditionalIntegerCommon(item
, properties
);
746 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_COMPARE_SPEED
;
747 DrawInstructionStringConditionalIntegerCommon(item
, properties
);
751 switch (static_cast<TraceRestrictOrderCondAuxField
>(GetTraceRestrictAuxField(item
))) {
753 if (GetTraceRestrictValue(item
) != INVALID_STATION
) {
754 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_ORDER_STATION
;
755 DrawInstructionStringConditionalIntegerCommon(item
, properties
);
757 // this is an invalid station, use a seperate string
758 DrawInstructionStringConditionalInvalidValue(item
, properties
, instruction_string
, selected
);
762 case TROCAF_WAYPOINT
:
763 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_ORDER_WAYPOINT
;
764 DrawInstructionStringConditionalIntegerCommon(item
, properties
);
768 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_ORDER_DEPOT
;
769 DrawInstructionStringConditionalCommon(item
, properties
);
770 SetDParam(3, VEH_TRAIN
);
771 SetDParam(4, GetTraceRestrictValue(item
));
782 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_CARGO
;
783 assert(GetTraceRestrictCondFlags(item
) <= TRCF_OR
);
784 SetDParam(0, _program_cond_type
[GetTraceRestrictCondFlags(item
)]);
785 SetDParam(1, GetDropDownStringByValue(&_cargo_cond_ops
, GetTraceRestrictCondOp(item
)));
786 SetDParam(2, GetCargoStringByID(GetTraceRestrictValue(item
)));
790 if (GetTraceRestrictValue(item
) >= TRDTSV_FRONT
) {
791 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_ENTRY_SIGNAL_FACE
;
793 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_ENTRY_DIRECTION
;
795 SetDParam(0, _program_cond_type
[GetTraceRestrictCondFlags(item
)]);
796 SetDParam(1, GetDropDownStringByValue(GetCondOpDropDownListSet(properties
), GetTraceRestrictCondOp(item
)));
797 SetDParam(2, GetDropDownStringByValue(&_direction_value
, GetTraceRestrictValue(item
)));
800 case TRVT_TILE_INDEX
: {
801 assert(prog
!= nullptr);
802 assert(GetTraceRestrictType(item
) == TRIT_COND_PBS_ENTRY_SIGNAL
);
803 TileIndex tile
= *(TraceRestrictProgram::InstructionAt(prog
->items
, index
- 1) + 1);
804 if (tile
== INVALID_TILE
) {
805 DrawInstructionStringConditionalInvalidValue(item
, properties
, instruction_string
, selected
);
807 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_TILE_INDEX
;
808 SetDParam(0, _program_cond_type
[GetTraceRestrictCondFlags(item
)]);
809 SetDParam(1, STR_TRACE_RESTRICT_VARIABLE_PBS_ENTRY_SIGNAL_LONG
);
810 SetDParam(2, GetDropDownStringByValue(GetCondOpDropDownListSet(properties
), GetTraceRestrictCondOp(item
)));
811 SetDParam(3, TileX(tile
));
812 SetDParam(4, TileY(tile
));
817 case TRVT_GROUP_INDEX
: {
818 assert(GetTraceRestrictCondFlags(item
) <= TRCF_OR
);
819 SetDParam(0, _program_cond_type
[GetTraceRestrictCondFlags(item
)]);
820 SetDParam(1, GetDropDownStringByValue(GetCondOpDropDownListSet(properties
), GetTraceRestrictCondOp(item
)));
821 if (GetTraceRestrictValue(item
) == INVALID_GROUP
) {
822 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_GROUP_STR
;
823 SetDParam(2, STR_TRACE_RESTRICT_VARIABLE_UNDEFINED_RED
);
824 SetDParam(3, selected
? STR_TRACE_RESTRICT_WHITE
: STR_EMPTY
);
825 } else if (GetTraceRestrictValue(item
) == DEFAULT_GROUP
) {
826 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_GROUP_STR
;
827 SetDParam(2, STR_GROUP_DEFAULT_TRAINS
);
828 SetDParam(3, selected
? STR_TRACE_RESTRICT_WHITE
: STR_EMPTY
);
830 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_GROUP
;
831 SetDParam(2, GetTraceRestrictValue(item
));
836 case TRVT_SLOT_INDEX
:
837 SetDParam(0, _program_cond_type
[GetTraceRestrictCondFlags(item
)]);
838 SetDParam(1, GetDropDownStringByValue(GetCondOpDropDownListSet(properties
), GetTraceRestrictCondOp(item
)));
839 if (GetTraceRestrictValue(item
) == INVALID_TRACE_RESTRICT_SLOT_ID
) {
840 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_SLOT_STR
;
841 SetDParam(2, STR_TRACE_RESTRICT_VARIABLE_UNDEFINED_RED
);
842 SetDParam(3, selected
? STR_TRACE_RESTRICT_WHITE
: STR_EMPTY
);
844 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_SLOT
;
845 SetDParam(2, GetTraceRestrictValue(item
));
849 case TRVT_SLOT_INDEX_INT
: {
850 assert(prog
!= nullptr);
851 assert(GetTraceRestrictType(item
) == TRIT_COND_SLOT_OCCUPANCY
);
852 uint32 value
= *(TraceRestrictProgram::InstructionAt(prog
->items
, index
- 1) + 1);
853 SetDParam(0, _program_cond_type
[GetTraceRestrictCondFlags(item
)]);
854 SetDParam(1, GetTraceRestrictAuxField(item
) ? STR_TRACE_RESTRICT_VARIABLE_SLOT_OCCUPANCY_REMAINING_SHORT
: STR_TRACE_RESTRICT_VARIABLE_SLOT_OCCUPANCY_SHORT
);
855 if (GetTraceRestrictValue(item
) == INVALID_TRACE_RESTRICT_SLOT_ID
) {
856 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_SLOT_OCCUPANCY_STR
;
857 SetDParam(2, STR_TRACE_RESTRICT_VARIABLE_UNDEFINED_RED
);
858 SetDParam(3, selected
? STR_TRACE_RESTRICT_WHITE
: STR_EMPTY
);
859 SetDParam(4, GetDropDownStringByValue(GetCondOpDropDownListSet(properties
), GetTraceRestrictCondOp(item
)));
862 instruction_string
= STR_TRACE_RESTRICT_CONDITIONAL_SLOT_OCCUPANCY
;
863 SetDParam(2, GetTraceRestrictValue(item
));
864 SetDParam(3, GetDropDownStringByValue(GetCondOpDropDownListSet(properties
), GetTraceRestrictCondOp(item
)));
876 switch (GetTraceRestrictType(item
)) {
878 switch (GetTraceRestrictValue(item
)) {
880 instruction_string
= STR_TRACE_RESTRICT_START
;
884 instruction_string
= STR_TRACE_RESTRICT_END
;
894 instruction_string
= GetTraceRestrictValue(item
) ? STR_TRACE_RESTRICT_PF_ALLOW_LONG
: STR_TRACE_RESTRICT_PF_DENY
;
897 case TRIT_PF_PENALTY
:
898 switch (static_cast<TraceRestrictPathfinderPenaltyAuxField
>(GetTraceRestrictAuxField(item
))) {
900 instruction_string
= STR_TRACE_RESTRICT_PF_PENALTY_ITEM
;
901 SetDParam(0, GetTraceRestrictValue(item
));
904 case TRPPAF_PRESET
: {
905 instruction_string
= STR_TRACE_RESTRICT_PF_PENALTY_ITEM_PRESET
;
906 uint16 index
= GetTraceRestrictValue(item
);
907 assert(index
< TRPPPI_END
);
908 SetDParam(0, _pf_penalty_dropdown_str
[index
]);
917 case TRIT_RESERVE_THROUGH
:
918 instruction_string
= GetTraceRestrictValue(item
) ? STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL
: STR_TRACE_RESTRICT_RESERVE_THROUGH
;
921 case TRIT_LONG_RESERVE
:
922 instruction_string
= GetTraceRestrictValue(item
) ? STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL
: STR_TRACE_RESTRICT_LONG_RESERVE
;
925 case TRIT_WAIT_AT_PBS
:
926 instruction_string
= GetTraceRestrictValue(item
) ? STR_TRACE_RESTRICT_WAIT_AT_PBS_CANCEL
: STR_TRACE_RESTRICT_WAIT_AT_PBS
;
930 switch (static_cast<TraceRestrictSlotCondOpField
>(GetTraceRestrictCondOp(item
))) {
931 case TRSCOF_ACQUIRE_WAIT
:
932 instruction_string
= STR_TRACE_RESTRICT_SLOT_ACQUIRE_WAIT_ITEM
;
935 case TRSCOF_ACQUIRE_TRY
:
936 instruction_string
= STR_TRACE_RESTRICT_SLOT_TRY_ACQUIRE_ITEM
;
939 case TRSCOF_RELEASE_BACK
:
940 instruction_string
= STR_TRACE_RESTRICT_SLOT_RELEASE_BACK_ITEM
;
943 case TRSCOF_RELEASE_FRONT
:
944 instruction_string
= STR_TRACE_RESTRICT_SLOT_RELEASE_FRONT_ITEM
;
951 if (GetTraceRestrictValue(item
) == INVALID_TRACE_RESTRICT_SLOT_ID
) {
952 SetDParam(0, STR_TRACE_RESTRICT_VARIABLE_UNDEFINED_RED
);
954 SetDParam(0, STR_TRACE_RESTRICT_SLOT_NAME
);
955 SetDParam(1, GetTraceRestrictValue(item
));
957 SetDParam(2, selected
? STR_TRACE_RESTRICT_WHITE
: STR_EMPTY
);
966 DrawString(left
+ indent
* 16, right
, y
, instruction_string
, selected
? TC_WHITE
: TC_BLACK
);
969 /** Main GUI window class */
970 class TraceRestrictWindow
: public Window
{
971 TileIndex tile
; ///< tile this window is for
972 Track track
; ///< track this window is for
973 int selected_instruction
; ///< selected instruction index, this is offset by one due to the display of the "start" item
974 Scrollbar
*vscroll
; ///< scrollbar widget
975 std::map
<int, const TraceRestrictDropDownListSet
*> drop_down_list_mapping
; ///< mapping of widget IDs to drop down list sets
976 TraceRestrictItem expecting_inserted_item
; ///< set to instruction when performing an instruction insertion, used to handle selection update on insertion
977 int current_placement_widget
; ///< which widget has a SetObjectToPlaceWnd, if any
978 int current_left_aux_plane
; ///< current plane for TR_WIDGET_SEL_TOP_LEFT_AUX widget
981 TraceRestrictWindow(WindowDesc
*desc
, TileIndex tile
, Track track
)
986 this->selected_instruction
= -1;
987 this->expecting_inserted_item
= static_cast<TraceRestrictItem
>(0);
988 this->current_placement_widget
= -1;
990 this->CreateNestedTree();
991 this->vscroll
= this->GetScrollbar(TR_WIDGET_SCROLLBAR
);
992 this->GetWidget
<NWidgetStacked
>(TR_WIDGET_SEL_TOP_LEFT_AUX
)->SetDisplayedPlane(SZSP_NONE
);
993 this->current_left_aux_plane
= SZSP_NONE
;
994 this->FinishInitNested(MakeTraceRestrictRefId(tile
, track
));
996 this->ReloadProgramme();
999 virtual void OnClick(Point pt
, int widget
, int click_count
)
1002 case TR_WIDGET_INSTRUCTION_LIST
: {
1003 int sel
= this->GetItemIndexFromPt(pt
.y
);
1005 if (_ctrl_pressed
) {
1006 // scroll to target (for stations, waypoints, depots)
1008 if (sel
== -1) return;
1010 TraceRestrictItem item
= this->GetItem(this->GetProgram(), sel
);
1011 if (GetTraceRestrictTypeProperties(item
).value_type
== TRVT_ORDER
) {
1012 switch (static_cast<TraceRestrictOrderCondAuxField
>(GetTraceRestrictAuxField(item
))) {
1013 case TROCAF_STATION
:
1014 case TROCAF_WAYPOINT
: {
1015 BaseStation
*st
= BaseStation::GetIfValid(GetTraceRestrictValue(item
));
1017 ScrollMainWindowToTile(st
->xy
);
1022 case TROCAF_DEPOT
: {
1023 Depot
*depot
= Depot::GetIfValid(GetTraceRestrictValue(item
));
1025 ScrollMainWindowToTile(depot
->xy
);
1030 } else if (GetTraceRestrictTypeProperties(item
).value_type
== TRVT_TILE_INDEX
) {
1031 TileIndex tile
= *(TraceRestrictProgram::InstructionAt(this->GetProgram()->items
, sel
- 1) + 1);
1032 if (tile
!= INVALID_TILE
) {
1033 ScrollMainWindowToTile(tile
);
1039 this->DeleteChildWindows();
1040 HideDropDownMenu(this);
1042 if (sel
== -1 || this->GetOwner() != _local_company
) {
1044 this->selected_instruction
= -1;
1046 this->selected_instruction
= sel
;
1049 this->expecting_inserted_item
= static_cast<TraceRestrictItem
>(0);
1051 this->UpdateButtonState();
1055 case TR_WIDGET_INSERT
: {
1056 if (this->GetOwner() != _local_company
|| this->selected_instruction
< 1) {
1060 uint32 disabled
= _program_insert_or_if_hide_mask
;
1061 TraceRestrictItem item
= this->GetSelected();
1062 if (GetTraceRestrictType(item
) == TRIT_COND_ENDIF
||
1063 (IsTraceRestrictConditional(item
) && GetTraceRestrictCondFlags(item
) != 0)) {
1064 // this is either: an else/or if, an else, or an end if
1065 // try to include else if, else in insertion list
1066 if (!ElseInsertionDryRun(false)) disabled
|= _program_insert_else_hide_mask
;
1067 if (!ElseIfInsertionDryRun(false)) disabled
|= _program_insert_else_if_hide_mask
;
1069 // can't insert else/end if here
1070 disabled
|= _program_insert_else_hide_mask
| _program_insert_else_if_hide_mask
;
1072 if (this->selected_instruction
> 1) {
1073 TraceRestrictItem prev_item
= this->GetItem(this->GetProgram(), this->selected_instruction
- 1);
1074 if (IsTraceRestrictConditional(prev_item
) && GetTraceRestrictType(prev_item
) != TRIT_COND_ENDIF
) {
1075 // previous item is either: an if, or an else/or if
1077 // else if has same validation rules as or if, use it instead of creating another test function
1078 if (ElseIfInsertionDryRun(false)) disabled
&= ~_program_insert_or_if_hide_mask
;
1082 this->ShowDropDownListWithValue(&_program_insert
, 0, true, TR_WIDGET_INSERT
, disabled
, 0, 0);
1086 case TR_WIDGET_REMOVE
: {
1087 TraceRestrictItem item
= this->GetSelected();
1088 if (this->GetOwner() != _local_company
|| item
== 0) {
1092 TraceRestrictDoCommandP(tile
, track
, _ctrl_pressed
? TRDCT_SHALLOW_REMOVE_ITEM
: TRDCT_REMOVE_ITEM
,
1093 this->selected_instruction
- 1, 0, STR_TRACE_RESTRICT_ERROR_CAN_T_REMOVE_ITEM
);
1097 case TR_WIDGET_UP_BTN
:
1098 case TR_WIDGET_DOWN_BTN
: {
1099 TraceRestrictItem item
= this->GetSelected();
1100 if (this->GetOwner() != _local_company
|| item
== 0) {
1105 if (widget
== TR_WIDGET_UP_BTN
) p2
|= 1;
1106 if (_ctrl_pressed
) p2
|= 2;
1108 uint32 offset
= this->selected_instruction
- 1;
1110 this->IsUpDownBtnUsable(widget
== TR_WIDGET_UP_BTN
, true);
1112 TraceRestrictDoCommandP(tile
, track
, TRDCT_MOVE_ITEM
,
1113 offset
, p2
, STR_TRACE_RESTRICT_ERROR_CAN_T_MOVE_ITEM
);
1117 case TR_WIDGET_CONDFLAGS
: {
1118 TraceRestrictItem item
= this->GetSelected();
1119 if (this->GetOwner() != _local_company
|| item
== 0) {
1123 CondFlagsDropDownType type
;
1124 if (GetTraceRestrictType(item
) == TRIT_COND_ENDIF
) {
1125 if (GetTraceRestrictCondFlags(item
) == 0) return; // end if
1127 } else if (IsTraceRestrictConditional(item
) && GetTraceRestrictCondFlags(item
) != 0) {
1128 type
= static_cast<CondFlagsDropDownType
>(GetTraceRestrictCondFlags(item
));
1133 uint32 disabled
= 0;
1134 if (!ElseInsertionDryRun(true)) disabled
|= _condflags_dropdown_else_hide_mask
;
1135 if (!ElseIfInsertionDryRun(true)) disabled
|= _condflags_dropdown_else_if_hide_mask
;
1137 this->ShowDropDownListWithValue(&_condflags_dropdown
, type
, false, TR_WIDGET_CONDFLAGS
, disabled
, 0, 0);
1141 case TR_WIDGET_TYPE_COND
:
1142 case TR_WIDGET_TYPE_NONCOND
: {
1143 TraceRestrictItem item
= this->GetSelected();
1144 TraceRestrictGuiItemType type
= GetItemGuiType(item
);
1146 if (type
!= TRIT_NULL
) {
1147 uint32 hide_mask
= 0;
1148 const TraceRestrictDropDownListSet
*set
= GetTypeDropDownListSet(type
, &hide_mask
);
1149 this->ShowDropDownListWithValue(set
, type
, false, widget
, 0, hide_mask
, 0);
1155 case TR_WIDGET_COMPARATOR
: {
1156 TraceRestrictItem item
= this->GetSelected();
1157 const TraceRestrictDropDownListSet
*list_set
= GetCondOpDropDownListSet(GetTraceRestrictTypeProperties(item
));
1159 this->ShowDropDownListWithValue(list_set
, GetTraceRestrictCondOp(item
), false, TR_WIDGET_COMPARATOR
, 0, 0, 0);
1164 case TR_WIDGET_SLOT_OP
: {
1165 TraceRestrictItem item
= this->GetSelected();
1166 this->ShowDropDownListWithValue(&_slot_op_cond_ops
, GetTraceRestrictCondOp(item
), false, TR_WIDGET_SLOT_OP
, 0, 0, 0);
1170 case TR_WIDGET_VALUE_INT
: {
1171 TraceRestrictItem item
= this->GetSelected();
1172 TraceRestrictValueType type
= GetTraceRestrictTypeProperties(item
).value_type
;
1173 if (IsIntegerValueType(type
)) {
1174 SetDParam(0, ConvertIntegerValue(type
, GetTraceRestrictValue(item
), true));
1175 ShowQueryString(STR_JUST_INT
, STR_TRACE_RESTRICT_VALUE_CAPTION
, 10, this, CS_NUMERAL
, QSF_NONE
);
1177 else if (type
== TRVT_SLOT_INDEX_INT
) {
1178 SetDParam(0, *(TraceRestrictProgram::InstructionAt(this->GetProgram()->items
, this->selected_instruction
- 1) + 1));
1179 ShowQueryString(STR_JUST_INT
, STR_TRACE_RESTRICT_VALUE_CAPTION
, 10, this, CS_NUMERAL
, QSF_NONE
);
1184 case TR_WIDGET_VALUE_DROPDOWN
: {
1185 TraceRestrictItem item
= this->GetSelected();
1186 switch (GetTraceRestrictTypeProperties(item
).value_type
) {
1188 this->ShowDropDownListWithValue(&_deny_value
, GetTraceRestrictValue(item
), false, TR_WIDGET_VALUE_DROPDOWN
, 0, 0, 0);
1192 this->ShowDropDownListWithValue(GetSortedCargoTypeDropDownListSet(), GetTraceRestrictValue(item
), true, TR_WIDGET_VALUE_DROPDOWN
, 0, 0, 0); // current cargo is permitted to not be in list
1195 case TRVT_DIRECTION
:
1196 this->ShowDropDownListWithValue(&_direction_value
, GetTraceRestrictValue(item
), false, TR_WIDGET_VALUE_DROPDOWN
, 0, 0, 0);
1199 case TRVT_PF_PENALTY
:
1200 this->ShowDropDownListWithValue(&_pf_penalty_dropdown
, GetPathfinderPenaltyDropdownIndex(item
), false, TR_WIDGET_VALUE_DROPDOWN
, 0, 0, 0);
1203 case TRVT_RESERVE_THROUGH
:
1204 this->ShowDropDownListWithValue(&_reserve_through_value
, GetTraceRestrictValue(item
), false, TR_WIDGET_VALUE_DROPDOWN
, 0, 0, 0);
1207 case TRVT_LONG_RESERVE
:
1208 this->ShowDropDownListWithValue(&_long_reserve_value
, GetTraceRestrictValue(item
), false, TR_WIDGET_VALUE_DROPDOWN
, 0, 0, 0);
1211 case TRVT_WAIT_AT_PBS
:
1212 this->ShowDropDownListWithValue(&_wait_at_pbs_value
, GetTraceRestrictValue(item
), false, TR_WIDGET_VALUE_DROPDOWN
, 0, 0, 0);
1215 case TRVT_GROUP_INDEX
: {
1217 DropDownList
*dlist
= GetGroupDropDownList(this->GetOwner(), GetTraceRestrictValue(item
), selected
);
1218 ShowDropDownList(this, dlist
, selected
, TR_WIDGET_VALUE_DROPDOWN
);
1222 case TRVT_SLOT_INDEX
: {
1224 DropDownList
*dlist
= GetSlotDropDownList(this->GetOwner(), GetTraceRestrictValue(item
), selected
);
1225 if (dlist
!= nullptr) ShowDropDownList(this, dlist
, selected
, TR_WIDGET_VALUE_DROPDOWN
);
1235 case TR_WIDGET_LEFT_AUX_DROPDOWN
: {
1236 TraceRestrictItem item
= this->GetSelected();
1237 switch (GetTraceRestrictTypeProperties(item
).value_type
) {
1238 case TRVT_SLOT_INDEX_INT
: {
1240 DropDownList
*dlist
= GetSlotDropDownList(this->GetOwner(),
1241 *(TraceRestrictProgram::InstructionAt(this->GetProgram()->items
, this->selected_instruction
- 1) + 1), selected
);
1242 if (dlist
!= nullptr) ShowDropDownList(this, dlist
, selected
, TR_WIDGET_LEFT_AUX_DROPDOWN
);
1251 case TR_WIDGET_VALUE_DEST
: {
1252 SetObjectToPlaceAction(widget
, ANIMCURSOR_PICKSTATION
);
1256 case TR_WIDGET_VALUE_SIGNAL
: {
1257 SetObjectToPlaceAction(widget
, ANIMCURSOR_BUILDSIGNALS
);
1261 case TR_WIDGET_GOTO_SIGNAL
: {
1262 ScrollMainWindowToTile(this->tile
);
1263 this->UpdateButtonState();
1267 case TR_WIDGET_RESET
: {
1268 TraceRestrictProgMgmtDoCommandP(tile
, track
, TRDCT_PROG_RESET
, STR_TRACE_RESTRICT_ERROR_CAN_T_RESET_SIGNAL
);
1272 case TR_WIDGET_COPY
:
1273 case TR_WIDGET_COPY_APPEND
:
1274 case TR_WIDGET_SHARE
:
1275 SetObjectToPlaceAction(widget
, ANIMCURSOR_BUILDSIGNALS
);
1278 case TR_WIDGET_UNSHARE
: {
1279 TraceRestrictProgMgmtDoCommandP(tile
, track
, TRDCT_PROG_UNSHARE
, STR_TRACE_RESTRICT_ERROR_CAN_T_UNSHARE_PROGRAM
);
1285 virtual void OnQueryTextFinished(char *str
)
1287 if (StrEmpty(str
)) {
1291 TraceRestrictItem item
= GetSelected();
1292 TraceRestrictValueType type
= GetTraceRestrictTypeProperties(item
).value_type
;
1295 if (IsIntegerValueType(type
) || type
== TRVT_PF_PENALTY
) {
1296 value
= ConvertIntegerValue(type
, atoi(str
), false);
1297 if (value
>= (1 << TRIFA_VALUE_COUNT
)) {
1298 SetDParam(0, ConvertIntegerValue(type
, (1 << TRIFA_VALUE_COUNT
) - 1, true));
1299 ShowErrorMessage(STR_TRACE_RESTRICT_ERROR_VALUE_TOO_LARGE
, STR_EMPTY
, WL_INFO
);
1303 if (type
== TRVT_PF_PENALTY
) {
1304 SetTraceRestrictAuxField(item
, TRPPAF_VALUE
);
1306 } else if (type
== TRVT_SLOT_INDEX_INT
) {
1308 TraceRestrictDoCommandP(this->tile
, this->track
, TRDCT_MODIFY_DUAL_ITEM
, this->selected_instruction
- 1, value
, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM
);
1314 SetTraceRestrictValue(item
, value
);
1315 TraceRestrictDoCommandP(tile
, track
, TRDCT_MODIFY_ITEM
, this->selected_instruction
- 1, item
, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM
);
1318 virtual void OnDropdownSelect(int widget
, int index
)
1320 TraceRestrictItem item
= GetSelected();
1321 if (item
== 0 || index
< 0 || this->selected_instruction
< 1) {
1325 if (widget
== TR_WIDGET_VALUE_DROPDOWN
|| widget
== TR_WIDGET_LEFT_AUX_DROPDOWN
) {
1326 TraceRestrictTypePropertySet type
= GetTraceRestrictTypeProperties(item
);
1327 if (type
.value_type
== TRVT_GROUP_INDEX
|| type
.value_type
== TRVT_SLOT_INDEX
|| type
.value_type
== TRVT_SLOT_INDEX_INT
) {
1328 SetTraceRestrictValue(item
, index
);
1329 TraceRestrictDoCommandP(this->tile
, this->track
, TRDCT_MODIFY_ITEM
, this->selected_instruction
- 1, item
, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM
);
1334 const TraceRestrictDropDownListSet
*list_set
= this->drop_down_list_mapping
[widget
];
1339 uint value
= list_set
->value_array
[index
];
1342 case TR_WIDGET_INSERT
: {
1343 TraceRestrictItem insert_item
= 0;
1345 TraceRestrictCondFlags cond_flags
= static_cast<TraceRestrictCondFlags
>(value
>> 16);
1347 SetTraceRestrictTypeAndNormalise(insert_item
, static_cast<TraceRestrictItemType
>(value
));
1348 SetTraceRestrictCondFlags(insert_item
, cond_flags
); // this needs to happen after calling SetTraceRestrictTypeAndNormalise
1350 this->expecting_inserted_item
= insert_item
;
1351 TraceRestrictDoCommandP(this->tile
, this->track
, TRDCT_INSERT_ITEM
, this->selected_instruction
- 1, insert_item
, STR_TRACE_RESTRICT_ERROR_CAN_T_INSERT_ITEM
);
1355 case TR_WIDGET_CONDFLAGS
: {
1356 CondFlagsDropDownType cond_type
= static_cast<CondFlagsDropDownType
>(value
);
1357 if (cond_type
== CFDDT_ELSE
) {
1358 SetTraceRestrictTypeAndNormalise(item
, TRIT_COND_ENDIF
);
1359 SetTraceRestrictCondFlags(item
, TRCF_ELSE
);
1361 if (GetTraceRestrictType(item
) == TRIT_COND_ENDIF
) {
1362 // item is currently an else, convert to else/or if
1363 SetTraceRestrictTypeAndNormalise(item
, TRIT_COND_UNDEFINED
);
1366 SetTraceRestrictCondFlags(item
, static_cast<TraceRestrictCondFlags
>(cond_type
));
1369 TraceRestrictDoCommandP(this->tile
, this->track
, TRDCT_MODIFY_ITEM
, this->selected_instruction
- 1, item
, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM
);
1373 case TR_WIDGET_TYPE_COND
:
1374 case TR_WIDGET_TYPE_NONCOND
: {
1375 SetTraceRestrictTypeAndNormalise(item
, static_cast<TraceRestrictItemType
>(value
& 0xFFFF), value
>> 16);
1376 TraceRestrictDoCommandP(this->tile
, this->track
, TRDCT_MODIFY_ITEM
, this->selected_instruction
- 1, item
, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM
);
1380 case TR_WIDGET_COMPARATOR
:
1381 case TR_WIDGET_SLOT_OP
: {
1382 SetTraceRestrictCondOp(item
, static_cast<TraceRestrictCondOp
>(value
));
1383 TraceRestrictDoCommandP(this->tile
, this->track
, TRDCT_MODIFY_ITEM
, this->selected_instruction
- 1, item
, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM
);
1387 case TR_WIDGET_VALUE_DROPDOWN
: {
1388 if (GetTraceRestrictTypeProperties(item
).value_type
== TRVT_PF_PENALTY
) {
1389 if (value
== TRPPPI_END
) {
1390 uint16 penalty_value
;
1391 if (GetTraceRestrictAuxField(item
) == TRPPAF_PRESET
) {
1392 penalty_value
= _tracerestrict_pathfinder_penalty_preset_values
[GetTraceRestrictValue(item
)];
1394 penalty_value
= GetTraceRestrictValue(item
);
1396 SetDParam(0, penalty_value
);
1397 ShowQueryString(STR_JUST_INT
, STR_TRACE_RESTRICT_VALUE_CAPTION
, 10, this, CS_NUMERAL
, QSF_NONE
);
1400 SetTraceRestrictValue(item
, value
);
1401 SetTraceRestrictAuxField(item
, TRPPAF_PRESET
);
1404 SetTraceRestrictValue(item
, value
);
1406 TraceRestrictDoCommandP(this->tile
, this->track
, TRDCT_MODIFY_ITEM
, this->selected_instruction
- 1, item
, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM
);
1412 virtual void OnPlaceObject(Point pt
, TileIndex tile
)
1414 int widget
= this->current_placement_widget
;
1415 this->current_placement_widget
= -1;
1417 this->RaiseButtons();
1418 ResetObjectToPlace();
1425 case TR_WIDGET_COPY
:
1426 OnPlaceObjectSignal(pt
, tile
, widget
, STR_TRACE_RESTRICT_ERROR_CAN_T_COPY_PROGRAM
);
1429 case TR_WIDGET_COPY_APPEND
:
1430 OnPlaceObjectSignal(pt
, tile
, widget
, STR_TRACE_RESTRICT_ERROR_CAN_T_COPY_APPEND_PROGRAM
);
1433 case TR_WIDGET_SHARE
:
1434 OnPlaceObjectSignal(pt
, tile
, widget
, STR_TRACE_RESTRICT_ERROR_CAN_T_SHARE_PROGRAM
);
1437 case TR_WIDGET_VALUE_DEST
:
1438 OnPlaceObjectDestination(pt
, tile
, widget
, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM
);
1441 case TR_WIDGET_VALUE_SIGNAL
:
1442 OnPlaceObjectSignalTileValue(pt
, tile
, widget
, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM
);
1452 * Common OnPlaceObject handler for program management actions which involve clicking on a signal
1454 void OnPlaceObjectSignal(Point pt
, TileIndex source_tile
, int widget
, int error_message
)
1456 if (!IsPlainRailTile(source_tile
)) {
1457 ShowErrorMessage(error_message
, STR_ERROR_THERE_IS_NO_RAILROAD_TRACK
, WL_INFO
);
1461 TrackBits trackbits
= TrackStatusToTrackBits(GetTileTrackStatus(source_tile
, TRANSPORT_RAIL
, 0));
1462 if (trackbits
& TRACK_BIT_VERT
) { // N-S direction
1463 trackbits
= (_tile_fract_coords
.x
<= _tile_fract_coords
.y
) ? TRACK_BIT_RIGHT
: TRACK_BIT_LEFT
;
1466 if (trackbits
& TRACK_BIT_HORZ
) { // E-W direction
1467 trackbits
= (_tile_fract_coords
.x
+ _tile_fract_coords
.y
<= 15) ? TRACK_BIT_UPPER
: TRACK_BIT_LOWER
;
1469 Track source_track
= FindFirstTrack(trackbits
);
1470 if(source_track
== INVALID_TRACK
) {
1471 ShowErrorMessage(error_message
, STR_ERROR_THERE_IS_NO_RAILROAD_TRACK
, WL_INFO
);
1475 if (!HasTrack(source_tile
, source_track
)) {
1476 ShowErrorMessage(error_message
, STR_ERROR_THERE_IS_NO_RAILROAD_TRACK
, WL_INFO
);
1480 if (!HasSignalOnTrack(source_tile
, source_track
)) {
1481 ShowErrorMessage(error_message
, STR_ERROR_THERE_ARE_NO_SIGNALS
, WL_INFO
);
1486 case TR_WIDGET_COPY
:
1487 TraceRestrictProgMgmtWithSourceDoCommandP(this->tile
, this->track
, TRDCT_PROG_COPY
,
1488 source_tile
, source_track
, STR_TRACE_RESTRICT_ERROR_CAN_T_COPY_PROGRAM
);
1491 case TR_WIDGET_COPY_APPEND
:
1492 TraceRestrictProgMgmtWithSourceDoCommandP(this->tile
, this->track
, TRDCT_PROG_COPY_APPEND
,
1493 source_tile
, source_track
, STR_TRACE_RESTRICT_ERROR_CAN_T_COPY_APPEND_PROGRAM
);
1496 case TR_WIDGET_SHARE
:
1497 TraceRestrictProgMgmtWithSourceDoCommandP(this->tile
, this->track
, TRDCT_PROG_SHARE
,
1498 source_tile
, source_track
, STR_TRACE_RESTRICT_ERROR_CAN_T_SHARE_PROGRAM
);
1508 * Common OnPlaceObject handler for instruction value modification actions which involve selecting an order target
1510 void OnPlaceObjectDestination(Point pt
, TileIndex tile
, int widget
, int error_message
)
1512 TraceRestrictItem item
= GetSelected();
1513 if (GetTraceRestrictTypeProperties(item
).value_type
!= TRVT_ORDER
) return;
1515 bool stations_only
= (GetTraceRestrictType(item
) == TRIT_COND_LAST_STATION
);
1517 if (IsDepotTypeTile(tile
, TRANSPORT_RAIL
)) {
1518 if (stations_only
) return;
1519 SetTraceRestrictValue(item
, GetDepotIndex(tile
));
1520 SetTraceRestrictAuxField(item
, TROCAF_DEPOT
);
1521 } else if (IsRailWaypointTile(tile
)) {
1522 if (stations_only
) return;
1523 SetTraceRestrictValue(item
, GetStationIndex(tile
));
1524 SetTraceRestrictAuxField(item
, TROCAF_WAYPOINT
);
1525 } else if (IsTileType(tile
, MP_STATION
)) {
1526 StationID st_index
= GetStationIndex(tile
);
1527 const Station
*st
= Station::Get(st_index
);
1528 if (st
->facilities
& FACIL_TRAIN
) {
1529 SetTraceRestrictValue(item
, st_index
);
1530 SetTraceRestrictAuxField(item
, TROCAF_STATION
);
1538 if (!IsTileOwner(tile
, _local_company
)) {
1539 ShowErrorMessage(error_message
, STR_ERROR_AREA_IS_OWNED_BY_ANOTHER
, WL_INFO
);
1543 TraceRestrictDoCommandP(this->tile
, this->track
, TRDCT_MODIFY_ITEM
, this->selected_instruction
- 1, item
, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM
);
1547 * Common OnPlaceObject handler for instruction value modification actions which involve selecting a signal tile value
1549 void OnPlaceObjectSignalTileValue(Point pt
, TileIndex tile
, int widget
, int error_message
)
1551 TraceRestrictItem item
= GetSelected();
1552 if (GetTraceRestrictTypeProperties(item
).value_type
!= TRVT_TILE_INDEX
) return;
1554 if (!IsTileOwner(tile
, _local_company
)) {
1555 ShowErrorMessage(error_message
, STR_ERROR_AREA_IS_OWNED_BY_ANOTHER
, WL_INFO
);
1558 if (IsRailDepotTile(tile
)) {
1561 if (!IsPlainRailTile(tile
)) {
1562 ShowErrorMessage(error_message
, STR_ERROR_THERE_IS_NO_RAILROAD_TRACK
, WL_INFO
);
1565 if (GetPresentSignals(tile
) == 0) {
1566 ShowErrorMessage(error_message
, STR_ERROR_THERE_ARE_NO_SIGNALS
, WL_INFO
);
1571 TraceRestrictDoCommandP(this->tile
, this->track
, TRDCT_MODIFY_DUAL_ITEM
, this->selected_instruction
- 1, tile
, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM
);
1574 virtual void OnPlaceObjectAbort()
1576 this->RaiseButtons();
1577 this->current_placement_widget
= -1;
1580 virtual void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
)
1583 case TR_WIDGET_INSTRUCTION_LIST
:
1584 resize
->height
= FONT_HEIGHT_NORMAL
;
1585 size
->height
= 6 * resize
->height
+ WD_FRAMERECT_TOP
+ WD_FRAMERECT_BOTTOM
;
1590 virtual void OnResize()
1592 /* Update the scroll bar */
1593 this->vscroll
->SetCapacityFromWidget(this, TR_WIDGET_INSTRUCTION_LIST
);
1596 virtual void OnPaint()
1598 this->DrawWidgets();
1601 virtual void DrawWidget(const Rect
&r
, int widget
) const
1603 if (widget
!= TR_WIDGET_INSTRUCTION_LIST
) return;
1605 int y
= r
.top
+ WD_FRAMERECT_TOP
;
1606 int line_height
= this->GetWidget
<NWidgetBase
>(TR_WIDGET_INSTRUCTION_LIST
)->resize_y
;
1607 int scroll_position
= this->vscroll
->GetPosition();
1609 // prog may be nullptr
1610 const TraceRestrictProgram
*prog
= this->GetProgram();
1612 int count
= this->GetItemCount(prog
);
1614 for(int i
= 0; i
< count
; i
++) {
1615 TraceRestrictItem item
= this->GetItem(prog
, i
);
1616 uint this_indent
= indent
;
1617 if (IsTraceRestrictConditional(item
)) {
1618 if (GetTraceRestrictCondFlags(item
) & (TRCF_ELSE
| TRCF_OR
)) {
1620 } else if (GetTraceRestrictType(item
) == TRIT_COND_ENDIF
) {
1626 } else if (GetTraceRestrictType(item
) == TRIT_NULL
) {
1630 if (i
>= scroll_position
&& this->vscroll
->IsVisible(i
)) {
1631 DrawInstructionString(prog
, item
, i
, y
, i
== this->selected_instruction
, this_indent
, r
.left
+ WD_FRAMETEXT_LEFT
, r
.right
- WD_FRAMETEXT_RIGHT
);
1637 virtual void OnInvalidateData(int data
, bool gui_scope
)
1640 this->ReloadProgramme();
1644 virtual void SetStringParameters(int widget
) const
1647 case TR_WIDGET_VALUE_INT
: {
1649 TraceRestrictItem item
= this->GetSelected();
1650 TraceRestrictValueType type
= GetTraceRestrictTypeProperties(item
).value_type
;
1651 if (IsIntegerValueType(type
)) {
1652 SetDParam(0, ConvertIntegerValue(type
, GetTraceRestrictValue(item
), true));
1653 } else if (type
== TRVT_SLOT_INDEX_INT
) {
1654 SetDParam(0, *(TraceRestrictProgram::InstructionAt(this->GetProgram()->items
, this->selected_instruction
- 1) + 1));
1659 case TR_WIDGET_CAPTION
: {
1660 const TraceRestrictProgram
*prog
= this->GetProgram();
1662 SetDParam(0, prog
->refcount
);
1669 case TR_WIDGET_VALUE_DROPDOWN
: {
1670 TraceRestrictItem item
= this->GetSelected();
1671 TraceRestrictTypePropertySet type
= GetTraceRestrictTypeProperties(item
);
1672 if ((type
.value_type
== TRVT_PF_PENALTY
&&
1673 GetTraceRestrictAuxField(item
) == TRPPAF_VALUE
)
1674 || type
.value_type
== TRVT_GROUP_INDEX
1675 || type
.value_type
== TRVT_SLOT_INDEX
) {
1676 SetDParam(0, GetTraceRestrictValue(item
));
1681 case TR_WIDGET_LEFT_AUX_DROPDOWN
: {
1682 TraceRestrictItem item
= this->GetSelected();
1683 TraceRestrictTypePropertySet type
= GetTraceRestrictTypeProperties(item
);
1684 if (type
.value_type
== TRVT_SLOT_INDEX_INT
) {
1685 SetDParam(0, GetTraceRestrictValue(item
));
1692 virtual EventState
OnCTRLStateChange() {
1693 this->UpdateButtonState();
1694 return ES_NOT_HANDLED
;
1699 * Helper function to make start and end instructions (these are not stored in the actual program)
1701 TraceRestrictItem
MakeSpecialItem(TraceRestrictNullTypeSpecialValue value
) const
1703 TraceRestrictItem item
= 0;
1704 SetTraceRestrictType(item
, TRIT_NULL
);
1705 SetTraceRestrictValue(item
, value
);
1710 * Get item count of program, including start and end markers
1712 int GetItemCount(const TraceRestrictProgram
*prog
) const
1715 return 2 + (int)prog
->GetInstructionCount();
1722 * Get current program
1723 * This may return nullptr if no program currently exists
1725 const TraceRestrictProgram
*GetProgram() const
1727 return GetTraceRestrictProgram(MakeTraceRestrictRefId(tile
, track
), false);
1731 * Get instruction at @p index in program @p prog
1732 * This correctly handles start/end markers, offsets, etc.
1733 * This returns a 0 instruction if out of bounds
1734 * @p prog may be nullptr
1736 TraceRestrictItem
GetItem(const TraceRestrictProgram
*prog
, int index
) const
1743 return MakeSpecialItem(TRNTSV_START
);
1747 size_t instruction_count
= prog
->GetInstructionCount();
1749 if (static_cast<size_t>(index
) == instruction_count
+ 1) {
1750 return MakeSpecialItem(TRNTSV_END
);
1753 if (static_cast<size_t>(index
) > instruction_count
+ 1) {
1757 return prog
->items
[prog
->InstructionOffsetToArrayOffset(index
- 1)];
1759 // No program defined, this is equivalent to an empty program
1761 return MakeSpecialItem(TRNTSV_END
);
1769 * Get selected instruction, or a zero instruction
1771 TraceRestrictItem
GetSelected() const
1773 return this->GetItem(this->GetProgram(), this->selected_instruction
);
1777 * Get owner of the signal tile this window is pointing at
1781 return GetTileOwner(this->tile
);
1785 * Return item index from point in instruction list widget
1787 int GetItemIndexFromPt(int y
)
1789 NWidgetBase
*nwid
= this->GetWidget
<NWidgetBase
>(TR_WIDGET_INSTRUCTION_LIST
);
1790 int sel
= (y
- nwid
->pos_y
- WD_FRAMERECT_TOP
) / nwid
->resize_y
; // Selected line
1792 if ((uint
)sel
>= this->vscroll
->GetCapacity()) return -1;
1794 sel
+= this->vscroll
->GetPosition();
1796 return (sel
< this->GetItemCount(this->GetProgram()) && sel
>= 0) ? sel
: -1;
1800 * Reload details of program, and adjust length/selection position as necessary
1802 void ReloadProgramme()
1804 const TraceRestrictProgram
*prog
= this->GetProgram();
1806 if (this->vscroll
->GetCount() != this->GetItemCount(prog
)) {
1807 // program length has changed
1809 if (this->GetItemCount(prog
) < this->vscroll
->GetCount() ||
1810 this->GetItem(prog
, this->selected_instruction
) != this->expecting_inserted_item
) {
1811 // length has shrunk or if we weren't expecting an insertion, deselect
1812 this->selected_instruction
= -1;
1814 this->expecting_inserted_item
= static_cast<TraceRestrictItem
>(0);
1816 // update scrollbar size
1817 this->vscroll
->SetCount(this->GetItemCount(prog
));
1819 this->UpdateButtonState();
1822 bool IsUpDownBtnUsable(bool up
, bool update_selection
= false) {
1823 const TraceRestrictProgram
*prog
= this->GetProgram();
1824 if (!prog
) return false;
1826 TraceRestrictItem item
= this->GetSelected();
1827 if (GetTraceRestrictType(item
) == TRIT_NULL
) return false;
1829 std::vector
<TraceRestrictItem
> items
= prog
->items
; // copy
1830 uint32 offset
= this->selected_instruction
- 1;
1831 if (TraceRestrictProgramMoveItemAt(items
, offset
, up
, _ctrl_pressed
).Succeeded()) {
1832 TraceRestrictProgramActionsUsedFlags actions_used_flags
;
1833 if (TraceRestrictProgram::Validate(items
, actions_used_flags
).Succeeded()) {
1834 if (update_selection
) this->selected_instruction
= offset
+ 1;
1843 * Update button states, text values, etc.
1845 void UpdateButtonState()
1847 this->RaiseWidget(TR_WIDGET_INSERT
);
1848 this->RaiseWidget(TR_WIDGET_REMOVE
);
1849 this->RaiseWidget(TR_WIDGET_TYPE_COND
);
1850 this->RaiseWidget(TR_WIDGET_TYPE_NONCOND
);
1851 this->RaiseWidget(TR_WIDGET_CONDFLAGS
);
1852 this->RaiseWidget(TR_WIDGET_COMPARATOR
);
1853 this->RaiseWidget(TR_WIDGET_SLOT_OP
);
1854 this->RaiseWidget(TR_WIDGET_VALUE_INT
);
1855 this->RaiseWidget(TR_WIDGET_VALUE_DROPDOWN
);
1856 this->RaiseWidget(TR_WIDGET_VALUE_DEST
);
1857 this->RaiseWidget(TR_WIDGET_VALUE_SIGNAL
);
1858 this->RaiseWidget(TR_WIDGET_LEFT_AUX_DROPDOWN
);
1860 NWidgetStacked
*left_2_sel
= this->GetWidget
<NWidgetStacked
>(TR_WIDGET_SEL_TOP_LEFT_2
);
1861 NWidgetStacked
*left_sel
= this->GetWidget
<NWidgetStacked
>(TR_WIDGET_SEL_TOP_LEFT
);
1862 NWidgetStacked
*left_aux_sel
= this->GetWidget
<NWidgetStacked
>(TR_WIDGET_SEL_TOP_LEFT_AUX
);
1863 NWidgetStacked
*middle_sel
= this->GetWidget
<NWidgetStacked
>(TR_WIDGET_SEL_TOP_MIDDLE
);
1864 NWidgetStacked
*right_sel
= this->GetWidget
<NWidgetStacked
>(TR_WIDGET_SEL_TOP_RIGHT
);
1865 NWidgetStacked
*share_sel
= this->GetWidget
<NWidgetStacked
>(TR_WIDGET_SEL_SHARE
);
1866 NWidgetStacked
*copy_sel
= this->GetWidget
<NWidgetStacked
>(TR_WIDGET_SEL_COPY
);
1868 this->DisableWidget(TR_WIDGET_TYPE_COND
);
1869 this->DisableWidget(TR_WIDGET_TYPE_NONCOND
);
1870 this->DisableWidget(TR_WIDGET_CONDFLAGS
);
1871 this->DisableWidget(TR_WIDGET_COMPARATOR
);
1872 this->DisableWidget(TR_WIDGET_SLOT_OP
);
1873 this->DisableWidget(TR_WIDGET_VALUE_INT
);
1874 this->DisableWidget(TR_WIDGET_VALUE_DROPDOWN
);
1875 this->DisableWidget(TR_WIDGET_VALUE_DEST
);
1876 this->DisableWidget(TR_WIDGET_VALUE_SIGNAL
);
1877 this->DisableWidget(TR_WIDGET_LEFT_AUX_DROPDOWN
);
1879 this->DisableWidget(TR_WIDGET_INSERT
);
1880 this->DisableWidget(TR_WIDGET_REMOVE
);
1881 this->DisableWidget(TR_WIDGET_RESET
);
1882 this->DisableWidget(TR_WIDGET_COPY
);
1883 this->DisableWidget(TR_WIDGET_SHARE
);
1884 this->DisableWidget(TR_WIDGET_UNSHARE
);
1886 this->DisableWidget(TR_WIDGET_BLANK_L2
);
1887 this->DisableWidget(TR_WIDGET_BLANK_L
);
1888 this->DisableWidget(TR_WIDGET_BLANK_M
);
1889 this->DisableWidget(TR_WIDGET_BLANK_R
);
1891 this->DisableWidget(TR_WIDGET_UP_BTN
);
1892 this->DisableWidget(TR_WIDGET_DOWN_BTN
);
1894 this->EnableWidget(TR_WIDGET_COPY_APPEND
);
1896 left_2_sel
->SetDisplayedPlane(DPL2_BLANK
);
1897 left_sel
->SetDisplayedPlane(DPL_BLANK
);
1898 left_aux_sel
->SetDisplayedPlane(SZSP_NONE
);
1899 middle_sel
->SetDisplayedPlane(DPM_BLANK
);
1900 right_sel
->SetDisplayedPlane(DPR_BLANK
);
1901 share_sel
->SetDisplayedPlane(DPS_SHARE
);
1902 copy_sel
->SetDisplayedPlane(_ctrl_pressed
? DPC_APPEND
: DPC_COPY
);
1904 const TraceRestrictProgram
*prog
= this->GetProgram();
1906 this->GetWidget
<NWidgetCore
>(TR_WIDGET_CAPTION
)->widget_data
=
1907 (prog
&& prog
->refcount
> 1) ? STR_TRACE_RESTRICT_CAPTION_SHARED
: STR_TRACE_RESTRICT_CAPTION
;
1909 auto left_aux_guard
= scope_guard([&]() {
1910 if (this->current_left_aux_plane
!= left_aux_sel
->shown_plane
) {
1911 this->current_left_aux_plane
= left_aux_sel
->shown_plane
;
1916 // Don't allow modifications if don't own
1917 if (this->GetOwner() != _local_company
) {
1922 if (prog
&& prog
->refcount
> 1) {
1923 // program is shared, show and enable unshare button, and reset button
1924 share_sel
->SetDisplayedPlane(DPS_UNSHARE
);
1925 this->EnableWidget(TR_WIDGET_UNSHARE
);
1926 this->EnableWidget(TR_WIDGET_RESET
);
1927 } else if (this->GetItemCount(prog
) > 2) {
1928 // program is non-empty and not shared, enable reset button
1929 this->EnableWidget(TR_WIDGET_RESET
);
1931 // program is empty and not shared, show copy and share buttons
1932 this->EnableWidget(TR_WIDGET_COPY
);
1933 this->EnableWidget(TR_WIDGET_SHARE
);
1936 // haven't selected instruction
1937 if (this->selected_instruction
< 1) {
1942 TraceRestrictItem item
= this->GetItem(prog
, this->selected_instruction
);
1944 if (GetTraceRestrictType(item
) == TRIT_NULL
) {
1945 switch (GetTraceRestrictValue(item
)) {
1950 this->EnableWidget(TR_WIDGET_INSERT
);
1957 } else if (GetTraceRestrictType(item
) == TRIT_COND_ENDIF
) {
1958 this->EnableWidget(TR_WIDGET_INSERT
);
1959 if (GetTraceRestrictCondFlags(item
) != 0) {
1960 // this is not an end if, it must be an else, enable removing
1961 this->EnableWidget(TR_WIDGET_REMOVE
);
1963 // setup condflags dropdown to show else
1964 left_2_sel
->SetDisplayedPlane(DPL2_CONDFLAGS
);
1965 this->EnableWidget(TR_WIDGET_CONDFLAGS
);
1966 this->GetWidget
<NWidgetCore
>(TR_WIDGET_CONDFLAGS
)->widget_data
= STR_TRACE_RESTRICT_CONDITIONAL_ELSE
;
1969 TraceRestrictTypePropertySet properties
= GetTraceRestrictTypeProperties(item
);
1972 if (IsTraceRestrictConditional(item
)) {
1973 // note that else and end if items are not handled here, they are handled above
1975 left_2_sel
->SetDisplayedPlane(DPL2_CONDFLAGS
);
1976 left_sel
->SetDisplayedPlane(DPL_TYPE
);
1977 type_widget
= TR_WIDGET_TYPE_COND
;
1979 // setup condflags dropdown box
1980 left_2_sel
->SetDisplayedPlane(DPL2_CONDFLAGS
);
1981 switch (GetTraceRestrictCondFlags(item
)) {
1982 case TRCF_DEFAULT
: // opening if, leave disabled
1983 this->GetWidget
<NWidgetCore
>(TR_WIDGET_CONDFLAGS
)->widget_data
= STR_TRACE_RESTRICT_CONDITIONAL_IF
;
1986 case TRCF_ELSE
: // else-if
1987 this->GetWidget
<NWidgetCore
>(TR_WIDGET_CONDFLAGS
)->widget_data
= STR_TRACE_RESTRICT_CONDITIONAL_ELIF
;
1988 this->EnableWidget(TR_WIDGET_CONDFLAGS
);
1991 case TRCF_OR
: // or-if
1992 this->GetWidget
<NWidgetCore
>(TR_WIDGET_CONDFLAGS
)->widget_data
= STR_TRACE_RESTRICT_CONDITIONAL_ORIF
;
1993 this->EnableWidget(TR_WIDGET_CONDFLAGS
);
2001 left_2_sel
->SetDisplayedPlane(DPL2_TYPE
);
2002 type_widget
= TR_WIDGET_TYPE_NONCOND
;
2004 this->EnableWidget(type_widget
);
2006 this->GetWidget
<NWidgetCore
>(type_widget
)->widget_data
=
2007 GetTypeString(item
);
2009 if (properties
.cond_type
== TRCOT_BINARY
|| properties
.cond_type
== TRCOT_ALL
) {
2010 middle_sel
->SetDisplayedPlane(DPM_COMPARATOR
);
2011 this->EnableWidget(TR_WIDGET_COMPARATOR
);
2013 const TraceRestrictDropDownListSet
*list_set
= GetCondOpDropDownListSet(properties
);
2016 this->GetWidget
<NWidgetCore
>(TR_WIDGET_COMPARATOR
)->widget_data
=
2017 GetDropDownStringByValue(list_set
, GetTraceRestrictCondOp(item
));
2021 if (IsIntegerValueType(properties
.value_type
)) {
2022 right_sel
->SetDisplayedPlane(DPR_VALUE_INT
);
2023 this->EnableWidget(TR_WIDGET_VALUE_INT
);
2025 switch (properties
.value_type
) {
2027 right_sel
->SetDisplayedPlane(DPR_VALUE_DROPDOWN
);
2028 this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN
);
2029 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
=
2030 GetTraceRestrictValue(item
) ? STR_TRACE_RESTRICT_PF_ALLOW
: STR_TRACE_RESTRICT_PF_DENY
;
2034 right_sel
->SetDisplayedPlane(DPR_VALUE_DEST
);
2035 this->EnableWidget(TR_WIDGET_VALUE_DEST
);
2039 right_sel
->SetDisplayedPlane(DPR_VALUE_DROPDOWN
);
2040 this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN
);
2041 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
=
2042 GetCargoStringByID(GetTraceRestrictValue(item
));
2045 case TRVT_DIRECTION
:
2046 right_sel
->SetDisplayedPlane(DPR_VALUE_DROPDOWN
);
2047 this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN
);
2048 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
=
2049 GetDropDownStringByValue(&_direction_value
, GetTraceRestrictValue(item
));
2052 case TRVT_TILE_INDEX
:
2053 right_sel
->SetDisplayedPlane(DPR_VALUE_SIGNAL
);
2054 this->EnableWidget(TR_WIDGET_VALUE_SIGNAL
);
2057 case TRVT_PF_PENALTY
:
2058 right_sel
->SetDisplayedPlane(DPR_VALUE_DROPDOWN
);
2059 this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN
);
2060 if (GetTraceRestrictAuxField(item
) == TRPPAF_VALUE
) {
2061 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
= STR_BLACK_COMMA
;
2063 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
=
2064 GetDropDownStringByValue(&_pf_penalty_dropdown
, GetPathfinderPenaltyDropdownIndex(item
));
2068 case TRVT_RESERVE_THROUGH
:
2069 right_sel
->SetDisplayedPlane(DPR_VALUE_DROPDOWN
);
2070 this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN
);
2071 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
=
2072 GetTraceRestrictValue(item
) ? STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL
: STR_TRACE_RESTRICT_RESERVE_THROUGH
;
2075 case TRVT_LONG_RESERVE
:
2076 right_sel
->SetDisplayedPlane(DPR_VALUE_DROPDOWN
);
2077 this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN
);
2078 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
=
2079 GetTraceRestrictValue(item
) ? STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL
: STR_TRACE_RESTRICT_LONG_RESERVE
;
2082 case TRVT_WAIT_AT_PBS
:
2083 right_sel
->SetDisplayedPlane(DPR_VALUE_DROPDOWN
);
2084 this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN
);
2085 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
=
2086 GetTraceRestrictValue(item
) ? STR_TRACE_RESTRICT_WAIT_AT_PBS_CANCEL
: STR_TRACE_RESTRICT_WAIT_AT_PBS
;
2089 case TRVT_GROUP_INDEX
:
2090 right_sel
->SetDisplayedPlane(DPR_VALUE_DROPDOWN
);
2091 this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN
);
2092 switch (GetTraceRestrictValue(item
)) {
2094 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
= STR_TRACE_RESTRICT_VARIABLE_UNDEFINED
;
2098 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
= STR_GROUP_DEFAULT_TRAINS
;
2102 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
= STR_GROUP_NAME
;
2107 case TRVT_SLOT_INDEX
: {
2108 right_sel
->SetDisplayedPlane(DPR_VALUE_DROPDOWN
);
2109 if (!IsTraceRestrictConditional(item
)) {
2110 middle_sel
->SetDisplayedPlane(DPM_SLOT_OP
);
2111 this->EnableWidget(TR_WIDGET_SLOT_OP
);
2114 const TraceRestrictSlot
*slot
;
2115 FOR_ALL_TRACE_RESTRICT_SLOTS(slot
) {
2116 if (slot
->owner
== this->GetOwner()) {
2117 this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN
);
2122 this->GetWidget
<NWidgetCore
>(TR_WIDGET_SLOT_OP
)->widget_data
=
2123 GetDropDownStringByValue(&_slot_op_cond_ops
, GetTraceRestrictCondOp(item
));
2124 switch (GetTraceRestrictValue(item
)) {
2125 case INVALID_TRACE_RESTRICT_SLOT_ID
:
2126 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
= STR_TRACE_RESTRICT_VARIABLE_UNDEFINED
;
2130 this->GetWidget
<NWidgetCore
>(TR_WIDGET_VALUE_DROPDOWN
)->widget_data
= STR_TRACE_RESTRICT_SLOT_NAME
;
2136 case TRVT_SLOT_INDEX_INT
: {
2137 right_sel
->SetDisplayedPlane(DPR_VALUE_INT
);
2138 left_aux_sel
->SetDisplayedPlane(DPLA_DROPDOWN
);
2139 this->EnableWidget(TR_WIDGET_VALUE_INT
);
2141 const TraceRestrictSlot
*slot
;
2142 FOR_ALL_TRACE_RESTRICT_SLOTS(slot
) {
2143 if (slot
->owner
== this->GetOwner()) {
2144 this->EnableWidget(TR_WIDGET_LEFT_AUX_DROPDOWN
);
2149 switch (GetTraceRestrictValue(item
)) {
2150 case INVALID_TRACE_RESTRICT_SLOT_ID
:
2151 this->GetWidget
<NWidgetCore
>(TR_WIDGET_LEFT_AUX_DROPDOWN
)->widget_data
= STR_TRACE_RESTRICT_VARIABLE_UNDEFINED
;
2155 this->GetWidget
<NWidgetCore
>(TR_WIDGET_LEFT_AUX_DROPDOWN
)->widget_data
= STR_TRACE_RESTRICT_SLOT_NAME
;
2166 this->EnableWidget(TR_WIDGET_INSERT
);
2167 this->EnableWidget(TR_WIDGET_REMOVE
);
2170 if (this->IsUpDownBtnUsable(true)) this->EnableWidget(TR_WIDGET_UP_BTN
);
2171 if (this->IsUpDownBtnUsable(false)) this->EnableWidget(TR_WIDGET_DOWN_BTN
);
2178 * Show a drop down list using @p list_set, setting the pre-selected item to the one corresponding to @p value
2179 * This asserts if @p value is not in @p list_set, and @p missing_ok is false
2181 void ShowDropDownListWithValue(const TraceRestrictDropDownListSet
*list_set
, uint value
, bool missing_ok
,
2182 int button
, uint32 disabled_mask
, uint32 hidden_mask
, uint width
)
2184 this->drop_down_list_mapping
[button
] = list_set
;
2185 int selected
= GetDropDownListIndexByValue(list_set
, value
, missing_ok
);
2186 ShowDropDownMenu(this, list_set
->string_array
, selected
, button
, disabled_mask
, hidden_mask
, width
);
2190 * Helper function to set or unset a SetObjectToPlaceWnd, for the given widget and cursor type
2192 void SetObjectToPlaceAction(int widget
, CursorID cursor
)
2194 if (this->current_placement_widget
!= -1 && widget
!= this->current_placement_widget
) {
2195 ResetObjectToPlace();
2198 this->ToggleWidgetLoweredState(widget
);
2199 this->SetWidgetDirty(widget
);
2200 if (this->IsWidgetLowered(widget
)) {
2201 SetObjectToPlaceWnd(cursor
, PAL_NONE
, HT_RECT
, this);
2202 this->current_placement_widget
= widget
;
2204 ResetObjectToPlace();
2205 this->current_placement_widget
= -1;
2210 * This used for testing whether else or else-if blocks could be inserted, or replace the selection
2211 * If @p replace is true, replace selection with @p item, else insert @p item before selection
2212 * Returns true if resulting instruction list passes validation
2214 bool GenericElseInsertionDryRun(TraceRestrictItem item
, bool replace
)
2216 if (this->selected_instruction
< 1) return false;
2217 uint offset
= this->selected_instruction
- 1;
2219 const TraceRestrictProgram
*prog
= this->GetProgram();
2220 if (!prog
) return false;
2222 std::vector
<TraceRestrictItem
> items
= prog
->items
; // copy
2224 if (offset
>= (TraceRestrictProgram::GetInstructionCount(items
) + (replace
? 0 : 1))) return false; // off the end of the program
2226 uint array_offset
= (uint
)TraceRestrictProgram::InstructionOffsetToArrayOffset(items
, offset
);
2228 items
[array_offset
] = item
;
2230 items
.insert(items
.begin() + array_offset
, item
);
2233 TraceRestrictProgramActionsUsedFlags actions_used_flags
;
2234 return TraceRestrictProgram::Validate(items
, actions_used_flags
).Succeeded();
2238 * Run GenericElseInsertionDryRun with an else instruction
2240 bool ElseInsertionDryRun(bool replace
)
2242 TraceRestrictItem item
= 0;
2243 SetTraceRestrictType(item
, TRIT_COND_ENDIF
);
2244 SetTraceRestrictCondFlags(item
, TRCF_ELSE
);
2245 return GenericElseInsertionDryRun(item
, replace
);
2249 * Run GenericElseInsertionDryRun with an elif instruction
2251 bool ElseIfInsertionDryRun(bool replace
)
2253 TraceRestrictItem item
= 0;
2254 SetTraceRestrictType(item
, TRIT_COND_UNDEFINED
);
2255 SetTraceRestrictCondFlags(item
, TRCF_ELSE
);
2256 return GenericElseInsertionDryRun(item
, replace
);
2260 static const NWidgetPart _nested_program_widgets
[] = {
2262 NWidget(NWID_HORIZONTAL
),
2263 NWidget(WWT_CLOSEBOX
, COLOUR_GREY
),
2264 NWidget(WWT_CAPTION
, COLOUR_GREY
, TR_WIDGET_CAPTION
), SetDataTip(STR_TRACE_RESTRICT_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
2265 NWidget(WWT_SHADEBOX
, COLOUR_GREY
),
2266 NWidget(WWT_STICKYBOX
, COLOUR_GREY
),
2270 NWidget(NWID_HORIZONTAL
),
2271 NWidget(WWT_PANEL
, COLOUR_GREY
, TR_WIDGET_INSTRUCTION_LIST
), SetMinimalSize(372, 62), SetDataTip(0x0, STR_TRACE_RESTRICT_INSTRUCTION_LIST_TOOLTIP
),
2272 SetResize(1, 1), SetScrollbar(TR_WIDGET_SCROLLBAR
), EndContainer(),
2273 NWidget(NWID_VSCROLLBAR
, COLOUR_GREY
, TR_WIDGET_SCROLLBAR
),
2277 NWidget(NWID_HORIZONTAL
),
2278 NWidget(WWT_PUSHIMGBTN
, COLOUR_GREY
, TR_WIDGET_UP_BTN
), SetMinimalSize(12, 12), SetDataTip(SPR_ARROW_UP
, STR_TRACE_RESTRICT_UP_BTN_TOOLTIP
),
2279 NWidget(WWT_PUSHIMGBTN
, COLOUR_GREY
, TR_WIDGET_DOWN_BTN
), SetMinimalSize(12, 12), SetDataTip(SPR_ARROW_DOWN
, STR_TRACE_RESTRICT_DOWN_BTN_TOOLTIP
),
2280 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
2281 NWidget(NWID_SELECTION
, INVALID_COLOUR
, TR_WIDGET_SEL_TOP_LEFT_2
),
2282 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, TR_WIDGET_TYPE_NONCOND
), SetMinimalSize(124, 12), SetFill(1, 0),
2283 SetDataTip(STR_NULL
, STR_TRACE_RESTRICT_TYPE_TOOLTIP
), SetResize(1, 0),
2284 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, TR_WIDGET_CONDFLAGS
), SetMinimalSize(124, 12), SetFill(1, 0),
2285 SetDataTip(STR_NULL
, STR_TRACE_RESTRICT_CONDFLAGS_TOOLTIP
), SetResize(1, 0),
2286 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_BLANK_L2
), SetMinimalSize(124, 12), SetFill(1, 0),
2287 SetDataTip(STR_EMPTY
, STR_NULL
), SetResize(1, 0),
2289 NWidget(NWID_SELECTION
, INVALID_COLOUR
, TR_WIDGET_SEL_TOP_LEFT
),
2290 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, TR_WIDGET_TYPE_COND
), SetMinimalSize(124, 12), SetFill(1, 0),
2291 SetDataTip(STR_NULL
, STR_TRACE_RESTRICT_TYPE_TOOLTIP
), SetResize(1, 0),
2292 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_BLANK_L
), SetMinimalSize(124, 12), SetFill(1, 0),
2293 SetDataTip(STR_EMPTY
, STR_NULL
), SetResize(1, 0),
2295 NWidget(NWID_SELECTION
, INVALID_COLOUR
, TR_WIDGET_SEL_TOP_LEFT_AUX
),
2296 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, TR_WIDGET_LEFT_AUX_DROPDOWN
), SetMinimalSize(124, 12), SetFill(1, 0),
2297 SetDataTip(STR_NULL
, STR_TRACE_RESTRICT_COND_VALUE_TOOLTIP
), SetResize(1, 0),
2299 NWidget(NWID_SELECTION
, INVALID_COLOUR
, TR_WIDGET_SEL_TOP_MIDDLE
),
2300 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, TR_WIDGET_COMPARATOR
), SetMinimalSize(124, 12), SetFill(1, 0),
2301 SetDataTip(STR_NULL
, STR_TRACE_RESTRICT_COND_COMPARATOR_TOOLTIP
), SetResize(1, 0),
2302 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, TR_WIDGET_SLOT_OP
), SetMinimalSize(124, 12), SetFill(1, 0),
2303 SetDataTip(STR_NULL
, STR_TRACE_RESTRICT_SLOT_OP_TOOLTIP
), SetResize(1, 0),
2304 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_BLANK_M
), SetMinimalSize(124, 12), SetFill(1, 0),
2305 SetDataTip(STR_EMPTY
, STR_NULL
), SetResize(1, 0),
2307 NWidget(NWID_SELECTION
, INVALID_COLOUR
, TR_WIDGET_SEL_TOP_RIGHT
),
2308 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_VALUE_INT
), SetMinimalSize(124, 12), SetFill(1, 0),
2309 SetDataTip(STR_BLACK_COMMA
, STR_TRACE_RESTRICT_COND_VALUE_TOOLTIP
), SetResize(1, 0),
2310 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, TR_WIDGET_VALUE_DROPDOWN
), SetMinimalSize(124, 12), SetFill(1, 0),
2311 SetDataTip(STR_NULL
, STR_TRACE_RESTRICT_COND_VALUE_TOOLTIP
), SetResize(1, 0),
2312 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_VALUE_DEST
), SetMinimalSize(124, 12), SetFill(1, 0),
2313 SetDataTip(STR_TRACE_RESTRICT_SELECT_TARGET
, STR_TRACE_RESTRICT_SELECT_TARGET
), SetResize(1, 0),
2314 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_VALUE_SIGNAL
), SetMinimalSize(124, 12), SetFill(1, 0),
2315 SetDataTip(STR_TRACE_RESTRICT_SELECT_SIGNAL
, STR_TRACE_RESTRICT_SELECT_SIGNAL
), SetResize(1, 0),
2316 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_BLANK_R
), SetMinimalSize(124, 12), SetFill(1, 0),
2317 SetDataTip(STR_EMPTY
, STR_NULL
), SetResize(1, 0),
2320 NWidget(WWT_PUSHIMGBTN
, COLOUR_GREY
, TR_WIDGET_GOTO_SIGNAL
), SetMinimalSize(12, 12), SetDataTip(SPR_ARROW_RIGHT
, STR_TRACE_RESTRICT_GOTO_SIGNAL_TOOLTIP
),
2323 /* Second button row. */
2324 NWidget(NWID_HORIZONTAL
),
2325 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
2326 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, TR_WIDGET_INSERT
), SetMinimalSize(124, 12), SetFill(1, 0),
2327 SetDataTip(STR_TRACE_RESTRICT_INSERT
, STR_TRACE_RESTRICT_INSERT_TOOLTIP
), SetResize(1, 0),
2328 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_REMOVE
), SetMinimalSize(124, 12), SetFill(1, 0),
2329 SetDataTip(STR_TRACE_RESTRICT_REMOVE
, STR_TRACE_RESTRICT_REMOVE_TOOLTIP
), SetResize(1, 0),
2330 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_RESET
), SetMinimalSize(124, 12), SetFill(1, 0),
2331 SetDataTip(STR_TRACE_RESTRICT_RESET
, STR_TRACE_RESTRICT_RESET_TOOLTIP
), SetResize(1, 0),
2332 NWidget(NWID_SELECTION
, INVALID_COLOUR
, TR_WIDGET_SEL_COPY
),
2333 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_COPY
), SetMinimalSize(124, 12), SetFill(1, 0),
2334 SetDataTip(STR_TRACE_RESTRICT_COPY
, STR_TRACE_RESTRICT_COPY_TOOLTIP
), SetResize(1, 0),
2335 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_COPY_APPEND
), SetMinimalSize(124, 12), SetFill(1, 0),
2336 SetDataTip(STR_TRACE_RESTRICT_APPEND
, STR_TRACE_RESTRICT_COPY_TOOLTIP
), SetResize(1, 0),
2338 NWidget(NWID_SELECTION
, INVALID_COLOUR
, TR_WIDGET_SEL_SHARE
),
2339 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_SHARE
), SetMinimalSize(124, 12), SetFill(1, 0),
2340 SetDataTip(STR_TRACE_RESTRICT_SHARE
, STR_TRACE_RESTRICT_SHARE_TOOLTIP
), SetResize(1, 0),
2341 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, TR_WIDGET_UNSHARE
), SetMinimalSize(124, 12), SetFill(1, 0),
2342 SetDataTip(STR_TRACE_RESTRICT_UNSHARE
, STR_TRACE_RESTRICT_UNSHARE_TOOLTIP
), SetResize(1, 0),
2345 NWidget(WWT_RESIZEBOX
, COLOUR_GREY
),
2349 static WindowDesc
_program_desc(
2350 WDP_AUTO
, "trace_restrict_gui", 384, 100,
2351 WC_TRACE_RESTRICT
, WC_BUILD_SIGNAL
,
2353 _nested_program_widgets
, lengthof(_nested_program_widgets
)
2357 * Show or create program window for given @p tile and @p track
2359 void ShowTraceRestrictProgramWindow(TileIndex tile
, Track track
)
2361 if (BringWindowToFrontById(WC_TRACE_RESTRICT
, MakeTraceRestrictRefId(tile
, track
)) != nullptr) {
2365 new TraceRestrictWindow(&_program_desc
, tile
, track
);
2368 /** Slot GUI widget IDs */
2369 enum TraceRestrictSlotWindowWidgets
{
2371 WID_TRSL_ALL_VEHICLES
,
2372 WID_TRSL_LIST_SLOTS
,
2373 WID_TRSL_LIST_SLOTS_SCROLLBAR
,
2374 WID_TRSL_CREATE_SLOT
,
2375 WID_TRSL_DELETE_SLOT
,
2376 WID_TRSL_RENAME_SLOT
,
2377 WID_TRSL_SET_SLOT_MAX_OCCUPANCY
,
2378 WID_TRSL_SORT_BY_ORDER
,
2379 WID_TRSL_SORT_BY_DROPDOWN
,
2380 WID_TRSL_FILTER_BY_CARGO
,
2381 WID_TRSL_LIST_VEHICLE
,
2382 WID_TRSL_LIST_VEHICLE_SCROLLBAR
,
2386 static const NWidgetPart _nested_slot_widgets
[] = {
2387 NWidget(NWID_HORIZONTAL
), // Window header
2388 NWidget(WWT_CLOSEBOX
, COLOUR_GREY
),
2389 NWidget(WWT_CAPTION
, COLOUR_GREY
, WID_TRSL_CAPTION
), SetDataTip(STR_TRACE_RESTRICT_SLOT_CAPTION
, STR_NULL
),
2390 NWidget(WWT_SHADEBOX
, COLOUR_GREY
),
2391 NWidget(WWT_DEFSIZEBOX
, COLOUR_GREY
),
2392 NWidget(WWT_STICKYBOX
, COLOUR_GREY
),
2394 NWidget(NWID_HORIZONTAL
),
2396 NWidget(NWID_VERTICAL
),
2397 NWidget(WWT_PANEL
, COLOUR_GREY
), SetMinimalTextLines(1, WD_DROPDOWNTEXT_TOP
+ WD_DROPDOWNTEXT_BOTTOM
), SetFill(1, 0), EndContainer(),
2398 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_TRSL_ALL_VEHICLES
), SetFill(1, 0), EndContainer(),
2399 NWidget(NWID_HORIZONTAL
),
2400 NWidget(WWT_MATRIX
, COLOUR_GREY
, WID_TRSL_LIST_SLOTS
), SetMatrixDataTip(1, 0, STR_TRACE_RESTRICT_SLOT_GUI_LIST_TOOLTIP
),
2401 SetFill(1, 0), SetResize(0, 1), SetScrollbar(WID_TRSL_LIST_SLOTS_SCROLLBAR
),
2402 NWidget(NWID_VSCROLLBAR
, COLOUR_GREY
, WID_TRSL_LIST_SLOTS_SCROLLBAR
),
2404 NWidget(NWID_HORIZONTAL
),
2405 NWidget(WWT_PUSHIMGBTN
, COLOUR_GREY
, WID_TRSL_CREATE_SLOT
), SetFill(0, 1),
2406 SetDataTip(SPR_GROUP_CREATE_TRAIN
, STR_TRACE_RESTRICT_SLOT_CREATE_TOOLTIP
),
2407 NWidget(WWT_PUSHIMGBTN
, COLOUR_GREY
, WID_TRSL_DELETE_SLOT
), SetFill(0, 1),
2408 SetDataTip(SPR_GROUP_DELETE_TRAIN
, STR_TRACE_RESTRICT_SLOT_DELETE_TOOLTIP
),
2409 NWidget(WWT_PUSHIMGBTN
, COLOUR_GREY
, WID_TRSL_RENAME_SLOT
), SetFill(0, 1),
2410 SetDataTip(SPR_GROUP_RENAME_TRAIN
, STR_TRACE_RESTRICT_SLOT_RENAME_TOOLTIP
),
2411 NWidget(WWT_PANEL
, COLOUR_GREY
), SetFill(1, 1), EndContainer(),
2412 NWidget(WWT_PUSHIMGBTN
, COLOUR_GREY
, WID_TRSL_SET_SLOT_MAX_OCCUPANCY
), SetFill(0, 1),
2413 SetDataTip(SPR_IMG_SETTINGS
, STR_TRACE_RESTRICT_SLOT_SET_MAX_OCCUPANCY_TOOLTIP
),
2417 NWidget(NWID_VERTICAL
),
2418 NWidget(NWID_HORIZONTAL
),
2419 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_TRSL_SORT_BY_ORDER
), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY
, STR_TOOLTIP_SORT_ORDER
),
2420 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, WID_TRSL_SORT_BY_DROPDOWN
), SetMinimalSize(167, 12), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA
),
2421 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, WID_TRSL_FILTER_BY_CARGO
), SetMinimalSize(167, 12), SetDataTip(STR_JUST_STRING
, STR_TOOLTIP_FILTER_CRITERIA
),
2422 NWidget(WWT_PANEL
, COLOUR_GREY
), SetMinimalSize(12, 12), SetResize(1, 0), EndContainer(),
2424 NWidget(NWID_HORIZONTAL
),
2425 NWidget(WWT_MATRIX
, COLOUR_GREY
, WID_TRSL_LIST_VEHICLE
), SetMinimalSize(248, 0), SetMatrixDataTip(1, 0, STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP
), SetResize(1, 1), SetFill(1, 0), SetScrollbar(WID_TRSL_LIST_VEHICLE_SCROLLBAR
),
2426 NWidget(NWID_VSCROLLBAR
, COLOUR_GREY
, WID_TRSL_LIST_VEHICLE_SCROLLBAR
),
2428 NWidget(WWT_PANEL
, COLOUR_GREY
), SetMinimalSize(1, 0), SetFill(1, 1), SetResize(1, 0), EndContainer(),
2429 NWidget(NWID_HORIZONTAL
),
2430 NWidget(WWT_PANEL
, COLOUR_GREY
), SetFill(1, 1), EndContainer(),
2431 NWidget(WWT_RESIZEBOX
, COLOUR_GREY
),
2437 class TraceRestrictSlotWindow
: public BaseVehicleListWindow
{
2439 /* Columns in the group list */
2441 VGC_NAME
, ///< Group name.
2442 VGC_NUMBER
, ///< Number of vehicles in the group.
2447 TraceRestrictSlotID slot_sel
; ///< Selected slot (for drag/drop)
2448 bool slot_set_max_occupancy
; ///< True if slot max occupancy is being changed, instead of renaming
2449 TraceRestrictSlotID slot_rename
; ///< Slot being renamed or max occupancy changed, INVALID_TRACE_RESTRICT_SLOT_ID if none
2450 TraceRestrictSlotID slot_over
; ///< Slot over which a vehicle is dragged, INVALID_TRACE_RESTRICT_SLOT_ID if none
2451 TraceRestrictSlotID slot_confirm
; ///< Slot awaiting delete confirmation
2452 GUIList
<const TraceRestrictSlot
*> slots
; ///< List of slots
2453 uint tiny_step_height
; ///< Step height for the slot list
2456 Dimension column_size
[VGC_END
]; ///< Size of the columns in the group list.
2459 * (Re)Build the slot list.
2461 * @param owner The owner of the window
2463 void BuildSlotList(Owner owner
)
2465 if (!this->slots
.NeedRebuild()) return;
2467 this->slots
.Clear();
2469 const TraceRestrictSlot
*slot
;
2470 FOR_ALL_TRACE_RESTRICT_SLOTS(slot
) {
2471 if (slot
->owner
== owner
) {
2472 *(this->slots
.Append()) = slot
;
2476 this->slots
.ForceResort();
2477 this->slots
.Sort(&SlotNameSorter
);
2478 this->slots
.Compact();
2479 this->slots
.RebuildDone();
2483 * Compute tiny_step_height and column_size
2484 * @return Total width required for the group list.
2486 uint
ComputeSlotInfoSize()
2488 this->column_size
[VGC_NAME
] = GetStringBoundingBox(STR_GROUP_ALL_TRAINS
);
2489 this->column_size
[VGC_NAME
].width
= max(170u, this->column_size
[VGC_NAME
].width
);
2490 this->tiny_step_height
= this->column_size
[VGC_NAME
].height
;
2492 SetDParamMaxValue(0, 9999, 3, FS_SMALL
);
2493 SetDParamMaxValue(1, 9999, 3, FS_SMALL
);
2494 this->column_size
[VGC_NUMBER
] = GetStringBoundingBox(STR_TRACE_RESTRICT_SLOT_MAX_OCCUPANCY
);
2495 this->tiny_step_height
= max(this->tiny_step_height
, this->column_size
[VGC_NUMBER
].height
);
2497 this->tiny_step_height
+= WD_MATRIX_TOP
;
2499 return WD_FRAMERECT_LEFT
+ 8 +
2500 this->column_size
[VGC_NAME
].width
+ 8 +
2501 this->column_size
[VGC_NUMBER
].width
+ 2 +
2506 * Draw a row in the slot list.
2507 * @param y Top of the row.
2508 * @param left Left of the row.
2509 * @param right Right of the row.
2510 * @param g_id Group to list.
2512 void DrawSlotInfo(int y
, int left
, int right
, TraceRestrictSlotID slot_id
) const
2514 /* Highlight the group if a vehicle is dragged over it */
2515 if (slot_id
== this->slot_over
) {
2516 GfxFillRect(left
+ WD_FRAMERECT_LEFT
, y
+ WD_FRAMERECT_TOP
, right
- WD_FRAMERECT_RIGHT
, y
+ this->tiny_step_height
- WD_FRAMERECT_BOTTOM
- WD_MATRIX_TOP
, _colour_gradient
[COLOUR_GREY
][7]);
2519 /* draw the selected group in white, else we draw it in black */
2520 TextColour colour
= slot_id
== this->vli
.index
? TC_WHITE
: TC_BLACK
;
2521 bool rtl
= _current_text_dir
== TD_RTL
;
2523 /* draw group name */
2525 if (slot_id
== ALL_TRAINS_TRACE_RESTRICT_SLOT_ID
) {
2526 str
= STR_GROUP_ALL_TRAINS
;
2528 SetDParam(0, slot_id
);
2529 str
= STR_TRACE_RESTRICT_SLOT_NAME
;
2531 int x
= rtl
? right
- WD_FRAMERECT_RIGHT
- 8 - this->column_size
[VGC_NAME
].width
+ 1 : left
+ WD_FRAMERECT_LEFT
+ 8;
2532 DrawString(x
, x
+ this->column_size
[VGC_NAME
].width
- 1, y
+ (this->tiny_step_height
- this->column_size
[VGC_NAME
].height
) / 2, str
, colour
);
2534 if (slot_id
== ALL_TRAINS_TRACE_RESTRICT_SLOT_ID
) return;
2536 const TraceRestrictSlot
*slot
= TraceRestrictSlot::Get(slot_id
);
2538 /* draw the number of vehicles of the group */
2539 x
= rtl
? x
- 2 - this->column_size
[VGC_NUMBER
].width
: x
+ 2 + this->column_size
[VGC_NAME
].width
;
2540 SetDParam(0, slot
->occupants
.size());
2541 SetDParam(1, slot
->max_occupancy
);
2542 DrawString(x
, x
+ this->column_size
[VGC_NUMBER
].width
- 1, y
+ (this->tiny_step_height
- this->column_size
[VGC_NUMBER
].height
) / 2, STR_TRACE_RESTRICT_SLOT_MAX_OCCUPANCY
, colour
, SA_RIGHT
| SA_FORCE
);
2546 * Mark the widget containing the currently highlighted slot as dirty.
2548 void DirtyHighlightedSlotWidget()
2550 if (this->slot_over
== INVALID_TRACE_RESTRICT_SLOT_ID
) return;
2552 if (this->slot_over
== ALL_TRAINS_TRACE_RESTRICT_SLOT_ID
) {
2553 this->SetWidgetDirty(WID_TRSL_ALL_VEHICLES
);
2555 this->SetWidgetDirty(WID_TRSL_LIST_SLOTS
);
2560 TraceRestrictSlotWindow(WindowDesc
*desc
, WindowNumber window_number
) : BaseVehicleListWindow(desc
, window_number
)
2562 this->CreateNestedTree();
2564 this->vscroll
= this->GetScrollbar(WID_TRSL_LIST_VEHICLE_SCROLLBAR
);
2565 this->slot_sb
= this->GetScrollbar(WID_TRSL_LIST_SLOTS_SCROLLBAR
);
2566 this->sorting
= &_sorting
.train
;
2568 this->vli
.index
= ALL_TRAINS_TRACE_RESTRICT_SLOT_ID
;
2569 this->slot_sel
= INVALID_TRACE_RESTRICT_SLOT_ID
;
2570 this->slot_rename
= INVALID_TRACE_RESTRICT_SLOT_ID
;
2571 this->slot_set_max_occupancy
= false;
2572 this->slot_over
= INVALID_TRACE_RESTRICT_SLOT_ID
;
2574 this->vehicles
.SetListing(*this->sorting
);
2575 this->vehicles
.ForceRebuild();
2576 this->vehicles
.NeedResort();
2578 this->BuildVehicleList();
2579 this->SortVehicleList();
2581 this->slots
.ForceRebuild();
2582 this->slots
.NeedResort();
2583 this->BuildSlotList(vli
.company
);
2585 this->FinishInitNested(window_number
);
2586 this->owner
= vli
.company
;
2589 ~TraceRestrictSlotWindow()
2591 *this->sorting
= this->vehicles
.GetListing();
2594 virtual void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
)
2597 case WID_TRSL_LIST_SLOTS
: {
2598 size
->width
= this->ComputeSlotInfoSize();
2599 resize
->height
= this->tiny_step_height
;
2601 /* Minimum height is the height of the list widget minus all vehicles... */
2602 size
->height
= 4 * GetVehicleListHeight(this->vli
.vtype
, this->tiny_step_height
) - this->tiny_step_height
;
2604 /* ... minus the buttons at the bottom ... */
2605 uint max_icon_height
= GetSpriteSize(this->GetWidget
<NWidgetCore
>(WID_TRSL_CREATE_SLOT
)->widget_data
).height
;
2606 max_icon_height
= max(max_icon_height
, GetSpriteSize(this->GetWidget
<NWidgetCore
>(WID_TRSL_DELETE_SLOT
)->widget_data
).height
);
2607 max_icon_height
= max(max_icon_height
, GetSpriteSize(this->GetWidget
<NWidgetCore
>(WID_TRSL_RENAME_SLOT
)->widget_data
).height
);
2608 max_icon_height
= max(max_icon_height
, GetSpriteSize(this->GetWidget
<NWidgetCore
>(WID_TRSL_SET_SLOT_MAX_OCCUPANCY
)->widget_data
).height
);
2610 /* Get a multiple of tiny_step_height of that amount */
2611 size
->height
= Ceil(size
->height
- max_icon_height
, tiny_step_height
);
2615 case WID_TRSL_ALL_VEHICLES
:
2616 size
->width
= this->ComputeSlotInfoSize();
2617 size
->height
= this->tiny_step_height
;
2620 case WID_TRSL_SORT_BY_ORDER
: {
2621 Dimension d
= GetStringBoundingBox(this->GetWidget
<NWidgetCore
>(widget
)->widget_data
);
2622 d
.width
+= padding
.width
+ Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
2623 d
.height
+= padding
.height
;
2624 *size
= maxdim(*size
, d
);
2628 case WID_TRSL_LIST_VEHICLE
:
2629 this->ComputeSlotInfoSize();
2630 resize
->height
= GetVehicleListHeight(this->vli
.vtype
, this->tiny_step_height
);
2631 size
->height
= 4 * resize
->height
;
2637 * Some data on this window has become invalid.
2638 * @param data Information about the changed data.
2639 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
2641 virtual void OnInvalidateData(int data
= 0, bool gui_scope
= true)
2644 /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
2645 this->vehicles
.ForceRebuild();
2646 this->slots
.ForceRebuild();
2648 this->vehicles
.ForceResort();
2649 this->slots
.ForceResort();
2652 /* Process ID-invalidation in command-scope as well */
2653 if (this->slot_rename
!= INVALID_TRACE_RESTRICT_SLOT_ID
&& this->slot_rename
!= NEW_TRACE_RESTRICT_SLOT_ID
&&
2654 !TraceRestrictSlot::IsValidID(this->slot_rename
)) {
2655 DeleteWindowByClass(WC_QUERY_STRING
);
2656 this->slot_rename
= INVALID_TRACE_RESTRICT_SLOT_ID
;
2659 if (this->vli
.index
!= ALL_TRAINS_TRACE_RESTRICT_SLOT_ID
&& !TraceRestrictSlot::IsValidID(this->vli
.index
)) {
2660 this->vli
.index
= ALL_TRAINS_TRACE_RESTRICT_SLOT_ID
;
2665 virtual void SetStringParameters(int widget
) const
2668 case WID_TRSL_FILTER_BY_CARGO
:
2669 SetDParam(0, this->cargo_filter_texts
[this->cargo_filter_criteria
]);
2674 virtual void OnPaint()
2676 /* If we select the all vehicles, this->list will contain all vehicles of the owner
2677 * else this->list will contain all vehicles which belong to the selected group */
2678 this->BuildVehicleList();
2679 this->SortVehicleList();
2681 this->BuildSlotList(this->owner
);
2683 this->slot_sb
->SetCount(this->slots
.Length());
2684 this->vscroll
->SetCount(this->vehicles
.Length());
2686 /* Disable the slot specific function when we select all vehicles */
2687 this->SetWidgetsDisabledState(this->vli
.index
== ALL_TRAINS_TRACE_RESTRICT_SLOT_ID
|| _local_company
!= this->vli
.company
,
2688 WID_TRSL_DELETE_SLOT
,
2689 WID_TRSL_RENAME_SLOT
,
2690 WID_TRSL_SET_SLOT_MAX_OCCUPANCY
,
2693 /* Disable remaining buttons for non-local companies
2694 * Needed while changing _local_company, eg. by cheats
2695 * All procedures (eg. move vehicle to a slot)
2696 * verify, whether you are the owner of the vehicle,
2697 * so it doesn't have to be disabled
2699 this->SetWidgetsDisabledState(_local_company
!= this->vli
.company
,
2700 WID_TRSL_CREATE_SLOT
,
2703 /* Set text of sort by dropdown */
2704 this->GetWidget
<NWidgetCore
>(WID_TRSL_SORT_BY_DROPDOWN
)->widget_data
= this->vehicle_sorter_names
[this->vehicles
.SortType()];
2706 this->GetWidget
<NWidgetCore
>(WID_TRSL_FILTER_BY_CARGO
)->widget_data
= this->cargo_filter_texts
[this->cargo_filter_criteria
];
2708 this->DrawWidgets();
2711 virtual void DrawWidget(const Rect
&r
, int widget
) const
2714 case WID_TRSL_ALL_VEHICLES
:
2715 DrawSlotInfo(r
.top
+ WD_FRAMERECT_TOP
, r
.left
, r
.right
, ALL_TRAINS_TRACE_RESTRICT_SLOT_ID
);
2718 case WID_TRSL_LIST_SLOTS
: {
2719 int y1
= r
.top
+ WD_FRAMERECT_TOP
;
2720 int max
= min(this->slot_sb
->GetPosition() + this->slot_sb
->GetCapacity(), this->slots
.Length());
2721 for (int i
= this->slot_sb
->GetPosition(); i
< max
; ++i
) {
2722 const TraceRestrictSlot
*slot
= this->slots
[i
];
2724 assert(slot
->owner
== this->owner
);
2726 DrawSlotInfo(y1
, r
.left
, r
.right
, slot
->index
);
2728 y1
+= this->tiny_step_height
;
2733 case WID_TRSL_SORT_BY_ORDER
:
2734 this->DrawSortButtonState(WID_TRSL_SORT_BY_ORDER
, this->vehicles
.IsDescSortOrder() ? SBS_DOWN
: SBS_UP
);
2737 case WID_TRSL_LIST_VEHICLE
:
2738 this->DrawVehicleListItems(this->vehicle_sel
, this->resize
.step_height
, r
);
2743 static void DeleteSlotCallback(Window
*win
, bool confirmed
)
2746 TraceRestrictSlotWindow
*w
= (TraceRestrictSlotWindow
*)win
;
2747 w
->vli
.index
= ALL_TRAINS_TRACE_RESTRICT_SLOT_ID
;
2748 DoCommandP(0, w
->slot_confirm
, 0, CMD_DELETE_TRACERESTRICT_SLOT
| CMD_MSG(STR_TRACE_RESTRICT_ERROR_SLOT_CAN_T_DELETE
));
2752 virtual void OnClick(Point pt
, int widget
, int click_count
)
2755 case WID_TRSL_SORT_BY_ORDER
: // Flip sorting method ascending/descending
2756 this->vehicles
.ToggleSortOrder();
2760 case WID_TRSL_SORT_BY_DROPDOWN
: // Select sorting criteria dropdown menu
2761 ShowDropDownMenu(this, this->vehicle_sorter_names
, this->vehicles
.SortType(), WID_TRSL_SORT_BY_DROPDOWN
, 0, 0);
2764 case WID_TRSL_FILTER_BY_CARGO
: // Cargo filter dropdown
2765 ShowDropDownMenu(this, this->cargo_filter_texts
, this->cargo_filter_criteria
, WID_TRSL_FILTER_BY_CARGO
, 0, 0);
2768 case WID_TRSL_ALL_VEHICLES
: // All vehicles button
2769 if (this->vli
.index
!= ALL_TRAINS_TRACE_RESTRICT_SLOT_ID
) {
2770 this->vli
.index
= ALL_TRAINS_TRACE_RESTRICT_SLOT_ID
;
2771 this->slot_sel
= INVALID_TRACE_RESTRICT_SLOT_ID
;
2772 this->vehicles
.ForceRebuild();
2777 case WID_TRSL_LIST_SLOTS
: { // Matrix Slot
2778 uint id_s
= this->slot_sb
->GetScrolledRowFromWidget(pt
.y
, this, WID_TRSL_LIST_SLOTS
, 0, this->tiny_step_height
);
2779 if (id_s
>= this->slots
.Length()) return;
2781 this->slot_sel
= this->vli
.index
= this->slots
[id_s
]->index
;
2783 this->vehicles
.ForceRebuild();
2788 case WID_TRSL_LIST_VEHICLE
: { // Matrix Vehicle
2789 uint id_v
= this->vscroll
->GetScrolledRowFromWidget(pt
.y
, this, WID_TRSL_LIST_VEHICLE
);
2790 if (id_v
>= this->vehicles
.Length()) return; // click out of list bound
2792 const Vehicle
*v
= this->vehicles
[id_v
];
2793 if (VehicleClicked(v
)) break;
2795 this->vehicle_sel
= v
->index
;
2797 SetObjectToPlaceWnd(SPR_CURSOR_MOUSE
, PAL_NONE
, HT_DRAG
, this);
2798 SetMouseCursorVehicle(v
, EIT_IN_LIST
);
2799 _cursor
.vehchain
= true;
2805 case WID_TRSL_CREATE_SLOT
: { // Create a new slot
2806 this->ShowCreateSlotWindow();
2810 case WID_TRSL_DELETE_SLOT
: { // Delete the selected slot
2811 this->slot_confirm
= this->vli
.index
;
2812 ShowQuery(STR_TRACE_RESTRICT_SLOT_QUERY_DELETE_CAPTION
, STR_TRACE_RESTRICT_SLOT_DELETE_QUERY_TEXT
, this, DeleteSlotCallback
);
2816 case WID_TRSL_RENAME_SLOT
: // Rename the selected slot
2817 this->ShowRenameSlotWindow(this->vli
.index
);
2820 case WID_TRSL_SET_SLOT_MAX_OCCUPANCY
: // Set max occupancy of the selected slot
2821 this->ShowSetSlotMaxOccupancyWindow(this->vli
.index
);
2826 void OnDragDrop_Vehicle(Point pt
, int widget
)
2829 case WID_TRSL_ALL_VEHICLES
: // All vehicles
2830 if (this->slot_sel
!= INVALID_TRACE_RESTRICT_SLOT_ID
) {
2831 DoCommandP(0, this->slot_sel
, this->vehicle_sel
, CMD_REMOVE_VEHICLE_TRACERESTRICT_SLOT
| CMD_MSG(STR_TRACE_RESTRICT_ERROR_SLOT_CAN_T_REMOVE_VEHICLE
));
2833 this->vehicle_sel
= INVALID_VEHICLE
;
2834 this->slot_over
= INVALID_GROUP
;
2840 case WID_TRSL_LIST_SLOTS
: { // Matrix slot
2841 const VehicleID vindex
= this->vehicle_sel
;
2842 this->vehicle_sel
= INVALID_VEHICLE
;
2843 this->slot_over
= INVALID_GROUP
;
2846 uint id_s
= this->slot_sb
->GetScrolledRowFromWidget(pt
.y
, this, WID_TRSL_LIST_SLOTS
, 0, this->tiny_step_height
);
2847 if (id_s
>= this->slots
.Length()) return; // click out of list bound
2849 if (_ctrl_pressed
) {
2850 // remove from old group
2851 DoCommandP(0, this->slot_sel
, vindex
, CMD_REMOVE_VEHICLE_TRACERESTRICT_SLOT
| CMD_MSG(STR_TRACE_RESTRICT_ERROR_SLOT_CAN_T_REMOVE_VEHICLE
));
2853 DoCommandP(0, this->slots
[id_s
]->index
, vindex
, CMD_ADD_VEHICLE_TRACERESTRICT_SLOT
| CMD_MSG(STR_TRACE_RESTRICT_ERROR_SLOT_CAN_T_ADD_VEHICLE
));
2857 case WID_TRSL_LIST_VEHICLE
: { // Matrix vehicle
2858 const VehicleID vindex
= this->vehicle_sel
;
2859 this->vehicle_sel
= INVALID_VEHICLE
;
2860 this->slot_over
= INVALID_GROUP
;
2863 uint id_v
= this->vscroll
->GetScrolledRowFromWidget(pt
.y
, this, WID_TRSL_LIST_VEHICLE
);
2864 if (id_v
>= this->vehicles
.Length()) return; // click out of list bound
2866 const Vehicle
*v
= this->vehicles
[id_v
];
2867 if (!VehicleClicked(v
) && vindex
== v
->index
) {
2868 ShowVehicleViewWindow(v
);
2875 virtual void OnDragDrop(Point pt
, int widget
)
2877 if (this->vehicle_sel
!= INVALID_VEHICLE
) OnDragDrop_Vehicle(pt
, widget
);
2879 _cursor
.vehchain
= false;
2882 virtual void OnQueryTextFinished(char *str
)
2884 if (str
!= nullptr) {
2885 if (this->slot_set_max_occupancy
) {
2886 if (!StrEmpty(str
)) DoCommandP(0, this->slot_rename
| (1 << 16), atoi(str
), CMD_ALTER_TRACERESTRICT_SLOT
| CMD_MSG(STR_TRACE_RESTRICT_ERROR_SLOT_CAN_T_SET_MAX_OCCUPANCY
));
2887 } else if (this->slot_rename
== NEW_TRACE_RESTRICT_SLOT_ID
) {
2888 DoCommandP(0, 0, 0, CMD_CREATE_TRACERESTRICT_SLOT
| CMD_MSG(STR_TRACE_RESTRICT_ERROR_SLOT_CAN_T_CREATE
), nullptr, str
);
2890 DoCommandP(0, this->slot_rename
, 0, CMD_ALTER_TRACERESTRICT_SLOT
| CMD_MSG(STR_TRACE_RESTRICT_ERROR_SLOT_CAN_T_RENAME
), nullptr, str
);
2893 this->slot_rename
= INVALID_TRACE_RESTRICT_SLOT_ID
;
2896 virtual void OnResize()
2898 this->slot_sb
->SetCapacityFromWidget(this, WID_TRSL_LIST_SLOTS
);
2899 this->vscroll
->SetCapacityFromWidget(this, WID_TRSL_LIST_VEHICLE
);
2902 virtual void OnDropdownSelect(int widget
, int index
)
2905 case WID_TRSL_SORT_BY_DROPDOWN
:
2906 this->vehicles
.SetSortType(index
);
2909 case WID_TRSL_FILTER_BY_CARGO
: // Select a cargo filter criteria
2910 this->SetCargoFilterIndex(index
);
2913 default: NOT_REACHED();
2919 virtual void OnTick()
2921 if (_pause_mode
!= PM_UNPAUSED
) return;
2922 if (this->slots
.NeedResort() || this->vehicles
.NeedResort()) {
2927 virtual void OnPlaceObjectAbort()
2929 /* abort drag & drop */
2930 this->vehicle_sel
= INVALID_VEHICLE
;
2931 this->DirtyHighlightedSlotWidget();
2932 this->slot_over
= INVALID_GROUP
;
2933 this->SetWidgetDirty(WID_TRSL_LIST_VEHICLE
);
2936 virtual void OnMouseDrag(Point pt
, int widget
)
2938 if (this->vehicle_sel
== INVALID_VEHICLE
) return;
2940 /* A vehicle is dragged over... */
2941 TraceRestrictSlotID new_slot_over
= INVALID_TRACE_RESTRICT_SLOT_ID
;
2943 case WID_TRSL_ALL_VEHICLES
: // ... all trains.
2944 new_slot_over
= ALL_TRAINS_TRACE_RESTRICT_SLOT_ID
;
2947 case WID_TRSL_LIST_SLOTS
: { // ... the list of slots.
2948 uint id_s
= this->slot_sb
->GetScrolledRowFromWidget(pt
.y
, this, WID_TRSL_LIST_SLOTS
, 0, this->tiny_step_height
);
2949 if (id_s
< this->slots
.Length()) new_slot_over
= this->slots
[id_s
]->index
;
2954 /* Do not highlight when dragging over the current group */
2955 if (this->slot_sel
== new_slot_over
) new_slot_over
= INVALID_TRACE_RESTRICT_SLOT_ID
;
2957 /* Mark widgets as dirty if the group changed. */
2958 if (new_slot_over
!= this->slot_over
) {
2959 this->DirtyHighlightedSlotWidget();
2960 this->slot_over
= new_slot_over
;
2961 this->DirtyHighlightedSlotWidget();
2965 void ShowRenameSlotWindow(TraceRestrictSlotID slot_id
)
2967 assert(TraceRestrictSlot::IsValidID(slot_id
));
2968 this->slot_set_max_occupancy
= false;
2969 this->slot_rename
= slot_id
;
2970 SetDParam(0, slot_id
);
2971 ShowQueryString(STR_TRACE_RESTRICT_SLOT_NAME
, STR_TRACE_RESTRICT_SLOT_RENAME_CAPTION
, MAX_LENGTH_TRACE_RESTRICT_SLOT_NAME_CHARS
, this, CS_ALPHANUMERAL
, QSF_ENABLE_DEFAULT
| QSF_LEN_IN_CHARS
);
2974 void ShowSetSlotMaxOccupancyWindow(TraceRestrictSlotID slot_id
)
2976 this->slot_set_max_occupancy
= true;
2977 this->slot_rename
= slot_id
;
2978 SetDParam(0, TraceRestrictSlot::Get(slot_id
)->max_occupancy
);
2979 ShowQueryString(STR_JUST_INT
, STR_TRACE_RESTRICT_SLOT_SET_MAX_OCCUPANCY_CAPTION
, 5, this, CS_NUMERAL
, QSF_ENABLE_DEFAULT
);
2982 void ShowCreateSlotWindow()
2984 this->slot_set_max_occupancy
= false;
2985 this->slot_rename
= NEW_TRACE_RESTRICT_SLOT_ID
;
2986 ShowQueryString(STR_EMPTY
, STR_TRACE_RESTRICT_SLOT_CREATE_CAPTION
, MAX_LENGTH_TRACE_RESTRICT_SLOT_NAME_CHARS
, this, CS_ALPHANUMERAL
, QSF_ENABLE_DEFAULT
| QSF_LEN_IN_CHARS
);
2990 * Tests whether a given vehicle is selected in the window, and unselects it if necessary.
2991 * Called when the vehicle is deleted.
2992 * @param vehicle Vehicle that is going to be deleted
2994 void UnselectVehicle(VehicleID vehicle
)
2996 if (this->vehicle_sel
== vehicle
) ResetObjectToPlace();
3000 static WindowDesc
_slot_window_desc(
3001 WDP_AUTO
, "list_groups_train", 525, 246,
3002 WC_TRACE_RESTRICT_SLOTS
, WC_NONE
,
3004 _nested_slot_widgets
, lengthof(_nested_slot_widgets
)
3008 * Show the trace restrict slot window for the given company.
3009 * @param company The company to show the window for.
3011 void ShowTraceRestrictSlotWindow(CompanyID company
)
3013 if (!Company::IsValidID(company
)) return;
3015 WindowNumber num
= VehicleListIdentifier(VL_SLOT_LIST
, VEH_TRAIN
, company
).Pack();
3016 AllocateWindowDescFront
<TraceRestrictSlotWindow
>(&_slot_window_desc
, num
);
3020 * Finds a group list window determined by vehicle type and owner
3021 * @param vt vehicle type
3022 * @param owner owner of groups
3023 * @return pointer to VehicleGroupWindow, nullptr if not found
3025 static inline TraceRestrictSlotWindow
*FindTraceRestrictSlotWindow(Owner owner
)
3027 return (TraceRestrictSlotWindow
*)FindWindowById(GetWindowClassForVehicleType(VEH_TRAIN
), VehicleListIdentifier(VL_SLOT_LIST
, VEH_TRAIN
, owner
).Pack());
3031 * Removes the highlight of a vehicle in a group window
3032 * @param *v Vehicle to remove all highlights from
3034 void DeleteTraceRestrictSlotHighlightOfVehicle(const Vehicle
*v
)
3036 /* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any group windows either
3037 * If that is the case, we can skip looping though the windows and save time
3039 if (_special_mouse_mode
!= WSM_DRAGDROP
) return;
3041 TraceRestrictSlotWindow
*w
= FindTraceRestrictSlotWindow(v
->owner
);
3042 if (w
!= nullptr) w
->UnselectVehicle(v
->index
);