newgrf_debug_gui.cpp

Go to the documentation of this file.
00001 /* $Id: newgrf_debug_gui.cpp 21331 2010-11-26 15:22:18Z alberth $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
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 
00038 NewGrfDebugSpritePicker _newgrf_debug_sprite_picker = { SPM_NONE, NULL, 0, SmallVector<SpriteID, 256>() };
00039 
00045 static inline uint GetFeatureIndex(uint window_number)
00046 {
00047   return GB(window_number, 0, 24);
00048 }
00049 
00057 static inline uint GetInspectWindowNumber(GrfSpecFeature feature, uint index)
00058 {
00059   assert((index >> 24) == 0);
00060   return (feature << 24) | index;
00061 }
00062 
00067 enum NIType {
00068   NIT_INT,   
00069   NIT_CARGO, 
00070 };
00071 
00073 struct NIProperty {
00074   const char *name;       
00075   ptrdiff_t offset;       
00076   byte read_size;         
00077   byte prop;              
00078   byte type;
00079 };
00080 
00081 
00086 struct NICallback {
00087   const char *name; 
00088   ptrdiff_t offset; 
00089   byte read_size;   
00090   byte cb_bit;      
00091   uint16 cb_id;     
00092 };
00094 static const int CBM_NO_BIT = UINT8_MAX;
00095 
00097 struct NIVariable {
00098   const char *name;
00099   byte var;
00100 };
00101 
00103 class NIHelper {
00104 public:
00106   virtual ~NIHelper() {}
00107 
00113   virtual bool IsInspectable(uint index) const = 0;
00114 
00120   virtual uint GetParent(uint index) const = 0;
00121 
00127   virtual const void *GetInstance(uint index) const = 0;
00128 
00134   virtual const void *GetSpec(uint index) const = 0;
00135 
00140   virtual void SetStringParameters(uint index) const = 0;
00141 
00150   virtual uint Resolve(uint index, uint var, uint param, bool *avail) const
00151   {
00152     ResolverObject ro;
00153     memset(&ro, 0, sizeof(ro));
00154     this->Resolve(&ro, index);
00155     return ro.GetVariable(&ro, var, param, avail);
00156   }
00157 
00158 protected:
00165   virtual void Resolve(ResolverObject *ro, uint index) const {}
00166 
00172   void SetSimpleStringParameters(StringID string, uint32 index) const
00173   {
00174     SetDParam(0, string);
00175     SetDParam(1, index);
00176   }
00177 
00178 
00185   void SetObjectAtStringParameters(StringID string, uint32 index, TileIndex tile) const
00186   {
00187     SetDParam(0, STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT);
00188     SetDParam(1, string);
00189     SetDParam(2, index);
00190     SetDParam(3, tile);
00191   }
00192 };
00193 
00194 
00196 struct NIFeature {
00197   const NIProperty *properties; 
00198   const NICallback *callbacks;  
00199   const NIVariable *variables;  
00200   const NIHelper   *helper;     
00201   uint psa_size;                
00202   size_t psa_offset;            
00203 };
00204 
00205 /* Load all the NewGRF debug data; externalised as it is just a huge bunch of tables. */
00206 #include "table/newgrf_debug_data.h"
00207 
00213 static inline GrfSpecFeature GetFeatureNum(uint window_number)
00214 {
00215   return (GrfSpecFeature)GB(window_number, 24, 8);
00216 }
00217 
00223 static inline const NIFeature *GetFeature(uint window_number)
00224 {
00225   GrfSpecFeature idx = GetFeatureNum(window_number);
00226   return idx < GSF_FAKE_END ? _nifeatures[idx] : NULL;
00227 }
00228 
00235 static inline const NIHelper *GetFeatureHelper(uint window_number)
00236 {
00237   return GetFeature(window_number)->helper;
00238 }
00239 
00240 
00242 enum NewGRFInspectWidgets {
00243   NIW_CAPTION,   
00244   NIW_PARENT,    
00245   NIW_MAINPANEL, 
00246   NIW_SCROLLBAR, 
00247 };
00248 
00250 struct NewGRFInspectWindow : Window {
00251   static const int LEFT_OFFSET   = 5; 
00252   static const int RIGHT_OFFSET  = 5; 
00253   static const int TOP_OFFSET    = 5; 
00254   static const int BOTTOM_OFFSET = 5; 
00255 
00257   static byte var60params[GSF_FAKE_END][0x20];
00258 
00260   byte current_edit_param;
00261 
00262   Scrollbar *vscroll;
00263 
00269   static bool HasVariableParameter(uint variable)
00270   {
00271     return IsInsideBS(variable, 0x60, 0x20);
00272   }
00273 
00274   NewGRFInspectWindow(const WindowDesc *desc, WindowNumber wno) : Window()
00275   {
00276     this->CreateNestedTree(desc);
00277     this->vscroll = this->GetScrollbar(NIW_SCROLLBAR);
00278     this->FinishInitNested(desc, wno);
00279 
00280     this->vscroll->SetCount(0);
00281     this->SetWidgetDisabledState(NIW_PARENT, GetFeatureHelper(this->window_number)->GetParent(GetFeatureIndex(this->window_number)) == UINT32_MAX);
00282   }
00283 
00284   virtual void SetStringParameters(int widget) const
00285   {
00286     if (widget != NIW_CAPTION) return;
00287 
00288     GetFeatureHelper(this->window_number)->SetStringParameters(GetFeatureIndex(this->window_number));
00289   }
00290 
00291   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00292   {
00293     if (widget != NIW_MAINPANEL) return;
00294 
00295     resize->height = max(11, FONT_HEIGHT_NORMAL + 1);
00296     resize->width  = 1;
00297 
00298     size->height = 5 * resize->height + TOP_OFFSET + BOTTOM_OFFSET;
00299   }
00300 
00307   void WARN_FORMAT(4, 5) DrawString(const Rect &r, int offset, const char *format, ...) const
00308   {
00309     char buf[1024];
00310 
00311     va_list va;
00312     va_start(va, format);
00313     vsnprintf(buf, lengthof(buf), format, va);
00314     va_end(va);
00315 
00316     offset -= this->vscroll->GetPosition();
00317     if (offset < 0 || offset >= this->vscroll->GetCapacity()) return;
00318 
00319 		::DrawString(r.left + LEFT_OFFSET, r.right + RIGHT_OFFSET, r.top + TOP_OFFSET + (offset * this->resize.step_height), buf, TC_BLACK);
00320   }
00321 
00322   virtual void DrawWidget(const Rect &r, int widget) const
00323   {
00324     if (widget != NIW_MAINPANEL) return;
00325 
00326     uint index = GetFeatureIndex(this->window_number);
00327     const NIFeature *nif  = GetFeature(this->window_number);
00328     const NIHelper *nih   = nif->helper;
00329     const void *base      = nih->GetInstance(index);
00330     const void *base_spec = nih->GetSpec(index);
00331 
00332     uint i = 0;
00333     if (nif->variables != NULL) {
00334       this->DrawString(r, i++, "Variables:");
00335       for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++) {
00336         bool avail = true;
00337         uint param = HasVariableParameter(niv->var) ? NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][niv->var - 0x60] : 0;
00338         uint value = nih->Resolve(index, niv->var, param, &avail);
00339 
00340         if (!avail) continue;
00341 
00342         if (HasVariableParameter(niv->var)) {
00343           this->DrawString(r, i++, "  %02x[%02x]: %08x (%s)", niv->var, param, value, niv->name);
00344         } else {
00345           this->DrawString(r, i++, "  %02x: %08x (%s)", niv->var, value, niv->name);
00346         }
00347       }
00348     }
00349 
00350     if (nif->psa_size != 0) {
00351       this->DrawString(r, i++, "Persistent storage:");
00352       assert(nif->psa_size % 4 == 0);
00353       int32 *psa = (int32*)((byte*)base + nif->psa_offset);
00354       for (uint j = 0; j < nif->psa_size; j += 4, psa += 4) {
00355         this->DrawString(r, i++, "  %i: %i %i %i %i", j, psa[0], psa[1], psa[2], psa[3]);
00356       }
00357     }
00358 
00359     if (nif->properties != NULL) {
00360       this->DrawString(r, i++, "Properties:");
00361       for (const NIProperty *nip = nif->properties; nip->name != NULL; nip++) {
00362         void *ptr = (byte*)base + nip->offset;
00363         uint value;
00364         switch (nip->read_size) {
00365           case 1: value = *(uint8  *)ptr; break;
00366           case 2: value = *(uint16 *)ptr; break;
00367           case 4: value = *(uint32 *)ptr; break;
00368           default: NOT_REACHED();
00369         }
00370 
00371         StringID string;
00372         SetDParam(0, value);
00373         switch (nip->type) {
00374           case NIT_INT:
00375             string = STR_JUST_INT;
00376             break;
00377 
00378           case NIT_CARGO:
00379             string = value != INVALID_CARGO ? CargoSpec::Get(value)->name : STR_QUANTITY_N_A;
00380             break;
00381 
00382           default:
00383             NOT_REACHED();
00384         }
00385 
00386         char buffer[64];
00387         GetString(buffer, string, lastof(buffer));
00388         this->DrawString(r, i++, "  %02x: %s (%s)", nip->prop, buffer, nip->name);
00389       }
00390     }
00391 
00392     if (nif->callbacks != NULL) {
00393       this->DrawString(r, i++, "Callbacks:");
00394       for (const NICallback *nic = nif->callbacks; nic->name != NULL; nic++) {
00395         if (nic->cb_bit != CBM_NO_BIT) {
00396           void *ptr = (byte*)base_spec + nic->offset;
00397           uint value;
00398           switch (nic->read_size) {
00399             case 1: value = *(uint8  *)ptr; break;
00400             case 2: value = *(uint16 *)ptr; break;
00401             case 4: value = *(uint32 *)ptr; break;
00402             default: NOT_REACHED();
00403           }
00404 
00405           if (!HasBit(value, nic->cb_bit)) continue;
00406           this->DrawString(r, i++, "  %03x: %s", nic->cb_id, nic->name);
00407         } else {
00408           this->DrawString(r, i++, "  %03x: %s (unmasked)", nic->cb_id, nic->name);
00409         }
00410       }
00411     }
00412 
00413     /* Not nice and certainly a hack, but it beats duplicating
00414      * this whole function just to count the actual number of
00415      * elements. Especially because they need to be redrawn. */
00416     const_cast<NewGRFInspectWindow*>(this)->vscroll->SetCount(i);
00417   }
00418 
00419   virtual void OnClick(Point pt, int widget, int click_count)
00420   {
00421     switch (widget) {
00422       case NIW_PARENT: {
00423         uint index = GetFeatureHelper(this->window_number)->GetParent(GetFeatureIndex(this->window_number));
00424 				::ShowNewGRFInspectWindow((GrfSpecFeature)GB(index, 24, 8), GetFeatureIndex(index));
00425         break;
00426       }
00427 
00428       case NIW_MAINPANEL: {
00429         /* Does this feature have variables? */
00430         const NIFeature *nif  = GetFeature(this->window_number);
00431         if (nif->variables == NULL) return;
00432 
00433         /* Get the line, make sure it's within the boundaries. */
00434         int line = this->vscroll->GetScrolledRowFromWidget(pt.y, this, NIW_MAINPANEL, TOP_OFFSET);
00435         if (line == INT_MAX) return;
00436 
00437         /* Find the variable related to the line */
00438         for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++, line--) {
00439           if (line != 1) continue; // 1 because of the "Variables:" line
00440 
00441           if (!HasVariableParameter(niv->var)) break;
00442 
00443           this->current_edit_param = niv->var;
00444           ShowQueryString(STR_EMPTY, STR_NEWGRF_INSPECT_QUERY_CAPTION, 3, 100, this, CS_HEXADECIMAL, QSF_NONE);
00445         }
00446       }
00447     }
00448   }
00449 
00450   virtual void OnQueryTextFinished(char *str)
00451   {
00452     if (StrEmpty(str)) return;
00453 
00454     NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][this->current_edit_param - 0x60] = strtol(str, NULL, 16);
00455     this->SetDirty();
00456   }
00457 
00458   virtual void OnResize()
00459   {
00460     this->vscroll->SetCapacityFromWidget(this, NIW_MAINPANEL, TOP_OFFSET + BOTTOM_OFFSET);
00461   }
00462 };
00463 
00464 /* static */ byte NewGRFInspectWindow::var60params[GSF_FAKE_END][0x20] = { {0} }; // Use spec to have 0s in whole array
00465 
00466 static const NWidgetPart _nested_newgrf_inspect_widgets[] = {
00467   NWidget(NWID_HORIZONTAL),
00468     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00469     NWidget(WWT_CAPTION, COLOUR_GREY, NIW_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00470     NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, NIW_PARENT), SetDataTip(STR_NEWGRF_INSPECT_PARENT_BUTTON, STR_NEWGRF_INSPECT_PARENT_TOOLTIP),
00471     NWidget(WWT_SHADEBOX, COLOUR_GREY),
00472     NWidget(WWT_STICKYBOX, COLOUR_GREY),
00473   EndContainer(),
00474   NWidget(NWID_HORIZONTAL),
00475     NWidget(WWT_PANEL, COLOUR_GREY, NIW_MAINPANEL), SetMinimalSize(300, 0), SetScrollbar(NIW_SCROLLBAR), EndContainer(),
00476     NWidget(NWID_VERTICAL),
00477       NWidget(NWID_VSCROLLBAR, COLOUR_GREY, NIW_SCROLLBAR),
00478       NWidget(WWT_RESIZEBOX, COLOUR_GREY),
00479     EndContainer(),
00480   EndContainer(),
00481 };
00482 
00483 static const WindowDesc _newgrf_inspect_desc(
00484   WDP_AUTO, 400, 300,
00485   WC_NEWGRF_INSPECT, WC_NONE,
00486   WDF_UNCLICK_BUTTONS,
00487   _nested_newgrf_inspect_widgets, lengthof(_nested_newgrf_inspect_widgets)
00488 );
00489 
00490 void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index)
00491 {
00492   if (!IsNewGRFInspectable(feature, index)) return;
00493 
00494   WindowNumber wno = GetInspectWindowNumber(feature, index);
00495   AllocateWindowDescFront<NewGRFInspectWindow>(&_newgrf_inspect_desc, wno);
00496 }
00497 
00498 void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
00499 {
00500   if (feature == GSF_INVALID) return;
00501 
00502   WindowNumber wno = GetInspectWindowNumber(feature, index);
00503   DeleteWindowById(WC_NEWGRF_INSPECT, wno);
00504 
00505   /* Reinitialise the land information window to remove the "debug" sprite if needed. */
00506   Window *w = FindWindowById(WC_LAND_INFO, 0);
00507   if (w != NULL) w->ReInit();
00508 }
00509 
00510 bool IsNewGRFInspectable(GrfSpecFeature feature, uint index)
00511 {
00512   const NIFeature *nif = GetFeature(GetInspectWindowNumber(feature, index));
00513   if (nif == NULL) return false;
00514   return nif->helper->IsInspectable(index);
00515 }
00516 
00517 GrfSpecFeature GetGrfSpecFeature(TileIndex tile)
00518 {
00519   switch (GetTileType(tile)) {
00520     default:              return GSF_INVALID;
00521     case MP_RAILWAY:      return GSF_RAILTYPES;
00522     case MP_ROAD:         return IsLevelCrossing(tile) ? GSF_RAILTYPES : GSF_INVALID;
00523     case MP_HOUSE:        return GSF_HOUSES;
00524     case MP_INDUSTRY:     return GSF_INDUSTRYTILES;
00525     case MP_OBJECT:       return GSF_OBJECTS;
00526 
00527     case MP_STATION:
00528       switch (GetStationType(tile)) {
00529         case STATION_RAIL:    return GSF_STATIONS;
00530         case STATION_AIRPORT: return GSF_AIRPORTTILES;
00531         default:              return GSF_INVALID;
00532       }
00533   }
00534 }
00535 
00536 GrfSpecFeature GetGrfSpecFeature(VehicleType type)
00537 {
00538   switch (type) {
00539     case VEH_TRAIN:    return GSF_TRAINS;
00540     case VEH_ROAD:     return GSF_ROADVEHICLES;
00541     case VEH_SHIP:     return GSF_SHIPS;
00542     case VEH_AIRCRAFT: return GSF_AIRCRAFT;
00543     default:           return GSF_INVALID;
00544   }
00545 }
00546 
00547 
00548 
00549 /**** Sprite Aligner ****/
00550 
00552 enum SpriteAlignerWidgets {
00553   SAW_CAPTION,  
00554   SAW_PREVIOUS, 
00555   SAW_GOTO,     
00556   SAW_NEXT,     
00557   SAW_UP,       
00558   SAW_LEFT,     
00559   SAW_RIGHT,    
00560   SAW_DOWN,     
00561   SAW_SPRITE,   
00562   SAW_OFFSETS,  
00563   SAW_PICKER,   
00564   SAW_LIST,     
00565   SAW_SCROLLBAR,
00566 };
00567 
00569 struct SpriteAlignerWindow : Window {
00570   SpriteID current_sprite; 
00571   Scrollbar *vscroll;
00572 
00573   SpriteAlignerWindow(const WindowDesc *desc, WindowNumber wno) : Window()
00574   {
00575     this->CreateNestedTree(desc);
00576     this->vscroll = this->GetScrollbar(SAW_SCROLLBAR);
00577     this->FinishInitNested(desc, wno);
00578 
00579     /* Oh yes, we assume there is at least one normal sprite! */
00580     while (GetSpriteType(this->current_sprite) != ST_NORMAL) this->current_sprite++;
00581   }
00582 
00583   virtual void SetStringParameters(int widget) const
00584   {
00585     switch (widget) {
00586       case SAW_CAPTION:
00587         SetDParam(0, this->current_sprite);
00588         SetDParamStr(1, FioGetFilename(GetOriginFileSlot(this->current_sprite)));
00589         break;
00590 
00591       case SAW_OFFSETS: {
00592         const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL);
00593         SetDParam(0, spr->x_offs);
00594         SetDParam(1, spr->y_offs);
00595         break;
00596       }
00597 
00598       default:
00599         break;
00600     }
00601   }
00602 
00603   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00604   {
00605     if (widget != SAW_LIST) return;
00606 
00607     resize->height = max(11, FONT_HEIGHT_NORMAL + 1);
00608     resize->width  = 1;
00609 
00610     /* Resize to about 200 pixels (for the preview) */
00611     size->height = (1 + 200 / resize->height) * resize->height;
00612   }
00613 
00614   virtual void DrawWidget(const Rect &r, int widget) const
00615   {
00616     switch (widget) {
00617       case SAW_SPRITE: {
00618         /* Center the sprite ourselves */
00619         const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL);
00620         int width  = r.right  - r.left + 1;
00621         int height = r.bottom - r.top  + 1;
00622         int x = r.left - spr->x_offs + (width  - spr->width) / 2;
00623         int y = r.top  - spr->y_offs + (height - spr->height) / 2;
00624 
00625         /* And draw only the part within the sprite area */
00626         SubSprite subspr = {
00627           spr->x_offs + (spr->width  - width)  / 2 + 1,
00628           spr->y_offs + (spr->height - height) / 2 + 1,
00629           spr->x_offs + (spr->width  + width)  / 2 - 1,
00630           spr->y_offs + (spr->height + height) / 2 - 1,
00631         };
00632 
00633         DrawSprite(this->current_sprite, PAL_NONE, x, y, &subspr);
00634         break;
00635       }
00636 
00637       case SAW_LIST: {
00638         const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
00639         int step_size = nwid->resize_y;
00640 
00641         SmallVector<SpriteID, 256> &list = _newgrf_debug_sprite_picker.sprites;
00642         int max = min<int>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), list.Length());
00643 
00644         int y = r.top + WD_FRAMERECT_TOP;
00645         for (int i = this->vscroll->GetPosition(); i < max; i++) {
00646           SetDParam(0, list[i]);
00647           DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_BLACK_COMMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE);
00648           y += step_size;
00649         }
00650         break;
00651       }
00652     }
00653   }
00654 
00655   virtual void OnClick(Point pt, int widget, int click_count)
00656   {
00657     switch (widget) {
00658       case SAW_PREVIOUS:
00659         do {
00660           this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() :  this->current_sprite) - 1;
00661         } while (GetSpriteType(this->current_sprite) != ST_NORMAL);
00662         this->SetDirty();
00663         break;
00664 
00665       case SAW_GOTO:
00666         ShowQueryString(STR_EMPTY, STR_SPRITE_ALIGNER_GOTO_CAPTION, 7, 150, this, CS_NUMERAL, QSF_NONE);
00667         break;
00668 
00669       case SAW_NEXT:
00670         do {
00671           this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
00672         } while (GetSpriteType(this->current_sprite) != ST_NORMAL);
00673         this->SetDirty();
00674         break;
00675 
00676       case SAW_PICKER:
00677         this->LowerWidget(SAW_PICKER);
00678         _newgrf_debug_sprite_picker.mode = SPM_WAIT_CLICK;
00679         this->SetDirty();
00680         break;
00681 
00682       case SAW_LIST: {
00683         const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
00684         int step_size = nwid->resize_y;
00685 
00686         uint i = this->vscroll->GetPosition() + (pt.y - nwid->pos_y) / step_size;
00687         if (i < _newgrf_debug_sprite_picker.sprites.Length()) {
00688           SpriteID spr = _newgrf_debug_sprite_picker.sprites[i];
00689           if (GetSpriteType(spr) == ST_NORMAL) this->current_sprite = spr;
00690         }
00691         this->SetDirty();
00692         break;
00693       }
00694 
00695       case SAW_UP:
00696       case SAW_DOWN:
00697       case SAW_LEFT:
00698       case SAW_RIGHT: {
00699         /*
00700          * Yes... this is a hack.
00701          *
00702          * No... I don't think it is useful to make this less of a hack.
00703          *
00704          * If you want to align sprites, you just need the number. Generally
00705          * the sprite caches are big enough to not remove the sprite from the
00706          * cache. If that's not the case, just let the NewGRF developer
00707          * increase the cache size instead of storing thousands of offsets
00708          * for the incredibly small chance that it's actually going to be
00709          * used by someone and the sprite cache isn't big enough for that
00710          * particular NewGRF developer.
00711          */
00712         Sprite *spr = const_cast<Sprite *>(GetSprite(this->current_sprite, ST_NORMAL));
00713         switch (widget) {
00714           case SAW_UP:    spr->y_offs--; break;
00715           case SAW_DOWN:  spr->y_offs++; break;
00716           case SAW_LEFT:  spr->x_offs--; break;
00717           case SAW_RIGHT: spr->x_offs++; break;
00718         }
00719         /* Ofcourse, we need to redraw the sprite, but where is it used?
00720          * Everywhere is a safe bet. */
00721         MarkWholeScreenDirty();
00722         break;
00723       }
00724     }
00725   }
00726 
00727   virtual void OnQueryTextFinished(char *str)
00728   {
00729     if (StrEmpty(str)) return;
00730 
00731     this->current_sprite = atoi(str);
00732     if (this->current_sprite >= GetMaxSpriteID()) this->current_sprite = 0;
00733     while (GetSpriteType(this->current_sprite) != ST_NORMAL) {
00734       this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
00735     }
00736     this->SetDirty();
00737   }
00738 
00739   virtual void OnInvalidateData(int data)
00740   {
00741     if (data == 1) {
00742       /* Sprite picker finished */
00743       this->RaiseWidget(SAW_PICKER);
00744       this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.Length());
00745     }
00746   }
00747 
00748   virtual void OnResize()
00749   {
00750     this->vscroll->SetCapacityFromWidget(this, SAW_LIST);
00751     this->GetWidget<NWidgetCore>(SAW_LIST)->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
00752   }
00753 };
00754 
00755 static const NWidgetPart _nested_sprite_aligner_widgets[] = {
00756   NWidget(NWID_HORIZONTAL),
00757     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00758     NWidget(WWT_CAPTION, COLOUR_GREY, SAW_CAPTION), SetDataTip(STR_SPRITE_ALIGNER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00759     NWidget(WWT_SHADEBOX, COLOUR_GREY),
00760     NWidget(WWT_STICKYBOX, COLOUR_GREY),
00761   EndContainer(),
00762   NWidget(WWT_PANEL, COLOUR_GREY),
00763     NWidget(NWID_HORIZONTAL), SetPIP(0, 0, 10),
00764       NWidget(NWID_VERTICAL), SetPIP(10, 5, 10),
00765         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 5, 10),
00766           NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SAW_PREVIOUS), SetDataTip(STR_SPRITE_ALIGNER_PREVIOUS_BUTTON, STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP), SetFill(1, 0),
00767           NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SAW_GOTO), SetDataTip(STR_SPRITE_ALIGNER_GOTO_BUTTON, STR_SPRITE_ALIGNER_GOTO_TOOLTIP), SetFill(1, 0),
00768           NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SAW_NEXT), SetDataTip(STR_SPRITE_ALIGNER_NEXT_BUTTON, STR_SPRITE_ALIGNER_NEXT_TOOLTIP), SetFill(1, 0),
00769         EndContainer(),
00770         NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
00771           NWidget(NWID_SPACER), SetFill(1, 1),
00772           NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, SAW_UP), SetDataTip(SPR_ARROW_UP, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00773           NWidget(NWID_SPACER), SetFill(1, 1),
00774         EndContainer(),
00775         NWidget(NWID_HORIZONTAL_LTR), SetPIP(10, 5, 10),
00776           NWidget(NWID_VERTICAL),
00777             NWidget(NWID_SPACER), SetFill(1, 1),
00778             NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, SAW_LEFT), SetDataTip(SPR_ARROW_LEFT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00779             NWidget(NWID_SPACER), SetFill(1, 1),
00780           EndContainer(),
00781           NWidget(WWT_PANEL, COLOUR_DARK_BLUE, SAW_SPRITE), SetDataTip(STR_NULL, STR_SPRITE_ALIGNER_SPRITE_TOOLTIP),
00782           EndContainer(),
00783           NWidget(NWID_VERTICAL),
00784             NWidget(NWID_SPACER), SetFill(1, 1),
00785             NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, SAW_RIGHT), SetDataTip(SPR_ARROW_RIGHT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00786             NWidget(NWID_SPACER), SetFill(1, 1),
00787           EndContainer(),
00788         EndContainer(),
00789         NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
00790           NWidget(NWID_SPACER), SetFill(1, 1),
00791           NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, SAW_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0),
00792           NWidget(NWID_SPACER), SetFill(1, 1),
00793         EndContainer(),
00794         NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10),
00795           NWidget(WWT_LABEL, COLOUR_GREY, SAW_OFFSETS), SetDataTip(STR_SPRITE_ALIGNER_OFFSETS, STR_NULL), SetFill(1, 0),
00796         EndContainer(),
00797       EndContainer(),
00798       NWidget(NWID_VERTICAL), SetPIP(10, 5, 10),
00799         NWidget(WWT_TEXTBTN, COLOUR_GREY, SAW_PICKER), SetDataTip(STR_SPRITE_ALIGNER_PICKER_BUTTON, STR_SPRITE_ALIGNER_PICKER_TOOLTIP), SetFill(1, 0),
00800         NWidget(NWID_HORIZONTAL),
00801           NWidget(WWT_MATRIX, COLOUR_GREY, SAW_LIST), SetResize(1, 1), SetDataTip(0x101, STR_NULL), SetFill(1, 1), SetScrollbar(SAW_SCROLLBAR),
00802           NWidget(NWID_VSCROLLBAR, COLOUR_GREY, SAW_SCROLLBAR),
00803         EndContainer(),
00804       EndContainer(),
00805     EndContainer(),
00806   EndContainer(),
00807 };
00808 
00809 static const WindowDesc _sprite_aligner_desc(
00810   WDP_AUTO, 400, 300,
00811   WC_SPRITE_ALIGNER, WC_NONE,
00812   WDF_UNCLICK_BUTTONS,
00813   _nested_sprite_aligner_widgets, lengthof(_nested_sprite_aligner_widgets)
00814 );
00815 
00816 void ShowSpriteAlignerWindow()
00817 {
00818   AllocateWindowDescFront<SpriteAlignerWindow>(&_sprite_aligner_desc, 0);
00819 }

Generated on Thu Jan 20 22:57:37 2011 for OpenTTD by  doxygen 1.6.1