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 "table/strings.h"
00037
00039 NewGrfDebugSpritePicker _newgrf_debug_sprite_picker = { SPM_NONE, NULL, 0, SmallVector<SpriteID, 256>() };
00040
00046 static inline uint GetFeatureIndex(uint window_number)
00047 {
00048 return GB(window_number, 0, 24);
00049 }
00050
00058 static inline uint GetInspectWindowNumber(GrfSpecFeature feature, uint index)
00059 {
00060 assert((index >> 24) == 0);
00061 return (feature << 24) | index;
00062 }
00063
00068 enum NIType {
00069 NIT_INT,
00070 NIT_CARGO,
00071 };
00072
00074 struct NIProperty {
00075 const char *name;
00076 ptrdiff_t offset;
00077 byte read_size;
00078 byte prop;
00079 byte type;
00080 };
00081
00082
00087 struct NICallback {
00088 const char *name;
00089 ptrdiff_t offset;
00090 byte read_size;
00091 byte cb_bit;
00092 uint16 cb_id;
00093 };
00095 static const int CBM_NO_BIT = UINT8_MAX;
00096
00098 struct NIVariable {
00099 const char *name;
00100 byte var;
00101 };
00102
00104 class NIHelper {
00105 public:
00107 virtual ~NIHelper() {}
00108
00114 virtual bool IsInspectable(uint index) const = 0;
00115
00121 virtual uint GetParent(uint index) const = 0;
00122
00128 virtual const void *GetInstance(uint index) const = 0;
00129
00135 virtual const void *GetSpec(uint index) const = 0;
00136
00141 virtual void SetStringParameters(uint index) const = 0;
00142
00148 virtual uint32 GetGRFID(uint index) const = 0;
00149
00158 virtual uint Resolve(uint index, uint var, uint param, bool *avail) const
00159 {
00160 ResolverObject ro;
00161 memset(&ro, 0, sizeof(ro));
00162 this->Resolve(&ro, index);
00163 return ro.GetVariable(&ro, var, param, avail);
00164 }
00165
00170 virtual bool PSAWithParameter() const
00171 {
00172 return false;
00173 }
00174
00181 virtual uint GetPSASize(uint index, uint32 grfid) const
00182 {
00183 return 0;
00184 }
00185
00192 virtual const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const
00193 {
00194 return NULL;
00195 }
00196
00197 protected:
00204 virtual void Resolve(ResolverObject *ro, uint index) const {}
00205
00211 void SetSimpleStringParameters(StringID string, uint32 index) const
00212 {
00213 SetDParam(0, string);
00214 SetDParam(1, index);
00215 }
00216
00217
00224 void SetObjectAtStringParameters(StringID string, uint32 index, TileIndex tile) const
00225 {
00226 SetDParam(0, STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT);
00227 SetDParam(1, string);
00228 SetDParam(2, index);
00229 SetDParam(3, tile);
00230 }
00231 };
00232
00233
00235 struct NIFeature {
00236 const NIProperty *properties;
00237 const NICallback *callbacks;
00238 const NIVariable *variables;
00239 const NIHelper *helper;
00240 };
00241
00242
00243 #include "table/newgrf_debug_data.h"
00244
00250 static inline GrfSpecFeature GetFeatureNum(uint window_number)
00251 {
00252 return (GrfSpecFeature)GB(window_number, 24, 8);
00253 }
00254
00260 static inline const NIFeature *GetFeature(uint window_number)
00261 {
00262 GrfSpecFeature idx = GetFeatureNum(window_number);
00263 return idx < GSF_FAKE_END ? _nifeatures[idx] : NULL;
00264 }
00265
00272 static inline const NIHelper *GetFeatureHelper(uint window_number)
00273 {
00274 return GetFeature(window_number)->helper;
00275 }
00276
00277
00279 enum NewGRFInspectWidgets {
00280 NIW_CAPTION,
00281 NIW_PARENT,
00282 NIW_MAINPANEL,
00283 NIW_SCROLLBAR,
00284 };
00285
00287 struct NewGRFInspectWindow : Window {
00288 static const int LEFT_OFFSET = 5;
00289 static const int RIGHT_OFFSET = 5;
00290 static const int TOP_OFFSET = 5;
00291 static const int BOTTOM_OFFSET = 5;
00292
00294 static uint32 var60params[GSF_FAKE_END][0x20];
00295
00297 uint32 caller_grfid;
00298
00300 byte current_edit_param;
00301
00302 Scrollbar *vscroll;
00303
00309 static bool HasVariableParameter(uint variable)
00310 {
00311 return IsInsideBS(variable, 0x60, 0x20);
00312 }
00313
00318 void SetCallerGRFID(uint32 grfid)
00319 {
00320 this->caller_grfid = grfid;
00321 this->SetDirty();
00322 }
00323
00324 NewGRFInspectWindow(const WindowDesc *desc, WindowNumber wno) : Window()
00325 {
00326 this->CreateNestedTree(desc);
00327 this->vscroll = this->GetScrollbar(NIW_SCROLLBAR);
00328 this->FinishInitNested(desc, wno);
00329
00330 this->vscroll->SetCount(0);
00331 this->SetWidgetDisabledState(NIW_PARENT, GetFeatureHelper(this->window_number)->GetParent(GetFeatureIndex(this->window_number)) == UINT32_MAX);
00332 }
00333
00334 virtual void SetStringParameters(int widget) const
00335 {
00336 if (widget != NIW_CAPTION) return;
00337
00338 GetFeatureHelper(this->window_number)->SetStringParameters(GetFeatureIndex(this->window_number));
00339 }
00340
00341 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00342 {
00343 if (widget != NIW_MAINPANEL) return;
00344
00345 resize->height = max(11, FONT_HEIGHT_NORMAL + 1);
00346 resize->width = 1;
00347
00348 size->height = 5 * resize->height + TOP_OFFSET + BOTTOM_OFFSET;
00349 }
00350
00357 void WARN_FORMAT(4, 5) DrawString(const Rect &r, int offset, const char *format, ...) const
00358 {
00359 char buf[1024];
00360
00361 va_list va;
00362 va_start(va, format);
00363 vsnprintf(buf, lengthof(buf), format, va);
00364 va_end(va);
00365
00366 offset -= this->vscroll->GetPosition();
00367 if (offset < 0 || offset >= this->vscroll->GetCapacity()) return;
00368
00369 ::DrawString(r.left + LEFT_OFFSET, r.right + RIGHT_OFFSET, r.top + TOP_OFFSET + (offset * this->resize.step_height), buf, TC_BLACK);
00370 }
00371
00372 virtual void DrawWidget(const Rect &r, int widget) const
00373 {
00374 if (widget != NIW_MAINPANEL) return;
00375
00376 uint index = GetFeatureIndex(this->window_number);
00377 const NIFeature *nif = GetFeature(this->window_number);
00378 const NIHelper *nih = nif->helper;
00379 const void *base = nih->GetInstance(index);
00380 const void *base_spec = nih->GetSpec(index);
00381
00382 uint i = 0;
00383 if (nif->variables != NULL) {
00384 this->DrawString(r, i++, "Variables:");
00385 for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++) {
00386 bool avail = true;
00387 uint param = HasVariableParameter(niv->var) ? NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][niv->var - 0x60] : 0;
00388 uint value = nih->Resolve(index, niv->var, param, &avail);
00389
00390 if (!avail) continue;
00391
00392 if (HasVariableParameter(niv->var)) {
00393 this->DrawString(r, i++, " %02x[%02x]: %08x (%s)", niv->var, param, value, niv->name);
00394 } else {
00395 this->DrawString(r, i++, " %02x: %08x (%s)", niv->var, value, niv->name);
00396 }
00397 }
00398 }
00399
00400 uint psa_size = nih->GetPSASize(index, this->caller_grfid);
00401 const int32 *psa = nih->GetPSAFirstPosition(index, this->caller_grfid);
00402 if (psa_size != 0 && psa != NULL) {
00403 if (nih->PSAWithParameter()) {
00404 this->DrawString(r, i++, "Persistent storage [%08X]:", BSWAP32(this->caller_grfid));
00405 } else {
00406 this->DrawString(r, i++, "Persistent storage:");
00407 }
00408 assert(psa_size % 4 == 0);
00409 for (uint j = 0; j < psa_size; j += 4, psa += 4) {
00410 this->DrawString(r, i++, " %i: %i %i %i %i", j, psa[0], psa[1], psa[2], psa[3]);
00411 }
00412 }
00413
00414 if (nif->properties != NULL) {
00415 this->DrawString(r, i++, "Properties:");
00416 for (const NIProperty *nip = nif->properties; nip->name != NULL; nip++) {
00417 const void *ptr = (const byte *)base + nip->offset;
00418 uint value;
00419 switch (nip->read_size) {
00420 case 1: value = *(const uint8 *)ptr; break;
00421 case 2: value = *(const uint16 *)ptr; break;
00422 case 4: value = *(const uint32 *)ptr; break;
00423 default: NOT_REACHED();
00424 }
00425
00426 StringID string;
00427 SetDParam(0, value);
00428 switch (nip->type) {
00429 case NIT_INT:
00430 string = STR_JUST_INT;
00431 break;
00432
00433 case NIT_CARGO:
00434 string = value != INVALID_CARGO ? CargoSpec::Get(value)->name : STR_QUANTITY_N_A;
00435 break;
00436
00437 default:
00438 NOT_REACHED();
00439 }
00440
00441 char buffer[64];
00442 GetString(buffer, string, lastof(buffer));
00443 this->DrawString(r, i++, " %02x: %s (%s)", nip->prop, buffer, nip->name);
00444 }
00445 }
00446
00447 if (nif->callbacks != NULL) {
00448 this->DrawString(r, i++, "Callbacks:");
00449 for (const NICallback *nic = nif->callbacks; nic->name != NULL; nic++) {
00450 if (nic->cb_bit != CBM_NO_BIT) {
00451 const void *ptr = (const byte *)base_spec + nic->offset;
00452 uint value;
00453 switch (nic->read_size) {
00454 case 1: value = *(const uint8 *)ptr; break;
00455 case 2: value = *(const uint16 *)ptr; break;
00456 case 4: value = *(const uint32 *)ptr; break;
00457 default: NOT_REACHED();
00458 }
00459
00460 if (!HasBit(value, nic->cb_bit)) continue;
00461 this->DrawString(r, i++, " %03x: %s", nic->cb_id, nic->name);
00462 } else {
00463 this->DrawString(r, i++, " %03x: %s (unmasked)", nic->cb_id, nic->name);
00464 }
00465 }
00466 }
00467
00468
00469
00470
00471 const_cast<NewGRFInspectWindow*>(this)->vscroll->SetCount(i);
00472 }
00473
00474 virtual void OnClick(Point pt, int widget, int click_count)
00475 {
00476 switch (widget) {
00477 case NIW_PARENT: {
00478 const NIHelper *nih = GetFeatureHelper(this->window_number);
00479 uint index = nih->GetParent(GetFeatureIndex(this->window_number));
00480 ::ShowNewGRFInspectWindow((GrfSpecFeature)GB(index, 24, 8), GetFeatureIndex(index), nih->GetGRFID(GetFeatureIndex(this->window_number)));
00481 break;
00482 }
00483
00484 case NIW_MAINPANEL: {
00485
00486 const NIFeature *nif = GetFeature(this->window_number);
00487 if (nif->variables == NULL) return;
00488
00489
00490 int line = this->vscroll->GetScrolledRowFromWidget(pt.y, this, NIW_MAINPANEL, TOP_OFFSET);
00491 if (line == INT_MAX) return;
00492
00493
00494 for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++, line--) {
00495 if (line != 1) continue;
00496
00497 if (!HasVariableParameter(niv->var)) break;
00498
00499 this->current_edit_param = niv->var;
00500 ShowQueryString(STR_EMPTY, STR_NEWGRF_INSPECT_QUERY_CAPTION, 9, this, CS_HEXADECIMAL, QSF_NONE);
00501 }
00502 }
00503 }
00504 }
00505
00506 virtual void OnQueryTextFinished(char *str)
00507 {
00508 if (StrEmpty(str)) return;
00509
00510 NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][this->current_edit_param - 0x60] = strtol(str, NULL, 16);
00511 this->SetDirty();
00512 }
00513
00514 virtual void OnResize()
00515 {
00516 this->vscroll->SetCapacityFromWidget(this, NIW_MAINPANEL, TOP_OFFSET + BOTTOM_OFFSET);
00517 }
00518 };
00519
00520 uint32 NewGRFInspectWindow::var60params[GSF_FAKE_END][0x20] = { {0} };
00521
00522 static const NWidgetPart _nested_newgrf_inspect_widgets[] = {
00523 NWidget(NWID_HORIZONTAL),
00524 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00525 NWidget(WWT_CAPTION, COLOUR_GREY, NIW_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00526 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, NIW_PARENT), SetDataTip(STR_NEWGRF_INSPECT_PARENT_BUTTON, STR_NEWGRF_INSPECT_PARENT_TOOLTIP),
00527 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00528 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00529 EndContainer(),
00530 NWidget(NWID_HORIZONTAL),
00531 NWidget(WWT_PANEL, COLOUR_GREY, NIW_MAINPANEL), SetMinimalSize(300, 0), SetScrollbar(NIW_SCROLLBAR), EndContainer(),
00532 NWidget(NWID_VERTICAL),
00533 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, NIW_SCROLLBAR),
00534 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
00535 EndContainer(),
00536 EndContainer(),
00537 };
00538
00539 static const WindowDesc _newgrf_inspect_desc(
00540 WDP_AUTO, 400, 300,
00541 WC_NEWGRF_INSPECT, WC_NONE,
00542 WDF_UNCLICK_BUTTONS,
00543 _nested_newgrf_inspect_widgets, lengthof(_nested_newgrf_inspect_widgets)
00544 );
00545
00555 void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index, const uint32 grfid)
00556 {
00557 if (!IsNewGRFInspectable(feature, index)) return;
00558
00559 WindowNumber wno = GetInspectWindowNumber(feature, index);
00560 NewGRFInspectWindow *w = AllocateWindowDescFront<NewGRFInspectWindow>(&_newgrf_inspect_desc, wno);
00561 if (w == NULL) w = (NewGRFInspectWindow *)FindWindowById(WC_NEWGRF_INSPECT, wno);
00562 w->SetCallerGRFID(grfid);
00563 }
00564
00573 void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
00574 {
00575 if (feature == GSF_INVALID) return;
00576
00577 WindowNumber wno = GetInspectWindowNumber(feature, index);
00578 DeleteWindowById(WC_NEWGRF_INSPECT, wno);
00579
00580
00581
00582
00583 InvalidateWindowData(WC_LAND_INFO, 0, 1);
00584 }
00585
00595 bool IsNewGRFInspectable(GrfSpecFeature feature, uint index)
00596 {
00597 const NIFeature *nif = GetFeature(GetInspectWindowNumber(feature, index));
00598 if (nif == NULL) return false;
00599 return nif->helper->IsInspectable(index);
00600 }
00601
00607 GrfSpecFeature GetGrfSpecFeature(TileIndex tile)
00608 {
00609 switch (GetTileType(tile)) {
00610 default: return GSF_INVALID;
00611 case MP_RAILWAY: return GSF_RAILTYPES;
00612 case MP_ROAD: return IsLevelCrossing(tile) ? GSF_RAILTYPES : GSF_INVALID;
00613 case MP_HOUSE: return GSF_HOUSES;
00614 case MP_INDUSTRY: return GSF_INDUSTRYTILES;
00615 case MP_OBJECT: return GSF_OBJECTS;
00616
00617 case MP_STATION:
00618 switch (GetStationType(tile)) {
00619 case STATION_RAIL: return GSF_STATIONS;
00620 case STATION_AIRPORT: return GSF_AIRPORTTILES;
00621 default: return GSF_INVALID;
00622 }
00623 }
00624 }
00625
00631 GrfSpecFeature GetGrfSpecFeature(VehicleType type)
00632 {
00633 switch (type) {
00634 case VEH_TRAIN: return GSF_TRAINS;
00635 case VEH_ROAD: return GSF_ROADVEHICLES;
00636 case VEH_SHIP: return GSF_SHIPS;
00637 case VEH_AIRCRAFT: return GSF_AIRCRAFT;
00638 default: return GSF_INVALID;
00639 }
00640 }
00641
00642
00643
00644
00645
00647 enum SpriteAlignerWidgets {
00648 SAW_CAPTION,
00649 SAW_PREVIOUS,
00650 SAW_GOTO,
00651 SAW_NEXT,
00652 SAW_UP,
00653 SAW_LEFT,
00654 SAW_RIGHT,
00655 SAW_DOWN,
00656 SAW_SPRITE,
00657 SAW_OFFSETS,
00658 SAW_PICKER,
00659 SAW_LIST,
00660 SAW_SCROLLBAR,
00661 };
00662
00664 struct SpriteAlignerWindow : Window {
00665 SpriteID current_sprite;
00666 Scrollbar *vscroll;
00667
00668 SpriteAlignerWindow(const WindowDesc *desc, WindowNumber wno) : Window()
00669 {
00670 this->CreateNestedTree(desc);
00671 this->vscroll = this->GetScrollbar(SAW_SCROLLBAR);
00672 this->FinishInitNested(desc, wno);
00673
00674
00675 while (GetSpriteType(this->current_sprite) != ST_NORMAL) this->current_sprite++;
00676 }
00677
00678 virtual void SetStringParameters(int widget) const
00679 {
00680 switch (widget) {
00681 case SAW_CAPTION:
00682 SetDParam(0, this->current_sprite);
00683 SetDParamStr(1, FioGetFilename(GetOriginFileSlot(this->current_sprite)));
00684 break;
00685
00686 case SAW_OFFSETS: {
00687 const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL);
00688 SetDParam(0, spr->x_offs / ZOOM_LVL_BASE);
00689 SetDParam(1, spr->y_offs / ZOOM_LVL_BASE);
00690 break;
00691 }
00692
00693 default:
00694 break;
00695 }
00696 }
00697
00698 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00699 {
00700 if (widget != SAW_LIST) return;
00701
00702 resize->height = max(11, FONT_HEIGHT_NORMAL + 1);
00703 resize->width = 1;
00704
00705
00706 size->height = (1 + 200 / resize->height) * resize->height;
00707 }
00708
00709 virtual void DrawWidget(const Rect &r, int widget) const
00710 {
00711 switch (widget) {
00712 case SAW_SPRITE: {
00713
00714 const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL);
00715 int width = r.right - r.left + 1;
00716 int height = r.bottom - r.top + 1;
00717 int x = r.left - spr->x_offs / ZOOM_LVL_BASE + (width - spr->width / ZOOM_LVL_BASE) / 2;
00718 int y = r.top - spr->y_offs / ZOOM_LVL_BASE + (height - spr->height / ZOOM_LVL_BASE) / 2;
00719
00720
00721 SubSprite subspr = {
00722 spr->x_offs + (spr->width - width * ZOOM_LVL_BASE) / 2 + 1,
00723 spr->y_offs + (spr->height - height * ZOOM_LVL_BASE) / 2 + 1,
00724 spr->x_offs + (spr->width + width * ZOOM_LVL_BASE) / 2 - 1,
00725 spr->y_offs + (spr->height + height * ZOOM_LVL_BASE) / 2 - 1,
00726 };
00727
00728 DrawSprite(this->current_sprite, PAL_NONE, x, y, &subspr, ZOOM_LVL_GUI);
00729 break;
00730 }
00731
00732 case SAW_LIST: {
00733 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
00734 int step_size = nwid->resize_y;
00735
00736 SmallVector<SpriteID, 256> &list = _newgrf_debug_sprite_picker.sprites;
00737 int max = min<int>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), list.Length());
00738
00739 int y = r.top + WD_FRAMERECT_TOP;
00740 for (int i = this->vscroll->GetPosition(); i < max; i++) {
00741 SetDParam(0, list[i]);
00742 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_BLACK_COMMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE);
00743 y += step_size;
00744 }
00745 break;
00746 }
00747 }
00748 }
00749
00750 virtual void OnClick(Point pt, int widget, int click_count)
00751 {
00752 switch (widget) {
00753 case SAW_PREVIOUS:
00754 do {
00755 this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() : this->current_sprite) - 1;
00756 } while (GetSpriteType(this->current_sprite) != ST_NORMAL);
00757 this->SetDirty();
00758 break;
00759
00760 case SAW_GOTO:
00761 ShowQueryString(STR_EMPTY, STR_SPRITE_ALIGNER_GOTO_CAPTION, 7, this, CS_NUMERAL, QSF_NONE);
00762 break;
00763
00764 case SAW_NEXT:
00765 do {
00766 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
00767 } while (GetSpriteType(this->current_sprite) != ST_NORMAL);
00768 this->SetDirty();
00769 break;
00770
00771 case SAW_PICKER:
00772 this->LowerWidget(SAW_PICKER);
00773 _newgrf_debug_sprite_picker.mode = SPM_WAIT_CLICK;
00774 this->SetDirty();
00775 break;
00776
00777 case SAW_LIST: {
00778 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
00779 int step_size = nwid->resize_y;
00780
00781 uint i = this->vscroll->GetPosition() + (pt.y - nwid->pos_y) / step_size;
00782 if (i < _newgrf_debug_sprite_picker.sprites.Length()) {
00783 SpriteID spr = _newgrf_debug_sprite_picker.sprites[i];
00784 if (GetSpriteType(spr) == ST_NORMAL) this->current_sprite = spr;
00785 }
00786 this->SetDirty();
00787 break;
00788 }
00789
00790 case SAW_UP:
00791 case SAW_DOWN:
00792 case SAW_LEFT:
00793 case SAW_RIGHT: {
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807 Sprite *spr = const_cast<Sprite *>(GetSprite(this->current_sprite, ST_NORMAL));
00808 switch (widget) {
00809 case SAW_UP: spr->y_offs -= ZOOM_LVL_BASE; break;
00810 case SAW_DOWN: spr->y_offs += ZOOM_LVL_BASE; break;
00811 case SAW_LEFT: spr->x_offs -= ZOOM_LVL_BASE; break;
00812 case SAW_RIGHT: spr->x_offs += ZOOM_LVL_BASE; break;
00813 }
00814
00815
00816 MarkWholeScreenDirty();
00817 break;
00818 }
00819 }
00820 }
00821
00822 virtual void OnQueryTextFinished(char *str)
00823 {
00824 if (StrEmpty(str)) return;
00825
00826 this->current_sprite = atoi(str);
00827 if (this->current_sprite >= GetMaxSpriteID()) this->current_sprite = 0;
00828 while (GetSpriteType(this->current_sprite) != ST_NORMAL) {
00829 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
00830 }
00831 this->SetDirty();
00832 }
00833
00839 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
00840 {
00841 if (!gui_scope) return;
00842 if (data == 1) {
00843
00844 this->RaiseWidget(SAW_PICKER);
00845 this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.Length());
00846 }
00847 }
00848
00849 virtual void OnResize()
00850 {
00851 this->vscroll->SetCapacityFromWidget(this, SAW_LIST);
00852 this->GetWidget<NWidgetCore>(SAW_LIST)->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
00853 }
00854 };
00855
00856 static const NWidgetPart _nested_sprite_aligner_widgets[] = {
00857 NWidget(NWID_HORIZONTAL),
00858 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00859 NWidget(WWT_CAPTION, COLOUR_GREY, SAW_CAPTION), SetDataTip(STR_SPRITE_ALIGNER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00860 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00861 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00862 EndContainer(),
00863 NWidget(WWT_PANEL, COLOUR_GREY),
00864 NWidget(NWID_HORIZONTAL), SetPIP(0, 0, 10),
00865 NWidget(NWID_VERTICAL), SetPIP(10, 5, 10),
00866 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 5, 10),
00867 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SAW_PREVIOUS), SetDataTip(STR_SPRITE_ALIGNER_PREVIOUS_BUTTON, STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP), SetFill(1, 0),
00868 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SAW_GOTO), SetDataTip(STR_SPRITE_ALIGNER_GOTO_BUTTON, STR_SPRITE_ALIGNER_GOTO_TOOLTIP), SetFill(1, 0),
00869 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SAW_NEXT), SetDataTip(STR_SPRITE_ALIGNER_NEXT_BUTTON, STR_SPRITE_ALIGNER_NEXT_TOOLTIP), SetFill(1, 0),
00870 EndContainer(),
00871 NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
00872 NWidget(NWID_SPACER), SetFill(1, 1),
00873 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, SAW_UP), SetDataTip(SPR_ARROW_UP, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00874 NWidget(NWID_SPACER), SetFill(1, 1),
00875 EndContainer(),
00876 NWidget(NWID_HORIZONTAL_LTR), SetPIP(10, 5, 10),
00877 NWidget(NWID_VERTICAL),
00878 NWidget(NWID_SPACER), SetFill(1, 1),
00879 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, SAW_LEFT), SetDataTip(SPR_ARROW_LEFT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00880 NWidget(NWID_SPACER), SetFill(1, 1),
00881 EndContainer(),
00882 NWidget(WWT_PANEL, COLOUR_DARK_BLUE, SAW_SPRITE), SetDataTip(STR_NULL, STR_SPRITE_ALIGNER_SPRITE_TOOLTIP),
00883 EndContainer(),
00884 NWidget(NWID_VERTICAL),
00885 NWidget(NWID_SPACER), SetFill(1, 1),
00886 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, SAW_RIGHT), SetDataTip(SPR_ARROW_RIGHT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00887 NWidget(NWID_SPACER), SetFill(1, 1),
00888 EndContainer(),
00889 EndContainer(),
00890 NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
00891 NWidget(NWID_SPACER), SetFill(1, 1),
00892 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, SAW_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00893 NWidget(NWID_SPACER), SetFill(1, 1),
00894 EndContainer(),
00895 NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
00896 NWidget(WWT_LABEL, COLOUR_GREY, SAW_OFFSETS), SetDataTip(STR_SPRITE_ALIGNER_OFFSETS, STR_NULL), SetFill(1, 0),
00897 EndContainer(),
00898 EndContainer(),
00899 NWidget(NWID_VERTICAL), SetPIP(10, 5, 10),
00900 NWidget(WWT_TEXTBTN, COLOUR_GREY, SAW_PICKER), SetDataTip(STR_SPRITE_ALIGNER_PICKER_BUTTON, STR_SPRITE_ALIGNER_PICKER_TOOLTIP), SetFill(1, 0),
00901 NWidget(NWID_HORIZONTAL),
00902 NWidget(WWT_MATRIX, COLOUR_GREY, SAW_LIST), SetResize(1, 1), SetDataTip(0x101, STR_NULL), SetFill(1, 1), SetScrollbar(SAW_SCROLLBAR),
00903 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, SAW_SCROLLBAR),
00904 EndContainer(),
00905 EndContainer(),
00906 EndContainer(),
00907 EndContainer(),
00908 };
00909
00910 static const WindowDesc _sprite_aligner_desc(
00911 WDP_AUTO, 400, 300,
00912 WC_SPRITE_ALIGNER, WC_NONE,
00913 WDF_UNCLICK_BUTTONS,
00914 _nested_sprite_aligner_widgets, lengthof(_nested_sprite_aligner_widgets)
00915 );
00916
00920 void ShowSpriteAlignerWindow()
00921 {
00922 AllocateWindowDescFront<SpriteAlignerWindow>(&_sprite_aligner_desc, 0);
00923 }