Fix crash when setting separation mode for vehicles with no orders list.
[openttd-joker.git] / src / logic_signals_gui.cpp
blob897c5c237cc4939839e5780436f7bda6e16a23e1
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
8 /** @file logic_signals_gui.cpp A Window for editing signal programs. */
10 #include "logic_signals.h"
11 #include "window_type.h"
12 #include "window_gui.h"
13 #include "table/strings.h"
14 #include "command_func.h"
15 #include "tilehighlight_func.h"
16 #include "table/sprites.h"
17 #include "rail_map.h"
18 #include "strings_func.h"
19 #include "overlay_cmd.h"
21 /**
22 * Definition of widgets
24 enum ProgramSignalWidgets {
25 WID_PROGSIG_OWN_DEFAULT_COLOR_RED,
26 WID_PROGSIG_OWN_DEFAULT_COLOR_GREEN,
27 WID_PROGSIG_TRIGGER_COLOR_RED,
28 WID_PROGSIG_TRIGGER_COLOR_GREEN,
29 WID_PROGSIG_OPERATOR_OR,
30 WID_PROGSIG_OPERATOR_AND,
31 WID_PROGSIG_OPERATOR_NAND,
32 WID_PROGSIG_OPERATOR_XOR,
33 WID_PROGSIG_LINK_COUNT,
34 WID_PROGSIG_ADD_LINK,
35 WID_PROGSIG_CLEAR_LINKS
38 /**
39 * The Window used for editing signal programs of logic signals.
41 struct SignalProgramWindow : Window
43 SignalProgram *program;
44 bool add_link_button;
46 /**
47 * Constructor
49 SignalProgramWindow(WindowDesc *desc, WindowNumber window_number, SignalProgram *prog) : Window(desc)
51 this->program = prog;
52 this->add_link_button = false;
53 this->InitNested(window_number);
54 this->OnInvalidateData();
57 ~SignalProgramWindow()
59 if (_focused_window == this) {
60 Overlays::Instance()->ClearLogicSignalOverlay();
64 /**
65 * Handler which is executed whenever user clicks on the window.
67 virtual void OnClick(Point pt, int widget, int click_count)
69 uint32 p1 = 0;
70 const uint32 p2 = 0;
71 bool changed = false;
73 SB(p1, 0, 3, program->track);
75 switch (widget) {
76 case WID_PROGSIG_OWN_DEFAULT_COLOR_RED:
77 if (this->program->own_default_state != SIGNAL_STATE_RED) {
78 SB(p1, 3, 3, 1);
79 SB(p1, 6, 2, SIGNAL_STATE_RED);
80 changed = true;
82 break;
83 case WID_PROGSIG_OWN_DEFAULT_COLOR_GREEN:
84 if (this->program->own_default_state != SIGNAL_STATE_GREEN) {
85 SB(p1, 3, 3, 1);
86 SB(p1, 6, 2, SIGNAL_STATE_GREEN);
87 changed = true;
89 break;
90 case WID_PROGSIG_TRIGGER_COLOR_RED:
91 if (this->program->trigger_state != SIGNAL_STATE_RED) {
92 SB(p1, 3, 3, 2);
93 SB(p1, 6, 2, SIGNAL_STATE_RED);
94 changed = true;
96 break;
97 case WID_PROGSIG_TRIGGER_COLOR_GREEN:
98 if (this->program->trigger_state != SIGNAL_STATE_GREEN) {
99 SB(p1, 3, 3, 2);
100 SB(p1, 6, 2, SIGNAL_STATE_GREEN);
101 changed = true;
103 break;
104 case WID_PROGSIG_OPERATOR_OR:
105 if (this->program->signal_op != SIGNAL_OP_OR) {
106 SB(p1, 3, 3, 3);
107 SB(p1, 6, 2, SIGNAL_OP_OR);
108 changed = true;
110 break;
111 case WID_PROGSIG_OPERATOR_AND:
112 if (this->program->signal_op != SIGNAL_OP_AND) {
113 SB(p1, 3, 3, 3);
114 SB(p1, 6, 2, SIGNAL_OP_AND);
115 changed = true;
117 break;
118 case WID_PROGSIG_OPERATOR_NAND:
119 if (this->program->signal_op != SIGNAL_OP_NAND) {
120 SB(p1, 3, 3, 3);
121 SB(p1, 6, 2, SIGNAL_OP_NAND);
122 changed = true;
124 break;
125 case WID_PROGSIG_OPERATOR_XOR:
126 if (this->program->signal_op != SIGNAL_OP_XOR) {
127 SB(p1, 3, 3, 3);
128 SB(p1, 6, 2, SIGNAL_OP_XOR);
129 changed = true;
131 break;
132 case WID_PROGSIG_ADD_LINK:
133 SetWidgetDirty(WID_PROGSIG_ADD_LINK);
134 ToggleWidgetLoweredState(WID_PROGSIG_ADD_LINK);
135 if (IsWidgetLowered(WID_PROGSIG_ADD_LINK)) {
136 SetObjectToPlaceWnd(SPR_CURSOR_TRANSMITTER, PAL_NONE, HT_RECT, this);
137 } else {
138 ResetObjectToPlace();
140 break;
141 case WID_PROGSIG_CLEAR_LINKS:
142 if (this->program->LinkCount() > 0) {
143 SB(p1, 3, 2, 5);
144 changed = true;
146 break;
149 if (changed) DoCommandP(program->tile, p1, p2, CMD_PROGRAM_LOGIC_SIGNAL | CMD_MSG(STR_ERROR_PROGRAM_SIGNAL_HEADER));
152 virtual void OnFocus(Window *previously_focused_window) override
154 if (this != previously_focused_window) {
155 Overlays::Instance()->SetLogicSignalOverlay(this->program);
159 virtual void OnFocusLost(Window *newly_focused_window) override
161 if (newly_focused_window != nullptr && newly_focused_window->window_class != WC_SIGNAL_PROGRAM) {
162 Overlays::Instance()->ClearLogicSignalOverlay();
167 * Handler which is executed whenever data has become invalid on the window.
169 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
171 if (!gui_scope) return;
173 this->SetWidgetLoweredState(WID_PROGSIG_OWN_DEFAULT_COLOR_RED, this->program->own_default_state == SIGNAL_STATE_RED);
174 this->SetWidgetLoweredState(WID_PROGSIG_OWN_DEFAULT_COLOR_GREEN, this->program->own_default_state == SIGNAL_STATE_GREEN);
175 this->SetWidgetLoweredState(WID_PROGSIG_TRIGGER_COLOR_RED, this->program->trigger_state == SIGNAL_STATE_RED);
176 this->SetWidgetLoweredState(WID_PROGSIG_TRIGGER_COLOR_GREEN, this->program->trigger_state == SIGNAL_STATE_GREEN);
177 this->SetWidgetLoweredState(WID_PROGSIG_OPERATOR_OR, this->program->signal_op == SIGNAL_OP_OR);
178 this->SetWidgetLoweredState(WID_PROGSIG_OPERATOR_AND, this->program->signal_op == SIGNAL_OP_AND);
179 this->SetWidgetLoweredState(WID_PROGSIG_OPERATOR_NAND, this->program->signal_op == SIGNAL_OP_NAND);
180 this->SetWidgetLoweredState(WID_PROGSIG_OPERATOR_XOR, this->program->signal_op == SIGNAL_OP_XOR);
184 * Used to set dynamic string parameters to the widget.
186 virtual void SetStringParameters(int widget) const
188 switch (widget) {
189 case WID_PROGSIG_LINK_COUNT:
190 SetDParam(0, program->LinkCount());
191 break;
196 * Executed whenever user tries to link two signals together
198 virtual void OnPlaceObject(Point pt, TileIndex tile)
200 uint32 p1 = 0;
202 SB(p1, 0, 3, this->program->track);
203 SB(p1, 3, 3, 4);
205 DoCommandP(this->program->tile, p1, tile, CMD_PROGRAM_LOGIC_SIGNAL | CMD_MSG(STR_ERROR_LINK_SIGNAL_HEADER));
209 * Executed when user aborts the linking of signals
211 virtual void OnPlaceObjectAbort()
213 SetWidgetLoweredState(WID_PROGSIG_ADD_LINK, false);
214 SetWidgetDirty(WID_PROGSIG_ADD_LINK);
219 * Widget structure definition for programmable signals
221 static const NWidgetPart _nested_program_widgets[] = {
222 NWidget(NWID_HORIZONTAL),
223 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
224 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_PROGSIG_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
225 NWidget(WWT_SHADEBOX, COLOUR_GREY),
226 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
227 NWidget(WWT_STICKYBOX, COLOUR_GREY),
228 EndContainer(),
229 NWidget(WWT_PANEL, COLOUR_GREY),
230 NWidget(NWID_HORIZONTAL), SetPIP(3, 0, 0),
231 NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(200, 14), SetFill(1, 0), SetDataTip(STR_PROGSIG_OWN_DEFAULT_COLOR, STR_PROGSIG_OWN_DEFAULT_COLOR_TOOLTIP),
232 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_PROGSIG_OWN_DEFAULT_COLOR_RED), SetMinimalSize(80, 14), SetFill(1, 0), SetDataTip(STR_PROGSIG_COLOR_RED, STR_PROGSIG_OWN_DEFAULT_COLOR_TOOLTIP),
233 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_PROGSIG_OWN_DEFAULT_COLOR_GREEN), SetMinimalSize(80, 14), SetFill(1, 0), SetDataTip(STR_PROGSIG_COLOR_GREEN, STR_PROGSIG_OWN_DEFAULT_COLOR_TOOLTIP),
234 EndContainer(),
235 NWidget(NWID_HORIZONTAL), SetPIP(3, 0, 0),
236 NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(200, 14), SetFill(1, 0), SetDataTip(STR_PROGSIG_TRIGGER_COLOR, STR_PROGSIG_TRIGGER_COLOR_TOOLTIP),
237 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_PROGSIG_TRIGGER_COLOR_RED), SetMinimalSize(80, 14), SetFill(1, 0), SetDataTip(STR_PROGSIG_COLOR_RED, STR_PROGSIG_TRIGGER_COLOR_TOOLTIP),
238 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_PROGSIG_TRIGGER_COLOR_GREEN), SetMinimalSize(80, 14), SetFill(1, 0), SetDataTip(STR_PROGSIG_COLOR_GREEN, STR_PROGSIG_TRIGGER_COLOR_TOOLTIP),
239 EndContainer(),
240 NWidget(NWID_HORIZONTAL), SetPIP(3, 0, 0),
241 NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(200, 14), SetFill(1, 0), SetDataTip(STR_PROGSIG_OPERATOR, STR_PROGSIG_OPERATOR_TOOLTIP),
242 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_PROGSIG_OPERATOR_OR), SetMinimalSize(40, 14), SetFill(1, 0), SetDataTip(STR_PROGSIG_OP_OR, STR_PROGSIG_OPERATOR_TOOLTIP),
243 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_PROGSIG_OPERATOR_AND), SetMinimalSize(40, 14), SetFill(1, 0), SetDataTip(STR_PROGSIG_OP_AND, STR_PROGSIG_OPERATOR_TOOLTIP),
244 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_PROGSIG_OPERATOR_XOR), SetMinimalSize(40, 14), SetFill(1, 0), SetDataTip(STR_PROGSIG_OP_XOR, STR_PROGSIG_OPERATOR_TOOLTIP),
245 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_PROGSIG_OPERATOR_NAND), SetMinimalSize(40, 14), SetFill(1, 0), SetDataTip(STR_PROGSIG_OP_NAND, STR_PROGSIG_OPERATOR_TOOLTIP),
246 EndContainer(),
247 NWidget(NWID_HORIZONTAL), SetPIP(3, 0, 0),
248 NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(200, 14), SetFill(1, 0), SetDataTip(STR_PROGSIG_LINKED_SIGNALS, STR_PROGSIG_LINKED_SIGNALS_TOOLTIP),
249 NWidget(WWT_TEXT, COLOUR_ORANGE, WID_PROGSIG_LINK_COUNT), SetMinimalSize(160, 14), SetFill(1, 0), SetDataTip(STR_JUST_INT, STR_PROGSIG_LINKED_SIGNALS_TOOLTIP),
250 EndContainer(),
251 EndContainer(),
252 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
253 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_PROGSIG_ADD_LINK), SetFill(1, 0), SetDataTip(STR_PROGSIG_ADD_LINK, STR_PROGSIG_ADD_LINK_TOOLTIP),
254 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_PROGSIG_CLEAR_LINKS), SetFill(1, 0), SetDataTip(STR_PROGSIG_CLEAR_LINKS, STR_PROGSIG_CLEAR_LINKS_TOOLTIP),
255 EndContainer(),
258 static WindowDesc _signal_program_desc (
259 WDP_AUTO, nullptr, 0, 0,
260 WC_SIGNAL_PROGRAM, WC_NONE,
261 WDF_CONSTRUCTION,
262 _nested_program_widgets, lengthof(_nested_program_widgets)
266 * Displays a signal program window.
267 * @param program The target signal program which this window modifies.
269 void ShowSignalProgramWindow(SignalProgram *program)
271 WindowNumber wnum = GetSignalReference(program->tile, program->track);
273 if (BringWindowToFrontById(WC_SIGNAL_PROGRAM, wnum) != nullptr) return;
275 new SignalProgramWindow(&_signal_program_desc, wnum, program);