00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "programmable_signals.h"
00014 #include "command_func.h"
00015 #include "window_func.h"
00016 #include "strings_func.h"
00017 #include "string_func.h"
00018 #include "viewport_func.h"
00019 #include "textbuf_gui.h"
00020 #include "company_func.h"
00021 #include "widgets/dropdown_func.h"
00022 #include "gui.h"
00023 #include "gfx_func.h"
00024 #include "tilehighlight_func.h"
00025 #include "rail_map.h"
00026 #include "tile_cmd.h"
00027
00028 #include "table/sprites.h"
00029 #include "table/strings.h"
00030
00031 enum ProgramWindowWidgets {
00032 PROGRAM_WIDGET_CAPTION,
00033 PROGRAM_WIDGET_INSTRUCTION_LIST,
00034 PROGRAM_WIDGET_SCROLLBAR,
00035
00036 PROGRAM_WIDGET_SEL_TOP_LEFT,
00037 PROGRAM_WIDGET_SEL_TOP_MIDDLE,
00038 PROGRAM_WIDGET_SEL_TOP_RIGHT,
00039
00040 PROGRAM_WIDGET_SET_STATE,
00041 PROGRAM_WIDGET_COND_VARIABLE,
00042 PROGRAM_WIDGET_COND_COMPARATOR,
00043 PROGRAM_WIDGET_COND_VALUE,
00044 PROGRAM_WIDGET_COND_GOTO_SIGNAL,
00045 PROGRAM_WIDGET_COND_SET_SIGNAL,
00046
00047 PROGRAM_WIDGET_GOTO_SIGNAL,
00048 PROGRAM_WIDGET_INSERT,
00049 PROGRAM_WIDGET_REMOVE,
00050 };
00051
00052 enum PanelWidgets {
00053
00054 DPL_COND_VARIABLE = 0,
00055 DPL_SET_STATE,
00056
00057
00058 DPM_COND_COMPARATOR = 0,
00059 DPM_COND_GOTO_SIGNAL,
00060
00061
00062 DPR_COND_VALUE = 0,
00063 DPR_COND_SET_SIGNAL
00064 };
00065
00066 static const StringID _program_insert[] = {
00067 STR_PROGSIG_INSERT_IF,
00068 STR_PROGSIG_INSERT_SET_SIGNAL,
00069 INVALID_STRING_ID
00070 };
00071
00072 static SignalOpcode OpcodeForIndex(int index)
00073 {
00074 switch (index) {
00075 case 0: return PSO_IF;
00076 case 1: return PSO_SET_SIGNAL;
00077 default: NOT_REACHED();
00078 }
00079 }
00080
00081 static bool IsConditionComparator(SignalCondition *cond)
00082 {
00083 switch (cond->ConditionCode()) {
00084 case PSC_NUM_GREEN:
00085 case PSC_NUM_RED:
00086 return true;
00087
00088 default:
00089 return false;
00090 }
00091 }
00092
00093 static const StringID _program_condvar[] = {
00094 STR_PROGSIG_COND_ALWAYS,
00095 STR_PROGSIG_COND_NEVER,
00096 STR_PROGSIG_CONDVAR_NUM_GREEN,
00097 STR_PROGSIG_CONDVAR_NUM_RED,
00098 STR_PROGSIG_COND_SIGNAL_STATE,
00099 INVALID_STRING_ID
00100 };
00101
00102
00103 static const StringID _program_comparator[] = {
00104 STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS,
00105 STR_ORDER_CONDITIONAL_COMPARATOR_NOT_EQUALS,
00106 STR_ORDER_CONDITIONAL_COMPARATOR_LESS_THAN,
00107 STR_ORDER_CONDITIONAL_COMPARATOR_LESS_EQUALS,
00108 STR_ORDER_CONDITIONAL_COMPARATOR_MORE_THAN,
00109 STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS,
00110 STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE,
00111 STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE,
00112 INVALID_STRING_ID
00113 };
00114
00115 static const StringID _program_sigstate[] = {
00116 STR_COLOUR_RED,
00117 STR_COLOUR_GREEN,
00118 INVALID_STRING_ID
00119 };
00120
00122 static char *GetConditionString(SignalCondition *cond, char *buf, char *buflast, bool selected)
00123 {
00124 StringID string = INVALID_STRING_ID;
00125 bool comparator = IsConditionComparator(cond);
00126
00127 if (comparator) {
00128 SignalVariableCondition *cv = static_cast<SignalVariableCondition*>(cond);
00129 string = STR_PROGSIG_COND_COMPARE;
00130 SetDParam(0, _program_condvar[cond->ConditionCode()]);
00131 SetDParam(1, _program_comparator[cv->comparator]);
00132 SetDParam(2, cv->value);
00133 } else {
00134 string = _program_condvar[cond->ConditionCode()];
00135 if (cond->ConditionCode() == PSC_SIGNAL_STATE) {
00136 string = STR_PROGSIG_CONDVAR_SIGNAL_STATE;
00137 SetDParam(0, static_cast<SignalStateCondition*>(cond)->IsSignalValid()
00138 ? STR_PROGSIG_CONDVAR_SIGNAL_STATE_SPECIFIED : STR_PROGSIG_CONDVAR_SIGNAL_STATE_UNSPECIFIED);
00139 SetDParam(1, selected ? STR_WHITE : STR_BLACK);
00140 }
00141 }
00142 return GetString(buf, string, buflast);
00143 }
00144
00154 static void DrawInstructionString(SignalInstruction *instruction, int y, bool selected, int indent, int left, int right)
00155 {
00156 StringID instruction_string = INVALID_STRING_ID;
00157
00158 char condstr[512];
00159
00160 switch (instruction->Opcode()) {
00161 case PSO_FIRST:
00162 instruction_string = STR_PROGSIG_FIRST;
00163 break;
00164
00165 case PSO_LAST:
00166 instruction_string = STR_PROGSIG_LAST;
00167 break;
00168
00169 case PSO_IF: {
00170 SignalIf *if_ins = static_cast<SignalIf*>(instruction);
00171 GetConditionString(if_ins->condition, condstr, lastof(condstr), selected);
00172 SetDParamStr(0, condstr);
00173 instruction_string = STR_PROGSIG_IF;
00174 break;
00175 }
00176
00177 case PSO_IF_ELSE:
00178 instruction_string = STR_PROGSIG_ELSE;
00179 break;
00180
00181 case PSO_IF_ENDIF:
00182 instruction_string = STR_PROGSIG_ENDIF;
00183 break;
00184
00185 case PSO_SET_SIGNAL: {
00186 instruction_string = STR_PROGSIG_SET_SIGNAL;
00187 SignalSet *set = static_cast<SignalSet*>(instruction);
00188 SetDParam(0, _program_sigstate[set->to_state]);
00189 break;
00190 }
00191
00192 default: NOT_REACHED();
00193 }
00194
00195 DrawString(left + indent * 16, right, y, instruction_string, selected ? TC_WHITE : TC_BLACK);
00196 }
00197
00198 struct GuiInstruction {
00199 SignalInstruction *insn;
00200 uint indent;
00201 };
00202
00203 typedef SmallVector<GuiInstruction, 4> GuiInstructionList;
00204
00205 class ProgramWindow: public Window {
00206 public:
00207 ProgramWindow(const WindowDesc *desc, SignalReference ref)
00208 {
00209 this->tile = ref.tile;
00210 this->track = ref.track;
00211 this->selected_instruction = -1;
00212
00213 this->CreateNestedTree(desc);
00214 this->vscroll = this->GetScrollbar(PROGRAM_WIDGET_SCROLLBAR);
00215 this->FinishInitNested(desc, (ref.tile << 3) | ref.track);
00216
00217 program = GetSignalProgram(ref);
00218 RebuildInstructionList();
00219 }
00220
00221 virtual void OnClick(Point pt, int widget, int click_count)
00222 {
00223 switch (widget) {
00224 case PROGRAM_WIDGET_INSTRUCTION_LIST: {
00225 int sel = this->GetInstructionFromPt(pt.y);
00226
00227 this->DeleteChildWindows();
00228 HideDropDownMenu(this);
00229
00230 if (sel == -1 || this->GetOwner() != _local_company) {
00231
00232 this->selected_instruction = -1;
00233 } else {
00234 this->selected_instruction = sel;
00235 }
00236
00237 this->UpdateButtonState();
00238 } break;
00239
00240 case PROGRAM_WIDGET_INSERT: {
00241 DEBUG(misc, 5, "Selection is %d", this->selected_instruction);
00242 if (this->GetOwner() != _local_company || this->selected_instruction < 1)
00243 return;
00244 ShowDropDownMenu(this, _program_insert, -1, PROGRAM_WIDGET_INSERT, 0, 0, 0);
00245 } break;
00246
00247 case PROGRAM_WIDGET_REMOVE: {
00248 SignalInstruction *ins = GetSelected();
00249 if (this->GetOwner() != _local_company || !ins)
00250 return;
00251
00252 uint32 p1 = 0;
00253 SB(p1, 0, 3, this->track);
00254 SB(p1, 3, 16, ins->Id());
00255
00256 DoCommandP(this->tile, p1, 0, CMD_REMOVE_SIGNAL_INSTRUCTION | CMD_MSG(STR_ERROR_CAN_T_MODIFY_INSTRUCTION));
00257 } break;
00258
00259 case PROGRAM_WIDGET_SET_STATE: {
00260 SignalInstruction *si = this->GetSelected();
00261 if (!si || si->Opcode() != PSO_SET_SIGNAL) return;
00262 SignalSet *ss = static_cast <SignalSet*>(si);
00263
00264 ShowDropDownMenu(this, _program_sigstate, ss->to_state, PROGRAM_WIDGET_SET_STATE, 0, 0, 0);
00265 } break;
00266
00267 case PROGRAM_WIDGET_COND_VARIABLE: {
00268 SignalInstruction *si = this->GetSelected();
00269 if (!si || si->Opcode() != PSO_IF) return;
00270 SignalIf *sif = static_cast <SignalIf*>(si);
00271
00272 ShowDropDownMenu(this, _program_condvar, sif->condition->ConditionCode(), PROGRAM_WIDGET_COND_VARIABLE, 0, 0, 0);
00273 } break;
00274
00275 case PROGRAM_WIDGET_COND_COMPARATOR: {
00276 SignalInstruction *si = this->GetSelected();
00277 if (!si || si->Opcode() != PSO_IF) return;
00278 SignalIf *sif = static_cast <SignalIf*>(si);
00279 if (!IsConditionComparator(sif->condition)) return;
00280 SignalVariableCondition *vc = static_cast<SignalVariableCondition*>(sif->condition);
00281
00282 ShowDropDownMenu(this, _program_comparator, vc->comparator, PROGRAM_WIDGET_COND_COMPARATOR, 0, 0, 0);
00283 } break;
00284
00285 case PROGRAM_WIDGET_COND_VALUE: {
00286 SignalInstruction *si = this->GetSelected();
00287 if (!si || si->Opcode() != PSO_IF) return;
00288 SignalIf *sif = static_cast <SignalIf*>(si);
00289 if (!IsConditionComparator(sif->condition)) return;
00290 SignalVariableCondition *vc = static_cast<SignalVariableCondition*>(sif->condition);
00291
00292 SetDParam(0, vc->value);
00293 ShowQueryString(STR_JUST_INT, STR_PROGSIG_CONDITION_VALUE_CAPT, 5, this, CS_NUMERAL, QSF_NONE);
00294 } break;
00295
00296 case PROGRAM_WIDGET_COND_GOTO_SIGNAL: {
00297 SignalInstruction *si = this->GetSelected();
00298 if (!si || si->Opcode() != PSO_IF) return;
00299 SignalIf *sif = static_cast <SignalIf*>(si);
00300 if (sif->condition->ConditionCode() != PSC_SIGNAL_STATE) return;
00301 SignalStateCondition *sc = static_cast<SignalStateCondition*>(sif->condition);
00302
00303 if (sc->IsSignalValid()) {
00304 ScrollMainWindowToTile(sc->sig_tile);
00305 } else {
00306 ShowErrorMessage(STR_ERROR_CAN_T_GOTO_UNDEFINED_SIGNAL, STR_EMPTY, WL_INFO);
00307 }
00308 this->RaiseWidget(PROGRAM_WIDGET_COND_GOTO_SIGNAL);
00309 } break;
00310
00311 case PROGRAM_WIDGET_COND_SET_SIGNAL: {
00312 this->SetWidgetDirty(PROGRAM_WIDGET_COND_SET_SIGNAL);
00313 if (this->IsWidgetLowered(PROGRAM_WIDGET_COND_SET_SIGNAL)) {
00314 SetObjectToPlaceWnd(ANIMCURSOR_BUILDSIGNALS, PAL_NONE, HT_RECT, this);
00315 } else {
00316 ResetObjectToPlace();
00317 }
00318 } break;
00319
00320 case PROGRAM_WIDGET_GOTO_SIGNAL: {
00321 ScrollMainWindowToTile(this->tile);
00322 this->RaiseWidget(PROGRAM_WIDGET_GOTO_SIGNAL);
00323 } break;
00324 }
00325 }
00326
00327 virtual void OnPlaceObject(Point pt, TileIndex tile)
00328 {
00329 SignalInstruction *si = this->GetSelected();
00330 if (!si || si->Opcode() != PSO_IF) return;
00331 SignalIf *sif = static_cast <SignalIf*>(si);
00332 if (sif->condition->ConditionCode() != PSC_SIGNAL_STATE) return;
00333
00334 if (!IsPlainRailTile(tile)) {
00335 return;
00336 }
00337
00338 TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
00339 if (trackbits & TRACK_BIT_VERT) {
00340 trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT;
00341 }
00342
00343 if (trackbits & TRACK_BIT_HORZ) {
00344 trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER;
00345 }
00346 Track track = FindFirstTrack(trackbits);
00347
00348 if (track == INVALID_TRACK) {
00349 return;
00350 }
00351
00352 Trackdir td = TrackToTrackdir(track);
00353 Trackdir tdr = ReverseTrackdir(td);
00354
00355 if (HasSignalOnTrackdir(tile, td) && HasSignalOnTrackdir(tile, tdr)) {
00356 ShowErrorMessage(STR_ERROR_INVALID_SIGNAL, STR_ERROR_CAN_T_DEPEND_UPON_BIDIRECTIONAL_SIGNALS, WL_INFO);
00357 return;
00358 } else if (HasSignalOnTrackdir(tile, tdr) && !HasSignalOnTrackdir(tile, td)) {
00359 td = tdr;
00360 }
00361
00362 if (!HasSignalOnTrackdir(tile, td)) {
00363 return;
00364 }
00365
00366 if (!IsPresignalExit(tile, track)) {
00367 ShowErrorMessage(STR_ERROR_INVALID_SIGNAL, STR_ERROR_NOT_AN_EXIT_SIGNAL, WL_INFO);
00368 return;
00369 }
00370
00371 uint32 p1 = 0, p2 = 0;
00372 SB(p1, 0, 3, this->track);
00373 SB(p1, 3, 16, si->Id());
00374
00375 SB(p2, 0, 1, 1);
00376 SB(p2, 1, 5, td);
00377 SB(p2, 5, 27, tile);
00378
00379 DoCommandP(this->tile, p1, p2, CMD_MODIFY_SIGNAL_INSTRUCTION | CMD_MSG(STR_ERROR_CAN_T_MODIFY_INSTRUCTION));
00380 ResetObjectToPlace();
00381 this->RaiseWidget(PROGRAM_WIDGET_COND_SET_SIGNAL);
00382 }
00383
00384 virtual void OnQueryTextFinished(char *str)
00385 {
00386 if (!StrEmpty(str)) {
00387 SignalInstruction *si = this->GetSelected();
00388 if (!si || si->Opcode() != PSO_IF) return;
00389 SignalIf *sif = static_cast <SignalIf*>(si);
00390 if (!IsConditionComparator(sif->condition)) return;
00391
00392 uint value = atoi(str);
00393
00394 uint32 p1 = 0, p2 = 0;
00395 SB(p1, 0, 3, this->track);
00396 SB(p1, 3, 16, si->Id());
00397
00398 SB(p2, 0, 1, 1);
00399 SB(p2, 1, 2, SCF_VALUE);
00400 SB(p2, 3, 27, value);
00401
00402 DoCommandP(this->tile, p1, p2, CMD_MODIFY_SIGNAL_INSTRUCTION | CMD_MSG(STR_ERROR_CAN_T_MODIFY_INSTRUCTION));
00403 }
00404 }
00405
00406 virtual void OnDropdownSelect(int widget, int index)
00407 {
00408 SignalInstruction *ins = this->GetSelected();
00409 if (!ins) return;
00410
00411 switch (widget) {
00412 case PROGRAM_WIDGET_INSERT: {
00413 uint32 p1 = 0;
00414 SB(p1, 0, 3, this->track);
00415 SB(p1, 3, 16, ins->Id());
00416 SB(p1, 19, 8, OpcodeForIndex(index));
00417
00418 DoCommandP(this->tile, p1, 0, CMD_INSERT_SIGNAL_INSTRUCTION | CMD_MSG(STR_ERROR_CAN_T_INSERT_INSTRUCTION));
00419 break;
00420 }
00421
00422 case PROGRAM_WIDGET_SET_STATE: {
00423 uint32 p1 = 0;
00424 SB(p1, 0, 3, this->track);
00425 SB(p1, 3, 16, ins->Id());
00426
00427 DoCommandP(this->tile, p1, index, CMD_MODIFY_SIGNAL_INSTRUCTION | CMD_MSG(STR_ERROR_CAN_T_MODIFY_INSTRUCTION));
00428 break;
00429 }
00430
00431 case PROGRAM_WIDGET_COND_VARIABLE: {
00432 uint32 p1 = 0, p2 = 0;
00433 SB(p1, 0, 3, this->track);
00434 SB(p1, 3, 16, ins->Id());
00435
00436 SB(p2, 0, 1, 0);
00437 SB(p2, 1, 8, index);
00438
00439 DoCommandP(this->tile, p1, p2, CMD_MODIFY_SIGNAL_INSTRUCTION | CMD_MSG(STR_ERROR_CAN_T_MODIFY_INSTRUCTION));
00440 break;
00441 }
00442
00443 case PROGRAM_WIDGET_COND_COMPARATOR: {
00444 uint32 p1 = 0, p2 = 0;
00445 SB(p1, 0, 3, this->track);
00446 SB(p1, 3, 16, ins->Id());
00447
00448 SB(p2, 0, 1, 1);
00449 SB(p2, 1, 2, SCF_COMPARATOR);
00450 SB(p2, 3, 27, index);
00451
00452 DoCommandP(this->tile, p1, p2, CMD_MODIFY_SIGNAL_INSTRUCTION | CMD_MSG(STR_ERROR_CAN_T_MODIFY_INSTRUCTION));
00453 break;
00454 }
00455 }
00456 }
00457
00458 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00459 {
00460 switch (widget) {
00461 case PROGRAM_WIDGET_INSTRUCTION_LIST:
00462 resize->height = FONT_HEIGHT_NORMAL;
00463 size->height = 6 * resize->height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
00464 break;
00465 }
00466 }
00467
00468 virtual void OnResize()
00469 {
00470
00471 this->vscroll->SetCapacityFromWidget(this, PROGRAM_WIDGET_INSTRUCTION_LIST);
00472 }
00473
00474 virtual void OnPaint()
00475 {
00476 this->DrawWidgets();
00477 }
00478
00479 virtual void DrawWidget(const Rect &r, int widget) const
00480 {
00481 if (widget != PROGRAM_WIDGET_INSTRUCTION_LIST) return;
00482
00483 int y = r.top + WD_FRAMERECT_TOP;
00484 int line_height = this->GetWidget<NWidgetBase>(PROGRAM_WIDGET_INSTRUCTION_LIST)->resize_y;
00485
00486 int no = this->vscroll->GetPosition();
00487
00488 for (const GuiInstruction *i = instructions.Begin() + no, *e = instructions.End();
00489 i != e; ++i, no++) {
00490
00491 if (!this->vscroll->IsVisible(no)) break;
00492
00493 DrawInstructionString(i->insn, y, no == this->selected_instruction, i->indent, r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT);
00494 y += line_height;
00495 }
00496 }
00497
00498 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
00499 {
00500 if (!gui_scope) return;
00501 RebuildInstructionList();
00502 }
00503
00504 virtual void SetStringParameters(int widget) const
00505 {
00506 switch (widget) {
00507 case PROGRAM_WIDGET_COND_VALUE: {
00508 SetDParam(0, 0);
00509 SignalInstruction *insn = this->GetSelected();
00510 if (!insn || insn->Opcode() != PSO_IF) return;
00511 SignalIf *si = static_cast<SignalIf*>(insn);
00512 if (!IsConditionComparator(si->condition)) return;
00513 SignalVariableCondition *vc = static_cast<SignalVariableCondition*>(si->condition);
00514 SetDParam(0, vc->value);
00515 } break;
00516 }
00517 }
00518
00519 private:
00520 SignalInstruction *GetSelected() const
00521 {
00522 if (this->selected_instruction == -1
00523 || this->selected_instruction >= int(this->instructions.Length()))
00524 return NULL;
00525
00526 return this->instructions[this->selected_instruction].insn;
00527 }
00528
00529 Owner GetOwner()
00530 {
00531 return GetTileOwner(this->tile);
00532 }
00533
00534 int GetInstructionFromPt(int y)
00535 {
00536 NWidgetBase *nwid = this->GetWidget<NWidgetBase>(PROGRAM_WIDGET_INSTRUCTION_LIST);
00537 int sel = (y - nwid->pos_y - WD_FRAMERECT_TOP) / nwid->resize_y;
00538
00539 if ((uint)sel >= this->vscroll->GetCapacity()) return -1;
00540
00541 sel += this->vscroll->GetPosition();
00542
00543 return (sel <= int(this->instructions.Length()) && sel >= 0) ? sel : -1;
00544 }
00545
00546 void RebuildInstructionList()
00547 {
00548 uint old_len = this->instructions.Length();
00549 this->instructions.Clear();
00550 SignalInstruction *insn = program->first_instruction;
00551 uint indent = 0;
00552
00553 do {
00554 DEBUG(misc, 5, "PSig Gui: Opcode %d", insn->Opcode());
00555 switch (insn->Opcode()) {
00556 case PSO_FIRST:
00557 case PSO_LAST: {
00558 SignalSpecial *s = static_cast<SignalSpecial*>(insn);
00559 GuiInstruction *gi = this->instructions.Append();
00560 gi->insn = s;
00561 gi->indent = indent;
00562 insn = s->next;
00563 break;
00564 }
00565
00566 case PSO_IF: {
00567 SignalIf *i = static_cast<SignalIf*>(insn);
00568 GuiInstruction *gi = this->instructions.Append();
00569 gi->insn = i;
00570 gi->indent = indent++;
00571 insn = i->if_true;
00572 break;
00573 }
00574
00575 case PSO_IF_ELSE: {
00576 SignalIf::PseudoInstruction *p = static_cast<SignalIf::PseudoInstruction*>(insn);
00577 GuiInstruction *gi = this->instructions.Append();
00578 gi->insn = p;
00579 gi->indent = indent - 1;
00580 insn = p->block->if_false;
00581 break;
00582 }
00583
00584 case PSO_IF_ENDIF: {
00585 SignalIf::PseudoInstruction *p = static_cast<SignalIf::PseudoInstruction*>(insn);
00586 GuiInstruction *gi = this->instructions.Append();
00587 gi->insn = p;
00588 gi->indent = --indent;
00589 insn = p->block->after;
00590 break;
00591 }
00592
00593 case PSO_SET_SIGNAL: {
00594 SignalSet *s = static_cast<SignalSet*>(insn);
00595 GuiInstruction *gi = this->instructions.Append();
00596 gi->insn = s;
00597 gi->indent = indent;
00598 insn = s->next;
00599 break;
00600 }
00601
00602 default: NOT_REACHED();
00603 }
00604 } while (insn);
00605
00606 this->vscroll->SetCount(this->instructions.Length());
00607 if (this->instructions.Length() != old_len)
00608 selected_instruction = -1;
00609 UpdateButtonState();
00610 }
00611
00612 void UpdateButtonState()
00613 {
00614
00615 this->RaiseWidget(PROGRAM_WIDGET_INSERT);
00616 this->RaiseWidget(PROGRAM_WIDGET_REMOVE);
00617 this->RaiseWidget(PROGRAM_WIDGET_SET_STATE);
00618 this->RaiseWidget(PROGRAM_WIDGET_COND_VARIABLE);
00619 this->RaiseWidget(PROGRAM_WIDGET_COND_COMPARATOR);
00620 this->RaiseWidget(PROGRAM_WIDGET_COND_VALUE);
00621 this->RaiseWidget(PROGRAM_WIDGET_COND_GOTO_SIGNAL);
00622
00623 NWidgetStacked *left_sel = this->GetWidget<NWidgetStacked>(PROGRAM_WIDGET_SEL_TOP_LEFT);
00624 NWidgetStacked *middle_sel = this->GetWidget<NWidgetStacked>(PROGRAM_WIDGET_SEL_TOP_MIDDLE);
00625 NWidgetStacked *right_sel = this->GetWidget<NWidgetStacked>(PROGRAM_WIDGET_SEL_TOP_RIGHT);
00626
00627
00628 this->DisableWidget(PROGRAM_WIDGET_SET_STATE);
00629 this->DisableWidget(PROGRAM_WIDGET_COND_VARIABLE);
00630 this->DisableWidget(PROGRAM_WIDGET_COND_COMPARATOR);
00631 this->DisableWidget(PROGRAM_WIDGET_COND_VALUE);
00632 this->DisableWidget(PROGRAM_WIDGET_COND_SET_SIGNAL);
00633 this->DisableWidget(PROGRAM_WIDGET_COND_GOTO_SIGNAL);
00634
00635
00636 if (this->GetOwner() != _local_company || this->selected_instruction < 1) {
00637 this->DisableWidget(PROGRAM_WIDGET_INSERT);
00638 this->DisableWidget(PROGRAM_WIDGET_REMOVE);
00639 this->SetDirty();
00640 return;
00641 } else {
00642 this->EnableWidget(PROGRAM_WIDGET_INSERT);
00643 this->EnableWidget(PROGRAM_WIDGET_REMOVE);
00644 }
00645
00646 SignalInstruction *insn = GetSelected();
00647 if (!insn) return;
00648
00649 switch (insn->Opcode()) {
00650 case PSO_IF: {
00651 SignalIf *i = static_cast<SignalIf*>(insn);
00652 left_sel->SetDisplayedPlane(DPL_COND_VARIABLE);
00653 middle_sel->SetDisplayedPlane(DPM_COND_COMPARATOR);
00654 right_sel->SetDisplayedPlane(DPR_COND_VALUE);
00655
00656 this->EnableWidget(PROGRAM_WIDGET_COND_VARIABLE);
00657 this->GetWidget<NWidgetCore>(PROGRAM_WIDGET_COND_VARIABLE)->widget_data =
00658 _program_condvar[i->condition->ConditionCode()];
00659
00660 if (IsConditionComparator(i->condition)) {
00661 SignalVariableCondition *vc = static_cast<SignalVariableCondition*>(i->condition);
00662 this->EnableWidget(PROGRAM_WIDGET_COND_COMPARATOR);
00663 this->EnableWidget(PROGRAM_WIDGET_COND_VALUE);
00664
00665 this->GetWidget<NWidgetCore>(PROGRAM_WIDGET_COND_COMPARATOR)->widget_data =
00666 _program_comparator[vc->comparator];
00667
00668 } else if (i->condition->ConditionCode() == PSC_SIGNAL_STATE) {
00669 this->EnableWidget(PROGRAM_WIDGET_COND_GOTO_SIGNAL);
00670 this->EnableWidget(PROGRAM_WIDGET_COND_SET_SIGNAL);
00671 middle_sel->SetDisplayedPlane(DPM_COND_GOTO_SIGNAL);
00672 right_sel->SetDisplayedPlane(DPR_COND_SET_SIGNAL);
00673 }
00674 } break;
00675
00676 case PSO_SET_SIGNAL: {
00677 SignalSet *s = static_cast<SignalSet*>(insn);
00678 left_sel->SetDisplayedPlane(DPL_SET_STATE);
00679 this->SetWidgetDisabledState(PROGRAM_WIDGET_SET_STATE, false);
00680 this->GetWidget<NWidgetCore>(PROGRAM_WIDGET_SET_STATE)->widget_data =
00681 _program_sigstate[s->to_state];
00682 } break;
00683
00684 case PSO_FIRST:
00685 case PSO_LAST:
00686 case PSO_IF_ELSE:
00687 case PSO_IF_ENDIF:
00688
00689 this->DisableWidget(PROGRAM_WIDGET_REMOVE);
00690 break;
00691
00692 default:
00693 NOT_REACHED();
00694 }
00695
00696 this->SetDirty();
00697 }
00698
00699 TileIndex tile;
00700 Track track;
00701 SignalProgram *program;
00702 GuiInstructionList instructions;
00703 int selected_instruction;
00704 Scrollbar *vscroll;
00705 };
00706
00707 static const NWidgetPart _nested_program_widgets[] = {
00708
00709 NWidget(NWID_HORIZONTAL),
00710 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00711 NWidget(WWT_CAPTION, COLOUR_GREY, PROGRAM_WIDGET_CAPTION), SetDataTip(STR_PROGSIG_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00712 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00713 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00714 EndContainer(),
00715
00716
00717 NWidget(NWID_HORIZONTAL),
00718 NWidget(WWT_PANEL, COLOUR_GREY, PROGRAM_WIDGET_INSTRUCTION_LIST), SetMinimalSize(372, 62), SetDataTip(0x0, STR_PROGSIG_CAPTION), SetResize(1, 1), SetScrollbar(PROGRAM_WIDGET_SCROLLBAR), EndContainer(),
00719 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, PROGRAM_WIDGET_SCROLLBAR),
00720 EndContainer(),
00721
00722
00723 NWidget(NWID_HORIZONTAL),
00724 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
00725 NWidget(NWID_SELECTION, INVALID_COLOUR, PROGRAM_WIDGET_SEL_TOP_LEFT),
00726 NWidget(WWT_DROPDOWN, COLOUR_GREY, PROGRAM_WIDGET_COND_VARIABLE), SetMinimalSize(124, 12), SetFill(1, 0),
00727 SetDataTip(STR_NULL, STR_PROGSIG_COND_VARIABLE_TOOLTIP), SetResize(1, 0),
00728 NWidget(WWT_DROPDOWN, COLOUR_GREY, PROGRAM_WIDGET_SET_STATE), SetMinimalSize(124, 12), SetFill(1, 0),
00729 SetDataTip(STR_NULL, STR_PROGSIG_SIGNAL_STATE_TOOLTIP), SetResize(1, 0),
00730 EndContainer(),
00731 NWidget(NWID_SELECTION, INVALID_COLOUR, PROGRAM_WIDGET_SEL_TOP_MIDDLE),
00732 NWidget(WWT_DROPDOWN, COLOUR_GREY, PROGRAM_WIDGET_COND_COMPARATOR), SetMinimalSize(124, 12), SetFill(1, 0),
00733 SetDataTip(STR_NULL, STR_PROGSIG_COND_COMPARATOR_TOOLTIP), SetResize(1, 0),
00734 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, PROGRAM_WIDGET_COND_GOTO_SIGNAL), SetMinimalSize(124, 12), SetFill(1, 0),
00735 SetDataTip(STR_PROGSIG_GOTO_SIGNAL, STR_PROGSIG_GOTO_SIGNAL_TOOLTIP), SetResize(1, 0),
00736 EndContainer(),
00737 NWidget(NWID_SELECTION, INVALID_COLOUR, PROGRAM_WIDGET_SEL_TOP_RIGHT),
00738 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, PROGRAM_WIDGET_COND_VALUE), SetMinimalSize(124, 12), SetFill(1, 0),
00739 SetDataTip(STR_BLACK_COMMA, STR_PROGSIG_COND_VALUE_TOOLTIP), SetResize(1, 0),
00740 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, PROGRAM_WIDGET_COND_SET_SIGNAL), SetMinimalSize(124, 12), SetFill(1, 0),
00741 SetDataTip(STR_PROGSIG_COND_SET_SIGNAL, STR_PROGSIG_COND_SET_SIGNAL_TOOLTIP), SetResize(1, 0),
00742 EndContainer(),
00743 EndContainer(),
00744 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, PROGRAM_WIDGET_GOTO_SIGNAL), SetMinimalSize(12, 12), SetDataTip(SPR_ARROW_RIGHT, STR_PROGSIG_GOTO_SIGNAL_TOOLTIP),
00745 EndContainer(),
00746
00747
00748 NWidget(NWID_HORIZONTAL),
00749 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
00750 NWidget(WWT_DROPDOWN, COLOUR_GREY, PROGRAM_WIDGET_INSERT), SetMinimalSize(124, 12), SetFill(1, 0),
00751 SetDataTip(STR_PROGSIG_INSERT, STR_PROGSIG_INSERT_TOOLTIP), SetResize(1, 0),
00752 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, PROGRAM_WIDGET_REMOVE), SetMinimalSize(186, 12), SetFill(1, 0),
00753 SetDataTip(STR_PROGSIG_REMOVE, STR_PROGSIG_REMOVE_TOOLTIP), SetResize(1, 0),
00754 EndContainer(),
00755 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
00756 EndContainer(),
00757 };
00758
00759 static const WindowDesc _program_desc(
00760 WDP_AUTO, 384, 100,
00761 WC_SIGNAL_PROGRAM, WC_BUILD_SIGNAL,
00762 WDF_CONSTRUCTION,
00763 _nested_program_widgets, lengthof(_nested_program_widgets)
00764 );
00765
00766 void ShowSignalProgramWindow(SignalReference ref)
00767 {
00768 uint32 window_id = (ref.tile << 3) | ref.track;
00769 if (BringWindowToFrontById(WC_SIGNAL_PROGRAM, window_id) != NULL) return;
00770
00771 new ProgramWindow(&_program_desc, ref);
00772 }
00773
00774 extern uint ConvertSpeedToDisplaySpeed(uint speed);
00775 extern uint ConvertDisplaySpeedToSpeed(uint speed);
00776
00777 enum SpeedWindowWidgets {
00778 SPEED_WIDGET_CAPTION,
00779 SPEED_WIDGET_VALUE,
00780 SPEED_WIDGET_CLEAR,
00781 SPEED_WIDGET_CHANGE,
00782 };
00783
00784 class SpeedWindow: public Window {
00785 public:
00786 SpeedWindow(const WindowDesc *desc, SignalReference ref)
00787 {
00788 this->InitNested(desc, (ref.tile << 3) | ref.track);
00789 this->tile = ref.tile;
00790 this->track = ref.track;
00791
00792 this->InvalidateData();
00793 this->SetWidgetLoweredState(SPEED_WIDGET_CHANGE, true);
00794 this->ShowChangeSpeedLimit();
00795 }
00796
00797 void ShowChangeSpeedLimit()
00798 {
00799 uint16 speed = GetSignalSpeed(SignalReference(this->tile, this->track));
00800 speed = ConvertSpeedToDisplaySpeed((speed * 10) / 16);
00801
00802 SetDParam(0, speed);
00803 ShowQueryString(STR_JUST_INT, STR_SPEEDSIG_CAPTION, 31, this, CS_NUMERAL, QSF_NONE);
00804 }
00805
00806 virtual void OnClick(Point pt, int widget, int click_count)
00807 {
00808 switch (widget) {
00809 case SPEED_WIDGET_CLEAR: {
00810 this->SetSpeedLimit(0);
00811 break;
00812 }
00813 case SPEED_WIDGET_CHANGE: {
00814 this->ShowChangeSpeedLimit();
00815 break;
00816 }
00817 }
00818 }
00819
00820 virtual void OnQueryTextFinished(char *str)
00821 {
00822 this->SetWidgetLoweredState(SPEED_WIDGET_CHANGE, false);
00823 this->SetWidgetDirty(SPEED_WIDGET_CHANGE);
00824
00825 if (str == NULL) return;
00826
00827 uint16 speed = StrEmpty(str) ? 0 : strtoul(str, NULL, 10);
00828 speed = ConvertDisplaySpeedToSpeed((speed * 16) / 10);
00829
00830 this->SetSpeedLimit(speed);
00831 }
00832
00833 void SetSpeedLimit(uint16 speed)
00834 {
00835 uint32 p1 = 0;
00836 SB(p1, 0, 3, this->track);
00837
00838 DoCommandP(this->tile, p1, (uint32)speed, CMD_SET_SIGNAL_SPEED_LIMIT | CMD_MSG(STR_ERROR_CAN_T_SET_SPEED));
00839 }
00840
00841 virtual void OnPaint()
00842 {
00843 if (this->GetOwner() == _local_company) {
00844 this->EnableWidget(SPEED_WIDGET_CLEAR);
00845 this->EnableWidget(SPEED_WIDGET_CHANGE);
00846 } else {
00847 this->DisableWidget(SPEED_WIDGET_CLEAR);
00848 this->DisableWidget(SPEED_WIDGET_CHANGE);
00849 }
00850 this->DrawWidgets();
00851 }
00852
00853 virtual void OnInvalidateData(int data = 0, bool gui_scope = true) {
00854 uint16 speed = GetSignalSpeed(SignalReference(this->tile, this->track));
00855
00856 NWidgetCore *w = this->GetWidget<NWidgetCore>(SPEED_WIDGET_VALUE);
00857
00858 if (speed == 0) {
00859 w->SetDataTip(STR_SPEEDSIG_VALUE_NONE, STR_NULL);
00860 } else {
00861 w->SetDataTip(STR_SPEEDSIG_VALUE, STR_NULL);
00862 }
00863 }
00864
00865 virtual void SetStringParameters(int widget) const
00866 {
00867 switch (widget) {
00868 case SPEED_WIDGET_VALUE: {
00869 uint16 speed = GetSignalSpeed(SignalReference(this->tile, this->track));
00870 SetDParam(0, speed);
00871 break;
00872 }
00873 }
00874 }
00875
00876 private:
00877 Owner GetOwner()
00878 {
00879 return GetTileOwner(this->tile);
00880 }
00881
00882 TileIndex tile;
00883 Track track;
00884 };
00885
00886 static const NWidgetPart _nested_speed_widgets[] = {
00887 NWidget(NWID_HORIZONTAL),
00888 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00889 NWidget(WWT_CAPTION, COLOUR_GREY, SPEED_WIDGET_CAPTION), SetDataTip(STR_SPEEDSIG_CAPTION, STR_NULL),
00890 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00891 EndContainer(),
00892 NWidget(WWT_PANEL, COLOUR_GREY),
00893 NWidget(WWT_LABEL, COLOUR_GREY, SPEED_WIDGET_VALUE), SetMinimalSize(128, 12), SetFill(1, 1), SetPadding(2, 2, 2, 2),
00894 EndContainer(),
00895 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
00896 NWidget(WWT_TEXTBTN, COLOUR_GREY, SPEED_WIDGET_CLEAR), SetDataTip(STR_SPEEDSIG_CLEAR, STR_NULL), SetMinimalSize(87, 12), SetFill(1, 0),
00897 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SPEED_WIDGET_CHANGE), SetDataTip(STR_SPEEDSIG_CHANGE, STR_NULL), SetMinimalSize(87, 12), SetFill(1, 0),
00898 EndContainer(),
00899 };
00900
00901 static const WindowDesc _speed_desc(
00902 WDP_AUTO, 384, 100,
00903 WC_SPEED_SIGNAL, WC_BUILD_SIGNAL,
00904 WDF_CONSTRUCTION,
00905 _nested_speed_widgets, lengthof(_nested_speed_widgets)
00906 );
00907
00908 void ShowSpeedSignalWindow(SignalReference ref)
00909 {
00910 uint32 window_id = (ref.tile << 3) | ref.track;
00911 if (BringWindowToFrontById(WC_SPEED_SIGNAL, window_id) != NULL) return;
00912
00913 new SpeedWindow(&_speed_desc, ref);
00914 }