2010-04-24 13:36:29 +00:00
/*
* This file is part of OpenTTD .
* 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.
* 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 .
* 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/>.
*/
/** @file newgrf_debug_gui.cpp GUIs for debugging NewGRFs. */
# include "stdafx.h"
# include <stdarg.h>
# include "window_gui.h"
# include "window_func.h"
2010-04-25 16:27:30 +00:00
# include "fileio_func.h"
# include "spritecache.h"
2010-04-24 13:36:29 +00:00
# include "string_func.h"
# include "strings_func.h"
# include "textbuf_gui.h"
2013-11-07 18:17:21 +00:00
# include "vehicle_gui.h"
2014-09-30 11:29:23 +00:00
# include "zoom_func.h"
2010-04-24 13:36:29 +00:00
# include "engine_base.h"
# include "industry.h"
2010-08-28 19:48:46 +00:00
# include "object_base.h"
2010-04-24 13:36:29 +00:00
# include "station_base.h"
# include "town.h"
# include "vehicle_base.h"
2013-11-07 18:17:21 +00:00
# include "train.h"
# include "roadveh.h"
2010-04-24 13:36:29 +00:00
# include "newgrf_airporttiles.h"
# include "newgrf_debug.h"
2010-08-28 19:48:46 +00:00
# include "newgrf_object.h"
2010-04-24 13:36:29 +00:00
# include "newgrf_spritegroup.h"
# include "newgrf_station.h"
# include "newgrf_town.h"
2012-11-10 20:41:45 +00:00
# include "newgrf_railtype.h"
2012-11-10 20:44:10 +00:00
# include "newgrf_industries.h"
2012-11-10 20:44:38 +00:00
# include "newgrf_industrytiles.h"
2010-04-24 13:36:29 +00:00
2011-12-15 22:22:55 +00:00
# include "widgets/newgrf_debug_widget.h"
2010-04-24 13:36:29 +00:00
# include "table/strings.h"
2014-04-23 20:13:33 +00:00
# include "safeguards.h"
2011-05-02 16:14:23 +00:00
/** The sprite picker. */
2021-02-26 13:00:53 +00:00
NewGrfDebugSpritePicker _newgrf_debug_sprite_picker = { SPM_NONE , nullptr , std : : vector < SpriteID > ( ) } ;
2010-04-26 20:35:27 +00:00
2010-04-24 13:36:29 +00:00
/**
* Get the feature index related to the window number .
* @ param window_number The window to get the feature index from .
* @ return the feature index
*/
static inline uint GetFeatureIndex ( uint window_number )
{
return GB ( window_number , 0 , 24 ) ;
}
/**
* Get the window number for the inspect window given a
* feature and index .
* @ param feature The feature we want to inspect .
* @ param index The index / identifier of the feature to inspect .
* @ return the InspectWindow ( Window ) Number
*/
static inline uint GetInspectWindowNumber ( GrfSpecFeature feature , uint index )
{
assert ( ( index > > 24 ) = = 0 ) ;
return ( feature < < 24 ) | index ;
}
/**
* The type of a property to show . This is used to
2013-01-08 22:46:42 +00:00
* provide an appropriate representation in the GUI .
2010-04-24 13:36:29 +00:00
*/
enum NIType {
NIT_INT , ///< The property is a simple integer
NIT_CARGO , ///< The property is a cargo
} ;
2020-12-13 23:22:04 +00:00
typedef const void * NIOffsetProc ( const void * b ) ;
2010-04-24 13:36:29 +00:00
/** Representation of the data from a NewGRF property. */
struct NIProperty {
2020-12-13 23:22:04 +00:00
const char * name ; ///< A (human readable) name for the property
NIOffsetProc * offset_proc ; ///< Callback proc to get the actual variable address in memory
byte read_size ; ///< Number of bytes (i.e. byte, word, dword etc)
byte prop ; ///< The number of the property
2010-04-24 13:36:29 +00:00
byte type ;
} ;
/**
* Representation of the available callbacks with
* information on when they actually apply .
*/
struct NICallback {
2020-12-13 23:22:04 +00:00
const char * name ; ///< The human readable name of the callback
NIOffsetProc * offset_proc ; ///< Callback proc to get the actual variable address in memory
byte read_size ; ///< The number of bytes (i.e. byte, word, dword etc) to read
byte cb_bit ; ///< The bit that needs to be set for this callback to be enabled
uint16 cb_id ; ///< The number of the callback
2010-04-24 13:36:29 +00:00
} ;
/** Mask to show no bit needs to be enabled for the callback. */
static const int CBM_NO_BIT = UINT8_MAX ;
/** Representation on the NewGRF variables. */
struct NIVariable {
const char * name ;
byte var ;
} ;
/** Helper class to wrap some functionality/queries in. */
class NIHelper {
public :
2010-06-23 14:38:17 +00:00
/** Silence a warning. */
virtual ~ NIHelper ( ) { }
2010-04-24 13:36:29 +00:00
/**
* Is the item with the given index inspectable ?
* @ param index the index to check .
* @ return true iff the index is inspectable .
*/
virtual bool IsInspectable ( uint index ) const = 0 ;
/**
* Get the parent " window_number " of a given instance .
* @ param index the instance to get the parent for .
* @ return the parent ' s window_number or UINT32_MAX if there is none .
*/
virtual uint GetParent ( uint index ) const = 0 ;
/**
* Get the instance given an index .
* @ param index the index to get the instance for .
* @ return the instance .
*/
virtual const void * GetInstance ( uint index ) const = 0 ;
/**
* Get ( NewGRF ) specs given an index .
* @ param index the index to get the specs for for .
* @ return the specs .
*/
virtual const void * GetSpec ( uint index ) const = 0 ;
/**
* Set the string parameters to write the right data for a STRINGn .
* @ param index the index to get the string parameters for .
*/
virtual void SetStringParameters ( uint index ) const = 0 ;
2011-06-12 20:51:38 +00:00
/**
* Get the GRFID of the file that includes this item .
* @ param index index to check .
* @ return GRFID of the item . 0 means that the item is not inspectable .
*/
virtual uint32 GetGRFID ( uint index ) const = 0 ;
2010-04-24 13:36:29 +00:00
/**
* Resolve ( action2 ) variable for a given index .
* @ param index The ( instance ) index to resolve the variable for .
* @ param var The variable to actually resolve .
* @ param param The varaction2 0x60 + x parameter to pass .
* @ param avail Return whether the variable is available .
* @ return The resolved variable ' s value .
*/
2012-11-10 20:45:59 +00:00
virtual uint Resolve ( uint index , uint var , uint param , bool * avail ) const = 0 ;
2010-04-24 13:36:29 +00:00
2011-06-12 20:53:16 +00:00
/**
* Used to decide if the PSA needs a parameter or not .
* @ return True iff this item has a PSA that requires a parameter .
*/
virtual bool PSAWithParameter ( ) const
{
return false ;
}
2011-06-12 20:41:17 +00:00
/**
* Allows to know the size of the persistent storage .
2011-06-12 20:47:45 +00:00
* @ param index Index of the item .
2011-06-12 20:53:16 +00:00
* @ param grfid Parameter for the PSA . Only required for items with parameters .
2011-06-12 20:41:17 +00:00
* @ return Size of the persistent storage in indices .
*/
virtual uint GetPSASize ( uint index , uint32 grfid ) const
{
return 0 ;
}
/**
* Gets the first position of the array containing the persistent storage .
2011-06-12 20:47:45 +00:00
* @ param index Index of the item .
2011-06-12 20:53:16 +00:00
* @ param grfid Parameter for the PSA . Only required for items with parameters .
2019-04-10 21:07:06 +00:00
* @ return Pointer to the first position of the storage array or nullptr if not present .
2011-06-12 20:41:17 +00:00
*/
2011-11-12 08:10:22 +00:00
virtual const int32 * GetPSAFirstPosition ( uint index , uint32 grfid ) const
2011-06-12 20:41:17 +00:00
{
2019-04-10 21:07:06 +00:00
return nullptr ;
2011-06-12 20:41:17 +00:00
}
2010-04-24 13:36:29 +00:00
protected :
/**
* Helper to make setting the strings easier .
* @ param string the string to actually draw .
* @ param index the ( instance ) index for the string .
*/
void SetSimpleStringParameters ( StringID string , uint32 index ) const
{
SetDParam ( 0 , string ) ;
SetDParam ( 1 , index ) ;
}
/**
* Helper to make setting the strings easier for objects at a specific tile .
* @ param string the string to draw the object ' s name
* @ param index the ( instance ) index for the string .
* @ param tile the tile the object is at
*/
void SetObjectAtStringParameters ( StringID string , uint32 index , TileIndex tile ) const
{
SetDParam ( 0 , STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT ) ;
SetDParam ( 1 , string ) ;
SetDParam ( 2 , index ) ;
SetDParam ( 3 , tile ) ;
}
} ;
/** Container for all information for a given feature. */
struct NIFeature {
const NIProperty * properties ; ///< The properties associated with this feature.
const NICallback * callbacks ; ///< The callbacks associated with this feature.
const NIVariable * variables ; ///< The variables associated with this feature.
const NIHelper * helper ; ///< The class container all helper functions.
} ;
/* Load all the NewGRF debug data; externalised as it is just a huge bunch of tables. */
# include "table/newgrf_debug_data.h"
2010-10-31 16:16:28 +00:00
/**
* Get the feature number related to the window number .
* @ param window_number The window to get the feature number for .
* @ return The feature number .
*/
static inline GrfSpecFeature GetFeatureNum ( uint window_number )
{
return ( GrfSpecFeature ) GB ( window_number , 24 , 8 ) ;
}
2010-04-24 13:36:29 +00:00
/**
* Get the NIFeature related to the window number .
* @ param window_number The window to get the NIFeature for .
2019-04-10 21:07:06 +00:00
* @ return the NIFeature , or nullptr is there isn ' t one .
2010-04-24 13:36:29 +00:00
*/
static inline const NIFeature * GetFeature ( uint window_number )
{
2010-10-31 16:16:28 +00:00
GrfSpecFeature idx = GetFeatureNum ( window_number ) ;
2019-04-10 21:07:06 +00:00
return idx < GSF_FAKE_END ? _nifeatures [ idx ] : nullptr ;
2010-04-24 13:36:29 +00:00
}
/**
* Get the NIHelper related to the window number .
* @ param window_number The window to get the NIHelper for .
2019-04-10 21:07:06 +00:00
* @ pre GetFeature ( window_number ) ! = nullptr
2010-04-24 13:36:29 +00:00
* @ return the NIHelper
*/
static inline const NIHelper * GetFeatureHelper ( uint window_number )
{
return GetFeature ( window_number ) - > helper ;
}
/** Window used for inspecting NewGRFs. */
struct NewGRFInspectWindow : Window {
static const int LEFT_OFFSET = 5 ; ///< Position of left edge
static const int RIGHT_OFFSET = 5 ; ///< Position of right edge
static const int TOP_OFFSET = 5 ; ///< Position of top edge
static const int BOTTOM_OFFSET = 5 ; ///< Position of bottom edge
/** The value for the variable 60 parameters. */
2011-11-08 17:23:30 +00:00
static uint32 var60params [ GSF_FAKE_END ] [ 0x20 ] ;
2010-04-24 13:36:29 +00:00
2011-06-12 20:51:38 +00:00
/** GRFID of the caller of this window, 0 if it has no caller. */
uint32 caller_grfid ;
2013-11-07 18:17:21 +00:00
/** For ground vehicles: Index in vehicle chain. */
uint chain_index ;
2013-01-08 22:46:42 +00:00
/** The currently edited parameter, to update the right one. */
2010-04-24 13:36:29 +00:00
byte current_edit_param ;
2010-08-12 08:37:01 +00:00
Scrollbar * vscroll ;
2010-04-24 13:36:29 +00:00
/**
* Check whether the given variable has a parameter .
* @ param variable the variable to check .
* @ return true iff the variable has a parameter .
*/
static bool HasVariableParameter ( uint variable )
{
return IsInsideBS ( variable , 0x60 , 0x20 ) ;
}
2011-06-12 20:51:38 +00:00
/**
* Set the GRFID of the item opening this window .
* @ param grfid GRFID of the item opening this window , or 0 if not opened by other window .
*/
void SetCallerGRFID ( uint32 grfid )
{
this - > caller_grfid = grfid ;
this - > SetDirty ( ) ;
}
2013-11-07 18:17:21 +00:00
/**
* Check whether this feature has chain index , i . e . refers to ground vehicles .
*/
bool HasChainIndex ( ) const
{
GrfSpecFeature f = GetFeatureNum ( this - > window_number ) ;
return f = = GSF_TRAINS | | f = = GSF_ROADVEHICLES ;
}
2013-11-07 18:15:32 +00:00
/**
* Get the feature index .
* @ return the feature index
*/
uint GetFeatureIndex ( ) const
{
uint index = : : GetFeatureIndex ( this - > window_number ) ;
2013-11-07 18:17:21 +00:00
if ( this - > chain_index > 0 ) {
assert ( this - > HasChainIndex ( ) ) ;
const Vehicle * v = Vehicle : : Get ( index ) ;
v = v - > Move ( this - > chain_index ) ;
2019-04-10 21:07:06 +00:00
if ( v ! = nullptr ) index = v - > index ;
2013-11-07 18:17:21 +00:00
}
2013-11-07 18:15:32 +00:00
return index ;
}
2013-11-07 18:17:21 +00:00
/**
* Ensure that this - > chain_index is in range .
*/
void ValidateChainIndex ( )
{
if ( this - > chain_index = = 0 ) return ;
assert ( this - > HasChainIndex ( ) ) ;
const Vehicle * v = Vehicle : : Get ( : : GetFeatureIndex ( this - > window_number ) ) ;
v = v - > Move ( this - > chain_index ) ;
2019-04-10 21:07:06 +00:00
if ( v = = nullptr ) this - > chain_index = 0 ;
2013-11-07 18:17:21 +00:00
}
2013-05-26 19:23:42 +00:00
NewGRFInspectWindow ( WindowDesc * desc , WindowNumber wno ) : Window ( desc )
2010-04-24 13:36:29 +00:00
{
2013-05-26 19:23:42 +00:00
this - > CreateNestedTree ( ) ;
2011-12-16 17:15:40 +00:00
this - > vscroll = this - > GetScrollbar ( WID_NGRFI_SCROLLBAR ) ;
2013-05-26 19:23:42 +00:00
this - > FinishInitNested ( wno ) ;
2010-04-24 13:36:29 +00:00
2010-08-12 08:37:01 +00:00
this - > vscroll - > SetCount ( 0 ) ;
2013-11-07 18:15:32 +00:00
this - > SetWidgetDisabledState ( WID_NGRFI_PARENT , GetFeatureHelper ( this - > window_number ) - > GetParent ( this - > GetFeatureIndex ( ) ) = = UINT32_MAX ) ;
2013-11-07 18:17:21 +00:00
this - > OnInvalidateData ( 0 , true ) ;
2010-04-24 13:36:29 +00:00
}
2019-03-04 07:49:37 +00:00
void SetStringParameters ( int widget ) const override
2010-04-24 13:36:29 +00:00
{
2011-12-16 17:15:40 +00:00
if ( widget ! = WID_NGRFI_CAPTION ) return ;
2010-04-24 13:36:29 +00:00
2013-11-07 18:15:32 +00:00
GetFeatureHelper ( this - > window_number ) - > SetStringParameters ( this - > GetFeatureIndex ( ) ) ;
2010-04-24 13:36:29 +00:00
}
2019-03-04 07:49:37 +00:00
void UpdateWidgetSize ( int widget , Dimension * size , const Dimension & padding , Dimension * fill , Dimension * resize ) override
2010-04-24 13:36:29 +00:00
{
2013-11-07 18:17:21 +00:00
switch ( widget ) {
case WID_NGRFI_VEH_CHAIN : {
assert ( this - > HasChainIndex ( ) ) ;
GrfSpecFeature f = GetFeatureNum ( this - > window_number ) ;
2021-01-08 10:16:18 +00:00
size - > height = std : : max ( size - > height , GetVehicleImageCellSize ( ( VehicleType ) ( VEH_TRAIN + ( f - GSF_TRAINS ) ) , EIT_IN_DEPOT ) . height + 2 + WD_BEVEL_TOP + WD_BEVEL_BOTTOM ) ;
2013-11-07 18:17:21 +00:00
break ;
}
2010-04-24 13:36:29 +00:00
2013-11-07 18:17:21 +00:00
case WID_NGRFI_MAINPANEL :
2021-01-08 10:16:18 +00:00
resize - > height = std : : max ( 11 , FONT_HEIGHT_NORMAL + 1 ) ;
2013-11-07 18:17:21 +00:00
resize - > width = 1 ;
2010-04-24 13:36:29 +00:00
2013-11-07 18:17:21 +00:00
size - > height = 5 * resize - > height + TOP_OFFSET + BOTTOM_OFFSET ;
break ;
}
2010-04-24 13:36:29 +00:00
}
/**
* Helper function to draw a string ( line ) in the window .
* @ param r The ( screen ) rectangle we must draw within
* @ param offset The offset ( in lines ) we want to draw for
* @ param format The format string
*/
void WARN_FORMAT ( 4 , 5 ) DrawString ( const Rect & r , int offset , const char * format , . . . ) const
{
char buf [ 1024 ] ;
va_list va ;
va_start ( va , format ) ;
2014-04-24 19:51:45 +00:00
vseprintf ( buf , lastof ( buf ) , format , va ) ;
2010-04-24 13:36:29 +00:00
va_end ( va ) ;
2010-08-12 08:37:01 +00:00
offset - = this - > vscroll - > GetPosition ( ) ;
if ( offset < 0 | | offset > = this - > vscroll - > GetCapacity ( ) ) return ;
2010-04-24 13:36:29 +00:00
2013-11-06 15:10:17 +00:00
: : DrawString ( r . left + LEFT_OFFSET , r . right - RIGHT_OFFSET , r . top + TOP_OFFSET + ( offset * this - > resize . step_height ) , buf , TC_BLACK ) ;
2010-04-24 13:36:29 +00:00
}
2019-03-04 07:49:37 +00:00
void DrawWidget ( const Rect & r , int widget ) const override
2010-04-24 13:36:29 +00:00
{
2013-11-07 18:17:21 +00:00
switch ( widget ) {
case WID_NGRFI_VEH_CHAIN : {
const Vehicle * v = Vehicle : : Get ( this - > GetFeatureIndex ( ) ) ;
int total_width = 0 ;
int sel_start = 0 ;
int sel_end = 0 ;
2019-04-10 21:07:06 +00:00
for ( const Vehicle * u = v - > First ( ) ; u ! = nullptr ; u = u - > Next ( ) ) {
2013-11-07 18:17:21 +00:00
if ( u = = v ) sel_start = total_width ;
switch ( u - > type ) {
case VEH_TRAIN : total_width + = Train : : From ( u ) - > GetDisplayImageWidth ( ) ; break ;
case VEH_ROAD : total_width + = RoadVehicle : : From ( u ) - > GetDisplayImageWidth ( ) ; break ;
default : NOT_REACHED ( ) ;
}
if ( u = = v ) sel_end = total_width ;
}
int width = r . right + 1 - r . left - WD_BEVEL_LEFT - WD_BEVEL_RIGHT ;
int skip = 0 ;
if ( total_width > width ) {
int sel_center = ( sel_start + sel_end ) / 2 ;
2021-01-08 10:16:18 +00:00
if ( sel_center > width / 2 ) skip = std : : min ( total_width - width , sel_center - width / 2 ) ;
2013-11-07 18:17:21 +00:00
}
GrfSpecFeature f = GetFeatureNum ( this - > window_number ) ;
int h = GetVehicleImageCellSize ( ( VehicleType ) ( VEH_TRAIN + ( f - GSF_TRAINS ) ) , EIT_IN_DEPOT ) . height ;
int y = ( r . top + r . bottom - h ) / 2 ;
DrawVehicleImage ( v - > First ( ) , r . left + WD_BEVEL_LEFT , r . right - WD_BEVEL_RIGHT , y + 1 , INVALID_VEHICLE , EIT_IN_DETAILS , skip ) ;
/* Highlight the articulated part (this is different to the whole-vehicle highlighting of DrawVehicleImage */
if ( _current_text_dir = = TD_RTL ) {
DrawFrameRect ( r . right - sel_end + skip , y , r . right - sel_start + skip , y + h , COLOUR_WHITE , FR_BORDERONLY ) ;
} else {
DrawFrameRect ( r . left + sel_start - skip , y , r . left + sel_end - skip , y + h , COLOUR_WHITE , FR_BORDERONLY ) ;
}
break ;
}
}
2011-12-16 17:15:40 +00:00
if ( widget ! = WID_NGRFI_MAINPANEL ) return ;
2010-04-24 13:36:29 +00:00
2013-11-07 18:15:32 +00:00
uint index = this - > GetFeatureIndex ( ) ;
2010-04-24 13:36:29 +00:00
const NIFeature * nif = GetFeature ( this - > window_number ) ;
const NIHelper * nih = nif - > helper ;
const void * base = nih - > GetInstance ( index ) ;
const void * base_spec = nih - > GetSpec ( index ) ;
uint i = 0 ;
2019-04-10 21:07:06 +00:00
if ( nif - > variables ! = nullptr ) {
2010-04-24 13:36:29 +00:00
this - > DrawString ( r , i + + , " Variables: " ) ;
2019-04-10 21:07:06 +00:00
for ( const NIVariable * niv = nif - > variables ; niv - > name ! = nullptr ; niv + + ) {
2010-04-24 13:36:29 +00:00
bool avail = true ;
2010-10-31 16:16:28 +00:00
uint param = HasVariableParameter ( niv - > var ) ? NewGRFInspectWindow : : var60params [ GetFeatureNum ( this - > window_number ) ] [ niv - > var - 0x60 ] : 0 ;
2010-04-24 13:36:29 +00:00
uint value = nih - > Resolve ( index , niv - > var , param , & avail ) ;
if ( ! avail ) continue ;
if ( HasVariableParameter ( niv - > var ) ) {
this - > DrawString ( r , i + + , " %02x[%02x]: %08x (%s) " , niv - > var , param , value , niv - > name ) ;
} else {
this - > DrawString ( r , i + + , " %02x: %08x (%s) " , niv - > var , value , niv - > name ) ;
}
}
}
2011-06-12 20:53:16 +00:00
uint psa_size = nih - > GetPSASize ( index , this - > caller_grfid ) ;
2011-11-12 08:10:22 +00:00
const int32 * psa = nih - > GetPSAFirstPosition ( index , this - > caller_grfid ) ;
2019-04-10 21:07:06 +00:00
if ( psa_size ! = 0 & & psa ! = nullptr ) {
2011-06-12 20:53:16 +00:00
if ( nih - > PSAWithParameter ( ) ) {
this - > DrawString ( r , i + + , " Persistent storage [%08X]: " , BSWAP32 ( this - > caller_grfid ) ) ;
} else {
this - > DrawString ( r , i + + , " Persistent storage: " ) ;
}
2011-06-12 20:41:17 +00:00
assert ( psa_size % 4 = = 0 ) ;
for ( uint j = 0 ; j < psa_size ; j + = 4 , psa + = 4 ) {
2010-04-24 13:36:29 +00:00
this - > DrawString ( r , i + + , " %i: %i %i %i %i " , j , psa [ 0 ] , psa [ 1 ] , psa [ 2 ] , psa [ 3 ] ) ;
}
}
2019-04-10 21:07:06 +00:00
if ( nif - > properties ! = nullptr ) {
2010-04-24 13:36:29 +00:00
this - > DrawString ( r , i + + , " Properties: " ) ;
2019-04-10 21:07:06 +00:00
for ( const NIProperty * nip = nif - > properties ; nip - > name ! = nullptr ; nip + + ) {
2020-12-13 23:22:04 +00:00
const void * ptr = nip - > offset_proc ( base ) ;
2010-04-24 13:36:29 +00:00
uint value ;
switch ( nip - > read_size ) {
2011-11-12 08:10:22 +00:00
case 1 : value = * ( const uint8 * ) ptr ; break ;
case 2 : value = * ( const uint16 * ) ptr ; break ;
case 4 : value = * ( const uint32 * ) ptr ; break ;
2010-04-24 13:36:29 +00:00
default : NOT_REACHED ( ) ;
}
StringID string ;
SetDParam ( 0 , value ) ;
switch ( nip - > type ) {
case NIT_INT :
string = STR_JUST_INT ;
break ;
case NIT_CARGO :
string = value ! = INVALID_CARGO ? CargoSpec : : Get ( value ) - > name : STR_QUANTITY_N_A ;
break ;
default :
NOT_REACHED ( ) ;
}
char buffer [ 64 ] ;
GetString ( buffer , string , lastof ( buffer ) ) ;
this - > DrawString ( r , i + + , " %02x: %s (%s) " , nip - > prop , buffer , nip - > name ) ;
}
}
2019-04-10 21:07:06 +00:00
if ( nif - > callbacks ! = nullptr ) {
2010-04-24 13:36:29 +00:00
this - > DrawString ( r , i + + , " Callbacks: " ) ;
2019-04-10 21:07:06 +00:00
for ( const NICallback * nic = nif - > callbacks ; nic - > name ! = nullptr ; nic + + ) {
2010-04-24 13:36:29 +00:00
if ( nic - > cb_bit ! = CBM_NO_BIT ) {
2020-12-13 23:22:04 +00:00
const void * ptr = nic - > offset_proc ( base_spec ) ;
2010-04-24 13:36:29 +00:00
uint value ;
switch ( nic - > read_size ) {
2011-11-12 08:10:22 +00:00
case 1 : value = * ( const uint8 * ) ptr ; break ;
case 2 : value = * ( const uint16 * ) ptr ; break ;
case 4 : value = * ( const uint32 * ) ptr ; break ;
2010-04-24 13:36:29 +00:00
default : NOT_REACHED ( ) ;
}
if ( ! HasBit ( value , nic - > cb_bit ) ) continue ;
this - > DrawString ( r , i + + , " %03x: %s " , nic - > cb_id , nic - > name ) ;
} else {
this - > DrawString ( r , i + + , " %03x: %s (unmasked) " , nic - > cb_id , nic - > name ) ;
}
}
}
/* Not nice and certainly a hack, but it beats duplicating
* this whole function just to count the actual number of
* elements . Especially because they need to be redrawn . */
2010-08-12 08:37:01 +00:00
const_cast < NewGRFInspectWindow * > ( this ) - > vscroll - > SetCount ( i ) ;
2010-04-24 13:36:29 +00:00
}
2019-03-04 07:49:37 +00:00
void OnClick ( Point pt , int widget , int click_count ) override
2010-04-24 13:36:29 +00:00
{
switch ( widget ) {
2011-12-16 17:15:40 +00:00
case WID_NGRFI_PARENT : {
2011-06-12 20:51:38 +00:00
const NIHelper * nih = GetFeatureHelper ( this - > window_number ) ;
2013-11-07 18:15:32 +00:00
uint index = nih - > GetParent ( this - > GetFeatureIndex ( ) ) ;
2013-11-07 18:17:21 +00:00
: : ShowNewGRFInspectWindow ( GetFeatureNum ( index ) , : : GetFeatureIndex ( index ) , nih - > GetGRFID ( this - > GetFeatureIndex ( ) ) ) ;
2010-08-01 18:53:30 +00:00
break ;
}
2010-04-24 13:36:29 +00:00
2013-11-07 18:17:21 +00:00
case WID_NGRFI_VEH_PREV :
if ( this - > chain_index > 0 ) {
this - > chain_index - - ;
this - > InvalidateData ( ) ;
}
break ;
case WID_NGRFI_VEH_NEXT :
if ( this - > HasChainIndex ( ) ) {
uint index = this - > GetFeatureIndex ( ) ;
Vehicle * v = Vehicle : : Get ( index ) ;
2019-04-10 21:07:06 +00:00
if ( v ! = nullptr & & v - > Next ( ) ! = nullptr ) {
2013-11-07 18:17:21 +00:00
this - > chain_index + + ;
this - > InvalidateData ( ) ;
}
}
break ;
2011-12-16 17:15:40 +00:00
case WID_NGRFI_MAINPANEL : {
2010-04-24 13:36:29 +00:00
/* Does this feature have variables? */
const NIFeature * nif = GetFeature ( this - > window_number ) ;
2019-04-10 21:07:06 +00:00
if ( nif - > variables = = nullptr ) return ;
2010-04-24 13:36:29 +00:00
/* Get the line, make sure it's within the boundaries. */
2011-12-16 17:15:40 +00:00
int line = this - > vscroll - > GetScrolledRowFromWidget ( pt . y , this , WID_NGRFI_MAINPANEL , TOP_OFFSET ) ;
2010-07-26 13:08:48 +00:00
if ( line = = INT_MAX ) return ;
2010-04-24 13:36:29 +00:00
/* Find the variable related to the line */
2019-04-10 21:07:06 +00:00
for ( const NIVariable * niv = nif - > variables ; niv - > name ! = nullptr ; niv + + , line - - ) {
2010-04-24 13:36:29 +00:00
if ( line ! = 1 ) continue ; // 1 because of the "Variables:" line
if ( ! HasVariableParameter ( niv - > var ) ) break ;
this - > current_edit_param = niv - > var ;
2011-11-08 17:23:30 +00:00
ShowQueryString ( STR_EMPTY , STR_NEWGRF_INSPECT_QUERY_CAPTION , 9 , this , CS_HEXADECIMAL , QSF_NONE ) ;
2010-04-24 13:36:29 +00:00
}
}
}
}
2019-03-04 07:49:37 +00:00
void OnQueryTextFinished ( char * str ) override
2010-04-24 13:36:29 +00:00
{
if ( StrEmpty ( str ) ) return ;
2019-04-10 21:07:06 +00:00
NewGRFInspectWindow : : var60params [ GetFeatureNum ( this - > window_number ) ] [ this - > current_edit_param - 0x60 ] = strtol ( str , nullptr , 16 ) ;
2010-04-24 13:36:29 +00:00
this - > SetDirty ( ) ;
}
2019-03-04 07:49:37 +00:00
void OnResize ( ) override
2010-04-24 13:36:29 +00:00
{
2011-12-16 17:15:40 +00:00
this - > vscroll - > SetCapacityFromWidget ( this , WID_NGRFI_MAINPANEL , TOP_OFFSET + BOTTOM_OFFSET ) ;
2010-04-24 13:36:29 +00:00
}
2013-11-07 18:17:21 +00:00
/**
* Some data on this window has become invalid .
* @ param data Information about the changed data .
* @ param gui_scope Whether the call is done from GUI scope . You may not do everything when not in GUI scope . See # InvalidateWindowData ( ) for details .
*/
2019-03-04 07:49:37 +00:00
void OnInvalidateData ( int data = 0 , bool gui_scope = true ) override
2013-11-07 18:17:21 +00:00
{
if ( ! gui_scope ) return ;
if ( this - > HasChainIndex ( ) ) {
this - > ValidateChainIndex ( ) ;
this - > SetWidgetDisabledState ( WID_NGRFI_VEH_PREV , this - > chain_index = = 0 ) ;
Vehicle * v = Vehicle : : Get ( this - > GetFeatureIndex ( ) ) ;
2019-04-10 21:07:06 +00:00
this - > SetWidgetDisabledState ( WID_NGRFI_VEH_NEXT , v = = nullptr | | v - > Next ( ) = = nullptr ) ;
2013-11-07 18:17:21 +00:00
}
}
2010-04-24 13:36:29 +00:00
} ;
2011-11-08 17:23:30 +00:00
/* static */ uint32 NewGRFInspectWindow : : var60params [ GSF_FAKE_END ] [ 0x20 ] = { { 0 } } ; // Use spec to have 0s in whole array
2010-04-24 13:36:29 +00:00
2013-11-07 18:17:21 +00:00
static const NWidgetPart _nested_newgrf_inspect_chain_widgets [ ] = {
NWidget ( NWID_HORIZONTAL ) ,
NWidget ( WWT_CLOSEBOX , COLOUR_GREY ) ,
NWidget ( WWT_CAPTION , COLOUR_GREY , WID_NGRFI_CAPTION ) , SetDataTip ( STR_NEWGRF_INSPECT_CAPTION , STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS ) ,
NWidget ( WWT_SHADEBOX , COLOUR_GREY ) ,
NWidget ( WWT_DEFSIZEBOX , COLOUR_GREY ) ,
NWidget ( WWT_STICKYBOX , COLOUR_GREY ) ,
EndContainer ( ) ,
NWidget ( WWT_PANEL , COLOUR_GREY ) ,
NWidget ( NWID_HORIZONTAL ) ,
NWidget ( WWT_PUSHARROWBTN , COLOUR_GREY , WID_NGRFI_VEH_PREV ) , SetDataTip ( AWV_DECREASE , STR_NULL ) ,
NWidget ( WWT_PUSHARROWBTN , COLOUR_GREY , WID_NGRFI_VEH_NEXT ) , SetDataTip ( AWV_INCREASE , STR_NULL ) ,
NWidget ( WWT_EMPTY , COLOUR_GREY , WID_NGRFI_VEH_CHAIN ) , SetFill ( 1 , 0 ) , SetResize ( 1 , 0 ) ,
EndContainer ( ) ,
EndContainer ( ) ,
NWidget ( NWID_HORIZONTAL ) ,
NWidget ( WWT_PANEL , COLOUR_GREY , WID_NGRFI_MAINPANEL ) , SetMinimalSize ( 300 , 0 ) , SetScrollbar ( WID_NGRFI_SCROLLBAR ) , EndContainer ( ) ,
NWidget ( NWID_VERTICAL ) ,
NWidget ( NWID_VSCROLLBAR , COLOUR_GREY , WID_NGRFI_SCROLLBAR ) ,
NWidget ( WWT_RESIZEBOX , COLOUR_GREY ) ,
EndContainer ( ) ,
EndContainer ( ) ,
} ;
2010-04-24 13:36:29 +00:00
static const NWidgetPart _nested_newgrf_inspect_widgets [ ] = {
NWidget ( NWID_HORIZONTAL ) ,
NWidget ( WWT_CLOSEBOX , COLOUR_GREY ) ,
2011-12-16 17:15:40 +00:00
NWidget ( WWT_CAPTION , COLOUR_GREY , WID_NGRFI_CAPTION ) , SetDataTip ( STR_NEWGRF_INSPECT_CAPTION , STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS ) ,
NWidget ( WWT_PUSHTXTBTN , COLOUR_GREY , WID_NGRFI_PARENT ) , SetDataTip ( STR_NEWGRF_INSPECT_PARENT_BUTTON , STR_NEWGRF_INSPECT_PARENT_TOOLTIP ) ,
2010-04-24 13:36:29 +00:00
NWidget ( WWT_SHADEBOX , COLOUR_GREY ) ,
2013-05-26 19:30:07 +00:00
NWidget ( WWT_DEFSIZEBOX , COLOUR_GREY ) ,
2010-04-24 13:36:29 +00:00
NWidget ( WWT_STICKYBOX , COLOUR_GREY ) ,
EndContainer ( ) ,
NWidget ( NWID_HORIZONTAL ) ,
2011-12-16 17:15:40 +00:00
NWidget ( WWT_PANEL , COLOUR_GREY , WID_NGRFI_MAINPANEL ) , SetMinimalSize ( 300 , 0 ) , SetScrollbar ( WID_NGRFI_SCROLLBAR ) , EndContainer ( ) ,
2010-04-24 13:36:29 +00:00
NWidget ( NWID_VERTICAL ) ,
2011-12-16 17:15:40 +00:00
NWidget ( NWID_VSCROLLBAR , COLOUR_GREY , WID_NGRFI_SCROLLBAR ) ,
2010-04-24 13:36:29 +00:00
NWidget ( WWT_RESIZEBOX , COLOUR_GREY ) ,
EndContainer ( ) ,
EndContainer ( ) ,
} ;
2013-11-07 18:17:21 +00:00
static WindowDesc _newgrf_inspect_chain_desc (
WDP_AUTO , " newgrf_inspect_chain " , 400 , 300 ,
WC_NEWGRF_INSPECT , WC_NONE ,
0 ,
_nested_newgrf_inspect_chain_widgets , lengthof ( _nested_newgrf_inspect_chain_widgets )
) ;
2013-05-26 19:23:42 +00:00
static WindowDesc _newgrf_inspect_desc (
2013-05-26 19:25:01 +00:00
WDP_AUTO , " newgrf_inspect " , 400 , 300 ,
2010-04-24 13:36:29 +00:00
WC_NEWGRF_INSPECT , WC_NONE ,
2012-11-11 16:10:43 +00:00
0 ,
2010-04-24 13:36:29 +00:00
_nested_newgrf_inspect_widgets , lengthof ( _nested_newgrf_inspect_widgets )
) ;
2011-01-22 09:53:15 +00:00
/**
* Show the inspect window for a given feature and index .
* The index is normally an in - game location / identifier , such
* as a TileIndex or an IndustryID depending on the feature
* we want to inspect .
* @ param feature The feature we want to inspect .
* @ param index The index / identifier of the feature to inspect .
2011-06-12 20:51:38 +00:00
* @ param grfid GRFID of the item opening this window , or 0 if not opened by other window .
2011-01-22 09:53:15 +00:00
*/
2011-06-12 20:51:38 +00:00
void ShowNewGRFInspectWindow ( GrfSpecFeature feature , uint index , const uint32 grfid )
2010-04-24 13:36:29 +00:00
{
if ( ! IsNewGRFInspectable ( feature , index ) ) return ;
WindowNumber wno = GetInspectWindowNumber ( feature , index ) ;
2014-12-18 18:22:23 +00:00
WindowDesc * desc = ( feature = = GSF_TRAINS | | feature = = GSF_ROADVEHICLES ) ? & _newgrf_inspect_chain_desc : & _newgrf_inspect_desc ;
NewGRFInspectWindow * w = AllocateWindowDescFront < NewGRFInspectWindow > ( desc , wno , true ) ;
2011-06-12 20:51:38 +00:00
w - > SetCallerGRFID ( grfid ) ;
2010-04-24 13:36:29 +00:00
}
2013-11-07 18:17:21 +00:00
/**
* Invalidate the inspect window for a given feature and index .
* The index is normally an in - game location / identifier , such
* as a TileIndex or an IndustryID depending on the feature
* we want to inspect .
* @ param feature The feature we want to invalidate the window for .
* @ param index The index / identifier of the feature to invalidate .
*/
void InvalidateNewGRFInspectWindow ( GrfSpecFeature feature , uint index )
{
if ( feature = = GSF_INVALID ) return ;
WindowNumber wno = GetInspectWindowNumber ( feature , index ) ;
InvalidateWindowData ( WC_NEWGRF_INSPECT , wno ) ;
}
2011-01-22 09:53:15 +00:00
/**
* Delete inspect window for a given feature and index .
* The index is normally an in - game location / identifier , such
* as a TileIndex or an IndustryID depending on the feature
* we want to inspect .
* @ param feature The feature we want to delete the window for .
* @ param index The index / identifier of the feature to delete .
*/
2010-04-24 13:36:29 +00:00
void DeleteNewGRFInspectWindow ( GrfSpecFeature feature , uint index )
{
if ( feature = = GSF_INVALID ) return ;
WindowNumber wno = GetInspectWindowNumber ( feature , index ) ;
DeleteWindowById ( WC_NEWGRF_INSPECT , wno ) ;
2011-02-23 20:54:55 +00:00
/* Reinitialise the land information window to remove the "debug" sprite if needed.
* Note : Since we might be called from a command here , it is important to not execute
2011-02-24 21:48:06 +00:00
* the invalidation immediately . The landinfo window tests commands itself . */
2011-02-23 20:45:52 +00:00
InvalidateWindowData ( WC_LAND_INFO , 0 , 1 ) ;
2010-04-24 13:36:29 +00:00
}
2011-01-22 09:53:15 +00:00
/**
* Can we inspect the data given a certain feature and index .
* The index is normally an in - game location / identifier , such
* as a TileIndex or an IndustryID depending on the feature
* we want to inspect .
* @ param feature The feature we want to inspect .
* @ param index The index / identifier of the feature to inspect .
* @ return true if there is something to show .
*/
2010-04-24 13:36:29 +00:00
bool IsNewGRFInspectable ( GrfSpecFeature feature , uint index )
{
const NIFeature * nif = GetFeature ( GetInspectWindowNumber ( feature , index ) ) ;
2019-04-10 21:07:06 +00:00
if ( nif = = nullptr ) return false ;
2010-04-24 13:36:29 +00:00
return nif - > helper - > IsInspectable ( index ) ;
}
2011-01-22 09:53:15 +00:00
/**
* Get the GrfSpecFeature associated with the tile .
* @ param tile The tile to get the feature from .
* @ return the GrfSpecFeature .
*/
2010-04-24 13:36:29 +00:00
GrfSpecFeature GetGrfSpecFeature ( TileIndex tile )
{
switch ( GetTileType ( tile ) ) {
default : return GSF_INVALID ;
case MP_RAILWAY : return GSF_RAILTYPES ;
case MP_ROAD : return IsLevelCrossing ( tile ) ? GSF_RAILTYPES : GSF_INVALID ;
case MP_HOUSE : return GSF_HOUSES ;
case MP_INDUSTRY : return GSF_INDUSTRYTILES ;
2010-08-28 19:48:46 +00:00
case MP_OBJECT : return GSF_OBJECTS ;
2010-04-24 13:36:29 +00:00
case MP_STATION :
switch ( GetStationType ( tile ) ) {
case STATION_RAIL : return GSF_STATIONS ;
case STATION_AIRPORT : return GSF_AIRPORTTILES ;
default : return GSF_INVALID ;
}
}
}
2011-01-22 09:53:15 +00:00
/**
* Get the GrfSpecFeature associated with the vehicle .
* @ param type The vehicle type to get the feature from .
* @ return the GrfSpecFeature .
*/
2010-04-24 13:36:29 +00:00
GrfSpecFeature GetGrfSpecFeature ( VehicleType type )
{
switch ( type ) {
case VEH_TRAIN : return GSF_TRAINS ;
case VEH_ROAD : return GSF_ROADVEHICLES ;
case VEH_SHIP : return GSF_SHIPS ;
case VEH_AIRCRAFT : return GSF_AIRCRAFT ;
default : return GSF_INVALID ;
}
}
2010-04-25 16:27:30 +00:00
/**** Sprite Aligner ****/
/** Window used for aligning sprites. */
struct SpriteAlignerWindow : Window {
2020-05-17 21:31:44 +00:00
typedef std : : pair < int16 , int16 > XyOffs ; ///< Pair for x and y offsets of the sprite before alignment. First value contains the x offset, second value y offset.
2015-03-01 08:17:14 +00:00
SpriteID current_sprite ; ///< The currently shown sprite.
2010-08-12 08:37:01 +00:00
Scrollbar * vscroll ;
2015-03-01 08:17:14 +00:00
SmallMap < SpriteID , XyOffs > offs_start_map ; ///< Mapping of starting offsets for the sprites which have been aligned in the sprite aligner window.
2010-04-25 16:27:30 +00:00
2013-05-26 19:23:42 +00:00
SpriteAlignerWindow ( WindowDesc * desc , WindowNumber wno ) : Window ( desc )
2010-04-25 16:27:30 +00:00
{
2013-05-26 19:23:42 +00:00
this - > CreateNestedTree ( ) ;
2011-12-16 17:15:40 +00:00
this - > vscroll = this - > GetScrollbar ( WID_SA_SCROLLBAR ) ;
2013-05-26 19:23:42 +00:00
this - > FinishInitNested ( wno ) ;
2010-04-25 16:27:30 +00:00
/* Oh yes, we assume there is at least one normal sprite! */
while ( GetSpriteType ( this - > current_sprite ) ! = ST_NORMAL ) this - > current_sprite + + ;
}
2019-03-04 07:49:37 +00:00
void SetStringParameters ( int widget ) const override
2010-04-25 16:27:30 +00:00
{
2015-03-01 08:17:14 +00:00
const Sprite * spr = GetSprite ( this - > current_sprite , ST_NORMAL ) ;
2010-04-25 16:27:30 +00:00
switch ( widget ) {
2011-12-16 17:15:40 +00:00
case WID_SA_CAPTION :
2010-04-25 16:27:30 +00:00
SetDParam ( 0 , this - > current_sprite ) ;
SetDParamStr ( 1 , FioGetFilename ( GetOriginFileSlot ( this - > current_sprite ) ) ) ;
break ;
2015-03-01 08:17:14 +00:00
case WID_SA_OFFSETS_ABS :
2014-09-30 11:35:21 +00:00
SetDParam ( 0 , spr - > x_offs ) ;
SetDParam ( 1 , spr - > y_offs ) ;
2010-08-01 18:53:30 +00:00
break ;
2015-03-01 08:17:14 +00:00
case WID_SA_OFFSETS_REL : {
/* Relative offset is new absolute offset - starting absolute offset.
* Show 0 , 0 as the relative offsets if entry is not in the map ( meaning they have not been changed yet ) .
*/
2019-02-17 11:20:52 +00:00
const auto key_offs_pair = this - > offs_start_map . Find ( this - > current_sprite ) ;
if ( key_offs_pair ! = this - > offs_start_map . end ( ) ) {
2015-03-01 08:17:14 +00:00
SetDParam ( 0 , spr - > x_offs - key_offs_pair - > second . first ) ;
SetDParam ( 1 , spr - > y_offs - key_offs_pair - > second . second ) ;
} else {
SetDParam ( 0 , 0 ) ;
SetDParam ( 1 , 0 ) ;
}
break ;
2010-08-01 18:53:30 +00:00
}
2010-04-25 16:27:30 +00:00
default :
break ;
}
}
2019-03-04 07:49:37 +00:00
void UpdateWidgetSize ( int widget , Dimension * size , const Dimension & padding , Dimension * fill , Dimension * resize ) override
2010-04-26 20:35:27 +00:00
{
2020-08-02 14:26:53 +00:00
switch ( widget ) {
case WID_SA_SPRITE :
size - > height = ScaleGUITrad ( 200 ) ;
break ;
case WID_SA_LIST :
2021-01-08 10:16:18 +00:00
resize - > height = std : : max ( 11 , FONT_HEIGHT_NORMAL + 1 ) ;
2020-08-02 14:26:53 +00:00
resize - > width = 1 ;
break ;
default :
break ;
}
2010-04-26 20:35:27 +00:00
}
2019-03-04 07:49:37 +00:00
void DrawWidget ( const Rect & r , int widget ) const override
2010-04-25 16:27:30 +00:00
{
2010-04-26 20:35:27 +00:00
switch ( widget ) {
2011-12-16 17:15:40 +00:00
case WID_SA_SPRITE : {
2010-04-26 20:35:27 +00:00
/* Center the sprite ourselves */
const Sprite * spr = GetSprite ( this - > current_sprite , ST_NORMAL ) ;
2015-02-28 20:09:49 +00:00
int width = r . right - r . left + 1 - WD_BEVEL_LEFT - WD_BEVEL_RIGHT ;
int height = r . bottom - r . top + 1 - WD_BEVEL_TOP - WD_BEVEL_BOTTOM ;
int x = - UnScaleGUI ( spr - > x_offs ) + ( width - UnScaleGUI ( spr - > width ) ) / 2 ;
int y = - UnScaleGUI ( spr - > y_offs ) + ( height - UnScaleGUI ( spr - > height ) ) / 2 ;
DrawPixelInfo new_dpi ;
if ( ! FillDrawPixelInfo ( & new_dpi , r . left + WD_BEVEL_LEFT , r . top + WD_BEVEL_TOP , width , height ) ) break ;
DrawPixelInfo * old_dpi = _cur_dpi ;
_cur_dpi = & new_dpi ;
2019-04-10 21:07:06 +00:00
DrawSprite ( this - > current_sprite , PAL_NONE , x , y , nullptr , ZOOM_LVL_GUI ) ;
2015-02-28 20:09:49 +00:00
_cur_dpi = old_dpi ;
2010-04-26 20:35:27 +00:00
break ;
}
2011-12-16 17:15:40 +00:00
case WID_SA_LIST : {
2010-04-26 20:35:27 +00:00
const NWidgetBase * nwid = this - > GetWidget < NWidgetBase > ( widget ) ;
int step_size = nwid - > resize_y ;
2019-03-03 17:30:09 +00:00
std : : vector < SpriteID > & list = _newgrf_debug_sprite_picker . sprites ;
2021-01-08 10:16:18 +00:00
int max = std : : min < int > ( this - > vscroll - > GetPosition ( ) + this - > vscroll - > GetCapacity ( ) , ( uint ) list . size ( ) ) ;
2010-04-26 20:35:27 +00:00
int y = r . top + WD_FRAMERECT_TOP ;
2010-08-12 08:37:01 +00:00
for ( int i = this - > vscroll - > GetPosition ( ) ; i < max ; i + + ) {
2010-04-26 20:35:27 +00:00
SetDParam ( 0 , list [ i ] ) ;
DrawString ( r . left + WD_FRAMERECT_LEFT , r . right - WD_FRAMERECT_RIGHT , y , STR_BLACK_COMMA , TC_FROMSTRING , SA_RIGHT | SA_FORCE ) ;
y + = step_size ;
}
break ;
}
}
2010-04-25 16:27:30 +00:00
}
2019-03-04 07:49:37 +00:00
void OnClick ( Point pt , int widget , int click_count ) override
2010-04-25 16:27:30 +00:00
{
switch ( widget ) {
2011-12-16 17:15:40 +00:00
case WID_SA_PREVIOUS :
2010-04-25 16:27:30 +00:00
do {
this - > current_sprite = ( this - > current_sprite = = 0 ? GetMaxSpriteID ( ) : this - > current_sprite ) - 1 ;
} while ( GetSpriteType ( this - > current_sprite ) ! = ST_NORMAL ) ;
this - > SetDirty ( ) ;
break ;
2011-12-16 17:15:40 +00:00
case WID_SA_GOTO :
2011-04-17 18:42:17 +00:00
ShowQueryString ( STR_EMPTY , STR_SPRITE_ALIGNER_GOTO_CAPTION , 7 , this , CS_NUMERAL , QSF_NONE ) ;
2010-04-25 16:27:30 +00:00
break ;
2011-12-16 17:15:40 +00:00
case WID_SA_NEXT :
2010-04-25 16:27:30 +00:00
do {
this - > current_sprite = ( this - > current_sprite + 1 ) % GetMaxSpriteID ( ) ;
} while ( GetSpriteType ( this - > current_sprite ) ! = ST_NORMAL ) ;
this - > SetDirty ( ) ;
break ;
2011-12-16 17:15:40 +00:00
case WID_SA_PICKER :
this - > LowerWidget ( WID_SA_PICKER ) ;
2010-04-26 20:35:27 +00:00
_newgrf_debug_sprite_picker . mode = SPM_WAIT_CLICK ;
this - > SetDirty ( ) ;
break ;
2011-12-16 17:15:40 +00:00
case WID_SA_LIST : {
2010-04-26 20:35:27 +00:00
const NWidgetBase * nwid = this - > GetWidget < NWidgetBase > ( widget ) ;
int step_size = nwid - > resize_y ;
2010-08-12 08:37:01 +00:00
uint i = this - > vscroll - > GetPosition ( ) + ( pt . y - nwid - > pos_y ) / step_size ;
2018-09-23 11:23:54 +00:00
if ( i < _newgrf_debug_sprite_picker . sprites . size ( ) ) {
2010-04-26 20:35:27 +00:00
SpriteID spr = _newgrf_debug_sprite_picker . sprites [ i ] ;
if ( GetSpriteType ( spr ) = = ST_NORMAL ) this - > current_sprite = spr ;
}
this - > SetDirty ( ) ;
break ;
}
2011-12-16 17:15:40 +00:00
case WID_SA_UP :
case WID_SA_DOWN :
case WID_SA_LEFT :
case WID_SA_RIGHT : {
2010-04-25 16:27:30 +00:00
/*
* Yes . . . this is a hack .
*
* No . . . I don ' t think it is useful to make this less of a hack .
*
* If you want to align sprites , you just need the number . Generally
* the sprite caches are big enough to not remove the sprite from the
* cache . If that ' s not the case , just let the NewGRF developer
* increase the cache size instead of storing thousands of offsets
* for the incredibly small chance that it ' s actually going to be
* used by someone and the sprite cache isn ' t big enough for that
* particular NewGRF developer .
*/
Sprite * spr = const_cast < Sprite * > ( GetSprite ( this - > current_sprite , ST_NORMAL ) ) ;
2015-03-01 08:17:14 +00:00
/* Remember the original offsets of the current sprite, if not already in mapping. */
if ( ! ( this - > offs_start_map . Contains ( this - > current_sprite ) ) ) {
this - > offs_start_map . Insert ( this - > current_sprite , XyOffs ( spr - > x_offs , spr - > y_offs ) ) ;
}
2010-04-25 16:27:30 +00:00
switch ( widget ) {
2019-05-26 22:52:53 +00:00
/* Move eight units at a time if ctrl is pressed. */
2015-11-20 10:04:28 +00:00
case WID_SA_UP : spr - > y_offs - = _ctrl_pressed ? 8 : 1 ; break ;
case WID_SA_DOWN : spr - > y_offs + = _ctrl_pressed ? 8 : 1 ; break ;
case WID_SA_LEFT : spr - > x_offs - = _ctrl_pressed ? 8 : 1 ; break ;
case WID_SA_RIGHT : spr - > x_offs + = _ctrl_pressed ? 8 : 1 ; break ;
2010-04-25 16:27:30 +00:00
}
2013-01-08 22:46:42 +00:00
/* Of course, we need to redraw the sprite, but where is it used?
2010-04-25 16:27:30 +00:00
* Everywhere is a safe bet . */
MarkWholeScreenDirty ( ) ;
2010-08-01 18:53:30 +00:00
break ;
}
2015-03-01 08:17:14 +00:00
case WID_SA_RESET_REL :
/* Reset the starting offsets for the current sprite. */
2019-05-26 22:52:53 +00:00
this - > offs_start_map . Erase ( this - > current_sprite ) ;
2015-03-01 08:17:14 +00:00
this - > SetDirty ( ) ;
break ;
2010-04-25 16:27:30 +00:00
}
}
2019-03-04 07:49:37 +00:00
void OnQueryTextFinished ( char * str ) override
2010-04-25 16:27:30 +00:00
{
if ( StrEmpty ( str ) ) return ;
this - > current_sprite = atoi ( str ) ;
if ( this - > current_sprite > = GetMaxSpriteID ( ) ) this - > current_sprite = 0 ;
while ( GetSpriteType ( this - > current_sprite ) ! = ST_NORMAL ) {
this - > current_sprite = ( this - > current_sprite + 1 ) % GetMaxSpriteID ( ) ;
}
this - > SetDirty ( ) ;
}
2010-04-26 20:35:27 +00:00
2011-03-13 21:31:29 +00:00
/**
* Some data on this window has become invalid .
* @ param data Information about the changed data .
* @ param gui_scope Whether the call is done from GUI scope . You may not do everything when not in GUI scope . See # InvalidateWindowData ( ) for details .
*/
2019-03-04 07:49:37 +00:00
void OnInvalidateData ( int data = 0 , bool gui_scope = true ) override
2010-04-26 20:35:27 +00:00
{
2011-03-13 21:31:29 +00:00
if ( ! gui_scope ) return ;
2010-04-26 20:35:27 +00:00
if ( data = = 1 ) {
/* Sprite picker finished */
2011-12-16 17:15:40 +00:00
this - > RaiseWidget ( WID_SA_PICKER ) ;
2019-03-27 23:09:33 +00:00
this - > vscroll - > SetCount ( ( uint ) _newgrf_debug_sprite_picker . sprites . size ( ) ) ;
2010-04-26 20:35:27 +00:00
}
}
2019-03-04 07:49:37 +00:00
void OnResize ( ) override
2010-04-26 20:35:27 +00:00
{
2011-12-16 17:15:40 +00:00
this - > vscroll - > SetCapacityFromWidget ( this , WID_SA_LIST ) ;
2010-04-26 20:35:27 +00:00
}
2010-04-25 16:27:30 +00:00
} ;
static const NWidgetPart _nested_sprite_aligner_widgets [ ] = {
NWidget ( NWID_HORIZONTAL ) ,
NWidget ( WWT_CLOSEBOX , COLOUR_GREY ) ,
2011-12-16 17:15:40 +00:00
NWidget ( WWT_CAPTION , COLOUR_GREY , WID_SA_CAPTION ) , SetDataTip ( STR_SPRITE_ALIGNER_CAPTION , STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS ) ,
2010-04-25 16:27:30 +00:00
NWidget ( WWT_SHADEBOX , COLOUR_GREY ) ,
NWidget ( WWT_STICKYBOX , COLOUR_GREY ) ,
EndContainer ( ) ,
NWidget ( WWT_PANEL , COLOUR_GREY ) ,
2010-04-26 20:35:27 +00:00
NWidget ( NWID_HORIZONTAL ) , SetPIP ( 0 , 0 , 10 ) ,
NWidget ( NWID_VERTICAL ) , SetPIP ( 10 , 5 , 10 ) ,
NWidget ( NWID_HORIZONTAL , NC_EQUALSIZE ) , SetPIP ( 10 , 5 , 10 ) ,
2011-12-16 17:15:40 +00:00
NWidget ( WWT_PUSHTXTBTN , COLOUR_GREY , WID_SA_PREVIOUS ) , SetDataTip ( STR_SPRITE_ALIGNER_PREVIOUS_BUTTON , STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP ) , SetFill ( 1 , 0 ) ,
NWidget ( WWT_PUSHTXTBTN , COLOUR_GREY , WID_SA_GOTO ) , SetDataTip ( STR_SPRITE_ALIGNER_GOTO_BUTTON , STR_SPRITE_ALIGNER_GOTO_TOOLTIP ) , SetFill ( 1 , 0 ) ,
NWidget ( WWT_PUSHTXTBTN , COLOUR_GREY , WID_SA_NEXT ) , SetDataTip ( STR_SPRITE_ALIGNER_NEXT_BUTTON , STR_SPRITE_ALIGNER_NEXT_TOOLTIP ) , SetFill ( 1 , 0 ) ,
2010-04-26 20:35:27 +00:00
EndContainer ( ) ,
NWidget ( NWID_HORIZONTAL ) , SetPIP ( 10 , 5 , 10 ) ,
2010-04-25 16:27:30 +00:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
2011-12-16 17:15:40 +00:00
NWidget ( WWT_PUSHIMGBTN , COLOUR_GREY , WID_SA_UP ) , SetDataTip ( SPR_ARROW_UP , STR_SPRITE_ALIGNER_MOVE_TOOLTIP ) , SetResize ( 0 , 0 ) ,
2010-04-25 16:27:30 +00:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
EndContainer ( ) ,
2010-04-26 20:35:27 +00:00
NWidget ( NWID_HORIZONTAL_LTR ) , SetPIP ( 10 , 5 , 10 ) ,
NWidget ( NWID_VERTICAL ) ,
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
2011-12-16 17:15:40 +00:00
NWidget ( WWT_PUSHIMGBTN , COLOUR_GREY , WID_SA_LEFT ) , SetDataTip ( SPR_ARROW_LEFT , STR_SPRITE_ALIGNER_MOVE_TOOLTIP ) , SetResize ( 0 , 0 ) ,
2010-04-26 20:35:27 +00:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
EndContainer ( ) ,
2011-12-16 17:15:40 +00:00
NWidget ( WWT_PANEL , COLOUR_DARK_BLUE , WID_SA_SPRITE ) , SetDataTip ( STR_NULL , STR_SPRITE_ALIGNER_SPRITE_TOOLTIP ) ,
2010-04-26 20:35:27 +00:00
EndContainer ( ) ,
NWidget ( NWID_VERTICAL ) ,
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
2011-12-16 17:15:40 +00:00
NWidget ( WWT_PUSHIMGBTN , COLOUR_GREY , WID_SA_RIGHT ) , SetDataTip ( SPR_ARROW_RIGHT , STR_SPRITE_ALIGNER_MOVE_TOOLTIP ) , SetResize ( 0 , 0 ) ,
2010-04-26 20:35:27 +00:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
EndContainer ( ) ,
2010-04-25 16:27:30 +00:00
EndContainer ( ) ,
2010-04-26 20:35:27 +00:00
NWidget ( NWID_HORIZONTAL ) , SetPIP ( 10 , 5 , 10 ) ,
2010-04-25 16:27:30 +00:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
2011-12-16 17:15:40 +00:00
NWidget ( WWT_PUSHIMGBTN , COLOUR_GREY , WID_SA_DOWN ) , SetDataTip ( SPR_ARROW_DOWN , STR_SPRITE_ALIGNER_MOVE_TOOLTIP ) , SetResize ( 0 , 0 ) ,
2010-04-25 16:27:30 +00:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
EndContainer ( ) ,
2015-03-01 08:17:14 +00:00
NWidget ( WWT_LABEL , COLOUR_GREY , WID_SA_OFFSETS_ABS ) , SetDataTip ( STR_SPRITE_ALIGNER_OFFSETS_ABS , STR_NULL ) , SetFill ( 1 , 0 ) , SetPadding ( 0 , 10 , 0 , 10 ) ,
NWidget ( WWT_LABEL , COLOUR_GREY , WID_SA_OFFSETS_REL ) , SetDataTip ( STR_SPRITE_ALIGNER_OFFSETS_REL , STR_NULL ) , SetFill ( 1 , 0 ) , SetPadding ( 0 , 10 , 0 , 10 ) ,
2010-04-26 20:35:27 +00:00
NWidget ( NWID_HORIZONTAL ) , SetPIP ( 10 , 5 , 10 ) ,
2015-03-01 08:17:14 +00:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
NWidget ( WWT_PUSHTXTBTN , COLOUR_GREY , WID_SA_RESET_REL ) , SetDataTip ( STR_SPRITE_ALIGNER_RESET_BUTTON , STR_SPRITE_ALIGNER_RESET_TOOLTIP ) , SetFill ( 0 , 0 ) ,
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
2010-04-26 20:35:27 +00:00
EndContainer ( ) ,
2010-04-25 16:27:30 +00:00
EndContainer ( ) ,
2010-04-26 20:35:27 +00:00
NWidget ( NWID_VERTICAL ) , SetPIP ( 10 , 5 , 10 ) ,
2011-12-16 17:15:40 +00:00
NWidget ( WWT_TEXTBTN , COLOUR_GREY , WID_SA_PICKER ) , SetDataTip ( STR_SPRITE_ALIGNER_PICKER_BUTTON , STR_SPRITE_ALIGNER_PICKER_TOOLTIP ) , SetFill ( 1 , 0 ) ,
2010-04-26 20:35:27 +00:00
NWidget ( NWID_HORIZONTAL ) ,
2013-06-30 14:36:31 +00:00
NWidget ( WWT_MATRIX , COLOUR_GREY , WID_SA_LIST ) , SetResize ( 1 , 1 ) , SetMatrixDataTip ( 1 , 0 , STR_NULL ) , SetFill ( 1 , 1 ) , SetScrollbar ( WID_SA_SCROLLBAR ) ,
2011-12-16 17:15:40 +00:00
NWidget ( NWID_VSCROLLBAR , COLOUR_GREY , WID_SA_SCROLLBAR ) ,
2010-04-26 20:35:27 +00:00
EndContainer ( ) ,
2010-04-25 16:27:30 +00:00
EndContainer ( ) ,
EndContainer ( ) ,
EndContainer ( ) ,
} ;
2013-05-26 19:23:42 +00:00
static WindowDesc _sprite_aligner_desc (
2013-05-26 19:25:01 +00:00
WDP_AUTO , " sprite_aligner " , 400 , 300 ,
2010-04-25 16:27:30 +00:00
WC_SPRITE_ALIGNER , WC_NONE ,
2012-11-11 16:10:43 +00:00
0 ,
2010-04-25 16:27:30 +00:00
_nested_sprite_aligner_widgets , lengthof ( _nested_sprite_aligner_widgets )
) ;
2011-01-22 09:53:15 +00:00
/**
* Show the window for aligning sprites .
*/
2010-04-25 16:27:30 +00:00
void ShowSpriteAlignerWindow ( )
{
AllocateWindowDescFront < SpriteAlignerWindow > ( & _sprite_aligner_desc , 0 ) ;
}