newgrf_debug_gui.cpp

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

Generated on Mon May 9 05:18:56 2011 for OpenTTD by  doxygen 1.6.1