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 #include "newgrf_railtype.h"
00036 #include "newgrf_industries.h"
00037 #include "newgrf_industrytiles.h"
00038
00039 #include "widgets/newgrf_debug_widget.h"
00040
00041 #include "table/strings.h"
00042
00044 NewGrfDebugSpritePicker _newgrf_debug_sprite_picker = { SPM_NONE, NULL, 0, SmallVector<SpriteID, 256>() };
00045
00051 static inline uint GetFeatureIndex(uint window_number)
00052 {
00053 return GB(window_number, 0, 24);
00054 }
00055
00063 static inline uint GetInspectWindowNumber(GrfSpecFeature feature, uint index)
00064 {
00065 assert((index >> 24) == 0);
00066 return (feature << 24) | index;
00067 }
00068
00073 enum NIType {
00074 NIT_INT,
00075 NIT_CARGO,
00076 };
00077
00079 struct NIProperty {
00080 const char *name;
00081 ptrdiff_t offset;
00082 byte read_size;
00083 byte prop;
00084 byte type;
00085 };
00086
00087
00092 struct NICallback {
00093 const char *name;
00094 ptrdiff_t offset;
00095 byte read_size;
00096 byte cb_bit;
00097 uint16 cb_id;
00098 };
00100 static const int CBM_NO_BIT = UINT8_MAX;
00101
00103 struct NIVariable {
00104 const char *name;
00105 byte var;
00106 };
00107
00109 class NIHelper {
00110 public:
00112 virtual ~NIHelper() {}
00113
00119 virtual bool IsInspectable(uint index) const = 0;
00120
00126 virtual uint GetParent(uint index) const = 0;
00127
00133 virtual const void *GetInstance(uint index) const = 0;
00134
00140 virtual const void *GetSpec(uint index) const = 0;
00141
00146 virtual void SetStringParameters(uint index) const = 0;
00147
00153 virtual uint32 GetGRFID(uint index) const = 0;
00154
00163 virtual uint Resolve(uint index, uint var, uint param, bool *avail) const = 0;
00164
00169 virtual bool PSAWithParameter() const
00170 {
00171 return false;
00172 }
00173
00180 virtual uint GetPSASize(uint index, uint32 grfid) const
00181 {
00182 return 0;
00183 }
00184
00191 virtual const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const
00192 {
00193 return NULL;
00194 }
00195
00196 protected:
00202 void SetSimpleStringParameters(StringID string, uint32 index) const
00203 {
00204 SetDParam(0, string);
00205 SetDParam(1, index);
00206 }
00207
00208
00215 void SetObjectAtStringParameters(StringID string, uint32 index, TileIndex tile) const
00216 {
00217 SetDParam(0, STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT);
00218 SetDParam(1, string);
00219 SetDParam(2, index);
00220 SetDParam(3, tile);
00221 }
00222 };
00223
00224
00226 struct NIFeature {
00227 const NIProperty *properties;
00228 const NICallback *callbacks;
00229 const NIVariable *variables;
00230 const NIHelper *helper;
00231 };
00232
00233
00234 #include "table/newgrf_debug_data.h"
00235
00241 static inline GrfSpecFeature GetFeatureNum(uint window_number)
00242 {
00243 return (GrfSpecFeature)GB(window_number, 24, 8);
00244 }
00245
00251 static inline const NIFeature *GetFeature(uint window_number)
00252 {
00253 GrfSpecFeature idx = GetFeatureNum(window_number);
00254 return idx < GSF_FAKE_END ? _nifeatures[idx] : NULL;
00255 }
00256
00263 static inline const NIHelper *GetFeatureHelper(uint window_number)
00264 {
00265 return GetFeature(window_number)->helper;
00266 }
00267
00269 struct NewGRFInspectWindow : Window {
00270 static const int LEFT_OFFSET = 5;
00271 static const int RIGHT_OFFSET = 5;
00272 static const int TOP_OFFSET = 5;
00273 static const int BOTTOM_OFFSET = 5;
00274
00276 static uint32 var60params[GSF_FAKE_END][0x20];
00277
00279 uint32 caller_grfid;
00280
00282 byte current_edit_param;
00283
00284 Scrollbar *vscroll;
00285
00291 static bool HasVariableParameter(uint variable)
00292 {
00293 return IsInsideBS(variable, 0x60, 0x20);
00294 }
00295
00300 void SetCallerGRFID(uint32 grfid)
00301 {
00302 this->caller_grfid = grfid;
00303 this->SetDirty();
00304 }
00305
00306 NewGRFInspectWindow(WindowDesc *desc, WindowNumber wno) : Window(desc)
00307 {
00308 this->CreateNestedTree();
00309 this->vscroll = this->GetScrollbar(WID_NGRFI_SCROLLBAR);
00310 this->FinishInitNested(wno);
00311
00312 this->vscroll->SetCount(0);
00313 this->SetWidgetDisabledState(WID_NGRFI_PARENT, GetFeatureHelper(this->window_number)->GetParent(GetFeatureIndex(this->window_number)) == UINT32_MAX);
00314 }
00315
00316 virtual void SetStringParameters(int widget) const
00317 {
00318 if (widget != WID_NGRFI_CAPTION) return;
00319
00320 GetFeatureHelper(this->window_number)->SetStringParameters(GetFeatureIndex(this->window_number));
00321 }
00322
00323 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00324 {
00325 if (widget != WID_NGRFI_MAINPANEL) return;
00326
00327 resize->height = max(11, FONT_HEIGHT_NORMAL + 1);
00328 resize->width = 1;
00329
00330 size->height = 5 * resize->height + TOP_OFFSET + BOTTOM_OFFSET;
00331 }
00332
00339 void WARN_FORMAT(4, 5) DrawString(const Rect &r, int offset, const char *format, ...) const
00340 {
00341 char buf[1024];
00342
00343 va_list va;
00344 va_start(va, format);
00345 vsnprintf(buf, lengthof(buf), format, va);
00346 va_end(va);
00347
00348 offset -= this->vscroll->GetPosition();
00349 if (offset < 0 || offset >= this->vscroll->GetCapacity()) return;
00350
00351 ::DrawString(r.left + LEFT_OFFSET, r.right + RIGHT_OFFSET, r.top + TOP_OFFSET + (offset * this->resize.step_height), buf, TC_BLACK);
00352 }
00353
00354 virtual void DrawWidget(const Rect &r, int widget) const
00355 {
00356 if (widget != WID_NGRFI_MAINPANEL) return;
00357
00358 uint index = GetFeatureIndex(this->window_number);
00359 const NIFeature *nif = GetFeature(this->window_number);
00360 const NIHelper *nih = nif->helper;
00361 const void *base = nih->GetInstance(index);
00362 const void *base_spec = nih->GetSpec(index);
00363
00364 uint i = 0;
00365 if (nif->variables != NULL) {
00366 this->DrawString(r, i++, "Variables:");
00367 for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++) {
00368 bool avail = true;
00369 uint param = HasVariableParameter(niv->var) ? NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][niv->var - 0x60] : 0;
00370 uint value = nih->Resolve(index, niv->var, param, &avail);
00371
00372 if (!avail) continue;
00373
00374 if (HasVariableParameter(niv->var)) {
00375 this->DrawString(r, i++, " %02x[%02x]: %08x (%s)", niv->var, param, value, niv->name);
00376 } else {
00377 this->DrawString(r, i++, " %02x: %08x (%s)", niv->var, value, niv->name);
00378 }
00379 }
00380 }
00381
00382 uint psa_size = nih->GetPSASize(index, this->caller_grfid);
00383 const int32 *psa = nih->GetPSAFirstPosition(index, this->caller_grfid);
00384 if (psa_size != 0 && psa != NULL) {
00385 if (nih->PSAWithParameter()) {
00386 this->DrawString(r, i++, "Persistent storage [%08X]:", BSWAP32(this->caller_grfid));
00387 } else {
00388 this->DrawString(r, i++, "Persistent storage:");
00389 }
00390 assert(psa_size % 4 == 0);
00391 for (uint j = 0; j < psa_size; j += 4, psa += 4) {
00392 this->DrawString(r, i++, " %i: %i %i %i %i", j, psa[0], psa[1], psa[2], psa[3]);
00393 }
00394 }
00395
00396 if (nif->properties != NULL) {
00397 this->DrawString(r, i++, "Properties:");
00398 for (const NIProperty *nip = nif->properties; nip->name != NULL; nip++) {
00399 const void *ptr = (const byte *)base + nip->offset;
00400 uint value;
00401 switch (nip->read_size) {
00402 case 1: value = *(const uint8 *)ptr; break;
00403 case 2: value = *(const uint16 *)ptr; break;
00404 case 4: value = *(const uint32 *)ptr; break;
00405 default: NOT_REACHED();
00406 }
00407
00408 StringID string;
00409 SetDParam(0, value);
00410 switch (nip->type) {
00411 case NIT_INT:
00412 string = STR_JUST_INT;
00413 break;
00414
00415 case NIT_CARGO:
00416 string = value != INVALID_CARGO ? CargoSpec::Get(value)->name : STR_QUANTITY_N_A;
00417 break;
00418
00419 default:
00420 NOT_REACHED();
00421 }
00422
00423 char buffer[64];
00424 GetString(buffer, string, lastof(buffer));
00425 this->DrawString(r, i++, " %02x: %s (%s)", nip->prop, buffer, nip->name);
00426 }
00427 }
00428
00429 if (nif->callbacks != NULL) {
00430 this->DrawString(r, i++, "Callbacks:");
00431 for (const NICallback *nic = nif->callbacks; nic->name != NULL; nic++) {
00432 if (nic->cb_bit != CBM_NO_BIT) {
00433 const void *ptr = (const byte *)base_spec + nic->offset;
00434 uint value;
00435 switch (nic->read_size) {
00436 case 1: value = *(const uint8 *)ptr; break;
00437 case 2: value = *(const uint16 *)ptr; break;
00438 case 4: value = *(const uint32 *)ptr; break;
00439 default: NOT_REACHED();
00440 }
00441
00442 if (!HasBit(value, nic->cb_bit)) continue;
00443 this->DrawString(r, i++, " %03x: %s", nic->cb_id, nic->name);
00444 } else {
00445 this->DrawString(r, i++, " %03x: %s (unmasked)", nic->cb_id, nic->name);
00446 }
00447 }
00448 }
00449
00450
00451
00452
00453 const_cast<NewGRFInspectWindow*>(this)->vscroll->SetCount(i);
00454 }
00455
00456 virtual void OnClick(Point pt, int widget, int click_count)
00457 {
00458 switch (widget) {
00459 case WID_NGRFI_PARENT: {
00460 const NIHelper *nih = GetFeatureHelper(this->window_number);
00461 uint index = nih->GetParent(GetFeatureIndex(this->window_number));
00462 ::ShowNewGRFInspectWindow((GrfSpecFeature)GB(index, 24, 8), GetFeatureIndex(index), nih->GetGRFID(GetFeatureIndex(this->window_number)));
00463 break;
00464 }
00465
00466 case WID_NGRFI_MAINPANEL: {
00467
00468 const NIFeature *nif = GetFeature(this->window_number);
00469 if (nif->variables == NULL) return;
00470
00471
00472 int line = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NGRFI_MAINPANEL, TOP_OFFSET);
00473 if (line == INT_MAX) return;
00474
00475
00476 for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++, line--) {
00477 if (line != 1) continue;
00478
00479 if (!HasVariableParameter(niv->var)) break;
00480
00481 this->current_edit_param = niv->var;
00482 ShowQueryString(STR_EMPTY, STR_NEWGRF_INSPECT_QUERY_CAPTION, 9, this, CS_HEXADECIMAL, QSF_NONE);
00483 }
00484 }
00485 }
00486 }
00487
00488 virtual void OnQueryTextFinished(char *str)
00489 {
00490 if (StrEmpty(str)) return;
00491
00492 NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][this->current_edit_param - 0x60] = strtol(str, NULL, 16);
00493 this->SetDirty();
00494 }
00495
00496 virtual void OnResize()
00497 {
00498 this->vscroll->SetCapacityFromWidget(this, WID_NGRFI_MAINPANEL, TOP_OFFSET + BOTTOM_OFFSET);
00499 }
00500 };
00501
00502 uint32 NewGRFInspectWindow::var60params[GSF_FAKE_END][0x20] = { {0} };
00503
00504 static const NWidgetPart _nested_newgrf_inspect_widgets[] = {
00505 NWidget(NWID_HORIZONTAL),
00506 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00507 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00508 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NGRFI_PARENT), SetDataTip(STR_NEWGRF_INSPECT_PARENT_BUTTON, STR_NEWGRF_INSPECT_PARENT_TOOLTIP),
00509 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00510 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
00511 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00512 EndContainer(),
00513 NWidget(NWID_HORIZONTAL),
00514 NWidget(WWT_PANEL, COLOUR_GREY, WID_NGRFI_MAINPANEL), SetMinimalSize(300, 0), SetScrollbar(WID_NGRFI_SCROLLBAR), EndContainer(),
00515 NWidget(NWID_VERTICAL),
00516 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_NGRFI_SCROLLBAR),
00517 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
00518 EndContainer(),
00519 EndContainer(),
00520 };
00521
00522 static WindowDesc _newgrf_inspect_desc(
00523 WDP_AUTO, "newgrf_inspect", 400, 300,
00524 WC_NEWGRF_INSPECT, WC_NONE,
00525 0,
00526 _nested_newgrf_inspect_widgets, lengthof(_nested_newgrf_inspect_widgets)
00527 );
00528
00538 void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index, const uint32 grfid)
00539 {
00540 if (!IsNewGRFInspectable(feature, index)) return;
00541
00542 WindowNumber wno = GetInspectWindowNumber(feature, index);
00543 NewGRFInspectWindow *w = AllocateWindowDescFront<NewGRFInspectWindow>(&_newgrf_inspect_desc, wno);
00544 if (w == NULL) w = (NewGRFInspectWindow *)FindWindowById(WC_NEWGRF_INSPECT, wno);
00545 w->SetCallerGRFID(grfid);
00546 }
00547
00556 void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
00557 {
00558 if (feature == GSF_INVALID) return;
00559
00560 WindowNumber wno = GetInspectWindowNumber(feature, index);
00561 DeleteWindowById(WC_NEWGRF_INSPECT, wno);
00562
00563
00564
00565
00566 InvalidateWindowData(WC_LAND_INFO, 0, 1);
00567 }
00568
00578 bool IsNewGRFInspectable(GrfSpecFeature feature, uint index)
00579 {
00580 const NIFeature *nif = GetFeature(GetInspectWindowNumber(feature, index));
00581 if (nif == NULL) return false;
00582 return nif->helper->IsInspectable(index);
00583 }
00584
00590 GrfSpecFeature GetGrfSpecFeature(TileIndex tile)
00591 {
00592 switch (GetTileType(tile)) {
00593 default: return GSF_INVALID;
00594 case MP_RAILWAY: return GSF_RAILTYPES;
00595 case MP_ROAD: return IsLevelCrossing(tile) ? GSF_RAILTYPES : GSF_INVALID;
00596 case MP_HOUSE: return GSF_HOUSES;
00597 case MP_INDUSTRY: return GSF_INDUSTRYTILES;
00598 case MP_OBJECT: return GSF_OBJECTS;
00599
00600 case MP_STATION:
00601 switch (GetStationType(tile)) {
00602 case STATION_RAIL: return GSF_STATIONS;
00603 case STATION_AIRPORT: return GSF_AIRPORTTILES;
00604 default: return GSF_INVALID;
00605 }
00606 }
00607 }
00608
00614 GrfSpecFeature GetGrfSpecFeature(VehicleType type)
00615 {
00616 switch (type) {
00617 case VEH_TRAIN: return GSF_TRAINS;
00618 case VEH_ROAD: return GSF_ROADVEHICLES;
00619 case VEH_SHIP: return GSF_SHIPS;
00620 case VEH_AIRCRAFT: return GSF_AIRCRAFT;
00621 default: return GSF_INVALID;
00622 }
00623 }
00624
00625
00626
00627
00628
00630 struct SpriteAlignerWindow : Window {
00631 SpriteID current_sprite;
00632 Scrollbar *vscroll;
00633
00634 SpriteAlignerWindow(WindowDesc *desc, WindowNumber wno) : Window(desc)
00635 {
00636 this->CreateNestedTree();
00637 this->vscroll = this->GetScrollbar(WID_SA_SCROLLBAR);
00638 this->FinishInitNested(wno);
00639
00640
00641 while (GetSpriteType(this->current_sprite) != ST_NORMAL) this->current_sprite++;
00642 }
00643
00644 virtual void SetStringParameters(int widget) const
00645 {
00646 switch (widget) {
00647 case WID_SA_CAPTION:
00648 SetDParam(0, this->current_sprite);
00649 SetDParamStr(1, FioGetFilename(GetOriginFileSlot(this->current_sprite)));
00650 break;
00651
00652 case WID_SA_OFFSETS: {
00653 const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL);
00654 SetDParam(0, spr->x_offs / ZOOM_LVL_BASE);
00655 SetDParam(1, spr->y_offs / ZOOM_LVL_BASE);
00656 break;
00657 }
00658
00659 default:
00660 break;
00661 }
00662 }
00663
00664 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00665 {
00666 if (widget != WID_SA_LIST) return;
00667
00668 resize->height = max(11, FONT_HEIGHT_NORMAL + 1);
00669 resize->width = 1;
00670
00671
00672 size->height = (1 + 200 / resize->height) * resize->height;
00673 }
00674
00675 virtual void DrawWidget(const Rect &r, int widget) const
00676 {
00677 switch (widget) {
00678 case WID_SA_SPRITE: {
00679
00680 const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL);
00681 int width = r.right - r.left + 1;
00682 int height = r.bottom - r.top + 1;
00683 int x = r.left - spr->x_offs / ZOOM_LVL_BASE + (width - spr->width / ZOOM_LVL_BASE) / 2;
00684 int y = r.top - spr->y_offs / ZOOM_LVL_BASE + (height - spr->height / ZOOM_LVL_BASE) / 2;
00685
00686
00687 SubSprite subspr = {
00688 spr->x_offs + (spr->width - width * ZOOM_LVL_BASE) / 2 + 1,
00689 spr->y_offs + (spr->height - height * ZOOM_LVL_BASE) / 2 + 1,
00690 spr->x_offs + (spr->width + width * ZOOM_LVL_BASE) / 2 - 1,
00691 spr->y_offs + (spr->height + height * ZOOM_LVL_BASE) / 2 - 1,
00692 };
00693
00694 DrawSprite(this->current_sprite, PAL_NONE, x, y, &subspr, ZOOM_LVL_GUI);
00695 break;
00696 }
00697
00698 case WID_SA_LIST: {
00699 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
00700 int step_size = nwid->resize_y;
00701
00702 SmallVector<SpriteID, 256> &list = _newgrf_debug_sprite_picker.sprites;
00703 int max = min<int>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), list.Length());
00704
00705 int y = r.top + WD_FRAMERECT_TOP;
00706 for (int i = this->vscroll->GetPosition(); i < max; i++) {
00707 SetDParam(0, list[i]);
00708 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_BLACK_COMMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE);
00709 y += step_size;
00710 }
00711 break;
00712 }
00713 }
00714 }
00715
00716 virtual void OnClick(Point pt, int widget, int click_count)
00717 {
00718 switch (widget) {
00719 case WID_SA_PREVIOUS:
00720 do {
00721 this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() : this->current_sprite) - 1;
00722 } while (GetSpriteType(this->current_sprite) != ST_NORMAL);
00723 this->SetDirty();
00724 break;
00725
00726 case WID_SA_GOTO:
00727 ShowQueryString(STR_EMPTY, STR_SPRITE_ALIGNER_GOTO_CAPTION, 7, this, CS_NUMERAL, QSF_NONE);
00728 break;
00729
00730 case WID_SA_NEXT:
00731 do {
00732 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
00733 } while (GetSpriteType(this->current_sprite) != ST_NORMAL);
00734 this->SetDirty();
00735 break;
00736
00737 case WID_SA_PICKER:
00738 this->LowerWidget(WID_SA_PICKER);
00739 _newgrf_debug_sprite_picker.mode = SPM_WAIT_CLICK;
00740 this->SetDirty();
00741 break;
00742
00743 case WID_SA_LIST: {
00744 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
00745 int step_size = nwid->resize_y;
00746
00747 uint i = this->vscroll->GetPosition() + (pt.y - nwid->pos_y) / step_size;
00748 if (i < _newgrf_debug_sprite_picker.sprites.Length()) {
00749 SpriteID spr = _newgrf_debug_sprite_picker.sprites[i];
00750 if (GetSpriteType(spr) == ST_NORMAL) this->current_sprite = spr;
00751 }
00752 this->SetDirty();
00753 break;
00754 }
00755
00756 case WID_SA_UP:
00757 case WID_SA_DOWN:
00758 case WID_SA_LEFT:
00759 case WID_SA_RIGHT: {
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773 Sprite *spr = const_cast<Sprite *>(GetSprite(this->current_sprite, ST_NORMAL));
00774 switch (widget) {
00775 case WID_SA_UP: spr->y_offs -= ZOOM_LVL_BASE; break;
00776 case WID_SA_DOWN: spr->y_offs += ZOOM_LVL_BASE; break;
00777 case WID_SA_LEFT: spr->x_offs -= ZOOM_LVL_BASE; break;
00778 case WID_SA_RIGHT: spr->x_offs += ZOOM_LVL_BASE; break;
00779 }
00780
00781
00782 MarkWholeScreenDirty();
00783 break;
00784 }
00785 }
00786 }
00787
00788 virtual void OnQueryTextFinished(char *str)
00789 {
00790 if (StrEmpty(str)) return;
00791
00792 this->current_sprite = atoi(str);
00793 if (this->current_sprite >= GetMaxSpriteID()) this->current_sprite = 0;
00794 while (GetSpriteType(this->current_sprite) != ST_NORMAL) {
00795 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
00796 }
00797 this->SetDirty();
00798 }
00799
00805 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
00806 {
00807 if (!gui_scope) return;
00808 if (data == 1) {
00809
00810 this->RaiseWidget(WID_SA_PICKER);
00811 this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.Length());
00812 }
00813 }
00814
00815 virtual void OnResize()
00816 {
00817 this->vscroll->SetCapacityFromWidget(this, WID_SA_LIST);
00818 this->GetWidget<NWidgetCore>(WID_SA_LIST)->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
00819 }
00820 };
00821
00822 static const NWidgetPart _nested_sprite_aligner_widgets[] = {
00823 NWidget(NWID_HORIZONTAL),
00824 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00825 NWidget(WWT_CAPTION, COLOUR_GREY, WID_SA_CAPTION), SetDataTip(STR_SPRITE_ALIGNER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00826 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00827 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00828 EndContainer(),
00829 NWidget(WWT_PANEL, COLOUR_GREY),
00830 NWidget(NWID_HORIZONTAL), SetPIP(0, 0, 10),
00831 NWidget(NWID_VERTICAL), SetPIP(10, 5, 10),
00832 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 5, 10),
00833 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_PREVIOUS), SetDataTip(STR_SPRITE_ALIGNER_PREVIOUS_BUTTON, STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP), SetFill(1, 0),
00834 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_GOTO), SetDataTip(STR_SPRITE_ALIGNER_GOTO_BUTTON, STR_SPRITE_ALIGNER_GOTO_TOOLTIP), SetFill(1, 0),
00835 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_NEXT), SetDataTip(STR_SPRITE_ALIGNER_NEXT_BUTTON, STR_SPRITE_ALIGNER_NEXT_TOOLTIP), SetFill(1, 0),
00836 EndContainer(),
00837 NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
00838 NWidget(NWID_SPACER), SetFill(1, 1),
00839 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_UP), SetDataTip(SPR_ARROW_UP, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00840 NWidget(NWID_SPACER), SetFill(1, 1),
00841 EndContainer(),
00842 NWidget(NWID_HORIZONTAL_LTR), SetPIP(10, 5, 10),
00843 NWidget(NWID_VERTICAL),
00844 NWidget(NWID_SPACER), SetFill(1, 1),
00845 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_LEFT), SetDataTip(SPR_ARROW_LEFT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00846 NWidget(NWID_SPACER), SetFill(1, 1),
00847 EndContainer(),
00848 NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_SA_SPRITE), SetDataTip(STR_NULL, STR_SPRITE_ALIGNER_SPRITE_TOOLTIP),
00849 EndContainer(),
00850 NWidget(NWID_VERTICAL),
00851 NWidget(NWID_SPACER), SetFill(1, 1),
00852 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_RIGHT), SetDataTip(SPR_ARROW_RIGHT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00853 NWidget(NWID_SPACER), SetFill(1, 1),
00854 EndContainer(),
00855 EndContainer(),
00856 NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
00857 NWidget(NWID_SPACER), SetFill(1, 1),
00858 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00859 NWidget(NWID_SPACER), SetFill(1, 1),
00860 EndContainer(),
00861 NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
00862 NWidget(WWT_LABEL, COLOUR_GREY, WID_SA_OFFSETS), SetDataTip(STR_SPRITE_ALIGNER_OFFSETS, STR_NULL), SetFill(1, 0),
00863 EndContainer(),
00864 EndContainer(),
00865 NWidget(NWID_VERTICAL), SetPIP(10, 5, 10),
00866 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_PICKER), SetDataTip(STR_SPRITE_ALIGNER_PICKER_BUTTON, STR_SPRITE_ALIGNER_PICKER_TOOLTIP), SetFill(1, 0),
00867 NWidget(NWID_HORIZONTAL),
00868 NWidget(WWT_MATRIX, COLOUR_GREY, WID_SA_LIST), SetResize(1, 1), SetDataTip(0x101, STR_NULL), SetFill(1, 1), SetScrollbar(WID_SA_SCROLLBAR),
00869 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SA_SCROLLBAR),
00870 EndContainer(),
00871 EndContainer(),
00872 EndContainer(),
00873 EndContainer(),
00874 };
00875
00876 static WindowDesc _sprite_aligner_desc(
00877 WDP_AUTO, "sprite_aligner", 400, 300,
00878 WC_SPRITE_ALIGNER, WC_NONE,
00879 0,
00880 _nested_sprite_aligner_widgets, lengthof(_nested_sprite_aligner_widgets)
00881 );
00882
00886 void ShowSpriteAlignerWindow()
00887 {
00888 AllocateWindowDescFront<SpriteAlignerWindow>(&_sprite_aligner_desc, 0);
00889 }