00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include <stdarg.h>
00014 #include "window_gui.h"
00015 #include "window_func.h"
00016 #include "fileio_func.h"
00017 #include "spritecache.h"
00018 #include "string_func.h"
00019 #include "strings_func.h"
00020 #include "textbuf_gui.h"
00021 #include "vehicle_gui.h"
00022
00023 #include "engine_base.h"
00024 #include "industry.h"
00025 #include "object_base.h"
00026 #include "station_base.h"
00027 #include "town.h"
00028 #include "vehicle_base.h"
00029 #include "train.h"
00030 #include "roadveh.h"
00031
00032 #include "newgrf_airporttiles.h"
00033 #include "newgrf_debug.h"
00034 #include "newgrf_object.h"
00035 #include "newgrf_spritegroup.h"
00036 #include "newgrf_station.h"
00037 #include "newgrf_town.h"
00038 #include "newgrf_railtype.h"
00039 #include "newgrf_industries.h"
00040 #include "newgrf_industrytiles.h"
00041
00042 #include "widgets/newgrf_debug_widget.h"
00043
00044 #include "table/strings.h"
00045
00047 NewGrfDebugSpritePicker _newgrf_debug_sprite_picker = { SPM_NONE, NULL, 0, SmallVector<SpriteID, 256>() };
00048
00054 static inline uint GetFeatureIndex(uint window_number)
00055 {
00056 return GB(window_number, 0, 24);
00057 }
00058
00066 static inline uint GetInspectWindowNumber(GrfSpecFeature feature, uint index)
00067 {
00068 assert((index >> 24) == 0);
00069 return (feature << 24) | index;
00070 }
00071
00076 enum NIType {
00077 NIT_INT,
00078 NIT_CARGO,
00079 };
00080
00082 struct NIProperty {
00083 const char *name;
00084 ptrdiff_t offset;
00085 byte read_size;
00086 byte prop;
00087 byte type;
00088 };
00089
00090
00095 struct NICallback {
00096 const char *name;
00097 ptrdiff_t offset;
00098 byte read_size;
00099 byte cb_bit;
00100 uint16 cb_id;
00101 };
00103 static const int CBM_NO_BIT = UINT8_MAX;
00104
00106 struct NIVariable {
00107 const char *name;
00108 byte var;
00109 };
00110
00112 class NIHelper {
00113 public:
00115 virtual ~NIHelper() {}
00116
00122 virtual bool IsInspectable(uint index) const = 0;
00123
00129 virtual uint GetParent(uint index) const = 0;
00130
00136 virtual const void *GetInstance(uint index) const = 0;
00137
00143 virtual const void *GetSpec(uint index) const = 0;
00144
00149 virtual void SetStringParameters(uint index) const = 0;
00150
00156 virtual uint32 GetGRFID(uint index) const = 0;
00157
00166 virtual uint Resolve(uint index, uint var, uint param, bool *avail) const = 0;
00167
00172 virtual bool PSAWithParameter() const
00173 {
00174 return false;
00175 }
00176
00183 virtual uint GetPSASize(uint index, uint32 grfid) const
00184 {
00185 return 0;
00186 }
00187
00194 virtual const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const
00195 {
00196 return NULL;
00197 }
00198
00199 protected:
00205 void SetSimpleStringParameters(StringID string, uint32 index) const
00206 {
00207 SetDParam(0, string);
00208 SetDParam(1, index);
00209 }
00210
00211
00218 void SetObjectAtStringParameters(StringID string, uint32 index, TileIndex tile) const
00219 {
00220 SetDParam(0, STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT);
00221 SetDParam(1, string);
00222 SetDParam(2, index);
00223 SetDParam(3, tile);
00224 }
00225 };
00226
00227
00229 struct NIFeature {
00230 const NIProperty *properties;
00231 const NICallback *callbacks;
00232 const NIVariable *variables;
00233 const NIHelper *helper;
00234 };
00235
00236
00237 #include "table/newgrf_debug_data.h"
00238
00244 static inline GrfSpecFeature GetFeatureNum(uint window_number)
00245 {
00246 return (GrfSpecFeature)GB(window_number, 24, 8);
00247 }
00248
00254 static inline const NIFeature *GetFeature(uint window_number)
00255 {
00256 GrfSpecFeature idx = GetFeatureNum(window_number);
00257 return idx < GSF_FAKE_END ? _nifeatures[idx] : NULL;
00258 }
00259
00266 static inline const NIHelper *GetFeatureHelper(uint window_number)
00267 {
00268 return GetFeature(window_number)->helper;
00269 }
00270
00272 struct NewGRFInspectWindow : Window {
00273 static const int LEFT_OFFSET = 5;
00274 static const int RIGHT_OFFSET = 5;
00275 static const int TOP_OFFSET = 5;
00276 static const int BOTTOM_OFFSET = 5;
00277
00279 static uint32 var60params[GSF_FAKE_END][0x20];
00280
00282 uint32 caller_grfid;
00283
00285 uint chain_index;
00286
00288 byte current_edit_param;
00289
00290 Scrollbar *vscroll;
00291
00297 static bool HasVariableParameter(uint variable)
00298 {
00299 return IsInsideBS(variable, 0x60, 0x20);
00300 }
00301
00306 void SetCallerGRFID(uint32 grfid)
00307 {
00308 this->caller_grfid = grfid;
00309 this->SetDirty();
00310 }
00311
00315 bool HasChainIndex() const
00316 {
00317 GrfSpecFeature f = GetFeatureNum(this->window_number);
00318 return f == GSF_TRAINS || f == GSF_ROADVEHICLES;
00319 }
00320
00325 uint GetFeatureIndex() const
00326 {
00327 uint index = ::GetFeatureIndex(this->window_number);
00328 if (this->chain_index > 0) {
00329 assert(this->HasChainIndex());
00330 const Vehicle *v = Vehicle::Get(index);
00331 v = v->Move(this->chain_index);
00332 if (v != NULL) index = v->index;
00333 }
00334 return index;
00335 }
00336
00340 void ValidateChainIndex()
00341 {
00342 if (this->chain_index == 0) return;
00343
00344 assert(this->HasChainIndex());
00345
00346 const Vehicle *v = Vehicle::Get(::GetFeatureIndex(this->window_number));
00347 v = v->Move(this->chain_index);
00348 if (v == NULL) this->chain_index = 0;
00349 }
00350
00351 NewGRFInspectWindow(WindowDesc *desc, WindowNumber wno) : Window(desc)
00352 {
00353 this->CreateNestedTree();
00354 this->vscroll = this->GetScrollbar(WID_NGRFI_SCROLLBAR);
00355 this->FinishInitNested(wno);
00356
00357 this->vscroll->SetCount(0);
00358 this->SetWidgetDisabledState(WID_NGRFI_PARENT, GetFeatureHelper(this->window_number)->GetParent(this->GetFeatureIndex()) == UINT32_MAX);
00359
00360 this->OnInvalidateData(0, true);
00361 }
00362
00363 virtual void SetStringParameters(int widget) const
00364 {
00365 if (widget != WID_NGRFI_CAPTION) return;
00366
00367 GetFeatureHelper(this->window_number)->SetStringParameters(this->GetFeatureIndex());
00368 }
00369
00370 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00371 {
00372 switch (widget) {
00373 case WID_NGRFI_VEH_CHAIN: {
00374 assert(this->HasChainIndex());
00375 GrfSpecFeature f = GetFeatureNum(this->window_number);
00376 size->height = max(size->height, GetVehicleImageCellSize((VehicleType)(VEH_TRAIN + (f - GSF_TRAINS)), EIT_IN_DEPOT).height + 2 + WD_BEVEL_TOP + WD_BEVEL_BOTTOM);
00377 break;
00378 }
00379
00380 case WID_NGRFI_MAINPANEL:
00381 resize->height = max(11, FONT_HEIGHT_NORMAL + 1);
00382 resize->width = 1;
00383
00384 size->height = 5 * resize->height + TOP_OFFSET + BOTTOM_OFFSET;
00385 break;
00386 }
00387 }
00388
00395 void WARN_FORMAT(4, 5) DrawString(const Rect &r, int offset, const char *format, ...) const
00396 {
00397 char buf[1024];
00398
00399 va_list va;
00400 va_start(va, format);
00401 vsnprintf(buf, lengthof(buf), format, va);
00402 va_end(va);
00403
00404 offset -= this->vscroll->GetPosition();
00405 if (offset < 0 || offset >= this->vscroll->GetCapacity()) return;
00406
00407 ::DrawString(r.left + LEFT_OFFSET, r.right - RIGHT_OFFSET, r.top + TOP_OFFSET + (offset * this->resize.step_height), buf, TC_BLACK);
00408 }
00409
00410 virtual void DrawWidget(const Rect &r, int widget) const
00411 {
00412 switch (widget) {
00413 case WID_NGRFI_VEH_CHAIN: {
00414 const Vehicle *v = Vehicle::Get(this->GetFeatureIndex());
00415 int total_width = 0;
00416 int sel_start = 0;
00417 int sel_end = 0;
00418 for (const Vehicle *u = v->First(); u != NULL; u = u->Next()) {
00419 if (u == v) sel_start = total_width;
00420 switch (u->type) {
00421 case VEH_TRAIN: total_width += Train ::From(u)->GetDisplayImageWidth(); break;
00422 case VEH_ROAD: total_width += RoadVehicle::From(u)->GetDisplayImageWidth(); break;
00423 default: NOT_REACHED();
00424 }
00425 if (u == v) sel_end = total_width;
00426 }
00427
00428 int width = r.right + 1 - r.left - WD_BEVEL_LEFT - WD_BEVEL_RIGHT;
00429 int skip = 0;
00430 if (total_width > width) {
00431 int sel_center = (sel_start + sel_end) / 2;
00432 if (sel_center > width / 2) skip = min(total_width - width, sel_center - width / 2);
00433 }
00434
00435 GrfSpecFeature f = GetFeatureNum(this->window_number);
00436 int h = GetVehicleImageCellSize((VehicleType)(VEH_TRAIN + (f - GSF_TRAINS)), EIT_IN_DEPOT).height;
00437 int y = (r.top + r.bottom - h) / 2;
00438 DrawVehicleImage(v->First(), r.left + WD_BEVEL_LEFT, r.right - WD_BEVEL_RIGHT, y + 1, INVALID_VEHICLE, EIT_IN_DETAILS, skip);
00439
00440
00441 if (_current_text_dir == TD_RTL) {
00442 DrawFrameRect(r.right - sel_end + skip, y, r.right - sel_start + skip, y + h, COLOUR_WHITE, FR_BORDERONLY);
00443 } else {
00444 DrawFrameRect(r.left + sel_start - skip, y, r.left + sel_end - skip, y + h, COLOUR_WHITE, FR_BORDERONLY);
00445 }
00446 break;
00447 }
00448 }
00449
00450 if (widget != WID_NGRFI_MAINPANEL) return;
00451
00452 uint index = this->GetFeatureIndex();
00453 const NIFeature *nif = GetFeature(this->window_number);
00454 const NIHelper *nih = nif->helper;
00455 const void *base = nih->GetInstance(index);
00456 const void *base_spec = nih->GetSpec(index);
00457
00458 uint i = 0;
00459 if (nif->variables != NULL) {
00460 this->DrawString(r, i++, "Variables:");
00461 for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++) {
00462 bool avail = true;
00463 uint param = HasVariableParameter(niv->var) ? NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][niv->var - 0x60] : 0;
00464 uint value = nih->Resolve(index, niv->var, param, &avail);
00465
00466 if (!avail) continue;
00467
00468 if (HasVariableParameter(niv->var)) {
00469 this->DrawString(r, i++, " %02x[%02x]: %08x (%s)", niv->var, param, value, niv->name);
00470 } else {
00471 this->DrawString(r, i++, " %02x: %08x (%s)", niv->var, value, niv->name);
00472 }
00473 }
00474 }
00475
00476 uint psa_size = nih->GetPSASize(index, this->caller_grfid);
00477 const int32 *psa = nih->GetPSAFirstPosition(index, this->caller_grfid);
00478 if (psa_size != 0 && psa != NULL) {
00479 if (nih->PSAWithParameter()) {
00480 this->DrawString(r, i++, "Persistent storage [%08X]:", BSWAP32(this->caller_grfid));
00481 } else {
00482 this->DrawString(r, i++, "Persistent storage:");
00483 }
00484 assert(psa_size % 4 == 0);
00485 for (uint j = 0; j < psa_size; j += 4, psa += 4) {
00486 this->DrawString(r, i++, " %i: %i %i %i %i", j, psa[0], psa[1], psa[2], psa[3]);
00487 }
00488 }
00489
00490 if (nif->properties != NULL) {
00491 this->DrawString(r, i++, "Properties:");
00492 for (const NIProperty *nip = nif->properties; nip->name != NULL; nip++) {
00493 const void *ptr = (const byte *)base + nip->offset;
00494 uint value;
00495 switch (nip->read_size) {
00496 case 1: value = *(const uint8 *)ptr; break;
00497 case 2: value = *(const uint16 *)ptr; break;
00498 case 4: value = *(const uint32 *)ptr; break;
00499 default: NOT_REACHED();
00500 }
00501
00502 StringID string;
00503 SetDParam(0, value);
00504 switch (nip->type) {
00505 case NIT_INT:
00506 string = STR_JUST_INT;
00507 break;
00508
00509 case NIT_CARGO:
00510 string = value != INVALID_CARGO ? CargoSpec::Get(value)->name : STR_QUANTITY_N_A;
00511 break;
00512
00513 default:
00514 NOT_REACHED();
00515 }
00516
00517 char buffer[64];
00518 GetString(buffer, string, lastof(buffer));
00519 this->DrawString(r, i++, " %02x: %s (%s)", nip->prop, buffer, nip->name);
00520 }
00521 }
00522
00523 if (nif->callbacks != NULL) {
00524 this->DrawString(r, i++, "Callbacks:");
00525 for (const NICallback *nic = nif->callbacks; nic->name != NULL; nic++) {
00526 if (nic->cb_bit != CBM_NO_BIT) {
00527 const void *ptr = (const byte *)base_spec + nic->offset;
00528 uint value;
00529 switch (nic->read_size) {
00530 case 1: value = *(const uint8 *)ptr; break;
00531 case 2: value = *(const uint16 *)ptr; break;
00532 case 4: value = *(const uint32 *)ptr; break;
00533 default: NOT_REACHED();
00534 }
00535
00536 if (!HasBit(value, nic->cb_bit)) continue;
00537 this->DrawString(r, i++, " %03x: %s", nic->cb_id, nic->name);
00538 } else {
00539 this->DrawString(r, i++, " %03x: %s (unmasked)", nic->cb_id, nic->name);
00540 }
00541 }
00542 }
00543
00544
00545
00546
00547 const_cast<NewGRFInspectWindow*>(this)->vscroll->SetCount(i);
00548 }
00549
00550 virtual void OnClick(Point pt, int widget, int click_count)
00551 {
00552 switch (widget) {
00553 case WID_NGRFI_PARENT: {
00554 const NIHelper *nih = GetFeatureHelper(this->window_number);
00555 uint index = nih->GetParent(this->GetFeatureIndex());
00556 ::ShowNewGRFInspectWindow(GetFeatureNum(index), ::GetFeatureIndex(index), nih->GetGRFID(this->GetFeatureIndex()));
00557 break;
00558 }
00559
00560 case WID_NGRFI_VEH_PREV:
00561 if (this->chain_index > 0) {
00562 this->chain_index--;
00563 this->InvalidateData();
00564 }
00565 break;
00566
00567 case WID_NGRFI_VEH_NEXT:
00568 if (this->HasChainIndex()) {
00569 uint index = this->GetFeatureIndex();
00570 Vehicle *v = Vehicle::Get(index);
00571 if (v != NULL && v->Next() != NULL) {
00572 this->chain_index++;
00573 this->InvalidateData();
00574 }
00575 }
00576 break;
00577
00578 case WID_NGRFI_MAINPANEL: {
00579
00580 const NIFeature *nif = GetFeature(this->window_number);
00581 if (nif->variables == NULL) return;
00582
00583
00584 int line = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NGRFI_MAINPANEL, TOP_OFFSET);
00585 if (line == INT_MAX) return;
00586
00587
00588 for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++, line--) {
00589 if (line != 1) continue;
00590
00591 if (!HasVariableParameter(niv->var)) break;
00592
00593 this->current_edit_param = niv->var;
00594 ShowQueryString(STR_EMPTY, STR_NEWGRF_INSPECT_QUERY_CAPTION, 9, this, CS_HEXADECIMAL, QSF_NONE);
00595 }
00596 }
00597 }
00598 }
00599
00600 virtual void OnQueryTextFinished(char *str)
00601 {
00602 if (StrEmpty(str)) return;
00603
00604 NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][this->current_edit_param - 0x60] = strtol(str, NULL, 16);
00605 this->SetDirty();
00606 }
00607
00608 virtual void OnResize()
00609 {
00610 this->vscroll->SetCapacityFromWidget(this, WID_NGRFI_MAINPANEL, TOP_OFFSET + BOTTOM_OFFSET);
00611 }
00612
00618 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
00619 {
00620 if (!gui_scope) return;
00621 if (this->HasChainIndex()) {
00622 this->ValidateChainIndex();
00623 this->SetWidgetDisabledState(WID_NGRFI_VEH_PREV, this->chain_index == 0);
00624 Vehicle *v = Vehicle::Get(this->GetFeatureIndex());
00625 this->SetWidgetDisabledState(WID_NGRFI_VEH_NEXT, v == NULL || v->Next() == NULL);
00626 }
00627 }
00628 };
00629
00630 uint32 NewGRFInspectWindow::var60params[GSF_FAKE_END][0x20] = { {0} };
00631
00632 static const NWidgetPart _nested_newgrf_inspect_chain_widgets[] = {
00633 NWidget(NWID_HORIZONTAL),
00634 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00635 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00636 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00637 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
00638 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00639 EndContainer(),
00640 NWidget(WWT_PANEL, COLOUR_GREY),
00641 NWidget(NWID_HORIZONTAL),
00642 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_NGRFI_VEH_PREV), SetDataTip(AWV_DECREASE, STR_NULL),
00643 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_NGRFI_VEH_NEXT), SetDataTip(AWV_INCREASE, STR_NULL),
00644 NWidget(WWT_EMPTY, COLOUR_GREY, WID_NGRFI_VEH_CHAIN), SetFill(1, 0), SetResize(1, 0),
00645 EndContainer(),
00646 EndContainer(),
00647 NWidget(NWID_HORIZONTAL),
00648 NWidget(WWT_PANEL, COLOUR_GREY, WID_NGRFI_MAINPANEL), SetMinimalSize(300, 0), SetScrollbar(WID_NGRFI_SCROLLBAR), EndContainer(),
00649 NWidget(NWID_VERTICAL),
00650 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_NGRFI_SCROLLBAR),
00651 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
00652 EndContainer(),
00653 EndContainer(),
00654 };
00655
00656 static const NWidgetPart _nested_newgrf_inspect_widgets[] = {
00657 NWidget(NWID_HORIZONTAL),
00658 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00659 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00660 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NGRFI_PARENT), SetDataTip(STR_NEWGRF_INSPECT_PARENT_BUTTON, STR_NEWGRF_INSPECT_PARENT_TOOLTIP),
00661 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00662 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
00663 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00664 EndContainer(),
00665 NWidget(NWID_HORIZONTAL),
00666 NWidget(WWT_PANEL, COLOUR_GREY, WID_NGRFI_MAINPANEL), SetMinimalSize(300, 0), SetScrollbar(WID_NGRFI_SCROLLBAR), EndContainer(),
00667 NWidget(NWID_VERTICAL),
00668 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_NGRFI_SCROLLBAR),
00669 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
00670 EndContainer(),
00671 EndContainer(),
00672 };
00673
00674 static WindowDesc _newgrf_inspect_chain_desc(
00675 WDP_AUTO, "newgrf_inspect_chain", 400, 300,
00676 WC_NEWGRF_INSPECT, WC_NONE,
00677 0,
00678 _nested_newgrf_inspect_chain_widgets, lengthof(_nested_newgrf_inspect_chain_widgets)
00679 );
00680
00681 static WindowDesc _newgrf_inspect_desc(
00682 WDP_AUTO, "newgrf_inspect", 400, 300,
00683 WC_NEWGRF_INSPECT, WC_NONE,
00684 0,
00685 _nested_newgrf_inspect_widgets, lengthof(_nested_newgrf_inspect_widgets)
00686 );
00687
00697 void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index, const uint32 grfid)
00698 {
00699 if (!IsNewGRFInspectable(feature, index)) return;
00700
00701 WindowNumber wno = GetInspectWindowNumber(feature, index);
00702 NewGRFInspectWindow *w = AllocateWindowDescFront<NewGRFInspectWindow>(feature == GSF_TRAINS || feature == GSF_ROADVEHICLES ? &_newgrf_inspect_chain_desc : &_newgrf_inspect_desc, wno);
00703 if (w == NULL) w = (NewGRFInspectWindow *)FindWindowById(WC_NEWGRF_INSPECT, wno);
00704 w->SetCallerGRFID(grfid);
00705 }
00706
00715 void InvalidateNewGRFInspectWindow(GrfSpecFeature feature, uint index)
00716 {
00717 if (feature == GSF_INVALID) return;
00718
00719 WindowNumber wno = GetInspectWindowNumber(feature, index);
00720 InvalidateWindowData(WC_NEWGRF_INSPECT, wno);
00721 }
00722
00731 void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
00732 {
00733 if (feature == GSF_INVALID) return;
00734
00735 WindowNumber wno = GetInspectWindowNumber(feature, index);
00736 DeleteWindowById(WC_NEWGRF_INSPECT, wno);
00737
00738
00739
00740
00741 InvalidateWindowData(WC_LAND_INFO, 0, 1);
00742 }
00743
00753 bool IsNewGRFInspectable(GrfSpecFeature feature, uint index)
00754 {
00755 const NIFeature *nif = GetFeature(GetInspectWindowNumber(feature, index));
00756 if (nif == NULL) return false;
00757 return nif->helper->IsInspectable(index);
00758 }
00759
00765 GrfSpecFeature GetGrfSpecFeature(TileIndex tile)
00766 {
00767 switch (GetTileType(tile)) {
00768 default: return GSF_INVALID;
00769 case MP_RAILWAY: return GSF_RAILTYPES;
00770 case MP_ROAD: return IsLevelCrossing(tile) ? GSF_RAILTYPES : GSF_INVALID;
00771 case MP_HOUSE: return GSF_HOUSES;
00772 case MP_INDUSTRY: return GSF_INDUSTRYTILES;
00773 case MP_OBJECT: return GSF_OBJECTS;
00774
00775 case MP_STATION:
00776 switch (GetStationType(tile)) {
00777 case STATION_RAIL: return GSF_STATIONS;
00778 case STATION_AIRPORT: return GSF_AIRPORTTILES;
00779 default: return GSF_INVALID;
00780 }
00781 }
00782 }
00783
00789 GrfSpecFeature GetGrfSpecFeature(VehicleType type)
00790 {
00791 switch (type) {
00792 case VEH_TRAIN: return GSF_TRAINS;
00793 case VEH_ROAD: return GSF_ROADVEHICLES;
00794 case VEH_SHIP: return GSF_SHIPS;
00795 case VEH_AIRCRAFT: return GSF_AIRCRAFT;
00796 default: return GSF_INVALID;
00797 }
00798 }
00799
00800
00801
00802
00803
00805 struct SpriteAlignerWindow : Window {
00806 SpriteID current_sprite;
00807 Scrollbar *vscroll;
00808
00809 SpriteAlignerWindow(WindowDesc *desc, WindowNumber wno) : Window(desc)
00810 {
00811 this->CreateNestedTree();
00812 this->vscroll = this->GetScrollbar(WID_SA_SCROLLBAR);
00813 this->FinishInitNested(wno);
00814
00815
00816 while (GetSpriteType(this->current_sprite) != ST_NORMAL) this->current_sprite++;
00817 }
00818
00819 virtual void SetStringParameters(int widget) const
00820 {
00821 switch (widget) {
00822 case WID_SA_CAPTION:
00823 SetDParam(0, this->current_sprite);
00824 SetDParamStr(1, FioGetFilename(GetOriginFileSlot(this->current_sprite)));
00825 break;
00826
00827 case WID_SA_OFFSETS: {
00828 const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL);
00829 SetDParam(0, spr->x_offs / ZOOM_LVL_BASE);
00830 SetDParam(1, spr->y_offs / ZOOM_LVL_BASE);
00831 break;
00832 }
00833
00834 default:
00835 break;
00836 }
00837 }
00838
00839 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00840 {
00841 if (widget != WID_SA_LIST) return;
00842
00843 resize->height = max(11, FONT_HEIGHT_NORMAL + 1);
00844 resize->width = 1;
00845
00846
00847 size->height = (1 + 200 / resize->height) * resize->height;
00848 }
00849
00850 virtual void DrawWidget(const Rect &r, int widget) const
00851 {
00852 switch (widget) {
00853 case WID_SA_SPRITE: {
00854
00855 const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL);
00856 int width = r.right - r.left + 1;
00857 int height = r.bottom - r.top + 1;
00858 int x = r.left - spr->x_offs / ZOOM_LVL_BASE + (width - spr->width / ZOOM_LVL_BASE) / 2;
00859 int y = r.top - spr->y_offs / ZOOM_LVL_BASE + (height - spr->height / ZOOM_LVL_BASE) / 2;
00860
00861
00862 SubSprite subspr = {
00863 spr->x_offs + (spr->width - width * ZOOM_LVL_BASE) / 2 + 1,
00864 spr->y_offs + (spr->height - height * ZOOM_LVL_BASE) / 2 + 1,
00865 spr->x_offs + (spr->width + width * ZOOM_LVL_BASE) / 2 - 1,
00866 spr->y_offs + (spr->height + height * ZOOM_LVL_BASE) / 2 - 1,
00867 };
00868
00869 DrawSprite(this->current_sprite, PAL_NONE, x, y, &subspr, ZOOM_LVL_GUI);
00870 break;
00871 }
00872
00873 case WID_SA_LIST: {
00874 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
00875 int step_size = nwid->resize_y;
00876
00877 SmallVector<SpriteID, 256> &list = _newgrf_debug_sprite_picker.sprites;
00878 int max = min<int>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), list.Length());
00879
00880 int y = r.top + WD_FRAMERECT_TOP;
00881 for (int i = this->vscroll->GetPosition(); i < max; i++) {
00882 SetDParam(0, list[i]);
00883 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_BLACK_COMMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE);
00884 y += step_size;
00885 }
00886 break;
00887 }
00888 }
00889 }
00890
00891 virtual void OnClick(Point pt, int widget, int click_count)
00892 {
00893 switch (widget) {
00894 case WID_SA_PREVIOUS:
00895 do {
00896 this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() : this->current_sprite) - 1;
00897 } while (GetSpriteType(this->current_sprite) != ST_NORMAL);
00898 this->SetDirty();
00899 break;
00900
00901 case WID_SA_GOTO:
00902 ShowQueryString(STR_EMPTY, STR_SPRITE_ALIGNER_GOTO_CAPTION, 7, this, CS_NUMERAL, QSF_NONE);
00903 break;
00904
00905 case WID_SA_NEXT:
00906 do {
00907 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
00908 } while (GetSpriteType(this->current_sprite) != ST_NORMAL);
00909 this->SetDirty();
00910 break;
00911
00912 case WID_SA_PICKER:
00913 this->LowerWidget(WID_SA_PICKER);
00914 _newgrf_debug_sprite_picker.mode = SPM_WAIT_CLICK;
00915 this->SetDirty();
00916 break;
00917
00918 case WID_SA_LIST: {
00919 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
00920 int step_size = nwid->resize_y;
00921
00922 uint i = this->vscroll->GetPosition() + (pt.y - nwid->pos_y) / step_size;
00923 if (i < _newgrf_debug_sprite_picker.sprites.Length()) {
00924 SpriteID spr = _newgrf_debug_sprite_picker.sprites[i];
00925 if (GetSpriteType(spr) == ST_NORMAL) this->current_sprite = spr;
00926 }
00927 this->SetDirty();
00928 break;
00929 }
00930
00931 case WID_SA_UP:
00932 case WID_SA_DOWN:
00933 case WID_SA_LEFT:
00934 case WID_SA_RIGHT: {
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948 Sprite *spr = const_cast<Sprite *>(GetSprite(this->current_sprite, ST_NORMAL));
00949 switch (widget) {
00950 case WID_SA_UP: spr->y_offs -= ZOOM_LVL_BASE; break;
00951 case WID_SA_DOWN: spr->y_offs += ZOOM_LVL_BASE; break;
00952 case WID_SA_LEFT: spr->x_offs -= ZOOM_LVL_BASE; break;
00953 case WID_SA_RIGHT: spr->x_offs += ZOOM_LVL_BASE; break;
00954 }
00955
00956
00957 MarkWholeScreenDirty();
00958 break;
00959 }
00960 }
00961 }
00962
00963 virtual void OnQueryTextFinished(char *str)
00964 {
00965 if (StrEmpty(str)) return;
00966
00967 this->current_sprite = atoi(str);
00968 if (this->current_sprite >= GetMaxSpriteID()) this->current_sprite = 0;
00969 while (GetSpriteType(this->current_sprite) != ST_NORMAL) {
00970 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
00971 }
00972 this->SetDirty();
00973 }
00974
00980 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
00981 {
00982 if (!gui_scope) return;
00983 if (data == 1) {
00984
00985 this->RaiseWidget(WID_SA_PICKER);
00986 this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.Length());
00987 }
00988 }
00989
00990 virtual void OnResize()
00991 {
00992 this->vscroll->SetCapacityFromWidget(this, WID_SA_LIST);
00993 }
00994 };
00995
00996 static const NWidgetPart _nested_sprite_aligner_widgets[] = {
00997 NWidget(NWID_HORIZONTAL),
00998 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00999 NWidget(WWT_CAPTION, COLOUR_GREY, WID_SA_CAPTION), SetDataTip(STR_SPRITE_ALIGNER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01000 NWidget(WWT_SHADEBOX, COLOUR_GREY),
01001 NWidget(WWT_STICKYBOX, COLOUR_GREY),
01002 EndContainer(),
01003 NWidget(WWT_PANEL, COLOUR_GREY),
01004 NWidget(NWID_HORIZONTAL), SetPIP(0, 0, 10),
01005 NWidget(NWID_VERTICAL), SetPIP(10, 5, 10),
01006 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 5, 10),
01007 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_PREVIOUS), SetDataTip(STR_SPRITE_ALIGNER_PREVIOUS_BUTTON, STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP), SetFill(1, 0),
01008 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_GOTO), SetDataTip(STR_SPRITE_ALIGNER_GOTO_BUTTON, STR_SPRITE_ALIGNER_GOTO_TOOLTIP), SetFill(1, 0),
01009 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_NEXT), SetDataTip(STR_SPRITE_ALIGNER_NEXT_BUTTON, STR_SPRITE_ALIGNER_NEXT_TOOLTIP), SetFill(1, 0),
01010 EndContainer(),
01011 NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
01012 NWidget(NWID_SPACER), SetFill(1, 1),
01013 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_UP), SetDataTip(SPR_ARROW_UP, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
01014 NWidget(NWID_SPACER), SetFill(1, 1),
01015 EndContainer(),
01016 NWidget(NWID_HORIZONTAL_LTR), SetPIP(10, 5, 10),
01017 NWidget(NWID_VERTICAL),
01018 NWidget(NWID_SPACER), SetFill(1, 1),
01019 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_LEFT), SetDataTip(SPR_ARROW_LEFT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
01020 NWidget(NWID_SPACER), SetFill(1, 1),
01021 EndContainer(),
01022 NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_SA_SPRITE), SetDataTip(STR_NULL, STR_SPRITE_ALIGNER_SPRITE_TOOLTIP),
01023 EndContainer(),
01024 NWidget(NWID_VERTICAL),
01025 NWidget(NWID_SPACER), SetFill(1, 1),
01026 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_RIGHT), SetDataTip(SPR_ARROW_RIGHT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
01027 NWidget(NWID_SPACER), SetFill(1, 1),
01028 EndContainer(),
01029 EndContainer(),
01030 NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
01031 NWidget(NWID_SPACER), SetFill(1, 1),
01032 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
01033 NWidget(NWID_SPACER), SetFill(1, 1),
01034 EndContainer(),
01035 NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
01036 NWidget(WWT_LABEL, COLOUR_GREY, WID_SA_OFFSETS), SetDataTip(STR_SPRITE_ALIGNER_OFFSETS, STR_NULL), SetFill(1, 0),
01037 EndContainer(),
01038 EndContainer(),
01039 NWidget(NWID_VERTICAL), SetPIP(10, 5, 10),
01040 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_PICKER), SetDataTip(STR_SPRITE_ALIGNER_PICKER_BUTTON, STR_SPRITE_ALIGNER_PICKER_TOOLTIP), SetFill(1, 0),
01041 NWidget(NWID_HORIZONTAL),
01042 NWidget(WWT_MATRIX, COLOUR_GREY, WID_SA_LIST), SetResize(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetFill(1, 1), SetScrollbar(WID_SA_SCROLLBAR),
01043 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SA_SCROLLBAR),
01044 EndContainer(),
01045 EndContainer(),
01046 EndContainer(),
01047 EndContainer(),
01048 };
01049
01050 static WindowDesc _sprite_aligner_desc(
01051 WDP_AUTO, "sprite_aligner", 400, 300,
01052 WC_SPRITE_ALIGNER, WC_NONE,
01053 0,
01054 _nested_sprite_aligner_widgets, lengthof(_nested_sprite_aligner_widgets)
01055 );
01056
01060 void ShowSpriteAlignerWindow()
01061 {
01062 AllocateWindowDescFront<SpriteAlignerWindow>(&_sprite_aligner_desc, 0);
01063 }