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
00022 #include "engine_base.h"
00023 #include "industry.h"
00024 #include "object_base.h"
00025 #include "station_base.h"
00026 #include "town.h"
00027 #include "vehicle_base.h"
00028
00029 #include "newgrf_airporttiles.h"
00030 #include "newgrf_debug.h"
00031 #include "newgrf_object.h"
00032 #include "newgrf_spritegroup.h"
00033 #include "newgrf_station.h"
00034 #include "newgrf_town.h"
00035
00036 #include "widgets/newgrf_debug_widget.h"
00037
00038 #include "table/strings.h"
00039
00041 NewGrfDebugSpritePicker _newgrf_debug_sprite_picker = { SPM_NONE, NULL, 0, SmallVector<SpriteID, 256>() };
00042
00048 static inline uint GetFeatureIndex(uint window_number)
00049 {
00050 return GB(window_number, 0, 24);
00051 }
00052
00060 static inline uint GetInspectWindowNumber(GrfSpecFeature feature, uint index)
00061 {
00062 assert((index >> 24) == 0);
00063 return (feature << 24) | index;
00064 }
00065
00070 enum NIType {
00071 NIT_INT,
00072 NIT_CARGO,
00073 };
00074
00076 struct NIProperty {
00077 const char *name;
00078 ptrdiff_t offset;
00079 byte read_size;
00080 byte prop;
00081 byte type;
00082 };
00083
00084
00089 struct NICallback {
00090 const char *name;
00091 ptrdiff_t offset;
00092 byte read_size;
00093 byte cb_bit;
00094 uint16 cb_id;
00095 };
00097 static const int CBM_NO_BIT = UINT8_MAX;
00098
00100 struct NIVariable {
00101 const char *name;
00102 byte var;
00103 };
00104
00106 class NIHelper {
00107 public:
00109 virtual ~NIHelper() {}
00110
00116 virtual bool IsInspectable(uint index) const = 0;
00117
00123 virtual uint GetParent(uint index) const = 0;
00124
00130 virtual const void *GetInstance(uint index) const = 0;
00131
00137 virtual const void *GetSpec(uint index) const = 0;
00138
00143 virtual void SetStringParameters(uint index) const = 0;
00144
00150 virtual uint32 GetGRFID(uint index) const = 0;
00151
00160 virtual uint Resolve(uint index, uint var, uint param, bool *avail) const
00161 {
00162 ResolverObject ro;
00163 memset(&ro, 0, sizeof(ro));
00164 this->Resolve(&ro, index);
00165 return ro.GetVariable(&ro, var, param, avail);
00166 }
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:
00206 virtual void Resolve(ResolverObject *ro, uint index) const {}
00207
00213 void SetSimpleStringParameters(StringID string, uint32 index) const
00214 {
00215 SetDParam(0, string);
00216 SetDParam(1, index);
00217 }
00218
00219
00226 void SetObjectAtStringParameters(StringID string, uint32 index, TileIndex tile) const
00227 {
00228 SetDParam(0, STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT);
00229 SetDParam(1, string);
00230 SetDParam(2, index);
00231 SetDParam(3, tile);
00232 }
00233 };
00234
00235
00237 struct NIFeature {
00238 const NIProperty *properties;
00239 const NICallback *callbacks;
00240 const NIVariable *variables;
00241 const NIHelper *helper;
00242 };
00243
00244
00245 #include "table/newgrf_debug_data.h"
00246
00252 static inline GrfSpecFeature GetFeatureNum(uint window_number)
00253 {
00254 return (GrfSpecFeature)GB(window_number, 24, 8);
00255 }
00256
00262 static inline const NIFeature *GetFeature(uint window_number)
00263 {
00264 GrfSpecFeature idx = GetFeatureNum(window_number);
00265 return idx < GSF_FAKE_END ? _nifeatures[idx] : NULL;
00266 }
00267
00274 static inline const NIHelper *GetFeatureHelper(uint window_number)
00275 {
00276 return GetFeature(window_number)->helper;
00277 }
00278
00280 struct NewGRFInspectWindow : Window {
00281 static const int LEFT_OFFSET = 5;
00282 static const int RIGHT_OFFSET = 5;
00283 static const int TOP_OFFSET = 5;
00284 static const int BOTTOM_OFFSET = 5;
00285
00287 static uint32 var60params[GSF_FAKE_END][0x20];
00288
00290 uint32 caller_grfid;
00291
00293 byte current_edit_param;
00294
00295 Scrollbar *vscroll;
00296
00302 static bool HasVariableParameter(uint variable)
00303 {
00304 return IsInsideBS(variable, 0x60, 0x20);
00305 }
00306
00311 void SetCallerGRFID(uint32 grfid)
00312 {
00313 this->caller_grfid = grfid;
00314 this->SetDirty();
00315 }
00316
00317 NewGRFInspectWindow(const WindowDesc *desc, WindowNumber wno) : Window()
00318 {
00319 this->CreateNestedTree(desc);
00320 this->vscroll = this->GetScrollbar(WID_NGRFI_SCROLLBAR);
00321 this->FinishInitNested(desc, wno);
00322
00323 this->vscroll->SetCount(0);
00324 this->SetWidgetDisabledState(WID_NGRFI_PARENT, GetFeatureHelper(this->window_number)->GetParent(GetFeatureIndex(this->window_number)) == UINT32_MAX);
00325 }
00326
00327 virtual void SetStringParameters(int widget) const
00328 {
00329 if (widget != WID_NGRFI_CAPTION) return;
00330
00331 GetFeatureHelper(this->window_number)->SetStringParameters(GetFeatureIndex(this->window_number));
00332 }
00333
00334 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00335 {
00336 if (widget != WID_NGRFI_MAINPANEL) return;
00337
00338 resize->height = max(11, FONT_HEIGHT_NORMAL + 1);
00339 resize->width = 1;
00340
00341 size->height = 5 * resize->height + TOP_OFFSET + BOTTOM_OFFSET;
00342 }
00343
00350 void WARN_FORMAT(4, 5) DrawString(const Rect &r, int offset, const char *format, ...) const
00351 {
00352 char buf[1024];
00353
00354 va_list va;
00355 va_start(va, format);
00356 vsnprintf(buf, lengthof(buf), format, va);
00357 va_end(va);
00358
00359 offset -= this->vscroll->GetPosition();
00360 if (offset < 0 || offset >= this->vscroll->GetCapacity()) return;
00361
00362 ::DrawString(r.left + LEFT_OFFSET, r.right + RIGHT_OFFSET, r.top + TOP_OFFSET + (offset * this->resize.step_height), buf, TC_BLACK);
00363 }
00364
00365 virtual void DrawWidget(const Rect &r, int widget) const
00366 {
00367 if (widget != WID_NGRFI_MAINPANEL) return;
00368
00369 uint index = GetFeatureIndex(this->window_number);
00370 const NIFeature *nif = GetFeature(this->window_number);
00371 const NIHelper *nih = nif->helper;
00372 const void *base = nih->GetInstance(index);
00373 const void *base_spec = nih->GetSpec(index);
00374
00375 uint i = 0;
00376 if (nif->variables != NULL) {
00377 this->DrawString(r, i++, "Variables:");
00378 for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++) {
00379 bool avail = true;
00380 uint param = HasVariableParameter(niv->var) ? NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][niv->var - 0x60] : 0;
00381 uint value = nih->Resolve(index, niv->var, param, &avail);
00382
00383 if (!avail) continue;
00384
00385 if (HasVariableParameter(niv->var)) {
00386 this->DrawString(r, i++, " %02x[%02x]: %08x (%s)", niv->var, param, value, niv->name);
00387 } else {
00388 this->DrawString(r, i++, " %02x: %08x (%s)", niv->var, value, niv->name);
00389 }
00390 }
00391 }
00392
00393 uint psa_size = nih->GetPSASize(index, this->caller_grfid);
00394 const int32 *psa = nih->GetPSAFirstPosition(index, this->caller_grfid);
00395 if (psa_size != 0 && psa != NULL) {
00396 if (nih->PSAWithParameter()) {
00397 this->DrawString(r, i++, "Persistent storage [%08X]:", BSWAP32(this->caller_grfid));
00398 } else {
00399 this->DrawString(r, i++, "Persistent storage:");
00400 }
00401 assert(psa_size % 4 == 0);
00402 for (uint j = 0; j < psa_size; j += 4, psa += 4) {
00403 this->DrawString(r, i++, " %i: %i %i %i %i", j, psa[0], psa[1], psa[2], psa[3]);
00404 }
00405 }
00406
00407 if (nif->properties != NULL) {
00408 this->DrawString(r, i++, "Properties:");
00409 for (const NIProperty *nip = nif->properties; nip->name != NULL; nip++) {
00410 const void *ptr = (const byte *)base + nip->offset;
00411 uint value;
00412 switch (nip->read_size) {
00413 case 1: value = *(const uint8 *)ptr; break;
00414 case 2: value = *(const uint16 *)ptr; break;
00415 case 4: value = *(const uint32 *)ptr; break;
00416 default: NOT_REACHED();
00417 }
00418
00419 StringID string;
00420 SetDParam(0, value);
00421 switch (nip->type) {
00422 case NIT_INT:
00423 string = STR_JUST_INT;
00424 break;
00425
00426 case NIT_CARGO:
00427 string = value != INVALID_CARGO ? CargoSpec::Get(value)->name : STR_QUANTITY_N_A;
00428 break;
00429
00430 default:
00431 NOT_REACHED();
00432 }
00433
00434 char buffer[64];
00435 GetString(buffer, string, lastof(buffer));
00436 this->DrawString(r, i++, " %02x: %s (%s)", nip->prop, buffer, nip->name);
00437 }
00438 }
00439
00440 if (nif->callbacks != NULL) {
00441 this->DrawString(r, i++, "Callbacks:");
00442 for (const NICallback *nic = nif->callbacks; nic->name != NULL; nic++) {
00443 if (nic->cb_bit != CBM_NO_BIT) {
00444 const void *ptr = (const byte *)base_spec + nic->offset;
00445 uint value;
00446 switch (nic->read_size) {
00447 case 1: value = *(const uint8 *)ptr; break;
00448 case 2: value = *(const uint16 *)ptr; break;
00449 case 4: value = *(const uint32 *)ptr; break;
00450 default: NOT_REACHED();
00451 }
00452
00453 if (!HasBit(value, nic->cb_bit)) continue;
00454 this->DrawString(r, i++, " %03x: %s", nic->cb_id, nic->name);
00455 } else {
00456 this->DrawString(r, i++, " %03x: %s (unmasked)", nic->cb_id, nic->name);
00457 }
00458 }
00459 }
00460
00461
00462
00463
00464 const_cast<NewGRFInspectWindow*>(this)->vscroll->SetCount(i);
00465 }
00466
00467 virtual void OnClick(Point pt, int widget, int click_count)
00468 {
00469 switch (widget) {
00470 case WID_NGRFI_PARENT: {
00471 const NIHelper *nih = GetFeatureHelper(this->window_number);
00472 uint index = nih->GetParent(GetFeatureIndex(this->window_number));
00473 ::ShowNewGRFInspectWindow((GrfSpecFeature)GB(index, 24, 8), GetFeatureIndex(index), nih->GetGRFID(GetFeatureIndex(this->window_number)));
00474 break;
00475 }
00476
00477 case WID_NGRFI_MAINPANEL: {
00478
00479 const NIFeature *nif = GetFeature(this->window_number);
00480 if (nif->variables == NULL) return;
00481
00482
00483 int line = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NGRFI_MAINPANEL, TOP_OFFSET);
00484 if (line == INT_MAX) return;
00485
00486
00487 for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++, line--) {
00488 if (line != 1) continue;
00489
00490 if (!HasVariableParameter(niv->var)) break;
00491
00492 this->current_edit_param = niv->var;
00493 ShowQueryString(STR_EMPTY, STR_NEWGRF_INSPECT_QUERY_CAPTION, 9, this, CS_HEXADECIMAL, QSF_NONE);
00494 }
00495 }
00496 }
00497 }
00498
00499 virtual void OnQueryTextFinished(char *str)
00500 {
00501 if (StrEmpty(str)) return;
00502
00503 NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][this->current_edit_param - 0x60] = strtol(str, NULL, 16);
00504 this->SetDirty();
00505 }
00506
00507 virtual void OnResize()
00508 {
00509 this->vscroll->SetCapacityFromWidget(this, WID_NGRFI_MAINPANEL, TOP_OFFSET + BOTTOM_OFFSET);
00510 }
00511 };
00512
00513 uint32 NewGRFInspectWindow::var60params[GSF_FAKE_END][0x20] = { {0} };
00514
00515 static const NWidgetPart _nested_newgrf_inspect_widgets[] = {
00516 NWidget(NWID_HORIZONTAL),
00517 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00518 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00519 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NGRFI_PARENT), SetDataTip(STR_NEWGRF_INSPECT_PARENT_BUTTON, STR_NEWGRF_INSPECT_PARENT_TOOLTIP),
00520 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00521 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00522 EndContainer(),
00523 NWidget(NWID_HORIZONTAL),
00524 NWidget(WWT_PANEL, COLOUR_GREY, WID_NGRFI_MAINPANEL), SetMinimalSize(300, 0), SetScrollbar(WID_NGRFI_SCROLLBAR), EndContainer(),
00525 NWidget(NWID_VERTICAL),
00526 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_NGRFI_SCROLLBAR),
00527 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
00528 EndContainer(),
00529 EndContainer(),
00530 };
00531
00532 static const WindowDesc _newgrf_inspect_desc(
00533 WDP_AUTO, 400, 300,
00534 WC_NEWGRF_INSPECT, WC_NONE,
00535 WDF_UNCLICK_BUTTONS,
00536 _nested_newgrf_inspect_widgets, lengthof(_nested_newgrf_inspect_widgets)
00537 );
00538
00548 void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index, const uint32 grfid)
00549 {
00550 if (!IsNewGRFInspectable(feature, index)) return;
00551
00552 WindowNumber wno = GetInspectWindowNumber(feature, index);
00553 NewGRFInspectWindow *w = AllocateWindowDescFront<NewGRFInspectWindow>(&_newgrf_inspect_desc, wno);
00554 if (w == NULL) w = (NewGRFInspectWindow *)FindWindowById(WC_NEWGRF_INSPECT, wno);
00555 w->SetCallerGRFID(grfid);
00556 }
00557
00566 void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
00567 {
00568 if (feature == GSF_INVALID) return;
00569
00570 WindowNumber wno = GetInspectWindowNumber(feature, index);
00571 DeleteWindowById(WC_NEWGRF_INSPECT, wno);
00572
00573
00574
00575
00576 InvalidateWindowData(WC_LAND_INFO, 0, 1);
00577 }
00578
00588 bool IsNewGRFInspectable(GrfSpecFeature feature, uint index)
00589 {
00590 const NIFeature *nif = GetFeature(GetInspectWindowNumber(feature, index));
00591 if (nif == NULL) return false;
00592 return nif->helper->IsInspectable(index);
00593 }
00594
00600 GrfSpecFeature GetGrfSpecFeature(TileIndex tile)
00601 {
00602 switch (GetTileType(tile)) {
00603 default: return GSF_INVALID;
00604 case MP_RAILWAY: return GSF_RAILTYPES;
00605 case MP_ROAD: return IsLevelCrossing(tile) ? GSF_RAILTYPES : GSF_INVALID;
00606 case MP_HOUSE: return GSF_HOUSES;
00607 case MP_INDUSTRY: return GSF_INDUSTRYTILES;
00608 case MP_OBJECT: return GSF_OBJECTS;
00609
00610 case MP_STATION:
00611 switch (GetStationType(tile)) {
00612 case STATION_RAIL: return GSF_STATIONS;
00613 case STATION_AIRPORT: return GSF_AIRPORTTILES;
00614 default: return GSF_INVALID;
00615 }
00616 }
00617 }
00618
00624 GrfSpecFeature GetGrfSpecFeature(VehicleType type)
00625 {
00626 switch (type) {
00627 case VEH_TRAIN: return GSF_TRAINS;
00628 case VEH_ROAD: return GSF_ROADVEHICLES;
00629 case VEH_SHIP: return GSF_SHIPS;
00630 case VEH_AIRCRAFT: return GSF_AIRCRAFT;
00631 default: return GSF_INVALID;
00632 }
00633 }
00634
00635
00636
00637
00638
00640 struct SpriteAlignerWindow : Window {
00641 SpriteID current_sprite;
00642 Scrollbar *vscroll;
00643
00644 SpriteAlignerWindow(const WindowDesc *desc, WindowNumber wno) : Window()
00645 {
00646 this->CreateNestedTree(desc);
00647 this->vscroll = this->GetScrollbar(WID_SA_SCROLLBAR);
00648 this->FinishInitNested(desc, wno);
00649
00650
00651 while (GetSpriteType(this->current_sprite) != ST_NORMAL) this->current_sprite++;
00652 }
00653
00654 virtual void SetStringParameters(int widget) const
00655 {
00656 switch (widget) {
00657 case WID_SA_CAPTION:
00658 SetDParam(0, this->current_sprite);
00659 SetDParamStr(1, FioGetFilename(GetOriginFileSlot(this->current_sprite)));
00660 break;
00661
00662 case WID_SA_OFFSETS: {
00663 const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL);
00664 SetDParam(0, spr->x_offs / ZOOM_LVL_BASE);
00665 SetDParam(1, spr->y_offs / ZOOM_LVL_BASE);
00666 break;
00667 }
00668
00669 default:
00670 break;
00671 }
00672 }
00673
00674 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00675 {
00676 if (widget != WID_SA_LIST) return;
00677
00678 resize->height = max(11, FONT_HEIGHT_NORMAL + 1);
00679 resize->width = 1;
00680
00681
00682 size->height = (1 + 200 / resize->height) * resize->height;
00683 }
00684
00685 virtual void DrawWidget(const Rect &r, int widget) const
00686 {
00687 switch (widget) {
00688 case WID_SA_SPRITE: {
00689
00690 const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL);
00691 int width = r.right - r.left + 1;
00692 int height = r.bottom - r.top + 1;
00693 int x = r.left - spr->x_offs / ZOOM_LVL_BASE + (width - spr->width / ZOOM_LVL_BASE) / 2;
00694 int y = r.top - spr->y_offs / ZOOM_LVL_BASE + (height - spr->height / ZOOM_LVL_BASE) / 2;
00695
00696
00697 SubSprite subspr = {
00698 spr->x_offs + (spr->width - width * ZOOM_LVL_BASE) / 2 + 1,
00699 spr->y_offs + (spr->height - height * ZOOM_LVL_BASE) / 2 + 1,
00700 spr->x_offs + (spr->width + width * ZOOM_LVL_BASE) / 2 - 1,
00701 spr->y_offs + (spr->height + height * ZOOM_LVL_BASE) / 2 - 1,
00702 };
00703
00704 DrawSprite(this->current_sprite, PAL_NONE, x, y, &subspr, ZOOM_LVL_GUI);
00705 break;
00706 }
00707
00708 case WID_SA_LIST: {
00709 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
00710 int step_size = nwid->resize_y;
00711
00712 SmallVector<SpriteID, 256> &list = _newgrf_debug_sprite_picker.sprites;
00713 int max = min<int>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), list.Length());
00714
00715 int y = r.top + WD_FRAMERECT_TOP;
00716 for (int i = this->vscroll->GetPosition(); i < max; i++) {
00717 SetDParam(0, list[i]);
00718 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_BLACK_COMMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE);
00719 y += step_size;
00720 }
00721 break;
00722 }
00723 }
00724 }
00725
00726 virtual void OnClick(Point pt, int widget, int click_count)
00727 {
00728 switch (widget) {
00729 case WID_SA_PREVIOUS:
00730 do {
00731 this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() : this->current_sprite) - 1;
00732 } while (GetSpriteType(this->current_sprite) != ST_NORMAL);
00733 this->SetDirty();
00734 break;
00735
00736 case WID_SA_GOTO:
00737 ShowQueryString(STR_EMPTY, STR_SPRITE_ALIGNER_GOTO_CAPTION, 7, this, CS_NUMERAL, QSF_NONE);
00738 break;
00739
00740 case WID_SA_NEXT:
00741 do {
00742 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
00743 } while (GetSpriteType(this->current_sprite) != ST_NORMAL);
00744 this->SetDirty();
00745 break;
00746
00747 case WID_SA_PICKER:
00748 this->LowerWidget(WID_SA_PICKER);
00749 _newgrf_debug_sprite_picker.mode = SPM_WAIT_CLICK;
00750 this->SetDirty();
00751 break;
00752
00753 case WID_SA_LIST: {
00754 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
00755 int step_size = nwid->resize_y;
00756
00757 uint i = this->vscroll->GetPosition() + (pt.y - nwid->pos_y) / step_size;
00758 if (i < _newgrf_debug_sprite_picker.sprites.Length()) {
00759 SpriteID spr = _newgrf_debug_sprite_picker.sprites[i];
00760 if (GetSpriteType(spr) == ST_NORMAL) this->current_sprite = spr;
00761 }
00762 this->SetDirty();
00763 break;
00764 }
00765
00766 case WID_SA_UP:
00767 case WID_SA_DOWN:
00768 case WID_SA_LEFT:
00769 case WID_SA_RIGHT: {
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783 Sprite *spr = const_cast<Sprite *>(GetSprite(this->current_sprite, ST_NORMAL));
00784 switch (widget) {
00785 case WID_SA_UP: spr->y_offs -= ZOOM_LVL_BASE; break;
00786 case WID_SA_DOWN: spr->y_offs += ZOOM_LVL_BASE; break;
00787 case WID_SA_LEFT: spr->x_offs -= ZOOM_LVL_BASE; break;
00788 case WID_SA_RIGHT: spr->x_offs += ZOOM_LVL_BASE; break;
00789 }
00790
00791
00792 MarkWholeScreenDirty();
00793 break;
00794 }
00795 }
00796 }
00797
00798 virtual void OnQueryTextFinished(char *str)
00799 {
00800 if (StrEmpty(str)) return;
00801
00802 this->current_sprite = atoi(str);
00803 if (this->current_sprite >= GetMaxSpriteID()) this->current_sprite = 0;
00804 while (GetSpriteType(this->current_sprite) != ST_NORMAL) {
00805 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
00806 }
00807 this->SetDirty();
00808 }
00809
00815 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
00816 {
00817 if (!gui_scope) return;
00818 if (data == 1) {
00819
00820 this->RaiseWidget(WID_SA_PICKER);
00821 this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.Length());
00822 }
00823 }
00824
00825 virtual void OnResize()
00826 {
00827 this->vscroll->SetCapacityFromWidget(this, WID_SA_LIST);
00828 this->GetWidget<NWidgetCore>(WID_SA_LIST)->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
00829 }
00830 };
00831
00832 static const NWidgetPart _nested_sprite_aligner_widgets[] = {
00833 NWidget(NWID_HORIZONTAL),
00834 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00835 NWidget(WWT_CAPTION, COLOUR_GREY, WID_SA_CAPTION), SetDataTip(STR_SPRITE_ALIGNER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00836 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00837 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00838 EndContainer(),
00839 NWidget(WWT_PANEL, COLOUR_GREY),
00840 NWidget(NWID_HORIZONTAL), SetPIP(0, 0, 10),
00841 NWidget(NWID_VERTICAL), SetPIP(10, 5, 10),
00842 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 5, 10),
00843 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_PREVIOUS), SetDataTip(STR_SPRITE_ALIGNER_PREVIOUS_BUTTON, STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP), SetFill(1, 0),
00844 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_GOTO), SetDataTip(STR_SPRITE_ALIGNER_GOTO_BUTTON, STR_SPRITE_ALIGNER_GOTO_TOOLTIP), SetFill(1, 0),
00845 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_NEXT), SetDataTip(STR_SPRITE_ALIGNER_NEXT_BUTTON, STR_SPRITE_ALIGNER_NEXT_TOOLTIP), SetFill(1, 0),
00846 EndContainer(),
00847 NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
00848 NWidget(NWID_SPACER), SetFill(1, 1),
00849 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_UP), SetDataTip(SPR_ARROW_UP, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00850 NWidget(NWID_SPACER), SetFill(1, 1),
00851 EndContainer(),
00852 NWidget(NWID_HORIZONTAL_LTR), SetPIP(10, 5, 10),
00853 NWidget(NWID_VERTICAL),
00854 NWidget(NWID_SPACER), SetFill(1, 1),
00855 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_LEFT), SetDataTip(SPR_ARROW_LEFT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00856 NWidget(NWID_SPACER), SetFill(1, 1),
00857 EndContainer(),
00858 NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_SA_SPRITE), SetDataTip(STR_NULL, STR_SPRITE_ALIGNER_SPRITE_TOOLTIP),
00859 EndContainer(),
00860 NWidget(NWID_VERTICAL),
00861 NWidget(NWID_SPACER), SetFill(1, 1),
00862 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_RIGHT), SetDataTip(SPR_ARROW_RIGHT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00863 NWidget(NWID_SPACER), SetFill(1, 1),
00864 EndContainer(),
00865 EndContainer(),
00866 NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
00867 NWidget(NWID_SPACER), SetFill(1, 1),
00868 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00869 NWidget(NWID_SPACER), SetFill(1, 1),
00870 EndContainer(),
00871 NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
00872 NWidget(WWT_LABEL, COLOUR_GREY, WID_SA_OFFSETS), SetDataTip(STR_SPRITE_ALIGNER_OFFSETS, STR_NULL), SetFill(1, 0),
00873 EndContainer(),
00874 EndContainer(),
00875 NWidget(NWID_VERTICAL), SetPIP(10, 5, 10),
00876 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_PICKER), SetDataTip(STR_SPRITE_ALIGNER_PICKER_BUTTON, STR_SPRITE_ALIGNER_PICKER_TOOLTIP), SetFill(1, 0),
00877 NWidget(NWID_HORIZONTAL),
00878 NWidget(WWT_MATRIX, COLOUR_GREY, WID_SA_LIST), SetResize(1, 1), SetDataTip(0x101, STR_NULL), SetFill(1, 1), SetScrollbar(WID_SA_SCROLLBAR),
00879 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SA_SCROLLBAR),
00880 EndContainer(),
00881 EndContainer(),
00882 EndContainer(),
00883 EndContainer(),
00884 };
00885
00886 static const WindowDesc _sprite_aligner_desc(
00887 WDP_AUTO, 400, 300,
00888 WC_SPRITE_ALIGNER, WC_NONE,
00889 WDF_UNCLICK_BUTTONS,
00890 _nested_sprite_aligner_widgets, lengthof(_nested_sprite_aligner_widgets)
00891 );
00892
00896 void ShowSpriteAlignerWindow()
00897 {
00898 AllocateWindowDescFront<SpriteAlignerWindow>(&_sprite_aligner_desc, 0);
00899 }