2010-04-24 15:36:29 +02: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"
2023-01-26 19:21:36 +01:00
# include "core/backup_type.hpp"
2010-04-24 15:36:29 +02:00
# include "window_gui.h"
# include "window_func.h"
2021-04-14 17:20:39 +02:00
# include "random_access_file_type.h"
2010-04-25 18:27:30 +02:00
# include "spritecache.h"
2010-04-24 15:36:29 +02:00
# include "string_func.h"
# include "strings_func.h"
# include "textbuf_gui.h"
2013-11-07 19:17:21 +01:00
# include "vehicle_gui.h"
2014-09-30 13:29:23 +02:00
# include "zoom_func.h"
2010-04-24 15:36:29 +02:00
# include "engine_base.h"
# include "industry.h"
2010-08-28 21:48:46 +02:00
# include "object_base.h"
2010-04-24 15:36:29 +02:00
# include "station_base.h"
# include "town.h"
# include "vehicle_base.h"
2013-11-07 19:17:21 +01:00
# include "train.h"
# include "roadveh.h"
2010-04-24 15:36:29 +02:00
2023-09-10 17:09:31 +02:00
# include "newgrf_airport.h"
2010-04-24 15:36:29 +02:00
# include "newgrf_airporttiles.h"
# include "newgrf_debug.h"
2010-08-28 21:48:46 +02:00
# include "newgrf_object.h"
2010-04-24 15:36:29 +02:00
# include "newgrf_spritegroup.h"
# include "newgrf_station.h"
# include "newgrf_town.h"
2012-11-10 21:41:45 +01:00
# include "newgrf_railtype.h"
2012-11-10 21:44:10 +01:00
# include "newgrf_industries.h"
2012-11-10 21:44:38 +01:00
# include "newgrf_industrytiles.h"
2010-04-24 15:36:29 +02:00
2011-12-15 23:22:55 +01:00
# include "widgets/newgrf_debug_widget.h"
2010-04-24 15:36:29 +02:00
# include "table/strings.h"
2014-04-23 22:13:33 +02:00
# include "safeguards.h"
2011-05-02 18:14:23 +02:00
/** The sprite picker. */
2021-02-26 14:00:53 +01:00
NewGrfDebugSpritePicker _newgrf_debug_sprite_picker = { SPM_NONE , nullptr , std : : vector < SpriteID > ( ) } ;
2010-04-26 22:35:27 +02:00
2010-04-24 15:36:29 +02: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 23:46:42 +01:00
* provide an appropriate representation in the GUI .
2010-04-24 15:36:29 +02:00
*/
enum NIType {
NIT_INT , ///< The property is a simple integer
NIT_CARGO , ///< The property is a cargo
} ;
2020-12-14 00:22:04 +01:00
typedef const void * NIOffsetProc ( const void * b ) ;
2010-04-24 15:36:29 +02:00
/** Representation of the data from a NewGRF property. */
struct NIProperty {
2020-12-14 00:22:04 +01: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 15:36:29 +02:00
byte type ;
} ;
/**
* Representation of the available callbacks with
* information on when they actually apply .
*/
struct NICallback {
2020-12-14 00:22:04 +01: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
2023-05-08 19:01:06 +02:00
uint16_t cb_id ; ///< The number of the callback
2010-04-24 15:36:29 +02: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 16:38:17 +02:00
/** Silence a warning. */
2023-05-14 23:31:03 +02:00
virtual ~ NIHelper ( ) = default ;
2010-06-23 16:38:17 +02:00
2010-04-24 15:36:29 +02: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 22:51:38 +02: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 .
*/
2023-05-08 19:01:06 +02:00
virtual uint32_t GetGRFID ( uint index ) const = 0 ;
2011-06-12 22:51:38 +02:00
2010-04-24 15:36:29 +02: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 21:45:59 +01:00
virtual uint Resolve ( uint index , uint var , uint param , bool * avail ) const = 0 ;
2010-04-24 15:36:29 +02:00
2011-06-12 22:53:16 +02: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 22:41:17 +02:00
/**
* Allows to know the size of the persistent storage .
2011-06-12 22:47:45 +02:00
* @ param index Index of the item .
2011-06-12 22:53:16 +02:00
* @ param grfid Parameter for the PSA . Only required for items with parameters .
2011-06-12 22:41:17 +02:00
* @ return Size of the persistent storage in indices .
*/
2023-09-16 22:20:53 +02:00
virtual uint GetPSASize ( [[maybe_unused]] uint index, [[maybe_unused]] uint32_t grfid ) const
2011-06-12 22:41:17 +02:00
{
return 0 ;
}
/**
* Gets the first position of the array containing the persistent storage .
2011-06-12 22:47:45 +02:00
* @ param index Index of the item .
2011-06-12 22:53:16 +02:00
* @ param grfid Parameter for the PSA . Only required for items with parameters .
2019-04-10 23:07:06 +02:00
* @ return Pointer to the first position of the storage array or nullptr if not present .
2011-06-12 22:41:17 +02:00
*/
2023-09-16 22:20:53 +02:00
virtual const int32_t * GetPSAFirstPosition ( [[maybe_unused]] uint index, [[maybe_unused]] uint32_t grfid ) const
2011-06-12 22:41:17 +02:00
{
2019-04-10 23:07:06 +02:00
return nullptr ;
2011-06-12 22:41:17 +02:00
}
2010-04-24 15:36:29 +02:00
protected :
/**
* Helper to make setting the strings easier .
* @ param string the string to actually draw .
* @ param index the ( instance ) index for the string .
*/
2023-05-08 19:01:06 +02:00
void SetSimpleStringParameters ( StringID string , uint32_t index ) const
2010-04-24 15:36:29 +02:00
{
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
*/
2023-05-08 19:01:06 +02:00
void SetObjectAtStringParameters ( StringID string , uint32_t index , TileIndex tile ) const
2010-04-24 15:36:29 +02:00
{
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 17:16:28 +01: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 15:36:29 +02:00
/**
* Get the NIFeature related to the window number .
* @ param window_number The window to get the NIFeature for .
2019-04-10 23:07:06 +02:00
* @ return the NIFeature , or nullptr is there isn ' t one .
2010-04-24 15:36:29 +02:00
*/
static inline const NIFeature * GetFeature ( uint window_number )
{
2010-10-31 17:16:28 +01:00
GrfSpecFeature idx = GetFeatureNum ( window_number ) ;
2019-04-10 23:07:06 +02:00
return idx < GSF_FAKE_END ? _nifeatures [ idx ] : nullptr ;
2010-04-24 15:36:29 +02:00
}
/**
* Get the NIHelper related to the window number .
* @ param window_number The window to get the NIHelper for .
2019-04-10 23:07:06 +02:00
* @ pre GetFeature ( window_number ) ! = nullptr
2010-04-24 15:36:29 +02: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 {
/** The value for the variable 60 parameters. */
2023-05-08 19:01:06 +02:00
static uint32_t var60params [ GSF_FAKE_END ] [ 0x20 ] ;
2010-04-24 15:36:29 +02:00
2011-06-12 22:51:38 +02:00
/** GRFID of the caller of this window, 0 if it has no caller. */
2023-05-08 19:01:06 +02:00
uint32_t caller_grfid ;
2011-06-12 22:51:38 +02:00
2013-11-07 19:17:21 +01:00
/** For ground vehicles: Index in vehicle chain. */
uint chain_index ;
2013-01-08 23:46:42 +01:00
/** The currently edited parameter, to update the right one. */
2010-04-24 15:36:29 +02:00
byte current_edit_param ;
2010-08-12 10:37:01 +02:00
Scrollbar * vscroll ;
2010-04-24 15:36:29 +02: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 22:51:38 +02: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 .
*/
2023-05-08 19:01:06 +02:00
void SetCallerGRFID ( uint32_t grfid )
2011-06-12 22:51:38 +02:00
{
this - > caller_grfid = grfid ;
this - > SetDirty ( ) ;
}
2013-11-07 19:17:21 +01: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 19:15:32 +01:00
/**
* Get the feature index .
* @ return the feature index
*/
uint GetFeatureIndex ( ) const
{
uint index = : : GetFeatureIndex ( this - > window_number ) ;
2013-11-07 19:17:21 +01:00
if ( this - > chain_index > 0 ) {
assert ( this - > HasChainIndex ( ) ) ;
const Vehicle * v = Vehicle : : Get ( index ) ;
v = v - > Move ( this - > chain_index ) ;
2019-04-10 23:07:06 +02:00
if ( v ! = nullptr ) index = v - > index ;
2013-11-07 19:17:21 +01:00
}
2013-11-07 19:15:32 +01:00
return index ;
}
2013-11-07 19:17:21 +01: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 23:07:06 +02:00
if ( v = = nullptr ) this - > chain_index = 0 ;
2013-11-07 19:17:21 +01:00
}
2013-05-26 21:23:42 +02:00
NewGRFInspectWindow ( WindowDesc * desc , WindowNumber wno ) : Window ( desc )
2010-04-24 15:36:29 +02:00
{
2013-05-26 21:23:42 +02:00
this - > CreateNestedTree ( ) ;
2011-12-16 18:15:40 +01:00
this - > vscroll = this - > GetScrollbar ( WID_NGRFI_SCROLLBAR ) ;
2013-05-26 21:23:42 +02:00
this - > FinishInitNested ( wno ) ;
2010-04-24 15:36:29 +02:00
2010-08-12 10:37:01 +02:00
this - > vscroll - > SetCount ( 0 ) ;
2013-11-07 19:15:32 +01:00
this - > SetWidgetDisabledState ( WID_NGRFI_PARENT , GetFeatureHelper ( this - > window_number ) - > GetParent ( this - > GetFeatureIndex ( ) ) = = UINT32_MAX ) ;
2013-11-07 19:17:21 +01:00
this - > OnInvalidateData ( 0 , true ) ;
2010-04-24 15:36:29 +02:00
}
2019-03-04 08:49:37 +01:00
void SetStringParameters ( int widget ) const override
2010-04-24 15:36:29 +02:00
{
2011-12-16 18:15:40 +01:00
if ( widget ! = WID_NGRFI_CAPTION ) return ;
2010-04-24 15:36:29 +02:00
2013-11-07 19:15:32 +01:00
GetFeatureHelper ( this - > window_number ) - > SetStringParameters ( this - > GetFeatureIndex ( ) ) ;
2010-04-24 15:36:29 +02:00
}
2023-09-16 22:20:53 +02:00
void UpdateWidgetSize ( int widget , Dimension * size , [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension * resize ) override
2010-04-24 15:36:29 +02:00
{
2013-11-07 19:17:21 +01:00
switch ( widget ) {
case WID_NGRFI_VEH_CHAIN : {
assert ( this - > HasChainIndex ( ) ) ;
GrfSpecFeature f = GetFeatureNum ( this - > window_number ) ;
2022-09-23 10:36:22 +02:00
size - > height = std : : max ( size - > height , GetVehicleImageCellSize ( ( VehicleType ) ( VEH_TRAIN + ( f - GSF_TRAINS ) ) , EIT_IN_DEPOT ) . height + 2 + WidgetDimensions : : scaled . bevel . Vertical ( ) ) ;
2013-11-07 19:17:21 +01:00
break ;
}
2010-04-24 15:36:29 +02:00
2013-11-07 19:17:21 +01:00
case WID_NGRFI_MAINPANEL :
2023-11-21 20:04:24 +01:00
resize - > height = std : : max ( 11 , GetCharacterHeight ( FS_NORMAL ) + WidgetDimensions : : scaled . vsep_normal ) ;
2013-11-07 19:17:21 +01:00
resize - > width = 1 ;
2010-04-24 15:36:29 +02:00
2022-09-23 10:36:22 +02:00
size - > height = 5 * resize - > height + WidgetDimensions : : scaled . frametext . Vertical ( ) ;
2013-11-07 19:17:21 +01:00
break ;
}
2010-04-24 15:36:29 +02: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
2023-04-19 21:38:09 +02:00
* @ param string The string to draw
2010-04-24 15:36:29 +02:00
*/
2023-04-19 21:38:09 +02:00
void DrawString ( const Rect & r , int offset , const std : : string & string ) const
2010-04-24 15:36:29 +02:00
{
2010-08-12 10:37:01 +02:00
offset - = this - > vscroll - > GetPosition ( ) ;
if ( offset < 0 | | offset > = this - > vscroll - > GetCapacity ( ) ) return ;
2010-04-24 15:36:29 +02:00
2023-04-19 20:37:21 +02:00
: : DrawString ( r . Shrink ( WidgetDimensions : : scaled . frametext ) . Shrink ( 0 , offset * this - > resize . step_height , 0 , 0 ) , string , TC_BLACK ) ;
2010-04-24 15:36:29 +02:00
}
2023-03-25 20:59:48 +01:00
/**
* Helper function to draw the vehicle chain widget .
* @ param r The rectangle to draw within .
*/
void DrawVehicleChainWidget ( const Rect & r ) const
2010-04-24 15:36:29 +02:00
{
2023-03-25 20:59:48 +01:00
const Vehicle * v = Vehicle : : Get ( this - > GetFeatureIndex ( ) ) ;
int total_width = 0 ;
int sel_start = 0 ;
int sel_end = 0 ;
for ( const Vehicle * u = v - > First ( ) ; u ! = nullptr ; u = u - > Next ( ) ) {
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 ( ) ;
2013-11-07 19:17:21 +01:00
}
2023-03-25 20:59:48 +01:00
if ( u = = v ) sel_end = total_width ;
}
Rect br = r . Shrink ( WidgetDimensions : : scaled . bevel ) ;
int width = br . Width ( ) ;
int skip = 0 ;
if ( total_width > width ) {
int sel_center = ( sel_start + sel_end ) / 2 ;
if ( sel_center > width / 2 ) skip = std : : min ( total_width - width , sel_center - width / 2 ) ;
2013-11-07 19:17:21 +01:00
}
2023-03-25 20:59:48 +01:00
GrfSpecFeature f = GetFeatureNum ( this - > window_number ) ;
int h = GetVehicleImageCellSize ( ( VehicleType ) ( VEH_TRAIN + ( f - GSF_TRAINS ) ) , EIT_IN_DEPOT ) . height ;
int y = CenterBounds ( br . top , br . bottom , h ) ;
DrawVehicleImage ( v - > First ( ) , br , 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 ) ;
}
}
2010-04-24 15:36:29 +02:00
2023-03-25 20:59:48 +01:00
/**
* Helper function to draw the main panel widget .
* @ param r The rectangle to draw within .
*/
void DrawMainPanelWidget ( const Rect & r ) const
{
2013-11-07 19:15:32 +01:00
uint index = this - > GetFeatureIndex ( ) ;
2010-04-24 15:36:29 +02: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 23:07:06 +02:00
if ( nif - > variables ! = nullptr ) {
2010-04-24 15:36:29 +02:00
this - > DrawString ( r , i + + , " Variables: " ) ;
2019-04-10 23:07:06 +02:00
for ( const NIVariable * niv = nif - > variables ; niv - > name ! = nullptr ; niv + + ) {
2010-04-24 15:36:29 +02:00
bool avail = true ;
2010-10-31 17:16:28 +01:00
uint param = HasVariableParameter ( niv - > var ) ? NewGRFInspectWindow : : var60params [ GetFeatureNum ( this - > window_number ) ] [ niv - > var - 0x60 ] : 0 ;
2010-04-24 15:36:29 +02:00
uint value = nih - > Resolve ( index , niv - > var , param , & avail ) ;
if ( ! avail ) continue ;
if ( HasVariableParameter ( niv - > var ) ) {
2023-04-19 21:38:09 +02:00
this - > DrawString ( r , i + + , fmt : : format ( " {:02x}[{:02x}]: {:08x} ({}) " , niv - > var , param , value , niv - > name ) ) ;
2010-04-24 15:36:29 +02:00
} else {
2023-04-19 21:38:09 +02:00
this - > DrawString ( r , i + + , fmt : : format ( " {:02x}: {:08x} ({}) " , niv - > var , value , niv - > name ) ) ;
2010-04-24 15:36:29 +02:00
}
}
}
2011-06-12 22:53:16 +02:00
uint psa_size = nih - > GetPSASize ( index , this - > caller_grfid ) ;
2023-05-08 19:01:06 +02:00
const int32_t * psa = nih - > GetPSAFirstPosition ( index , this - > caller_grfid ) ;
2019-04-10 23:07:06 +02:00
if ( psa_size ! = 0 & & psa ! = nullptr ) {
2011-06-12 22:53:16 +02:00
if ( nih - > PSAWithParameter ( ) ) {
2023-04-19 21:38:09 +02:00
this - > DrawString ( r , i + + , fmt : : format ( " Persistent storage [{:08X}]: " , BSWAP32 ( this - > caller_grfid ) ) ) ;
2011-06-12 22:53:16 +02:00
} else {
this - > DrawString ( r , i + + , " Persistent storage: " ) ;
}
2011-06-12 22:41:17 +02:00
assert ( psa_size % 4 = = 0 ) ;
for ( uint j = 0 ; j < psa_size ; j + = 4 , psa + = 4 ) {
2023-04-19 21:38:09 +02:00
this - > DrawString ( r , i + + , fmt : : format ( " {}: {} {} {} {} " , j , psa [ 0 ] , psa [ 1 ] , psa [ 2 ] , psa [ 3 ] ) ) ;
2010-04-24 15:36:29 +02:00
}
}
2019-04-10 23:07:06 +02:00
if ( nif - > properties ! = nullptr ) {
2010-04-24 15:36:29 +02:00
this - > DrawString ( r , i + + , " Properties: " ) ;
2019-04-10 23:07:06 +02:00
for ( const NIProperty * nip = nif - > properties ; nip - > name ! = nullptr ; nip + + ) {
2020-12-14 00:22:04 +01:00
const void * ptr = nip - > offset_proc ( base ) ;
2010-04-24 15:36:29 +02:00
uint value ;
switch ( nip - > read_size ) {
2023-05-08 19:01:06 +02:00
case 1 : value = * ( const uint8_t * ) ptr ; break ;
case 2 : value = * ( const uint16_t * ) ptr ; break ;
case 4 : value = * ( const uint32_t * ) ptr ; break ;
2010-04-24 15:36:29 +02:00
default : NOT_REACHED ( ) ;
}
StringID string ;
SetDParam ( 0 , value ) ;
switch ( nip - > type ) {
case NIT_INT :
string = STR_JUST_INT ;
break ;
case NIT_CARGO :
2023-05-04 12:29:21 +02:00
string = IsValidCargoID ( value ) ? CargoSpec : : Get ( value ) - > name : STR_QUANTITY_N_A ;
2010-04-24 15:36:29 +02:00
break ;
default :
NOT_REACHED ( ) ;
}
2023-05-31 17:16:31 +02:00
this - > DrawString ( r , i + + , fmt : : format ( " {:02x}: {} ({}) " , nip - > prop , GetString ( string ) , nip - > name ) ) ;
2010-04-24 15:36:29 +02:00
}
}
2019-04-10 23:07:06 +02:00
if ( nif - > callbacks ! = nullptr ) {
2010-04-24 15:36:29 +02:00
this - > DrawString ( r , i + + , " Callbacks: " ) ;
2019-04-10 23:07:06 +02:00
for ( const NICallback * nic = nif - > callbacks ; nic - > name ! = nullptr ; nic + + ) {
2010-04-24 15:36:29 +02:00
if ( nic - > cb_bit ! = CBM_NO_BIT ) {
2020-12-14 00:22:04 +01:00
const void * ptr = nic - > offset_proc ( base_spec ) ;
2010-04-24 15:36:29 +02:00
uint value ;
switch ( nic - > read_size ) {
2023-05-08 19:01:06 +02:00
case 1 : value = * ( const uint8_t * ) ptr ; break ;
case 2 : value = * ( const uint16_t * ) ptr ; break ;
case 4 : value = * ( const uint32_t * ) ptr ; break ;
2010-04-24 15:36:29 +02:00
default : NOT_REACHED ( ) ;
}
if ( ! HasBit ( value , nic - > cb_bit ) ) continue ;
2023-04-19 21:38:09 +02:00
this - > DrawString ( r , i + + , fmt : : format ( " {:03x}: {} " , nic - > cb_id , nic - > name ) ) ;
2010-04-24 15:36:29 +02:00
} else {
2023-04-19 21:38:09 +02:00
this - > DrawString ( r , i + + , fmt : : format ( " {:03x}: {} (unmasked) " , nic - > cb_id , nic - > name ) ) ;
2010-04-24 15:36:29 +02:00
}
}
}
/* 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 10:37:01 +02:00
const_cast < NewGRFInspectWindow * > ( this ) - > vscroll - > SetCount ( i ) ;
2010-04-24 15:36:29 +02:00
}
2023-03-25 20:59:48 +01:00
void DrawWidget ( const Rect & r , int widget ) const override
{
switch ( widget ) {
case WID_NGRFI_VEH_CHAIN :
this - > DrawVehicleChainWidget ( r ) ;
break ;
case WID_NGRFI_MAINPANEL :
this - > DrawMainPanelWidget ( r ) ;
break ;
}
}
2023-09-16 22:20:53 +02:00
void OnClick ( [[maybe_unused]] Point pt, int widget, [[maybe_unused]] int click_count ) override
2010-04-24 15:36:29 +02:00
{
switch ( widget ) {
2011-12-16 18:15:40 +01:00
case WID_NGRFI_PARENT : {
2011-06-12 22:51:38 +02:00
const NIHelper * nih = GetFeatureHelper ( this - > window_number ) ;
2013-11-07 19:15:32 +01:00
uint index = nih - > GetParent ( this - > GetFeatureIndex ( ) ) ;
2013-11-07 19:17:21 +01:00
: : ShowNewGRFInspectWindow ( GetFeatureNum ( index ) , : : GetFeatureIndex ( index ) , nih - > GetGRFID ( this - > GetFeatureIndex ( ) ) ) ;
2010-08-01 20:53:30 +02:00
break ;
}
2010-04-24 15:36:29 +02:00
2013-11-07 19:17:21 +01: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 23:07:06 +02:00
if ( v ! = nullptr & & v - > Next ( ) ! = nullptr ) {
2013-11-07 19:17:21 +01:00
this - > chain_index + + ;
this - > InvalidateData ( ) ;
}
}
break ;
2011-12-16 18:15:40 +01:00
case WID_NGRFI_MAINPANEL : {
2010-04-24 15:36:29 +02:00
/* Does this feature have variables? */
const NIFeature * nif = GetFeature ( this - > window_number ) ;
2019-04-10 23:07:06 +02:00
if ( nif - > variables = = nullptr ) return ;
2010-04-24 15:36:29 +02:00
/* Get the line, make sure it's within the boundaries. */
2022-09-23 10:36:22 +02:00
int line = this - > vscroll - > GetScrolledRowFromWidget ( pt . y , this , WID_NGRFI_MAINPANEL , WidgetDimensions : : scaled . frametext . top ) ;
2010-07-26 15:08:48 +02:00
if ( line = = INT_MAX ) return ;
2010-04-24 15:36:29 +02:00
/* Find the variable related to the line */
2019-04-10 23:07:06 +02:00
for ( const NIVariable * niv = nif - > variables ; niv - > name ! = nullptr ; niv + + , line - - ) {
2010-04-24 15:36:29 +02: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 18:23:30 +01:00
ShowQueryString ( STR_EMPTY , STR_NEWGRF_INSPECT_QUERY_CAPTION , 9 , this , CS_HEXADECIMAL , QSF_NONE ) ;
2010-04-24 15:36:29 +02:00
}
}
}
}
2019-03-04 08:49:37 +01:00
void OnQueryTextFinished ( char * str ) override
2010-04-24 15:36:29 +02:00
{
if ( StrEmpty ( str ) ) return ;
2023-04-26 13:56:14 +02:00
NewGRFInspectWindow : : var60params [ GetFeatureNum ( this - > window_number ) ] [ this - > current_edit_param - 0x60 ] = std : : strtol ( str , nullptr , 16 ) ;
2010-04-24 15:36:29 +02:00
this - > SetDirty ( ) ;
}
2019-03-04 08:49:37 +01:00
void OnResize ( ) override
2010-04-24 15:36:29 +02:00
{
2022-09-23 10:36:22 +02:00
this - > vscroll - > SetCapacityFromWidget ( this , WID_NGRFI_MAINPANEL , WidgetDimensions : : scaled . frametext . Vertical ( ) ) ;
2010-04-24 15:36:29 +02:00
}
2013-11-07 19:17:21 +01: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 .
*/
2023-09-16 22:20:53 +02:00
void OnInvalidateData ( [[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true ) override
2013-11-07 19:17:21 +01: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 23:07:06 +02:00
this - > SetWidgetDisabledState ( WID_NGRFI_VEH_NEXT , v = = nullptr | | v - > Next ( ) = = nullptr ) ;
2013-11-07 19:17:21 +01:00
}
}
2010-04-24 15:36:29 +02:00
} ;
2023-05-08 19:01:06 +02:00
/* static */ uint32_t NewGRFInspectWindow : : var60params [ GSF_FAKE_END ] [ 0x20 ] = { { 0 } } ; // Use spec to have 0s in whole array
2010-04-24 15:36:29 +02:00
2013-11-07 19:17:21 +01: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 15:36:29 +02:00
static const NWidgetPart _nested_newgrf_inspect_widgets [ ] = {
NWidget ( NWID_HORIZONTAL ) ,
NWidget ( WWT_CLOSEBOX , COLOUR_GREY ) ,
2011-12-16 18:15:40 +01: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 15:36:29 +02:00
NWidget ( WWT_SHADEBOX , COLOUR_GREY ) ,
2013-05-26 21:30:07 +02:00
NWidget ( WWT_DEFSIZEBOX , COLOUR_GREY ) ,
2010-04-24 15:36:29 +02:00
NWidget ( WWT_STICKYBOX , COLOUR_GREY ) ,
EndContainer ( ) ,
NWidget ( NWID_HORIZONTAL ) ,
2011-12-16 18:15:40 +01:00
NWidget ( WWT_PANEL , COLOUR_GREY , WID_NGRFI_MAINPANEL ) , SetMinimalSize ( 300 , 0 ) , SetScrollbar ( WID_NGRFI_SCROLLBAR ) , EndContainer ( ) ,
2010-04-24 15:36:29 +02:00
NWidget ( NWID_VERTICAL ) ,
2011-12-16 18:15:40 +01:00
NWidget ( NWID_VSCROLLBAR , COLOUR_GREY , WID_NGRFI_SCROLLBAR ) ,
2010-04-24 15:36:29 +02:00
NWidget ( WWT_RESIZEBOX , COLOUR_GREY ) ,
EndContainer ( ) ,
EndContainer ( ) ,
} ;
2023-11-02 20:33:01 +01:00
static WindowDesc _newgrf_inspect_chain_desc ( __FILE__ , __LINE__ ,
2013-11-07 19:17:21 +01:00
WDP_AUTO , " newgrf_inspect_chain " , 400 , 300 ,
WC_NEWGRF_INSPECT , WC_NONE ,
0 ,
2023-09-03 22:54:13 +02:00
std : : begin ( _nested_newgrf_inspect_chain_widgets ) , std : : end ( _nested_newgrf_inspect_chain_widgets )
2013-11-07 19:17:21 +01:00
) ;
2023-11-02 20:33:01 +01:00
static WindowDesc _newgrf_inspect_desc ( __FILE__ , __LINE__ ,
2013-05-26 21:25:01 +02:00
WDP_AUTO , " newgrf_inspect " , 400 , 300 ,
2010-04-24 15:36:29 +02:00
WC_NEWGRF_INSPECT , WC_NONE ,
2012-11-11 17:10:43 +01:00
0 ,
2023-09-03 22:54:13 +02:00
std : : begin ( _nested_newgrf_inspect_widgets ) , std : : end ( _nested_newgrf_inspect_widgets )
2010-04-24 15:36:29 +02:00
) ;
2011-01-22 10:53:15 +01: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 22:51:38 +02:00
* @ param grfid GRFID of the item opening this window , or 0 if not opened by other window .
2011-01-22 10:53:15 +01:00
*/
2023-05-08 19:01:06 +02:00
void ShowNewGRFInspectWindow ( GrfSpecFeature feature , uint index , const uint32_t grfid )
2010-04-24 15:36:29 +02:00
{
if ( ! IsNewGRFInspectable ( feature , index ) ) return ;
WindowNumber wno = GetInspectWindowNumber ( feature , index ) ;
2014-12-18 19:22:23 +01: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 22:51:38 +02:00
w - > SetCallerGRFID ( grfid ) ;
2010-04-24 15:36:29 +02:00
}
2013-11-07 19:17:21 +01: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 10:53:15 +01: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 15:36:29 +02:00
void DeleteNewGRFInspectWindow ( GrfSpecFeature feature , uint index )
{
if ( feature = = GSF_INVALID ) return ;
WindowNumber wno = GetInspectWindowNumber ( feature , index ) ;
2021-05-17 15:46:38 +02:00
CloseWindowById ( WC_NEWGRF_INSPECT , wno ) ;
2010-04-24 15:36:29 +02:00
2011-02-23 21:54:55 +01: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 22:48:06 +01:00
* the invalidation immediately . The landinfo window tests commands itself . */
2011-02-23 21:45:52 +01:00
InvalidateWindowData ( WC_LAND_INFO , 0 , 1 ) ;
2010-04-24 15:36:29 +02:00
}
2011-01-22 10:53:15 +01: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 15:36:29 +02:00
bool IsNewGRFInspectable ( GrfSpecFeature feature , uint index )
{
const NIFeature * nif = GetFeature ( GetInspectWindowNumber ( feature , index ) ) ;
2019-04-10 23:07:06 +02:00
if ( nif = = nullptr ) return false ;
2010-04-24 15:36:29 +02:00
return nif - > helper - > IsInspectable ( index ) ;
}
2011-01-22 10:53:15 +01:00
/**
* Get the GrfSpecFeature associated with the tile .
* @ param tile The tile to get the feature from .
* @ return the GrfSpecFeature .
*/
2010-04-24 15:36:29 +02:00
GrfSpecFeature GetGrfSpecFeature ( TileIndex tile )
{
switch ( GetTileType ( tile ) ) {
default : return GSF_INVALID ;
case MP_RAILWAY : return GSF_RAILTYPES ;
2023-09-20 23:54:34 +02:00
case MP_ROAD : return IsLevelCrossing ( tile ) ? GSF_RAILTYPES : GSF_ROADTYPES ;
2010-04-24 15:36:29 +02:00
case MP_HOUSE : return GSF_HOUSES ;
case MP_INDUSTRY : return GSF_INDUSTRYTILES ;
2010-08-28 21:48:46 +02:00
case MP_OBJECT : return GSF_OBJECTS ;
2010-04-24 15:36:29 +02:00
case MP_STATION :
switch ( GetStationType ( tile ) ) {
case STATION_RAIL : return GSF_STATIONS ;
case STATION_AIRPORT : return GSF_AIRPORTTILES ;
2022-11-06 16:01:27 +01:00
case STATION_BUS : return GSF_ROADSTOPS ;
case STATION_TRUCK : return GSF_ROADSTOPS ;
2010-04-24 15:36:29 +02:00
default : return GSF_INVALID ;
}
}
}
2011-01-22 10:53:15 +01:00
/**
* Get the GrfSpecFeature associated with the vehicle .
* @ param type The vehicle type to get the feature from .
* @ return the GrfSpecFeature .
*/
2010-04-24 15:36:29 +02: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 18:27:30 +02:00
/**** Sprite Aligner ****/
/** Window used for aligning sprites. */
struct SpriteAlignerWindow : Window {
2023-05-08 19:01:06 +02:00
typedef std : : pair < int16_t , int16_t > 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 09:17:14 +01:00
SpriteID current_sprite ; ///< The currently shown sprite.
2010-08-12 10:37:01 +02:00
Scrollbar * vscroll ;
2023-05-16 21:50:41 +02:00
std : : map < SpriteID , XyOffs > offs_start_map ; ///< Mapping of starting offsets for the sprites which have been aligned in the sprite aligner window.
2010-04-25 18:27:30 +02:00
2023-11-29 18:43:04 +01:00
static inline ZoomLevel zoom = ZOOM_LVL_END ;
2022-12-12 00:45:07 +01:00
static bool centre ;
static bool crosshair ;
2013-05-26 21:23:42 +02:00
SpriteAlignerWindow ( WindowDesc * desc , WindowNumber wno ) : Window ( desc )
2010-04-25 18:27:30 +02:00
{
2023-11-29 18:43:04 +01:00
/* On first opening, set initial zoom to current zoom level. */
if ( SpriteAlignerWindow : : zoom = = ZOOM_LVL_END ) SpriteAlignerWindow : : zoom = _gui_zoom ;
2013-05-26 21:23:42 +02:00
this - > CreateNestedTree ( ) ;
2011-12-16 18:15:40 +01:00
this - > vscroll = this - > GetScrollbar ( WID_SA_SCROLLBAR ) ;
2023-10-17 22:25:48 +02:00
this - > vscroll - > SetCount ( _newgrf_debug_sprite_picker . sprites . size ( ) ) ;
2013-05-26 21:23:42 +02:00
this - > FinishInitNested ( wno ) ;
2010-04-25 18:27:30 +02:00
2022-12-12 00:45:07 +01:00
this - > SetWidgetLoweredState ( WID_SA_CENTRE , SpriteAlignerWindow : : centre ) ;
this - > SetWidgetLoweredState ( WID_SA_CROSSHAIR , SpriteAlignerWindow : : crosshair ) ;
2010-04-25 18:27:30 +02:00
/* Oh yes, we assume there is at least one normal sprite! */
2023-04-16 21:00:55 +02:00
while ( GetSpriteType ( this - > current_sprite ) ! = SpriteType : : Normal ) this - > current_sprite + + ;
2023-11-29 18:43:04 +01:00
this - > InvalidateData ( 0 , true ) ;
2010-04-25 18:27:30 +02:00
}
2019-03-04 08:49:37 +01:00
void SetStringParameters ( int widget ) const override
2010-04-25 18:27:30 +02:00
{
2023-04-16 21:00:55 +02:00
const Sprite * spr = GetSprite ( this - > current_sprite , SpriteType : : Normal ) ;
2010-04-25 18:27:30 +02:00
switch ( widget ) {
2011-12-16 18:15:40 +01:00
case WID_SA_CAPTION :
2010-04-25 18:27:30 +02:00
SetDParam ( 0 , this - > current_sprite ) ;
2021-05-30 11:40:54 +02:00
SetDParamStr ( 1 , GetOriginFile ( this - > current_sprite ) - > GetSimplifiedFilename ( ) ) ;
2010-04-25 18:27:30 +02:00
break ;
2015-03-01 09:17:14 +01:00
case WID_SA_OFFSETS_ABS :
2023-11-29 18:43:04 +01:00
SetDParam ( 0 , UnScaleByZoom ( spr - > x_offs , SpriteAlignerWindow : : zoom ) ) ;
SetDParam ( 1 , UnScaleByZoom ( spr - > y_offs , SpriteAlignerWindow : : zoom ) ) ;
2010-08-01 20:53:30 +02:00
break ;
2015-03-01 09:17:14 +01: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 ) .
*/
2023-05-16 21:50:41 +02:00
const auto key_offs_pair = this - > offs_start_map . find ( this - > current_sprite ) ;
2019-02-17 12:20:52 +01:00
if ( key_offs_pair ! = this - > offs_start_map . end ( ) ) {
2023-11-29 18:43:04 +01:00
SetDParam ( 0 , UnScaleByZoom ( spr - > x_offs - key_offs_pair - > second . first , SpriteAlignerWindow : : zoom ) ) ;
SetDParam ( 1 , UnScaleByZoom ( spr - > y_offs - key_offs_pair - > second . second , SpriteAlignerWindow : : zoom ) ) ;
2015-03-01 09:17:14 +01:00
} else {
SetDParam ( 0 , 0 ) ;
SetDParam ( 1 , 0 ) ;
}
break ;
2010-08-01 20:53:30 +02:00
}
2010-04-25 18:27:30 +02:00
default :
break ;
}
}
2023-09-16 22:20:53 +02:00
void UpdateWidgetSize ( int widget , Dimension * size , [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension * resize ) override
2010-04-26 22:35:27 +02:00
{
2020-08-02 16:26:53 +02:00
switch ( widget ) {
case WID_SA_SPRITE :
size - > height = ScaleGUITrad ( 200 ) ;
break ;
case WID_SA_LIST :
2022-12-17 11:36:32 +01:00
SetDParamMaxDigits ( 0 , 6 ) ;
2023-04-25 10:45:05 +02:00
size - > width = GetStringBoundingBox ( STR_JUST_COMMA ) . width + padding . width ;
2023-11-21 20:04:24 +01:00
resize - > height = GetCharacterHeight ( FS_NORMAL ) + padding . height ;
2020-08-02 16:26:53 +02:00
resize - > width = 1 ;
2021-04-22 20:07:20 +02:00
fill - > height = resize - > height ;
2020-08-02 16:26:53 +02:00
break ;
default :
break ;
}
2010-04-26 22:35:27 +02:00
}
2019-03-04 08:49:37 +01:00
void DrawWidget ( const Rect & r , int widget ) const override
2010-04-25 18:27:30 +02:00
{
2010-04-26 22:35:27 +02:00
switch ( widget ) {
2011-12-16 18:15:40 +01:00
case WID_SA_SPRITE : {
2010-04-26 22:35:27 +02:00
/* Center the sprite ourselves */
2023-04-16 21:00:55 +02:00
const Sprite * spr = GetSprite ( this - > current_sprite , SpriteType : : Normal ) ;
2022-09-23 10:36:22 +02:00
Rect ir = r . Shrink ( WidgetDimensions : : scaled . bevel ) ;
2022-12-12 00:45:07 +01:00
int x ;
int y ;
if ( SpriteAlignerWindow : : centre ) {
2023-11-29 18:43:04 +01:00
x = - UnScaleByZoom ( spr - > x_offs , SpriteAlignerWindow : : zoom ) + ( ir . Width ( ) - UnScaleByZoom ( spr - > width , SpriteAlignerWindow : : zoom ) ) / 2 ;
y = - UnScaleByZoom ( spr - > y_offs , SpriteAlignerWindow : : zoom ) + ( ir . Height ( ) - UnScaleByZoom ( spr - > height , SpriteAlignerWindow : : zoom ) ) / 2 ;
2022-12-12 00:45:07 +01:00
} else {
x = ir . Width ( ) / 2 ;
y = ir . Height ( ) / 2 ;
}
2015-02-28 21:09:49 +01:00
DrawPixelInfo new_dpi ;
2022-10-15 17:55:47 +02:00
if ( ! FillDrawPixelInfo ( & new_dpi , ir . left , ir . top , ir . Width ( ) , ir . Height ( ) ) ) break ;
2023-01-26 19:21:36 +01:00
AutoRestoreBackup dpi_backup ( _cur_dpi , & new_dpi ) ;
2015-02-28 21:09:49 +01:00
2023-11-29 18:43:04 +01:00
DrawSprite ( this - > current_sprite , PAL_NONE , x , y , nullptr , SpriteAlignerWindow : : zoom ) ;
if ( SpriteAlignerWindow : : crosshair ) {
2022-12-12 00:45:07 +01:00
GfxDrawLine ( x , 0 , x , ir . Height ( ) - 1 , PC_WHITE , 1 , 1 ) ;
GfxDrawLine ( 0 , y , ir . Width ( ) - 1 , y , PC_WHITE , 1 , 1 ) ;
}
2010-04-26 22:35:27 +02:00
break ;
}
2011-12-16 18:15:40 +01:00
case WID_SA_LIST : {
2010-04-26 22:35:27 +02:00
const NWidgetBase * nwid = this - > GetWidget < NWidgetBase > ( widget ) ;
int step_size = nwid - > resize_y ;
2019-03-03 18:30:09 +01:00
std : : vector < SpriteID > & list = _newgrf_debug_sprite_picker . sprites ;
2021-01-08 11:16:18 +01:00
int max = std : : min < int > ( this - > vscroll - > GetPosition ( ) + this - > vscroll - > GetCapacity ( ) , ( uint ) list . size ( ) ) ;
2010-04-26 22:35:27 +02:00
2022-12-17 11:36:32 +01:00
Rect ir = r . Shrink ( WidgetDimensions : : scaled . matrix ) ;
2010-08-12 10:37:01 +02:00
for ( int i = this - > vscroll - > GetPosition ( ) ; i < max ; i + + ) {
2010-04-26 22:35:27 +02:00
SetDParam ( 0 , list [ i ] ) ;
2023-11-29 18:43:04 +01:00
DrawString ( ir , STR_JUST_COMMA , list [ i ] = = this - > current_sprite ? TC_WHITE : TC_BLACK , SA_RIGHT | SA_FORCE ) ;
2022-10-15 17:55:47 +02:00
ir . top + = step_size ;
2010-04-26 22:35:27 +02:00
}
break ;
}
}
2010-04-25 18:27:30 +02:00
}
2023-09-16 22:20:53 +02:00
void OnClick ( [[maybe_unused]] Point pt, int widget, [[maybe_unused]] int click_count ) override
2010-04-25 18:27:30 +02:00
{
switch ( widget ) {
2011-12-16 18:15:40 +01:00
case WID_SA_PREVIOUS :
2010-04-25 18:27:30 +02:00
do {
this - > current_sprite = ( this - > current_sprite = = 0 ? GetMaxSpriteID ( ) : this - > current_sprite ) - 1 ;
2023-04-16 21:00:55 +02:00
} while ( GetSpriteType ( this - > current_sprite ) ! = SpriteType : : Normal ) ;
2010-04-25 18:27:30 +02:00
this - > SetDirty ( ) ;
break ;
2011-12-16 18:15:40 +01:00
case WID_SA_GOTO :
2011-04-17 20:42:17 +02:00
ShowQueryString ( STR_EMPTY , STR_SPRITE_ALIGNER_GOTO_CAPTION , 7 , this , CS_NUMERAL , QSF_NONE ) ;
2010-04-25 18:27:30 +02:00
break ;
2011-12-16 18:15:40 +01:00
case WID_SA_NEXT :
2010-04-25 18:27:30 +02:00
do {
this - > current_sprite = ( this - > current_sprite + 1 ) % GetMaxSpriteID ( ) ;
2023-04-16 21:00:55 +02:00
} while ( GetSpriteType ( this - > current_sprite ) ! = SpriteType : : Normal ) ;
2010-04-25 18:27:30 +02:00
this - > SetDirty ( ) ;
break ;
2011-12-16 18:15:40 +01:00
case WID_SA_PICKER :
this - > LowerWidget ( WID_SA_PICKER ) ;
2010-04-26 22:35:27 +02:00
_newgrf_debug_sprite_picker . mode = SPM_WAIT_CLICK ;
this - > SetDirty ( ) ;
break ;
2011-12-16 18:15:40 +01:00
case WID_SA_LIST : {
2023-05-03 12:17:52 +02:00
auto it = this - > vscroll - > GetScrolledItemFromWidget ( _newgrf_debug_sprite_picker . sprites , pt . y , this , widget ) ;
if ( it ! = _newgrf_debug_sprite_picker . sprites . end ( ) ) {
SpriteID spr = * it ;
2023-04-16 21:00:55 +02:00
if ( GetSpriteType ( spr ) = = SpriteType : : Normal ) this - > current_sprite = spr ;
2010-04-26 22:35:27 +02:00
}
this - > SetDirty ( ) ;
break ;
}
2011-12-16 18:15:40 +01:00
case WID_SA_UP :
case WID_SA_DOWN :
case WID_SA_LEFT :
case WID_SA_RIGHT : {
2010-04-25 18:27:30 +02: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 .
*/
2023-04-16 21:00:55 +02:00
Sprite * spr = const_cast < Sprite * > ( GetSprite ( this - > current_sprite , SpriteType : : Normal ) ) ;
2015-03-01 09:17:14 +01:00
/* Remember the original offsets of the current sprite, if not already in mapping. */
2023-05-16 21:50:41 +02:00
if ( this - > offs_start_map . count ( this - > current_sprite ) = = 0 ) {
this - > offs_start_map [ this - > current_sprite ] = XyOffs ( spr - > x_offs , spr - > y_offs ) ;
2015-03-01 09:17:14 +01:00
}
2023-11-29 18:43:04 +01:00
int amt = ScaleByZoom ( _ctrl_pressed ? 8 : 1 , SpriteAlignerWindow : : zoom ) ;
2010-04-25 18:27:30 +02:00
switch ( widget ) {
2019-05-27 00:52:53 +02:00
/* Move eight units at a time if ctrl is pressed. */
2023-11-29 18:43:04 +01:00
case WID_SA_UP : spr - > y_offs - = amt ; break ;
case WID_SA_DOWN : spr - > y_offs + = amt ; break ;
case WID_SA_LEFT : spr - > x_offs - = amt ; break ;
case WID_SA_RIGHT : spr - > x_offs + = amt ; break ;
2010-04-25 18:27:30 +02:00
}
2013-01-08 23:46:42 +01:00
/* Of course, we need to redraw the sprite, but where is it used?
2010-04-25 18:27:30 +02:00
* Everywhere is a safe bet . */
MarkWholeScreenDirty ( ) ;
2010-08-01 20:53:30 +02:00
break ;
}
2015-03-01 09:17:14 +01:00
case WID_SA_RESET_REL :
/* Reset the starting offsets for the current sprite. */
2023-05-16 21:50:41 +02:00
this - > offs_start_map . erase ( this - > current_sprite ) ;
2015-03-01 09:17:14 +01:00
this - > SetDirty ( ) ;
break ;
2022-12-12 00:45:07 +01:00
case WID_SA_CENTRE :
SpriteAlignerWindow : : centre = ! SpriteAlignerWindow : : centre ;
this - > SetWidgetLoweredState ( widget , SpriteAlignerWindow : : centre ) ;
this - > SetDirty ( ) ;
break ;
case WID_SA_CROSSHAIR :
SpriteAlignerWindow : : crosshair = ! SpriteAlignerWindow : : crosshair ;
this - > SetWidgetLoweredState ( widget , SpriteAlignerWindow : : crosshair ) ;
this - > SetDirty ( ) ;
break ;
2023-11-29 18:43:04 +01:00
default :
if ( IsInsideBS ( widget , WID_SA_ZOOM , ZOOM_LVL_END ) ) {
SpriteAlignerWindow : : zoom = ZoomLevel ( widget - WID_SA_ZOOM ) ;
this - > InvalidateData ( 0 , true ) ;
}
break ;
2010-04-25 18:27:30 +02:00
}
}
2019-03-04 08:49:37 +01:00
void OnQueryTextFinished ( char * str ) override
2010-04-25 18:27:30 +02:00
{
if ( StrEmpty ( str ) ) return ;
this - > current_sprite = atoi ( str ) ;
if ( this - > current_sprite > = GetMaxSpriteID ( ) ) this - > current_sprite = 0 ;
2023-04-16 21:00:55 +02:00
while ( GetSpriteType ( this - > current_sprite ) ! = SpriteType : : Normal ) {
2010-04-25 18:27:30 +02:00
this - > current_sprite = ( this - > current_sprite + 1 ) % GetMaxSpriteID ( ) ;
}
this - > SetDirty ( ) ;
}
2010-04-26 22:35:27 +02:00
2011-03-13 22:31:29 +01: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 .
*/
2023-09-16 22:20:53 +02:00
void OnInvalidateData ( [[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true ) override
2010-04-26 22:35:27 +02:00
{
2011-03-13 22:31:29 +01:00
if ( ! gui_scope ) return ;
2010-04-26 22:35:27 +02:00
if ( data = = 1 ) {
/* Sprite picker finished */
2011-12-16 18:15:40 +01:00
this - > RaiseWidget ( WID_SA_PICKER ) ;
2023-05-07 17:10:56 +02:00
this - > vscroll - > SetCount ( _newgrf_debug_sprite_picker . sprites . size ( ) ) ;
2010-04-26 22:35:27 +02:00
}
2023-11-29 18:43:04 +01:00
for ( ZoomLevel z = ZOOM_LVL_NORMAL ; z < ZOOM_LVL_END ; z + + ) {
this - > SetWidgetsLoweredState ( SpriteAlignerWindow : : zoom = = z , WID_SA_ZOOM + z ) ;
}
2010-04-26 22:35:27 +02:00
}
2019-03-04 08:49:37 +01:00
void OnResize ( ) override
2010-04-26 22:35:27 +02:00
{
2011-12-16 18:15:40 +01:00
this - > vscroll - > SetCapacityFromWidget ( this , WID_SA_LIST ) ;
2010-04-26 22:35:27 +02:00
}
2010-04-25 18:27:30 +02:00
} ;
2022-12-12 00:45:07 +01:00
bool SpriteAlignerWindow : : centre = true ;
bool SpriteAlignerWindow : : crosshair = true ;
2010-04-25 18:27:30 +02:00
static const NWidgetPart _nested_sprite_aligner_widgets [ ] = {
NWidget ( NWID_HORIZONTAL ) ,
NWidget ( WWT_CLOSEBOX , COLOUR_GREY ) ,
2011-12-16 18:15:40 +01:00
NWidget ( WWT_CAPTION , COLOUR_GREY , WID_SA_CAPTION ) , SetDataTip ( STR_SPRITE_ALIGNER_CAPTION , STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS ) ,
2010-04-25 18:27:30 +02:00
NWidget ( WWT_SHADEBOX , COLOUR_GREY ) ,
NWidget ( WWT_STICKYBOX , COLOUR_GREY ) ,
EndContainer ( ) ,
NWidget ( WWT_PANEL , COLOUR_GREY ) ,
2023-10-25 02:44:41 +02:00
NWidget ( NWID_HORIZONTAL ) , SetPIP ( 0 , WidgetDimensions : : unscaled . hsep_wide , 0 ) , SetPadding ( WidgetDimensions : : unscaled . sparse ) ,
NWidget ( NWID_VERTICAL ) , SetPIP ( 0 , WidgetDimensions : : unscaled . vsep_sparse , 0 ) ,
NWidget ( NWID_HORIZONTAL , NC_EQUALSIZE ) , SetPIP ( 0 , WidgetDimensions : : unscaled . hsep_normal , 0 ) ,
2011-12-16 18:15:40 +01: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 22:35:27 +02:00
EndContainer ( ) ,
2023-10-25 02:44:41 +02:00
NWidget ( NWID_HORIZONTAL ) ,
2010-04-25 18:27:30 +02:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
2022-12-12 20:28:44 +01:00
NWidget ( WWT_PUSHIMGBTN , COLOUR_GREY , WID_SA_UP ) , SetDataTip ( SPR_ARROW_UP , STR_SPRITE_ALIGNER_MOVE_TOOLTIP ) , SetResize ( 0 , 0 ) , SetMinimalSize ( 11 , 11 ) ,
2010-04-25 18:27:30 +02:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
EndContainer ( ) ,
2023-10-25 02:44:41 +02:00
NWidget ( NWID_HORIZONTAL_LTR ) , SetPIP ( 0 , WidgetDimensions : : unscaled . hsep_wide , 0 ) ,
2010-04-26 22:35:27 +02:00
NWidget ( NWID_VERTICAL ) ,
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
2022-12-12 20:28:44 +01:00
NWidget ( WWT_PUSHIMGBTN , COLOUR_GREY , WID_SA_LEFT ) , SetDataTip ( SPR_ARROW_LEFT , STR_SPRITE_ALIGNER_MOVE_TOOLTIP ) , SetResize ( 0 , 0 ) , SetMinimalSize ( 11 , 11 ) ,
2010-04-26 22:35:27 +02:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
EndContainer ( ) ,
2011-12-16 18:15:40 +01:00
NWidget ( WWT_PANEL , COLOUR_DARK_BLUE , WID_SA_SPRITE ) , SetDataTip ( STR_NULL , STR_SPRITE_ALIGNER_SPRITE_TOOLTIP ) ,
2010-04-26 22:35:27 +02:00
EndContainer ( ) ,
NWidget ( NWID_VERTICAL ) ,
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
2022-12-12 20:28:44 +01:00
NWidget ( WWT_PUSHIMGBTN , COLOUR_GREY , WID_SA_RIGHT ) , SetDataTip ( SPR_ARROW_RIGHT , STR_SPRITE_ALIGNER_MOVE_TOOLTIP ) , SetResize ( 0 , 0 ) , SetMinimalSize ( 11 , 11 ) ,
2010-04-26 22:35:27 +02:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
EndContainer ( ) ,
2010-04-25 18:27:30 +02:00
EndContainer ( ) ,
2023-10-25 02:44:41 +02:00
NWidget ( NWID_HORIZONTAL ) ,
2010-04-25 18:27:30 +02:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
2022-12-12 20:28:44 +01:00
NWidget ( WWT_PUSHIMGBTN , COLOUR_GREY , WID_SA_DOWN ) , SetDataTip ( SPR_ARROW_DOWN , STR_SPRITE_ALIGNER_MOVE_TOOLTIP ) , SetResize ( 0 , 0 ) , SetMinimalSize ( 11 , 11 ) ,
2010-04-25 18:27:30 +02:00
NWidget ( NWID_SPACER ) , SetFill ( 1 , 1 ) ,
EndContainer ( ) ,
2023-10-25 02:44:41 +02:00
NWidget ( WWT_LABEL , COLOUR_GREY , WID_SA_OFFSETS_ABS ) , SetDataTip ( STR_SPRITE_ALIGNER_OFFSETS_ABS , STR_NULL ) , SetFill ( 1 , 0 ) ,
NWidget ( WWT_LABEL , COLOUR_GREY , WID_SA_OFFSETS_REL ) , SetDataTip ( STR_SPRITE_ALIGNER_OFFSETS_REL , STR_NULL ) , SetFill ( 1 , 0 ) ,
NWidget ( NWID_HORIZONTAL , NC_EQUALSIZE ) , SetPIP ( 0 , WidgetDimensions : : unscaled . hsep_normal , 0 ) ,
2022-12-12 00:45:07 +01:00
NWidget ( WWT_TEXTBTN_2 , COLOUR_GREY , WID_SA_CENTRE ) , SetDataTip ( STR_SPRITE_ALIGNER_CENTRE_OFFSET , STR_NULL ) , SetFill ( 1 , 0 ) ,
NWidget ( WWT_PUSHTXTBTN , COLOUR_GREY , WID_SA_RESET_REL ) , SetDataTip ( STR_SPRITE_ALIGNER_RESET_BUTTON , STR_SPRITE_ALIGNER_RESET_TOOLTIP ) , SetFill ( 1 , 0 ) ,
NWidget ( WWT_TEXTBTN , COLOUR_GREY , WID_SA_CROSSHAIR ) , SetDataTip ( STR_SPRITE_ALIGNER_CROSSHAIR , STR_NULL ) , SetFill ( 1 , 0 ) ,
2010-04-26 22:35:27 +02:00
EndContainer ( ) ,
2010-04-25 18:27:30 +02:00
EndContainer ( ) ,
2023-10-25 02:44:41 +02:00
NWidget ( NWID_VERTICAL ) , SetPIP ( 0 , WidgetDimensions : : unscaled . vsep_sparse , 0 ) ,
2011-12-16 18:15:40 +01: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 22:35:27 +02:00
NWidget ( NWID_HORIZONTAL ) ,
2013-06-30 16:36:31 +02: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 18:15:40 +01:00
NWidget ( NWID_VSCROLLBAR , COLOUR_GREY , WID_SA_SCROLLBAR ) ,
2010-04-26 22:35:27 +02:00
EndContainer ( ) ,
2023-11-29 18:43:04 +01:00
NWidget ( NWID_VERTICAL ) ,
NWidget ( WWT_TEXTBTN , COLOUR_GREY , WID_SA_ZOOM + ZOOM_LVL_NORMAL ) , SetDataTip ( STR_CONFIG_SETTING_ZOOM_LVL_MIN , STR_NULL ) , SetFill ( 1 , 0 ) ,
NWidget ( WWT_TEXTBTN , COLOUR_GREY , WID_SA_ZOOM + ZOOM_LVL_OUT_2X ) , SetDataTip ( STR_CONFIG_SETTING_ZOOM_LVL_IN_2X , STR_NULL ) , SetFill ( 1 , 0 ) ,
NWidget ( WWT_TEXTBTN , COLOUR_GREY , WID_SA_ZOOM + ZOOM_LVL_OUT_4X ) , SetDataTip ( STR_CONFIG_SETTING_ZOOM_LVL_NORMAL , STR_NULL ) , SetFill ( 1 , 0 ) ,
NWidget ( WWT_TEXTBTN , COLOUR_GREY , WID_SA_ZOOM + ZOOM_LVL_OUT_8X ) , SetDataTip ( STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X , STR_NULL ) , SetFill ( 1 , 0 ) ,
NWidget ( WWT_TEXTBTN , COLOUR_GREY , WID_SA_ZOOM + ZOOM_LVL_OUT_16X ) , SetDataTip ( STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X , STR_NULL ) , SetFill ( 1 , 0 ) ,
NWidget ( WWT_TEXTBTN , COLOUR_GREY , WID_SA_ZOOM + ZOOM_LVL_OUT_32X ) , SetDataTip ( STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X , STR_NULL ) , SetFill ( 1 , 0 ) ,
EndContainer ( ) ,
2010-04-25 18:27:30 +02:00
EndContainer ( ) ,
EndContainer ( ) ,
EndContainer ( ) ,
} ;
2023-11-02 20:33:01 +01:00
static WindowDesc _sprite_aligner_desc ( __FILE__ , __LINE__ ,
2013-05-26 21:25:01 +02:00
WDP_AUTO , " sprite_aligner " , 400 , 300 ,
2010-04-25 18:27:30 +02:00
WC_SPRITE_ALIGNER , WC_NONE ,
2012-11-11 17:10:43 +01:00
0 ,
2023-09-03 22:54:13 +02:00
std : : begin ( _nested_sprite_aligner_widgets ) , std : : end ( _nested_sprite_aligner_widgets )
2010-04-25 18:27:30 +02:00
) ;
2011-01-22 10:53:15 +01:00
/**
* Show the window for aligning sprites .
*/
2010-04-25 18:27:30 +02:00
void ShowSpriteAlignerWindow ( )
{
AllocateWindowDescFront < SpriteAlignerWindow > ( & _sprite_aligner_desc , 0 ) ;
}