From 6dc8be0332ce016f31511c71307d4d1385a8057d Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 15 Mar 2014 19:44:27 +0200 Subject: [PATCH 001/187] Android patches --- findversion.sh | 1 + src/debug.cpp | 6 ++++++ src/fontdetection.cpp | 9 ++++++--- src/music/libtimidity.cpp | 20 ++++++++++++++++++++ src/network/core/os_abstraction.h | 2 +- src/os/unix/crashlog_unix.cpp | 4 ++++ src/os/unix/unix.cpp | 7 ++++++- src/osk_gui.cpp | 13 +++++++++++++ src/script/api/script_date.cpp | 2 +- src/settings_gui.cpp | 12 ++++++------ src/sound/sdl_s.cpp | 7 +++++++ src/strings.cpp | 7 ++++--- src/strings_func.h | 2 +- src/video/sdl_v.cpp | 24 +++++++++++++++++++++--- 14 files changed, 97 insertions(+), 19 deletions(-) diff --git a/findversion.sh b/findversion.sh index c0d500a8fd..d9b57aa622 100755 --- a/findversion.sh +++ b/findversion.sh @@ -134,6 +134,7 @@ else REV_NR="" fi +MODIFIED="0" # This prevents Andorid build from connecting to a public servers if [ "$MODIFIED" -eq "2" ]; then REV="${REV}M" fi diff --git a/src/debug.cpp b/src/debug.cpp index dceae7ec49..d39e434576 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -16,6 +16,9 @@ #include "string_func.h" #include "fileio_func.h" #include "settings_type.h" +#ifdef __ANDROID__ +#include +#endif #include @@ -107,6 +110,9 @@ char *DumpDebugFacilityNames(char *buf, char *last) */ static void debug_print(const char *dbg, const char *buf) { +#ifdef __ANDROID__ + __android_log_print(ANDROID_LOG_INFO, "OpenTTD", "[%s] %s", dbg, buf); +#endif #if defined(ENABLE_NETWORK) if (_debug_socket != INVALID_SOCKET) { char buf2[1024 + 32]; diff --git a/src/fontdetection.cpp b/src/fontdetection.cpp index 82c4f354f6..c1dd6cdbd5 100644 --- a/src/fontdetection.cpp +++ b/src/fontdetection.cpp @@ -639,6 +639,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i if (fs != NULL) { int best_weight = -1; const char *best_font = NULL; + int best_missing_glypths = 65536; for (int i = 0; i < fs->nfont; i++) { FcPattern *font = fs->fonts[i]; @@ -664,12 +665,13 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i callback->SetFontNames(settings, (const char*)file); - bool missing = callback->FindMissingGlyphs(NULL); - DEBUG(freetype, 1, "Font \"%s\" misses%s glyphs", file, missing ? "" : " no"); + int missing = callback->FindMissingGlyphs(NULL); + DEBUG(freetype, 1, "Font \"%s\" misses %d glyphs for lang %s", file, missing, lang); - if (!missing) { + if (missing < best_missing_glypths) { best_weight = value; best_font = (const char *)file; + best_missing_glypths = missing; } } @@ -677,6 +679,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i ret = true; callback->SetFontNames(settings, best_font); InitFreeType(callback->Monospace()); + DEBUG(freetype, 1, "Selected font %s for lang %s", best_font, lang); } /* Clean up the list of filenames. */ diff --git a/src/music/libtimidity.cpp b/src/music/libtimidity.cpp index 92f17212c3..96534b6204 100644 --- a/src/music/libtimidity.cpp +++ b/src/music/libtimidity.cpp @@ -13,6 +13,7 @@ #include "../openttd.h" #include "../sound_type.h" #include "../debug.h" +#include "../core/math_func.hpp" #include "libtimidity.h" #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #if defined(PSP) #include #endif /* PSP */ @@ -51,6 +53,24 @@ static void AudioOutCallback(void *buf, unsigned int _reqn, void *userdata) } } #endif /* PSP */ +#ifdef __ANDROID__ +/* Android does not have Midi chip, we have to route the libtimidity output through SDL audio output */ +void Android_MidiMixMusic(Sint16 *stream, int len) +{ + if (_midi.status == MIDI_PLAYING) { + Sint16 buf[16384]; + while( len > 0 ) + { + int minlen = min(sizeof(buf), len); + mid_song_read_wave(_midi.song, stream, min(sizeof(buf), len*2)); + for( Uint16 i = 0; i < minlen; i++ ) + stream[i] += buf[i]; + stream += minlen; + len -= minlen; + } + } +} +#endif /* __ANDROID__ */ /** Factory for the libtimidity driver. */ static FMusicDriver_LibTimidity iFMusicDriver_LibTimidity; diff --git a/src/network/core/os_abstraction.h b/src/network/core/os_abstraction.h index 980c6f7f6d..a3760c5f2d 100644 --- a/src/network/core/os_abstraction.h +++ b/src/network/core/os_abstraction.h @@ -161,7 +161,7 @@ static inline void OTTDfreeaddrinfo(struct addrinfo *ai) # include /* According to glibc/NEWS, appeared in glibc-2.3. */ # if !defined(__sgi__) && !defined(SUNOS) && !defined(__MORPHOS__) && !defined(__BEOS__) && !defined(__HAIKU__) && !defined(__INNOTEK_LIBC__) \ - && !(defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)) && !defined(__dietlibc__) && !defined(HPUX) + && !(defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)) && !defined(__dietlibc__) && !defined(HPUX) && !defined(__ANDROID__) /* If for any reason ifaddrs.h does not exist on your system, comment out * the following two lines and an alternative way will be used to fetch * the list of IPs from the system. */ diff --git a/src/os/unix/crashlog_unix.cpp b/src/os/unix/crashlog_unix.cpp index 0960720d1a..b417bf2102 100644 --- a/src/os/unix/crashlog_unix.cpp +++ b/src/os/unix/crashlog_unix.cpp @@ -141,7 +141,11 @@ public: }; /** The signals we want our crash handler to handle. */ +#ifdef __ANDROID__ +static const int _signals_to_handle[] = { }; // Default Android signal handler will give us stack trace +#else static const int _signals_to_handle[] = { SIGSEGV, SIGABRT, SIGFPE, SIGBUS, SIGILL }; +#endif /** * Entry point for the crash handler. diff --git a/src/os/unix/unix.cpp b/src/os/unix/unix.cpp index 09bf6c6e70..6899b16f35 100644 --- a/src/os/unix/unix.cpp +++ b/src/os/unix/unix.cpp @@ -25,7 +25,7 @@ #ifdef __APPLE__ #include -#elif (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || defined(__GLIBC__) +#elif ((defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || defined(__GLIBC__)) && !defined(__ANDROID__) #define HAS_STATVFS #endif @@ -254,6 +254,11 @@ void cocoaSetupAutoreleasePool(); void cocoaReleaseAutoreleasePool(); #endif +#ifdef __ANDROID__ +#define main SDL_main +extern "C" int CDECL main(int, char *[]); +#endif + int CDECL main(int argc, char *argv[]) { int ret; diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp index 2516c4dbf6..d8d70e70c8 100644 --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -22,6 +22,9 @@ #include "table/sprites.h" #include "table/strings.h" +#ifdef __ANDROID__ +#include +#endif char _keyboard_opt[2][OSK_KEYBOARD_ENTRIES * 4 + 1]; static WChar _keyboard[2][OSK_KEYBOARD_ENTRIES]; @@ -413,6 +416,16 @@ void ShowOnScreenKeyboard(Window *parent, int button) GetKeyboardLayout(); new OskWindow(&_osk_desc, parent, button); +#ifdef __ANDROID__ + char text[256]; + SDL_ANDROID_GetScreenKeyboardTextInput(text, sizeof(text) - 1); /* Invoke Android built-in screen keyboard */ + OskWindow *osk = dynamic_cast(FindWindowById(WC_OSK, 0)); + osk->qs->text.Assign(text); + free(osk->orig_str_buf); + osk->orig_str_buf = strdup(osk->qs->text.buf); + + osk->SetDirty(); +#endif } /** diff --git a/src/script/api/script_date.cpp b/src/script/api/script_date.cpp index 6ff92debac..3fcc605db0 100644 --- a/src/script/api/script_date.cpp +++ b/src/script/api/script_date.cpp @@ -9,8 +9,8 @@ /** @file script_date.cpp Implementation of ScriptDate. */ +#include "../../stdafx.h" /* Have to be included before time.h, if we want UINT32_MAX macro defined on Android */ #include -#include "../../stdafx.h" #include "script_date.hpp" #include "../../date_func.h" diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 908ddadbf6..5775e73732 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -323,17 +323,17 @@ struct GameOptionsWindow : Window { switch (widget) { case WID_GO_BASE_GRF_DESCRIPTION: SetDParamStr(0, BaseGraphics::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); - DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_BLACK_RAW_STRING); + DrawString(r.left, r.right, r.top, STR_BLACK_RAW_STRING); break; case WID_GO_BASE_SFX_DESCRIPTION: SetDParamStr(0, BaseSounds::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); - DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_BLACK_RAW_STRING); + DrawString(r.left, r.right, r.top, STR_BLACK_RAW_STRING); break; case WID_GO_BASE_MUSIC_DESCRIPTION: SetDParamStr(0, BaseMusic::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); - DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_BLACK_RAW_STRING); + DrawString(r.left, r.right, r.top, STR_BLACK_RAW_STRING); break; } } @@ -344,7 +344,7 @@ struct GameOptionsWindow : Window { case WID_GO_BASE_GRF_DESCRIPTION: /* Find the biggest description for the default size. */ for (int i = 0; i < BaseGraphics::GetNumSets(); i++) { - SetDParamStr(0, BaseGraphics::GetSet(i)->GetDescription(GetCurrentLanguageIsoCode())); + SetDParamStr(0, "123"); size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); } break; @@ -363,7 +363,7 @@ struct GameOptionsWindow : Window { case WID_GO_BASE_SFX_DESCRIPTION: /* Find the biggest description for the default size. */ for (int i = 0; i < BaseSounds::GetNumSets(); i++) { - SetDParamStr(0, BaseSounds::GetSet(i)->GetDescription(GetCurrentLanguageIsoCode())); + SetDParamStr(0, "123"); size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); } break; @@ -371,7 +371,7 @@ struct GameOptionsWindow : Window { case WID_GO_BASE_MUSIC_DESCRIPTION: /* Find the biggest description for the default size. */ for (int i = 0; i < BaseMusic::GetNumSets(); i++) { - SetDParamStr(0, BaseMusic::GetSet(i)->GetDescription(GetCurrentLanguageIsoCode())); + SetDParamStr(0, "123"); size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); } break; diff --git a/src/sound/sdl_s.cpp b/src/sound/sdl_s.cpp index 7e1c3e9936..9e80418ba0 100644 --- a/src/sound/sdl_s.cpp +++ b/src/sound/sdl_s.cpp @@ -21,6 +21,10 @@ /** Factory for the SDL sound driver. */ static FSoundDriver_SDL iFSoundDriver_SDL; +#ifdef __ANDROID__ +extern void Android_MidiMixMusic(Sint16 *stream, int len); +#endif + /** * Callback that fills the sound buffer. * @param userdata Ignored. @@ -30,6 +34,9 @@ static FSoundDriver_SDL iFSoundDriver_SDL; static void CDECL fill_sound_buffer(void *userdata, Uint8 *stream, int len) { MxMixSamples(stream, len / 4); +#if defined(__ANDROID__) && defined(LIBTIMIDITY) + Android_MidiMixMusic((Sint16 *)stream, len / 2); +#endif } const char *SoundDriver_SDL::Start(const char * const *parm) diff --git a/src/strings.cpp b/src/strings.cpp index dcaa6ae292..faaffb8258 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -2005,7 +2005,7 @@ const char *GetCurrentLanguageIsoCode() * @return If glyphs are missing, return \c true, else return \c false. * @post If \c true is returned and str is not NULL, *str points to a string that is found to contain at least one missing glyph. */ -bool MissingGlyphSearcher::FindMissingGlyphs(const char **str) +int MissingGlyphSearcher::FindMissingGlyphs(const char **str) { InitFreeType(this->Monospace()); const Sprite *question_mark[FS_END]; @@ -2015,6 +2015,7 @@ bool MissingGlyphSearcher::FindMissingGlyphs(const char **str) } this->Reset(); + int missing = 0; for (const char *text = this->NextString(); text != NULL; text = this->NextString()) { FontSize size = this->DefaultSize(); if (str != NULL) *str = text; @@ -2025,11 +2026,11 @@ bool MissingGlyphSearcher::FindMissingGlyphs(const char **str) size = FS_LARGE; } else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) { /* The character is printable, but not in the normal font. This is the case we were testing for. */ - return true; + missing++; } } } - return false; + return missing; } /** Helper for searching through the language pack. */ diff --git a/src/strings_func.h b/src/strings_func.h index 2c7809d020..6be4992d69 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -235,7 +235,7 @@ public: */ virtual void SetFontNames(struct FreeTypeSettings *settings, const char *font_name) = 0; - bool FindMissingGlyphs(const char **str); + int FindMissingGlyphs(const char **str); }; void CheckForMissingGlyphs(bool base_font = true, MissingGlyphSearcher *search = NULL); diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index cad21955d0..3d80153229 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -25,6 +25,9 @@ #include "../fileio_func.h" #include "sdl_v.h" #include +#ifdef __ANDROID__ +#include +#endif static FVideoDriver_SDL iFVideoDriver_SDL; @@ -349,6 +352,15 @@ bool VideoDriver_SDL::CreateMainSurface(uint w, uint h) * surface, for example). */ _requested_hwpalette = want_hwpalette; +#ifdef __ANDROID__ + SDL_Rect r; + r.h = SDL_ListModes(NULL, 0)[0]->h / 10; + r.w = r.h; + r.x = SDL_ListModes(NULL, 0)[0]->w - r.w; + r.y = SDL_ListModes(NULL, 0)[0]->h - r.h; + SDL_ANDROID_SetScreenKeyboardButtonPos(SDL_ANDROID_SCREENKEYBOARD_BUTTON_TEXT, &r); +#endif + /* DO NOT CHANGE TO HWSURFACE, IT DOES NOT WORK */ newscreen = SDL_CALL SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE | (want_hwpalette ? SDL_HWPALETTE : 0) | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE)); if (newscreen == NULL) { @@ -521,6 +533,8 @@ static uint ConvertSdlKeyIntoMy(SDL_keysym *sym, WChar *character) if (sym->scancode == 49) key = WKC_BACKSPACE; #elif defined(__sgi__) if (sym->scancode == 22) key = WKC_BACKQUOTE; +#elif defined(__ANDROID__) + if (sym->scancode == SDLK_BACKQUOTE) key = WKC_BACKQUOTE; #else if (sym->scancode == 49) key = WKC_BACKQUOTE; #endif @@ -597,7 +611,7 @@ int VideoDriver_SDL::PollEvent() } HandleMouseEvents(); break; - +#ifndef __ANDROID__ case SDL_ACTIVEEVENT: if (!(ev.active.state & SDL_APPMOUSEFOCUS)) break; @@ -608,7 +622,7 @@ int VideoDriver_SDL::PollEvent() _cursor.in_window = false; } break; - +#endif /* not __ANDROID__ */ case SDL_QUIT: HandleExitGameRequest(); break; @@ -623,13 +637,14 @@ int VideoDriver_SDL::PollEvent() HandleKeypress(keycode, character); } break; - +#ifndef __ANDROID__ case SDL_VIDEORESIZE: { int w = max(ev.resize.w, 64); int h = max(ev.resize.h, 64); CreateMainSurface(w, h); break; } +#endif /* not __ANDROID__ */ case SDL_VIDEOEXPOSE: { /* Force a redraw of the entire screen. Note * that SDL 1.2 seems to do this automatically @@ -661,6 +676,9 @@ const char *VideoDriver_SDL::Start(const char * const *parm) SetupKeyboard(); _draw_threaded = GetDriverParam(parm, "no_threads") == NULL && GetDriverParam(parm, "no_thread") == NULL; +#ifdef __ANDROID__ + _draw_threaded = false; +#endif return NULL; } From d7b18a8e2d5fbd64cea3099a6ea318d0fe1b3493 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 15 Mar 2014 19:53:53 +0200 Subject: [PATCH 002/187] Detect version from git submodule --- config.lib | 2 +- findversion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.lib b/config.lib index 32fe4790ce..e7c2d4e82d 100644 --- a/config.lib +++ b/config.lib @@ -1035,7 +1035,7 @@ check_params() { # of the tags folder, the folder of the tag does not have a .svn folder # anymore and this fails to detect the subversion repository checkout. log 1 "checking revision... svn detection (tag)" - elif [ -d "$ROOT_DIR/.git" ] && [ -n "`git help 2>/dev/null`" ]; then + elif [ -e "$ROOT_DIR/.git" ] && [ -n "`git help 2>/dev/null`" ]; then log 1 "checking revision... git detection" elif [ -d "$ROOT_DIR/.hg" ] && [ -n "`hg help 2>/dev/null`" ]; then log 1 "checking revision... hg detection" diff --git a/findversion.sh b/findversion.sh index d9b57aa622..6f11113e64 100755 --- a/findversion.sh +++ b/findversion.sh @@ -84,7 +84,7 @@ if [ -d "$ROOT_DIR/.svn" ] || [ -d "$ROOT_DIR/../.svn" ]; then else REV="r$REV_NR" fi -elif [ -d "$ROOT_DIR/.git" ]; then +elif [ -e "$ROOT_DIR/.git" ]; then # We are a git checkout # Refresh the index to make sure file stat info is in sync, then look for modifications git update-index --refresh >/dev/null From 02d035fbefb37b7812fe53a4c0a73ae5eb3fde47 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 19 Oct 2013 11:48:29 +0000 Subject: [PATCH 003/187] Position of landscaping toolbar. --- src/airport_gui.cpp.orig | 574 ++ src/autoreplace_gui.cpp.orig | 624 +++ src/build_vehicle_gui.cpp.orig | 1427 +++++ src/error_gui.cpp.orig | 432 ++ src/gfx.cpp.orig | 1697 ++++++ src/gfx_func.h.orig | 226 + src/group_gui.cpp.orig | 891 +++ src/industry_gui.cpp.orig | 2718 +++++++++ src/lang/english.txt.orig | 4887 +++++++++++++++++ src/misc_gui.cpp.orig | 1213 ++++ src/osk_gui.cpp.orig | 460 ++ src/rail_gui.cpp.orig | 1991 +++++++ src/road_gui.cpp.orig | 1092 ++++ src/script/api/game/game_window.hpp.sq.orig | 1328 +++++ src/script/api/script_window.hpp.orig | 2579 +++++++++ .../api/template/template_window.hpp.sq.orig | 257 + src/settings.cpp.orig | 2174 ++++++++ src/settings.cpp.rej | 11 + src/settings_gui.cpp.orig | 2651 +++++++++ src/smallmap_gui.cpp.orig | 1827 ++++++ src/smallmap_gui.h.orig | 192 + src/station_base.h.orig | 534 ++ src/station_gui.cpp.orig | 2450 +++++++++ src/terraform_gui.cpp | 10 +- src/terraform_gui.cpp.orig | 760 +++ src/toolbar_gui.cpp.orig | 2228 ++++++++ src/toolbar_type.h | 23 + src/town_gui.cpp.orig | 1199 ++++ src/vehicle_gui.cpp.orig | 2841 ++++++++++ src/vehicle_gui.h.orig | 104 + src/video/sdl_v.cpp.orig | 868 +++ src/viewport.cpp.orig | 3012 ++++++++++ src/widget.cpp.orig | 2938 ++++++++++ src/window.cpp.orig | 3515 ++++++++++++ 34 files changed, 49724 insertions(+), 9 deletions(-) create mode 100644 src/airport_gui.cpp.orig create mode 100644 src/autoreplace_gui.cpp.orig create mode 100644 src/build_vehicle_gui.cpp.orig create mode 100644 src/error_gui.cpp.orig create mode 100644 src/gfx.cpp.orig create mode 100644 src/gfx_func.h.orig create mode 100644 src/group_gui.cpp.orig create mode 100644 src/industry_gui.cpp.orig create mode 100644 src/lang/english.txt.orig create mode 100644 src/misc_gui.cpp.orig create mode 100644 src/osk_gui.cpp.orig create mode 100644 src/rail_gui.cpp.orig create mode 100644 src/road_gui.cpp.orig create mode 100644 src/script/api/game/game_window.hpp.sq.orig create mode 100644 src/script/api/script_window.hpp.orig create mode 100644 src/script/api/template/template_window.hpp.sq.orig create mode 100644 src/settings.cpp.orig create mode 100644 src/settings.cpp.rej create mode 100644 src/settings_gui.cpp.orig create mode 100644 src/smallmap_gui.cpp.orig create mode 100644 src/smallmap_gui.h.orig create mode 100644 src/station_base.h.orig create mode 100644 src/station_gui.cpp.orig create mode 100644 src/terraform_gui.cpp.orig create mode 100644 src/toolbar_gui.cpp.orig create mode 100644 src/toolbar_type.h create mode 100644 src/town_gui.cpp.orig create mode 100644 src/vehicle_gui.cpp.orig create mode 100644 src/vehicle_gui.h.orig create mode 100644 src/video/sdl_v.cpp.orig create mode 100644 src/viewport.cpp.orig create mode 100644 src/widget.cpp.orig create mode 100644 src/window.cpp.orig diff --git a/src/airport_gui.cpp.orig b/src/airport_gui.cpp.orig new file mode 100644 index 0000000000..0ba237c024 --- /dev/null +++ b/src/airport_gui.cpp.orig @@ -0,0 +1,574 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file airport_gui.cpp The GUI for airports. */ + +#include "stdafx.h" +#include "window_gui.h" +#include "station_gui.h" +#include "terraform_gui.h" +#include "sound_func.h" +#include "window_func.h" +#include "strings_func.h" +#include "viewport_func.h" +#include "company_func.h" +#include "tilehighlight_func.h" +#include "company_base.h" +#include "station_type.h" +#include "newgrf_airport.h" +#include "newgrf_callbacks.h" +#include "widgets/dropdown_type.h" +#include "core/geometry_func.hpp" +#include "hotkeys.h" +#include "vehicle_func.h" +#include "gui.h" + +#include "widgets/airport_widget.h" + + +static AirportClassID _selected_airport_class; ///< the currently visible airport class +static int _selected_airport_index; ///< the index of the selected airport in the current class or -1 +static byte _selected_airport_layout; ///< selected airport layout number. + +static void ShowBuildAirportPicker(Window *parent); + +SpriteID GetCustomAirportSprite(const AirportSpec *as, byte layout); + +void CcBuildAirport(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + + if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); +} + +/** + * Place an airport. + * @param tile Position to put the new airport. + */ +static void PlaceAirport(TileIndex tile) +{ + if (_selected_airport_index == -1) return; + uint32 p2 = _ctrl_pressed; + SB(p2, 16, 16, INVALID_STATION); // no station to join + + uint32 p1 = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index)->GetIndex(); + p1 |= _selected_airport_layout << 8; + CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_AIRPORT | CMD_MSG(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE), CcBuildAirport, "" }; + ShowSelectStationIfNeeded(cmdcont, TileArea(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE)); +} + +/** Airport build toolbar window handler. */ +struct BuildAirToolbarWindow : Window { + int last_user_action; // Last started user action. + + BuildAirToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->InitNested(window_number); + if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); + this->last_user_action = WIDGET_LIST_END; + } + + ~BuildAirToolbarWindow() + { + if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_AT_AIRPORT: + if (HandlePlacePushButton(this, WID_AT_AIRPORT, SPR_CURSOR_AIRPORT, HT_RECT)) { + ShowBuildAirportPicker(this); + this->last_user_action = widget; + } + break; + + case WID_AT_DEMOLISH: + HandlePlacePushButton(this, WID_AT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); + this->last_user_action = widget; + break; + + default: break; + } + } + + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + switch (this->last_user_action) { + case WID_AT_AIRPORT: + PlaceAirport(tile); + break; + + case WID_AT_DEMOLISH: + PlaceProc_DemolishArea(tile); + break; + + default: NOT_REACHED(); + } + } + + virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + { + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + } + + virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + { + if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) { + GUIPlaceProcDragXY(select_proc, start_tile, end_tile); + } + } + + virtual void OnPlaceObjectAbort() + { + this->RaiseButtons(); + + DeleteWindowById(WC_BUILD_STATION, TRANSPORT_AIR); + DeleteWindowById(WC_SELECT_STATION, 0); + } + + static HotkeyList hotkeys; +}; + +/** + * Handler for global hotkeys of the BuildAirToolbarWindow. + * @param hotkey Hotkey + * @return ES_HANDLED if hotkey was accepted. + */ +static EventState AirportToolbarGlobalHotkeys(int hotkey) +{ + if (_game_mode != GM_NORMAL || !CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) return ES_NOT_HANDLED; + Window *w = ShowBuildAirToolbar(); + if (w == NULL) return ES_NOT_HANDLED; + return w->OnHotkey(hotkey); +} + +static Hotkey airtoolbar_hotkeys[] = { + Hotkey('1', "airport", WID_AT_AIRPORT), + Hotkey('2', "demolish", WID_AT_DEMOLISH), + HOTKEY_LIST_END +}; +HotkeyList BuildAirToolbarWindow::hotkeys("airtoolbar", airtoolbar_hotkeys, AirportToolbarGlobalHotkeys); + +static const NWidgetPart _nested_air_toolbar_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_TOOLBAR_AIRCRAFT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_AIRPORT), SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_AIRPORT, STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetFill(1, 1), EndContainer(), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_DEMOLISH), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), + EndContainer(), +}; + +static WindowDesc _air_toolbar_desc( + WDP_ALIGN_TOOLBAR, "toolbar_air", 0, 0, + WC_BUILD_TOOLBAR, WC_NONE, + WDF_CONSTRUCTION, + _nested_air_toolbar_widgets, lengthof(_nested_air_toolbar_widgets), + &BuildAirToolbarWindow::hotkeys +); + +/** + * Open the build airport toolbar window + * + * If the terraform toolbar is linked to the toolbar, that window is also opened. + * + * @return newly opened airport toolbar, or NULL if the toolbar could not be opened. + */ +Window *ShowBuildAirToolbar() +{ + if (!Company::IsValidID(_local_company)) return NULL; + + DeleteWindowByClass(WC_BUILD_TOOLBAR); + return AllocateWindowDescFront(&_air_toolbar_desc, TRANSPORT_AIR); +} + +class BuildAirportWindow : public PickerWindowBase { + SpriteID preview_sprite; ///< Cached airport preview sprite. + int line_height; + Scrollbar *vscroll; + + /** Build a dropdown list of available airport classes */ + static DropDownList *BuildAirportClassDropDown() + { + DropDownList *list = new DropDownList(); + + for (uint i = 0; i < AirportClass::GetClassCount(); i++) { + *list->Append() = new DropDownListStringItem(AirportClass::Get((AirportClassID)i)->name, i, false); + } + + return list; + } + +public: + BuildAirportWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) + { + this->CreateNestedTree(); + + this->vscroll = this->GetScrollbar(WID_AP_SCROLLBAR); + this->vscroll->SetCapacity(5); + this->vscroll->SetPosition(0); + + this->FinishInitNested(TRANSPORT_AIR); + + this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT, !_settings_client.gui.station_show_coverage); + this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT, _settings_client.gui.station_show_coverage); + this->OnInvalidateData(); + + this->vscroll->SetCount(AirportClass::Get(_selected_airport_class)->GetSpecCount()); + this->SelectFirstAvailableAirport(true); + } + + virtual ~BuildAirportWindow() + { + DeleteWindowById(WC_SELECT_STATION, 0); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_AP_CLASS_DROPDOWN: + SetDParam(0, AirportClass::Get(_selected_airport_class)->name); + break; + + case WID_AP_LAYOUT_NUM: + SetDParam(0, STR_EMPTY); + if (_selected_airport_index != -1) { + const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); + StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_LAYOUT_NAME); + if (string != STR_UNDEFINED) { + SetDParam(0, string); + } else if (as->num_table > 1) { + SetDParam(0, STR_STATION_BUILD_AIRPORT_LAYOUT_NAME); + SetDParam(1, _selected_airport_layout + 1); + } + } + break; + + default: break; + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_AP_CLASS_DROPDOWN: { + Dimension d = {0, 0}; + for (uint i = 0; i < AirportClass::GetClassCount(); i++) { + SetDParam(0, AirportClass::Get((AirportClassID)i)->name); + d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING)); + } + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_AP_AIRPORT_LIST: { + for (int i = 0; i < NUM_AIRPORTS; i++) { + const AirportSpec *as = AirportSpec::Get(i); + if (!as->enabled) continue; + + size->width = max(size->width, GetStringBoundingBox(as->name).width); + } + + this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + size->height = 5 * this->line_height; + break; + } + + case WID_AP_AIRPORT_SPRITE: + for (int i = 0; i < NUM_AIRPORTS; i++) { + const AirportSpec *as = AirportSpec::Get(i); + if (!as->enabled) continue; + for (byte layout = 0; layout < as->num_table; layout++) { + SpriteID sprite = GetCustomAirportSprite(as, layout); + if (sprite != 0) { + Dimension d = GetSpriteSize(sprite); + d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + *size = maxdim(d, *size); + } + } + } + break; + + case WID_AP_EXTRA_TEXT: + for (int i = NEW_AIRPORT_OFFSET; i < NUM_AIRPORTS; i++) { + const AirportSpec *as = AirportSpec::Get(i); + if (!as->enabled) continue; + for (byte layout = 0; layout < as->num_table; layout++) { + StringID string = GetAirportTextCallback(as, layout, CBID_AIRPORT_ADDITIONAL_TEXT); + if (string == STR_UNDEFINED) continue; + + /* STR_BLACK_STRING is used to start the string with {BLACK} */ + SetDParam(0, string); + Dimension d = GetStringMultiLineBoundingBox(STR_BLACK_STRING, *size); + *size = maxdim(d, *size); + } + } + break; + + default: break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_AP_AIRPORT_LIST: { + int y = r.top; + AirportClass *apclass = AirportClass::Get(_selected_airport_class); + for (uint i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < apclass->GetSpecCount(); i++) { + const AirportSpec *as = apclass->GetSpec(i); + if (!as->IsAvailable()) { + GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->line_height - 2, PC_BLACK, FILLRECT_CHECKER); + } + + DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, Center(y, this->line_height), as->name, ((int)i == _selected_airport_index) ? TC_WHITE : TC_BLACK); + + y += this->line_height; + } + break; + } + + case WID_AP_AIRPORT_SPRITE: + if (this->preview_sprite != 0) { + Dimension d = GetSpriteSize(this->preview_sprite); + DrawSprite(this->preview_sprite, COMPANY_SPRITE_COLOUR(_local_company), (r.left + r.right - d.width) / 2, (r.top + r.bottom - d.height) / 2); + } + break; + + case WID_AP_EXTRA_TEXT: + if (_selected_airport_index != -1) { + const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); + StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_ADDITIONAL_TEXT); + if (string != STR_UNDEFINED) { + SetDParam(0, string); + DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BLACK_STRING); + } + } + break; + } + } + + virtual void OnPaint() + { + this->DrawWidgets(); + + uint16 top = this->GetWidget(WID_AP_BTN_DOHILIGHT)->pos_y + this->GetWidget(WID_AP_BTN_DOHILIGHT)->current_y + WD_PAR_VSEP_NORMAL; + NWidgetBase *panel_nwi = this->GetWidget(WID_AP_BOTTOMPANEL); + + int right = panel_nwi->pos_x + panel_nwi->current_x; + int bottom = panel_nwi->pos_y + panel_nwi->current_y; + + if (_selected_airport_index != -1) { + const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); + int rad = _settings_game.station.modified_catchment ? as->catchment : (uint)CA_UNMODIFIED; + + /* only show the station (airport) noise, if the noise option is activated */ + if (_settings_game.economy.station_noise_level) { + /* show the noise of the selected airport */ + SetDParam(0, as->noise_level); + DrawString(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_STATION_BUILD_NOISE); + top += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + } + + /* strings such as 'Size' and 'Coverage Area' */ + top = DrawStationCoverageAreaText(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, false) + WD_PAR_VSEP_NORMAL; + top = DrawStationCoverageAreaText(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, true) + WD_PAR_VSEP_NORMAL; + } + + /* Resize background if the window is too small. + * Never make the window smaller to avoid oscillating if the size change affects the acceptance. + * (This is the case, if making the window bigger moves the mouse into the window.) */ + if (top > bottom) { + ResizeWindow(this, 0, top - bottom); + } + } + + void SelectOtherAirport(int airport_index) + { + _selected_airport_index = airport_index; + _selected_airport_layout = 0; + + this->UpdateSelectSize(); + this->SetDirty(); + } + + void UpdateSelectSize() + { + if (_selected_airport_index == -1) { + SetTileSelectSize(1, 1); + this->DisableWidget(WID_AP_LAYOUT_DECREASE); + this->DisableWidget(WID_AP_LAYOUT_INCREASE); + } else { + const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); + int w = as->size_x; + int h = as->size_y; + Direction rotation = as->rotation[_selected_airport_layout]; + if (rotation == DIR_E || rotation == DIR_W) Swap(w, h); + SetTileSelectSize(w, h); + + this->preview_sprite = GetCustomAirportSprite(as, _selected_airport_layout); + + this->SetWidgetDisabledState(WID_AP_LAYOUT_DECREASE, _selected_airport_layout == 0); + this->SetWidgetDisabledState(WID_AP_LAYOUT_INCREASE, _selected_airport_layout + 1 >= as->num_table); + + int rad = _settings_game.station.modified_catchment ? as->catchment : (uint)CA_UNMODIFIED; + if (_settings_client.gui.station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_AP_CLASS_DROPDOWN: + ShowDropDownList(this, BuildAirportClassDropDown(), _selected_airport_class, WID_AP_CLASS_DROPDOWN); + break; + + case WID_AP_AIRPORT_LIST: { + int num_clicked = this->vscroll->GetPosition() + (pt.y - this->nested_array[widget]->pos_y) / this->line_height; + if (num_clicked >= this->vscroll->GetCount()) break; + const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(num_clicked); + if (as->IsAvailable()) this->SelectOtherAirport(num_clicked); + break; + } + + case WID_AP_BTN_DONTHILIGHT: case WID_AP_BTN_DOHILIGHT: + _settings_client.gui.station_show_coverage = (widget != WID_AP_BTN_DONTHILIGHT); + this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT, !_settings_client.gui.station_show_coverage); + this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT, _settings_client.gui.station_show_coverage); + this->SetDirty(); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->UpdateSelectSize(); + break; + + case WID_AP_LAYOUT_DECREASE: + _selected_airport_layout--; + this->UpdateSelectSize(); + this->SetDirty(); + break; + + case WID_AP_LAYOUT_INCREASE: + _selected_airport_layout++; + this->UpdateSelectSize(); + this->SetDirty(); + break; + } + } + + /** + * Select the first available airport. + * @param change_class If true, change the class if no airport in the current + * class is available. + */ + void SelectFirstAvailableAirport(bool change_class) + { + /* First try to select an airport in the selected class. */ + AirportClass *sel_apclass = AirportClass::Get(_selected_airport_class); + for (uint i = 0; i < sel_apclass->GetSpecCount(); i++) { + const AirportSpec *as = sel_apclass->GetSpec(i); + if (as->IsAvailable()) { + this->SelectOtherAirport(i); + return; + } + } + if (change_class) { + /* If that fails, select the first available airport + * from a random class. */ + for (AirportClassID j = APC_BEGIN; j < APC_MAX; j++) { + AirportClass *apclass = AirportClass::Get(j); + for (uint i = 0; i < apclass->GetSpecCount(); i++) { + const AirportSpec *as = apclass->GetSpec(i); + if (as->IsAvailable()) { + _selected_airport_class = j; + this->SelectOtherAirport(i); + return; + } + } + } + } + /* If all airports are unavailable, select nothing. */ + this->SelectOtherAirport(-1); + } + + virtual void OnDropdownSelect(int widget, int index) + { + assert(widget == WID_AP_CLASS_DROPDOWN); + _selected_airport_class = (AirportClassID)index; + this->vscroll->SetCount(AirportClass::Get(_selected_airport_class)->GetSpecCount()); + this->SelectFirstAvailableAirport(false); + } + + virtual void OnTick() + { + CheckRedrawStationCoverage(this); + } +}; + +static const NWidgetPart _nested_build_airport_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 0), SetPIP(2, 0, 2), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL, STR_NULL), SetFill(1, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_AP_CLASS_DROPDOWN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_STATION_BUILD_AIRPORT_TOOLTIP), + NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_AIRPORT_SPRITE), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_AP_AIRPORT_LIST), SetFill(1, 0), SetMatrixDataTip(1, 5, STR_STATION_BUILD_AIRPORT_TOOLTIP), SetScrollbar(WID_AP_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AP_SCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_DECREASE), SetMinimalSize(12, 0), SetDataTip(AWV_DECREASE, STR_NULL), + NWidget(WWT_LABEL, COLOUR_GREY, WID_AP_LAYOUT_NUM), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NULL), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_INCREASE), SetMinimalSize(12, 0), SetDataTip(AWV_INCREASE, STR_NULL), + EndContainer(), + NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_EXTRA_TEXT), SetFill(1, 0), SetMinimalSize(150, 0), + EndContainer(), + /* Bottom panel. */ + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_AP_BOTTOMPANEL), SetPIP(2, 2, 2), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DONTHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), + SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DOHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), + SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1), SetFill(1, 0), + EndContainer(), +}; + +static WindowDesc _build_airport_desc( + WDP_AUTO, "build_station_air", 0, 0, + WC_BUILD_STATION, WC_BUILD_TOOLBAR, + WDF_CONSTRUCTION, + _nested_build_airport_widgets, lengthof(_nested_build_airport_widgets) +); + +static void ShowBuildAirportPicker(Window *parent) +{ + new BuildAirportWindow(&_build_airport_desc, parent); +} + +void InitializeAirportGui() +{ + _selected_airport_class = APC_BEGIN; + _selected_airport_index = -1; +} diff --git a/src/autoreplace_gui.cpp.orig b/src/autoreplace_gui.cpp.orig new file mode 100644 index 0000000000..dc1f5ed738 --- /dev/null +++ b/src/autoreplace_gui.cpp.orig @@ -0,0 +1,624 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file autoreplace_gui.cpp GUI for autoreplace handling. */ + +#include "stdafx.h" +#include "command_func.h" +#include "vehicle_gui.h" +#include "newgrf_engine.h" +#include "rail.h" +#include "strings_func.h" +#include "window_func.h" +#include "autoreplace_func.h" +#include "company_func.h" +#include "engine_base.h" +#include "window_gui.h" +#include "engine_gui.h" +#include "settings_func.h" +#include "core/geometry_func.hpp" +#include "rail_gui.h" +#include "widgets/dropdown_func.h" + +#include "widgets/autoreplace_widget.h" + + +uint GetEngineListHeight(VehicleType type); +void DrawEngineList(VehicleType type, int x, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group); + +static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b) +{ + int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; + + return r; +} + +/** + * Rebuild the left autoreplace list if an engine is removed or added + * @param e Engine to check if it is removed or added + * @param id_g The group the engine belongs to + * Note: this function only works if it is called either + * - when a new vehicle is build, but before it's counted in num_engines + * - when a vehicle is deleted and after it's subtracted from num_engines + * - when not changing the count (used when changing replace orders) + */ +void InvalidateAutoreplaceWindow(EngineID e, GroupID id_g) +{ + if (GetGroupNumEngines(_local_company, id_g, e) == 0 || GetGroupNumEngines(_local_company, ALL_GROUP, e) == 0) { + /* We don't have any of this engine type. + * Either we just sold the last one, we build a new one or we stopped replacing it. + * In all cases, we need to update the left list */ + InvalidateWindowData(WC_REPLACE_VEHICLE, Engine::Get(e)->type, 1); + } +} + +/** + * When an engine is made buildable or is removed from being buildable, add/remove it from the build/autoreplace lists + * @param type The type of engine + */ +void AddRemoveEngineFromAutoreplaceAndBuildWindows(VehicleType type) +{ + InvalidateWindowData(WC_REPLACE_VEHICLE, type, 0); // Update the autoreplace window + InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well +} + +static const StringID _start_replace_dropdown[] = { + STR_REPLACE_VEHICLES_NOW, + STR_REPLACE_VEHICLES_WHEN_OLD, + INVALID_STRING_ID +}; + +/** + * Window for the autoreplacing of vehicles. + */ +class ReplaceVehicleWindow : public Window { + EngineID sel_engine[2]; ///< Selected engine left and right. + GUIEngineList engines[2]; ///< Left and right list of engines. + bool replace_engines; ///< If \c true, engines are replaced, if \c false, wagons are replaced (only for trains). + bool reset_sel_engine; ///< Also reset #sel_engine while updating left and/or right (#update_left and/or #update_right) and no valid engine selected. + GroupID sel_group; ///< Group selected to replace. + int details_height; ///< Minimal needed height of the details panels (found so far). + RailType sel_railtype; ///< Type of rail tracks selected. + Scrollbar *vscroll[2]; + + /** + * Figure out if an engine should be added to a list. + * @param e The EngineID. + * @param draw_left If \c true, the left list is drawn (the engines specific to the railtype you selected). + * @param show_engines If \c true, the locomotives are drawn, else the wagons are drawn (never both). + * @return \c true if the engine should be in the list (based on this check), else \c false. + */ + bool GenerateReplaceRailList(EngineID e, bool draw_left, bool show_engines) + { + const RailVehicleInfo *rvi = RailVehInfo(e); + + /* Ensure that the wagon/engine selection fits the engine. */ + if ((rvi->railveh_type == RAILVEH_WAGON) == show_engines) return false; + + if (draw_left && show_engines) { + /* Ensure that the railtype is specific to the selected one */ + if (rvi->railtype != this->sel_railtype) return false; + } + return true; + } + + + /** + * Generate an engines list + * @param draw_left true if generating the left list, otherwise false + */ + void GenerateReplaceVehList(bool draw_left) + { + EngineID selected_engine = INVALID_ENGINE; + VehicleType type = (VehicleType)this->window_number; + byte side = draw_left ? 0 : 1; + + GUIEngineList *list = &this->engines[side]; + list->Clear(); + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, type) { + EngineID eid = e->index; + if (type == VEH_TRAIN && !this->GenerateReplaceRailList(eid, draw_left, this->replace_engines)) continue; // special rules for trains + + if (draw_left) { + const uint num_engines = GetGroupNumEngines(_local_company, this->sel_group, eid); + + /* Skip drawing the engines we don't have any of and haven't set for replacement */ + if (num_engines == 0 && EngineReplacementForCompany(Company::Get(_local_company), eid, this->sel_group) == INVALID_ENGINE) continue; + } else { + if (!CheckAutoreplaceValidity(this->sel_engine[0], eid, _local_company)) continue; + } + + *list->Append() = eid; + if (eid == this->sel_engine[side]) selected_engine = eid; // The selected engine is still in the list + } + this->sel_engine[side] = selected_engine; // update which engine we selected (the same or none, if it's not in the list anymore) + EngList_Sort(list, &EngineNumberSorter); + } + + /** Generate the lists */ + void GenerateLists() + { + EngineID e = this->sel_engine[0]; + + if (this->engines[0].NeedRebuild()) { + /* We need to rebuild the left engines list */ + this->GenerateReplaceVehList(true); + this->vscroll[0]->SetCount(this->engines[0].Length()); + if (this->reset_sel_engine && this->sel_engine[0] == INVALID_ENGINE && this->engines[0].Length() != 0) { + this->sel_engine[0] = this->engines[0][0]; + } + } + + if (this->engines[1].NeedRebuild() || e != this->sel_engine[0]) { + /* Either we got a request to rebuild the right engines list, or the left engines list selected a different engine */ + if (this->sel_engine[0] == INVALID_ENGINE) { + /* Always empty the right engines list when nothing is selected in the left engines list */ + this->engines[1].Clear(); + this->sel_engine[1] = INVALID_ENGINE; + } else { + if (this->reset_sel_engine && this->sel_engine[0] != INVALID_ENGINE) { + /* Select the current replacement for sel_engine[0]. */ + const Company *c = Company::Get(_local_company); + this->sel_engine[1] = EngineReplacementForCompany(c, this->sel_engine[0], this->sel_group); + } + /* Regenerate the list on the right. Note: This resets sel_engine[1] to INVALID_ENGINE, if it is no longer available. */ + this->GenerateReplaceVehList(false); + this->vscroll[1]->SetCount(this->engines[1].Length()); + if (this->reset_sel_engine && this->sel_engine[1] != INVALID_ENGINE) { + int position = 0; + for (EngineID *it = this->engines[1].Begin(); it != this->engines[1].End(); ++it) { + if (*it == this->sel_engine[1]) break; + ++position; + } + this->vscroll[1]->ScrollTowards(position); + } + } + } + /* Reset the flags about needed updates */ + this->engines[0].RebuildDone(); + this->engines[1].RebuildDone(); + this->reset_sel_engine = false; + } + + /** + * Handle click on the start replace button. + * @param replace_when_old Replace now or only when old? + */ + void ReplaceClick_StartReplace(bool replace_when_old) + { + EngineID veh_from = this->sel_engine[0]; + EngineID veh_to = this->sel_engine[1]; + DoCommandP(0, (replace_when_old ? 1 : 0) | (this->sel_group << 16), veh_from + (veh_to << 16), CMD_SET_AUTOREPLACE); + } + +public: + ReplaceVehicleWindow(WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc) + { + if (vehicletype == VEH_TRAIN) { + /* For rail vehicles find the most used vehicle type, which is usually + * better than 'just' the first/previous vehicle type. */ + uint type_count[RAILTYPE_END]; + memset(type_count, 0, sizeof(type_count)); + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { + if (e->u.rail.railveh_type == RAILVEH_WAGON) continue; + type_count[e->u.rail.railtype] += GetGroupNumEngines(_local_company, id_g, e->index); + } + + this->sel_railtype = RAILTYPE_BEGIN; + for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) { + if (type_count[this->sel_railtype] < type_count[rt]) this->sel_railtype = rt; + } + } + + this->replace_engines = true; // start with locomotives (all other vehicles will not read this bool) + this->engines[0].ForceRebuild(); + this->engines[1].ForceRebuild(); + this->reset_sel_engine = true; + this->details_height = ((vehicletype == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + this->sel_engine[0] = INVALID_ENGINE; + this->sel_engine[1] = INVALID_ENGINE; + + this->CreateNestedTree(); + this->vscroll[0] = this->GetScrollbar(WID_RV_LEFT_SCROLLBAR); + this->vscroll[1] = this->GetScrollbar(WID_RV_RIGHT_SCROLLBAR); + this->FinishInitNested(vehicletype); + + this->owner = _local_company; + this->sel_group = id_g; + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_RV_LEFT_MATRIX: + case WID_RV_RIGHT_MATRIX: + resize->height = GetEngineListHeight((VehicleType)this->window_number); + size->height = (this->window_number <= VEH_ROAD ? 8 : 4) * resize->height; + break; + + case WID_RV_LEFT_DETAILS: + case WID_RV_RIGHT_DETAILS: + size->height = this->details_height; + break; + + case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: { + StringID str = this->GetWidget(widget)->widget_data; + SetDParam(0, STR_CONFIG_SETTING_ON); + Dimension d = GetStringBoundingBox(str); + SetDParam(0, STR_CONFIG_SETTING_OFF); + d = maxdim(d, GetStringBoundingBox(str)); + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_RV_TRAIN_ENGINEWAGON_TOGGLE: { + StringID str = this->GetWidget(widget)->widget_data; + SetDParam(0, STR_REPLACE_ENGINES); + Dimension d = GetStringBoundingBox(str); + SetDParam(0, STR_REPLACE_WAGONS); + d = maxdim(d, GetStringBoundingBox(str)); + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_RV_INFO_TAB: { + SetDParam(0, STR_REPLACE_NOT_REPLACING); + Dimension d = GetStringBoundingBox(STR_BLACK_STRING); + SetDParam(0, STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED); + d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING)); + d.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; + d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + *size = maxdim(*size, d); + break; + } + + case WID_RV_TRAIN_RAILTYPE_DROPDOWN: { + Dimension d = {0, 0}; + for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + const RailtypeInfo *rti = GetRailTypeInfo(rt); + /* Skip rail type if it has no label */ + if (rti->label == 0) continue; + d = maxdim(d, GetStringBoundingBox(rti->strings.replace_text)); + } + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_RV_START_REPLACE: { + Dimension d = GetStringBoundingBox(STR_REPLACE_VEHICLES_START); + for (int i = 0; _start_replace_dropdown[i] != INVALID_STRING_ID; i++) { + d = maxdim(d, GetStringBoundingBox(_start_replace_dropdown[i])); + } + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + } + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_RV_CAPTION: + SetDParam(0, STR_REPLACE_VEHICLE_TRAIN + this->window_number); + switch (this->sel_group) { + case ALL_GROUP: + SetDParam(1, STR_GROUP_ALL_TRAINS + this->window_number); + break; + + case DEFAULT_GROUP: + SetDParam(1, STR_GROUP_DEFAULT_TRAINS + this->window_number); + break; + + default: + SetDParam(1, STR_GROUP_NAME); + SetDParam(2, sel_group); + break; + } + break; + + case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: { + const Company *c = Company::Get(_local_company); + SetDParam(0, c->settings.renew_keep_length ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); + break; + } + + case WID_RV_TRAIN_ENGINEWAGON_TOGGLE: + SetDParam(0, this->replace_engines ? STR_REPLACE_ENGINES : STR_REPLACE_WAGONS); + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_RV_INFO_TAB: { + const Company *c = Company::Get(_local_company); + if (this->sel_engine[0] != INVALID_ENGINE) { + if (!EngineHasReplacementForCompany(c, this->sel_engine[0], this->sel_group)) { + SetDParam(0, STR_REPLACE_NOT_REPLACING); + } else { + bool when_old = false; + EngineID e = EngineReplacementForCompany(c, this->sel_engine[0], this->sel_group, &when_old); + SetDParam(0, when_old ? STR_REPLACE_REPLACING_WHEN_OLD : STR_ENGINE_NAME); + SetDParam(1, e); + } + } else { + SetDParam(0, STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED); + } + + DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_BLACK_STRING, TC_FROMSTRING, SA_HOR_CENTER); + break; + } + + case WID_RV_LEFT_MATRIX: + case WID_RV_RIGHT_MATRIX: { + int side = (widget == WID_RV_LEFT_MATRIX) ? 0 : 1; + EngineID start = this->vscroll[side]->GetPosition(); // what is the offset for the start (scrolling) + EngineID end = min(this->vscroll[side]->GetCapacity() + start, this->engines[side].Length()); + + /* Do the actual drawing */ + DrawEngineList((VehicleType)this->window_number, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, + &this->engines[side], start, end, this->sel_engine[side], side == 0, this->sel_group); + break; + } + } + } + + virtual void OnPaint() + { + if (this->engines[0].NeedRebuild() || this->engines[1].NeedRebuild()) this->GenerateLists(); + + Company *c = Company::Get(_local_company); + + /* Disable the "Start Replacing" button if: + * Either engines list is empty + * or The selected replacement engine has a replacement (to prevent loops). */ + this->SetWidgetDisabledState(WID_RV_START_REPLACE, + this->sel_engine[0] == INVALID_ENGINE || + this->sel_engine[1] == INVALID_ENGINE || + EngineReplacementForCompany(c, this->sel_engine[1], this->sel_group) != INVALID_ENGINE); + + /* Disable the "Stop Replacing" button if: + * The left engines list (existing vehicle) is empty + * or The selected vehicle has no replacement set up */ + this->SetWidgetDisabledState(WID_RV_STOP_REPLACE, + this->sel_engine[0] == INVALID_ENGINE || + !EngineHasReplacementForCompany(c, this->sel_engine[0], this->sel_group)); + + if (this->window_number == VEH_TRAIN) { + /* sets the colour of that art thing */ + this->GetWidget(WID_RV_TRAIN_FLUFF_LEFT)->colour = _company_colours[_local_company]; + this->GetWidget(WID_RV_TRAIN_FLUFF_RIGHT)->colour = _company_colours[_local_company]; + + /* Show the selected railtype in the pulldown menu */ + this->GetWidget(WID_RV_TRAIN_RAILTYPE_DROPDOWN)->widget_data = GetRailTypeInfo(sel_railtype)->strings.replace_text; + } + + this->DrawWidgets(); + + if (!this->IsShaded()) { + int needed_height = this->details_height; + /* Draw details panels. */ + for (int side = 0; side < 2; side++) { + if (this->sel_engine[side] != INVALID_ENGINE) { + NWidgetBase *nwi = this->GetWidget(side == 0 ? WID_RV_LEFT_DETAILS : WID_RV_RIGHT_DETAILS); + int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, + nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine[side]); + needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); + } + } + if (needed_height != this->details_height) { // Details window are not high enough, enlarge them. + this->details_height = needed_height; + this->ReInit(); + return; + } + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_RV_TRAIN_ENGINEWAGON_TOGGLE: + this->replace_engines = !(this->replace_engines); + this->engines[0].ForceRebuild(); + this->reset_sel_engine = true; + this->SetDirty(); + break; + + case WID_RV_TRAIN_RAILTYPE_DROPDOWN: // Railtype selection dropdown menu + ShowDropDownList(this, GetRailTypeDropDownList(true), sel_railtype, WID_RV_TRAIN_RAILTYPE_DROPDOWN); + break; + + case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: // toggle renew_keep_length + DoCommandP(0, GetCompanySettingIndex("company.renew_keep_length"), Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1, CMD_CHANGE_COMPANY_SETTING); + break; + + case WID_RV_START_REPLACE: { // Start replacing + if (this->GetWidget(widget)->ButtonHit(pt)) { + this->HandleButtonClick(WID_RV_START_REPLACE); + ReplaceClick_StartReplace(false); + } else { + bool replacment_when_old = EngineHasReplacementWhenOldForCompany(Company::Get(_local_company), this->sel_engine[0], this->sel_group); + ShowDropDownMenu(this, _start_replace_dropdown, replacment_when_old ? 1 : 0, WID_RV_START_REPLACE, !this->replace_engines ? 1 << 1 : 0, 0); + } + break; + } + + case WID_RV_STOP_REPLACE: { // Stop replacing + EngineID veh_from = this->sel_engine[0]; + DoCommandP(0, this->sel_group << 16, veh_from + (INVALID_ENGINE << 16), CMD_SET_AUTOREPLACE); + break; + } + + case WID_RV_LEFT_MATRIX: + case WID_RV_RIGHT_MATRIX: { + byte click_side; + if (widget == WID_RV_LEFT_MATRIX) { + click_side = 0; + } else { + click_side = 1; + } + uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget); + size_t engine_count = this->engines[click_side].Length(); + + EngineID e = engine_count > i ? this->engines[click_side][i] : INVALID_ENGINE; + if (e == this->sel_engine[click_side]) break; // we clicked the one we already selected + this->sel_engine[click_side] = e; + if (click_side == 0) { + this->engines[1].ForceRebuild(); + this->reset_sel_engine = true; + } + this->SetDirty(); + break; + } + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + switch (widget) { + case WID_RV_TRAIN_RAILTYPE_DROPDOWN: { + RailType temp = (RailType)index; + if (temp == sel_railtype) return; // we didn't select a new one. No need to change anything + sel_railtype = temp; + /* Reset scrollbar positions */ + this->vscroll[0]->SetPosition(0); + this->vscroll[1]->SetPosition(0); + /* Rebuild the lists */ + this->engines[0].ForceRebuild(); + this->engines[1].ForceRebuild(); + this->reset_sel_engine = true; + this->SetDirty(); + break; + } + + case WID_RV_START_REPLACE: + this->ReplaceClick_StartReplace(index != 0); + break; + } + } + + virtual void OnResize() + { + this->vscroll[0]->SetCapacityFromWidget(this, WID_RV_LEFT_MATRIX); + this->vscroll[1]->SetCapacityFromWidget(this, WID_RV_RIGHT_MATRIX); + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (data != 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ + this->engines[0].ForceRebuild(); + } else { + this->engines[1].ForceRebuild(); + } + } +}; + +static const NWidgetPart _nested_replace_rail_vehicle_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetDataTip(STR_REPLACE_VEHICLES_WHITE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_LEFT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_LEFT_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_LEFT_SCROLLBAR), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_RIGHT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_RIGHT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_RIGHT_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_RIGHT_SCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_LEFT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_PUSHBUTTON_DROPDOWN, COLOUR_GREY, WID_RV_START_REPLACE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_INFO_TAB), SetMinimalSize(167, 12), SetDataTip(0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB), SetResize(1, 0), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_STOP_REPLACE), SetMinimalSize(150, 12), SetDataTip(STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_TRAIN_ENGINEWAGON_TOGGLE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_ENGINE_WAGON_SELECT, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_TRAIN_FLUFF_LEFT), SetMinimalSize(15, 12), EndContainer(), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_TRAIN_RAILTYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(0x0, STR_REPLACE_HELP_RAILTYPE), SetResize(1, 0), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_TRAIN_FLUFF_RIGHT), SetMinimalSize(16, 12), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_TRAIN_WAGONREMOVE_TOGGLE), SetMinimalSize(138, 12), SetDataTip(STR_REPLACE_REMOVE_WAGON, STR_REPLACE_REMOVE_WAGON_HELP), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +static WindowDesc _replace_rail_vehicle_desc( + WDP_AUTO, "replace_vehicle_train", 500, 140, + WC_REPLACE_VEHICLE, WC_NONE, + WDF_CONSTRUCTION, + _nested_replace_rail_vehicle_widgets, lengthof(_nested_replace_rail_vehicle_widgets) +); + +static const NWidgetPart _nested_replace_vehicle_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetMinimalSize(433, 14), SetDataTip(STR_REPLACE_VEHICLES_WHITE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_LEFT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_LEFT_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_LEFT_SCROLLBAR), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_RIGHT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_RIGHT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_RIGHT_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_RIGHT_SCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_LEFT_DETAILS), SetMinimalSize(228, 92), SetResize(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(228, 92), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_PUSHBUTTON_DROPDOWN, COLOUR_GREY, WID_RV_START_REPLACE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_INFO_TAB), SetMinimalSize(167, 12), SetDataTip(0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB), SetResize(1, 0), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_STOP_REPLACE), SetMinimalSize(138, 12), SetDataTip(STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +static WindowDesc _replace_vehicle_desc( + WDP_AUTO, "replace_vehicle", 456, 118, + WC_REPLACE_VEHICLE, WC_NONE, + WDF_CONSTRUCTION, + _nested_replace_vehicle_widgets, lengthof(_nested_replace_vehicle_widgets) +); + +/** + * Show the autoreplace configuration window for a particular group. + * @param id_g The group to replace the vehicles for. + * @param vehicletype The type of vehicles in the group. + */ +void ShowReplaceGroupVehicleWindow(GroupID id_g, VehicleType vehicletype) +{ + DeleteWindowById(WC_REPLACE_VEHICLE, vehicletype); + new ReplaceVehicleWindow(vehicletype == VEH_TRAIN ? &_replace_rail_vehicle_desc : &_replace_vehicle_desc, vehicletype, id_g); +} diff --git a/src/build_vehicle_gui.cpp.orig b/src/build_vehicle_gui.cpp.orig new file mode 100644 index 0000000000..410b2dbb3b --- /dev/null +++ b/src/build_vehicle_gui.cpp.orig @@ -0,0 +1,1427 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file build_vehicle_gui.cpp GUI for building vehicles. */ + +#include "stdafx.h" +#include "engine_base.h" +#include "engine_func.h" +#include "station_base.h" +#include "network/network.h" +#include "articulated_vehicles.h" +#include "textbuf_gui.h" +#include "command_func.h" +#include "company_func.h" +#include "vehicle_gui.h" +#include "newgrf_engine.h" +#include "newgrf_text.h" +#include "group.h" +#include "string_func.h" +#include "strings_func.h" +#include "window_func.h" +#include "date_func.h" +#include "vehicle_func.h" +#include "widgets/dropdown_func.h" +#include "engine_gui.h" +#include "cargotype.h" +#include "core/geometry_func.hpp" +#include "autoreplace_func.h" + +#include "widgets/build_vehicle_widget.h" + +#include "table/strings.h" + +/** + * Get the height of a single 'entry' in the engine lists. + * @param type the vehicle type to get the height of + * @return the height for the entry + */ +uint GetEngineListHeight(VehicleType type) +{ + return max(FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM, GetVehicleImageCellSize(type, EIT_PURCHASE).height); +} + +static const NWidgetPart _nested_build_vehicle_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_BV_CAPTION), SetDataTip(STR_WHITE_STRING, 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(NWID_VERTICAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASSENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), + NWidget(NWID_SPACER), SetFill(1, 1), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), + EndContainer(), + EndContainer(), + EndContainer(), + /* Vehicle list. */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_BV_LIST), SetResize(1, 1), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_BV_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BV_SCROLLBAR), + EndContainer(), + /* Panel with details. */ + NWidget(WWT_PANEL, COLOUR_GREY, WID_BV_PANEL), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + /* Build/rename buttons, resize button. */ + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BV_BUILD_SEL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_BUILD), SetResize(1, 0), SetFill(1, 0), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_RENAME), SetResize(1, 0), SetFill(1, 0), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +/** Special cargo filter criteria */ +static const CargoID CF_ANY = CT_NO_REFIT; ///< Show all vehicles independent of carried cargo (i.e. no filtering) +static const CargoID CF_NONE = CT_INVALID; ///< Show only vehicles which do not carry cargo (e.g. train engines) + +static bool _internal_sort_order; ///< false = descending, true = ascending +static byte _last_sort_criteria[] = {0, 0, 0, 0}; +static bool _last_sort_order[] = {false, false, false, false}; +static CargoID _last_filter_criteria[] = {CF_ANY, CF_ANY, CF_ANY, CF_ANY}; + +/** + * Determines order of engines by engineID + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b) +{ + int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; + + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by introduction date + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineIntroDateSorter(const EngineID *a, const EngineID *b) +{ + const int va = Engine::Get(*a)->intro_date; + const int vb = Engine::Get(*b)->intro_date; + const int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by name + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineNameSorter(const EngineID *a, const EngineID *b) +{ + static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE }; + static char last_name[2][64] = { "\0", "\0" }; + + const EngineID va = *a; + const EngineID vb = *b; + + if (va != last_engine[0]) { + last_engine[0] = va; + SetDParam(0, va); + GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); + } + + if (vb != last_engine[1]) { + last_engine[1] = vb; + SetDParam(0, vb); + GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); + } + + int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by reliability + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineReliabilitySorter(const EngineID *a, const EngineID *b) +{ + const int va = Engine::Get(*a)->reliability; + const int vb = Engine::Get(*b)->reliability; + const int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by purchase cost + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineCostSorter(const EngineID *a, const EngineID *b) +{ + Money va = Engine::Get(*a)->GetCost(); + Money vb = Engine::Get(*b)->GetCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by speed + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineSpeedSorter(const EngineID *a, const EngineID *b) +{ + int va = Engine::Get(*a)->GetDisplayMaxSpeed(); + int vb = Engine::Get(*b)->GetDisplayMaxSpeed(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by power + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EnginePowerSorter(const EngineID *a, const EngineID *b) +{ + int va = Engine::Get(*a)->GetPower(); + int vb = Engine::Get(*b)->GetPower(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by tractive effort + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineTractiveEffortSorter(const EngineID *a, const EngineID *b) +{ + int va = Engine::Get(*a)->GetDisplayMaxTractiveEffort(); + int vb = Engine::Get(*b)->GetDisplayMaxTractiveEffort(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by running costs + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineRunningCostSorter(const EngineID *a, const EngineID *b) +{ + Money va = Engine::Get(*a)->GetRunningCost(); + Money vb = Engine::Get(*b)->GetRunningCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by running costs + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EnginePowerVsRunningCostSorter(const EngineID *a, const EngineID *b) +{ + const Engine *e_a = Engine::Get(*a); + const Engine *e_b = Engine::Get(*b); + + /* Here we are using a few tricks to get the right sort. + * We want power/running cost, but since we usually got higher running cost than power and we store the result in an int, + * we will actually calculate cunning cost/power (to make it more than 1). + * Because of this, the return value have to be reversed as well and we return b - a instead of a - b. + * Another thing is that both power and running costs should be doubled for multiheaded engines. + * Since it would be multiplying with 2 in both numerator and denominator, it will even themselves out and we skip checking for multiheaded. */ + Money va = (e_a->GetRunningCost()) / max(1U, (uint)e_a->GetPower()); + Money vb = (e_b->GetRunningCost()) / max(1U, (uint)e_b->GetPower()); + int r = ClampToI32(vb - va); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/* Train sorting functions */ + +/** + * Determines order of train engines by capacity + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL TrainEngineCapacitySorter(const EngineID *a, const EngineID *b) +{ + const RailVehicleInfo *rvi_a = RailVehInfo(*a); + const RailVehicleInfo *rvi_b = RailVehInfo(*b); + + int va = GetTotalCapacityOfArticulatedParts(*a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int vb = GetTotalCapacityOfArticulatedParts(*b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of train engines by engine / wagon + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL TrainEnginesThenWagonsSorter(const EngineID *a, const EngineID *b) +{ + int val_a = (RailVehInfo(*a)->railveh_type == RAILVEH_WAGON ? 1 : 0); + int val_b = (RailVehInfo(*b)->railveh_type == RAILVEH_WAGON ? 1 : 0); + int r = val_a - val_b; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/* Road vehicle sorting functions */ + +/** + * Determines order of road vehicles by capacity + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL RoadVehEngineCapacitySorter(const EngineID *a, const EngineID *b) +{ + int va = GetTotalCapacityOfArticulatedParts(*a); + int vb = GetTotalCapacityOfArticulatedParts(*b); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/* Ship vehicle sorting functions */ + +/** + * Determines order of ships by capacity + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL ShipEngineCapacitySorter(const EngineID *a, const EngineID *b) +{ + const Engine *e_a = Engine::Get(*a); + const Engine *e_b = Engine::Get(*b); + + int va = e_a->GetDisplayDefaultCapacity(); + int vb = e_b->GetDisplayDefaultCapacity(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/* Aircraft sorting functions */ + +/** + * Determines order of aircraft by cargo + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL AircraftEngineCargoSorter(const EngineID *a, const EngineID *b) +{ + const Engine *e_a = Engine::Get(*a); + const Engine *e_b = Engine::Get(*b); + + uint16 mail_a, mail_b; + int va = e_a->GetDisplayDefaultCapacity(&mail_a); + int vb = e_b->GetDisplayDefaultCapacity(&mail_b); + int r = va - vb; + + if (r == 0) { + /* The planes have the same passenger capacity. Check mail capacity instead */ + r = mail_a - mail_b; + + if (r == 0) { + /* Use EngineID to sort instead since we want consistent sorting */ + return EngineNumberSorter(a, b); + } + } + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of aircraft by range. + * @param *a first engine to compare. + * @param *b second engine to compare. + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal. + */ +static int CDECL AircraftRangeSorter(const EngineID *a, const EngineID *b) +{ + uint16 r_a = Engine::Get(*a)->GetRange(); + uint16 r_b = Engine::Get(*b)->GetRange(); + + int r = r_a - r_b; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +static EngList_SortTypeFunction * const _sorter[][11] = {{ + /* Trains */ + &EngineNumberSorter, + &EngineCostSorter, + &EngineSpeedSorter, + &EnginePowerSorter, + &EngineTractiveEffortSorter, + &EngineIntroDateSorter, + &EngineNameSorter, + &EngineRunningCostSorter, + &EnginePowerVsRunningCostSorter, + &EngineReliabilitySorter, + &TrainEngineCapacitySorter, +}, { + /* Road vehicles */ + &EngineNumberSorter, + &EngineCostSorter, + &EngineSpeedSorter, + &EnginePowerSorter, + &EngineTractiveEffortSorter, + &EngineIntroDateSorter, + &EngineNameSorter, + &EngineRunningCostSorter, + &EnginePowerVsRunningCostSorter, + &EngineReliabilitySorter, + &RoadVehEngineCapacitySorter, +}, { + /* Ships */ + &EngineNumberSorter, + &EngineCostSorter, + &EngineSpeedSorter, + &EngineIntroDateSorter, + &EngineNameSorter, + &EngineRunningCostSorter, + &EngineReliabilitySorter, + &ShipEngineCapacitySorter, +}, { + /* Aircraft */ + &EngineNumberSorter, + &EngineCostSorter, + &EngineSpeedSorter, + &EngineIntroDateSorter, + &EngineNameSorter, + &EngineRunningCostSorter, + &EngineReliabilitySorter, + &AircraftEngineCargoSorter, + &AircraftRangeSorter, +}}; + +static const StringID _sort_listing[][12] = {{ + /* Trains */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_POWER, + STR_SORT_BY_TRACTIVE_EFFORT, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_POWER_VS_RUNNING_COST, + STR_SORT_BY_RELIABILITY, + STR_SORT_BY_CARGO_CAPACITY, + INVALID_STRING_ID +}, { + /* Road vehicles */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_POWER, + STR_SORT_BY_TRACTIVE_EFFORT, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_POWER_VS_RUNNING_COST, + STR_SORT_BY_RELIABILITY, + STR_SORT_BY_CARGO_CAPACITY, + INVALID_STRING_ID +}, { + /* Ships */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_RELIABILITY, + STR_SORT_BY_CARGO_CAPACITY, + INVALID_STRING_ID +}, { + /* Aircraft */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_RELIABILITY, + STR_SORT_BY_CARGO_CAPACITY, + STR_SORT_BY_RANGE, + INVALID_STRING_ID +}}; + +/** Cargo filter functions */ +static bool CDECL CargoFilter(const EngineID *eid, const CargoID cid) +{ + if (cid == CF_ANY) return true; + uint32 refit_mask = GetUnionOfArticulatedRefitMasks(*eid, true) & _standard_cargo_mask; + return (cid == CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cid)); +} + +static GUIEngineList::FilterFunction * const _filter_funcs[] = { + &CargoFilter, +}; + +static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine, bool refittable) +{ + CargoArray cap = GetCapacityOfArticulatedParts(engine); + + for (CargoID c = 0; c < NUM_CARGO; c++) { + if (cap[c] == 0) continue; + + SetDParam(0, c); + SetDParam(1, cap[c]); + SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); + DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); + y += FONT_HEIGHT_NORMAL; + + /* Only show as refittable once */ + refittable = false; + } + + return y; +} + +/* Draw rail wagon specific details */ +static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi) +{ + const Engine *e = Engine::Get(engine_number); + + /* Purchase cost */ + SetDParam(0, e->GetCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST); + y += FONT_HEIGHT_NORMAL; + + /* Wagon weight - (including cargo) */ + uint weight = e->GetDisplayWeight(); + SetDParam(0, weight); + uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16 : 0); + SetDParam(1, cargo_weight + weight); + DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT); + y += FONT_HEIGHT_NORMAL; + + /* Wagon speed limit, displayed if above zero */ + if (_settings_game.vehicle.wagon_speed_limits) { + uint max_speed = e->GetDisplayMaxSpeed(); + if (max_speed > 0) { + SetDParam(0, max_speed); + DrawString(left, right, y, STR_PURCHASE_INFO_SPEED); + y += FONT_HEIGHT_NORMAL; + } + } + + /* Running cost */ + if (rvi->running_cost_class != INVALID_PRICE) { + SetDParam(0, e->GetRunningCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); + y += FONT_HEIGHT_NORMAL; + } + + return y; +} + +/* Draw locomotive specific details */ +static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi) +{ + const Engine *e = Engine::Get(engine_number); + + /* Purchase Cost - Engine weight */ + SetDParam(0, e->GetCost()); + SetDParam(1, e->GetDisplayWeight()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT); + y += FONT_HEIGHT_NORMAL; + + /* Max speed - Engine power */ + SetDParam(0, e->GetDisplayMaxSpeed()); + SetDParam(1, e->GetPower()); + DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER); + y += FONT_HEIGHT_NORMAL; + + /* Max tractive effort - not applicable if old acceleration or maglev */ + if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(rvi->railtype)->acceleration_type != 2) { + SetDParam(0, e->GetDisplayMaxTractiveEffort()); + DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE); + y += FONT_HEIGHT_NORMAL; + } + + /* Running cost */ + if (rvi->running_cost_class != INVALID_PRICE) { + SetDParam(0, e->GetRunningCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); + y += FONT_HEIGHT_NORMAL; + } + + /* Powered wagons power - Powered wagons extra weight */ + if (rvi->pow_wag_power != 0) { + SetDParam(0, rvi->pow_wag_power); + SetDParam(1, rvi->pow_wag_weight); + DrawString(left, right, y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT); + y += FONT_HEIGHT_NORMAL; + } + + return y; +} + +/* Draw road vehicle specific details */ +static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number) +{ + const Engine *e = Engine::Get(engine_number); + + if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) { + /* Purchase Cost */ + SetDParam(0, e->GetCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST); + y += FONT_HEIGHT_NORMAL; + + /* Road vehicle weight - (including cargo) */ + int16 weight = e->GetDisplayWeight(); + SetDParam(0, weight); + uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16 : 0); + SetDParam(1, cargo_weight + weight); + DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT); + y += FONT_HEIGHT_NORMAL; + + /* Max speed - Engine power */ + SetDParam(0, e->GetDisplayMaxSpeed()); + SetDParam(1, e->GetPower()); + DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER); + y += FONT_HEIGHT_NORMAL; + + /* Max tractive effort */ + SetDParam(0, e->GetDisplayMaxTractiveEffort()); + DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE); + y += FONT_HEIGHT_NORMAL; + } else { + /* Purchase cost - Max speed */ + SetDParam(0, e->GetCost()); + SetDParam(1, e->GetDisplayMaxSpeed()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); + y += FONT_HEIGHT_NORMAL; + } + + /* Running cost */ + SetDParam(0, e->GetRunningCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); + y += FONT_HEIGHT_NORMAL; + + return y; +} + +/* Draw ship specific details */ +static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable) +{ + const Engine *e = Engine::Get(engine_number); + + /* Purchase cost - Max speed */ + uint raw_speed = e->GetDisplayMaxSpeed(); + uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true); + uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false); + + SetDParam(0, e->GetCost()); + if (ocean_speed == canal_speed) { + SetDParam(1, ocean_speed); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); + y += FONT_HEIGHT_NORMAL; + } else { + DrawString(left, right, y, STR_PURCHASE_INFO_COST); + y += FONT_HEIGHT_NORMAL; + + SetDParam(0, ocean_speed); + DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_OCEAN); + y += FONT_HEIGHT_NORMAL; + + SetDParam(0, canal_speed); + DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_CANAL); + y += FONT_HEIGHT_NORMAL; + } + + /* Cargo type + capacity */ + SetDParam(0, e->GetDefaultCargoType()); + SetDParam(1, e->GetDisplayDefaultCapacity()); + SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); + DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); + y += FONT_HEIGHT_NORMAL; + + /* Running cost */ + SetDParam(0, e->GetRunningCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); + y += FONT_HEIGHT_NORMAL; + + return y; +} + +/* Draw aircraft specific details */ +static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable) +{ + const Engine *e = Engine::Get(engine_number); + CargoID cargo = e->GetDefaultCargoType(); + + /* Purchase cost - Max speed */ + SetDParam(0, e->GetCost()); + SetDParam(1, e->GetDisplayMaxSpeed()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); + y += FONT_HEIGHT_NORMAL; + + /* Cargo capacity */ + uint16 mail_capacity; + uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity); + if (mail_capacity > 0) { + SetDParam(0, cargo); + SetDParam(1, capacity); + SetDParam(2, CT_MAIL); + SetDParam(3, mail_capacity); + DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY); + } else { + /* Note, if the default capacity is selected by the refit capacity + * callback, then the capacity shown is likely to be incorrect. */ + SetDParam(0, cargo); + SetDParam(1, capacity); + SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); + DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); + } + y += FONT_HEIGHT_NORMAL; + + /* Running cost */ + SetDParam(0, e->GetRunningCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); + y += FONT_HEIGHT_NORMAL; + + uint16 range = e->GetRange(); + if (range != 0) { + SetDParam(0, range); + DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_RANGE); + y += FONT_HEIGHT_NORMAL; + } + + return y; +} + +/** + * Display additional text from NewGRF in the purchase information window + * @param left Left border of text bounding box + * @param right Right border of text bounding box + * @param y Top border of text bounding box + * @param engine Engine to query the additional purchase information for + * @return Bottom border of text bounding box + */ +static uint ShowAdditionalText(int left, int right, int y, EngineID engine) +{ + uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, NULL); + if (callback == CALLBACK_FAILED || callback == 0x400) return y; + const GRFFile *grffile = Engine::Get(engine)->GetGRF(); + if (callback > 0x400) { + ErrorUnknownCallbackResult(grffile->grfid, CBID_VEHICLE_ADDITIONAL_TEXT, callback); + return y; + } + + StartTextRefStackUsage(grffile, 6); + uint result = DrawStringMultiLine(left, right, y, INT32_MAX, GetGRFStringID(grffile->grfid, 0xD000 + callback), TC_BLACK); + StopTextRefStackUsage(); + return result; +} + +/** + * Draw the purchase info details of a vehicle at a given location. + * @param left,right,y location where to draw the info + * @param engine_number the engine of which to draw the info of + * @return y after drawing all the text + */ +int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number) +{ + const Engine *e = Engine::Get(engine_number); + YearMonthDay ymd; + ConvertDateToYMD(e->intro_date, &ymd); + bool refittable = IsArticulatedVehicleRefittable(engine_number); + bool articulated_cargo = false; + + switch (e->type) { + default: NOT_REACHED(); + case VEH_TRAIN: + if (e->u.rail.railveh_type == RAILVEH_WAGON) { + y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail); + } else { + y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail); + } + articulated_cargo = true; + break; + + case VEH_ROAD: + y = DrawRoadVehPurchaseInfo(left, right, y, engine_number); + articulated_cargo = true; + break; + + case VEH_SHIP: + y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable); + break; + + case VEH_AIRCRAFT: + y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable); + break; + } + + if (articulated_cargo) { + /* Cargo type + capacity, or N/A */ + int new_y = DrawCargoCapacityInfo(left, right, y, engine_number, refittable); + + if (new_y == y) { + SetDParam(0, CT_INVALID); + SetDParam(2, STR_EMPTY); + DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); + y += FONT_HEIGHT_NORMAL; + } else { + y = new_y; + } + } + + /* Draw details that apply to all types except rail wagons. */ + if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) { + /* Design date - Life length */ + SetDParam(0, ymd.year); + SetDParam(1, e->GetLifeLengthInDays() / DAYS_IN_LEAP_YEAR); + DrawString(left, right, y, STR_PURCHASE_INFO_DESIGNED_LIFE); + y += FONT_HEIGHT_NORMAL; + + /* Reliability */ + SetDParam(0, ToPercent16(e->reliability)); + DrawString(left, right, y, STR_PURCHASE_INFO_RELIABILITY); + y += FONT_HEIGHT_NORMAL; + } + + if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number); + + /* Additional text from NewGRF */ + y = ShowAdditionalText(left, right, y, engine_number); + + return y; +} + +/** + * Engine drawing loop + * @param type Type of vehicle (VEH_*) + * @param l The left most location of the list + * @param r The right most location of the list + * @param y The top most location of the list + * @param eng_list What engines to draw + * @param min where to start in the list + * @param max where in the list to end + * @param selected_id what engine to highlight as selected, if any + * @param show_count Whether to show the amount of engines or not + * @param selected_group the group to list the engines of + */ +void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group) +{ + static const int sprite_y_offsets[] = { -1, -1, -2, -2 }; + + /* Obligatory sanity checks! */ + assert(max <= eng_list->Length()); + + bool rtl = _current_text_dir == TD_RTL; + int step_size = GetEngineListHeight(type); + int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left; + int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right; + int sprite_width = sprite_left + sprite_right; + + int sprite_x = rtl ? r - sprite_right - 1 : l + sprite_left + 1; + + Dimension replace_icon = {0, 0}; + int count_width = 0; + if (show_count) { + replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE); + SetDParamMaxDigits(0, 3, FS_SMALL); + count_width = GetStringBoundingBox(STR_TINY_BLACK_COMA).width; + } + + int text_left = l + (rtl ? WD_FRAMERECT_LEFT + replace_icon.width + 8 + count_width : sprite_width + WD_FRAMETEXT_LEFT); + int text_right = r - (rtl ? sprite_width + WD_FRAMETEXT_RIGHT : WD_FRAMERECT_RIGHT + replace_icon.width + 8 + count_width); + int replace_icon_left = rtl ? l + WD_FRAMERECT_LEFT : r - WD_FRAMERECT_RIGHT - replace_icon.width; + int count_left = l; + int count_right = rtl ? text_left : r - WD_FRAMERECT_RIGHT - replace_icon.width - 8; + + for (; min < max; min++, y += step_size) { + const EngineID engine = (*eng_list)[min]; + /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */ + const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine); + + SetDParam(0, engine); + DrawString(text_left, text_right, Center(y, step_size), STR_ENGINE_NAME, text_colour); + DrawVehicleEngine(l, r, sprite_x, Center(y, step_size, sprite_y_offsets[type]), engine, palette_crash ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); + if (show_count) { + SetDParam(0, num_engines); + DrawString(count_left, count_right, Center(y, step_size, FONT_HEIGHT_SMALL), STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); + if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, replace_icon_left, Center(y, step_size, replace_icon.height)); + } + } +} + + +struct BuildVehicleWindow : Window { + VehicleType vehicle_type; + union { + RailTypeByte railtype; + RoadTypes roadtypes; + } filter; + bool descending_sort_order; + byte sort_criteria; + bool listview_mode; + EngineID sel_engine; + EngineID rename_engine; + GUIEngineList eng_list; + CargoID cargo_filter[NUM_CARGO + 2]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE + StringID cargo_filter_texts[NUM_CARGO + 3]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID + byte cargo_filter_criteria; ///< Selected cargo filter + int details_height; ///< Minimal needed height of the details panels (found so far). + Scrollbar *vscroll; + + BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc) + { + this->vehicle_type = type; + this->window_number = tile == INVALID_TILE ? (int)type : tile; + + this->sel_engine = INVALID_ENGINE; + + this->sort_criteria = _last_sort_criteria[type]; + this->descending_sort_order = _last_sort_order[type]; + + switch (type) { + default: NOT_REACHED(); + case VEH_TRAIN: + this->filter.railtype = (tile == INVALID_TILE) ? RAILTYPE_END : GetRailType(tile); + break; + case VEH_ROAD: + this->filter.roadtypes = (tile == INVALID_TILE) ? ROADTYPES_ALL : GetRoadTypes(tile); + case VEH_SHIP: + case VEH_AIRCRAFT: + break; + } + + this->listview_mode = (this->window_number <= VEH_END); + + this->CreateNestedTree(); + + this->vscroll = this->GetScrollbar(WID_BV_SCROLLBAR); + + /* If we are just viewing the list of vehicles, we do not need the Build button. + * So we just hide it, and enlarge the Rename button by the now vacant place. */ + if (this->listview_mode) this->GetWidget(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE); + + /* disable renaming engines in network games if you are not the server */ + this->SetWidgetDisabledState(WID_BV_RENAME, _networking && !_network_server); + + NWidgetCore *widget = this->GetWidget(WID_BV_LIST); + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + type; + + widget = this->GetWidget(WID_BV_BUILD); + widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + type; + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + type; + + widget = this->GetWidget(WID_BV_RENAME); + widget->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + type; + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + type; + + this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + + this->FinishInitNested(tile == INVALID_TILE ? (int)type : tile); + + this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company; + + this->eng_list.ForceRebuild(); + this->GenerateBuildList(); // generate the list, since we need it in the next line + /* Select the first engine in the list as default when opening the window */ + if (this->eng_list.Length() > 0) this->sel_engine = this->eng_list[0]; + } + + /** Populate the filter list and set the cargo filter criteria. */ + void SetCargoFilterArray() + { + uint filter_items = 0; + + /* Add item for disabling filtering. */ + this->cargo_filter[filter_items] = CF_ANY; + this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_ALL_TYPES; + filter_items++; + + /* Add item for vehicles not carrying anything, e.g. train engines. + * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */ + if (this->vehicle_type == VEH_TRAIN) { + this->cargo_filter[filter_items] = CF_NONE; + this->cargo_filter_texts[filter_items] = STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE; + filter_items++; + } + + /* Collect available cargo types for filtering. */ + const CargoSpec *cs; + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + this->cargo_filter[filter_items] = cs->Index(); + this->cargo_filter_texts[filter_items] = cs->name; + filter_items++; + } + + /* Terminate the filter list. */ + this->cargo_filter_texts[filter_items] = INVALID_STRING_ID; + + /* If not found, the cargo criteria will be set to all cargoes. */ + this->cargo_filter_criteria = 0; + + /* Find the last cargo filter criteria. */ + for (uint i = 0; i < filter_items; i++) { + if (this->cargo_filter[i] == _last_filter_criteria[this->vehicle_type]) { + this->cargo_filter_criteria = i; + break; + } + } + + this->eng_list.SetFilterFuncs(_filter_funcs); + this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY); + } + + void OnInit() + { + this->SetCargoFilterArray(); + } + + /** Filter the engine list against the currently selected cargo filter */ + void FilterEngineList() + { + this->eng_list.Filter(this->cargo_filter[this->cargo_filter_criteria]); + if (0 == this->eng_list.Length()) { // no engine passed through the filter, invalidate the previously selected engine + this->sel_engine = INVALID_ENGINE; + } else if (!this->eng_list.Contains(this->sel_engine)) { // previously selected engine didn't pass the filter, select the first engine of the list + this->sel_engine = this->eng_list[0]; + } + } + + /** Filter a single engine */ + bool FilterSingleEngine(EngineID eid) + { + CargoID filter_type = this->cargo_filter[this->cargo_filter_criteria]; + return (filter_type == CF_ANY || CargoFilter(&eid, filter_type)); + } + + /* Figure out what train EngineIDs to put in the list */ + void GenerateBuildTrainList() + { + EngineID sel_id = INVALID_ENGINE; + int num_engines = 0; + int num_wagons = 0; + + this->filter.railtype = (this->listview_mode) ? RAILTYPE_END : GetRailType(this->window_number); + + this->eng_list.Clear(); + + /* Make list of all available train engines and wagons. + * Also check to see if the previously selected engine is still available, + * and if not, reset selection to INVALID_ENGINE. This could be the case + * when engines become obsolete and are removed */ + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { + EngineID eid = e->index; + const RailVehicleInfo *rvi = &e->u.rail; + + if (this->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue; + if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; + + /* Filter now! So num_engines and num_wagons is valid */ + if (!FilterSingleEngine(eid)) continue; + + *this->eng_list.Append() = eid; + + if (rvi->railveh_type != RAILVEH_WAGON) { + num_engines++; + } else { + num_wagons++; + } + + if (eid == this->sel_engine) sel_id = eid; + } + + this->sel_engine = sel_id; + + /* make engines first, and then wagons, sorted by selected sort_criteria */ + _internal_sort_order = false; + EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter); + + /* and then sort engines */ + _internal_sort_order = this->descending_sort_order; + EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], 0, num_engines); + + /* and finally sort wagons */ + EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], num_engines, num_wagons); + } + + /* Figure out what road vehicle EngineIDs to put in the list */ + void GenerateBuildRoadVehList() + { + EngineID sel_id = INVALID_ENGINE; + + this->eng_list.Clear(); + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { + EngineID eid = e->index; + if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue; + if (!HasBit(this->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue; + *this->eng_list.Append() = eid; + + if (eid == this->sel_engine) sel_id = eid; + } + this->sel_engine = sel_id; + } + + /* Figure out what ship EngineIDs to put in the list */ + void GenerateBuildShipList() + { + EngineID sel_id = INVALID_ENGINE; + this->eng_list.Clear(); + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) { + EngineID eid = e->index; + if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue; + *this->eng_list.Append() = eid; + + if (eid == this->sel_engine) sel_id = eid; + } + this->sel_engine = sel_id; + } + + /* Figure out what aircraft EngineIDs to put in the list */ + void GenerateBuildAircraftList() + { + EngineID sel_id = INVALID_ENGINE; + + this->eng_list.Clear(); + + const Station *st = this->listview_mode ? NULL : Station::GetByTile(this->window_number); + + /* Make list of all available planes. + * Also check to see if the previously selected plane is still available, + * and if not, reset selection to INVALID_ENGINE. This could be the case + * when planes become obsolete and are removed */ + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) { + EngineID eid = e->index; + if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_company)) continue; + /* First VEH_END window_numbers are fake to allow a window open for all different types at once */ + if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue; + + *this->eng_list.Append() = eid; + if (eid == this->sel_engine) sel_id = eid; + } + + this->sel_engine = sel_id; + } + + /* Generate the list of vehicles */ + void GenerateBuildList() + { + if (!this->eng_list.NeedRebuild()) return; + switch (this->vehicle_type) { + default: NOT_REACHED(); + case VEH_TRAIN: + this->GenerateBuildTrainList(); + this->eng_list.Compact(); + this->eng_list.RebuildDone(); + return; // trains should not reach the last sorting + case VEH_ROAD: + this->GenerateBuildRoadVehList(); + break; + case VEH_SHIP: + this->GenerateBuildShipList(); + break; + case VEH_AIRCRAFT: + this->GenerateBuildAircraftList(); + break; + } + + this->FilterEngineList(); + + _internal_sort_order = this->descending_sort_order; + EngList_Sort(&this->eng_list, _sorter[this->vehicle_type][this->sort_criteria]); + + this->eng_list.Compact(); + this->eng_list.RebuildDone(); + } + + void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_BV_SORT_ASSENDING_DESCENDING: + this->descending_sort_order ^= true; + _last_sort_order[this->vehicle_type] = this->descending_sort_order; + this->eng_list.ForceRebuild(); + this->SetDirty(); + break; + + case WID_BV_LIST: { + uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST); + size_t num_items = this->eng_list.Length(); + this->sel_engine = (i < num_items) ? this->eng_list[i] : INVALID_ENGINE; + this->SetDirty(); + if (click_count > 1 && !this->listview_mode) this->OnClick(pt, WID_BV_BUILD, 1); + break; + } + + case WID_BV_SORT_DROPDOWN: { // Select sorting criteria dropdown menu + uint32 hidden_mask = 0; + /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */ + if (this->vehicle_type == VEH_ROAD && + _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) { + SetBit(hidden_mask, 3); // power + SetBit(hidden_mask, 4); // tractive effort + SetBit(hidden_mask, 8); // power by running costs + } + /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */ + if (this->vehicle_type == VEH_TRAIN && + _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) { + SetBit(hidden_mask, 4); // tractive effort + } + ShowDropDownMenu(this, _sort_listing[this->vehicle_type], this->sort_criteria, WID_BV_SORT_DROPDOWN, 0, hidden_mask); + break; + } + + case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu + ShowDropDownMenu(this, this->cargo_filter_texts, this->cargo_filter_criteria, WID_BV_CARGO_FILTER_DROPDOWN, 0, 0); + break; + + case WID_BV_BUILD: { + EngineID sel_eng = this->sel_engine; + if (sel_eng != INVALID_ENGINE) { + CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle; + DoCommandP(this->window_number, sel_eng, 0, GetCmdBuildVeh(this->vehicle_type), callback); + } + break; + } + + case WID_BV_RENAME: { + EngineID sel_eng = this->sel_engine; + if (sel_eng != INVALID_ENGINE) { + this->rename_engine = sel_eng; + SetDParam(0, sel_eng); + ShowQueryString(STR_ENGINE_NAME, STR_QUERY_RENAME_TRAIN_TYPE_CAPTION + this->vehicle_type, MAX_LENGTH_ENGINE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); + } + break; + } + } + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */ + if (this->vehicle_type == VEH_ROAD && + _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL && + this->sort_criteria > 7) { + this->sort_criteria = 0; + _last_sort_criteria[VEH_ROAD] = 0; + } + this->eng_list.ForceRebuild(); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_BV_CAPTION: + if (this->vehicle_type == VEH_TRAIN && !this->listview_mode) { + const RailtypeInfo *rti = GetRailTypeInfo(this->filter.railtype); + SetDParam(0, rti->strings.build_caption); + } else { + SetDParam(0, (this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type); + } + break; + + case WID_BV_SORT_DROPDOWN: + SetDParam(0, _sort_listing[this->vehicle_type][this->sort_criteria]); + break; + + case WID_BV_CARGO_FILTER_DROPDOWN: + SetDParam(0, this->cargo_filter_texts[this->cargo_filter_criteria]); + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_BV_LIST: + resize->height = GetEngineListHeight(this->vehicle_type); + size->height = 3 * resize->height; + break; + + case WID_BV_PANEL: + size->height = this->details_height; + break; + + case WID_BV_SORT_ASSENDING_DESCENDING: { + Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); + d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_BV_LIST: + DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list, this->vscroll->GetPosition(), min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->eng_list.Length()), this->sel_engine, false, DEFAULT_GROUP); + break; + + case WID_BV_SORT_ASSENDING_DESCENDING: + this->DrawSortButtonState(WID_BV_SORT_ASSENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP); + break; + } + } + + virtual void OnPaint() + { + this->GenerateBuildList(); + this->vscroll->SetCount(this->eng_list.Length()); + + this->DrawWidgets(); + + if (!this->IsShaded()) { + int needed_height = this->details_height; + /* Draw details panels. */ + if (this->sel_engine != INVALID_ENGINE) { + NWidgetBase *nwi = this->GetWidget(WID_BV_PANEL); + int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, + nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine); + needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); + } + if (needed_height != this->details_height) { // Details window are not high enough, enlarge them. + int resize = needed_height - this->details_height; + this->details_height = needed_height; + this->ReInit(0, resize); + return; + } + } + } + + virtual void OnQueryTextFinished(char *str) + { + if (str == NULL) return; + + DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), NULL, str); + } + + virtual void OnDropdownSelect(int widget, int index) + { + switch (widget) { + case WID_BV_SORT_DROPDOWN: + if (this->sort_criteria != index) { + this->sort_criteria = index; + _last_sort_criteria[this->vehicle_type] = this->sort_criteria; + this->eng_list.ForceRebuild(); + } + break; + + case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria + if (this->cargo_filter_criteria != index) { + this->cargo_filter_criteria = index; + _last_filter_criteria[this->vehicle_type] = this->cargo_filter[this->cargo_filter_criteria]; + /* deactivate filter if criteria is 'Show All', activate it otherwise */ + this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY); + this->eng_list.ForceRebuild(); + } + break; + } + this->SetDirty(); + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST); + } +}; + +static WindowDesc _build_vehicle_desc( + WDP_AUTO, "build_vehicle", 240, 268, + WC_BUILD_VEHICLE, WC_NONE, + WDF_CONSTRUCTION, + _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets) +); + +void ShowBuildVehicleWindow(TileIndex tile, VehicleType type) +{ + /* We want to be able to open both Available Train as Available Ships, + * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number. + * As it always is a low value, it won't collide with any real tile + * number. */ + uint num = (tile == INVALID_TILE) ? (int)type : tile; + + assert(IsCompanyBuildableVehicleType(type)); + + DeleteWindowById(WC_BUILD_VEHICLE, num); + + new BuildVehicleWindow(&_build_vehicle_desc, tile, type); +} diff --git a/src/error_gui.cpp.orig b/src/error_gui.cpp.orig new file mode 100644 index 0000000000..5e8f52432d --- /dev/null +++ b/src/error_gui.cpp.orig @@ -0,0 +1,432 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file error_gui.cpp GUI related to errors. */ + +#include "stdafx.h" +#include "landscape.h" +#include "newgrf_text.h" +#include "error.h" +#include "viewport_func.h" +#include "gfx_func.h" +#include "string_func.h" +#include "company_base.h" +#include "company_manager_face.h" +#include "strings_func.h" +#include "zoom_func.h" +#include "window_func.h" +#include "console_func.h" +#include "window_gui.h" + +#include "widgets/error_widget.h" + +#include "table/strings.h" +#include + +static const NWidgetPart _nested_errmsg_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_RED), + NWidget(WWT_CAPTION, COLOUR_RED, WID_EM_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION, STR_NULL), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_RED), + NWidget(WWT_EMPTY, COLOUR_RED, WID_EM_MESSAGE), SetPadding(0, 2, 0, 2), SetMinimalSize(236, 32), + EndContainer(), +}; + +static WindowDesc _errmsg_desc( + WDP_MANUAL, "error", 0, 0, + WC_ERRMSG, WC_NONE, + 0, + _nested_errmsg_widgets, lengthof(_nested_errmsg_widgets) +); + +static const NWidgetPart _nested_errmsg_face_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_RED), + NWidget(WWT_CAPTION, COLOUR_RED, WID_EM_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, STR_NULL), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_RED), + NWidget(NWID_HORIZONTAL), SetPIP(2, 1, 2), + NWidget(WWT_EMPTY, COLOUR_RED, WID_EM_FACE), SetMinimalSize(92, 119), SetFill(0, 1), SetPadding(2, 0, 1, 0), + NWidget(WWT_EMPTY, COLOUR_RED, WID_EM_MESSAGE), SetFill(0, 1), SetMinimalSize(238, 123), + EndContainer(), + EndContainer(), +}; + +static WindowDesc _errmsg_face_desc( + WDP_MANUAL, "error_face", 0, 0, + WC_ERRMSG, WC_NONE, + 0, + _nested_errmsg_face_widgets, lengthof(_nested_errmsg_face_widgets) +); + +/** + * Copy the given data into our instance. + * @param data The data to copy. + */ +ErrorMessageData::ErrorMessageData(const ErrorMessageData &data) +{ + *this = data; + for (size_t i = 0; i < lengthof(this->strings); i++) { + if (this->strings[i] != NULL) { + this->strings[i] = strdup(this->strings[i]); + this->decode_params[i] = (size_t)this->strings[i]; + } + } +} + +/** Free all the strings. */ +ErrorMessageData::~ErrorMessageData() +{ + for (size_t i = 0; i < lengthof(this->strings); i++) free(this->strings[i]); +} + +/** + * Display an error message in a window. + * @param summary_msg General error message showed in first line. Must be valid. + * @param detailed_msg Detailed error message showed in second line. Can be INVALID_STRING_ID. + * @param duration The amount of time to show this error message. + * @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. + * @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. + * @param textref_stack_grffile NewGRF that provides the #TextRefStack for the error message. + * @param textref_stack_size Number of uint32 values to put on the #TextRefStack for the error message; 0 if the #TextRefStack shall not be used. + * @param textref_stack Values to put on the #TextRefStack. + */ +ErrorMessageData::ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32 *textref_stack) : + duration(duration), + textref_stack_grffile(textref_stack_grffile), + textref_stack_size(textref_stack_size), + summary_msg(summary_msg), + detailed_msg(detailed_msg), + face(INVALID_COMPANY) +{ + this->position.x = x; + this->position.y = y; + + memset(this->decode_params, 0, sizeof(this->decode_params)); + memset(this->strings, 0, sizeof(this->strings)); + + if (textref_stack_size > 0) MemCpyT(this->textref_stack, textref_stack, textref_stack_size); + + assert(summary_msg != INVALID_STRING_ID); +} + +/** + * Copy error parameters from current DParams. + */ +void ErrorMessageData::CopyOutDParams() +{ + /* Reset parameters */ + for (size_t i = 0; i < lengthof(this->strings); i++) free(this->strings[i]); + memset(this->decode_params, 0, sizeof(this->decode_params)); + memset(this->strings, 0, sizeof(this->strings)); + + /* Get parameters using type information */ + if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack); + CopyOutDParam(this->decode_params, this->strings, this->detailed_msg == INVALID_STRING_ID ? this->summary_msg : this->detailed_msg, lengthof(this->decode_params)); + if (this->textref_stack_size > 0) StopTextRefStackUsage(); + + if (this->detailed_msg == STR_ERROR_OWNED_BY) { + CompanyID company = (CompanyID)GetDParamX(this->decode_params, 2); + if (company < MAX_COMPANIES) face = company; + } +} + +/** + * Set a error string parameter. + * @param n Parameter index + * @param v Parameter value + */ +void ErrorMessageData::SetDParam(uint n, uint64 v) +{ + this->decode_params[n] = v; +} + +/** + * Set a rawstring parameter. + * @param n Parameter index + * @param str Raw string + */ +void ErrorMessageData::SetDParamStr(uint n, const char *str) +{ + free(this->strings[n]); + this->strings[n] = strdup(str); +} + +/** Define a queue with errors. */ +typedef std::list ErrorList; +/** The actual queue with errors. */ +ErrorList _error_list; +/** Whether the window system is initialized or not. */ +bool _window_system_initialized = false; + +/** Window class for displaying an error message window. */ +struct ErrmsgWindow : public Window, ErrorMessageData { +private: + uint height_summary; ///< Height of the #summary_msg string in pixels in the #WID_EM_MESSAGE widget. + uint height_detailed; ///< Height of the #detailed_msg string in pixels in the #WID_EM_MESSAGE widget. + +public: + ErrmsgWindow(const ErrorMessageData &data) : Window(data.HasFace() ? &_errmsg_face_desc : &_errmsg_desc), ErrorMessageData(data) + { + this->InitNested(); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget != WID_EM_MESSAGE) return; + + CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); + if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack); + + int text_width = max(0, (int)size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT); + this->height_summary = GetStringHeight(this->summary_msg, text_width); + this->height_detailed = (this->detailed_msg == INVALID_STRING_ID) ? 0 : GetStringHeight(this->detailed_msg, text_width); + + if (this->textref_stack_size > 0) StopTextRefStackUsage(); + + uint panel_height = WD_FRAMERECT_TOP + this->height_summary + WD_FRAMERECT_BOTTOM; + if (this->detailed_msg != INVALID_STRING_ID) panel_height += this->height_detailed + WD_PAR_VSEP_WIDE; + + size->height = max(size->height, panel_height); + } + + virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + { + /* Position (0, 0) given, center the window. */ + if (this->position.x == 0 && this->position.y == 0) { + Point pt = {(_screen.width - sm_width) >> 1, (_screen.height - sm_height) >> 1}; + return pt; + } + + /* Find the free screen space between the main toolbar at the top, and the statusbar at the bottom. + * Add a fixed distance 20 to make it less cluttered. + */ + int scr_top = GetMainViewTop() + 20; + int scr_bot = GetMainViewBottom() - 20; + + Point pt = RemapCoords2(this->position.x, this->position.y); + const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; + if (this->face == INVALID_COMPANY) { + /* move x pos to opposite corner */ + pt.x = UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left; + pt.x = (pt.x < (_screen.width >> 1)) ? _screen.width - sm_width - 20 : 20; // Stay 20 pixels away from the edge of the screen. + + /* move y pos to opposite corner */ + pt.y = UnScaleByZoom(pt.y - vp->virtual_top, vp->zoom) + vp->top; + pt.y = (pt.y < (_screen.height >> 1)) ? scr_bot - sm_height : scr_top; + } else { + pt.x = Clamp(UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left - (sm_width / 2), 0, _screen.width - sm_width); + pt.y = Clamp(UnScaleByZoom(pt.y - vp->virtual_top, vp->zoom) + vp->top - (sm_height / 2), scr_top, scr_bot - sm_height); + } + return pt; + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + /* If company gets shut down, while displaying an error about it, remove the error message. */ + if (this->face != INVALID_COMPANY && !Company::IsValidID(this->face)) delete this; + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_EM_CAPTION) CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_EM_FACE: { + const Company *c = Company::Get(this->face); + DrawCompanyManagerFace(c->face, c->colour, r.left, r.top); + break; + } + + case WID_EM_MESSAGE: + CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); + if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack); + + if (this->detailed_msg == INVALID_STRING_ID) { + DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, + this->summary_msg, TC_FROMSTRING, SA_CENTER); + } else { + int extra = (r.bottom - r.top + 1 - this->height_summary - this->height_detailed - WD_PAR_VSEP_WIDE) / 2; + + /* Note: NewGRF supplied error message often do not start with a colour code, so default to white. */ + int top = r.top + WD_FRAMERECT_TOP; + int bottom = top + this->height_summary + extra; + DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, top, bottom, this->summary_msg, TC_WHITE, SA_CENTER); + + bottom = r.bottom - WD_FRAMERECT_BOTTOM; + top = bottom - this->height_detailed - extra; + DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, top, bottom, this->detailed_msg, TC_WHITE, SA_CENTER); + } + + if (this->textref_stack_size > 0) StopTextRefStackUsage(); + break; + + default: + break; + } + } + + virtual void OnMouseLoop() + { + /* Disallow closing the window too easily, if timeout is disabled */ + if (_right_button_down && this->duration != 0) delete this; + } + + virtual void OnHundredthTick() + { + /* Timeout enabled? */ + if (this->duration != 0) { + this->duration--; + if (this->duration == 0) delete this; + } + } + + ~ErrmsgWindow() + { + SetRedErrorSquare(INVALID_TILE); + if (_window_system_initialized) ShowFirstError(); + } + + virtual EventState OnKeyPress(WChar key, uint16 keycode) + { + if (keycode != WKC_SPACE) return ES_NOT_HANDLED; + delete this; + return ES_HANDLED; + } + + /** + * Check whether the currently shown error message was critical or not. + * @return True iff the message was critical. + */ + bool IsCritical() + { + return this->duration == 0; + } +}; + +/** + * Clear all errors from the queue. + */ +void ClearErrorMessages() +{ + UnshowCriticalError(); + _error_list.clear(); +} + +/** Show the first error of the queue. */ +void ShowFirstError() +{ + _window_system_initialized = true; + if (!_error_list.empty()) { + new ErrmsgWindow(_error_list.front()); + _error_list.pop_front(); + } +} + +/** + * Unshow the critical error. This has to happen when a critical + * error is shown and we uninitialise the window system, i.e. + * remove all the windows. + */ +void UnshowCriticalError() +{ + ErrmsgWindow *w = (ErrmsgWindow*)FindWindowById(WC_ERRMSG, 0); + if (_window_system_initialized && w != NULL) { + if (w->IsCritical()) _error_list.push_front(*w); + _window_system_initialized = false; + delete w; + } +} + +/** + * Display an error message in a window. + * @param summary_msg General error message showed in first line. Must be valid. + * @param detailed_msg Detailed error message showed in second line. Can be INVALID_STRING_ID. + * @param wl Message severity. + * @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. + * @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. + * @param textref_stack_grffile NewGRF providing the #TextRefStack for the error message. + * @param textref_stack_size Number of uint32 values to put on the #TextRefStack for the error message; 0 if the #TextRefStack shall not be used. + * @param textref_stack Values to put on the #TextRefStack. + */ +void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32 *textref_stack) +{ + assert(textref_stack_size == 0 || (textref_stack_grffile != NULL && textref_stack != NULL)); + if (summary_msg == STR_NULL) summary_msg = STR_EMPTY; + + if (wl != WL_INFO) { + /* Print message to console */ + char buf[DRAW_STRING_BUFFER]; + + if (textref_stack_size > 0) StartTextRefStackUsage(textref_stack_grffile, textref_stack_size, textref_stack); + + char *b = GetString(buf, summary_msg, lastof(buf)); + if (detailed_msg != INVALID_STRING_ID) { + b += seprintf(b, lastof(buf), " "); + GetString(b, detailed_msg, lastof(buf)); + } + + if (textref_stack_size > 0) StopTextRefStackUsage(); + + switch (wl) { + case WL_WARNING: IConsolePrint(CC_WARNING, buf); break; + default: IConsoleError(buf); break; + } + } + + bool no_timeout = wl == WL_CRITICAL; + + if (_settings_client.gui.errmsg_duration == 0 && !no_timeout) return; + + ErrorMessageData data(summary_msg, detailed_msg, no_timeout ? 0 : _settings_client.gui.errmsg_duration, x, y, textref_stack_grffile, textref_stack_size, textref_stack); + data.CopyOutDParams(); + + ErrmsgWindow *w = (ErrmsgWindow*)FindWindowById(WC_ERRMSG, 0); + if (w != NULL && w->IsCritical()) { + /* A critical error is currently shown. */ + if (wl == WL_CRITICAL) { + /* Push another critical error in the queue of errors, + * but do not put other errors in the queue. */ + _error_list.push_back(data); + } + } else { + /* Nothing or a non-critical error was shown. */ + delete w; + new ErrmsgWindow(data); + } +} + +/** + * Schedule a list of errors. + * Note: This does not try to display the error now. This is useful if the window system is not yet running. + * @param data Error message datas; cleared afterwards + */ +void ScheduleErrorMessage(ErrorList &datas) +{ + _error_list.splice(_error_list.end(), datas); +} + +/** + * Schedule an error. + * Note: This does not try to display the error now. This is useful if the window system is not yet running. + * @param data Error message data; cleared afterwards + */ +void ScheduleErrorMessage(const ErrorMessageData &data) +{ + _error_list.push_back(data); +} diff --git a/src/gfx.cpp.orig b/src/gfx.cpp.orig new file mode 100644 index 0000000000..01f29b9fb9 --- /dev/null +++ b/src/gfx.cpp.orig @@ -0,0 +1,1697 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file gfx.cpp Handling of drawing text and other gfx related stuff. */ + +#include "stdafx.h" +#include "gfx_layout.h" +#include "progress.h" +#include "zoom_func.h" +#include "blitter/factory.hpp" +#include "video/video_driver.hpp" +#include "strings_func.h" +#include "settings_type.h" +#include "network/network.h" +#include "network/network_func.h" +#include "window_func.h" +#include "newgrf_debug.h" + +#include "table/palettes.h" +#include "table/sprites.h" +#include "table/control_codes.h" + +byte _dirkeys; ///< 1 = left, 2 = up, 4 = right, 8 = down +bool _fullscreen; +CursorVars _cursor; +bool _ctrl_pressed; ///< Is Ctrl pressed? +bool _shift_pressed; ///< Is Shift pressed? +byte _fast_forward; +bool _left_button_down; ///< Is left mouse button pressed? +bool _left_button_clicked; ///< Is left mouse button clicked? +bool _right_button_down; ///< Is right mouse button pressed? +bool _right_button_clicked; ///< Is right mouse button clicked? +DrawPixelInfo _screen; +bool _screen_disable_anim = false; ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot) +bool _exit_game; +GameMode _game_mode; +SwitchMode _switch_mode; ///< The next mainloop command. +PauseModeByte _pause_mode; +Palette _cur_palette; + +static byte _stringwidth_table[FS_END][224]; ///< Cache containing width of often used characters. @see GetCharacterWidth() +DrawPixelInfo *_cur_dpi; +byte _colour_gradient[COLOUR_END][8]; + +static void GfxMainBlitterViewport(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL, SpriteID sprite_id = SPR_CURSOR_MOUSE); +static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL, SpriteID sprite_id = SPR_CURSOR_MOUSE, ZoomLevel zoom = ZOOM_LVL_NORMAL); + +static ReusableBuffer _cursor_backup; + +/** + * The rect for repaint. + * + * This rectangle defines the area which should be repaint by the video driver. + * + * @ingroup dirty + */ +static Rect _invalid_rect; +static const byte *_colour_remap_ptr; +static byte _string_colourremap[3]; ///< Recoloursprite for stringdrawing. The grf loader ensures that #ST_FONT sprites only use colours 0 to 2. + +static const uint DIRTY_BLOCK_HEIGHT = 8; +static const uint DIRTY_BLOCK_WIDTH = 64; + +static uint _dirty_bytes_per_line = 0; +static byte *_dirty_blocks = NULL; +extern uint _dirty_block_colour; + +void GfxScroll(int left, int top, int width, int height, int xo, int yo) +{ + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + + if (xo == 0 && yo == 0) return; + + if (_cursor.visible) UndrawMouseCursor(); + +#ifdef ENABLE_NETWORK + if (_networking) NetworkUndrawChatMessage(); +#endif /* ENABLE_NETWORK */ + + blitter->ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo); + /* This part of the screen is now dirty. */ + _video_driver->MakeDirty(left, top, width, height); +} + + +/** + * Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen. + * + * @pre dpi->zoom == ZOOM_LVL_NORMAL, right >= left, bottom >= top + * @param left Minimum X (inclusive) + * @param top Minimum Y (inclusive) + * @param right Maximum X (inclusive) + * @param bottom Maximum Y (inclusive) + * @param colour A 8 bit palette index (FILLRECT_OPAQUE and FILLRECT_CHECKER) or a recolour spritenumber (FILLRECT_RECOLOUR) + * @param mode + * FILLRECT_OPAQUE: Fill the rectangle with the specified colour + * FILLRECT_CHECKER: Like FILLRECT_OPAQUE, but only draw every second pixel (used to grey out things) + * FILLRECT_RECOLOUR: Apply a recolour sprite to every pixel in the rectangle currently on screen + */ +void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode) +{ + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + const DrawPixelInfo *dpi = _cur_dpi; + void *dst; + const int otop = top; + const int oleft = left; + + if (dpi->zoom != ZOOM_LVL_NORMAL) return; + if (left > right || top > bottom) return; + if (right < dpi->left || left >= dpi->left + dpi->width) return; + if (bottom < dpi->top || top >= dpi->top + dpi->height) return; + + if ( (left -= dpi->left) < 0) left = 0; + right = right - dpi->left + 1; + if (right > dpi->width) right = dpi->width; + right -= left; + assert(right > 0); + + if ( (top -= dpi->top) < 0) top = 0; + bottom = bottom - dpi->top + 1; + if (bottom > dpi->height) bottom = dpi->height; + bottom -= top; + assert(bottom > 0); + + dst = blitter->MoveTo(dpi->dst_ptr, left, top); + + switch (mode) { + default: // FILLRECT_OPAQUE + blitter->DrawRect(dst, right, bottom, (uint8)colour); + break; + + case FILLRECT_RECOLOUR: + blitter->DrawColourMappingRect(dst, right, bottom, GB(colour, 0, PALETTE_WIDTH)); + break; + + case FILLRECT_CHECKER: { + byte bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1; + do { + for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8)colour); + dst = blitter->MoveTo(dst, 0, 1); + } while (--bottom > 0); + break; + } + } +} + +/** + * Check line clipping by using a linear equation and draw the visible part of + * the line given by x/y and x2/y2. + * @param video Destination pointer to draw into. + * @param x X coordinate of first point. + * @param y Y coordinate of first point. + * @param x2 X coordinate of second point. + * @param y2 Y coordinate of second point. + * @param screen_width With of the screen to check clipping against. + * @param screen_height Height of the screen to check clipping against. + * @param colour Colour of the line. + * @param width Width of the line. + * @param dash Length of dashes for dashed lines. 0 means solid line. + */ +static inline void GfxDoDrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash = 0) +{ + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + + assert(width > 0); + + if (y2 == y) { + /* Special case: horizontal line. */ + blitter->DrawLine(video, + Clamp(x, 0, screen_width), y, + Clamp(x2, 0, screen_width), y2, + screen_width, screen_height, colour, width, dash); + return; + } + if (x2 == x) { + /* Special case: vertical line. */ + blitter->DrawLine(video, + x, Clamp(y, 0, screen_height), + x2, Clamp(y2, 0, screen_height), + screen_width, screen_height, colour, width, dash); + return; + } + + int grade_y = y2 - y; + int grade_x = x2 - x; + + /* prevent integer overflows. */ + int margin = 1; + while (INT_MAX / abs(grade_y) < max(abs(x), abs(screen_width - x))) { + grade_y /= 2; + grade_x /= 2; + margin *= 2; // account for rounding errors + } + + /* If the line is outside the screen on the same side at X positions 0 + * and screen_width, we don't need to draw anything. */ + int offset_0 = y - x * grade_y / grade_x; + int offset_width = y + (screen_width - x) * grade_y / grade_x; + if ((offset_0 > screen_height + width / 2 + margin && offset_width > screen_height + width / 2 + margin) || + (offset_0 < -width / 2 - margin && offset_width < -width / 2 - margin)) { + return; + } + + /* It is possible to use the line equation to further reduce the amount of + * work the blitter has to do by shortening the effective line segment. + * However, in order to get that right and prevent the flickering effects + * of rounding errors so much additional code has to be run here that in + * the general case the effect is not noticable. */ + + blitter->DrawLine(video, x, y, x2, y2, screen_width, screen_height, colour, width, dash); +} + +/** + * Align parameters of a line to the given DPI and check simple clipping. + * @param dpi Screen parameters to align with. + * @param x X coordinate of first point. + * @param y Y coordinate of first point. + * @param x2 X coordinate of second point. + * @param y2 Y coordinate of second point. + * @param width Width of the line. + * @return True if the line is likely to be visible, false if it's certainly + * invisible. + */ +static inline bool GfxPreprocessLine(DrawPixelInfo *dpi, int &x, int &y, int &x2, int &y2, int width) +{ + x -= dpi->left; + x2 -= dpi->left; + y -= dpi->top; + y2 -= dpi->top; + + /* Check simple clipping */ + if (x + width / 2 < 0 && x2 + width / 2 < 0 ) return false; + if (y + width / 2 < 0 && y2 + width / 2 < 0 ) return false; + if (x - width / 2 > dpi->width && x2 - width / 2 > dpi->width ) return false; + if (y - width / 2 > dpi->height && y2 - width / 2 > dpi->height) return false; + return true; +} + +void GfxDrawLine(int x, int y, int x2, int y2, int colour, int width, int dash) +{ + DrawPixelInfo *dpi = _cur_dpi; + if (GfxPreprocessLine(dpi, x, y, x2, y2, width)) { + GfxDoDrawLine(dpi->dst_ptr, x, y, x2, y2, dpi->width, dpi->height, colour, width, dash); + } +} + +void GfxDrawLineUnscaled(int x, int y, int x2, int y2, int colour) +{ + DrawPixelInfo *dpi = _cur_dpi; + if (GfxPreprocessLine(dpi, x, y, x2, y2, 1)) { + GfxDoDrawLine(dpi->dst_ptr, + UnScaleByZoom(x, dpi->zoom), UnScaleByZoom(y, dpi->zoom), + UnScaleByZoom(x2, dpi->zoom), UnScaleByZoom(y2, dpi->zoom), + UnScaleByZoom(dpi->width, dpi->zoom), UnScaleByZoom(dpi->height, dpi->zoom), colour, 1); + } +} + +/** + * Draws the projection of a parallelepiped. + * This can be used to draw boxes in world coordinates. + * + * @param x Screen X-coordinate of top front corner. + * @param y Screen Y-coordinate of top front corner. + * @param dx1 Screen X-length of first edge. + * @param dy1 Screen Y-length of first edge. + * @param dx2 Screen X-length of second edge. + * @param dy2 Screen Y-length of second edge. + * @param dx3 Screen X-length of third edge. + * @param dy3 Screen Y-length of third edge. + */ +void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3) +{ + /* .... + * .. .... + * .. .... + * .. ^ + * <--__(dx1,dy1) /(dx2,dy2) + * : --__ / : + * : --__ / : + * : *(x,y) : + * : | : + * : | .. + * .... |(dx3,dy3) + * .... | .. + * ....V. + */ + + static const byte colour = PC_WHITE; + + GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, colour); + GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, colour); + GfxDrawLineUnscaled(x, y, x + dx3, y + dy3, colour); + + GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx2, y + dy1 + dy2, colour); + GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx3, y + dy1 + dy3, colour); + GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx1, y + dy2 + dy1, colour); + GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx3, y + dy2 + dy3, colour); + GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx1, y + dy3 + dy1, colour); + GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx2, y + dy3 + dy2, colour); +} + +/** + * Set the colour remap to be for the given colour. + * @param colour the new colour of the remap. + */ +static void SetColourRemap(TextColour colour) +{ + if (colour == TC_INVALID) return; + + /* Black strings have no shading ever; the shading is black, so it + * would be invisible at best, but it actually makes it illegible. */ + bool no_shade = (colour & TC_NO_SHADE) != 0 || colour == TC_BLACK; + bool raw_colour = (colour & TC_IS_PALETTE_COLOUR) != 0; + colour &= ~(TC_NO_SHADE | TC_IS_PALETTE_COLOUR); + + _string_colourremap[1] = raw_colour ? (byte)colour : _string_colourmap[colour]; + _string_colourremap[2] = no_shade ? 0 : 1; + _colour_remap_ptr = _string_colourremap; +} + +/** + * Drawing routine for drawing a laid out line of text. + * @param line String to draw. + * @param y The top most position to draw on. + * @param left The left most position to draw on. + * @param right The right most position to draw on. + * @param align The alignment of the string when drawing left-to-right. In the + * case a right-to-left language is chosen this is inverted so it + * will be drawn in the right direction. + * @param underline Whether to underline what has been drawn or not. + * @param truncation Whether to perform string truncation or not. + * + * @return In case of left or center alignment the right most pixel we have drawn to. + * In case of right alignment the left most pixel we have drawn to. + */ +static int DrawLayoutLine(const ParagraphLayouter::Line *line, int y, int left, int right, StringAlignment align, bool underline, bool truncation) +{ + if (line->CountRuns() == 0) return 0; + + int w = line->GetWidth(); + int h = line->GetLeading(); + + /* + * The following is needed for truncation. + * Depending on the text direction, we either remove bits at the rear + * or the front. For this we shift the entire area to draw so it fits + * within the left/right bounds and the side we do not truncate it on. + * Then we determine the truncation location, i.e. glyphs that fall + * outside of the range min_x - max_x will not be drawn; they are thus + * the truncated glyphs. + * + * At a later step we insert the dots. + */ + + int max_w = right - left + 1; // The maximum width. + + int offset_x = 0; // The offset we need for positioning the glyphs + int min_x = left; // The minimum x position to draw normal glyphs on. + int max_x = right; // The maximum x position to draw normal glyphs on. + + truncation &= max_w < w; // Whether we need to do truncation. + int dot_width = 0; // Cache for the width of the dot. + const Sprite *dot_sprite = NULL; // Cache for the sprite of the dot. + + if (truncation) { + /* + * Assumption may be made that all fonts of a run are of the same size. + * In any case, we'll use these dots for the abbreviation, so even if + * another size would be chosen it won't have truncated too little for + * the truncation dots. + */ + FontCache *fc = ((const Font*)line->GetVisualRun(0)->GetFont())->fc; + GlyphID dot_glyph = fc->MapCharToGlyph('.'); + dot_width = fc->GetGlyphWidth(dot_glyph); + dot_sprite = fc->GetGlyph(dot_glyph); + + if (_current_text_dir == TD_RTL) { + min_x += 3 * dot_width; + offset_x = w - 3 * dot_width - max_w; + } else { + max_x -= 3 * dot_width; + } + + w = max_w; + } + + /* In case we have a RTL language we swap the alignment. */ + if (!(align & SA_FORCE) && _current_text_dir == TD_RTL && (align & SA_HOR_MASK) != SA_HOR_CENTER) align ^= SA_RIGHT; + + /* right is the right most position to draw on. In this case we want to do + * calculations with the width of the string. In comparison right can be + * seen as lastof(todraw) and width as lengthof(todraw). They differ by 1. + * So most +1/-1 additions are to move from lengthof to 'indices'. + */ + switch (align & SA_HOR_MASK) { + case SA_LEFT: + /* right + 1 = left + w */ + right = left + w - 1; + break; + + case SA_HOR_CENTER: + left = RoundDivSU(right + 1 + left - w, 2); + /* right + 1 = left + w */ + right = left + w - 1; + break; + + case SA_RIGHT: + left = right + 1 - w; + break; + + default: + NOT_REACHED(); + } + + for (int run_index = 0; run_index < line->CountRuns(); run_index++) { + const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index); + const Font *f = (const Font*)run->GetFont(); + + FontCache *fc = f->fc; + TextColour colour = f->colour; + SetColourRemap(colour); + + DrawPixelInfo *dpi = _cur_dpi; + int dpi_left = dpi->left; + int dpi_right = dpi->left + dpi->width - 1; + + bool draw_shadow = fc->GetDrawGlyphShadow() && colour != TC_BLACK; + + for (int i = 0; i < run->GetGlyphCount(); i++) { + GlyphID glyph = run->GetGlyphs()[i]; + + /* Not a valid glyph (empty) */ + if (glyph == 0xFFFF) continue; + + int begin_x = (int)run->GetPositions()[i * 2] + left - offset_x; + int end_x = (int)run->GetPositions()[i * 2 + 2] + left - offset_x - 1; + int top = (int)run->GetPositions()[i * 2 + 1] + y; + + /* Truncated away. */ + if (truncation && (begin_x < min_x || end_x > max_x)) continue; + + const Sprite *sprite = fc->GetGlyph(glyph); + /* Check clipping (the "+ 1" is for the shadow). */ + if (begin_x + sprite->x_offs > dpi_right || begin_x + sprite->x_offs + sprite->width /* - 1 + 1 */ < dpi_left) continue; + + if (draw_shadow && (glyph & SPRITE_GLYPH) == 0) { + SetColourRemap(TC_BLACK); + GfxMainBlitter(sprite, begin_x + 1, top + 1, BM_COLOUR_REMAP); + SetColourRemap(colour); + } + GfxMainBlitter(sprite, begin_x, top, BM_COLOUR_REMAP); + } + } + + if (truncation) { + int x = (_current_text_dir == TD_RTL) ? left : (right - 3 * dot_width); + for (int i = 0; i < 3; i++, x += dot_width) { + GfxMainBlitter(dot_sprite, x, y, BM_COLOUR_REMAP); + } + } + + if (underline) { + GfxFillRect(left, y + h, right, y + h, _string_colourremap[1]); + } + + return (align & SA_HOR_MASK) == SA_RIGHT ? left : right; +} + +/** + * Draw string, possibly truncated to make it fit in its allocated space + * + * @param left The left most position to draw on. + * @param right The right most position to draw on. + * @param top The top most position to draw on. + * @param str String to draw. + * @param colour Colour used for drawing the string, see DoDrawString() for details + * @param align The alignment of the string when drawing left-to-right. In the + * case a right-to-left language is chosen this is inverted so it + * will be drawn in the right direction. + * @param underline Whether to underline what has been drawn or not. + * @param fontsize The size of the initial characters. + * @return In case of left or center alignment the right most pixel we have drawn to. + * In case of right alignment the left most pixel we have drawn to. + */ +int DrawString(int left, int right, int top, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) +{ + /* The string may contain control chars to change the font, just use the biggest font for clipping. */ + int max_height = max(max(FONT_HEIGHT_SMALL, FONT_HEIGHT_NORMAL), max(FONT_HEIGHT_LARGE, FONT_HEIGHT_MONO)); + + /* Funny glyphs may extent outside the usual bounds, so relax the clipping somewhat. */ + int extra = max_height / 2; + + if (_cur_dpi->top + _cur_dpi->height + extra < top || _cur_dpi->top > top + max_height + extra || + _cur_dpi->left + _cur_dpi->width + extra < left || _cur_dpi->left > right + extra) { + return 0; + } + + Layouter layout(str, INT32_MAX, colour, fontsize); + if (layout.Length() == 0) return 0; + + return DrawLayoutLine(*layout.Begin(), top, left, right, align, underline, true); +} + +/** + * Draw string, possibly truncated to make it fit in its allocated space + * + * @param left The left most position to draw on. + * @param right The right most position to draw on. + * @param top The top most position to draw on. + * @param str String to draw. + * @param colour Colour used for drawing the string, see DoDrawString() for details + * @param align The alignment of the string when drawing left-to-right. In the + * case a right-to-left language is chosen this is inverted so it + * will be drawn in the right direction. + * @param underline Whether to underline what has been drawn or not. + * @param fontsize The size of the initial characters. + * @return In case of left or center alignment the right most pixel we have drawn to. + * In case of right alignment the left most pixel we have drawn to. + */ +int DrawString(int left, int right, int top, StringID str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) +{ + char buffer[DRAW_STRING_BUFFER]; + GetString(buffer, str, lastof(buffer)); + return DrawString(left, right, top, buffer, colour, align, underline, fontsize); +} + +/** + * Calculates height of string (in pixels). The string is changed to a multiline string if needed. + * @param str string to check + * @param maxw maximum string width + * @return height of pixels of string when it is drawn + */ +int GetStringHeight(const char *str, int maxw, FontSize fontsize) +{ + Layouter layout(str, maxw, TC_FROMSTRING, fontsize); + return layout.GetBounds().height; +} + +/** + * Calculates height of string (in pixels). The string is changed to a multiline string if needed. + * @param str string to check + * @param maxw maximum string width + * @return height of pixels of string when it is drawn + */ +int GetStringHeight(StringID str, int maxw) +{ + char buffer[DRAW_STRING_BUFFER]; + GetString(buffer, str, lastof(buffer)); + return GetStringHeight(buffer, maxw); +} + +/** + * Calculates number of lines of string. The string is changed to a multiline string if needed. + * @param str string to check + * @param maxw maximum string width + * @return number of lines of string when it is drawn + */ +int GetStringLineCount(StringID str, int maxw) +{ + char buffer[DRAW_STRING_BUFFER]; + GetString(buffer, str, lastof(buffer)); + + Layouter layout(buffer, maxw); + return layout.Length(); +} + +/** + * Calculate string bounding box for multi-line strings. + * @param str String to check. + * @param suggestion Suggested bounding box. + * @return Bounding box for the multi-line string, may be bigger than \a suggestion. + */ +Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion) +{ + Dimension box = {suggestion.width, GetStringHeight(str, suggestion.width)}; + return box; +} + +/** + * Calculate string bounding box for multi-line strings. + * @param str String to check. + * @param suggestion Suggested bounding box. + * @return Bounding box for the multi-line string, may be bigger than \a suggestion. + */ +Dimension GetStringMultiLineBoundingBox(const char *str, const Dimension &suggestion) +{ + Dimension box = {suggestion.width, GetStringHeight(str, suggestion.width)}; + return box; +} + +/** + * Draw string, possibly over multiple lines. + * + * @param left The left most position to draw on. + * @param right The right most position to draw on. + * @param top The top most position to draw on. + * @param bottom The bottom most position to draw on. + * @param str String to draw. + * @param colour Colour used for drawing the string, see DoDrawString() for details + * @param align The horizontal and vertical alignment of the string. + * @param underline Whether to underline all strings + * @param fontsize The size of the initial characters. + * + * @return If \a align is #SA_BOTTOM, the top to where we have written, else the bottom to where we have written. + */ +int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) +{ + int maxw = right - left + 1; + int maxh = bottom - top + 1; + + /* It makes no sense to even try if it can't be drawn anyway, or + * do we really want to support fonts of 0 or less pixels high? */ + if (maxh <= 0) return top; + + Layouter layout(str, maxw, colour, fontsize); + int total_height = layout.GetBounds().height; + int y; + switch (align & SA_VERT_MASK) { + case SA_TOP: + y = top; + break; + + case SA_VERT_CENTER: + y = RoundDivSU(bottom + top - total_height, 2); + break; + + case SA_BOTTOM: + y = bottom - total_height; + break; + + default: NOT_REACHED(); + } + + int last_line = top; + int first_line = bottom; + + for (const ParagraphLayouter::Line **iter = layout.Begin(); iter != layout.End(); iter++) { + const ParagraphLayouter::Line *line = *iter; + + int line_height = line->GetLeading(); + if (y >= top && y < bottom) { + last_line = y + line_height; + if (first_line > y) first_line = y; + + DrawLayoutLine(line, y, left, right, align, underline, false); + } + y += line_height; + } + + return ((align & SA_VERT_MASK) == SA_BOTTOM) ? first_line : last_line; +} + +/** + * Draw string, possibly over multiple lines. + * + * @param left The left most position to draw on. + * @param right The right most position to draw on. + * @param top The top most position to draw on. + * @param bottom The bottom most position to draw on. + * @param str String to draw. + * @param colour Colour used for drawing the string, see DoDrawString() for details + * @param align The horizontal and vertical alignment of the string. + * @param underline Whether to underline all strings + * @param fontsize The size of the initial characters. + * + * @return If \a align is #SA_BOTTOM, the top to where we have written, else the bottom to where we have written. + */ +int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) +{ + char buffer[DRAW_STRING_BUFFER]; + GetString(buffer, str, lastof(buffer)); + return DrawStringMultiLine(left, right, top, bottom, buffer, colour, align, underline, fontsize); +} + +/** + * Return the string dimension in pixels. The height and width are returned + * in a single Dimension value. TINYFONT, BIGFONT modifiers are only + * supported as the first character of the string. The returned dimensions + * are therefore a rough estimation correct for all the current strings + * but not every possible combination + * @param str string to calculate pixel-width + * @param start_fontsize Fontsize to start the text with + * @return string width and height in pixels + */ +Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize) +{ + Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); + return layout.GetBounds(); +} + +/** + * Get bounding box of a string. Uses parameters set by #DParam if needed. + * Has the same restrictions as #GetStringBoundingBox(const char *str). + * @param strid String to examine. + * @return Width and height of the bounding box for the string in pixels. + */ +Dimension GetStringBoundingBox(StringID strid) +{ + char buffer[DRAW_STRING_BUFFER]; + + GetString(buffer, strid, lastof(buffer)); + return GetStringBoundingBox(buffer); +} + +/** + * Get the leading corner of a character in a single-line string relative + * to the start of the string. + * @param str String containing the character. + * @param ch Pointer to the character in the string. + * @param start_fontsize Font size to start the text with. + * @return Upper left corner of the glyph associated with the character. + */ +Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsize) +{ + Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); + return layout.GetCharPosition(ch); +} + +/** + * Get the character from a string that is drawn at a specific position. + * @param str String to test. + * @param x Position relative to the start of the string. + * @param start_fontsize Font size to start the text with. + * @return Pointer to the character at the position or NULL if there is no character at the position. + */ +const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize) +{ + if (x < 0) return NULL; + + Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); + return layout.GetCharAtPosition(x); +} + +/** + * Draw single character horizontally centered around (x,y) + * @param c Character (glyph) to draw + * @param x X position to draw character + * @param y Y position to draw character + * @param colour Colour to use, see DoDrawString() for details + */ +void DrawCharCentered(WChar c, int x, int y, TextColour colour) +{ + SetColourRemap(colour); + GfxMainBlitter(GetGlyph(FS_NORMAL, c), x - GetCharacterWidth(FS_NORMAL, c) / 2, y, BM_COLOUR_REMAP); +} + +/** + * Get the size of a sprite. + * @param sprid Sprite to examine. + * @param [out] offset Optionally returns the sprite position offset. + * @return Sprite size in pixels. + * @note The size assumes (0, 0) as top-left coordinate and ignores any part of the sprite drawn at the left or above that position. + */ +Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom) +{ + const Sprite *sprite = GetSprite(sprid, ST_NORMAL); + + if (offset != NULL) { + offset->x = UnScaleByZoom(sprite->x_offs, zoom); + offset->y = UnScaleByZoom(sprite->y_offs, zoom); + } + + Dimension d; + d.width = max(0, UnScaleByZoom(sprite->x_offs + sprite->width, zoom)); + d.height = max(0, UnScaleByZoom(sprite->y_offs + sprite->height, zoom)); + return d; +} + +/** + * Draw a sprite in a viewport. + * @param img Image number to draw + * @param pal Palette to use. + * @param x Left coordinate of image in viewport, scaled by zoom + * @param y Top coordinate of image in viewport, scaled by zoom + * @param sub If available, draw only specified part of the sprite + */ +void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub) +{ + SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH); + if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) { + _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; + GfxMainBlitterViewport(GetSprite(real_sprite, ST_NORMAL), x, y, BM_TRANSPARENT, sub, real_sprite); + } else if (pal != PAL_NONE) { + _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; + GfxMainBlitterViewport(GetSprite(real_sprite, ST_NORMAL), x, y, BM_COLOUR_REMAP, sub, real_sprite); + } else { + GfxMainBlitterViewport(GetSprite(real_sprite, ST_NORMAL), x, y, BM_NORMAL, sub, real_sprite); + } +} + +/** + * Draw a sprite, not in a viewport + * @param img Image number to draw + * @param pal Palette to use. + * @param x Left coordinate of image in pixels + * @param y Top coordinate of image in pixels + * @param sub If available, draw only specified part of the sprite + * @param zoom Zoom level of sprite + */ +void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom) +{ + SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH); + if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) { + _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; + GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_TRANSPARENT, sub, real_sprite, zoom); + } else if (pal != PAL_NONE) { + _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; + GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_COLOUR_REMAP, sub, real_sprite, zoom); + } else { + GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_NORMAL, sub, real_sprite, zoom); + } +} + +/** + * The code for setting up the blitter mode and sprite information before finally drawing the sprite. + * @param sprite The sprite to draw. + * @param x The X location to draw. + * @param y The Y location to draw. + * @param mode The settings for the blitter to pass. + * @param sub Whether to only draw a sub set of the sprite. + * @param zoom The zoom level at which to draw the sprites. + * @tparam ZOOM_BASE The factor required to get the sub sprite information into the right size. + * @tparam SCALED_XY Whether the X and Y are scaled or unscaled. + */ +template +static void GfxBlitter(const Sprite * const sprite, int x, int y, BlitterMode mode, const SubSprite * const sub, SpriteID sprite_id, ZoomLevel zoom) +{ + const DrawPixelInfo *dpi = _cur_dpi; + Blitter::BlitterParams bp; + + if (SCALED_XY) { + /* Scale it */ + x = ScaleByZoom(x, zoom); + y = ScaleByZoom(y, zoom); + } + + /* Move to the correct offset */ + x += sprite->x_offs; + y += sprite->y_offs; + + if (sub == NULL) { + /* No clipping. */ + bp.skip_left = 0; + bp.skip_top = 0; + bp.width = UnScaleByZoom(sprite->width, zoom); + bp.height = UnScaleByZoom(sprite->height, zoom); + } else { + /* Amount of pixels to clip from the source sprite */ + int clip_left = max(0, -sprite->x_offs + sub->left * ZOOM_BASE ); + int clip_top = max(0, -sprite->y_offs + sub->top * ZOOM_BASE ); + int clip_right = max(0, sprite->width - (-sprite->x_offs + (sub->right + 1) * ZOOM_BASE)); + int clip_bottom = max(0, sprite->height - (-sprite->y_offs + (sub->bottom + 1) * ZOOM_BASE)); + + if (clip_left + clip_right >= sprite->width) return; + if (clip_top + clip_bottom >= sprite->height) return; + + bp.skip_left = UnScaleByZoomLower(clip_left, zoom); + bp.skip_top = UnScaleByZoomLower(clip_top, zoom); + bp.width = UnScaleByZoom(sprite->width - clip_left - clip_right, zoom); + bp.height = UnScaleByZoom(sprite->height - clip_top - clip_bottom, zoom); + + x += ScaleByZoom(bp.skip_left, zoom); + y += ScaleByZoom(bp.skip_top, zoom); + } + + /* Copy the main data directly from the sprite */ + bp.sprite = sprite->data; + bp.sprite_width = sprite->width; + bp.sprite_height = sprite->height; + bp.top = 0; + bp.left = 0; + + bp.dst = dpi->dst_ptr; + bp.pitch = dpi->pitch; + bp.remap = _colour_remap_ptr; + + assert(sprite->width > 0); + assert(sprite->height > 0); + + if (bp.width <= 0) return; + if (bp.height <= 0) return; + + y -= SCALED_XY ? ScaleByZoom(dpi->top, zoom) : dpi->top; + int y_unscaled = UnScaleByZoom(y, zoom); + /* Check for top overflow */ + if (y < 0) { + bp.height -= -y_unscaled; + if (bp.height <= 0) return; + bp.skip_top += -y_unscaled; + y = 0; + } else { + bp.top = y_unscaled; + } + + /* Check for bottom overflow */ + y += SCALED_XY ? ScaleByZoom(bp.height - dpi->height, zoom) : ScaleByZoom(bp.height, zoom) - dpi->height; + if (y > 0) { + bp.height -= UnScaleByZoom(y, zoom); + if (bp.height <= 0) return; + } + + x -= SCALED_XY ? ScaleByZoom(dpi->left, zoom) : dpi->left; + int x_unscaled = UnScaleByZoom(x, zoom); + /* Check for left overflow */ + if (x < 0) { + bp.width -= -x_unscaled; + if (bp.width <= 0) return; + bp.skip_left += -x_unscaled; + x = 0; + } else { + bp.left = x_unscaled; + } + + /* Check for right overflow */ + x += SCALED_XY ? ScaleByZoom(bp.width - dpi->width, zoom) : ScaleByZoom(bp.width, zoom) - dpi->width; + if (x > 0) { + bp.width -= UnScaleByZoom(x, zoom); + if (bp.width <= 0) return; + } + + assert(bp.skip_left + bp.width <= UnScaleByZoom(sprite->width, zoom)); + assert(bp.skip_top + bp.height <= UnScaleByZoom(sprite->height, zoom)); + + /* We do not want to catch the mouse. However we also use that spritenumber for unknown (text) sprites. */ + if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW && sprite_id != SPR_CURSOR_MOUSE) { + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + void *topleft = blitter->MoveTo(bp.dst, bp.left, bp.top); + void *bottomright = blitter->MoveTo(topleft, bp.width - 1, bp.height - 1); + + void *clicked = _newgrf_debug_sprite_picker.clicked_pixel; + + if (topleft <= clicked && clicked <= bottomright) { + uint offset = (((size_t)clicked - (size_t)topleft) / (blitter->GetScreenDepth() / 8)) % bp.pitch; + if (offset < (uint)bp.width) { + _newgrf_debug_sprite_picker.sprites.Include(sprite_id); + } + } + } + + BlitterFactory::GetCurrentBlitter()->Draw(&bp, mode, zoom); +} + +static void GfxMainBlitterViewport(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub, SpriteID sprite_id) +{ + GfxBlitter(sprite, x, y, mode, sub, sprite_id, _cur_dpi->zoom); +} + +static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub, SpriteID sprite_id, ZoomLevel zoom) +{ + GfxBlitter<1, true>(sprite, x, y, mode, sub, sprite_id, zoom); +} + +void DoPaletteAnimations(); + +void GfxInitPalettes() +{ + memcpy(&_cur_palette, &_palette, sizeof(_cur_palette)); + DoPaletteAnimations(); +} + +#define EXTR(p, q) (((uint16)(palette_animation_counter * (p)) * (q)) >> 16) +#define EXTR2(p, q) (((uint16)(~palette_animation_counter * (p)) * (q)) >> 16) + +void DoPaletteAnimations() +{ + /* Animation counter for the palette animation. */ + static int palette_animation_counter = 0; + palette_animation_counter += 8; + + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + const Colour *s; + const ExtraPaletteValues *ev = &_extra_palette_values; + Colour old_val[PALETTE_ANIM_SIZE]; + const uint old_tc = palette_animation_counter; + uint i; + uint j; + + if (blitter != NULL && blitter->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_NONE) { + palette_animation_counter = 0; + } + + Colour *palette_pos = &_cur_palette.palette[PALETTE_ANIM_START]; // Points to where animations are taking place on the palette + /* Makes a copy of the current animation palette in old_val, + * so the work on the current palette could be compared, see if there has been any changes */ + memcpy(old_val, palette_pos, sizeof(old_val)); + + /* Fizzy Drink bubbles animation */ + s = ev->fizzy_drink; + j = EXTR2(512, EPV_CYCLES_FIZZY_DRINK); + for (i = 0; i != EPV_CYCLES_FIZZY_DRINK; i++) { + *palette_pos++ = s[j]; + j++; + if (j == EPV_CYCLES_FIZZY_DRINK) j = 0; + } + + /* Oil refinery fire animation */ + s = ev->oil_refinery; + j = EXTR2(512, EPV_CYCLES_OIL_REFINERY); + for (i = 0; i != EPV_CYCLES_OIL_REFINERY; i++) { + *palette_pos++ = s[j]; + j++; + if (j == EPV_CYCLES_OIL_REFINERY) j = 0; + } + + /* Radio tower blinking */ + { + byte i = (palette_animation_counter >> 1) & 0x7F; + byte v; + + if (i < 0x3f) { + v = 255; + } else if (i < 0x4A || i >= 0x75) { + v = 128; + } else { + v = 20; + } + palette_pos->r = v; + palette_pos->g = 0; + palette_pos->b = 0; + palette_pos++; + + i ^= 0x40; + if (i < 0x3f) { + v = 255; + } else if (i < 0x4A || i >= 0x75) { + v = 128; + } else { + v = 20; + } + palette_pos->r = v; + palette_pos->g = 0; + palette_pos->b = 0; + palette_pos++; + } + + /* Handle lighthouse and stadium animation */ + s = ev->lighthouse; + j = EXTR(256, EPV_CYCLES_LIGHTHOUSE); + for (i = 0; i != EPV_CYCLES_LIGHTHOUSE; i++) { + *palette_pos++ = s[j]; + j++; + if (j == EPV_CYCLES_LIGHTHOUSE) j = 0; + } + + /* Dark blue water */ + s = (_settings_game.game_creation.landscape == LT_TOYLAND) ? ev->dark_water_toyland : ev->dark_water; + j = EXTR(320, EPV_CYCLES_DARK_WATER); + for (i = 0; i != EPV_CYCLES_DARK_WATER; i++) { + *palette_pos++ = s[j]; + j++; + if (j == EPV_CYCLES_DARK_WATER) j = 0; + } + + /* Glittery water */ + s = (_settings_game.game_creation.landscape == LT_TOYLAND) ? ev->glitter_water_toyland : ev->glitter_water; + j = EXTR(128, EPV_CYCLES_GLITTER_WATER); + for (i = 0; i != EPV_CYCLES_GLITTER_WATER / 3; i++) { + *palette_pos++ = s[j]; + j += 3; + if (j >= EPV_CYCLES_GLITTER_WATER) j -= EPV_CYCLES_GLITTER_WATER; + } + + if (blitter != NULL && blitter->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_NONE) { + palette_animation_counter = old_tc; + } else { + if (memcmp(old_val, &_cur_palette.palette[PALETTE_ANIM_START], sizeof(old_val)) != 0 && _cur_palette.count_dirty == 0) { + /* Did we changed anything on the palette? Seems so. Mark it as dirty */ + _cur_palette.first_dirty = PALETTE_ANIM_START; + _cur_palette.count_dirty = PALETTE_ANIM_SIZE; + } + } +} + +/** + * Determine a contrasty text colour for a coloured background. + * @param background Background colour. + * @return TC_BLACK or TC_WHITE depending on what gives a better contrast. + */ +TextColour GetContrastColour(uint8 background) +{ + Colour c = _cur_palette.palette[background]; + /* Compute brightness according to http://www.w3.org/TR/AERT#color-contrast. + * The following formula computes 1000 * brightness^2, with brightness being in range 0 to 255. */ + uint sq1000_brightness = c.r * c.r * 299 + c.g * c.g * 587 + c.b * c.b * 114; + /* Compare with threshold brightness 128 (50%) */ + return sq1000_brightness < 128 * 128 * 1000 ? TC_WHITE : TC_BLACK; +} + +/** + * Initialize _stringwidth_table cache + * @param monospace Whether to load the monospace cache or the normal fonts. + */ +void LoadStringWidthTable(bool monospace) +{ + for (FontSize fs = monospace ? FS_MONO : FS_BEGIN; fs < (monospace ? FS_END : FS_MONO); fs++) { + for (uint i = 0; i != 224; i++) { + _stringwidth_table[fs][i] = GetGlyphWidth(fs, i + 32); + } + } + + ReInitAllWindows(); +} + +/** + * Return width of character glyph. + * @param size Font of the character + * @param key Character code glyph + * @return Width of the character glyph + */ +byte GetCharacterWidth(FontSize size, WChar key) +{ + /* Use _stringwidth_table cache if possible */ + if (key >= 32 && key < 256) return _stringwidth_table[size][key - 32]; + + return GetGlyphWidth(size, key); +} + +/** + * Return the maximum width of single digit. + * @param size Font of the digit + * @return Width of the digit. + */ +byte GetDigitWidth(FontSize size) +{ + byte width = 0; + for (char c = '0'; c <= '9'; c++) { + width = max(GetCharacterWidth(size, c), width); + } + return width; +} + +/** + * Determine the broadest digits for guessing the maximum width of a n-digit number. + * @param [out] front Broadest digit, which is not 0. (Use this digit as first digit for numbers with more than one digit.) + * @param [out] next Broadest digit, including 0. (Use this digit for all digits, except the first one; or for numbers with only one digit.) + * @param size Font of the digit + */ +void GetBroadestDigit(uint *front, uint *next, FontSize size) +{ + int width = -1; + for (char c = '9'; c >= '0'; c--) { + int w = GetCharacterWidth(size, c); + if (w > width) { + width = w; + *next = c - '0'; + if (c != '0') *front = c - '0'; + } + } +} + +void ScreenSizeChanged() +{ + _dirty_bytes_per_line = CeilDiv(_screen.width, DIRTY_BLOCK_WIDTH); + _dirty_blocks = ReallocT(_dirty_blocks, _dirty_bytes_per_line * CeilDiv(_screen.height, DIRTY_BLOCK_HEIGHT)); + + /* check the dirty rect */ + if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width; + if (_invalid_rect.bottom >= _screen.height) _invalid_rect.bottom = _screen.height; + + /* screen size changed and the old bitmap is invalid now, so we don't want to undraw it */ + _cursor.visible = false; + + CheckWindowMinSizings(); +} + +void UndrawMouseCursor() +{ + /* Don't undraw the mouse cursor if the screen is not ready */ + if (_screen.dst_ptr == NULL) return; + + if (_cursor.visible) { + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + _cursor.visible = false; + blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, _cursor.draw_pos.x, _cursor.draw_pos.y), _cursor_backup.GetBuffer(), _cursor.draw_size.x, _cursor.draw_size.y); + _video_driver->MakeDirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y); + } +} + +void DrawMouseCursor() +{ +#if defined(WINCE) + /* Don't ever draw the mouse for WinCE, as we work with a stylus */ + return; +#endif + + /* Don't draw the mouse cursor if the screen is not ready */ + if (_screen.dst_ptr == NULL) return; + + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + int x; + int y; + int w; + int h; + + /* Redraw mouse cursor but only when it's inside the window */ + if (!_cursor.in_window) return; + + /* Don't draw the mouse cursor if it's already drawn */ + if (_cursor.visible) { + if (!_cursor.dirty) return; + UndrawMouseCursor(); + } + + w = _cursor.size.x; + x = _cursor.pos.x + _cursor.offs.x + _cursor.short_vehicle_offset; + if (x < 0) { + w += x; + x = 0; + } + if (w > _screen.width - x) w = _screen.width - x; + if (w <= 0) return; + _cursor.draw_pos.x = x; + _cursor.draw_size.x = w; + + h = _cursor.size.y; + y = _cursor.pos.y + _cursor.offs.y; + if (y < 0) { + h += y; + y = 0; + } + if (h > _screen.height - y) h = _screen.height - y; + if (h <= 0) return; + _cursor.draw_pos.y = y; + _cursor.draw_size.y = h; + + uint8 *buffer = _cursor_backup.Allocate(blitter->BufferSize(w, h)); + + /* Make backup of stuff below cursor */ + blitter->CopyToBuffer(blitter->MoveTo(_screen.dst_ptr, _cursor.draw_pos.x, _cursor.draw_pos.y), buffer, _cursor.draw_size.x, _cursor.draw_size.y); + + /* Draw cursor on screen */ + _cur_dpi = &_screen; + DrawSprite(_cursor.sprite, _cursor.pal, _cursor.pos.x + _cursor.short_vehicle_offset, _cursor.pos.y); + + _video_driver->MakeDirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y); + + _cursor.visible = true; + _cursor.dirty = false; +} + +void RedrawScreenRect(int left, int top, int right, int bottom) +{ + assert(right <= _screen.width && bottom <= _screen.height); + if (_cursor.visible) { + if (right > _cursor.draw_pos.x && + left < _cursor.draw_pos.x + _cursor.draw_size.x && + bottom > _cursor.draw_pos.y && + top < _cursor.draw_pos.y + _cursor.draw_size.y) { + UndrawMouseCursor(); + } + } + +#ifdef ENABLE_NETWORK + if (_networking) NetworkUndrawChatMessage(); +#endif /* ENABLE_NETWORK */ + + DrawOverlappedWindowForAll(left, top, right, bottom); + + _video_driver->MakeDirty(left, top, right - left, bottom - top); +} + +/** + * Repaints the rectangle blocks which are marked as 'dirty'. + * + * @see SetDirtyBlocks + */ +void DrawDirtyBlocks() +{ + byte *b = _dirty_blocks; + const int w = Align(_screen.width, DIRTY_BLOCK_WIDTH); + const int h = Align(_screen.height, DIRTY_BLOCK_HEIGHT); + int x; + int y; + + if (HasModalProgress()) { + /* We are generating the world, so release our rights to the map and + * painting while we are waiting a bit. */ + _modal_progress_paint_mutex->EndCritical(); + _modal_progress_work_mutex->EndCritical(); + + /* Wait a while and update _realtime_tick so we are given the rights */ + if (!IsFirstModalProgressLoop()) CSleep(MODAL_PROGRESS_REDRAW_TIMEOUT); + _realtime_tick += MODAL_PROGRESS_REDRAW_TIMEOUT; + _modal_progress_paint_mutex->BeginCritical(); + _modal_progress_work_mutex->BeginCritical(); + + /* When we ended with the modal progress, do not draw the blocks. + * Simply let the next run do so, otherwise we would be loading + * the new state (and possibly change the blitter) when we hold + * the drawing lock, which we must not do. */ + if (_switch_mode != SM_NONE && !HasModalProgress()) return; + } + + y = 0; + do { + x = 0; + do { + if (*b != 0) { + int left; + int top; + int right = x + DIRTY_BLOCK_WIDTH; + int bottom = y; + byte *p = b; + int h2; + + /* First try coalescing downwards */ + do { + *p = 0; + p += _dirty_bytes_per_line; + bottom += DIRTY_BLOCK_HEIGHT; + } while (bottom != h && *p != 0); + + /* Try coalescing to the right too. */ + h2 = (bottom - y) / DIRTY_BLOCK_HEIGHT; + assert(h2 > 0); + p = b; + + while (right != w) { + byte *p2 = ++p; + int h = h2; + /* Check if a full line of dirty flags is set. */ + do { + if (!*p2) goto no_more_coalesc; + p2 += _dirty_bytes_per_line; + } while (--h != 0); + + /* Wohoo, can combine it one step to the right! + * Do that, and clear the bits. */ + right += DIRTY_BLOCK_WIDTH; + + h = h2; + p2 = p; + do { + *p2 = 0; + p2 += _dirty_bytes_per_line; + } while (--h != 0); + } + no_more_coalesc: + + left = x; + top = y; + + if (left < _invalid_rect.left ) left = _invalid_rect.left; + if (top < _invalid_rect.top ) top = _invalid_rect.top; + if (right > _invalid_rect.right ) right = _invalid_rect.right; + if (bottom > _invalid_rect.bottom) bottom = _invalid_rect.bottom; + + if (left < right && top < bottom) { + RedrawScreenRect(left, top, right, bottom); + } + + } + } while (b++, (x += DIRTY_BLOCK_WIDTH) != w); + } while (b += -(int)(w / DIRTY_BLOCK_WIDTH) + _dirty_bytes_per_line, (y += DIRTY_BLOCK_HEIGHT) != h); + + ++_dirty_block_colour; + _invalid_rect.left = w; + _invalid_rect.top = h; + _invalid_rect.right = 0; + _invalid_rect.bottom = 0; +} + +/** + * This function extends the internal _invalid_rect rectangle as it + * now contains the rectangle defined by the given parameters. Note + * the point (0,0) is top left. + * + * @param left The left edge of the rectangle + * @param top The top edge of the rectangle + * @param right The right edge of the rectangle + * @param bottom The bottom edge of the rectangle + * @see DrawDirtyBlocks + * + * @todo The name of the function should be called like @c AddDirtyBlock as + * it neither set a dirty rect nor add several dirty rects although + * the function name is in plural. (Progman) + */ +void SetDirtyBlocks(int left, int top, int right, int bottom) +{ + byte *b; + int width; + int height; + + if (left < 0) left = 0; + if (top < 0) top = 0; + if (right > _screen.width) right = _screen.width; + if (bottom > _screen.height) bottom = _screen.height; + + if (left >= right || top >= bottom) return; + + if (left < _invalid_rect.left ) _invalid_rect.left = left; + if (top < _invalid_rect.top ) _invalid_rect.top = top; + if (right > _invalid_rect.right ) _invalid_rect.right = right; + if (bottom > _invalid_rect.bottom) _invalid_rect.bottom = bottom; + + left /= DIRTY_BLOCK_WIDTH; + top /= DIRTY_BLOCK_HEIGHT; + + b = _dirty_blocks + top * _dirty_bytes_per_line + left; + + width = ((right - 1) / DIRTY_BLOCK_WIDTH) - left + 1; + height = ((bottom - 1) / DIRTY_BLOCK_HEIGHT) - top + 1; + + assert(width > 0 && height > 0); + + do { + int i = width; + + do b[--i] = 0xFF; while (i != 0); + + b += _dirty_bytes_per_line; + } while (--height != 0); +} + +/** + * This function mark the whole screen as dirty. This results in repainting + * the whole screen. Use this with care as this function will break the + * idea about marking only parts of the screen as 'dirty'. + * @ingroup dirty + */ +void MarkWholeScreenDirty() +{ + SetDirtyBlocks(0, 0, _screen.width, _screen.height); +} + +/** + * Set up a clipping area for only drawing into a certain area. To do this, + * Fill a DrawPixelInfo object with the supplied relative rectangle, backup + * the original (calling) _cur_dpi and assign the just returned DrawPixelInfo + * _cur_dpi. When you are done, give restore _cur_dpi's original value + * @param *n the DrawPixelInfo that will be the clipping rectangle box allowed + * for drawing + * @param left,top,width,height the relative coordinates of the clipping + * rectangle relative to the current _cur_dpi. This will most likely be the + * offset from the calling window coordinates + * @return return false if the requested rectangle is not possible with the + * current dpi pointer. Only continue of the return value is true, or you'll + * get some nasty results + */ +bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int height) +{ + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + const DrawPixelInfo *o = _cur_dpi; + + n->zoom = ZOOM_LVL_NORMAL; + + assert(width > 0); + assert(height > 0); + + if ((left -= o->left) < 0) { + width += left; + if (width <= 0) return false; + n->left = -left; + left = 0; + } else { + n->left = 0; + } + + if (width > o->width - left) { + width = o->width - left; + if (width <= 0) return false; + } + n->width = width; + + if ((top -= o->top) < 0) { + height += top; + if (height <= 0) return false; + n->top = -top; + top = 0; + } else { + n->top = 0; + } + + n->dst_ptr = blitter->MoveTo(o->dst_ptr, left, top); + n->pitch = o->pitch; + + if (height > o->height - top) { + height = o->height - top; + if (height <= 0) return false; + } + n->height = height; + + return true; +} + +/** + * Update cursor dimension. + * Called when changing cursor sprite resp. reloading grfs. + */ +void UpdateCursorSize() +{ + CursorVars *cv = &_cursor; + const Sprite *p = GetSprite(GB(cv->sprite, 0, SPRITE_WIDTH), ST_NORMAL); + + cv->size.y = UnScaleByZoom(p->height, ZOOM_LVL_GUI); + cv->size.x = UnScaleByZoom(p->width, ZOOM_LVL_GUI); + cv->offs.x = UnScaleByZoom(p->x_offs, ZOOM_LVL_GUI); + cv->offs.y = UnScaleByZoom(p->y_offs, ZOOM_LVL_GUI); + + cv->dirty = true; +} + +/** + * Switch cursor to different sprite. + * @param cursor Sprite to draw for the cursor. + * @param pal Palette to use for recolouring. + */ +static void SetCursorSprite(CursorID cursor, PaletteID pal) +{ + CursorVars *cv = &_cursor; + if (cv->sprite == cursor) return; + + cv->sprite = cursor; + cv->pal = pal; + UpdateCursorSize(); + + cv->short_vehicle_offset = 0; +} + +static void SwitchAnimatedCursor() +{ + const AnimCursor *cur = _cursor.animate_cur; + + if (cur == NULL || cur->sprite == AnimCursor::LAST) cur = _cursor.animate_list; + + SetCursorSprite(cur->sprite, _cursor.pal); + + _cursor.animate_timeout = cur->display_time; + _cursor.animate_cur = cur + 1; +} + +void CursorTick() +{ + if (_cursor.animate_timeout != 0 && --_cursor.animate_timeout == 0) { + SwitchAnimatedCursor(); + } +} + +/** + * Assign a single non-animated sprite to the cursor. + * @param sprite Sprite to draw for the cursor. + * @param pal Palette to use for recolouring. + * @see SetAnimatedMouseCursor + */ +void SetMouseCursor(CursorID sprite, PaletteID pal) +{ + /* Turn off animation */ + _cursor.animate_timeout = 0; + /* Set cursor */ + SetCursorSprite(sprite, pal); +} + +/** + * Assign an animation to the cursor. + * @param table Array of animation states. + * @see SetMouseCursor + */ +void SetAnimatedMouseCursor(const AnimCursor *table) +{ + _cursor.animate_list = table; + _cursor.animate_cur = NULL; + _cursor.pal = PAL_NONE; + SwitchAnimatedCursor(); +} + +bool ChangeResInGame(int width, int height) +{ + return (_screen.width == width && _screen.height == height) || _video_driver->ChangeResolution(width, height); +} + +bool ToggleFullScreen(bool fs) +{ + bool result = _video_driver->ToggleFullscreen(fs); + if (_fullscreen != fs && _num_resolutions == 0) { + DEBUG(driver, 0, "Could not find a suitable fullscreen resolution"); + } + return result; +} + +static int CDECL compare_res(const Dimension *pa, const Dimension *pb) +{ + int x = pa->width - pb->width; + if (x != 0) return x; + return pa->height - pb->height; +} + +void SortResolutions(int count) +{ + QSortT(_resolutions, count, &compare_res); +} + + +/** + * Returns the initial value for a margin, after telling where are the left and right margins and where we want to draw/write (begining/end of line) + * @param left is the left margin of the horizontal space we want to draw to + * @param right: right margin + * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end + * @return the margin we asked + */ +int InitTempMargin(int left, int right, bool to_end_line) +{ + return to_end_line ^ (_current_text_dir == TD_RTL) ? right :left; +} + +/** + * Consumes a space in an horizontal margin + * @param space: amount of space used + * @param here: the margin where to add the space + * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end + */ +void AddSpace(int space, int &here, bool to_end_line) +{ + here += to_end_line ^ (_current_text_dir == TD_RTL) ? -space : space; +} + +/** + * After drawing something, update a margin + * @param end is where we ended drawing (usually the return value of a DrawString function) + * @param margin is the margin we want to update + * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end + */ +void UpdateMarginEnd(int end, int &margin, bool to_end_line) +{ + margin = to_end_line ^ (_current_text_dir == TD_RTL) ? min(end, margin) : max(end, margin); +} + +/** + * After drawing something, horizontal margins are updated + * @param end: last position drawn + * @param left is the left margin of the horizontal space drawn + * @param right: right margin + * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end + */ +void UpdateMarginsEnd(int end, int &left, int &right, bool to_end_line) +{ + if (to_end_line ^ (_current_text_dir == TD_RTL)) { + right = end; + } else { + left = end; + } +} + +/** + * After drawing something of a certain width, update margins + * @param width: used space + * @param initial left margin + * @param initial right margin + * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end + */ +void UpdateMarginsWidth(int width, int &left, int &right, bool to_end_line) +{ + if (to_end_line ^ (_current_text_dir == TD_RTL)) { + right -= width; + } else { + left += width; + } +} + +/** + * Draws a string in a delimited space; temporal margin gets updated + * @param left is the left margin of the horizontal space we want to draw to + * @param right: right margin of the horizontal space we want to draw to + * @param top: vertical position + * @param margin keeps the most extreme limit used of the line (this should be previously initialized with InitTempLimit) + * @param string to draw + * @param colour for the string + * @param alignment of the string (only left or right alignment) + * @param underline + */ +void DrawString2(int left, int right, int top, int &margin, StringID str, TextColour colour, StringAlignment align, bool underline) +{ + int end = DrawString(left, right, top, str, colour, align, underline); + UpdateMarginEnd(end, margin, align == SA_RIGHT); +} + +/** + * Draws a sprite in a delimited space; temporal margin gets updated + * @param width of the sprite + * @param left is the left margin of the horizontal space we want to draw to + * @param right: right margin of the horizontal space + * @param top: vertical position + * @param margin keeps the most extreme limit used of the line (this should be previously initialized with InitTempLimit) + * @param sprite + * @param palette + * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end + */ +void DrawSprite2(int width, int left, int right, int top, int &margin, SpriteID img, PaletteID pal, bool to_end_line, SubSprite *sub) +{ + DrawSprite(img, pal, to_end_line ^ (_current_text_dir == TD_RTL) ? right - width : left, top, sub); + margin = to_end_line ^ (_current_text_dir == TD_RTL) ? min(right - width, margin): max(margin, left + width); +} diff --git a/src/gfx_func.h.orig b/src/gfx_func.h.orig new file mode 100644 index 0000000000..33b13c1fd8 --- /dev/null +++ b/src/gfx_func.h.orig @@ -0,0 +1,226 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file gfx_func.h Functions related to the gfx engine. */ + +/** + * @defgroup dirty Dirty + * + * Handles the repaint of some part of the screen. + * + * Some places in the code are called functions which makes something "dirty". + * This has nothing to do with making a Tile or Window darker or less visible. + * This term comes from memory caching and is used to define an object must + * be repaint. If some data of an object (like a Tile, Window, Vehicle, whatever) + * are changed which are so extensive the object must be repaint its marked + * as "dirty". The video driver repaint this object instead of the whole screen + * (this is btw. also possible if needed). This is used to avoid a + * flickering of the screen by the video driver constantly repainting it. + * + * This whole mechanism is controlled by an rectangle defined in #_invalid_rect. This + * rectangle defines the area on the screen which must be repaint. If a new object + * needs to be repainted this rectangle is extended to 'catch' the object on the + * screen. At some point (which is normally uninteresting for patch writers) this + * rectangle is send to the video drivers method + * VideoDriver::MakeDirty and it is truncated back to an empty rectangle. At some + * later point (which is uninteresting, too) the video driver + * repaints all these saved rectangle instead of the whole screen and drop the + * rectangle informations. Then a new round begins by marking objects "dirty". + * + * @see VideoDriver::MakeDirty + * @see _invalid_rect + * @see _screen + */ + + +#ifndef GFX_FUNC_H +#define GFX_FUNC_H + +#include "gfx_type.h" +#include "strings_type.h" +#include "string_type.h" + +void GameLoop(); + +void CreateConsole(); + +extern byte _dirkeys; ///< 1 = left, 2 = up, 4 = right, 8 = down +extern bool _fullscreen; +extern CursorVars _cursor; +extern bool _ctrl_pressed; ///< Is Ctrl pressed? +extern bool _shift_pressed; ///< Is Shift pressed? +extern byte _fast_forward; + +extern bool _left_button_down; +extern bool _left_button_clicked; +extern bool _right_button_down; +extern bool _right_button_clicked; + +extern DrawPixelInfo _screen; +extern bool _screen_disable_anim; ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot) + +extern int _num_resolutions; +extern Dimension _resolutions[32]; +extern Dimension _cur_resolution; +extern Palette _cur_palette; ///< Current palette + +void HandleKeypress(uint keycode, WChar key); +void HandleTextInput(const char *str, bool marked = false, const char *caret = NULL, const char *insert_location = NULL, const char *replacement_end = NULL); +void HandleCtrlChanged(); +void HandleMouseEvents(); +void CSleep(int milliseconds); +void UpdateWindows(); + +void DrawMouseCursor(); +void ScreenSizeChanged(); +void GameSizeChanged(); +void UndrawMouseCursor(); + +/** Size of the buffer used for drawing strings. */ +static const int DRAW_STRING_BUFFER = 2048; + +void RedrawScreenRect(int left, int top, int right, int bottom); +void GfxScroll(int left, int top, int width, int height, int xo, int yo); + +Dimension GetSpriteSize(SpriteID sprid, Point *offset = NULL, ZoomLevel zoom = ZOOM_LVL_GUI); +void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = NULL); +void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = NULL, ZoomLevel zoom = ZOOM_LVL_GUI); + +/** How to align the to-be drawn text. */ +enum StringAlignment { + SA_LEFT = 0 << 0, ///< Left align the text. + SA_HOR_CENTER = 1 << 0, ///< Horizontally center the text. + SA_RIGHT = 2 << 0, ///< Right align the text (must be a single bit). + SA_HOR_MASK = 3 << 0, ///< Mask for horizontal alignment. + + SA_TOP = 0 << 2, ///< Top align the text. + SA_VERT_CENTER = 1 << 2, ///< Vertically center the text. + SA_BOTTOM = 2 << 2, ///< Bottom align the text. + SA_VERT_MASK = 3 << 2, ///< Mask for vertical alignment. + + SA_CENTER = SA_HOR_CENTER | SA_VERT_CENTER, ///< Center both horizontally and vertically. + + SA_FORCE = 1 << 4, ///< Force the alignment, i.e. don't swap for RTL languages. +}; +DECLARE_ENUM_AS_BIT_SET(StringAlignment) + +int DrawString(int left, int right, int top, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL); +int DrawString(int left, int right, int top, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL); +int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); +int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); + +void DrawCharCentered(uint32 c, int x, int y, TextColour colour); + +void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode = FILLRECT_OPAQUE); +void GfxDrawLine(int left, int top, int right, int bottom, int colour, int width = 1, int dash = 0); +void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3); + +Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize = FS_NORMAL); +Dimension GetStringBoundingBox(StringID strid); +int GetStringHeight(const char *str, int maxw, FontSize fontsize = FS_NORMAL); +int GetStringHeight(StringID str, int maxw); +int GetStringLineCount(StringID str, int maxw); +Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion); +Dimension GetStringMultiLineBoundingBox(const char *str, const Dimension &suggestion); +void LoadStringWidthTable(bool monospace = false); +Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsize = FS_NORMAL); +const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize = FS_NORMAL); + +void DrawDirtyBlocks(); +void SetDirtyBlocks(int left, int top, int right, int bottom); +void MarkWholeScreenDirty(); + +void GfxInitPalettes(); +void CheckBlitter(); + +bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int height); + +/* window.cpp */ +void DrawOverlappedWindowForAll(int left, int top, int right, int bottom); + +void SetMouseCursor(CursorID cursor, PaletteID pal); +void SetAnimatedMouseCursor(const AnimCursor *table); +void CursorTick(); +void UpdateCursorSize(); +bool ChangeResInGame(int w, int h); +void SortResolutions(int count); +bool ToggleFullScreen(bool fs); + +/* gfx.cpp */ +byte GetCharacterWidth(FontSize size, uint32 key); +byte GetDigitWidth(FontSize size = FS_NORMAL); +void GetBroadestDigit(uint *front, uint *next, FontSize size = FS_NORMAL); + +int GetCharacterHeight(FontSize size); + +/** Height of characters in the small (#FS_SMALL) font. */ +#define FONT_HEIGHT_SMALL (GetCharacterHeight(FS_SMALL)) + +/** Height of characters in the normal (#FS_NORMAL) font. */ +#define FONT_HEIGHT_NORMAL (GetCharacterHeight(FS_NORMAL)) + +/** Height of characters in the large (#FS_LARGE) font. */ +#define FONT_HEIGHT_LARGE (GetCharacterHeight(FS_LARGE)) + +/** Height of characters in the large (#FS_MONO) font. */ +#define FONT_HEIGHT_MONO (GetCharacterHeight(FS_MONO)) + +int InitTempMargin(int left, int right, bool to_end_line); +void AddSpace(int space, int &here, bool to_end_line); + +void UpdateMarginEnd(int end, int &margin, bool to_end_line); +void UpdateMarginWidth(int adding, int &margin, bool to_end_line); +void UpdateMarginsEnd(int end, int &left, int &right, bool to_end_line); +void UpdateMarginsWidth(int width, int &left, int &right, bool to_end_line); + +void DrawString2(int left, int right, int top, int &margin, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false); +void DrawSprite2(int width, int left, int right, int top, int &margin, SpriteID img, PaletteID pal, bool to_end_line = false, SubSprite *sub = NULL); + +extern DrawPixelInfo *_cur_dpi; + +TextColour GetContrastColour(uint8 background); + +/** + * All 16 colour gradients + * 8 colours per gradient from darkest (0) to lightest (7) + */ +extern byte _colour_gradient[COLOUR_END][8]; + +extern bool _palette_remap_grf[]; + +/** + * Return the colour for a particular greyscale level. + * @param level Intensity, 0 = black, 15 = white + * @return colour + */ +#define GREY_SCALE(level) (level) + +static const uint8 PC_BLACK = GREY_SCALE(1); ///< Black palette colour. +static const uint8 PC_DARK_GREY = GREY_SCALE(6); ///< Dark grey palette colour. +static const uint8 PC_GREY = GREY_SCALE(10); ///< Grey palette colour. +static const uint8 PC_WHITE = GREY_SCALE(15); ///< White palette colour. + +static const uint8 PC_VERY_DARK_RED = 0xB2; ///< Almost-black red palette colour. +static const uint8 PC_DARK_RED = 0xB4; ///< Dark red palette colour. +static const uint8 PC_RED = 0xB8; ///< Red palette colour. + +static const uint8 PC_VERY_DARK_BROWN = 0x56; ///< Almost-black brown palette colour. + +static const uint8 PC_ORANGE = 0xC2; ///< Orange palette colour. + +static const uint8 PC_YELLOW = 0xBF; ///< Yellow palette colour. +static const uint8 PC_LIGHT_YELLOW = 0x44; ///< Light yellow palette colour. +static const uint8 PC_VERY_LIGHT_YELLOW = 0x45; ///< Almost-white yellow palette colour. + +static const uint8 PC_GREEN = 0xD0; ///< Green palette colour. + +static const uint8 PC_DARK_BLUE = 0x9D; ///< Dark blue palette colour. +static const uint8 PC_LIGHT_BLUE = 0x98; ///< Light blue palette colour. + +#endif /* GFX_FUNC_H */ diff --git a/src/group_gui.cpp.orig b/src/group_gui.cpp.orig new file mode 100644 index 0000000000..93349a3f5d --- /dev/null +++ b/src/group_gui.cpp.orig @@ -0,0 +1,891 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file group_gui.cpp GUI for the group window. */ + +#include "stdafx.h" +#include "textbuf_gui.h" +#include "command_func.h" +#include "vehicle_gui.h" +#include "vehicle_base.h" +#include "string_func.h" +#include "strings_func.h" +#include "window_func.h" +#include "vehicle_func.h" +#include "autoreplace_gui.h" +#include "company_func.h" +#include "widgets/dropdown_func.h" +#include "tilehighlight_func.h" +#include "vehicle_gui_base.h" +#include "core/geometry_func.hpp" +#include "company_base.h" + +#include "widgets/group_widget.h" + +#include "table/sprites.h" + +typedef GUIList GUIGroupList; + +static const NWidgetPart _nested_group_widgets[] = { + NWidget(NWID_HORIZONTAL), // Window header + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_GL_CAPTION), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(NWID_HORIZONTAL), + /* left part */ + NWidget(NWID_VERTICAL), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalTextLines(1, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM), SetFill(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_ALL_VEHICLES), SetFill(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_DEFAULT_VEHICLES), SetFill(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_GL_LIST_GROUP), SetMatrixDataTip(1, 0, STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP), + SetFill(1, 0), SetResize(0, 1), SetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_GL_LIST_GROUP_SCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_CREATE_GROUP), SetFill(0, 1), + SetDataTip(SPR_GROUP_CREATE_TRAIN, STR_GROUP_CREATE_TOOLTIP), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_DELETE_GROUP), SetFill(0, 1), + SetDataTip(SPR_GROUP_DELETE_TRAIN, STR_GROUP_DELETE_TOOLTIP), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_RENAME_GROUP), SetFill(0, 1), + SetDataTip(SPR_GROUP_RENAME_TRAIN, STR_GROUP_RENAME_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), EndContainer(), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_REPLACE_PROTECTION), SetFill(0, 1), + SetDataTip(SPR_GROUP_REPLACE_OFF_TRAIN, STR_GROUP_REPLACE_PROTECTION_TOOLTIP), + EndContainer(), + EndContainer(), + /* right part */ + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_SORT_BY_ORDER), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_SORT_BY_DROPDOWN), SetMinimalSize(167, 12), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_GL_LIST_VEHICLE), SetMinimalSize(248, 0), SetMatrixDataTip(1, 0, STR_NULL), SetResize(1, 1), SetFill(1, 0), SetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_GL_LIST_VEHICLE_SCROLLBAR), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(1, 0), SetFill(1, 1), SetResize(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_AVAILABLE_VEHICLES), SetMinimalSize(106, 12), SetFill(0, 1), + SetDataTip(STR_BLACK_STRING, STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 1), SetResize(1, 0), EndContainer(), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_MANAGE_VEHICLES_DROPDOWN), SetMinimalSize(118, 12), SetFill(0, 1), + SetDataTip(STR_VEHICLE_LIST_MANAGE_LIST, STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_STOP_ALL), SetMinimalSize(12, 12), SetFill(0, 1), + SetDataTip(SPR_FLAG_VEH_STOPPED, STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_START_ALL), SetMinimalSize(12, 12), SetFill(0, 1), + SetDataTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), + EndContainer(), + EndContainer(), +}; + +class VehicleGroupWindow : public BaseVehicleListWindow { +private: + /* Columns in the group list */ + enum ListColumns { + VGC_NAME, ///< Group name. + VGC_PROTECT, ///< Autoreplace protect icon. + VGC_AUTOREPLACE, ///< Autoreplace active icon. + VGC_PROFIT, ///< Profit icon. + VGC_NUMBER, ///< Number of vehicles in the group. + + VGC_END + }; + + VehicleID vehicle_sel; ///< Selected vehicle + GroupID group_rename; ///< Group being renamed, INVALID_GROUP if none + GroupID group_over; ///< Group over which a vehicle is dragged, INVALID_GROUP if none + GUIGroupList groups; ///< List of groups + uint tiny_step_height; ///< Step height for the group list + Scrollbar *group_sb; + + Dimension column_size[VGC_END]; ///< Size of the columns in the group list. + + /** + * (Re)Build the group list. + * + * @param owner The owner of the window + */ + void BuildGroupList(Owner owner) + { + if (!this->groups.NeedRebuild()) return; + + this->groups.Clear(); + + const Group *g; + FOR_ALL_GROUPS(g) { + if (g->owner == owner && g->vehicle_type == this->vli.vtype) { + *this->groups.Append() = g; + } + } + + this->groups.Compact(); + this->groups.RebuildDone(); + } + + /** Sort the groups by their name */ + static int CDECL GroupNameSorter(const Group * const *a, const Group * const *b) + { + static const Group *last_group[2] = { NULL, NULL }; + static char last_name[2][64] = { "", "" }; + + if (*a != last_group[0]) { + last_group[0] = *a; + SetDParam(0, (*a)->index); + GetString(last_name[0], STR_GROUP_NAME, lastof(last_name[0])); + } + + if (*b != last_group[1]) { + last_group[1] = *b; + SetDParam(0, (*b)->index); + GetString(last_name[1], STR_GROUP_NAME, lastof(last_name[1])); + } + + int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). + if (r == 0) return (*a)->index - (*b)->index; + return r; + } + + /** + * Compute tiny_step_height and column_size + * @return Total width required for the group list. + */ + uint ComputeGroupInfoSize() + { + this->column_size[VGC_NAME] = maxdim(GetStringBoundingBox(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype), GetStringBoundingBox(STR_GROUP_ALL_TRAINS + this->vli.vtype)); +/* We consider the max average length of characters to be the one of "a" */ + this->column_size[VGC_NAME].width = max(GetCharacterWidth(FS_NORMAL, 97) * (MAX_LENGTH_GROUP_NAME_CHARS - 4), this->column_size[VGC_NAME].width); + this->tiny_step_height = this->column_size[VGC_NAME].height; + + this->column_size[VGC_PROTECT] = GetSpriteSize(SPR_GROUP_REPLACE_PROTECT); + this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_PROTECT].height); + + this->column_size[VGC_AUTOREPLACE] = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE); + this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_AUTOREPLACE].height); + + this->column_size[VGC_PROFIT].width = 0; + this->column_size[VGC_PROFIT].height = 0; + static const SpriteID profit_sprites[] = {SPR_PROFIT_NA, SPR_PROFIT_NEGATIVE, SPR_PROFIT_SOME, SPR_PROFIT_LOT}; + for (uint i = 0; i < lengthof(profit_sprites); i++) { + Dimension d = GetSpriteSize(profit_sprites[i]); + this->column_size[VGC_PROFIT] = maxdim(this->column_size[VGC_PROFIT], d); + } + this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_PROFIT].height); + + SetDParamMaxValue(0, GroupStatistics::Get(this->vli.company, ALL_GROUP, this->vli.vtype).num_vehicle, 3, FS_SMALL); + this->column_size[VGC_NUMBER] = GetStringBoundingBox(STR_TINY_COMMA); + this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_NUMBER].height); + + this->tiny_step_height += WD_MATRIX_TOP; + + return WD_FRAMERECT_LEFT + 8 + + this->column_size[VGC_NAME].width + 2 + + this->column_size[VGC_PROTECT].width + 2 + + this->column_size[VGC_AUTOREPLACE].width + 2 + + this->column_size[VGC_PROFIT].width + 2 + + this->column_size[VGC_NUMBER].width + 2 + + WD_FRAMERECT_RIGHT; + } + + /** + * Draw a row in the group list. + * @param y Top of the row. + * @param left Left of the row. + * @param right Right of the row. + * @param g_id Group to list. + * @param protection Whether autoreplace protection is set. + */ + void DrawGroupInfo(int y, int left, int right, GroupID g_id, bool protection = false) const + { + /* Highlight the group if a vehicle is dragged over it */ + if (g_id == this->group_over) { + GfxFillRect(left + WD_FRAMERECT_LEFT, y + WD_FRAMERECT_TOP + WD_MATRIX_TOP, right - WD_FRAMERECT_RIGHT, y + this->tiny_step_height - WD_FRAMERECT_BOTTOM - WD_MATRIX_TOP, _colour_gradient[COLOUR_GREY][7]); + } + + if (g_id == NEW_GROUP) return; + + /* draw the selected group in white, else we draw it in black */ + TextColour colour = g_id == this->vli.index ? TC_WHITE : TC_BLACK; + const GroupStatistics &stats = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype); + bool rtl = _current_text_dir == TD_RTL; + + /* draw group name */ + int longer_name = 0; + StringID str; + if (IsAllGroupID(g_id)) { + str = STR_GROUP_ALL_TRAINS + this->vli.vtype; + } else if (IsDefaultGroupID(g_id)) { + str = STR_GROUP_DEFAULT_TRAINS + this->vli.vtype; + } else { + SetDParam(0, g_id); + str = STR_GROUP_NAME; + if (!protection) { + longer_name += this->column_size[VGC_PROTECT].width + 2; + if (!stats.autoreplace_defined) longer_name += this->column_size[VGC_AUTOREPLACE].width + 2; + } + } + int x = rtl ? right - WD_FRAMERECT_RIGHT - 8 - this->column_size[VGC_NAME].width - longer_name + 1 : left + WD_FRAMERECT_LEFT + 8; + DrawString(x, x + this->column_size[VGC_NAME].width + longer_name - 1, y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour); + + /* draw autoreplace protection */ + x = rtl ? x - 2 - this->column_size[VGC_PROTECT].width : x + 2 + this->column_size[VGC_NAME].width; + if (protection) DrawSprite(SPR_GROUP_REPLACE_PROTECT, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROTECT].height) / 2); + + /* draw autoreplace status */ + x = rtl ? x - 2 - this->column_size[VGC_AUTOREPLACE].width : x + 2 + this->column_size[VGC_PROTECT].width; + if (stats.autoreplace_defined) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, stats.autoreplace_finished ? PALETTE_CRASH : PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_AUTOREPLACE].height) / 2); + + /* draw the profit icon */ + x = rtl ? x - 2 - this->column_size[VGC_PROFIT].width : x + 2 + this->column_size[VGC_AUTOREPLACE].width; + SpriteID spr; + if (stats.num_profit_vehicle == 0) { + spr = SPR_PROFIT_NA; + } else if (stats.profit_last_year < 0) { + spr = SPR_PROFIT_NEGATIVE; + } else if (stats.profit_last_year < 10000 * stats.num_profit_vehicle) { // TODO magic number + spr = SPR_PROFIT_SOME; + } else { + spr = SPR_PROFIT_LOT; + } + DrawSprite(spr, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROFIT].height) / 2); + + /* draw the number of vehicles of the group */ + x = rtl ? x - 2 - this->column_size[VGC_NUMBER].width : x + 2 + this->column_size[VGC_PROFIT].width; + SetDParam(0, stats.num_vehicle); + DrawString(x, x + this->column_size[VGC_NUMBER].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NUMBER].height) / 2, STR_TINY_COMMA, colour, SA_RIGHT | SA_FORCE); + } + + /** + * Mark the widget containing the currently highlighted group as dirty. + */ + void DirtyHighlightedGroupWidget() + { + if (this->group_over == INVALID_GROUP) return; + + if (IsAllGroupID(this->group_over)) { + this->SetWidgetDirty(WID_GL_ALL_VEHICLES); + } else if (IsDefaultGroupID(this->group_over)) { + this->SetWidgetDirty(WID_GL_DEFAULT_VEHICLES); + } else { + this->SetWidgetDirty(WID_GL_LIST_GROUP); + } + } + +public: + VehicleGroupWindow(WindowDesc *desc, WindowNumber window_number) : BaseVehicleListWindow(desc, window_number) + { + this->CreateNestedTree(); + + this->vscroll = this->GetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR); + this->group_sb = this->GetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR); + + switch (this->vli.vtype) { + default: NOT_REACHED(); + case VEH_TRAIN: this->sorting = &_sorting.train; break; + case VEH_ROAD: this->sorting = &_sorting.roadveh; break; + case VEH_SHIP: this->sorting = &_sorting.ship; break; + case VEH_AIRCRAFT: this->sorting = &_sorting.aircraft; break; + } + + this->vli.index = ALL_GROUP; + this->vehicle_sel = INVALID_VEHICLE; + this->group_rename = INVALID_GROUP; + this->group_over = INVALID_GROUP; + + this->vehicles.SetListing(*this->sorting); + this->vehicles.ForceRebuild(); + this->vehicles.NeedResort(); + + this->BuildVehicleList(); + this->SortVehicleList(); + + this->groups.ForceRebuild(); + this->groups.NeedResort(); + this->BuildGroupList(vli.company); + this->groups.Sort(&GroupNameSorter); + + this->GetWidget(WID_GL_CAPTION)->widget_data = STR_VEHICLE_LIST_TRAIN_CAPTION + this->vli.vtype; + this->GetWidget(WID_GL_LIST_VEHICLE)->tool_tip = STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vli.vtype; + + this->GetWidget(WID_GL_CREATE_GROUP)->widget_data += this->vli.vtype; + this->GetWidget(WID_GL_RENAME_GROUP)->widget_data += this->vli.vtype; + this->GetWidget(WID_GL_DELETE_GROUP)->widget_data += this->vli.vtype; + this->GetWidget(WID_GL_REPLACE_PROTECTION)->widget_data += this->vli.vtype; + + this->FinishInitNested(window_number); + this->owner = vli.company; + } + + ~VehicleGroupWindow() + { + *this->sorting = this->vehicles.GetListing(); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_GL_LIST_GROUP: { + size->width = this->ComputeGroupInfoSize(); + resize->height = this->tiny_step_height; + + /* Minimum height is the height of the list widget minus all and default vehicles... */ + size->height = 4 * GetVehicleListHeight(this->vli.vtype, this->tiny_step_height) - 2 * this->tiny_step_height; + + /* ... minus the buttons at the bottom ... */ + uint max_icon_height = GetSpriteSize(this->GetWidget(WID_GL_CREATE_GROUP)->widget_data).height; + max_icon_height = max(max_icon_height, GetSpriteSize(this->GetWidget(WID_GL_RENAME_GROUP)->widget_data).height); + max_icon_height = max(max_icon_height, GetSpriteSize(this->GetWidget(WID_GL_DELETE_GROUP)->widget_data).height); + max_icon_height = max(max_icon_height, GetSpriteSize(this->GetWidget(WID_GL_REPLACE_PROTECTION)->widget_data).height); + + /* Get a multiple of tiny_step_height of that amount */ + size->height = Ceil(size->height - max_icon_height, tiny_step_height); + break; + } + + case WID_GL_ALL_VEHICLES: + case WID_GL_DEFAULT_VEHICLES: + size->width = this->ComputeGroupInfoSize(); + size->height = this->tiny_step_height; + break; + + case WID_GL_SORT_BY_ORDER: { + Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); + d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_GL_LIST_VEHICLE: + this->ComputeGroupInfoSize(); + resize->height = GetVehicleListHeight(this->vli.vtype, this->tiny_step_height); + size->height = 4 * resize->height; + break; + + case WID_GL_MANAGE_VEHICLES_DROPDOWN: { + Dimension d = this->GetActionDropdownSize(true, true); + d.height += padding.height; + d.width += padding.width; + *size = maxdim(*size, d); + break; + } + } + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (data == 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ + this->vehicles.ForceRebuild(); + this->groups.ForceRebuild(); + } else { + this->vehicles.ForceResort(); + this->groups.ForceResort(); + } + + /* Process ID-invalidation in command-scope as well */ + if (this->group_rename != INVALID_GROUP && !Group::IsValidID(this->group_rename)) { + DeleteWindowByClass(WC_QUERY_STRING); + this->group_rename = INVALID_GROUP; + } + + if (!(IsAllGroupID(this->vli.index) || IsDefaultGroupID(this->vli.index) || Group::IsValidID(this->vli.index))) { + this->vli.index = ALL_GROUP; + HideDropDownMenu(this); + } + this->SetDirty(); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_GL_AVAILABLE_VEHICLES: + SetDParam(0, STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vli.vtype); + break; + + case WID_GL_CAPTION: + /* If selected_group == DEFAULT_GROUP || ALL_GROUP, draw the standard caption + * We list all vehicles or ungrouped vehicles */ + if (IsDefaultGroupID(this->vli.index) || IsAllGroupID(this->vli.index)) { + SetDParam(0, STR_COMPANY_NAME); + SetDParam(1, this->vli.company); + SetDParam(2, this->vehicles.Length()); + SetDParam(3, this->vehicles.Length()); + } else { + const Group *g = Group::Get(this->vli.index); + + SetDParam(0, STR_GROUP_NAME); + SetDParam(1, g->index); + SetDParam(2, g->statistics.num_vehicle); + SetDParam(3, g->statistics.num_vehicle); + } + break; + } + } + + virtual void OnPaint() + { + /* If we select the all vehicles, this->list will contain all vehicles of the owner + * else this->list will contain all vehicles which belong to the selected group */ + this->BuildVehicleList(); + this->SortVehicleList(); + + this->BuildGroupList(this->owner); + this->groups.Sort(&GroupNameSorter); + + this->group_sb->SetCount(this->groups.Length()); + this->vscroll->SetCount(this->vehicles.Length()); + + /* The drop down menu is out, *but* it may not be used, retract it. */ + if (this->vehicles.Length() == 0 && this->IsWidgetLowered(WID_GL_MANAGE_VEHICLES_DROPDOWN)) { + this->RaiseWidget(WID_GL_MANAGE_VEHICLES_DROPDOWN); + HideDropDownMenu(this); + } + + /* Disable all lists management button when the list is empty */ + this->SetWidgetsDisabledState(this->vehicles.Length() == 0 || _local_company != this->vli.company, + WID_GL_STOP_ALL, + WID_GL_START_ALL, + WID_GL_MANAGE_VEHICLES_DROPDOWN, + WIDGET_LIST_END); + + /* Disable the group specific function when we select the default group or all vehicles */ + this->SetWidgetsDisabledState(IsDefaultGroupID(this->vli.index) || IsAllGroupID(this->vli.index) || _local_company != this->vli.company, + WID_GL_DELETE_GROUP, + WID_GL_RENAME_GROUP, + WID_GL_REPLACE_PROTECTION, + WIDGET_LIST_END); + + /* Disable remaining buttons for non-local companies + * Needed while changing _local_company, eg. by cheats + * All procedures (eg. move vehicle to another group) + * verify, whether you are the owner of the vehicle, + * so it doesn't have to be disabled + */ + this->SetWidgetsDisabledState(_local_company != this->vli.company, + WID_GL_CREATE_GROUP, + WID_GL_AVAILABLE_VEHICLES, + WIDGET_LIST_END); + + /* If not a default group and the group has replace protection, show an enabled replace sprite. */ + uint16 protect_sprite = SPR_GROUP_REPLACE_OFF_TRAIN; + if (!IsDefaultGroupID(this->vli.index) && !IsAllGroupID(this->vli.index) && Group::Get(this->vli.index)->replace_protection) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN; + this->GetWidget(WID_GL_REPLACE_PROTECTION)->widget_data = protect_sprite + this->vli.vtype; + + /* Set text of sort by dropdown */ + this->GetWidget(WID_GL_SORT_BY_DROPDOWN)->widget_data = this->vehicle_sorter_names[this->vehicles.SortType()]; + + this->DrawWidgets(); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_GL_ALL_VEHICLES: + DrawGroupInfo(r.top, r.left, r.right, ALL_GROUP); + break; + + case WID_GL_DEFAULT_VEHICLES: + DrawGroupInfo(r.top, r.left, r.right, DEFAULT_GROUP); + break; + + case WID_GL_LIST_GROUP: { + int y1 = r.top; + int max = min(this->group_sb->GetPosition() + this->group_sb->GetCapacity(), this->groups.Length()); + for (int i = this->group_sb->GetPosition(); i < max; ++i) { + const Group *g = this->groups[i]; + + assert(g->owner == this->owner); + + DrawGroupInfo(y1, r.left, r.right, g->index, g->replace_protection); + + y1 += this->tiny_step_height; + } + if ((uint)this->group_sb->GetPosition() + this->group_sb->GetCapacity() > this->groups.Length()) { + DrawGroupInfo(y1, r.left, r.right, NEW_GROUP); + } + break; + } + + case WID_GL_SORT_BY_ORDER: + this->DrawSortButtonState(WID_GL_SORT_BY_ORDER, this->vehicles.IsDescSortOrder() ? SBS_DOWN : SBS_UP); + break; + + case WID_GL_LIST_VEHICLE: + this->DrawVehicleListItems(this->vehicle_sel, this->resize.step_height, r); + break; + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_GL_SORT_BY_ORDER: // Flip sorting method ascending/descending + this->vehicles.ToggleSortOrder(); + this->SetDirty(); + break; + + case WID_GL_SORT_BY_DROPDOWN: // Select sorting criteria dropdown menu + ShowDropDownMenu(this, this->vehicle_sorter_names, this->vehicles.SortType(), WID_GL_SORT_BY_DROPDOWN, 0, (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10)); + return; + + case WID_GL_ALL_VEHICLES: // All vehicles button + if (!IsAllGroupID(this->vli.index)) { + this->vli.index = ALL_GROUP; + this->vehicles.ForceRebuild(); + this->SetDirty(); + } + break; + + case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles button + if (!IsDefaultGroupID(this->vli.index)) { + this->vli.index = DEFAULT_GROUP; + this->vehicles.ForceRebuild(); + this->SetDirty(); + } + break; + + case WID_GL_LIST_GROUP: { // Matrix Group + uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); + if (id_g >= this->groups.Length()) return; + + this->vli.index = this->groups[id_g]->index; + + this->vehicles.ForceRebuild(); + this->SetDirty(); + break; + } + + case WID_GL_LIST_VEHICLE: { // Matrix Vehicle + uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE); + if (id_v >= this->vehicles.Length()) return; // click out of list bound + + const Vehicle *v = this->vehicles[id_v]; + if (VehicleClicked(v)) break; + + this->vehicle_sel = v->index; + + int image = v->GetImage(_current_text_dir == TD_RTL ? DIR_E : DIR_W, EIT_IN_LIST); + SetObjectToPlaceWnd(image, GetVehiclePalette(v), HT_DRAG, this); + _cursor.vehchain = true; + + this->SetDirty(); + break; + } + + case WID_GL_CREATE_GROUP: { // Create a new group + DoCommandP(0, this->vli.vtype, 0, CMD_CREATE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_CREATE), CcCreateGroup); + break; + } + + case WID_GL_DELETE_GROUP: { // Delete the selected group + GroupID group = this->vli.index; + this->vli.index = ALL_GROUP; + + DoCommandP(0, group, 0, CMD_DELETE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_DELETE)); + break; + } + + case WID_GL_RENAME_GROUP: // Rename the selected roup + this->ShowRenameGroupWindow(this->vli.index, false); + break; + + case WID_GL_AVAILABLE_VEHICLES: + ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype); + break; + + case WID_GL_MANAGE_VEHICLES_DROPDOWN: { + DropDownList *list = this->BuildActionDropdownList(true, Group::IsValidID(this->vli.index)); + ShowDropDownList(this, list, 0, WID_GL_MANAGE_VEHICLES_DROPDOWN); + break; + } + + case WID_GL_START_ALL: + case WID_GL_STOP_ALL: { // Start/stop all vehicles of the list + DoCommandP(0, (1 << 1) | (widget == WID_GL_START_ALL ? (1 << 0) : 0), this->vli.Pack(), CMD_MASS_START_STOP); + break; + } + + case WID_GL_REPLACE_PROTECTION: { + const Group *g = Group::GetIfValid(this->vli.index); + if (g != NULL) { + DoCommandP(0, this->vli.index, !g->replace_protection, CMD_SET_GROUP_REPLACE_PROTECTION); + } + break; + } + } + } + + virtual void OnDragDrop(Point pt, int widget) + { + switch (widget) { + case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles + DoCommandP(0, DEFAULT_GROUP, this->vehicle_sel | (_ctrl_pressed ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE)); + + this->vehicle_sel = INVALID_VEHICLE; + this->group_over = INVALID_GROUP; + + this->SetDirty(); + break; + + case WID_GL_LIST_GROUP: { // Matrix group + const VehicleID vindex = this->vehicle_sel; + this->vehicle_sel = INVALID_VEHICLE; + this->group_over = INVALID_GROUP; + this->SetDirty(); + + uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); + GroupID new_g = id_g >= this->groups.Length() ? NEW_GROUP : this->groups[id_g]->index; + + DoCommandP(0, new_g, vindex | (_ctrl_pressed ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE), new_g == NEW_GROUP ? CcAddVehicleNewGroup : NULL); + break; + } + + case WID_GL_LIST_VEHICLE: { // Matrix vehicle + const VehicleID vindex = this->vehicle_sel; + this->vehicle_sel = INVALID_VEHICLE; + this->group_over = INVALID_GROUP; + this->SetDirty(); + + uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE); + if (id_v >= this->vehicles.Length()) return; // click out of list bound + + const Vehicle *v = this->vehicles[id_v]; + if (!VehicleClicked(v) && vindex == v->index) { + ShowVehicleViewWindow(v); + } + break; + } + } + _cursor.vehchain = false; + } + + virtual void OnQueryTextFinished(char *str) + { + if (str != NULL) DoCommandP(0, this->group_rename, 0, CMD_RENAME_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_RENAME), NULL, str); + this->group_rename = INVALID_GROUP; + } + + virtual void OnResize() + { + this->group_sb->SetCapacityFromWidget(this, WID_GL_LIST_GROUP); + this->vscroll->SetCapacityFromWidget(this, WID_GL_LIST_VEHICLE); + } + + virtual void OnDropdownSelect(int widget, int index) + { + switch (widget) { + case WID_GL_SORT_BY_DROPDOWN: + this->vehicles.SetSortType(index); + break; + + case WID_GL_MANAGE_VEHICLES_DROPDOWN: + assert(this->vehicles.Length() != 0); + + switch (index) { + case ADI_REPLACE: // Replace window + ShowReplaceGroupVehicleWindow(this->vli.index, this->vli.vtype); + break; + case ADI_SERVICE: // Send for servicing + case ADI_DEPOT: { // Send to Depots + DoCommandP(0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : 0U), this->vli.Pack(), GetCmdSendToDepot(this->vli.vtype)); + break; + } + + case ADI_ADD_SHARED: // Add shared Vehicles + assert(Group::IsValidID(this->vli.index)); + + DoCommandP(0, this->vli.index, this->vli.vtype, CMD_ADD_SHARED_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE)); + break; + case ADI_REMOVE_ALL: // Remove all Vehicles from the selected group + assert(Group::IsValidID(this->vli.index)); + + DoCommandP(0, this->vli.index, 0, CMD_REMOVE_ALL_VEHICLES_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES)); + break; + default: NOT_REACHED(); + } + break; + + default: NOT_REACHED(); + } + + this->SetDirty(); + } + + virtual void OnTick() + { + if (_pause_mode != PM_UNPAUSED) return; + if (this->groups.NeedResort() || this->vehicles.NeedResort()) { + this->SetDirty(); + } + } + + virtual void OnPlaceObjectAbort() + { + /* abort drag & drop */ + this->vehicle_sel = INVALID_VEHICLE; + this->DirtyHighlightedGroupWidget(); + this->group_over = INVALID_GROUP; + this->SetWidgetDirty(WID_GL_LIST_VEHICLE); + } + + virtual void OnMouseDrag(Point pt, int widget) + { + if (this->vehicle_sel == INVALID_VEHICLE) return; + + /* A vehicle is dragged over... */ + GroupID new_group_over = INVALID_GROUP; + switch (widget) { + case WID_GL_DEFAULT_VEHICLES: // ... the 'default' group. + new_group_over = DEFAULT_GROUP; + break; + + case WID_GL_LIST_GROUP: { // ... the list of custom groups. + uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); + new_group_over = id_g >= this->groups.Length() ? NEW_GROUP : this->groups[id_g]->index; + break; + } + } + + /* Do not highlight when dragging over the current group */ + if (Vehicle::Get(vehicle_sel)->group_id == new_group_over) new_group_over = INVALID_GROUP; + + /* Mark widgets as dirty if the group changed. */ + if (new_group_over != this->group_over) { + this->DirtyHighlightedGroupWidget(); + this->group_over = new_group_over; + this->DirtyHighlightedGroupWidget(); + } + } + + void ShowRenameGroupWindow(GroupID group, bool empty) + { + assert(Group::IsValidID(group)); + this->group_rename = group; + /* Show empty query for new groups */ + StringID str = STR_EMPTY; + if (!empty) { + SetDParam(0, group); + str = STR_GROUP_NAME; + } + ShowQueryString(str, STR_GROUP_RENAME_CAPTION, MAX_LENGTH_GROUP_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); + } + + /** + * Tests whether a given vehicle is selected in the window, and unselects it if necessary. + * Called when the vehicle is deleted. + * @param vehicle Vehicle that is going to be deleted + */ + void UnselectVehicle(VehicleID vehicle) + { + if (this->vehicle_sel == vehicle) ResetObjectToPlace(); + } +}; + + +static WindowDesc _other_group_desc( + WDP_AUTO, "list_groups", 460, 246, + WC_INVALID, WC_NONE, + 0, + _nested_group_widgets, lengthof(_nested_group_widgets) +); + +static WindowDesc _train_group_desc( + WDP_AUTO, "list_groups_train", 525, 246, + WC_TRAINS_LIST, WC_NONE, + 0, + _nested_group_widgets, lengthof(_nested_group_widgets) +); + +/** + * Show the group window for the given company and vehicle type. + * @param company The company to show the window for. + * @param vehicle_type The type of vehicle to show it for. + */ +void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type) +{ + if (!Company::IsValidID(company)) return; + + WindowNumber num = VehicleListIdentifier(VL_GROUP_LIST, vehicle_type, company).Pack(); + if (vehicle_type == VEH_TRAIN) { + AllocateWindowDescFront(&_train_group_desc, num); + } else { + _other_group_desc.cls = GetWindowClassForVehicleType(vehicle_type); + AllocateWindowDescFront(&_other_group_desc, num); + } +} + +/** + * Finds a group list window determined by vehicle type and owner + * @param vt vehicle type + * @param owner owner of groups + * @return pointer to VehicleGroupWindow, NULL if not found + */ +static inline VehicleGroupWindow *FindVehicleGroupWindow(VehicleType vt, Owner owner) +{ + return (VehicleGroupWindow *)FindWindowById(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, owner).Pack()); +} + +/** + * Opens a 'Rename group' window for newly created group + * @param success did command succeed? + * @param tile unused + * @param p1 vehicle type + * @param p2 unused + * @see CmdCreateGroup + */ +void CcCreateGroup(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + assert(p1 <= VEH_AIRCRAFT); + + VehicleGroupWindow *w = FindVehicleGroupWindow((VehicleType)p1, _current_company); + if (w != NULL) w->ShowRenameGroupWindow(_new_group_id, true); +} + +/** + * Open rename window after adding a vehicle to a new group via drag and drop. + * @param success Did command succeed? + * @param tile Unused. + * @param p1 Unused. + * @param p2 Bit 0-19: Vehicle ID. + */ +void CcAddVehicleNewGroup(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + assert(Vehicle::IsValidID(GB(p2, 0, 20))); + + CcCreateGroup(result, 0, Vehicle::Get(GB(p2, 0, 20))->type, 0); +} + +/** + * Removes the highlight of a vehicle in a group window + * @param *v Vehicle to remove all highlights from + */ +void DeleteGroupHighlightOfVehicle(const Vehicle *v) +{ + /* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any group windows either + * If that is the case, we can skip looping though the windows and save time + */ + if (_special_mouse_mode != WSM_DRAGDROP) return; + + VehicleGroupWindow *w = FindVehicleGroupWindow(v->type, v->owner); + if (w != NULL) w->UnselectVehicle(v->index); +} diff --git a/src/industry_gui.cpp.orig b/src/industry_gui.cpp.orig new file mode 100644 index 0000000000..45a62a7fd3 --- /dev/null +++ b/src/industry_gui.cpp.orig @@ -0,0 +1,2718 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file industry_gui.cpp GUIs related to industries. */ + +#include "stdafx.h" +#include "error.h" +#include "gui.h" +#include "settings_gui.h" +#include "sound_func.h" +#include "window_func.h" +#include "textbuf_gui.h" +#include "command_func.h" +#include "viewport_func.h" +#include "industry.h" +#include "town.h" +#include "cheat_type.h" +#include "newgrf_industries.h" +#include "newgrf_text.h" +#include "newgrf_debug.h" +#include "strings_func.h" +#include "company_func.h" +#include "tilehighlight_func.h" +#include "string_func.h" +#include "sortlist_type.h" +#include "widgets/dropdown_func.h" +#include "company_base.h" +#include "core/geometry_func.hpp" +#include "core/random_func.hpp" +#include "core/backup_type.hpp" +#include "genworld.h" +#include "smallmap_gui.h" +#include "widgets/dropdown_type.h" +#include "widgets/industry_widget.h" + +#include "table/strings.h" + +bool _ignore_restrictions; +uint64 _displayed_industries; ///< Communication from the industry chain window to the smallmap window about what industries to display. + +assert_compile(NUM_INDUSTRYTYPES <= 64); // Make sure all industry types fit in _displayed_industries. + +/** Cargo suffix type (for which window is it requested) */ +enum CargoSuffixType { + CST_FUND, ///< Fund-industry window + CST_VIEW, ///< View-industry window + CST_DIR, ///< Industry-directory window +}; + +static void ShowIndustryCargoesWindow(IndustryType id); + +/** + * Gets the string to display after the cargo name (using callback 37) + * @param cargo the cargo for which the suffix is requested + * - 00 - first accepted cargo type + * - 01 - second accepted cargo type + * - 02 - third accepted cargo type + * - 03 - first produced cargo type + * - 04 - second produced cargo type + * @param cst the cargo suffix type (for which window is it requested). @see CargoSuffixType + * @param ind the industry (NULL if in fund window) + * @param ind_type the industry type + * @param indspec the industry spec + * @param suffix is filled with the string to display + * @param suffix_last lastof(suffix) + */ +static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, char *suffix, const char *suffix_last) +{ + suffix[0] = '\0'; + if (HasBit(indspec->callback_mask, CBM_IND_CARGO_SUFFIX)) { + uint16 callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, (cst << 8) | cargo, const_cast(ind), ind_type, (cst != CST_FUND) ? ind->location.tile : INVALID_TILE); + if (callback == CALLBACK_FAILED || callback == 0x400) return; + if (callback > 0x400) { + ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_CARGO_SUFFIX, callback); + } else if (indspec->grf_prop.grffile->grf_version >= 8 || GB(callback, 0, 8) != 0xFF) { + StartTextRefStackUsage(indspec->grf_prop.grffile, 6); + GetString(suffix, GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback), suffix_last); + StopTextRefStackUsage(); + } + } +} + +/** + * Gets all strings to display after the cargoes of industries (using callback 37) + * @param cb_offset The offset for the cargo used in cb37, 0 for accepted cargoes, 3 for produced cargoes + * @param cst the cargo suffix type (for which window is it requested). @see CargoSuffixType + * @param ind the industry (NULL if in fund window) + * @param ind_type the industry type + * @param indspec the industry spec + * @param cargoes array with cargotypes. for CT_INVALID no suffix will be determined + * @param suffixes is filled with the suffixes + */ +template +static inline void GetAllCargoSuffixes(uint cb_offset, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, const TC &cargoes, TS &suffixes) +{ + assert_compile(lengthof(cargoes) <= lengthof(suffixes)); + for (uint j = 0; j < lengthof(cargoes); j++) { + if (cargoes[j] != CT_INVALID) { + GetCargoSuffix(cb_offset + j, cst, ind, ind_type, indspec, suffixes[j], lastof(suffixes[j])); + } else { + suffixes[j][0] = '\0'; + } + } +} + +IndustryType _sorted_industry_types[NUM_INDUSTRYTYPES]; ///< Industry types sorted by name. + +/** Sort industry types by their name. */ +static int CDECL IndustryTypeNameSorter(const IndustryType *a, const IndustryType *b) +{ + static char industry_name[2][64]; + + const IndustrySpec *indsp1 = GetIndustrySpec(*a); + SetDParam(0, indsp1->name); + GetString(industry_name[0], STR_JUST_STRING, lastof(industry_name[0])); + + const IndustrySpec *indsp2 = GetIndustrySpec(*b); + SetDParam(0, indsp2->name); + GetString(industry_name[1], STR_JUST_STRING, lastof(industry_name[1])); + + int r = strnatcmp(industry_name[0], industry_name[1]); // Sort by name (natural sorting). + + /* If the names are equal, sort by industry type. */ + return (r != 0) ? r : (*a - *b); +} + +/** + * Initialize the list of sorted industry types. + */ +void SortIndustryTypes() +{ + /* Add each industry type to the list. */ + for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) { + _sorted_industry_types[i] = i; + } + + /* Sort industry types by name. */ + QSortT(_sorted_industry_types, NUM_INDUSTRYTYPES, &IndustryTypeNameSorter); +} + +/** + * Command callback. In case of failure to build an industry, show an error message. + * @param result Result of the command. + * @param tile Tile where the industry is placed. + * @param p1 Additional data of the #CMD_BUILD_INDUSTRY command. + * @param p2 Additional data of the #CMD_BUILD_INDUSTRY command. + */ +void CcBuildIndustry(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Succeeded()) return; + + uint8 indtype = GB(p1, 0, 8); + if (indtype < NUM_INDUSTRYTYPES) { + const IndustrySpec *indsp = GetIndustrySpec(indtype); + if (indsp->enabled) { + SetDParam(0, indsp->name); + ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HERE, result.GetErrorMessage(), WL_INFO, TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE); + } + } +} + +static const NWidgetPart _nested_build_industry_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_FUND_INDUSTRY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_DARK_GREEN, WID_DPI_MATRIX_WIDGET), SetMatrixDataTip(1, 0, STR_FUND_INDUSTRY_SELECTION_TOOLTIP), SetFill(1, 0), SetResize(1, 1), SetScrollbar(WID_DPI_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_DPI_SCROLLBAR), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_DPI_INFOPANEL), SetResize(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_DARK_GREEN, WID_DPI_DISPLAY_WIDGET), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_DARK_GREEN, WID_DPI_FUND_WIDGET), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_JUST_STRING, STR_NULL), + NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), + EndContainer(), +}; + +/** Window definition of the dynamic place industries gui */ +static WindowDesc _build_industry_desc( + WDP_AUTO, "build_industry", 170, 212, + WC_BUILD_INDUSTRY, WC_NONE, + WDF_CONSTRUCTION, + _nested_build_industry_widgets, lengthof(_nested_build_industry_widgets) +); + +/** Build (fund or prospect) a new industry, */ +class BuildIndustryWindow : public Window { + int selected_index; ///< index of the element in the matrix + IndustryType selected_type; ///< industry corresponding to the above index + uint16 callback_timer; ///< timer counter for callback eventual verification + bool timer_enabled; ///< timer can be used + uint16 count; ///< How many industries are loaded + IndustryType index[NUM_INDUSTRYTYPES + 1]; ///< Type of industry, in the order it was loaded + bool enabled[NUM_INDUSTRYTYPES + 1]; ///< availability state, coming from CBID_INDUSTRY_PROBABILITY (if ever) + Scrollbar *vscroll; + + void SetupArrays() + { + this->count = 0; + + for (uint i = 0; i < lengthof(this->index); i++) { + this->index[i] = INVALID_INDUSTRYTYPE; + this->enabled[i] = false; + } + + if (_game_mode == GM_EDITOR) { // give room for the Many Random "button" + this->index[this->count] = INVALID_INDUSTRYTYPE; + this->enabled[this->count] = true; + this->count++; + this->timer_enabled = false; + } + /* Fill the arrays with industries. + * The tests performed after the enabled allow to load the industries + * In the same way they are inserted by grf (if any) + */ + for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) { + IndustryType ind = _sorted_industry_types[i]; + const IndustrySpec *indsp = GetIndustrySpec(ind); + if (indsp->enabled) { + /* Rule is that editor mode loads all industries. + * In game mode, all non raw industries are loaded too + * and raw ones are loaded only when setting allows it */ + if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _settings_game.construction.raw_industry_construction == 0) { + /* Unselect if the industry is no longer in the list */ + if (this->selected_type == ind) this->selected_index = -1; + continue; + } + this->index[this->count] = ind; + this->enabled[this->count] = (_game_mode == GM_EDITOR) || GetIndustryProbabilityCallback(ind, IACT_USERCREATION, 1) > 0; + /* Keep the selection to the correct line */ + if (this->selected_type == ind) this->selected_index = this->count; + this->count++; + } + } + + /* first industry type is selected if the current selection is invalid. + * I'll be damned if there are none available ;) */ + if (this->selected_index == -1) { + this->selected_index = 0; + this->selected_type = this->index[0]; + } + + this->vscroll->SetCount(this->count); + } + + /** Update status of the fund and display-chain widgets. */ + void SetButtons() + { + this->SetWidgetDisabledState(WID_DPI_FUND_WIDGET, this->selected_type != INVALID_INDUSTRYTYPE && !this->enabled[this->selected_index]); + this->SetWidgetDisabledState(WID_DPI_DISPLAY_WIDGET, this->selected_type == INVALID_INDUSTRYTYPE && this->enabled[this->selected_index]); + } + +public: + BuildIndustryWindow() : Window(&_build_industry_desc) + { + this->timer_enabled = _loaded_newgrf_features.has_newindustries; + + this->selected_index = -1; + this->selected_type = INVALID_INDUSTRYTYPE; + + this->callback_timer = DAY_TICKS; + + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_DPI_SCROLLBAR); + this->FinishInitNested(0); + + this->SetButtons(); + } + + virtual void OnInit() + { + this->SetupArrays(); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_DPI_MATRIX_WIDGET: { + Dimension d = GetStringBoundingBox(STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES); + for (byte i = 0; i < this->count; i++) { + if (this->index[i] == INVALID_INDUSTRYTYPE) continue; + d = maxdim(d, GetStringBoundingBox(GetIndustrySpec(this->index[i])->name)); + } + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); + d.width += FONT_HEIGHT_NORMAL * 5 / 4 + padding.width; + d.height = 5 * resize->height; + *size = maxdim(*size, d); + break; + } + + case WID_DPI_INFOPANEL: { + /* Extra line for cost outside of editor + extra lines for 'extra' information for NewGRFs. */ + int height = 2 + (_game_mode == GM_EDITOR ? 0 : 1) + (_loaded_newgrf_features.has_newindustries ? 4 : 0); + Dimension d = {0, 0}; + for (byte i = 0; i < this->count; i++) { + if (this->index[i] == INVALID_INDUSTRYTYPE) continue; + + const IndustrySpec *indsp = GetIndustrySpec(this->index[i]); + + char cargo_suffix[3][512]; + GetAllCargoSuffixes(0, CST_FUND, NULL, this->index[i], indsp, indsp->accepts_cargo, cargo_suffix); + StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO; + byte p = 0; + SetDParam(0, STR_JUST_NOTHING); + SetDParamStr(1, ""); + for (byte j = 0; j < lengthof(indsp->accepts_cargo); j++) { + if (indsp->accepts_cargo[j] == CT_INVALID) continue; + if (p > 0) str++; + SetDParam(p++, CargoSpec::Get(indsp->accepts_cargo[j])->name); + SetDParamStr(p++, cargo_suffix[j]); + } + d = maxdim(d, GetStringBoundingBox(str)); + + /* Draw the produced cargoes, if any. Otherwise, will print "Nothing". */ + GetAllCargoSuffixes(3, CST_FUND, NULL, this->index[i], indsp, indsp->produced_cargo, cargo_suffix); + str = STR_INDUSTRY_VIEW_PRODUCES_CARGO; + p = 0; + SetDParam(0, STR_JUST_NOTHING); + SetDParamStr(1, ""); + for (byte j = 0; j < lengthof(indsp->produced_cargo); j++) { + if (indsp->produced_cargo[j] == CT_INVALID) continue; + if (p > 0) str++; + SetDParam(p++, CargoSpec::Get(indsp->produced_cargo[j])->name); + SetDParamStr(p++, cargo_suffix[j]); + } + d = maxdim(d, GetStringBoundingBox(str)); + } + + /* Set it to something more sane :) */ + size->height = height * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + size->width = d.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + break; + } + + case WID_DPI_FUND_WIDGET: { + Dimension d = GetStringBoundingBox(STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY); + d = maxdim(d, GetStringBoundingBox(STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY)); + d = maxdim(d, GetStringBoundingBox(STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY)); + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + } + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_DPI_FUND_WIDGET: + /* Raw industries might be prospected. Show this fact by changing the string + * In Editor, you just build, while ingame, or you fund or you prospect */ + if (_game_mode == GM_EDITOR) { + /* We've chosen many random industries but no industries have been specified */ + SetDParam(0, STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY); + } else { + const IndustrySpec *indsp = GetIndustrySpec(this->index[this->selected_index]); + SetDParam(0, (_settings_game.construction.raw_industry_construction == 2 && indsp->IsRawIndustry()) ? STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY : STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY); + } + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_DPI_MATRIX_WIDGET: { + uint text_left, text_right, icon_left, icon_right; + uint square_size = FONT_HEIGHT_NORMAL - 2; + uint text_offset = FONT_HEIGHT_NORMAL * 5 / 4; + if (_current_text_dir == TD_RTL) { + icon_right = r.right - WD_MATRIX_RIGHT; + icon_left = icon_right - square_size; + text_right = icon_right - text_offset; + text_left = r.left + WD_MATRIX_LEFT; + } else { + icon_left = r.left + WD_MATRIX_LEFT; + icon_right = icon_left + square_size; + text_left = icon_left + text_offset; + text_right = r.right - WD_MATRIX_RIGHT; + } + + int y = Center(r.top, this->resize.step_height); + for (byte i = 0; i < this->vscroll->GetCapacity() && i + this->vscroll->GetPosition() < this->count; i++, y += this->resize.step_height) { + bool selected = this->selected_index == i + this->vscroll->GetPosition(); + + if (this->index[i + this->vscroll->GetPosition()] == INVALID_INDUSTRYTYPE) { + DrawString(text_left, text_right, y, STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES, selected ? TC_WHITE : TC_ORANGE); + continue; + } + const IndustrySpec *indsp = GetIndustrySpec(this->index[i + this->vscroll->GetPosition()]); + + /* Draw the name of the industry in white is selected, otherwise, in orange */ + DrawString(text_left, text_right, y, indsp->name, selected ? TC_WHITE : TC_ORANGE); + GfxFillRect(icon_left, y + 1, icon_right, y + square_size, selected ? PC_WHITE : PC_BLACK); + GfxFillRect(icon_left + 1, y + 2, icon_right - 1, y + square_size - 1, indsp->map_colour); + } + break; + } + + case WID_DPI_INFOPANEL: { + int y = r.top + WD_FRAMERECT_TOP; + int bottom = r.bottom - WD_FRAMERECT_BOTTOM; + int left = r.left + WD_FRAMERECT_LEFT; + int right = r.right - WD_FRAMERECT_RIGHT; + + if (this->selected_type == INVALID_INDUSTRYTYPE) { + DrawStringMultiLine(left, right, y, bottom, STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP); + break; + } + + const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); + + if (_game_mode != GM_EDITOR) { + SetDParam(0, indsp->GetConstructionCost()); + DrawString(left, right, y, STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST); + y += FONT_HEIGHT_NORMAL; + } + + /* Draw the accepted cargoes, if any. Otherwise, will print "Nothing". */ + char cargo_suffix[3][512]; + GetAllCargoSuffixes(0, CST_FUND, NULL, this->selected_type, indsp, indsp->accepts_cargo, cargo_suffix); + StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO; + byte p = 0; + SetDParam(0, STR_JUST_NOTHING); + SetDParamStr(1, ""); + for (byte j = 0; j < lengthof(indsp->accepts_cargo); j++) { + if (indsp->accepts_cargo[j] == CT_INVALID) continue; + if (p > 0) str++; + SetDParam(p++, CargoSpec::Get(indsp->accepts_cargo[j])->name); + SetDParamStr(p++, cargo_suffix[j]); + } + DrawString(left, right, y, str); + y += FONT_HEIGHT_NORMAL; + + /* Draw the produced cargoes, if any. Otherwise, will print "Nothing". */ + GetAllCargoSuffixes(3, CST_FUND, NULL, this->selected_type, indsp, indsp->produced_cargo, cargo_suffix); + str = STR_INDUSTRY_VIEW_PRODUCES_CARGO; + p = 0; + SetDParam(0, STR_JUST_NOTHING); + SetDParamStr(1, ""); + for (byte j = 0; j < lengthof(indsp->produced_cargo); j++) { + if (indsp->produced_cargo[j] == CT_INVALID) continue; + if (p > 0) str++; + SetDParam(p++, CargoSpec::Get(indsp->produced_cargo[j])->name); + SetDParamStr(p++, cargo_suffix[j]); + } + DrawString(left, right, y, str); + y += FONT_HEIGHT_NORMAL; + + /* Get the additional purchase info text, if it has not already been queried. */ + str = STR_NULL; + if (HasBit(indsp->callback_mask, CBM_IND_FUND_MORE_TEXT)) { + uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, NULL, this->selected_type, INVALID_TILE); + if (callback_res != CALLBACK_FAILED && callback_res != 0x400) { + if (callback_res > 0x400) { + ErrorUnknownCallbackResult(indsp->grf_prop.grffile->grfid, CBID_INDUSTRY_FUND_MORE_TEXT, callback_res); + } else { + str = GetGRFStringID(indsp->grf_prop.grffile->grfid, 0xD000 + callback_res); // No. here's the new string + if (str != STR_UNDEFINED) { + StartTextRefStackUsage(indsp->grf_prop.grffile, 6); + DrawStringMultiLine(left, right, y, bottom, str, TC_YELLOW); + StopTextRefStackUsage(); + } + } + } + } + break; + } + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_DPI_MATRIX_WIDGET: { + int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_DPI_MATRIX_WIDGET); + if (y < this->count) { // Is it within the boundaries of available data? + this->selected_index = y; + this->selected_type = this->index[y]; + const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); + + this->SetDirty(); + + if (_thd.GetCallbackWnd() == this && + ((_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && indsp != NULL && indsp->IsRawIndustry()) || + this->selected_type == INVALID_INDUSTRYTYPE || + !this->enabled[this->selected_index])) { + /* Reset the button state if going to prospecting or "build many industries" */ + this->RaiseButtons(); + ResetObjectToPlace(); + } + + this->SetButtons(); + if (this->enabled[this->selected_index] && click_count > 1) this->OnClick(pt, WID_DPI_FUND_WIDGET, 1); + } + break; + } + + case WID_DPI_DISPLAY_WIDGET: + if (this->selected_type != INVALID_INDUSTRYTYPE) ShowIndustryCargoesWindow(this->selected_type); + break; + + case WID_DPI_FUND_WIDGET: { + if (this->selected_type == INVALID_INDUSTRYTYPE) { + this->HandleButtonClick(WID_DPI_FUND_WIDGET); + + if (Town::GetNumItems() == 0) { + ShowErrorMessage(STR_ERROR_CAN_T_GENERATE_INDUSTRIES, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO); + } else { + extern void GenerateIndustries(); + _generating_world = true; + GenerateIndustries(); + _generating_world = false; + } + } else if (_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && GetIndustrySpec(this->selected_type)->IsRawIndustry()) { + DoCommandP(0, this->selected_type, InteractiveRandom(), CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY)); + this->HandleButtonClick(WID_DPI_FUND_WIDGET); + } else { + HandlePlacePushButton(this, WID_DPI_FUND_WIDGET, SPR_CURSOR_INDUSTRY, HT_RECT); + } + break; + } + } + } + + virtual void OnResize() + { + /* Adjust the number of items in the matrix depending of the resize */ + this->vscroll->SetCapacityFromWidget(this, WID_DPI_MATRIX_WIDGET); + } + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + bool success = true; + /* We do not need to protect ourselves against "Random Many Industries" in this mode */ + const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); + uint32 seed = InteractiveRandom(); + + if (_game_mode == GM_EDITOR) { + /* Show error if no town exists at all */ + if (Town::GetNumItems() == 0) { + SetDParam(0, indsp->name); + ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HERE, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO, pt.x, pt.y); + return; + } + + Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); + _generating_world = true; + _ignore_restrictions = true; + + DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, + CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY), &CcBuildIndustry); + + cur_company.Restore(); + _ignore_restrictions = false; + _generating_world = false; + } else { + success = DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY)); + } + + /* If an industry has been built, just reset the cursor and the system */ + if (success && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + } + + virtual void OnTick() + { + if (_pause_mode != PM_UNPAUSED) return; + if (!this->timer_enabled) return; + if (--this->callback_timer == 0) { + /* We have just passed another day. + * See if we need to update availability of currently selected industry */ + this->callback_timer = DAY_TICKS; // restart counter + + const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); + + if (indsp->enabled) { + bool call_back_result = GetIndustryProbabilityCallback(this->selected_type, IACT_USERCREATION, 1) > 0; + + /* Only if result does match the previous state would it require a redraw. */ + if (call_back_result != this->enabled[this->selected_index]) { + this->enabled[this->selected_index] = call_back_result; + this->SetButtons(); + this->SetDirty(); + } + } + } + } + + virtual void OnTimeout() + { + this->RaiseButtons(); + } + + virtual void OnPlaceObjectAbort() + { + this->RaiseButtons(); + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + this->SetupArrays(); + + const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); + if (indsp == NULL) this->enabled[this->selected_index] = _settings_game.difficulty.industry_density != ID_FUND_ONLY; + this->SetButtons(); + } +}; + +void ShowBuildIndustryWindow() +{ + if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return; + if (BringWindowToFrontById(WC_BUILD_INDUSTRY, 0)) return; + new BuildIndustryWindow(); +} + +static void UpdateIndustryProduction(Industry *i); + +static inline bool IsProductionAlterable(const Industry *i) +{ + const IndustrySpec *is = GetIndustrySpec(i->type); + return ((_game_mode == GM_EDITOR || _cheats.setup_prod.value) && + (is->production_rate[0] != 0 || is->production_rate[1] != 0 || is->IsRawIndustry())); +} + +class IndustryViewWindow : public Window +{ + /** Modes for changing production */ + enum Editability { + EA_NONE, ///< Not alterable + EA_MULTIPLIER, ///< Allow changing the production multiplier + EA_RATE, ///< Allow changing the production rates + }; + + /** Specific lines in the info panel */ + enum InfoLine { + IL_NONE, ///< No line + IL_MULTIPLIER, ///< Production multiplier + IL_RATE1, ///< Production rate of cargo 1 + IL_RATE2, ///< Production rate of cargo 2 + }; + + Editability editable; ///< Mode for changing production + InfoLine editbox_line; ///< The line clicked to open the edit box + InfoLine clicked_line; ///< The line of the button that has been clicked + byte clicked_button; ///< The button that has been clicked (to raise) + int production_offset_y; ///< The offset of the production texts/buttons + int info_height; ///< Height needed for the #WID_IV_INFO panel + +public: + IndustryViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->flags |= WF_DISABLE_VP_SCROLL; + this->editbox_line = IL_NONE; + this->clicked_line = IL_NONE; + this->clicked_button = 0; + this->info_height = WD_FRAMERECT_TOP + 2 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM + 1; // Info panel has at least two lines text. + + this->InitNested(window_number); + NWidgetViewport *nvp = this->GetWidget(WID_IV_VIEWPORT); + nvp->InitializeViewport(this, Industry::Get(window_number)->location.GetCenterTile(), ZOOM_LVL_INDUSTRY); + + this->InvalidateData(); + } + + virtual void OnPaint() + { + this->DrawWidgets(); + + if (this->IsShaded()) return; // Don't draw anything when the window is shaded. + + NWidgetBase *nwi = this->GetWidget(WID_IV_INFO); + uint expected = this->DrawInfo(nwi->pos_x, nwi->pos_x + nwi->current_x - 1, nwi->pos_y) - nwi->pos_y; + if (expected > nwi->current_y - 1) { + this->info_height = expected + 1; + this->ReInit(); + return; + } + } + + /** + * Draw the text in the #WID_IV_INFO panel. + * @param left Left edge of the panel. + * @param right Right edge of the panel. + * @param top Top edge of the panel. + * @return Expected position of the bottom edge of the panel. + */ + int DrawInfo(uint left, uint right, uint top) + { + Industry *i = Industry::Get(this->window_number); + const IndustrySpec *ind = GetIndustrySpec(i->type); + int y = top + WD_FRAMERECT_TOP; + bool first = true; + bool has_accept = false; + char cargo_suffix[3][512]; + + if (i->prod_level == PRODLEVEL_CLOSURE) { + DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE); + y += 2 * FONT_HEIGHT_NORMAL; + } + + if (HasBit(ind->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) { + GetAllCargoSuffixes(0, CST_VIEW, i, i->type, ind, i->accepts_cargo, cargo_suffix); + for (byte j = 0; j < lengthof(i->accepts_cargo); j++) { + if (i->accepts_cargo[j] == CT_INVALID) continue; + has_accept = true; + if (first) { + DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING); + y += FONT_HEIGHT_NORMAL; + first = false; + } + SetDParam(0, i->accepts_cargo[j]); + SetDParam(1, i->incoming_cargo_waiting[j]); + SetDParamStr(2, cargo_suffix[j]); + DrawString(left + WD_FRAMETEXT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO); + y += FONT_HEIGHT_NORMAL; + } + } else { + GetAllCargoSuffixes(0, CST_VIEW, i, i->type, ind, i->accepts_cargo, cargo_suffix); + StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO; + byte p = 0; + for (byte j = 0; j < lengthof(i->accepts_cargo); j++) { + if (i->accepts_cargo[j] == CT_INVALID) continue; + has_accept = true; + if (p > 0) str++; + SetDParam(p++, CargoSpec::Get(i->accepts_cargo[j])->name); + SetDParamStr(p++, cargo_suffix[j]); + } + if (has_accept) { + DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, str); + y += FONT_HEIGHT_NORMAL; + } + } + + GetAllCargoSuffixes(3, CST_VIEW, i, i->type, ind, i->produced_cargo, cargo_suffix); + first = true; + for (byte j = 0; j < lengthof(i->produced_cargo); j++) { + if (i->produced_cargo[j] == CT_INVALID) continue; + if (first) { + if (has_accept) y += WD_PAR_VSEP_WIDE; + DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE); + y += this->editable == EA_RATE ? GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL) : FONT_HEIGHT_NORMAL; + if (this->editable == EA_RATE) this->production_offset_y = y; + first = false; + } + + SetDParam(0, i->produced_cargo[j]); + SetDParam(1, i->last_month_production[j]); + SetDParamStr(2, cargo_suffix[j]); + SetDParam(3, ToPercent8(i->last_month_pct_transported[j])); + uint x = left + WD_FRAMETEXT_LEFT + (this->editable == EA_RATE ? SETTING_BUTTON_WIDTH + 10 : 0); + DrawString(x, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_TRANSPORTED); + /* Let's put out those buttons.. */ + if (this->editable == EA_RATE) { + DrawArrowButtons(left + WD_FRAMETEXT_LEFT, y, COLOUR_YELLOW, (this->clicked_line == IL_RATE1 + j) ? this->clicked_button : 0, + i->production_rate[j] > 0, i->production_rate[j] < 255); + y += GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + } else { + y += FONT_HEIGHT_NORMAL; + } + } + + /* Display production multiplier if editable */ + if (this->editable == EA_MULTIPLIER) { + y += WD_PAR_VSEP_WIDE; + this->production_offset_y = y; + SetDParam(0, RoundDivSU(i->prod_level * 100, PRODLEVEL_DEFAULT)); + uint x = left + WD_FRAMETEXT_LEFT + SETTING_BUTTON_WIDTH + 10; + DrawString(x, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_PRODUCTION_LEVEL); + DrawArrowButtons(left + WD_FRAMETEXT_LEFT, y, COLOUR_YELLOW, (this->clicked_line == IL_MULTIPLIER) ? this->clicked_button : 0, + i->prod_level > PRODLEVEL_MINIMUM, i->prod_level < PRODLEVEL_MAXIMUM); + y += GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + } + + /* Get the extra message for the GUI */ + if (HasBit(ind->callback_mask, CBM_IND_WINDOW_MORE_TEXT)) { + uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_WINDOW_MORE_TEXT, 0, 0, i, i->type, i->location.tile); + if (callback_res != CALLBACK_FAILED && callback_res != 0x400) { + if (callback_res > 0x400) { + ErrorUnknownCallbackResult(ind->grf_prop.grffile->grfid, CBID_INDUSTRY_WINDOW_MORE_TEXT, callback_res); + } else { + StringID message = GetGRFStringID(ind->grf_prop.grffile->grfid, 0xD000 + callback_res); + if (message != STR_NULL && message != STR_UNDEFINED) { + y += WD_PAR_VSEP_WIDE; + + StartTextRefStackUsage(ind->grf_prop.grffile, 6); + /* Use all the available space left from where we stand up to the + * end of the window. We ALSO enlarge the window if needed, so we + * can 'go' wild with the bottom of the window. */ + y = DrawStringMultiLine(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, UINT16_MAX, message, TC_BLACK); + StopTextRefStackUsage(); + } + } + } + } + return y + WD_FRAMERECT_BOTTOM; + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_IV_CAPTION) SetDParam(0, this->window_number); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget == WID_IV_INFO) size->height = this->info_height; + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_IV_INFO: { + Industry *i = Industry::Get(this->window_number); + InfoLine line = IL_NONE; + + switch (this->editable) { + case EA_NONE: break; + + case EA_MULTIPLIER: + if (IsInsideBS(pt.y, this->production_offset_y, SETTING_BUTTON_HEIGHT)) line = IL_MULTIPLIER; + break; + + case EA_RATE: + if (pt.y >= this->production_offset_y) { + if ((pt.y - this->production_offset_y) % GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL) > (uint)SETTING_BUTTON_HEIGHT) break;; + + int row = (pt.y - this->production_offset_y) / GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + for (uint j = 0; j < lengthof(i->produced_cargo); j++) { + if (i->produced_cargo[j] == CT_INVALID) continue; + row--; + if (row < 0) { + line = (InfoLine)(IL_RATE1 + j); + break; + } + } + } + break; + } + if (line == IL_NONE) return; + + NWidgetBase *nwi = this->GetWidget(widget); + int left = nwi->pos_x + WD_FRAMETEXT_LEFT; + int right = nwi->pos_x + nwi->current_x - 1 - WD_FRAMERECT_RIGHT; + if (IsInsideMM(pt.x, left, left + SETTING_BUTTON_WIDTH)) { + /* Clicked buttons, decrease or increase production */ + byte button = (pt.x < left + SETTING_BUTTON_WIDTH / 2) ? 1 : 2; + switch (this->editable) { + case EA_MULTIPLIER: + if (button == 1) { + if (i->prod_level <= PRODLEVEL_MINIMUM) return; + i->prod_level = max(i->prod_level / 2, PRODLEVEL_MINIMUM); + } else { + if (i->prod_level >= PRODLEVEL_MAXIMUM) return; + i->prod_level = minu(i->prod_level * 2, PRODLEVEL_MAXIMUM); + } + break; + + case EA_RATE: + if (button == 1) { + if (i->production_rate[line - IL_RATE1] <= 0) return; + i->production_rate[line - IL_RATE1] = max(i->production_rate[line - IL_RATE1] / 2, 0); + } else { + if (i->production_rate[line - IL_RATE1] >= 255) return; + /* a zero production industry is unlikely to give anything but zero, so push it a little bit */ + int new_prod = i->production_rate[line - IL_RATE1] == 0 ? 1 : i->production_rate[line - IL_RATE1] * 2; + i->production_rate[line - IL_RATE1] = minu(new_prod, 255); + } + break; + + default: NOT_REACHED(); + } + + UpdateIndustryProduction(i); + this->SetDirty(); + this->SetTimeout(); + this->clicked_line = line; + this->clicked_button = button; + } else if (IsInsideMM(pt.x, left + SETTING_BUTTON_WIDTH + 10, right)) { + /* clicked the text */ + this->editbox_line = line; + switch (this->editable) { + case EA_MULTIPLIER: + SetDParam(0, RoundDivSU(i->prod_level * 100, PRODLEVEL_DEFAULT)); + ShowQueryString(STR_JUST_INT, STR_CONFIG_GAME_PRODUCTION_LEVEL, 10, this, CS_ALPHANUMERAL, QSF_NONE); + break; + + case EA_RATE: + SetDParam(0, i->production_rate[line - IL_RATE1] * 8); + ShowQueryString(STR_JUST_INT, STR_CONFIG_GAME_PRODUCTION, 10, this, CS_ALPHANUMERAL, QSF_NONE); + break; + + default: NOT_REACHED(); + } + } + break; + } + + case WID_IV_GOTO: { + Industry *i = Industry::Get(this->window_number); + if (_ctrl_pressed) { + ShowExtraViewPortWindow(i->location.GetCenterTile()); + } else { + ScrollMainWindowToTile(i->location.GetCenterTile()); + } + break; + } + + case WID_IV_DISPLAY: { + Industry *i = Industry::Get(this->window_number); + ShowIndustryCargoesWindow(i->type); + break; + } + } + } + + virtual void OnTimeout() + { + this->clicked_line = IL_NONE; + this->clicked_button = 0; + this->SetDirty(); + } + + virtual void OnResize() + { + if (this->viewport != NULL) { + NWidgetViewport *nvp = this->GetWidget(WID_IV_VIEWPORT); + nvp->UpdateViewportCoordinates(this); + + ScrollWindowToTile(Industry::Get(this->window_number)->location.GetCenterTile(), this, true); // Re-center viewport. + } + } + + virtual void OnQueryTextFinished(char *str) + { + if (StrEmpty(str)) return; + + Industry *i = Industry::Get(this->window_number); + uint value = atoi(str); + switch (this->editbox_line) { + case IL_NONE: NOT_REACHED(); + + case IL_MULTIPLIER: + i->prod_level = ClampU(RoundDivSU(value * PRODLEVEL_DEFAULT, 100), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM); + break; + + default: + i->production_rate[this->editbox_line - IL_RATE1] = ClampU(RoundDivSU(value, 8), 0, 255); + break; + } + UpdateIndustryProduction(i); + this->SetDirty(); + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + const Industry *i = Industry::Get(this->window_number); + if (IsProductionAlterable(i)) { + const IndustrySpec *ind = GetIndustrySpec(i->type); + this->editable = ind->UsesSmoothEconomy() ? EA_RATE : EA_MULTIPLIER; + } else { + this->editable = EA_NONE; + } + } + + virtual bool IsNewGRFInspectable() const + { + return ::IsNewGRFInspectable(GSF_INDUSTRIES, this->window_number); + } + + virtual void ShowNewGRFInspectWindow() const + { + ::ShowNewGRFInspectWindow(GSF_INDUSTRIES, this->window_number); + } +}; + +static void UpdateIndustryProduction(Industry *i) +{ + const IndustrySpec *indspec = GetIndustrySpec(i->type); + if (!indspec->UsesSmoothEconomy()) i->RecomputeProductionMultipliers(); + + for (byte j = 0; j < lengthof(i->produced_cargo); j++) { + if (i->produced_cargo[j] != CT_INVALID) { + i->last_month_production[j] = 8 * i->production_rate[j]; + } + } +} + +/** Widget definition of the view industry gui */ +static const NWidgetPart _nested_industry_view_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_CREAM), + NWidget(WWT_CAPTION, COLOUR_CREAM, WID_IV_CAPTION), SetDataTip(STR_INDUSTRY_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_DEBUGBOX, COLOUR_CREAM), + NWidget(WWT_SHADEBOX, COLOUR_CREAM), + NWidget(WWT_DEFSIZEBOX, COLOUR_CREAM), + NWidget(WWT_STICKYBOX, COLOUR_CREAM), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_CREAM), + NWidget(WWT_INSET, COLOUR_CREAM), SetPadding(2, 2, 2, 2), + NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_IV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 0), SetPadding(1, 1, 1, 1), SetResize(1, 1), + EndContainer(), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_CREAM, WID_IV_INFO), SetMinimalSize(260, 2), SetResize(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_GOTO), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_INDUSTRY_VIEW_LOCATION_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_DISPLAY), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP), + NWidget(WWT_RESIZEBOX, COLOUR_CREAM), + EndContainer(), +}; + +/** Window definition of the view industry gui */ +static WindowDesc _industry_view_desc( + WDP_AUTO, "view_industry", 260, 120, + WC_INDUSTRY_VIEW, WC_NONE, + 0, + _nested_industry_view_widgets, lengthof(_nested_industry_view_widgets) +); + +void ShowIndustryViewWindow(int industry) +{ + AllocateWindowDescFront(&_industry_view_desc, industry); +} + +/** Widget definition of the industry directory gui */ +static const NWidgetPart _nested_industry_directory_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_BROWN), + NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_INDUSTRY_DIRECTORY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_BROWN), + NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), + NWidget(WWT_STICKYBOX, COLOUR_BROWN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetSizingType(NWST_STEP), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_ID_INDUSTRY_LIST), SetDataTip(0x0, STR_INDUSTRY_DIRECTORY_LIST_CAPTION), SetResize(1, 1), SetScrollbar(WID_ID_SCROLLBAR), EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_ID_SCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_BROWN), + EndContainer(), + EndContainer(), +}; + +typedef GUIList GUIIndustryList; + + +/** + * The list of industries. + */ +class IndustryDirectoryWindow : public Window { +protected: + /* Runtime saved values */ + static Listing last_sorting; + static const Industry *last_industry; + + /* Constants for sorting stations */ + static const StringID sorter_names[]; + static GUIIndustryList::SortFunction * const sorter_funcs[]; + + GUIIndustryList industries; + Scrollbar *vscroll; + + /** (Re)Build industries list */ + void BuildSortIndustriesList() + { + if (this->industries.NeedRebuild()) { + this->industries.Clear(); + + const Industry *i; + FOR_ALL_INDUSTRIES(i) { + *this->industries.Append() = i; + } + + this->industries.Compact(); + this->industries.RebuildDone(); + this->vscroll->SetCount(this->industries.Length()); // Update scrollbar as well. + } + + if (!this->industries.Sort()) return; + IndustryDirectoryWindow::last_industry = NULL; // Reset name sorter sort cache + this->SetWidgetDirty(WID_ID_INDUSTRY_LIST); // Set the modified widget dirty + } + + /** + * Returns percents of cargo transported if industry produces this cargo, else -1 + * + * @param i industry to check + * @param id cargo slot + * @return percents of cargo transported, or -1 if industry doesn't use this cargo slot + */ + static inline int GetCargoTransportedPercentsIfValid(const Industry *i, uint id) + { + assert(id < lengthof(i->produced_cargo)); + + if (i->produced_cargo[id] == CT_INVALID) return 101; + return ToPercent8(i->last_month_pct_transported[id]); + } + + /** + * Returns value representing industry's transported cargo + * percentage for industry sorting + * + * @param i industry to check + * @return value used for sorting + */ + static int GetCargoTransportedSortValue(const Industry *i) + { + int p1 = GetCargoTransportedPercentsIfValid(i, 0); + int p2 = GetCargoTransportedPercentsIfValid(i, 1); + + if (p1 > p2) Swap(p1, p2); // lower value has higher priority + + return (p1 << 8) + p2; + } + + /** Sort industries by name */ + static int CDECL IndustryNameSorter(const Industry * const *a, const Industry * const *b) + { + static char buf_cache[96]; + static char buf[96]; + + SetDParam(0, (*a)->index); + GetString(buf, STR_INDUSTRY_NAME, lastof(buf)); + + if (*b != last_industry) { + last_industry = *b; + SetDParam(0, (*b)->index); + GetString(buf_cache, STR_INDUSTRY_NAME, lastof(buf_cache)); + } + + return strnatcmp(buf, buf_cache); // Sort by name (natural sorting). + } + + /** Sort industries by type and name */ + static int CDECL IndustryTypeSorter(const Industry * const *a, const Industry * const *b) + { + int it_a = 0; + while (it_a != NUM_INDUSTRYTYPES && (*a)->type != _sorted_industry_types[it_a]) it_a++; + int it_b = 0; + while (it_b != NUM_INDUSTRYTYPES && (*b)->type != _sorted_industry_types[it_b]) it_b++; + int r = it_a - it_b; + return (r == 0) ? IndustryNameSorter(a, b) : r; + } + + /** Sort industries by production and name */ + static int CDECL IndustryProductionSorter(const Industry * const *a, const Industry * const *b) + { + uint prod_a = 0, prod_b = 0; + for (uint i = 0; i < lengthof((*a)->produced_cargo); i++) { + if ((*a)->produced_cargo[i] != CT_INVALID) prod_a += (*a)->last_month_production[i]; + if ((*b)->produced_cargo[i] != CT_INVALID) prod_b += (*b)->last_month_production[i]; + } + int r = prod_a - prod_b; + + return (r == 0) ? IndustryTypeSorter(a, b) : r; + } + + /** Sort industries by transported cargo and name */ + static int CDECL IndustryTransportedCargoSorter(const Industry * const *a, const Industry * const *b) + { + int r = GetCargoTransportedSortValue(*a) - GetCargoTransportedSortValue(*b); + return (r == 0) ? IndustryNameSorter(a, b) : r; + } + + /** + * Get the StringID to draw and set the appropriate DParams. + * @param i the industry to get the StringID of. + * @return the StringID. + */ + StringID GetIndustryString(const Industry *i) const + { + const IndustrySpec *indsp = GetIndustrySpec(i->type); + byte p = 0; + + /* Industry name */ + SetDParam(p++, i->index); + + static char cargo_suffix[lengthof(i->produced_cargo)][512]; + GetAllCargoSuffixes(3, CST_DIR, i, i->type, indsp, i->produced_cargo, cargo_suffix); + + /* Industry productions */ + for (byte j = 0; j < lengthof(i->produced_cargo); j++) { + if (i->produced_cargo[j] == CT_INVALID) continue; + SetDParam(p++, i->produced_cargo[j]); + SetDParam(p++, i->last_month_production[j]); + SetDParamStr(p++, cargo_suffix[j]); + } + + /* Transported productions */ + for (byte j = 0; j < lengthof(i->produced_cargo); j++) { + if (i->produced_cargo[j] == CT_INVALID) continue; + SetDParam(p++, ToPercent8(i->last_month_pct_transported[j])); + } + + /* Drawing the right string */ + switch (p) { + case 1: return STR_INDUSTRY_DIRECTORY_ITEM_NOPROD; + case 5: return STR_INDUSTRY_DIRECTORY_ITEM; + default: return STR_INDUSTRY_DIRECTORY_ITEM_TWO; + } + } + +public: + IndustryDirectoryWindow(WindowDesc *desc, WindowNumber number) : Window(desc) + { + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_ID_SCROLLBAR); + + this->industries.SetListing(this->last_sorting); + this->industries.SetSortFuncs(IndustryDirectoryWindow::sorter_funcs); + this->industries.ForceRebuild(); + this->BuildSortIndustriesList(); + + this->FinishInitNested(0); + } + + ~IndustryDirectoryWindow() + { + this->last_sorting = this->industries.GetListing(); + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_ID_DROPDOWN_CRITERIA) SetDParam(0, IndustryDirectoryWindow::sorter_names[this->industries.SortType()]); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_ID_DROPDOWN_ORDER: + this->DrawSortButtonState(widget, this->industries.IsDescSortOrder() ? SBS_DOWN : SBS_UP); + break; + + case WID_ID_INDUSTRY_LIST: { + int n = 0; + int y = Center(r.top, this->resize.step_height); + if (this->industries.Length() == 0) { + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_DIRECTORY_NONE); + break; + } + for (uint i = this->vscroll->GetPosition(); i < this->industries.Length(); i++) { + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, this->GetIndustryString(this->industries[i])); + + y += this->resize.step_height; + if (++n == this->vscroll->GetCapacity()) break; // max number of industries in 1 window + } + break; + } + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_ID_DROPDOWN_ORDER: { + Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); + d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_ID_DROPDOWN_CRITERIA: { + Dimension d = {0, 0}; + for (uint i = 0; IndustryDirectoryWindow::sorter_names[i] != INVALID_STRING_ID; i++) { + d = maxdim(d, GetStringBoundingBox(IndustryDirectoryWindow::sorter_names[i])); + } + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_ID_INDUSTRY_LIST: { + Dimension d = GetStringBoundingBox(STR_INDUSTRY_DIRECTORY_NONE); + for (uint i = 0; i < this->industries.Length(); i++) { + d = maxdim(d, GetStringBoundingBox(this->GetIndustryString(this->industries[i]))); + } + resize->height = d.height = GetMinSizing(NWST_STEP, d.height); + d.height *= 5; + d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + *size = maxdim(*size, d); + break; + } + } + } + + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_ID_DROPDOWN_ORDER: + this->industries.ToggleSortOrder(); + this->SetDirty(); + break; + + case WID_ID_DROPDOWN_CRITERIA: + ShowDropDownMenu(this, IndustryDirectoryWindow::sorter_names, this->industries.SortType(), WID_ID_DROPDOWN_CRITERIA, 0, 0); + break; + + case WID_ID_INDUSTRY_LIST: { + uint p = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_ID_INDUSTRY_LIST, WD_FRAMERECT_TOP); + if (p < this->industries.Length()) { + if (_ctrl_pressed) { + ShowExtraViewPortWindow(this->industries[p]->location.tile); + } else { + ScrollMainWindowToTile(this->industries[p]->location.tile); + } + } + break; + } + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + if (this->industries.SortType() != index) { + this->industries.SetSortType(index); + this->BuildSortIndustriesList(); + } + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_ID_INDUSTRY_LIST); + } + + virtual void OnPaint() + { + if (this->industries.NeedRebuild()) this->BuildSortIndustriesList(); + this->DrawWidgets(); + } + + virtual void OnHundredthTick() + { + this->industries.ForceResort(); + this->BuildSortIndustriesList(); + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (data == 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ + this->industries.ForceRebuild(); + } else { + this->industries.ForceResort(); + } + } +}; + +Listing IndustryDirectoryWindow::last_sorting = {false, 0}; +const Industry *IndustryDirectoryWindow::last_industry = NULL; + +/* Available station sorting functions. */ +GUIIndustryList::SortFunction * const IndustryDirectoryWindow::sorter_funcs[] = { + &IndustryNameSorter, + &IndustryTypeSorter, + &IndustryProductionSorter, + &IndustryTransportedCargoSorter +}; + +/* Names of the sorting functions */ +const StringID IndustryDirectoryWindow::sorter_names[] = { + STR_SORT_BY_NAME, + STR_SORT_BY_TYPE, + STR_SORT_BY_PRODUCTION, + STR_SORT_BY_TRANSPORTED, + INVALID_STRING_ID +}; + + +/** Window definition of the industry directory gui */ +static WindowDesc _industry_directory_desc( + WDP_AUTO, "list_industries", 428, 190, + WC_INDUSTRY_DIRECTORY, WC_NONE, + 0, + _nested_industry_directory_widgets, lengthof(_nested_industry_directory_widgets) +); + +void ShowIndustryDirectory() +{ + AllocateWindowDescFront(&_industry_directory_desc, 0); +} + +/** Widgets of the industry cargoes window. */ +static const NWidgetPart _nested_industry_cargoes_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_BROWN), + NWidget(WWT_CAPTION, COLOUR_BROWN, WID_IC_CAPTION), SetDataTip(STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_BROWN), + NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), + NWidget(WWT_STICKYBOX, COLOUR_BROWN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_VERTICAL), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_IC_PANEL), SetResize(1, 10), SetMinimalSize(200, 90), SetScrollbar(WID_IC_SCROLLBAR), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_IC_NOTIFY), + SetDataTip(STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP, STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_BROWN), SetFill(1, 0), SetResize(0, 0), EndContainer(), + NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_IC_IND_DROPDOWN), SetFill(0, 0), SetResize(0, 0), + SetDataTip(STR_INDUSTRY_CARGOES_SELECT_INDUSTRY, STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP), + NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_IC_CARGO_DROPDOWN), SetFill(0, 0), SetResize(0, 0), + SetDataTip(STR_INDUSTRY_CARGOES_SELECT_CARGO, STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_IC_SCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_BROWN), + EndContainer(), + EndContainer(), +}; + +/** Window description for the industry cargoes window. */ +static WindowDesc _industry_cargoes_desc( + WDP_AUTO, "industry_cargoes", 300, 210, + WC_INDUSTRY_CARGOES, WC_NONE, + 0, + _nested_industry_cargoes_widgets, lengthof(_nested_industry_cargoes_widgets) +); + +/** Available types of field. */ +enum CargoesFieldType { + CFT_EMPTY, ///< Empty field. + CFT_SMALL_EMPTY, ///< Empty small field (for the header). + CFT_INDUSTRY, ///< Display industry. + CFT_CARGO, ///< Display cargo connections. + CFT_CARGO_LABEL, ///< Display cargo labels. + CFT_HEADER, ///< Header text. +}; + +static const uint MAX_CARGOES = 3; ///< Maximum number of cargoes carried in a #CFT_CARGO field in #CargoesField. + +/** Data about a single field in the #IndustryCargoesWindow panel. */ +struct CargoesField { + static const int VERT_INTER_INDUSTRY_SPACE; + static const int HOR_CARGO_BORDER_SPACE; + static const int CARGO_STUB_WIDTH; + static const int HOR_CARGO_WIDTH, HOR_CARGO_SPACE; + static const int CARGO_FIELD_WIDTH; + static const int VERT_CARGO_SPACE, VERT_CARGO_EDGE; + static const int BLOB_DISTANCE, BLOB_WIDTH, BLOB_HEIGHT; + + static const int INDUSTRY_LINE_COLOUR; + static const int CARGO_LINE_COLOUR; + + static int small_height, normal_height; + static int industry_width; + + CargoesFieldType type; ///< Type of field. + union { + struct { + IndustryType ind_type; ///< Industry type (#NUM_INDUSTRYTYPES means 'houses'). + CargoID other_produced[MAX_CARGOES]; ///< Cargoes produced but not used in this figure. + CargoID other_accepted[MAX_CARGOES]; ///< Cargoes accepted but not used in this figure. + } industry; ///< Industry data (for #CFT_INDUSTRY). + struct { + CargoID vertical_cargoes[MAX_CARGOES]; ///< Cargoes running from top to bottom (cargo ID or #INVALID_CARGO). + byte num_cargoes; ///< Number of cargoes. + CargoID supp_cargoes[MAX_CARGOES]; ///< Cargoes entering from the left (index in #vertical_cargoes, or #INVALID_CARGO). + byte top_end; ///< Stop at the top of the vertical cargoes. + CargoID cust_cargoes[MAX_CARGOES]; ///< Cargoes leaving to the right (index in #vertical_cargoes, or #INVALID_CARGO). + byte bottom_end; ///< Stop at the bottom of the vertical cargoes. + } cargo; ///< Cargo data (for #CFT_CARGO). + struct { + CargoID cargoes[MAX_CARGOES]; ///< Cargoes to display (or #INVALID_CARGO). + bool left_align; ///< Align all cargo texts to the left (else align to the right). + } cargo_label; ///< Label data (for #CFT_CARGO_LABEL). + StringID header; ///< Header text (for #CFT_HEADER). + } u; // Data for each type. + + /** + * Make one of the empty fields (#CFT_EMPTY or #CFT_SMALL_EMPTY). + * @param type Type of empty field. + */ + void MakeEmpty(CargoesFieldType type) + { + this->type = type; + } + + /** + * Make an industry type field. + * @param ind_type Industry type (#NUM_INDUSTRYTYPES means 'houses'). + * @note #other_accepted and #other_produced should be filled later. + */ + void MakeIndustry(IndustryType ind_type) + { + this->type = CFT_INDUSTRY; + this->u.industry.ind_type = ind_type; + MemSetT(this->u.industry.other_accepted, INVALID_CARGO, MAX_CARGOES); + MemSetT(this->u.industry.other_produced, INVALID_CARGO, MAX_CARGOES); + } + + /** + * Connect a cargo from an industry to the #CFT_CARGO column. + * @param cargo Cargo to connect. + * @param produced Cargo is produced (if \c false, cargo is assumed to be accepted). + * @return Horizontal connection index, or \c -1 if not accepted at all. + */ + int ConnectCargo(CargoID cargo, bool producer) + { + assert(this->type == CFT_CARGO); + if (cargo == INVALID_CARGO) return -1; + + /* Find the vertical cargo column carrying the cargo. */ + int column = -1; + for (int i = 0; i < this->u.cargo.num_cargoes; i++) { + if (cargo == this->u.cargo.vertical_cargoes[i]) { + column = i; + break; + } + } + if (column < 0) return -1; + + if (producer) { + assert(this->u.cargo.supp_cargoes[column] == INVALID_CARGO); + this->u.cargo.supp_cargoes[column] = column; + } else { + assert(this->u.cargo.cust_cargoes[column] == INVALID_CARGO); + this->u.cargo.cust_cargoes[column] = column; + } + return column; + } + + /** + * Does this #CFT_CARGO field have a horizontal connection? + * @return \c true if a horizontal connection exists, \c false otherwise. + */ + bool HasConnection() + { + assert(this->type == CFT_CARGO); + + for (uint i = 0; i < MAX_CARGOES; i++) { + if (this->u.cargo.supp_cargoes[i] != INVALID_CARGO) return true; + if (this->u.cargo.cust_cargoes[i] != INVALID_CARGO) return true; + } + return false; + } + + /** + * Make a piece of cargo column. + * @param cargoes Array of #CargoID (may contain #INVALID_CARGO). + * @param length Number of cargoes in \a cargoes. + * @param count Number of cargoes to display (should be at least the number of valid cargoes, or \c -1 to let the method compute it). + * @param top_end This is the first cargo field of this column. + * @param bottom_end This is the last cargo field of this column. + * @note #supp_cargoes and #cust_cargoes should be filled in later. + */ + void MakeCargo(const CargoID *cargoes, uint length, int count = -1, bool top_end = false, bool bottom_end = false) + { + this->type = CFT_CARGO; + uint i; + uint num = 0; + for (i = 0; i < MAX_CARGOES && i < length; i++) { + if (cargoes[i] != INVALID_CARGO) { + this->u.cargo.vertical_cargoes[num] = cargoes[i]; + num++; + } + } + this->u.cargo.num_cargoes = (count < 0) ? num : count; + for (; num < MAX_CARGOES; num++) this->u.cargo.vertical_cargoes[num] = INVALID_CARGO; + this->u.cargo.top_end = top_end; + this->u.cargo.bottom_end = bottom_end; + MemSetT(this->u.cargo.supp_cargoes, INVALID_CARGO, MAX_CARGOES); + MemSetT(this->u.cargo.cust_cargoes, INVALID_CARGO, MAX_CARGOES); + } + + /** + * Make a field displaying cargo type names. + * @param cargoes Array of #CargoID (may contain #INVALID_CARGO). + * @param length Number of cargoes in \a cargoes. + * @param left_align ALign texts to the left (else to the right). + */ + void MakeCargoLabel(const CargoID *cargoes, uint length, bool left_align) + { + this->type = CFT_CARGO_LABEL; + uint i; + for (i = 0; i < MAX_CARGOES && i < length; i++) this->u.cargo_label.cargoes[i] = cargoes[i]; + for (; i < MAX_CARGOES; i++) this->u.cargo_label.cargoes[i] = INVALID_CARGO; + this->u.cargo_label.left_align = left_align; + } + + /** + * Make a header above an industry column. + * @param textid Text to display. + */ + void MakeHeader(StringID textid) + { + this->type = CFT_HEADER; + this->u.header = textid; + } + + /** + * For a #CFT_CARGO, compute the left position of the left-most vertical cargo connection. + * @param xpos Left position of the field. + * @return Left position of the left-most vertical cargo column. + */ + int GetCargoBase(int xpos) const + { + assert(this->type == CFT_CARGO); + + switch (this->u.cargo.num_cargoes) { + case 0: return xpos + CARGO_FIELD_WIDTH / 2; + case 1: return xpos + CARGO_FIELD_WIDTH / 2 - HOR_CARGO_WIDTH / 2; + case 2: return xpos + CARGO_FIELD_WIDTH / 2 - HOR_CARGO_WIDTH - HOR_CARGO_SPACE / 2; + case 3: return xpos + CARGO_FIELD_WIDTH / 2 - HOR_CARGO_WIDTH - HOR_CARGO_SPACE - HOR_CARGO_WIDTH / 2; + default: NOT_REACHED(); + } + } + + /** + * Draw the field. + * @param xpos Position of the left edge. + * @param vpos Position of the top edge. + */ + void Draw(int xpos, int ypos) const + { + switch (this->type) { + case CFT_EMPTY: + case CFT_SMALL_EMPTY: + break; + + case CFT_HEADER: + ypos += (small_height - FONT_HEIGHT_NORMAL) / 2; + DrawString(xpos, xpos + industry_width, ypos, this->u.header, TC_WHITE, SA_HOR_CENTER); + break; + + case CFT_INDUSTRY: { + int ypos1 = ypos + VERT_INTER_INDUSTRY_SPACE / 2; + int ypos2 = ypos + normal_height - 1 - VERT_INTER_INDUSTRY_SPACE / 2; + int xpos2 = xpos + industry_width - 1; + GfxDrawLine(xpos, ypos1, xpos2, ypos1, INDUSTRY_LINE_COLOUR); + GfxDrawLine(xpos, ypos1, xpos, ypos2, INDUSTRY_LINE_COLOUR); + GfxDrawLine(xpos, ypos2, xpos2, ypos2, INDUSTRY_LINE_COLOUR); + GfxDrawLine(xpos2, ypos1, xpos2, ypos2, INDUSTRY_LINE_COLOUR); + ypos += (normal_height - FONT_HEIGHT_NORMAL) / 2; + if (this->u.industry.ind_type < NUM_INDUSTRYTYPES) { + const IndustrySpec *indsp = GetIndustrySpec(this->u.industry.ind_type); + SetDParam(0, indsp->name); + DrawString(xpos, xpos2, ypos, STR_JUST_STRING, TC_WHITE, SA_HOR_CENTER); + + /* Draw the industry legend. */ + int blob_left, blob_right; + if (_current_text_dir == TD_RTL) { + blob_right = xpos2 - BLOB_DISTANCE; + blob_left = blob_right - BLOB_WIDTH; + } else { + blob_left = xpos + BLOB_DISTANCE; + blob_right = blob_left + BLOB_WIDTH; + } + GfxFillRect(blob_left, ypos2 - BLOB_DISTANCE - BLOB_HEIGHT, blob_right, ypos2 - BLOB_DISTANCE, PC_BLACK); // Border + GfxFillRect(blob_left + 1, ypos2 - BLOB_DISTANCE - BLOB_HEIGHT + 1, blob_right - 1, ypos2 - BLOB_DISTANCE - 1, indsp->map_colour); + } else { + DrawString(xpos, xpos2, ypos, STR_INDUSTRY_CARGOES_HOUSES, TC_FROMSTRING, SA_HOR_CENTER); + } + + /* Draw the other_produced/other_accepted cargoes. */ + const CargoID *other_right, *other_left; + if (_current_text_dir == TD_RTL) { + other_right = this->u.industry.other_accepted; + other_left = this->u.industry.other_produced; + } else { + other_right = this->u.industry.other_produced; + other_left = this->u.industry.other_accepted; + } + ypos1 += VERT_CARGO_EDGE; + for (uint i = 0; i < MAX_CARGOES; i++) { + if (other_right[i] != INVALID_CARGO) { + const CargoSpec *csp = CargoSpec::Get(other_right[i]); + int xp = xpos + industry_width + CARGO_STUB_WIDTH; + DrawHorConnection(xpos + industry_width, xp - 1, ypos1, csp); + GfxDrawLine(xp, ypos1, xp, ypos1 + FONT_HEIGHT_NORMAL - 1, CARGO_LINE_COLOUR); + } + if (other_left[i] != INVALID_CARGO) { + const CargoSpec *csp = CargoSpec::Get(other_left[i]); + int xp = xpos - CARGO_STUB_WIDTH; + DrawHorConnection(xp + 1, xpos - 1, ypos1, csp); + GfxDrawLine(xp, ypos1, xp, ypos1 + FONT_HEIGHT_NORMAL - 1, CARGO_LINE_COLOUR); + } + ypos1 += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; + } + break; + } + + case CFT_CARGO: { + int cargo_base = this->GetCargoBase(xpos); + int top = ypos + (this->u.cargo.top_end ? VERT_INTER_INDUSTRY_SPACE / 2 + 1 : 0); + int bot = ypos - (this->u.cargo.bottom_end ? VERT_INTER_INDUSTRY_SPACE / 2 + 1 : 0) + normal_height - 1; + int colpos = cargo_base; + for (int i = 0; i < this->u.cargo.num_cargoes; i++) { + if (this->u.cargo.top_end) GfxDrawLine(colpos, top - 1, colpos + HOR_CARGO_WIDTH - 1, top - 1, CARGO_LINE_COLOUR); + if (this->u.cargo.bottom_end) GfxDrawLine(colpos, bot + 1, colpos + HOR_CARGO_WIDTH - 1, bot + 1, CARGO_LINE_COLOUR); + GfxDrawLine(colpos, top, colpos, bot, CARGO_LINE_COLOUR); + colpos++; + const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[i]); + GfxFillRect(colpos, top, colpos + HOR_CARGO_WIDTH - 2, bot, csp->legend_colour, FILLRECT_OPAQUE); + colpos += HOR_CARGO_WIDTH - 2; + GfxDrawLine(colpos, top, colpos, bot, CARGO_LINE_COLOUR); + colpos += 1 + HOR_CARGO_SPACE; + } + + const CargoID *hor_left, *hor_right; + if (_current_text_dir == TD_RTL) { + hor_left = this->u.cargo.cust_cargoes; + hor_right = this->u.cargo.supp_cargoes; + } else { + hor_left = this->u.cargo.supp_cargoes; + hor_right = this->u.cargo.cust_cargoes; + } + ypos += VERT_CARGO_EDGE + VERT_INTER_INDUSTRY_SPACE / 2; + for (uint i = 0; i < MAX_CARGOES; i++) { + if (hor_left[i] != INVALID_CARGO) { + int col = hor_left[i]; + int dx = 0; + const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[col]); + for (; col > 0; col--) { + int lf = cargo_base + col * HOR_CARGO_WIDTH + (col - 1) * HOR_CARGO_SPACE; + DrawHorConnection(lf, lf + HOR_CARGO_SPACE - dx, ypos, csp); + dx = 1; + } + DrawHorConnection(xpos, cargo_base - dx, ypos, csp); + } + if (hor_right[i] != INVALID_CARGO) { + int col = hor_right[i]; + int dx = 0; + const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[col]); + for (; col < this->u.cargo.num_cargoes - 1; col++) { + int lf = cargo_base + (col + 1) * HOR_CARGO_WIDTH + col * HOR_CARGO_SPACE; + DrawHorConnection(lf + dx - 1, lf + HOR_CARGO_SPACE - 1, ypos, csp); + dx = 1; + } + DrawHorConnection(cargo_base + col * HOR_CARGO_SPACE + (col + 1) * HOR_CARGO_WIDTH - 1 + dx, xpos + CARGO_FIELD_WIDTH - 1, ypos, csp); + } + ypos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; + } + break; + } + + case CFT_CARGO_LABEL: + ypos += VERT_CARGO_EDGE + VERT_INTER_INDUSTRY_SPACE / 2; + for (uint i = 0; i < MAX_CARGOES; i++) { + if (this->u.cargo_label.cargoes[i] != INVALID_CARGO) { + const CargoSpec *csp = CargoSpec::Get(this->u.cargo_label.cargoes[i]); + DrawString(xpos + WD_FRAMERECT_LEFT, xpos + industry_width - 1 - WD_FRAMERECT_RIGHT, ypos, csp->name, TC_WHITE, + (this->u.cargo_label.left_align) ? SA_LEFT : SA_RIGHT); + } + ypos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; + } + break; + + default: + NOT_REACHED(); + } + } + + /** + * Decide which cargo was clicked at in a #CFT_CARGO field. + * @param left Left industry neighbour if available (else \c NULL should be supplied). + * @param right Right industry neighbour if available (else \c NULL should be supplied). + * @param pt Click position in the cargo field. + * @return Cargo clicked at, or #INVALID_CARGO if none. + */ + CargoID CargoClickedAt(const CargoesField *left, const CargoesField *right, Point pt) const + { + assert(this->type == CFT_CARGO); + + /* Vertical matching. */ + int cpos = this->GetCargoBase(0); + uint col; + for (col = 0; col < this->u.cargo.num_cargoes; col++) { + if (pt.x < cpos) break; + if (pt.x < cpos + CargoesField::HOR_CARGO_WIDTH) return this->u.cargo.vertical_cargoes[col]; + cpos += CargoesField::HOR_CARGO_WIDTH + CargoesField::HOR_CARGO_SPACE; + } + /* col = 0 -> left of first col, 1 -> left of 2nd col, ... this->u.cargo.num_cargoes right of last-col. */ + + int vpos = VERT_INTER_INDUSTRY_SPACE / 2 + VERT_CARGO_EDGE; + uint row; + for (row = 0; row < MAX_CARGOES; row++) { + if (pt.y < vpos) return INVALID_CARGO; + if (pt.y < vpos + FONT_HEIGHT_NORMAL) break; + vpos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; + } + if (row == MAX_CARGOES) return INVALID_CARGO; + + /* row = 0 -> at first horizontal row, row = 1 -> second horizontal row, 2 = 3rd horizontal row. */ + if (col == 0) { + if (this->u.cargo.supp_cargoes[row] != INVALID_CARGO) return this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]]; + if (left != NULL) { + if (left->type == CFT_INDUSTRY) return left->u.industry.other_produced[row]; + if (left->type == CFT_CARGO_LABEL && !left->u.cargo_label.left_align) return left->u.cargo_label.cargoes[row]; + } + return INVALID_CARGO; + } + if (col == this->u.cargo.num_cargoes) { + if (this->u.cargo.cust_cargoes[row] != INVALID_CARGO) return this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]]; + if (right != NULL) { + if (right->type == CFT_INDUSTRY) return right->u.industry.other_accepted[row]; + if (right->type == CFT_CARGO_LABEL && right->u.cargo_label.left_align) return right->u.cargo_label.cargoes[row]; + } + return INVALID_CARGO; + } + if (row >= col) { + /* Clicked somewhere in-between vertical cargo connection. + * Since the horizontal connection is made in the same order as the vertical list, the above condition + * ensures we are left-below the main diagonal, thus at the supplying side. + */ + return (this->u.cargo.supp_cargoes[row] != INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]] : INVALID_CARGO; + } else { + /* Clicked at a customer connection. */ + return (this->u.cargo.cust_cargoes[row] != INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]] : INVALID_CARGO; + } + } + + /** + * Decide what cargo the user clicked in the cargo label field. + * @param pt Click position in the cargo label field. + * @return Cargo clicked at, or #INVALID_CARGO if none. + */ + CargoID CargoLabelClickedAt(Point pt) const + { + assert(this->type == CFT_CARGO_LABEL); + + int vpos = VERT_INTER_INDUSTRY_SPACE / 2 + VERT_CARGO_EDGE; + uint row; + for (row = 0; row < MAX_CARGOES; row++) { + if (pt.y < vpos) return INVALID_CARGO; + if (pt.y < vpos + FONT_HEIGHT_NORMAL) break; + vpos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; + } + if (row == MAX_CARGOES) return INVALID_CARGO; + return this->u.cargo_label.cargoes[row]; + } + +private: + /** + * Draw a horizontal cargo connection. + * @param left Left-most coordinate to draw. + * @param right Right-most coordinate to draw. + * @param top Top coordinate of the cargo connection. + * @param csp Cargo to draw. + */ + static void DrawHorConnection(int left, int right, int top, const CargoSpec *csp) + { + GfxDrawLine(left, top, right, top, CARGO_LINE_COLOUR); + GfxFillRect(left, top + 1, right, top + FONT_HEIGHT_NORMAL - 2, csp->legend_colour, FILLRECT_OPAQUE); + GfxDrawLine(left, top + FONT_HEIGHT_NORMAL - 1, right, top + FONT_HEIGHT_NORMAL - 1, CARGO_LINE_COLOUR); + } +}; + +assert_compile(MAX_CARGOES >= cpp_lengthof(IndustrySpec, produced_cargo)); +assert_compile(MAX_CARGOES >= cpp_lengthof(IndustrySpec, accepts_cargo)); + +int CargoesField::small_height; ///< Height of the header row. +int CargoesField::normal_height; ///< Height of the non-header rows. +int CargoesField::industry_width; ///< Width of an industry field. +const int CargoesField::VERT_INTER_INDUSTRY_SPACE = 6; ///< Amount of space between two industries in a column. + +const int CargoesField::HOR_CARGO_BORDER_SPACE = 15; ///< Amount of space between the left/right edge of a #CFT_CARGO field, and the left/right most vertical cargo. +const int CargoesField::CARGO_STUB_WIDTH = 10; ///< Width of a cargo not carried in the column (should be less than #HOR_CARGO_BORDER_SPACE). +const int CargoesField::HOR_CARGO_WIDTH = 15; ///< Width of a vertical cargo column (inclusive the border line). +const int CargoesField::HOR_CARGO_SPACE = 5; ///< Amount of horizontal space between two vertical cargoes. +const int CargoesField::VERT_CARGO_EDGE = 4; ///< Amount of vertical space between top/bottom and the top/bottom connected cargo at an industry. +const int CargoesField::VERT_CARGO_SPACE = 4; ///< Amount of vertical space between two connected cargoes at an industry. + +const int CargoesField::BLOB_DISTANCE = 5; ///< Distance of the industry legend colour from the edge of the industry box. +const int CargoesField::BLOB_WIDTH = 12; ///< Width of the industry legend colour, including border. +const int CargoesField::BLOB_HEIGHT = 9; ///< Height of the industry legend colour, including border + +/** Width of a #CFT_CARGO field. */ +const int CargoesField::CARGO_FIELD_WIDTH = HOR_CARGO_BORDER_SPACE * 2 + HOR_CARGO_WIDTH * MAX_CARGOES + HOR_CARGO_SPACE * (MAX_CARGOES - 1); + +const int CargoesField::INDUSTRY_LINE_COLOUR = PC_YELLOW; ///< Line colour of the industry type box. +const int CargoesField::CARGO_LINE_COLOUR = PC_YELLOW; ///< Line colour around the cargo. + +/** A single row of #CargoesField. */ +struct CargoesRow { + CargoesField columns[5]; ///< One row of fields. + + /** + * Connect industry production cargoes to the cargo column after it. + * @param column Column of the industry. + */ + void ConnectIndustryProduced(int column) + { + CargoesField *ind_fld = this->columns + column; + CargoesField *cargo_fld = this->columns + column + 1; + assert(ind_fld->type == CFT_INDUSTRY && cargo_fld->type == CFT_CARGO); + + MemSetT(ind_fld->u.industry.other_produced, INVALID_CARGO, MAX_CARGOES); + + if (ind_fld->u.industry.ind_type < NUM_INDUSTRYTYPES) { + CargoID others[MAX_CARGOES]; // Produced cargoes not carried in the cargo column. + int other_count = 0; + + const IndustrySpec *indsp = GetIndustrySpec(ind_fld->u.industry.ind_type); + for (uint i = 0; i < lengthof(indsp->produced_cargo); i++) { + int col = cargo_fld->ConnectCargo(indsp->produced_cargo[i], true); + if (col < 0) others[other_count++] = indsp->produced_cargo[i]; + } + + /* Allocate other cargoes in the empty holes of the horizontal cargo connections. */ + for (uint i = 0; i < MAX_CARGOES && other_count > 0; i++) { + if (cargo_fld->u.cargo.supp_cargoes[i] == INVALID_CARGO) ind_fld->u.industry.other_produced[i] = others[--other_count]; + } + } else { + /* Houses only display what is demanded. */ + for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) { + CargoID cid = cargo_fld->u.cargo.vertical_cargoes[i]; + if (cid == CT_PASSENGERS || cid == CT_MAIL) cargo_fld->ConnectCargo(cid, true); + } + } + } + + /** + * Construct a #CFT_CARGO_LABEL field. + * @param column Column to create the new field. + * @param accepting Display accepted cargo (if \c false, display produced cargo). + */ + void MakeCargoLabel(int column, bool accepting) + { + CargoID cargoes[MAX_CARGOES]; + MemSetT(cargoes, INVALID_CARGO, lengthof(cargoes)); + + CargoesField *label_fld = this->columns + column; + CargoesField *cargo_fld = this->columns + (accepting ? column - 1 : column + 1); + + assert(cargo_fld->type == CFT_CARGO && label_fld->type == CFT_EMPTY); + for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) { + int col = cargo_fld->ConnectCargo(cargo_fld->u.cargo.vertical_cargoes[i], !accepting); + if (col >= 0) cargoes[col] = cargo_fld->u.cargo.vertical_cargoes[i]; + } + label_fld->MakeCargoLabel(cargoes, lengthof(cargoes), accepting); + } + + + /** + * Connect industry accepted cargoes to the cargo column before it. + * @param column Column of the industry. + */ + void ConnectIndustryAccepted(int column) + { + CargoesField *ind_fld = this->columns + column; + CargoesField *cargo_fld = this->columns + column - 1; + assert(ind_fld->type == CFT_INDUSTRY && cargo_fld->type == CFT_CARGO); + + MemSetT(ind_fld->u.industry.other_accepted, INVALID_CARGO, MAX_CARGOES); + + if (ind_fld->u.industry.ind_type < NUM_INDUSTRYTYPES) { + CargoID others[MAX_CARGOES]; // Accepted cargoes not carried in the cargo column. + int other_count = 0; + + const IndustrySpec *indsp = GetIndustrySpec(ind_fld->u.industry.ind_type); + for (uint i = 0; i < lengthof(indsp->accepts_cargo); i++) { + int col = cargo_fld->ConnectCargo(indsp->accepts_cargo[i], false); + if (col < 0) others[other_count++] = indsp->accepts_cargo[i]; + } + + /* Allocate other cargoes in the empty holes of the horizontal cargo connections. */ + for (uint i = 0; i < MAX_CARGOES && other_count > 0; i++) { + if (cargo_fld->u.cargo.cust_cargoes[i] == INVALID_CARGO) ind_fld->u.industry.other_accepted[i] = others[--other_count]; + } + } else { + /* Houses only display what is demanded. */ + for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) { + for (uint h = 0; h < NUM_HOUSES; h++) { + HouseSpec *hs = HouseSpec::Get(h); + if (!hs->enabled) continue; + + for (uint j = 0; j < lengthof(hs->accepts_cargo); j++) { + if (cargo_fld->u.cargo.vertical_cargoes[i] == hs->accepts_cargo[j]) { + cargo_fld->ConnectCargo(cargo_fld->u.cargo.vertical_cargoes[i], false); + goto next_cargo; + } + } + } +next_cargo: ; + } + } + } +}; + + +/** + * Window displaying the cargo connections around an industry (or cargo). + * + * The main display is constructed from 'fields', rectangles that contain an industry, piece of the cargo connection, cargo labels, or headers. + * For a nice display, the following should be kept in mind: + * - A #CFT_HEADER is always at the top of an column of #CFT_INDUSTRY fields. + * - A #CFT_CARGO_LABEL field is also always put in a column of #CFT_INDUSTRY fields. + * - The top row contains #CFT_HEADER and #CFT_SMALL_EMPTY fields. + * - Cargo connections have a column of their own (#CFT_CARGO fields). + * - Cargo accepted or produced by an industry, but not carried in a cargo connection, is drawn in the space of a cargo column attached to the industry. + * The information however is part of the industry. + * + * This results in the following invariants: + * - Width of a #CFT_INDUSTRY column is large enough to hold all industry type labels, all cargo labels, and all header texts. + * - Height of a #CFT_INDUSTRY is large enough to hold a header line, or a industry type line, \c N cargo labels + * (where \c N is the maximum number of cargoes connected between industries), \c N connections of cargo types, and space + * between two industry types (1/2 above it, and 1/2 underneath it). + * - Width of a cargo field (#CFT_CARGO) is large enough to hold \c N vertical columns (one for each type of cargo). + * Also, space is needed between an industry and the leftmost/rightmost column to draw the non-carried cargoes. + * - Height of a #CFT_CARGO field is equally high as the height of the #CFT_INDUSTRY. + * - A field at the top (#CFT_HEADER or #CFT_SMALL_EMPTY) match the width of the fields below them (#CFT_INDUSTRY respectively + * #CFT_CARGO), the height should be sufficient to display the header text. + * + * When displaying the cargoes around an industry type, five columns are needed (supplying industries, accepted cargoes, the industry, + * produced cargoes, customer industries). Displaying the industries around a cargo needs three columns (supplying industries, the cargo, + * customer industries). The remaining two columns are set to #CFT_EMPTY with a width equal to the average of a cargo and an industry column. + */ +struct IndustryCargoesWindow : public Window { + static const int HOR_TEXT_PADDING, VERT_TEXT_PADDING; + + typedef SmallVector Fields; + + Fields fields; ///< Fields to display in the #WID_IC_PANEL. + uint ind_cargo; ///< If less than #NUM_INDUSTRYTYPES, an industry type, else a cargo id + NUM_INDUSTRYTYPES. + Dimension cargo_textsize; ///< Size to hold any cargo text, as well as STR_INDUSTRY_CARGOES_SELECT_CARGO. + Dimension ind_textsize; ///< Size to hold any industry type text, as well as STR_INDUSTRY_CARGOES_SELECT_INDUSTRY. + Scrollbar *vscroll; + + IndustryCargoesWindow(int id) : Window(&_industry_cargoes_desc) + { + this->OnInit(); + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_IC_SCROLLBAR); + this->FinishInitNested(0); + this->OnInvalidateData(id); + } + + virtual void OnInit() + { + /* Initialize static CargoesField size variables. */ + Dimension d = GetStringBoundingBox(STR_INDUSTRY_CARGOES_PRODUCERS); + d = maxdim(d, GetStringBoundingBox(STR_INDUSTRY_CARGOES_CUSTOMERS)); + d.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; + d.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM; + CargoesField::small_height = d.height; + + /* Decide about the size of the box holding the text of an industry type. */ + this->ind_textsize.width = 0; + this->ind_textsize.height = 0; + for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { + const IndustrySpec *indsp = GetIndustrySpec(it); + if (!indsp->enabled) continue; + this->ind_textsize = maxdim(this->ind_textsize, GetStringBoundingBox(indsp->name)); + } + d.width = max(d.width, this->ind_textsize.width); + d.height = this->ind_textsize.height; + this->ind_textsize = maxdim(this->ind_textsize, GetStringBoundingBox(STR_INDUSTRY_CARGOES_SELECT_INDUSTRY)); + + /* Compute max size of the cargo texts. */ + this->cargo_textsize.width = 0; + this->cargo_textsize.height = 0; + for (uint i = 0; i < NUM_CARGO; i++) { + const CargoSpec *csp = CargoSpec::Get(i); + if (!csp->IsValid()) continue; + this->cargo_textsize = maxdim(this->cargo_textsize, GetStringBoundingBox(csp->name)); + } + d = maxdim(d, this->cargo_textsize); // Box must also be wide enough to hold any cargo label. + this->cargo_textsize = maxdim(this->cargo_textsize, GetStringBoundingBox(STR_INDUSTRY_CARGOES_SELECT_CARGO)); + + d.width += 2 * HOR_TEXT_PADDING; + /* Ensure the height is enough for the industry type text, for the horizontal connections, and for the cargo labels. */ + uint min_ind_height = CargoesField::VERT_CARGO_EDGE * 2 + MAX_CARGOES * FONT_HEIGHT_NORMAL + (MAX_CARGOES - 1) * CargoesField::VERT_CARGO_SPACE; + d.height = max(d.height + 2 * VERT_TEXT_PADDING, min_ind_height); + + CargoesField::industry_width = d.width; + CargoesField::normal_height = d.height + CargoesField::VERT_INTER_INDUSTRY_SPACE; + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_IC_PANEL: + size->width = WD_FRAMETEXT_LEFT + CargoesField::industry_width * 3 + CargoesField::CARGO_FIELD_WIDTH * 2 + WD_FRAMETEXT_RIGHT; + break; + + case WID_IC_IND_DROPDOWN: + size->width = max(size->width, this->ind_textsize.width + padding.width); + break; + + case WID_IC_CARGO_DROPDOWN: + size->width = max(size->width, this->cargo_textsize.width + padding.width); + break; + } + } + + + CargoesFieldType type; ///< Type of field. + virtual void SetStringParameters (int widget) const + { + if (widget != WID_IC_CAPTION) return; + + if (this->ind_cargo < NUM_INDUSTRYTYPES) { + const IndustrySpec *indsp = GetIndustrySpec(this->ind_cargo); + SetDParam(0, indsp->name); + } else { + const CargoSpec *csp = CargoSpec::Get(this->ind_cargo - NUM_INDUSTRYTYPES); + SetDParam(0, csp->name); + } + } + + /** + * Do the two sets of cargoes have a valid cargo in common? + * @param cargoes1 Base address of the first cargo array. + * @param length1 Number of cargoes in the first cargo array. + * @param cargoes2 Base address of the second cargo array. + * @param length2 Number of cargoes in the second cargo array. + * @return Arrays have at least one valid cargo in common. + */ + static bool HasCommonValidCargo(const CargoID *cargoes1, uint length1, const CargoID *cargoes2, uint length2) + { + while (length1 > 0) { + if (*cargoes1 != INVALID_CARGO) { + for (uint i = 0; i < length2; i++) if (*cargoes1 == cargoes2[i]) return true; + } + cargoes1++; + length1--; + } + return false; + } + + /** + * Can houses be used to supply one of the cargoes? + * @param cargoes Base address of the cargo array. + * @param length Number of cargoes in the array. + * @return Houses can supply at least one of the cargoes. + */ + static bool HousesCanSupply(const CargoID *cargoes, uint length) + { + for (uint i = 0; i < length; i++) { + if (cargoes[i] == INVALID_CARGO) continue; + if (cargoes[i] == CT_PASSENGERS || cargoes[i] == CT_MAIL) return true; + } + return false; + } + + /** + * Can houses be used as customers of the produced cargoes? + * @param cargoes Base address of the cargo array. + * @param length Number of cargoes in the array. + * @return Houses can accept at least one of the cargoes. + */ + static bool HousesCanAccept(const CargoID *cargoes, uint length) + { + HouseZones climate_mask; + switch (_settings_game.game_creation.landscape) { + case LT_TEMPERATE: climate_mask = HZ_TEMP; break; + case LT_ARCTIC: climate_mask = HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW; break; + case LT_TROPIC: climate_mask = HZ_SUBTROPIC; break; + case LT_TOYLAND: climate_mask = HZ_TOYLND; break; + default: NOT_REACHED(); + } + for (uint i = 0; i < length; i++) { + if (cargoes[i] == INVALID_CARGO) continue; + + for (uint h = 0; h < NUM_HOUSES; h++) { + HouseSpec *hs = HouseSpec::Get(h); + if (!hs->enabled || !(hs->building_availability & climate_mask)) continue; + + for (uint j = 0; j < lengthof(hs->accepts_cargo); j++) { + if (cargoes[i] == hs->accepts_cargo[j]) return true; + } + } + } + return false; + } + + /** + * Count how many industries have accepted cargoes in common with one of the supplied set. + * @param cargoes Cargoes to search. + * @param length Number of cargoes in \a cargoes. + * @return Number of industries that have an accepted cargo in common with the supplied set. + */ + static int CountMatchingAcceptingIndustries(const CargoID *cargoes, uint length) + { + int count = 0; + for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { + const IndustrySpec *indsp = GetIndustrySpec(it); + if (!indsp->enabled) continue; + + if (HasCommonValidCargo(cargoes, length, indsp->accepts_cargo, lengthof(indsp->accepts_cargo))) count++; + } + return count; + } + + /** + * Count how many industries have produced cargoes in common with one of the supplied set. + * @param cargoes Cargoes to search. + * @param length Number of cargoes in \a cargoes. + * @return Number of industries that have a produced cargo in common with the supplied set. + */ + static int CountMatchingProducingIndustries(const CargoID *cargoes, uint length) + { + int count = 0; + for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { + const IndustrySpec *indsp = GetIndustrySpec(it); + if (!indsp->enabled) continue; + + if (HasCommonValidCargo(cargoes, length, indsp->produced_cargo, lengthof(indsp->produced_cargo))) count++; + } + return count; + } + + /** + * Shorten the cargo column to just the part between industries. + * @param column Column number of the cargo column. + * @param top Current top row. + * @param bottom Current bottom row. + */ + void ShortenCargoColumn(int column, int top, int bottom) + { + while (top < bottom && !this->fields[top].columns[column].HasConnection()) { + this->fields[top].columns[column].MakeEmpty(CFT_EMPTY); + top++; + } + this->fields[top].columns[column].u.cargo.top_end = true; + + while (bottom > top && !this->fields[bottom].columns[column].HasConnection()) { + this->fields[bottom].columns[column].MakeEmpty(CFT_EMPTY); + bottom--; + } + this->fields[bottom].columns[column].u.cargo.bottom_end = true; + } + + /** + * Place an industry in the fields. + * @param row Row of the new industry. + * @param col Column of the new industry. + * @param it Industry to place. + */ + void PlaceIndustry(int row, int col, IndustryType it) + { + assert(this->fields[row].columns[col].type == CFT_EMPTY); + this->fields[row].columns[col].MakeIndustry(it); + if (col == 0) { + this->fields[row].ConnectIndustryProduced(col); + } else { + this->fields[row].ConnectIndustryAccepted(col); + } + } + + /** + * Notify smallmap that new displayed industries have been selected (in #_displayed_industries). + */ + void NotifySmallmap() + { + if (!this->IsWidgetLowered(WID_IC_NOTIFY)) return; + + /* Only notify the smallmap window if it exists. In particular, do not + * bring it to the front to prevent messing up any nice layout of the user. */ + InvalidateWindowClassesData(WC_SMALLMAP, 0); + } + + /** + * Compute what and where to display for industry type \a it. + * @param it Industry type to display. + */ + void ComputeIndustryDisplay(IndustryType it) + { + this->GetWidget(WID_IC_CAPTION)->widget_data = STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION; + this->ind_cargo = it; + _displayed_industries = 1ULL << it; + + this->fields.Clear(); + CargoesRow *row = this->fields.Append(); + row->columns[0].MakeHeader(STR_INDUSTRY_CARGOES_PRODUCERS); + row->columns[1].MakeEmpty(CFT_SMALL_EMPTY); + row->columns[2].MakeEmpty(CFT_SMALL_EMPTY); + row->columns[3].MakeEmpty(CFT_SMALL_EMPTY); + row->columns[4].MakeHeader(STR_INDUSTRY_CARGOES_CUSTOMERS); + + const IndustrySpec *central_sp = GetIndustrySpec(it); + bool houses_supply = HousesCanSupply(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo)); + bool houses_accept = HousesCanAccept(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)); + /* Make a field consisting of two cargo columns. */ + int num_supp = CountMatchingProducingIndustries(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo)) + houses_supply; + int num_cust = CountMatchingAcceptingIndustries(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)) + houses_accept; + int num_indrows = max(3, max(num_supp, num_cust)); // One is needed for the 'it' industry, and 2 for the cargo labels. + for (int i = 0; i < num_indrows; i++) { + CargoesRow *row = this->fields.Append(); + row->columns[0].MakeEmpty(CFT_EMPTY); + row->columns[1].MakeCargo(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo)); + row->columns[2].MakeEmpty(CFT_EMPTY); + row->columns[3].MakeCargo(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)); + row->columns[4].MakeEmpty(CFT_EMPTY); + } + /* Add central industry. */ + int central_row = 1 + num_indrows / 2; + this->fields[central_row].columns[2].MakeIndustry(it); + this->fields[central_row].ConnectIndustryProduced(2); + this->fields[central_row].ConnectIndustryAccepted(2); + + /* Add cargo labels. */ + this->fields[central_row - 1].MakeCargoLabel(2, true); + this->fields[central_row + 1].MakeCargoLabel(2, false); + + /* Add suppliers and customers of the 'it' industry. */ + int supp_count = 0; + int cust_count = 0; + for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { + const IndustrySpec *indsp = GetIndustrySpec(it); + if (!indsp->enabled) continue; + + if (HasCommonValidCargo(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo), indsp->produced_cargo, lengthof(indsp->produced_cargo))) { + this->PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, it); + SetBit(_displayed_industries, it); + supp_count++; + } + if (HasCommonValidCargo(central_sp->produced_cargo, lengthof(central_sp->produced_cargo), indsp->accepts_cargo, lengthof(indsp->accepts_cargo))) { + this->PlaceIndustry(1 + cust_count * num_indrows / num_cust, 4, it); + SetBit(_displayed_industries, it); + cust_count++; + } + } + if (houses_supply) { + this->PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, NUM_INDUSTRYTYPES); + supp_count++; + } + if (houses_accept) { + this->PlaceIndustry(1 + cust_count * num_indrows / num_cust, 4, NUM_INDUSTRYTYPES); + cust_count++; + } + + this->ShortenCargoColumn(1, 1, num_indrows); + this->ShortenCargoColumn(3, 1, num_indrows); + const NWidgetBase *nwp = this->GetWidget(WID_IC_PANEL); + this->vscroll->SetCount(CeilDiv(WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + CargoesField::small_height + num_indrows * CargoesField::normal_height, nwp->resize_y)); + this->SetDirty(); + this->NotifySmallmap(); + } + + /** + * Compute what and where to display for cargo id \a cid. + * @param cid Cargo id to display. + */ + void ComputeCargoDisplay(CargoID cid) + { + this->GetWidget(WID_IC_CAPTION)->widget_data = STR_INDUSTRY_CARGOES_CARGO_CAPTION; + this->ind_cargo = cid + NUM_INDUSTRYTYPES; + _displayed_industries = 0; + + this->fields.Clear(); + CargoesRow *row = this->fields.Append(); + row->columns[0].MakeHeader(STR_INDUSTRY_CARGOES_PRODUCERS); + row->columns[1].MakeEmpty(CFT_SMALL_EMPTY); + row->columns[2].MakeHeader(STR_INDUSTRY_CARGOES_CUSTOMERS); + row->columns[3].MakeEmpty(CFT_SMALL_EMPTY); + row->columns[4].MakeEmpty(CFT_SMALL_EMPTY); + + bool houses_supply = HousesCanSupply(&cid, 1); + bool houses_accept = HousesCanAccept(&cid, 1); + int num_supp = CountMatchingProducingIndustries(&cid, 1) + houses_supply + 1; // Ensure room for the cargo label. + int num_cust = CountMatchingAcceptingIndustries(&cid, 1) + houses_accept; + int num_indrows = max(num_supp, num_cust); + for (int i = 0; i < num_indrows; i++) { + CargoesRow *row = this->fields.Append(); + row->columns[0].MakeEmpty(CFT_EMPTY); + row->columns[1].MakeCargo(&cid, 1); + row->columns[2].MakeEmpty(CFT_EMPTY); + row->columns[3].MakeEmpty(CFT_EMPTY); + row->columns[4].MakeEmpty(CFT_EMPTY); + } + + this->fields[num_indrows].MakeCargoLabel(0, false); // Add cargo labels at the left bottom. + + /* Add suppliers and customers of the cargo. */ + int supp_count = 0; + int cust_count = 0; + for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { + const IndustrySpec *indsp = GetIndustrySpec(it); + if (!indsp->enabled) continue; + + if (HasCommonValidCargo(&cid, 1, indsp->produced_cargo, lengthof(indsp->produced_cargo))) { + this->PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, it); + SetBit(_displayed_industries, it); + supp_count++; + } + if (HasCommonValidCargo(&cid, 1, indsp->accepts_cargo, lengthof(indsp->accepts_cargo))) { + this->PlaceIndustry(1 + cust_count * num_indrows / num_cust, 2, it); + SetBit(_displayed_industries, it); + cust_count++; + } + } + if (houses_supply) { + this->PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, NUM_INDUSTRYTYPES); + supp_count++; + } + if (houses_accept) { + this->PlaceIndustry(1 + cust_count * num_indrows / num_cust, 2, NUM_INDUSTRYTYPES); + cust_count++; + } + + this->ShortenCargoColumn(1, 1, num_indrows); + const NWidgetBase *nwp = this->GetWidget(WID_IC_PANEL); + this->vscroll->SetCount(CeilDiv(WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + CargoesField::small_height + num_indrows * CargoesField::normal_height, nwp->resize_y)); + this->SetDirty(); + this->NotifySmallmap(); + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * - data = 0 .. NUM_INDUSTRYTYPES - 1: Display the chain around the given industry. + * - data = NUM_INDUSTRYTYPES: Stop sending updates to the smallmap window. + * @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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + if (data == NUM_INDUSTRYTYPES) { + if (this->IsWidgetLowered(WID_IC_NOTIFY)) { + this->RaiseWidget(WID_IC_NOTIFY); + this->SetWidgetDirty(WID_IC_NOTIFY); + } + return; + } + + assert(data >= 0 && data < NUM_INDUSTRYTYPES); + this->ComputeIndustryDisplay(data); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_IC_PANEL) return; + + DrawPixelInfo tmp_dpi, *old_dpi; + int width = r.right - r.left + 1; + int height = r.bottom - r.top + 1 - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM; + if (!FillDrawPixelInfo(&tmp_dpi, r.left + WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, width, height)) return; + old_dpi = _cur_dpi; + _cur_dpi = &tmp_dpi; + + int left_pos = WD_FRAMERECT_LEFT; + if (this->ind_cargo >= NUM_INDUSTRYTYPES) left_pos += (CargoesField::industry_width + CargoesField::CARGO_FIELD_WIDTH) / 2; + int last_column = (this->ind_cargo < NUM_INDUSTRYTYPES) ? 4 : 2; + + const NWidgetBase *nwp = this->GetWidget(WID_IC_PANEL); + int vpos = -this->vscroll->GetPosition() * nwp->resize_y; + for (uint i = 0; i < this->fields.Length(); i++) { + int row_height = (i == 0) ? CargoesField::small_height : CargoesField::normal_height; + if (vpos + row_height >= 0) { + int xpos = left_pos; + int col, dir; + if (_current_text_dir == TD_RTL) { + col = last_column; + dir = -1; + } else { + col = 0; + dir = 1; + } + while (col >= 0 && col <= last_column) { + this->fields[i].columns[col].Draw(xpos, vpos); + xpos += (col & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width; + col += dir; + } + } + vpos += row_height; + if (vpos >= height) break; + } + + _cur_dpi = old_dpi; + } + + /** + * Calculate in which field was clicked, and within the field, at what position. + * @param pt Clicked position in the #WID_IC_PANEL widget. + * @param fieldxy If \c true is returned, field x/y coordinate of \a pt. + * @param xy If \c true is returned, x/y coordinate with in the field. + * @return Clicked at a valid position. + */ + bool CalculatePositionInWidget(Point pt, Point *fieldxy, Point *xy) + { + const NWidgetBase *nw = this->GetWidget(WID_IC_PANEL); + pt.x -= nw->pos_x; + pt.y -= nw->pos_y; + + int vpos = WD_FRAMERECT_TOP + CargoesField::small_height - this->vscroll->GetPosition() * nw->resize_y; + if (pt.y < vpos) return false; + + int row = (pt.y - vpos) / CargoesField::normal_height; // row is relative to row 1. + if (row + 1 >= (int)this->fields.Length()) return false; + vpos = pt.y - vpos - row * CargoesField::normal_height; // Position in the row + 1 field + row++; // rebase row to match index of this->fields. + + int xpos = 2 * WD_FRAMERECT_LEFT + ((this->ind_cargo < NUM_INDUSTRYTYPES) ? 0 : (CargoesField::industry_width + CargoesField::CARGO_FIELD_WIDTH) / 2); + if (pt.x < xpos) return false; + int column; + for (column = 0; column <= 5; column++) { + int width = (column & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width; + if (pt.x < xpos + width) break; + xpos += width; + } + int num_columns = (this->ind_cargo < NUM_INDUSTRYTYPES) ? 4 : 2; + if (column > num_columns) return false; + xpos = pt.x - xpos; + + /* Return both positions, compensating for RTL languages (which works due to the equal symmetry in both displays). */ + fieldxy->y = row; + xy->y = vpos; + if (_current_text_dir == TD_RTL) { + fieldxy->x = num_columns - column; + xy->x = ((column & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width) - xpos; + } else { + fieldxy->x = column; + xy->x = xpos; + } + return true; + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_IC_PANEL: { + Point fieldxy, xy; + if (!CalculatePositionInWidget(pt, &fieldxy, &xy)) return; + + const CargoesField *fld = this->fields[fieldxy.y].columns + fieldxy.x; + switch (fld->type) { + case CFT_INDUSTRY: + if (fld->u.industry.ind_type < NUM_INDUSTRYTYPES) this->ComputeIndustryDisplay(fld->u.industry.ind_type); + break; + + case CFT_CARGO: { + CargoesField *lft = (fieldxy.x > 0) ? this->fields[fieldxy.y].columns + fieldxy.x - 1 : NULL; + CargoesField *rgt = (fieldxy.x < 4) ? this->fields[fieldxy.y].columns + fieldxy.x + 1 : NULL; + CargoID cid = fld->CargoClickedAt(lft, rgt, xy); + if (cid != INVALID_CARGO) this->ComputeCargoDisplay(cid); + break; + } + + case CFT_CARGO_LABEL: { + CargoID cid = fld->CargoLabelClickedAt(xy); + if (cid != INVALID_CARGO) this->ComputeCargoDisplay(cid); + break; + } + + default: + break; + } + break; + } + + case WID_IC_NOTIFY: + this->ToggleWidgetLoweredState(WID_IC_NOTIFY); + this->SetWidgetDirty(WID_IC_NOTIFY); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + + if (this->IsWidgetLowered(WID_IC_NOTIFY)) { + if (FindWindowByClass(WC_SMALLMAP) == NULL) ShowSmallMap(); + this->NotifySmallmap(); + } + break; + + case WID_IC_CARGO_DROPDOWN: { + DropDownList *lst = new DropDownList; + const CargoSpec *cs; + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + *lst->Append() = new DropDownListStringItem(cs->name, cs->Index(), false); + } + if (lst->Length() == 0) { + delete lst; + break; + } + int selected = (this->ind_cargo >= NUM_INDUSTRYTYPES) ? (int)(this->ind_cargo - NUM_INDUSTRYTYPES) : -1; + ShowDropDownList(this, lst, selected, WID_IC_CARGO_DROPDOWN, 0, true); + break; + } + + case WID_IC_IND_DROPDOWN: { + DropDownList *lst = new DropDownList; + for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) { + IndustryType ind = _sorted_industry_types[i]; + const IndustrySpec *indsp = GetIndustrySpec(ind); + if (!indsp->enabled) continue; + *lst->Append() = new DropDownListStringItem(indsp->name, ind, false); + } + if (lst->Length() == 0) { + delete lst; + break; + } + int selected = (this->ind_cargo < NUM_INDUSTRYTYPES) ? (int)this->ind_cargo : -1; + ShowDropDownList(this, lst, selected, WID_IC_IND_DROPDOWN, 0, true); + break; + } + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + if (index < 0) return; + + switch (widget) { + case WID_IC_CARGO_DROPDOWN: + this->ComputeCargoDisplay(index); + break; + + case WID_IC_IND_DROPDOWN: + this->ComputeIndustryDisplay(index); + break; + } + } + + virtual void OnHover(Point pt, int widget) + { + if (widget != WID_IC_PANEL) return; + + Point fieldxy, xy; + if (!CalculatePositionInWidget(pt, &fieldxy, &xy)) return; + + const CargoesField *fld = this->fields[fieldxy.y].columns + fieldxy.x; + CargoID cid = INVALID_CARGO; + switch (fld->type) { + case CFT_CARGO: { + CargoesField *lft = (fieldxy.x > 0) ? this->fields[fieldxy.y].columns + fieldxy.x - 1 : NULL; + CargoesField *rgt = (fieldxy.x < 4) ? this->fields[fieldxy.y].columns + fieldxy.x + 1 : NULL; + cid = fld->CargoClickedAt(lft, rgt, xy); + break; + } + + case CFT_CARGO_LABEL: { + cid = fld->CargoLabelClickedAt(xy); + break; + } + + case CFT_INDUSTRY: + if (fld->u.industry.ind_type < NUM_INDUSTRYTYPES && (this->ind_cargo >= NUM_INDUSTRYTYPES || fieldxy.x != 2)) { + GuiShowTooltips(this, STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP, 0, NULL, TCC_HOVER); + } + return; + + default: + break; + } + if (cid != INVALID_CARGO && (this->ind_cargo < NUM_INDUSTRYTYPES || cid != this->ind_cargo - NUM_INDUSTRYTYPES)) { + const CargoSpec *csp = CargoSpec::Get(cid); + uint64 params[5]; + params[0] = csp->name; + GuiShowTooltips(this, STR_INDUSTRY_CARGOES_CARGO_TOOLTIP, 1, params, TCC_HOVER); + } + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_IC_PANEL); + } +}; + +const int IndustryCargoesWindow::HOR_TEXT_PADDING = 5; ///< Horizontal padding around the industry type text. +const int IndustryCargoesWindow::VERT_TEXT_PADDING = 5; ///< Vertical padding around the industry type text. + +/** + * Open the industry and cargoes window. + * @param id Industry type to display, \c NUM_INDUSTRYTYPES selects a default industry type. + */ +static void ShowIndustryCargoesWindow(IndustryType id) +{ + if (id >= NUM_INDUSTRYTYPES) { + for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) { + const IndustrySpec *indsp = GetIndustrySpec(_sorted_industry_types[i]); + if (indsp->enabled) { + id = _sorted_industry_types[i]; + break; + } + } + if (id >= NUM_INDUSTRYTYPES) return; + } + + Window *w = BringWindowToFrontById(WC_INDUSTRY_CARGOES, 0); + if (w != NULL) { + w->InvalidateData(id); + return; + } + new IndustryCargoesWindow(id); +} + +/** Open the industry and cargoes window with an industry. */ +void ShowIndustryCargoesWindow() +{ + ShowIndustryCargoesWindow(NUM_INDUSTRYTYPES); +} diff --git a/src/lang/english.txt.orig b/src/lang/english.txt.orig new file mode 100644 index 0000000000..fb21d3fded --- /dev/null +++ b/src/lang/english.txt.orig @@ -0,0 +1,4887 @@ +##name English (UK) +##ownname English (UK) +##isocode en_GB +##plural 0 +##textdir ltr +##digitsep , +##digitsepcur , +##decimalsep . +##winlangid 0x0809 +##grflangid 0x01 + + +# $Id$ + +# 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 . + + +##id 0x0000 +STR_NULL : +STR_EMPTY : +STR_UNDEFINED :(undefined string) +STR_JUST_NOTHING :Nothing + +# Cargo related strings +# Plural cargo name +STR_CARGO_PLURAL_NOTHING : +STR_CARGO_PLURAL_PASSENGERS :Passengers +STR_CARGO_PLURAL_COAL :Coal +STR_CARGO_PLURAL_MAIL :Mail +STR_CARGO_PLURAL_OIL :Oil +STR_CARGO_PLURAL_LIVESTOCK :Livestock +STR_CARGO_PLURAL_GOODS :Goods +STR_CARGO_PLURAL_GRAIN :Grain +STR_CARGO_PLURAL_WOOD :Wood +STR_CARGO_PLURAL_IRON_ORE :Iron Ore +STR_CARGO_PLURAL_STEEL :Steel +STR_CARGO_PLURAL_VALUABLES :Valuables +STR_CARGO_PLURAL_COPPER_ORE :Copper Ore +STR_CARGO_PLURAL_MAIZE :Maize +STR_CARGO_PLURAL_FRUIT :Fruit +STR_CARGO_PLURAL_DIAMONDS :Diamonds +STR_CARGO_PLURAL_FOOD :Food +STR_CARGO_PLURAL_PAPER :Paper +STR_CARGO_PLURAL_GOLD :Gold +STR_CARGO_PLURAL_WATER :Water +STR_CARGO_PLURAL_WHEAT :Wheat +STR_CARGO_PLURAL_RUBBER :Rubber +STR_CARGO_PLURAL_SUGAR :Sugar +STR_CARGO_PLURAL_TOYS :Toys +STR_CARGO_PLURAL_CANDY :Sweets +STR_CARGO_PLURAL_COLA :Cola +STR_CARGO_PLURAL_COTTON_CANDY :Candyfloss +STR_CARGO_PLURAL_BUBBLES :Bubbles +STR_CARGO_PLURAL_TOFFEE :Toffee +STR_CARGO_PLURAL_BATTERIES :Batteries +STR_CARGO_PLURAL_PLASTIC :Plastic +STR_CARGO_PLURAL_FIZZY_DRINKS :Fizzy Drinks + +# Singular cargo name +STR_CARGO_SINGULAR_NOTHING : +STR_CARGO_SINGULAR_PASSENGER :Passenger +STR_CARGO_SINGULAR_COAL :Coal +STR_CARGO_SINGULAR_MAIL :Mail +STR_CARGO_SINGULAR_OIL :Oil +STR_CARGO_SINGULAR_LIVESTOCK :Livestock +STR_CARGO_SINGULAR_GOODS :Goods +STR_CARGO_SINGULAR_GRAIN :Grain +STR_CARGO_SINGULAR_WOOD :Wood +STR_CARGO_SINGULAR_IRON_ORE :Iron Ore +STR_CARGO_SINGULAR_STEEL :Steel +STR_CARGO_SINGULAR_VALUABLES :Valuables +STR_CARGO_SINGULAR_COPPER_ORE :Copper Ore +STR_CARGO_SINGULAR_MAIZE :Maize +STR_CARGO_SINGULAR_FRUIT :Fruit +STR_CARGO_SINGULAR_DIAMOND :Diamond +STR_CARGO_SINGULAR_FOOD :Food +STR_CARGO_SINGULAR_PAPER :Paper +STR_CARGO_SINGULAR_GOLD :Gold +STR_CARGO_SINGULAR_WATER :Water +STR_CARGO_SINGULAR_WHEAT :Wheat +STR_CARGO_SINGULAR_RUBBER :Rubber +STR_CARGO_SINGULAR_SUGAR :Sugar +STR_CARGO_SINGULAR_TOY :Toy +STR_CARGO_SINGULAR_CANDY :Sweet +STR_CARGO_SINGULAR_COLA :Cola +STR_CARGO_SINGULAR_COTTON_CANDY :Candyfloss +STR_CARGO_SINGULAR_BUBBLE :Bubble +STR_CARGO_SINGULAR_TOFFEE :Toffee +STR_CARGO_SINGULAR_BATTERY :Battery +STR_CARGO_SINGULAR_PLASTIC :Plastic +STR_CARGO_SINGULAR_FIZZY_DRINK :Fizzy Drink + +# Quantity of cargo +STR_QUANTITY_NOTHING : +STR_QUANTITY_PASSENGERS :{COMMA} passenger{P "" s} +STR_QUANTITY_COAL :{WEIGHT_LONG} of coal +STR_QUANTITY_MAIL :{COMMA} bag{P "" s} of mail +STR_QUANTITY_OIL :{VOLUME_LONG} of oil +STR_QUANTITY_LIVESTOCK :{COMMA} item{P "" s} of livestock +STR_QUANTITY_GOODS :{COMMA} crate{P "" s} of goods +STR_QUANTITY_GRAIN :{WEIGHT_LONG} of grain +STR_QUANTITY_WOOD :{WEIGHT_LONG} of wood +STR_QUANTITY_IRON_ORE :{WEIGHT_LONG} of iron ore +STR_QUANTITY_STEEL :{WEIGHT_LONG} of steel +STR_QUANTITY_VALUABLES :{COMMA} bag{P "" s} of valuables +STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} of copper ore +STR_QUANTITY_MAIZE :{WEIGHT_LONG} of maize +STR_QUANTITY_FRUIT :{WEIGHT_LONG} of fruit +STR_QUANTITY_DIAMONDS :{COMMA} bag{P "" s} of diamonds +STR_QUANTITY_FOOD :{WEIGHT_LONG} of food +STR_QUANTITY_PAPER :{WEIGHT_LONG} of paper +STR_QUANTITY_GOLD :{COMMA} bag{P "" s} of gold +STR_QUANTITY_WATER :{VOLUME_LONG} of water +STR_QUANTITY_WHEAT :{WEIGHT_LONG} of wheat +STR_QUANTITY_RUBBER :{VOLUME_LONG} of rubber +STR_QUANTITY_SUGAR :{WEIGHT_LONG} of sugar +STR_QUANTITY_TOYS :{COMMA} toy{P "" s} +STR_QUANTITY_SWEETS :{COMMA} bag{P "" s} of sweets +STR_QUANTITY_COLA :{VOLUME_LONG} of cola +STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} of candyfloss +STR_QUANTITY_BUBBLES :{COMMA} bubble{P "" s} +STR_QUANTITY_TOFFEE :{WEIGHT_LONG} of toffee +STR_QUANTITY_BATTERIES :{COMMA} batter{P y ies} +STR_QUANTITY_PLASTIC :{VOLUME_LONG} of plastic +STR_QUANTITY_FIZZY_DRINKS :{COMMA} fizzy drink{P "" s} +STR_QUANTITY_N_A :N/A + +# Two letter abbreviation of cargo name +STR_ABBREV_NOTHING : +STR_ABBREV_PASSENGERS :{TINY_FONT}PS +STR_ABBREV_COAL :{TINY_FONT}CL +STR_ABBREV_MAIL :{TINY_FONT}ML +STR_ABBREV_OIL :{TINY_FONT}OL +STR_ABBREV_LIVESTOCK :{TINY_FONT}LV +STR_ABBREV_GOODS :{TINY_FONT}GD +STR_ABBREV_GRAIN :{TINY_FONT}GR +STR_ABBREV_WOOD :{TINY_FONT}WD +STR_ABBREV_IRON_ORE :{TINY_FONT}OR +STR_ABBREV_STEEL :{TINY_FONT}ST +STR_ABBREV_VALUABLES :{TINY_FONT}VL +STR_ABBREV_COPPER_ORE :{TINY_FONT}CO +STR_ABBREV_MAIZE :{TINY_FONT}MZ +STR_ABBREV_FRUIT :{TINY_FONT}FT +STR_ABBREV_DIAMONDS :{TINY_FONT}DM +STR_ABBREV_FOOD :{TINY_FONT}FD +STR_ABBREV_PAPER :{TINY_FONT}PR +STR_ABBREV_GOLD :{TINY_FONT}GD +STR_ABBREV_WATER :{TINY_FONT}WR +STR_ABBREV_WHEAT :{TINY_FONT}WH +STR_ABBREV_RUBBER :{TINY_FONT}RB +STR_ABBREV_SUGAR :{TINY_FONT}SG +STR_ABBREV_TOYS :{TINY_FONT}TY +STR_ABBREV_SWEETS :{TINY_FONT}SW +STR_ABBREV_COLA :{TINY_FONT}CL +STR_ABBREV_CANDYFLOSS :{TINY_FONT}CF +STR_ABBREV_BUBBLES :{TINY_FONT}BU +STR_ABBREV_TOFFEE :{TINY_FONT}TF +STR_ABBREV_BATTERIES :{TINY_FONT}BA +STR_ABBREV_PLASTIC :{TINY_FONT}PL +STR_ABBREV_FIZZY_DRINKS :{TINY_FONT}FZ +STR_ABBREV_NONE :{TINY_FONT}NO +STR_ABBREV_ALL :{TINY_FONT}ALL + +# 'Mode' of transport for cargoes +STR_PASSENGERS :{COMMA} passenger{P "" s} +STR_BAGS :{COMMA} bag{P "" s} +STR_TONS :{COMMA} tonne{P "" s} +STR_LITERS :{COMMA} litre{P "" s} +STR_ITEMS :{COMMA} item{P "" s} +STR_CRATES :{COMMA} crate{P "" s} + +# Colours, do not shuffle +STR_COLOUR_DARK_BLUE :Dark Blue +STR_COLOUR_PALE_GREEN :Pale Green +STR_COLOUR_PINK :Pink +STR_COLOUR_YELLOW :Yellow +STR_COLOUR_RED :Red +STR_COLOUR_LIGHT_BLUE :Light Blue +STR_COLOUR_GREEN :Green +STR_COLOUR_DARK_GREEN :Dark Green +STR_COLOUR_BLUE :Blue +STR_COLOUR_CREAM :Cream +STR_COLOUR_MAUVE :Mauve +STR_COLOUR_PURPLE :Purple +STR_COLOUR_ORANGE :Orange +STR_COLOUR_BROWN :Brown +STR_COLOUR_GREY :Grey +STR_COLOUR_WHITE :White + +# Units used in OpenTTD +STR_UNITS_VELOCITY_IMPERIAL :{COMMA} mph +STR_UNITS_VELOCITY_METRIC :{COMMA} km/h +STR_UNITS_VELOCITY_SI :{COMMA} m/s + +STR_UNITS_POWER_IMPERIAL :{COMMA}hp +STR_UNITS_POWER_METRIC :{COMMA}hp +STR_UNITS_POWER_SI :{COMMA}kW + +STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}t +STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}t +STR_UNITS_WEIGHT_SHORT_SI :{COMMA}kg + +STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA} ton{P "" s} +STR_UNITS_WEIGHT_LONG_METRIC :{COMMA} tonne{P "" s} +STR_UNITS_WEIGHT_LONG_SI :{COMMA} kg + +STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}gal +STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}l +STR_UNITS_VOLUME_SHORT_SI :{COMMA}m³ + +STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA} gallon{P "" s} +STR_UNITS_VOLUME_LONG_METRIC :{COMMA} litre{P "" s} +STR_UNITS_VOLUME_LONG_SI :{COMMA} m³ + +STR_UNITS_FORCE_IMPERIAL :{COMMA} lbf +STR_UNITS_FORCE_METRIC :{COMMA} kgf +STR_UNITS_FORCE_SI :{COMMA} kN + +STR_UNITS_HEIGHT_IMPERIAL :{COMMA} ft +STR_UNITS_HEIGHT_METRIC :{COMMA} m +STR_UNITS_HEIGHT_SI :{COMMA} m + +# Common window strings +STR_LIST_FILTER_TITLE :{BLACK}Filter string: +STR_LIST_FILTER_OSKTITLE :{BLACK}Enter filter string +STR_LIST_FILTER_TOOLTIP :{BLACK}Enter a keyword to filter the list for + +STR_TOOLTIP_GROUP_ORDER :{BLACK}Select grouping order +STR_TOOLTIP_SORT_ORDER :{BLACK}Select sorting order (descending/ascending) +STR_TOOLTIP_SORT_CRITERIA :{BLACK}Select sorting criteria +STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Select filtering criteria +STR_BUTTON_SORT_BY :{BLACK}Sort by +STR_BUTTON_LOCATION :{BLACK}Location +STR_BUTTON_RENAME :{BLACK}Rename + +STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Close window +STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Window title - drag this to move window +STR_TOOLTIP_SHADE :{BLACK}Shade window - only show the title bar +STR_TOOLTIP_DEBUG :{BLACK}Show NewGRF debug information +STR_TOOLTIP_DEFSIZE :{BLACK}Resize window to default size. Ctrl+Click to store current size as default +STR_TOOLTIP_STICKY :{BLACK}Mark this window as uncloseable by the 'Close All Windows' key. Ctrl+Click to also save state as default +STR_TOOLTIP_RESIZE :{BLACK}Click and drag to resize this window +STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Toggle large/small window size +STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}Scroll bar - scrolls list up/down +STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST :{BLACK}Scroll bar - scrolls list left/right +STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC :{BLACK}Demolish buildings etc. on a square of land. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate + +# Query window +STR_BUTTON_DEFAULT :{BLACK}Default +STR_BUTTON_CANCEL :{BLACK}Cancel +STR_BUTTON_OK :{BLACK}OK + +# On screen keyboard window +STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . +STR_OSK_KEYBOARD_LAYOUT_CAPS :~!@#$%^&*()_+|QWERTYUIOP{{}}ASDFGHJKL:" ZXCVBNM<>? . + +# Measurement tooltip +STR_MEASURE_LENGTH :{BLACK}Length: {NUM} +STR_MEASURE_AREA :{BLACK}Area: {NUM} x {NUM} +STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}Length: {NUM}{}Height difference: {HEIGHT} +STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}Area: {NUM} x {NUM}{}Height difference: {HEIGHT} + + +# These are used in buttons +STR_SORT_BY_CAPTION_NAME :{BLACK}Name +STR_SORT_BY_CAPTION_DATE :{BLACK}Date +# These are used in dropdowns +STR_SORT_BY_NAME :Name +STR_SORT_BY_PRODUCTION :Production +STR_SORT_BY_TYPE :Type +STR_SORT_BY_TRANSPORTED :Transported +STR_SORT_BY_NUMBER :Number +STR_SORT_BY_PROFIT_LAST_YEAR :Profit last year +STR_SORT_BY_PROFIT_THIS_YEAR :Profit this year +STR_SORT_BY_AGE :Age +STR_SORT_BY_RELIABILITY :Reliability +STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :Total capacity per cargo type +STR_SORT_BY_MAX_SPEED :Maximum speed +STR_SORT_BY_MODEL :Model +STR_SORT_BY_VALUE :Value +STR_SORT_BY_LENGTH :Length +STR_SORT_BY_LIFE_TIME :Remaining lifetime +STR_SORT_BY_TIMETABLE_DELAY :Timetable delay +STR_SORT_BY_FACILITY :Station type +STR_SORT_BY_WAITING_TOTAL :Total waiting cargo +STR_SORT_BY_WAITING_AVAILABLE :Available waiting cargo +STR_SORT_BY_RATING_MAX :Highest cargo rating +STR_SORT_BY_RATING_MIN :Lowest cargo rating +STR_SORT_BY_ENGINE_ID :EngineID (classic sort) +STR_SORT_BY_COST :Cost +STR_SORT_BY_POWER :Power +STR_SORT_BY_TRACTIVE_EFFORT :Tractive effort +STR_SORT_BY_INTRO_DATE :Introduction date +STR_SORT_BY_RUNNING_COST :Running cost +STR_SORT_BY_POWER_VS_RUNNING_COST :Power/Running cost +STR_SORT_BY_CARGO_CAPACITY :Cargo capacity +STR_SORT_BY_RANGE :Range +STR_SORT_BY_POPULATION :Population +STR_SORT_BY_RATING :Rating + +# Tooltips for the main toolbar +STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Pause game +STR_TOOLBAR_TOOLTIP_FORWARD :{BLACK}Fast forward the game +STR_TOOLBAR_TOOLTIP_OPTIONS :{BLACK}Options +STR_TOOLBAR_TOOLTIP_SAVE_GAME_ABANDON_GAME :{BLACK}Save game, abandon game, exit +STR_TOOLBAR_TOOLTIP_DISPLAY_MAP :{BLACK}Display map, extra viewport or list of signs +STR_TOOLBAR_TOOLTIP_DISPLAY_TOWN_DIRECTORY :{BLACK}Display town directory +STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Display subsidies +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Display list of company's stations +STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Display company finances information +STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Display general company information +STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK :{BLACK}Display story book +STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Display goal list +STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Display graphs +STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Display company league table +STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Fund construction of new industry or list all industries +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Display list of company's trains. Ctrl+Click toggles opening the group/vehicle list +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Display list of company's road vehicles. Ctrl+Click toggles opening the group/vehicle list +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Display list of company's ships. Ctrl+Click toggles opening the group/vehicle list +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Display list of company's aircraft. Ctrl+Click toggles opening the group/vehicle list +STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Zoom the view in +STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Zoom the view out +STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Build railway track +STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Build roads +STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Build ship docks +STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Build airports +STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Open the landscaping toolbar to raise/lower land, plant trees, etc. +STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Show sound/music window +STR_TOOLBAR_TOOLTIP_SHOW_LAST_MESSAGE_NEWS :{BLACK}Show last message/news report, show message options +STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION :{BLACK}Land area information, console, script debug, screenshots, about OpenTTD +STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR :{BLACK}Switch toolbars + +# Extra tooltips for the scenario editor toolbar +STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Save scenario, load scenario, abandon scenario editor, exit +STR_SCENEDIT_TOOLBAR_OPENTTD :{YELLOW}OpenTTD +STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR :{YELLOW}Scenario Editor +STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD :{BLACK}Move the starting date backward 1 year +STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD :{BLACK}Move the starting date forward 1 year +STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE :{BLACK}Click to enter the starting year +STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Display map, town directory +STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Landscape generation +STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Town generation +STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Industry generation +STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Road construction +STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plant trees. Shift toggles building/showing cost estimate +STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Place sign +STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Place object. Shift toggles building/showing cost estimate + +############ range for SE file menu starts +STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :Save scenario +STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO :Load scenario +STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP :Save heightmap +STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP :Load heightmap +STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Abandon scenario editor +STR_SCENEDIT_FILE_MENU_SEPARATOR : +STR_SCENEDIT_FILE_MENU_QUIT :Exit +############ range for SE file menu starts + +############ range for settings menu starts +STR_SETTINGS_MENU_GAME_OPTIONS :Game options +STR_SETTINGS_MENU_CONFIG_SETTINGS :Advanced settings +STR_SETTINGS_MENU_SCRIPT_SETTINGS :AI/Game script settings +STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF settings +STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Transparency options +STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Town names displayed +STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Station names displayed +STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Waypoint names displayed +STR_SETTINGS_MENU_SIGNS_DISPLAYED :Signs displayed +STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Competitor signs and names displayed +STR_SETTINGS_MENU_FULL_ANIMATION :Full animation +STR_SETTINGS_MENU_FULL_DETAIL :Full detail +STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :Transparent buildings +STR_SETTINGS_MENU_TRANSPARENT_SIGNS :Transparent signs +############ range ends here + +############ range for file menu starts +STR_FILE_MENU_SAVE_GAME :Save game +STR_FILE_MENU_LOAD_GAME :Load game +STR_FILE_MENU_QUIT_GAME :Abandon game +STR_FILE_MENU_SEPARATOR : +STR_FILE_MENU_EXIT :Exit +############ range ends here + +# map menu +STR_MAP_MENU_MAP_OF_WORLD :Map of world +STR_MAP_MENU_EXTRA_VIEW_PORT :Extra viewport +STR_MAP_MENU_LINGRAPH_LEGEND :Cargo Flow Legend +STR_MAP_MENU_SIGN_LIST :Sign list + +############ range for town menu starts +STR_TOWN_MENU_TOWN_DIRECTORY :Town directory +STR_TOWN_MENU_FOUND_TOWN :Found town +############ range ends here + +############ range for subsidies menu starts +STR_SUBSIDIES_MENU_SUBSIDIES :Subsidies +############ range ends here + +############ range for graph menu starts +STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH :Operating profit graph +STR_GRAPH_MENU_INCOME_GRAPH :Income graph +STR_GRAPH_MENU_DELIVERED_CARGO_GRAPH :Delivered cargo graph +STR_GRAPH_MENU_PERFORMANCE_HISTORY_GRAPH :Performance history graph +STR_GRAPH_MENU_COMPANY_VALUE_GRAPH :Company value graph +STR_GRAPH_MENU_CARGO_PAYMENT_RATES :Cargo payment rates +############ range ends here + +############ range for company league menu starts +STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE :Company league table +STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING :Detailed performance rating +STR_GRAPH_MENU_HIGHSCORE :Highscore table +############ range ends here + +############ range for industry menu starts +STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY :Industry directory +STR_INDUSTRY_MENU_INDUSTRY_CHAIN :Industry chains +STR_INDUSTRY_MENU_FUND_NEW_INDUSTRY :Fund new industry +############ range ends here + +############ range for railway construction menu starts +STR_RAIL_MENU_RAILROAD_CONSTRUCTION :Railway construction +STR_RAIL_MENU_ELRAIL_CONSTRUCTION :Electrified railway construction +STR_RAIL_MENU_MONORAIL_CONSTRUCTION :Monorail construction +STR_RAIL_MENU_MAGLEV_CONSTRUCTION :Maglev construction +############ range ends here + +############ range for road construction menu starts +STR_ROAD_MENU_ROAD_CONSTRUCTION :Road construction +STR_ROAD_MENU_TRAM_CONSTRUCTION :Tramway construction +############ range ends here + +############ range for waterways construction menu starts +STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION :Waterways construction +############ range ends here + +############ range for airport construction menu starts +STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION :Airport construction +############ range ends here + +############ range for landscaping menu starts +STR_LANDSCAPING_MENU_LANDSCAPING :Landscaping +############ range ends here + +############ range for music menu starts +STR_TOOLBAR_SOUND_MUSIC :Sound/music +############ range ends here + +############ range for message menu starts +STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT :Last message/news report +STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Message history +############ range ends here + +############ range for about menu starts +STR_ABOUT_MENU_LAND_BLOCK_INFO :Land area information +STR_ABOUT_MENU_SEPARATOR : +STR_ABOUT_MENU_TOGGLE_CONSOLE :Toggle console +STR_ABOUT_MENU_AI_DEBUG :AI/Game script debug +STR_ABOUT_MENU_SCREENSHOT :Screenshot +STR_ABOUT_MENU_ZOOMIN_SCREENSHOT :Fully zoomed in screenshot +STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :Default zoom screenshot +STR_ABOUT_MENU_GIANT_SCREENSHOT :Whole map screenshot +STR_ABOUT_MENU_ABOUT_OPENTTD :About 'OpenTTD' +STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite aligner +STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Toggle bounding boxes +STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Toggle colouring of dirty blocks +############ range ends here + +############ range for days starts (also used for the place in the highscore window) +STR_ORDINAL_NUMBER_1ST :1st +STR_ORDINAL_NUMBER_2ND :2nd +STR_ORDINAL_NUMBER_3RD :3rd +STR_ORDINAL_NUMBER_4TH :4th +STR_ORDINAL_NUMBER_5TH :5th +STR_ORDINAL_NUMBER_6TH :6th +STR_ORDINAL_NUMBER_7TH :7th +STR_ORDINAL_NUMBER_8TH :8th +STR_ORDINAL_NUMBER_9TH :9th +STR_ORDINAL_NUMBER_10TH :10th +STR_ORDINAL_NUMBER_11TH :11th +STR_ORDINAL_NUMBER_12TH :12th +STR_ORDINAL_NUMBER_13TH :13th +STR_ORDINAL_NUMBER_14TH :14th +STR_ORDINAL_NUMBER_15TH :15th +STR_ORDINAL_NUMBER_16TH :16th +STR_ORDINAL_NUMBER_17TH :17th +STR_ORDINAL_NUMBER_18TH :18th +STR_ORDINAL_NUMBER_19TH :19th +STR_ORDINAL_NUMBER_20TH :20th +STR_ORDINAL_NUMBER_21ST :21st +STR_ORDINAL_NUMBER_22ND :22nd +STR_ORDINAL_NUMBER_23RD :23rd +STR_ORDINAL_NUMBER_24TH :24th +STR_ORDINAL_NUMBER_25TH :25th +STR_ORDINAL_NUMBER_26TH :26th +STR_ORDINAL_NUMBER_27TH :27th +STR_ORDINAL_NUMBER_28TH :28th +STR_ORDINAL_NUMBER_29TH :29th +STR_ORDINAL_NUMBER_30TH :30th +STR_ORDINAL_NUMBER_31ST :31st +############ range for days ends + +############ range for months starts +STR_MONTH_ABBREV_JAN :Jan +STR_MONTH_ABBREV_FEB :Feb +STR_MONTH_ABBREV_MAR :Mar +STR_MONTH_ABBREV_APR :Apr +STR_MONTH_ABBREV_MAY :May +STR_MONTH_ABBREV_JUN :Jun +STR_MONTH_ABBREV_JUL :Jul +STR_MONTH_ABBREV_AUG :Aug +STR_MONTH_ABBREV_SEP :Sep +STR_MONTH_ABBREV_OCT :Oct +STR_MONTH_ABBREV_NOV :Nov +STR_MONTH_ABBREV_DEC :Dec + +STR_MONTH_JAN :January +STR_MONTH_FEB :February +STR_MONTH_MAR :March +STR_MONTH_APR :April +STR_MONTH_MAY :May +STR_MONTH_JUN :June +STR_MONTH_JUL :July +STR_MONTH_AUG :August +STR_MONTH_SEP :September +STR_MONTH_OCT :October +STR_MONTH_NOV :November +STR_MONTH_DEC :December +############ range for months ends + +# Graph window +STR_GRAPH_KEY_BUTTON :{BLACK}Key +STR_GRAPH_KEY_TOOLTIP :{BLACK}Show key to graphs +STR_GRAPH_X_LABEL_MONTH :{TINY_FONT}{STRING}{} {STRING} +STR_GRAPH_X_LABEL_MONTH_YEAR :{TINY_FONT}{STRING}{} {STRING}{}{NUM} +STR_GRAPH_Y_LABEL :{TINY_FONT}{STRING2} +STR_GRAPH_Y_LABEL_NUMBER :{TINY_FONT}{COMMA} + +STR_GRAPH_OPERATING_PROFIT_CAPTION :{WHITE}Operating Profit Graph +STR_GRAPH_INCOME_CAPTION :{WHITE}Income Graph +STR_GRAPH_CARGO_DELIVERED_CAPTION :{WHITE}Units of cargo delivered +STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION :{WHITE}Company performance ratings (maximum rating=1000) +STR_GRAPH_COMPANY_VALUES_CAPTION :{WHITE}Company values + +STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Cargo Payment Rates +STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL :{TINY_FONT}{BLACK}Days in transit +STR_GRAPH_CARGO_PAYMENT_RATES_TITLE :{TINY_FONT}{BLACK}Payment for delivering 10 units (or 10,000 litres) of cargo a distance of 20 squares +STR_GRAPH_CARGO_ENABLE_ALL :{TINY_FONT}{BLACK}Enable all +STR_GRAPH_CARGO_DISABLE_ALL :{TINY_FONT}{BLACK}Disable all +STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL :{BLACK}Display all cargoes on the cargo payment rates graph +STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Display no cargoes on the cargo payment rates graph +STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Toggle graph for cargo type on/off +STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} + +STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Show detailed performance ratings + +# Graph key window +STR_GRAPH_KEY_CAPTION :{WHITE}Key to company graphs +STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Click here to toggle company's entry on graph on/off + +# Company league window +STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Company League Table +STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}' +STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Engineer +STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Traffic Manager +STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR :Transport Coordinator +STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :Route Supervisor +STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR :Director +STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE :Chief Executive +STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :Chairman +STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT :President +STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON :Tycoon + +# Performance detail window +STR_PERFORMANCE_DETAIL :{WHITE}Detailed performance rating +STR_PERFORMANCE_DETAIL_KEY :{BLACK}Detail +STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}({CURRENCY_SHORT}/{CURRENCY_SHORT}) +STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}({COMMA}/{COMMA}) +STR_PERFORMANCE_DETAIL_PERCENT :{WHITE}{NUM}% +STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP :{BLACK}View details about this company +############ Those following lines need to be in this order!! +STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}Vehicles: +STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}Stations: +STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}Min. profit: +STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}Min. income: +STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Max. income: +STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}Delivered: +STR_PERFORMANCE_DETAIL_CARGO :{BLACK}Cargo: +STR_PERFORMANCE_DETAIL_MONEY :{BLACK}Money: +STR_PERFORMANCE_DETAIL_LOAN :{BLACK}Loan: +STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}Total: +############ End of order list +STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP :{BLACK}Number of vehicles that turned a profit last year. This includes road vehicles, trains, ships and aircraft +STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP :{BLACK}Number of recently-serviced stations. Train stations, bus stops, airports and so on are counted separately even if they belong to the same station +STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP :{BLACK}The profit of the vehicle with the lowest income (only vehicles older than two years are considered) +STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP :{BLACK}Amount of cash made in the quarter with the lowest profit of the last 12 quarters +STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP :{BLACK}Amount of cash made in the quarter with the highest profit of the last 12 quarters +STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP :{BLACK}Units of cargo delivered in the last four quarters +STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP :{BLACK}Number of types of cargo delivered in the last quarter +STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP :{BLACK}Amount of money this company has in the bank +STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP :{BLACK}The amount of money this company has taken on loan +STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP :{BLACK}Total points out of possible points + +# Music window +STR_MUSIC_JAZZ_JUKEBOX_CAPTION :{WHITE}Jazz Jukebox +STR_MUSIC_PLAYLIST_ALL :{TINY_FONT}{BLACK}All +STR_MUSIC_PLAYLIST_OLD_STYLE :{TINY_FONT}{BLACK}Old Style +STR_MUSIC_PLAYLIST_NEW_STYLE :{TINY_FONT}{BLACK}New Style +STR_MUSIC_PLAYLIST_EZY_STREET :{TINY_FONT}{BLACK}Ezy Street +STR_MUSIC_PLAYLIST_CUSTOM_1 :{TINY_FONT}{BLACK}Custom 1 +STR_MUSIC_PLAYLIST_CUSTOM_2 :{TINY_FONT}{BLACK}Custom 2 +STR_MUSIC_MUSIC_VOLUME :{TINY_FONT}{BLACK}Music Volume +STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLACK}Effects Volume +STR_MUSIC_RULER_MIN :{TINY_FONT}{BLACK}MIN +STR_MUSIC_RULER_MAX :{TINY_FONT}{BLACK}MAX +STR_MUSIC_RULER_MARKER :{TINY_FONT}{BLACK}' +STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- +STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} +STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ +STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{RAW_STRING}" +STR_MUSIC_TRACK :{TINY_FONT}{BLACK}Track +STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}Title +STR_MUSIC_SHUFFLE :{TINY_FONT}{BLACK}Shuffle +STR_MUSIC_PROGRAM :{TINY_FONT}{BLACK}Programme +STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Skip to previous track in selection +STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Skip to next track in selection +STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC :{BLACK}Stop playing music +STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC :{BLACK}Start playing music +STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Drag sliders to set music and sound effect volumes +STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Select 'all tracks' programme +STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC :{BLACK}Select 'old style music' programme +STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC :{BLACK}Select 'new style music' programme +STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}Select 'Ezy Street style music' programme +STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Select 'Custom 1' (user-defined) programme +STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Select 'Custom 2' (user-defined) programme +STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Toggle programme shuffle on/off +STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Show music track selection window + +STR_ERROR_NO_SONGS :{WHITE}A music set without songs has been selected. No songs will be played + +# Playlist window +STR_PLAYLIST_MUSIC_PROGRAM_SELECTION :{WHITE}Music Programme Selection +STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTBLUE}{ZEROFILL_NUM} "{RAW_STRING}" +STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLACK}Track Index +STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}Programme - '{STRING}' +STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}Clear +STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Clear current programme (Custom1 or Custom2 only) +STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Click on music track to add to current programme (Custom1 or Custom2 only) +STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Click on music track to remove it from current programme (Custom1 or Custom2 only) + +# Highscore window +STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED :{BIG_FONT}{BLACK}Top companies who reached {NUM} +STR_HIGHSCORE_TOP_COMPANIES_NETWORK_GAME :{BIG_FONT}{BLACK}Company League Table in {NUM} +STR_HIGHSCORE_POSITION :{BIG_FONT}{BLACK}{COMMA}. +STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :Businessman +STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR :Entrepreneur +STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST :Industrialist +STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST :Capitalist +STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE :Magnate +STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL :Mogul +STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY :Tycoon of the Century +STR_HIGHSCORE_NAME :{PRESIDENT_NAME}, {COMPANY} +STR_HIGHSCORE_STATS :{BIG_FONT}'{STRING}' ({COMMA}) +STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{BLACK}{COMPANY} achieves '{STRING}' status! +STR_HIGHSCORE_PRESIDENT_OF_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{WHITE}{PRESIDENT_NAME} of {COMPANY} achieves '{STRING}' status! + +# Smallmap window +STR_SMALLMAP_CAPTION :{WHITE}Map - {STRING} + +STR_SMALLMAP_TYPE_CONTOURS :Contours +STR_SMALLMAP_TYPE_VEHICLES :Vehicles +STR_SMALLMAP_TYPE_INDUSTRIES :Industries +STR_SMALLMAP_TYPE_ROUTEMAP :Cargo Flow +STR_SMALLMAP_TYPE_ROUTES :Routes +STR_SMALLMAP_TYPE_VEGETATION :Vegetation +STR_SMALLMAP_TYPE_OWNERS :Owners +STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Show land contours on map +STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP :{BLACK}Show vehicles on map +STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP :{BLACK}Show industries on map +STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP :{BLACK}Show cargo flow on map +STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Show transport routes on map +STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP :{BLACK}Show vegetation on map +STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Show land owners on map +STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}Click on an industry type to toggle displaying it. Ctrl+Click disables all types except the selected one. Ctrl+Click on it again to enable all industry types +STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}Click on a company to toggle displaying its property. Ctrl+Click disables all companies except the selected one. Ctrl+Click on it again to enable all companies +STR_SMALLMAP_TOOLTIP_CARGO_SELECTION :{BLACK}Click on a cargo to toggle displaying its property. Ctrl+Click disables all cargoes except the selected one. Ctrl+Click on it again to enable all cargoes + +STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}Roads +STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}Railways +STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS :{TINY_FONT}{BLACK}Stations/Airports/Docks +STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES :{TINY_FONT}{BLACK}Buildings/Industries +STR_SMALLMAP_LEGENDA_VEHICLES :{TINY_FONT}{BLACK}Vehicles +STR_SMALLMAP_LEGENDA_TRAINS :{TINY_FONT}{BLACK}Trains +STR_SMALLMAP_LEGENDA_ROAD_VEHICLES :{TINY_FONT}{BLACK}Road Vehicles +STR_SMALLMAP_LEGENDA_SHIPS :{TINY_FONT}{BLACK}Ships +STR_SMALLMAP_LEGENDA_AIRCRAFT :{TINY_FONT}{BLACK}Aircraft +STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES :{TINY_FONT}{BLACK}Transport Routes +STR_SMALLMAP_LEGENDA_FOREST :{TINY_FONT}{BLACK}Forest +STR_SMALLMAP_LEGENDA_RAILROAD_STATION :{TINY_FONT}{BLACK}Railway Station +STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Lorry Loading Bay +STR_SMALLMAP_LEGENDA_BUS_STATION :{TINY_FONT}{BLACK}Bus Station +STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT :{TINY_FONT}{BLACK}Airport/Heliport +STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLACK}Dock +STR_SMALLMAP_LEGENDA_ROUGH_LAND :{TINY_FONT}{BLACK}Rough Land +STR_SMALLMAP_LEGENDA_GRASS_LAND :{TINY_FONT}{BLACK}Grass Land +STR_SMALLMAP_LEGENDA_BARE_LAND :{TINY_FONT}{BLACK}Bare Land +STR_SMALLMAP_LEGENDA_FIELDS :{TINY_FONT}{BLACK}Fields +STR_SMALLMAP_LEGENDA_TREES :{TINY_FONT}{BLACK}Trees +STR_SMALLMAP_LEGENDA_ROCKS :{TINY_FONT}{BLACK}Rocks +STR_SMALLMAP_LEGENDA_WATER :{TINY_FONT}{BLACK}Water +STR_SMALLMAP_LEGENDA_NO_OWNER :{TINY_FONT}{BLACK}No Owner +STR_SMALLMAP_LEGENDA_TOWNS :{TINY_FONT}{BLACK}Towns +STR_SMALLMAP_LEGENDA_INDUSTRIES :{TINY_FONT}{BLACK}Industries +STR_SMALLMAP_LEGENDA_DESERT :{TINY_FONT}{BLACK}Desert +STR_SMALLMAP_LEGENDA_SNOW :{TINY_FONT}{BLACK}Snow + +STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Toggle town names on/off on map +STR_SMALLMAP_CENTER :{BLACK}Centre the smallmap on the current position +STR_SMALLMAP_INDUSTRY :{TINY_FONT}{STRING} ({NUM}) +STR_SMALLMAP_LINKSTATS :{TINY_FONT}{STRING} +STR_SMALLMAP_COMPANY :{TINY_FONT}{COMPANY} +STR_SMALLMAP_TOWN :{TINY_FONT}{WHITE}{TOWN} +STR_SMALLMAP_DISABLE_ALL :{BLACK}Disable all +STR_SMALLMAP_ENABLE_ALL :{BLACK}Enable all +STR_SMALLMAP_SHOW_HEIGHT :{BLACK}Show height +STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES :{BLACK}Display no industries on the map +STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES :{BLACK}Display all industries on the map +STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT :{BLACK}Toggle display of heightmap +STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES :{BLACK}Display no company property on the map +STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES :{BLACK}Display all company property on the map +STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS :{BLACK}Display no cargoes on the map +STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Display all cargoes on the map + +# Status bar messages +STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Show last message or news report +STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - +STR_STATUSBAR_PAUSED :{YELLOW}* * PAUSED * * +STR_STATUSBAR_AUTOSAVE :{RED}AUTOSAVE +STR_STATUSBAR_SAVING_GAME :{RED}* * SAVING GAME * * + +# News message history +STR_MESSAGE_HISTORY :{WHITE}Message History +STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}A list of the recent news messages +STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING5} + +STR_NEWS_MESSAGE_CAPTION :{WHITE}Message +STR_NEWS_CUSTOM_ITEM :{BIG_FONT}{BLACK}{RAW_STRING} + +STR_NEWS_FIRST_TRAIN_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First train arrives at {STATION}! +STR_NEWS_FIRST_BUS_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First bus arrives at {STATION}! +STR_NEWS_FIRST_TRUCK_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First truck arrives at {STATION}! +STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First passenger tram arrives at {STATION}! +STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First freight tram arrives at {STATION}! +STR_NEWS_FIRST_SHIP_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First ship arrives at {STATION}! +STR_NEWS_FIRST_AIRCRAFT_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First aircraft arrives at {STATION}! + +STR_NEWS_TRAIN_CRASH :{BIG_FONT}{BLACK}Train Crash!{}{COMMA} die in fireball after collision +STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER :{BIG_FONT}{BLACK}Road Vehicle Crash!{}Driver dies in fireball after collision with train +STR_NEWS_ROAD_VEHICLE_CRASH :{BIG_FONT}{BLACK}Road Vehicle Crash!{}{COMMA} die in fireball after collision with train +STR_NEWS_AIRCRAFT_CRASH :{BIG_FONT}{BLACK}Plane Crash!{}{COMMA} die in fireball at {STATION} +STR_NEWS_PLANE_CRASH_OUT_OF_FUEL :{BIG_FONT}{BLACK}Plane Crash!{}Aircraft ran out of fuel, {COMMA} die in fireball + +STR_NEWS_DISASTER_ZEPPELIN :{BIG_FONT}{BLACK}Zeppelin disaster at {STATION}! +STR_NEWS_DISASTER_SMALL_UFO :{BIG_FONT}{BLACK}Road vehicle destroyed in 'UFO' collision! +STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY :{BIG_FONT}{BLACK}Oil refinery explosion near {TOWN}! +STR_NEWS_DISASTER_HELICOPTER_FACTORY :{BIG_FONT}{BLACK}Factory destroyed in suspicious circumstances near {TOWN}! +STR_NEWS_DISASTER_BIG_UFO :{BIG_FONT}{BLACK}'UFO' lands near {TOWN}! +STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE :{BIG_FONT}{BLACK}Coal mine subsidence leaves trail of destruction near {TOWN}! +STR_NEWS_DISASTER_FLOOD_VEHICLE :{BIG_FONT}{BLACK}Floods!{}At least {COMMA} missing, presumed dead after significant flooding! + +STR_NEWS_COMPANY_IN_TROUBLE_TITLE :{BIG_FONT}{BLACK}Transport company in trouble! +STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION :{BIG_FONT}{BLACK}{RAW_STRING} will be sold off or declared bankrupt unless performance increases soon! +STR_NEWS_COMPANY_MERGER_TITLE :{BIG_FONT}{BLACK}Transport company merger! +STR_NEWS_COMPANY_MERGER_DESCRIPTION :{BIG_FONT}{BLACK}{RAW_STRING} has been sold to {RAW_STRING} for {CURRENCY_LONG}! +STR_NEWS_COMPANY_BANKRUPT_TITLE :{BIG_FONT}{BLACK}Bankrupt! +STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION :{BIG_FONT}{BLACK}{RAW_STRING} has been closed down by creditors and all assets sold off! +STR_NEWS_COMPANY_LAUNCH_TITLE :{BIG_FONT}{BLACK}New transport company launched! +STR_NEWS_COMPANY_LAUNCH_DESCRIPTION :{BIG_FONT}{BLACK}{RAW_STRING} starts construction near {TOWN}! +STR_NEWS_MERGER_TAKEOVER_TITLE :{BIG_FONT}{BLACK}{RAW_STRING} has been taken over by {RAW_STRING}! +STR_PRESIDENT_NAME_MANAGER :{BLACK}{PRESIDENT_NAME}{}(Manager) + +STR_NEWS_NEW_TOWN :{BLACK}{BIG_FONT}{RAW_STRING} sponsored construction of new town {TOWN}! + +STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}New {STRING} under construction near {TOWN}! +STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK}New {STRING} being planted near {TOWN}! + +STR_NEWS_INDUSTRY_CLOSURE_GENERAL :{BIG_FONT}{BLACK}{STRING2} announces imminent closure! +STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS :{BIG_FONT}{BLACK}Supply problems cause {STRING2} to announce imminent closure! +STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES :{BIG_FONT}{BLACK}Lack of nearby trees causes {STRING2} to announce imminent closure! + +STR_NEWS_EURO_INTRODUCTION :{BIG_FONT}{BLACK}European Monetary Union!{}{}The Euro is introduced as the sole currency for everyday transactions in your country! +STR_NEWS_BEGIN_OF_RECESSION :{BIG_FONT}{BLACK}World Recession!{}{}Financial experts fear worst as economy slumps! +STR_NEWS_END_OF_RECESSION :{BIG_FONT}{BLACK}Recession Over!{}{}Upturn in trade gives confidence to industries as economy strengthens! + +STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} increases production! +STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_COAL :{BIG_FONT}{BLACK}New coal seam found at {INDUSTRY}!{}Production is expected to double! +STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL :{BIG_FONT}{BLACK}New oil reserves found at {INDUSTRY}!{}Production is expected to double! +STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM :{BIG_FONT}{BLACK}Improved farming methods at {INDUSTRY} are expected to double production! +STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} production at {INDUSTRY} increases {COMMA}%! +STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} production down by 50% +STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM :{BIG_FONT}{BLACK}Insect infestation causes havoc at {INDUSTRY}!{}Production down by 50% +STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} production at {INDUSTRY} decreases {COMMA}%! + +STR_NEWS_TRAIN_IS_WAITING :{WHITE}{VEHICLE} is waiting in depot +STR_NEWS_ROAD_VEHICLE_IS_WAITING :{WHITE}{VEHICLE} is waiting in depot +STR_NEWS_SHIP_IS_WAITING :{WHITE}{VEHICLE} is waiting in depot +STR_NEWS_AIRCRAFT_IS_WAITING :{WHITE}{VEHICLE} is waiting in the aircraft hangar + +# Start of order review system +# DON'T ADD OR REMOVE LINES HERE +STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS :{WHITE}{VEHICLE} has too few orders in the schedule +STR_NEWS_VEHICLE_HAS_VOID_ORDER :{WHITE}{VEHICLE} has a void order +STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY :{WHITE}{VEHICLE} has duplicate orders +STR_NEWS_VEHICLE_HAS_INVALID_ENTRY :{WHITE}{VEHICLE} has an invalid station in its orders +# end of order system + +STR_NEWS_VEHICLE_IS_GETTING_OLD :{WHITE}{VEHICLE} is getting old +STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD :{WHITE}{VEHICLE} is getting very old +STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND :{WHITE}{VEHICLE} is getting very old and urgently needs replacing +STR_NEWS_TRAIN_IS_STUCK :{WHITE}{VEHICLE} can't find a path to continue +STR_NEWS_VEHICLE_IS_LOST :{WHITE}{VEHICLE} is lost +STR_NEWS_VEHICLE_IS_UNPROFITABLE :{WHITE}{VEHICLE}'s profit last year was {CURRENCY_LONG} +STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} can't get to the next destination because it is out of range + +STR_NEWS_ORDER_REFIT_FAILED :{WHITE}{VEHICLE} stopped because an ordered refit failed +STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Autorenew failed on {VEHICLE}{}{STRING} + +STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE :{BIG_FONT}{BLACK}New {STRING} now available! +STR_NEWS_NEW_VEHICLE_TYPE :{BIG_FONT}{BLACK}{ENGINE} +STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}New {STRING} now available! - {ENGINE} + +STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO :{WHITE}{STATION} no longer accepts {STRING} +STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO :{WHITE}{STATION} no longer accepts {STRING} or {STRING} +STR_NEWS_STATION_NOW_ACCEPTS_CARGO :{WHITE}{STATION} now accepts {STRING} +STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION} now accepts {STRING} and {STRING} + +STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Offer of subsidy expired:{}{}{STRING} from {STRING2} to {STRING2} will now not attract a subsidy +STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subsidy withdrawn:{}{}{STRING} service from {STRING2} to {STRING2} is no longer subsidised +STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Service subsidy offered:{}{}First {STRING} service from {STRING2} to {STRING2} will attract a year's subsidy from the local authority! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay 50% extra for the next year! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay double rates for the next year! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay triple rates for the next year! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay quadruple rates for the next year! + +STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Traffic chaos in {TOWN}!{}{}Road rebuilding programme funded by {RAW_STRING} brings 6 months of misery to motorists! +STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Transport monopoly! +STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION :{BIG_FONT}{BLACK}Local authority of {TOWN} signs contract with {RAW_STRING} for one year of exclusive transport rights! + +# Extra view window +STR_EXTRA_VIEW_PORT_TITLE :{WHITE}Viewport {COMMA} +STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}Copy to viewport +STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT :{BLACK}Copy the location of the main view to this viewport +STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}Paste from viewport +STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}Paste the location of this viewport to the main view + +# Game options window +STR_GAME_OPTIONS_CAPTION :{WHITE}Game Options +STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}Currency units +STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}Currency units selection + +############ start of currency region +STR_GAME_OPTIONS_CURRENCY_GBP :British Pound (GBP) +STR_GAME_OPTIONS_CURRENCY_USD :American Dollar (USD) +STR_GAME_OPTIONS_CURRENCY_EUR :Euro (EUR) +STR_GAME_OPTIONS_CURRENCY_JPY :Japanese Yen (JPY) +STR_GAME_OPTIONS_CURRENCY_ATS :Austrian Shilling (ATS) +STR_GAME_OPTIONS_CURRENCY_BEF :Belgian Franc (BEF) +STR_GAME_OPTIONS_CURRENCY_CHF :Swiss Franc (CHF) +STR_GAME_OPTIONS_CURRENCY_CZK :Czech Koruna (CZK) +STR_GAME_OPTIONS_CURRENCY_DEM :Deutschmark (DEM) +STR_GAME_OPTIONS_CURRENCY_DKK :Danish Krone (DKK) +STR_GAME_OPTIONS_CURRENCY_ESP :Spanish Peseta (ESP) +STR_GAME_OPTIONS_CURRENCY_FIM :Finnish Markka (FIM) +STR_GAME_OPTIONS_CURRENCY_FRF :French Franc (FRF) +STR_GAME_OPTIONS_CURRENCY_GRD :Greek Drachma (GRD) +STR_GAME_OPTIONS_CURRENCY_HUF :Hungarian Forint (HUF) +STR_GAME_OPTIONS_CURRENCY_ISK :Icelandic Krona (ISK) +STR_GAME_OPTIONS_CURRENCY_ITL :Italian Lira (ITL) +STR_GAME_OPTIONS_CURRENCY_NLG :Dutch Guilder (NLG) +STR_GAME_OPTIONS_CURRENCY_NOK :Norwegian Krone (NOK) +STR_GAME_OPTIONS_CURRENCY_PLN :Polish Złoty (PLN) +STR_GAME_OPTIONS_CURRENCY_RON :Romanian Leu (RON) +STR_GAME_OPTIONS_CURRENCY_RUR :Russian Rubles (RUR) +STR_GAME_OPTIONS_CURRENCY_SIT :Slovenian Tolar (SIT) +STR_GAME_OPTIONS_CURRENCY_SEK :Swedish Krona (SEK) +STR_GAME_OPTIONS_CURRENCY_TRY :Turkish Lira (TRY) +STR_GAME_OPTIONS_CURRENCY_SKK :Slovak Koruna (SKK) +STR_GAME_OPTIONS_CURRENCY_BRL :Brazilian Real (BRL) +STR_GAME_OPTIONS_CURRENCY_EEK :Estonian Krooni (EEK) +STR_GAME_OPTIONS_CURRENCY_LTL :Lithuanian Litas (LTL) +STR_GAME_OPTIONS_CURRENCY_KRW :South Korean Won (KRW) +STR_GAME_OPTIONS_CURRENCY_ZAR :South African Rand (ZAR) +STR_GAME_OPTIONS_CURRENCY_CUSTOM :Custom... +STR_GAME_OPTIONS_CURRENCY_GEL :Georgian Lari (GEL) +STR_GAME_OPTIONS_CURRENCY_IRR :Iranian Rial (IRR) +############ end of currency region + + +############ start of measuring units region +############ end of measuring units region + +STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Road vehicles +STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP :{BLACK}Select side of road for vehicles to drive on +STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Drive on left +STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Drive on right + +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Town names +STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Select style of town names + +############ start of townname region +STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH :English (Original) +STR_GAME_OPTIONS_TOWN_NAME_FRENCH :French +STR_GAME_OPTIONS_TOWN_NAME_GERMAN :German +STR_GAME_OPTIONS_TOWN_NAME_ADDITIONAL_ENGLISH :English (Additional) +STR_GAME_OPTIONS_TOWN_NAME_LATIN_AMERICAN :Latin-American +STR_GAME_OPTIONS_TOWN_NAME_SILLY :Silly +STR_GAME_OPTIONS_TOWN_NAME_SWEDISH :Swedish +STR_GAME_OPTIONS_TOWN_NAME_DUTCH :Dutch +STR_GAME_OPTIONS_TOWN_NAME_FINNISH :Finnish +STR_GAME_OPTIONS_TOWN_NAME_POLISH :Polish +STR_GAME_OPTIONS_TOWN_NAME_SLOVAK :Slovak +STR_GAME_OPTIONS_TOWN_NAME_NORWEGIAN :Norwegian +STR_GAME_OPTIONS_TOWN_NAME_HUNGARIAN :Hungarian +STR_GAME_OPTIONS_TOWN_NAME_AUSTRIAN :Austrian +STR_GAME_OPTIONS_TOWN_NAME_ROMANIAN :Romanian +STR_GAME_OPTIONS_TOWN_NAME_CZECH :Czech +STR_GAME_OPTIONS_TOWN_NAME_SWISS :Swiss +STR_GAME_OPTIONS_TOWN_NAME_DANISH :Danish +STR_GAME_OPTIONS_TOWN_NAME_TURKISH :Turkish +STR_GAME_OPTIONS_TOWN_NAME_ITALIAN :Italian +STR_GAME_OPTIONS_TOWN_NAME_CATALAN :Catalan +############ end of townname region + +STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Autosave +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Select interval between automatic game saves + +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF :Off +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH :Every month +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS :Every 3 months +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS :Every 6 months +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Every 12 months + +STR_GAME_OPTIONS_LANGUAGE :{BLACK}Language +STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Select the interface language to use + +STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Fullscreen +STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Check this box to play OpenTTD fullscreen mode + +STR_GAME_OPTIONS_RESOLUTION :{BLACK}Screen resolution +STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Select the screen resolution to use +STR_GAME_OPTIONS_RESOLUTION_OTHER :other + +STR_GAME_OPTIONS_SCREENSHOT_FORMAT :{BLACK}Screenshot format +STR_GAME_OPTIONS_SCREENSHOT_FORMAT_TOOLTIP :{BLACK}Select the screenshot format to use + +STR_GAME_OPTIONS_BASE_GRF :{BLACK}Base graphics set +STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Select the base graphics set to use +STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} missing/corrupted file{P "" s} +STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}Additional information about the base graphics set + +STR_GAME_OPTIONS_BASE_SFX :{BLACK}Base sounds set +STR_GAME_OPTIONS_BASE_SFX_TOOLTIP :{BLACK}Select the base sounds set to use +STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP :{BLACK}Additional information about the base sounds set + +STR_GAME_OPTIONS_BASE_MUSIC :{BLACK}Base music set +STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP :{BLACK}Select the base music set to use +STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} corrupted file{P "" s} +STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Additional information about the base music set + +STR_ERROR_FULLSCREEN_FAILED :{WHITE}Fullscreen mode failed +STR_ERROR_RESET_WINDOWS :{WHITE}All windows have been reseted... +STR_ERROR_AUTOMATIC_SIZING :{WHITE}Sizes of buttons and fonts have changed + +# Custom currency window + +STR_CURRENCY_WINDOW :{WHITE}Custom currency +STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}Exchange rate: {ORANGE}{CURRENCY_LONG} = £ {COMMA} +STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Decrease the amount of your currency for one Pound (£) +STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Increase the amount of your currency for one Pound (£) +STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP :{BLACK}Set the exchange rate of your currency for one Pound (£) + +STR_CURRENCY_SEPARATOR :{LTBLUE}Separator: {ORANGE}{RAW_STRING} +STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP :{BLACK}Set the separator for your currency + +STR_CURRENCY_PREFIX :{LTBLUE}Prefix: {ORANGE}{RAW_STRING} +STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP :{BLACK}Set the prefix string for your currency +STR_CURRENCY_SUFFIX :{LTBLUE}Suffix: {ORANGE}{RAW_STRING} +STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP :{BLACK}Set the suffix string for your currency + +STR_CURRENCY_SWITCH_TO_EURO :{LTBLUE}Switch to Euro: {ORANGE}{NUM} +STR_CURRENCY_SWITCH_TO_EURO_NEVER :{LTBLUE}Switch to Euro: {ORANGE}never +STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Set the year to switch to Euro +STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Switch to Euro earlier +STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Switch to Euro later + +STR_CURRENCY_PREVIEW :{LTBLUE}Preview: {ORANGE}{CURRENCY_LONG} +STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP :{BLACK}10000 Pound (£) in your currency +STR_CURRENCY_CHANGE_PARAMETER :{BLACK}Change custom currency parameter + +STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS :{LTBLUE}Maximum no. competitors: {ORANGE}{COMMA} + +STR_NONE :None +STR_FUNDING_ONLY :Funding only +STR_MINIMAL :Minimal +STR_NUM_VERY_LOW :Very Low +STR_NUM_LOW :Low +STR_NUM_NORMAL :Normal +STR_NUM_HIGH :High +STR_NUM_CUSTOM :Custom +STR_NUM_CUSTOM_NUMBER :Custom ({NUM}) + +STR_VARIETY_NONE :None +STR_VARIETY_VERY_LOW :Very Low +STR_VARIETY_LOW :Low +STR_VARIETY_MEDIUM :Medium +STR_VARIETY_HIGH :High +STR_VARIETY_VERY_HIGH :Very High + +STR_AI_SPEED_VERY_SLOW :Very Slow +STR_AI_SPEED_SLOW :Slow +STR_AI_SPEED_MEDIUM :Medium +STR_AI_SPEED_FAST :Fast +STR_AI_SPEED_VERY_FAST :Very Fast + +STR_SEA_LEVEL_VERY_LOW :Very Low +STR_SEA_LEVEL_LOW :Low +STR_SEA_LEVEL_MEDIUM :Medium +STR_SEA_LEVEL_HIGH :High +STR_SEA_LEVEL_CUSTOM :Custom +STR_SEA_LEVEL_CUSTOM_PERCENTAGE :Custom ({NUM}%) + +STR_RIVERS_NONE :None +STR_RIVERS_FEW :Few +STR_RIVERS_MODERATE :Medium +STR_RIVERS_LOT :Many + +STR_DISASTER_NONE :None +STR_DISASTER_REDUCED :Reduced +STR_DISASTER_NORMAL :Normal + +STR_SUBSIDY_X1_5 :x1.5 +STR_SUBSIDY_X2 :x2 +STR_SUBSIDY_X3 :x3 +STR_SUBSIDY_X4 :x4 + +STR_TERRAIN_TYPE_VERY_FLAT :Very Flat +STR_TERRAIN_TYPE_FLAT :Flat +STR_TERRAIN_TYPE_HILLY :Hilly +STR_TERRAIN_TYPE_MOUNTAINOUS :Mountainous + +STR_CITY_APPROVAL_PERMISSIVE :Permissive +STR_CITY_APPROVAL_TOLERANT :Tolerant +STR_CITY_APPROVAL_HOSTILE :Hostile + +STR_WARNING_NO_SUITABLE_AI :{WHITE}No suitable AIs available...{}You can download several AIs via the 'Online Content' system + +# Advanced settings window +STR_CONFIG_SETTING_CAPTION :{WHITE}Advanced Settings +STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filter string: +STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Expand all +STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Collapse all +STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(no explanation available) +STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Default value: {ORANGE}{STRING1} +STR_CONFIG_SETTING_TYPE :{LTBLUE}Setting type: {ORANGE}{STRING} +STR_CONFIG_SETTING_TYPE_CLIENT :Client setting (not stored in saves; affects all games) +STR_CONFIG_SETTING_TYPE_GAME_MENU :Game setting (stored in saves; affects only new games) +STR_CONFIG_SETTING_TYPE_GAME_INGAME :Game setting (stored in save; affects only current game) +STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Company setting (stored in saves; affects only new games) +STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Company setting (stored in save; affects only current company) + +STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Category: +STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Type: +STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}Restricts the list below showing only changed settings +STR_CONFIG_SETTING_RESTRICT_BASIC :Basic settings +STR_CONFIG_SETTING_RESTRICT_ADVANCED :Advanced settings +STR_CONFIG_SETTING_RESTRICT_ALL :Expert settings / all settings +STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT :Settings with a different value than the default +STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW :Settings with a different value than your new-game settings + +STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT :{BLACK}Restricts the list below to certain setting types +STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL :All setting types +STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT :Client settings (not stored in saves; affects all games) +STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU :Game settings (stored in saves; affects only new games) +STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :Game settings (stored in save; affects only current game) +STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU :Company settings (stored in saves; affects only new games) +STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME :Company settings (stored in save; affects only current company) +STR_CONFIG_SETTING_CATEGORY_HIDES :{BLACK}Show all search results by setting{}{SILVER}Category {BLACK}to {WHITE}{STRING} +STR_CONFIG_SETTING_TYPE_HIDES :{BLACK}Show all search results by setting{}{SILVER}Type {BLACK}to {WHITE}All setting types +STR_CONFIG_SETTING_CATEGORY_AND_TYPE_HIDES :{BLACK}Show all search results by setting{}{SILVER}Category {BLACK}to {WHITE}{STRING} {BLACK}and {SILVER}Type {BLACK}to {WHITE}All setting types +STR_CONFIG_SETTINGS_NONE :{WHITE}- None - + +STR_CONFIG_SETTING_OFF :Off +STR_CONFIG_SETTING_ON :On +STR_CONFIG_SETTING_DISABLED :Disabled + +STR_CONFIG_SETTING_COMPANIES_OFF :Off +STR_CONFIG_SETTING_COMPANIES_OWN :Own company +STR_CONFIG_SETTING_COMPANIES_ALL :All companies + +STR_CONFIG_SETTING_NONE :None +STR_CONFIG_SETTING_ORIGINAL :Original +STR_CONFIG_SETTING_REALISTIC :Realistic + +STR_CONFIG_SETTING_HORIZONTAL_POS_LEFT :Left +STR_CONFIG_SETTING_HORIZONTAL_POS_CENTER :Centre +STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :Right + +STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :Maximum initial loan: {STRING2} +STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :Maximum amount a company can loan (without taking inflation into account) +STR_CONFIG_SETTING_INTEREST_RATE :Interest rate: {STRING2} +STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Loan interest rate; also controls inflation, if enabled +STR_CONFIG_SETTING_RUNNING_COSTS :Running costs: {STRING2} +STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Set level of maintainance and running costs of vehicles and infrastructure +STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Construction speed: {STRING2} +STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Limit the amount of construction actions for AIs +STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Vehicle breakdowns: {STRING2} +STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Control how often inadequately serviced vehicles may break down +STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Subsidy multiplier: {STRING2} +STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Set how much is paid for subsidised connections +STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Construction costs: {STRING2} +STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Set level of construction and purchase costs +STR_CONFIG_SETTING_RECESSIONS :Recessions: {STRING2} +STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :If enabled, recessions may occur every few years. During a recession all production is significantly lower (it returns to previous level when the recession is over) +STR_CONFIG_SETTING_TRAIN_REVERSING :Disallow train reversing in stations: {STRING2} +STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :If enabled, trains will not reverse in non-terminus stations, even if there is a shorter path to their next destination when reversing +STR_CONFIG_SETTING_DISASTERS :Disasters: {STRING2} +STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Toggle disasters which may occasionally block or destroy vehicles or infrastructure +STR_CONFIG_SETTING_CITY_APPROVAL :City council's attitude towards area restructuring: {STRING2} +STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Choose how much noise and environmental damage by companies affect their town rating and further construction actions in their area + +STR_CONFIG_SETTING_BUILDONSLOPES :Allow building on slopes and coasts: {STRING2} +STR_CONFIG_SETTING_BUILDONSLOPES_HELPTEXT :If enabled, tracks and stations can be build on most slopes. If disabled, they are only allowed on slopes which match the direction of the track and thus require no foundations +STR_CONFIG_SETTING_AUTOSLOPE :Allow landscaping under buildings, tracks, etc. (autoslope): {STRING2} +STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Allow landscaping under buildings and tracks without removing them +STR_CONFIG_SETTING_CATCHMENT :Allow more realistically sized catchment areas: {STRING2} +STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Have differently sized catchment areas for different types of stations and airports +STR_CONFIG_SETTING_EXTRADYNAMITE :Allow removal of more town-owned roads, bridges and tunnels: {STRING2} +STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Make it easier to remove town-owned infrastructure and buildings +STR_CONFIG_SETTING_TRAIN_LENGTH :Maximum length of trains: {STRING2} +STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT :Set the maximum length of trains +STR_CONFIG_SETTING_TILE_LENGTH :{COMMA} tile{P 0 "" s} +STR_CONFIG_SETTING_SMOKE_AMOUNT :Amount of vehicle smoke/sparks: {STRING2} +STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT :Set how much smoke or how many sparks are emitted by vehicles +STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :Train acceleration model: {STRING2} +STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :Select the physics model for train acceleration. The "original" model penalises slopes equally for all vehicles. The "realistic" model penalises slopes and curves depending on various properties of the consist, like length and tractive effort +STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Road vehicle acceleration model: {STRING2} +STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :Select the physics model for road vehicle acceleration. The "original" model penalises slopes equally for all vehicles. The "realistic" model penalises slopes depending on various properties of the engine, for example 'tractive effort' +STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :Slope steepness for trains: {STRING2} +STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Steepness of a sloped tile for a train. Higher values make it more difficult to climb a hill +STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% +STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Slope steepness for road vehicles: {STRING2} +STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Steepness of a sloped tile for a road vehicle. Higher values make it more difficult to climb a hill +STR_CONFIG_SETTING_FORBID_90_DEG :Forbid trains and ships from making 90° turns: {STRING2} +STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 degree turns occur when a horizontal track is directly followed by a vertical track piece on the adjacent tile, thus making the train turn by 90 degree when traversing the tile edge instead of the usual 45 degrees for other track combinations. This also applies to the turning radius of ships +STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Allow to join stations not directly adjacent: {STRING2} +STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Allow adding parts to a station without directly touching the existing parts. Needs Ctrl+Click while placing the new parts +STR_CONFIG_SETTING_IMPROVEDLOAD :Use improved loading algorithm: {STRING2} +STR_CONFIG_SETTING_IMPROVEDLOAD_HELPTEXT :If enabled, multiple vehicles waiting at a station are loaded sequentially. Loading of the next vehicle only starts when there is enough cargo waiting to completely fill the first vehicle +STR_CONFIG_SETTING_GRADUAL_LOADING :Load vehicles gradually: {STRING2} +STR_CONFIG_SETTING_GRADUAL_LOADING_HELPTEXT :Gradually load vehicles using vehicle specific loading durations, instead of loading everything at once with a fixed time depending only on the amount of cargo loaded +STR_CONFIG_SETTING_INFLATION :Inflation: {STRING2} +STR_CONFIG_SETTING_INFLATION_HELPTEXT :Enable inflation in the economy, where costs are slightly faster rising than payments +STR_CONFIG_SETTING_SELECTGOODS :Deliver cargo to a station only when there is a demand: {STRING2} +STR_CONFIG_SETTING_SELECTGOODS_HELPTEXT :Only deliver cargo to a station that was requested from a loading vehicle. This prevents bad ratings for cargoes that are not serviced at a station +STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :Maximum bridge length: {STRING2} +STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT :Maximum length for building bridges +STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Maximum tunnel length: {STRING2} +STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :Maximum length for building tunnels +STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :Manual primary industry construction method: {STRING2} +STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :Method of funding a primary industry. 'none' means it is not possible to fund any, 'prospecting' means funding is possible, but construction occurs in a random spot on the map and may as well fail, 'as other industries' means raw industries can be constructed by companies like processing industries in any position they like +STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :None +STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :As other industries +STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :Prospecting +STR_CONFIG_SETTING_INDUSTRY_PLATFORM :Flat area around industries: {STRING2} +STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :Amount of flat space around an industry. This ensures empty space will remain available around an industry for building tracks, et cetera +STR_CONFIG_SETTING_MULTIPINDTOWN :Allow multiple similar industries per town: {STRING2} +STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :Normally, a town does not want more than one industry of each type. With this setting, it will allow several industries of the same type in the same town +STR_CONFIG_SETTING_SIGNALSIDE :Show signals: {STRING2} +STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :Select on which side of the track to place signals +STR_CONFIG_SETTING_SIGNALSIDE_LEFT :On the left +STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :On the driving side +STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :On the right +STR_CONFIG_SETTING_SHOWFINANCES :Show finances window at the end of the year: {STRING2} +STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :If enabled, the finances window pops up at the end of each year to allow easy inspection of the financial status of the company +STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :New orders are 'non-stop' by default: {STRING2} +STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Normally, a vehicle will stop at every station it passes. By enabling this setting, it will drive through all station on the way to its final destination without stopping. Note, that this setting only defines a default value for new orders. Individual orders can be set explicitly to either behaviour nevertheless +STR_CONFIG_SETTING_STOP_LOCATION :New train orders stop by default at the {STRING2} of the platform +STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Place where a train will stop at the platform by default. The 'near end' means close to the entry point, 'middle' means in the middle of the platform, and 'far end' means far away from the entry point. Note, that this setting only defines a default value for new orders. Individual orders can be set explicitly to either behaviour nevertheless +STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :near end +STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :middle +STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :far end +STR_CONFIG_SETTING_ROAD_VEHICLE_QUEUEING :Road vehicle queueing (with quantum effects): {STRING2} +STR_CONFIG_SETTING_ROAD_VEHICLE_QUEUEING_HELPTEXT :Make road vehicle wait in front of occupied road stops until they are cleared +STR_CONFIG_SETTING_AUTOSCROLL :Pan window when mouse is at the edge: {STRING2} +STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :When enabled, viewports will start to scroll when the mouse is near the edge of the window +STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :Disabled +STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN :Main viewport, full-screen only +STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT :Main viewport +STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT :Every viewport +STR_CONFIG_SETTING_BRIBE :Allow bribing of the local authority: {STRING2} +STR_CONFIG_SETTING_BRIBE_HELPTEXT :Allow companies to try bribing the local town authority. If the bribe is noticed by an inspector, the company will not be able to act in the town for six months +STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Allow buying exclusive transport rights: {STRING2} +STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :If a company buys exclusive transport rights for a town, opponents' stations (passenger and cargo) won't receive any cargo for a whole year +STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Allow funding buildings: {STRING2} +STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Allow companies to give money to towns for funding new houses +STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Allow funding local road reconstruction: {STRING2} +STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT :Allow companies to give money to towns for road re-construction to sabotage road-based services in the town +STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :Allow sending money to other companies: {STRING2} +STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :Allow transfer of money between companies in multiplayer mode +STR_CONFIG_SETTING_FREIGHT_TRAINS :Weight multiplier for freight to simulate heavy trains: {STRING2} +STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :Set the impact of carrying freight in trains. A higher value makes carrying freight more demanding for trains, especially at hills +STR_CONFIG_SETTING_PLANE_SPEED :Plane speed factor: {STRING2} +STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Set the relative speed of planes compared to other vehicle types, to reduce the amount of income of transport by aircraft +STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} +STR_CONFIG_SETTING_PLANE_CRASHES :Number of plane crashes: {STRING2} +STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Set the chance of an aircraft crash happening +STR_CONFIG_SETTING_PLANE_CRASHES_NONE :None +STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Reduced +STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normal +STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Allow drive-through road stops on town owned roads: {STRING} +STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :Allow construction of drive-through road stops on town-owned roads +STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :Allow drive-through road stops on roads owned by competitors: {STRING2} +STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :Allow construction of drive-through road stops on roads owned by other companies +STR_CONFIG_SETTING_ADJACENT_STATIONS :Allow building adjacent stations: {STRING2} +STR_CONFIG_SETTING_ADJACENT_STATIONS_HELPTEXT :Allow different stations to touch each other +STR_CONFIG_SETTING_DYNAMIC_ENGINES :Enable multiple NewGRF engine sets: {STRING2} +STR_CONFIG_SETTING_DYNAMIC_ENGINES_HELPTEXT :Compatibility option for old NewGRFs. Do not disable this, unless you know exactly what you are doing! +STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Changing this setting is not possible when there are vehicles +STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Infrastructure maintenance: {STRING2} +STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :When enabled, infrastructure causes maintenance costs. The cost grows over-proportional with the network size, thus affecting bigger companies more than smaller ones + +STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Airports never expire: {STRING2} +STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Enabling this setting makes each airport type stay available forever after its introduction + +STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Warn if vehicle is lost: {STRING2} +STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :Trigger messages about vehicles unable to find a path to their ordered destination +STR_CONFIG_SETTING_ORDER_REVIEW :Review vehicles' orders: {STRING2} +STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :When enabled, the orders of the vehicles are periodically checked, and some obvious issues are reported with a news message when detected +STR_CONFIG_SETTING_ORDER_REVIEW_OFF :No +STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :Yes, but exclude stopped vehicles +STR_CONFIG_SETTING_ORDER_REVIEW_ON :Of all vehicles +STR_CONFIG_SETTING_WARN_INCOME_LESS :Warn if a vehicle's income is negative: {STRING2} +STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT :When enabled, a news message gets sent when a vehicle has not made any profit within a calendar year +STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :Vehicles never expire: {STRING2} +STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES_HELPTEXT :When enabled, all vehicle models remain available forever after their introduction +STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Autorenew vehicle when it gets old: {STRING2} +STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :When enabled, a vehicle nearing its end of life gets automatically replaced when the renew conditions are fulfilled +STR_CONFIG_SETTING_AUTORENEW_MONTHS :Autorenew when vehicle is {STRING2} max age +STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Relative age when a vehicle should be considered for auto-renewing +STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} month{P 0 "" s} before +STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} month{P 0 "" s} after +STR_CONFIG_SETTING_AUTORENEW_MONEY :Autorenew minimum needed money for renew: {STRING2} +STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Minimal amount of money that must remain in the bank before considering auto-renewing vehicles +STR_CONFIG_SETTING_ERRMSG_DURATION :Duration of error message: {STRING2} +STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Duration for displaying error messages in a red window. Note that some (critical) error messages are not closed automatically after this time, but must be closed manually +STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} second{P 0 "" s} +STR_CONFIG_SETTING_HOVER_DELAY :Show tooltips: {STRING2} +STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :Delay before tooltips are displayed when hovering the mouse over some interface element. Alternatively tooltips can be bound to the right mouse button +STR_CONFIG_SETTING_HOVER_DELAY_VALUE :Hover for {COMMA} second{P 0 "" s} +STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :Right click +STR_CONFIG_SETTING_POPULATION_IN_LABEL :Show town population in the town name label: {STRING2} +STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Display the population of towns in their label on the map +STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Thickness of lines in graphs: {STRING2} +STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Width of the line in the graphs. A thin line is more precisely readable, a thicker line is easier to see and colours are easier to distinguish + +STR_CONFIG_SETTING_LAND_GENERATOR :Land generator: {STRING2} +STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Original +STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis +STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Max distance from edge for Oil Refineries: {STRING2} +STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Oil refineries are only constructed near the map border, that is at the coast for island maps +STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Snow line height: {STRING2} +STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Roughness of terrain (TerraGenesis only) : {STRING2} +STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Very Smooth +STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Smooth +STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Rough +STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Very Rough +STR_CONFIG_SETTING_TREE_PLACER :Tree placer algorithm: {STRING2} +STR_CONFIG_SETTING_TREE_PLACER_NONE :None +STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Original +STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Improved +STR_CONFIG_SETTING_HEIGHTMAP_ROTATION :Heightmap rotation: {STRING2} +STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :Counter clockwise +STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE :Clockwise +STR_CONFIG_SETTING_SE_FLAT_WORLD_HEIGHT :The height level a flat scenario map gets: {STRING2} +STR_CONFIG_SETTING_ENABLE_FREEFORM_EDGES :Enable landscaping the tiles at the map borders: {STRING2} +STR_CONFIG_SETTING_ENABLE_FREEFORM_EDGES_HELPTEXT :If disabled, the map borders will always be ocean +STR_CONFIG_SETTING_EDGES_NOT_EMPTY :{WHITE}One or more tiles at the northern edge are not empty +STR_CONFIG_SETTING_EDGES_NOT_WATER :{WHITE}One or more tiles at one of the edges is not water + +STR_CONFIG_SETTING_STATION_SPREAD :Max station spread: {STRING2} +STR_CONFIG_SETTING_STATION_SPREAD_HELPTEXT :Maximum area the parts of a single station may be spread out on. Note that high values will slow the game +STR_CONFIG_SETTING_SERVICEATHELIPAD :Service helicopters at helipads automatically: {STRING2} +STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :Service helicopters after every landing, even if there is no depot at the airport +STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Link landscape toolbar to rail/road/water/airport toolbars: {STRING2} +STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :When opening a construction toolbar for a transport type, also open the toolbar for terraforming +STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :Land colour used at the smallmap: {STRING2} +STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Colour of the terrain in the smallmap +STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :Green +STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :Dark green +STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :Violet +STR_CONFIG_SETTING_REVERSE_SCROLLING :Reverse scroll direction: {STRING2} +STR_CONFIG_SETTING_REVERSE_SCROLLING_HELPTEXT :Behaviour when scrolling the map with the right mouse button. When disabled, the mouse moves the camera. When enabled, the mouse moves the map +STR_CONFIG_SETTING_SMOOTH_SCROLLING :Smooth viewport scrolling: {STRING2} +STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Control how the main view scrolls to a specific position when clicking on the smallmap or when issuing a command to scroll to a specific object on the map. If enabled, the viewport scrolls smoothly, if disabled it jumps directly to the targeted spot +STR_CONFIG_SETTING_MEASURE_TOOLTIP :Show a measurement tooltip when using various build-tools: {STRING2} +STR_CONFIG_SETTING_MEASURE_TOOLTIP_HELPTEXT :Display tile-distances and height differences when dragging during construction operations +STR_CONFIG_SETTING_LIVERIES :Show company liveries: {STRING2} +STR_CONFIG_SETTING_LIVERIES_HELPTEXT :Control usage of vehicle-type specific liveries for vehicles (in contrary to company specific) +STR_CONFIG_SETTING_LIVERIES_NONE :None +STR_CONFIG_SETTING_LIVERIES_OWN :Own company +STR_CONFIG_SETTING_LIVERIES_ALL :All companies +STR_CONFIG_SETTING_PREFER_TEAMCHAT :Prefer team chat with : {STRING2} +STR_CONFIG_SETTING_PREFER_TEAMCHAT_HELPTEXT :Switch the binding of company-internal and public chat to resp. +STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING :Function of scrollwheel: {STRING2} +STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING_HELPTEXT :Enable scrolling with two-dimensional mouse-wheels +STR_CONFIG_SETTING_SCROLLWHEEL_ZOOM :Zoom map +STR_CONFIG_SETTING_SCROLLWHEEL_SCROLL :Scroll map +STR_CONFIG_SETTING_SCROLLWHEEL_OFF :Off +STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER :Map scrollwheel speed: {STRING2} +STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER_HELPTEXT :Control the sensitivity of mouse-wheel scrolling +STR_CONFIG_SETTING_OSK_ACTIVATION :On screen keyboard: {STRING2} +STR_CONFIG_SETTING_OSK_ACTIVATION_HELPTEXT :Select the method to open the on screen keyboard for entering text into editboxes only using the pointing device. This is meant for small devices without actual keyboard +STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED :Disabled +STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :Double click +STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :Single click (when focussed) +STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :Single click (immediately) + +STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU :Right-click emulation: {STRING2} +STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_HELPTEXT :Select the method to emulate right mouse-button clicks +STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND :Command+Click +STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_CONTROL :Ctrl+Click +STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_OFF :Off + +STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING :Left-click scrolling: {STRING2} +STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING_HELPTEXT :Enable scrolling the map by dragging it with the left mouse button. This is especially useful when using a touch-screen for scrolling + +STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :Use the {STRING2} date format for savegame names +STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :Format of the date in save game filenames +STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :long (31st Dec 2008) +STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :short (31-12-2008) +STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31) + +STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE :Default palette to assume for NewGRFs not specifying a palette: {STRING2} +STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_HELPTEXT :Default palette to use for NewGRFs that do not specify which one they need +STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_DOS :Default (D) palette +STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_WIN :Legacy (W) palette + +STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Automatically pause when starting a new game: {STRING2} +STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :When enabled, the game will automatically pause when starting a new game, allowing for closer study of the map +STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL :When paused allow: {STRING2} +STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_HELPTEXT :Select what actions may be done while the game is paused +STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS :No actions +STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_CONSTRUCTION :All non-construction actions +STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_LANDSCAPING :All but landscape modifying actions +STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :All actions +STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :Use the advanced vehicle list: {STRING2} +STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS_HELPTEXT :Enable usage of the advanced vehicle lists for grouping vehicles +STR_CONFIG_SETTING_LOADING_INDICATORS :Use loading indicators: {STRING2} +STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :Select whether loading indicators are displayed above loading or unloading vehicles +STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :Show timetable in ticks rather than days: {STRING2} +STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT :Show travel times in time tables in game ticks instead of days +STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Show arrival and departure in timetables: {STRING2} +STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Display anticipated arrival and departure times in timetables +STR_CONFIG_SETTING_QUICKGOTO :Quick creation of vehicle orders: {STRING2} +STR_CONFIG_SETTING_QUICKGOTO_HELPTEXT :Pre-select the 'goto cursor' when opening the orders window +STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE :Default rail type (after new game/game load): {STRING2} +STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_HELPTEXT :Rail type to select after starting or loading a game. 'first available' selects the oldest type of tracks, 'last available' selects the newest type of tracks, and 'most used' selects the type which is currently most in use +STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :First available +STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :Last available +STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :Most used +STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION :Show reserved tracks: {STRING2} +STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT :Give reserved tracks a different colour to assist in problems with trains refusing to enter path-based blocks +STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :Keep building tools active after usage: {STRING2} +STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :Keep the building tools for bridges, tunnels, etc. open after use +STR_CONFIG_SETTING_EXPENSES_LAYOUT :Group expenses in company finance window: {STRING2} +STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :Define the layout for the company expenses window + +STR_CONFIG_SETTING_SOUND_TICKER :News ticker: {STRING2} +STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Play sound for summarised news messages +STR_CONFIG_SETTING_SOUND_NEWS :Newspaper: {STRING2} +STR_CONFIG_SETTING_SOUND_NEWS_HELPTEXT :Play sound upon display of newspapers +STR_CONFIG_SETTING_SOUND_NEW_YEAR :End of year: {STRING2} +STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT :Play sound at the end of a year summarising the company's performance during the year compared to the previous year +STR_CONFIG_SETTING_SOUND_CONFIRM :Construction: {STRING2} +STR_CONFIG_SETTING_SOUND_CONFIRM_HELPTEXT :Play sound on successful constructions or other actions +STR_CONFIG_SETTING_SOUND_CLICK :Button clicks: {STRING2} +STR_CONFIG_SETTING_SOUND_CLICK_HELPTEXT :Beep when clicking buttons +STR_CONFIG_SETTING_SOUND_DISASTER :Disasters/accidents: {STRING2} +STR_CONFIG_SETTING_SOUND_DISASTER_HELPTEXT :Play sound effects of accidents and disasters +STR_CONFIG_SETTING_SOUND_VEHICLE :Vehicles: {STRING2} +STR_CONFIG_SETTING_SOUND_VEHICLE_HELPTEXT :Play sound effects of vehicles +STR_CONFIG_SETTING_SOUND_AMBIENT :Ambient: {STRING2} +STR_CONFIG_SETTING_SOUND_AMBIENT_HELPTEXT :Play ambient sounds of landscape, industries and towns + +STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING :Disable infrastructure building when no suitable vehicles are available: {STRING2} +STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT :When enabled, infrastructure is only available if there are also vehicles available, preventing waste of time and money on unusable infrastructure +STR_CONFIG_SETTING_MAX_TRAINS :Max trains per company: {STRING2} +STR_CONFIG_SETTING_MAX_TRAINS_HELPTEXT :Maximum number of trains that a company can have +STR_CONFIG_SETTING_MAX_ROAD_VEHICLES :Max road vehicles per company: {STRING2} +STR_CONFIG_SETTING_MAX_ROAD_VEHICLES_HELPTEXT :Maximum number of road vehicles that a company can have +STR_CONFIG_SETTING_MAX_AIRCRAFT :Max aircraft per company: {STRING2} +STR_CONFIG_SETTING_MAX_AIRCRAFT_HELPTEXT :Maximum number of aircraft that a company can have +STR_CONFIG_SETTING_MAX_SHIPS :Max ships per company: {STRING2} +STR_CONFIG_SETTING_MAX_SHIPS_HELPTEXT :Maximum number of ships that a company can have + +STR_CONFIG_SETTING_AI_BUILDS_TRAINS :Disable trains for computer: {STRING2} +STR_CONFIG_SETTING_AI_BUILDS_TRAINS_HELPTEXT :Enabling this setting makes building trains impossible for a computer player +STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES :Disable road vehicles for computer: {STRING2} +STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES_HELPTEXT :Enabling this setting makes building road vehicles impossible for a computer player +STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT :Disable aircraft for computer: {STRING2} +STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT_HELPTEXT :Enabling this setting makes building aircraft impossible for a computer player +STR_CONFIG_SETTING_AI_BUILDS_SHIPS :Disable ships for computer: {STRING2} +STR_CONFIG_SETTING_AI_BUILDS_SHIPS_HELPTEXT :Enabling this setting makes building ships impossible for a computer player + +STR_CONFIG_SETTING_AI_PROFILE :Default settings profile: {STRING2} +STR_CONFIG_SETTING_AI_PROFILE_HELPTEXT :Choose which settings profile to use for random AIs or for initial values when adding a new AI or Game Script +STR_CONFIG_SETTING_AI_PROFILE_EASY :Easy +STR_CONFIG_SETTING_AI_PROFILE_MEDIUM :Medium +STR_CONFIG_SETTING_AI_PROFILE_HARD :Hard + +STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Allow AIs in multiplayer: {STRING2} +STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Allow AI computer players to participate in multiplayer games +STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#opcodes before scripts are suspended: {STRING2} +STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Maximum number of computation steps that a script can take in one turn + +STR_CONFIG_SETTING_SERVINT_ISPERCENT :Service intervals are in percents: {STRING2} +STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Choose whether servicing of vehicles is triggered by the time passed since last service or by reliability dropping by a certain percentage of the maximum reliability +STR_CONFIG_SETTING_SERVINT_TRAINS :Default service interval for trains: {STRING2} +STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :Set the default service interval for new rail vehicles, if no explicit service interval is set for the vehicle +STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA} day{P 0 "" s}/% +STR_CONFIG_SETTING_SERVINT_DISABLED :Disabled +STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :Default service interval for road vehicles: {STRING2} +STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :Set the default service interval for new road vehicles, if no explicit service interval is set for the vehicle +STR_CONFIG_SETTING_SERVINT_AIRCRAFT :Default service interval for aircraft: {STRING2} +STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :Set the default service interval for new aircraft, if no explicit service interval is set for the vehicle +STR_CONFIG_SETTING_SERVINT_SHIPS :Default service interval for ships: {STRING2} +STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :Set the default service interval for new ships, if no explicit service interval is set for the vehicle +STR_CONFIG_SETTING_NOSERVICE :Disable servicing when breakdowns set to none: {STRING2} +STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :When enabled, vehicles do not get serviced if they cannot break down +STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Enable wagon speed limits: {STRING2} +STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :When enabled, also use speed limits of wagons for deciding the maximum speed of a train +STR_CONFIG_SETTING_DISABLE_ELRAILS :Disable electric rails: {STRING2} +STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :Enabling this setting disables the requirement to electrify tracks to make electric engines run on them + +STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN :Arrival of first vehicle at player's station: {STRING2} +STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN_HELPTEXT :Display a newspaper when the first vehicle arrives at a new player's station +STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER :Arrival of first vehicle at competitor's station: {STRING2} +STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER_HELPTEXT :Display a newspaper when the first vehicle arrives at a new competitor's station +STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS :Accidents / disasters: {STRING2} +STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS_HELPTEXT :Display a newspaper when accidents or disasters occur +STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION :Company information: {STRING2} +STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION_HELPTEXT :Display a newspaper when a new company starts, or when companies are risking to bankrupt +STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN :Opening of industries: {STRING2} +STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN_HELPTEXT :Display a newspaper when new industries open +STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE :Closing of industries: {STRING2} +STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE_HELPTEXT :Display a newspaper when industries close down +STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES :Economy changes: {STRING2} +STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES_HELPTEXT :Display a newspaper about global changes to economy +STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY :Production changes of industries served by the company: {STRING2} +STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY_HELPTEXT :Display a newspaper when the production level of industries change, which are served by the company +STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER :Production changes of industries served by competitor(s): {STRING2} +STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER_HELPTEXT :Display a newspaper when the production level of industries change, which are served by the competitors +STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED :Other industry production changes: {STRING2} +STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED_HELPTEXT :Display a newspaper when the production level of industries change, which are not served by the company or competitors +STR_CONFIG_SETTING_NEWS_ADVICE :Advice / information on company's vehicles: {STRING2} +STR_CONFIG_SETTING_NEWS_ADVICE_HELPTEXT :Display messages about vehicles needing attention +STR_CONFIG_SETTING_NEWS_NEW_VEHICLES :New vehicles: {STRING2} +STR_CONFIG_SETTING_NEWS_NEW_VEHICLES_HELPTEXT :Display a newspaper when a new vehicle type becomes available +STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE :Changes to cargo acceptance: {STRING2} +STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT :Display messages about stations changing acceptance of some cargoes +STR_CONFIG_SETTING_NEWS_SUBSIDIES :Subsidies: {STRING2} +STR_CONFIG_SETTING_NEWS_SUBSIDIES_HELPTEXT :Display a newspaper about subsidy related events +STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION :General information: {STRING2} +STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT :Display newspaper about general events, such as purchase of exclusive rights or funding of road reconstruction + +STR_CONFIG_SETTING_NEWS_MESSAGES_OFF :Off +STR_CONFIG_SETTING_NEWS_MESSAGES_SUMMARY :Summary +STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :Full + +STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Coloured news appears in: {STRING2} +STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Year that the newspaper announcements get printed in colour. Before this year, it uses monochrome black/white +STR_CONFIG_SETTING_STARTING_YEAR :Starting year: {STRING2} +STR_CONFIG_SETTING_SMOOTH_ECONOMY :Enable smooth economy (more, smaller changes): {STRING2} +STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :When enabled, industry production changes more often, and in smaller steps. This setting has usually no effect, if industry types are provided by a NewGRF +STR_CONFIG_SETTING_ALLOW_SHARES :Allow buying shares from other companies: {STRING2} +STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :When enabled, allow buying and selling of company shares. Shares will only be available for companies reaching a certain age +STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Percentage of leg profit to pay in feeder systems: {STRING2} +STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Percentage of income given to the intermediate legs in feeder systems, giving more control over the income +STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :When dragging, place signals every: {STRING2} +STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Set the distance at which signals will be built on a track up to the next obstacle (signal, junction), if signals are dragged +STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} tile{P 0 "" s} +STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :When dragging, keep fixed distance between signals: {STRING2} +STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :Select the behaviour of signal placement when Ctrl+dragging signals. If disabled, signals are placed around tunnels or bridges to avoid long stretches without signals. If enabled, signals are placed every n tiles, making alignment of signals at parallel tracks easier +STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :Automatically build semaphores before: {STRING2} +STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :Set the year when electric signals will be used for tracks. Before this year, non-electric signals will be used (which have the exact same function, but different looks) +STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :Enable the signal GUI: {STRING2} +STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT :Display a window for choosing signal types to build, instead of only window-less signal-type rotation with Ctrl+clicking on build signals +STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :Signal type to build by default: {STRING2} +STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :Default signal type to use +STR_CONFIG_SETTING_DEFAULT_SIGNAL_NORMAL :Block signals +STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBS :Path signals +STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBSOWAY :One-way path signals +STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES :Cycle through signal types: {STRING2} +STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES_HELPTEXT :Select which signal types to cycle through, when Ctrl+clicking on a build signal with the signal tool +STR_CONFIG_SETTING_CYCLE_SIGNAL_NORMAL :Block signals only +STR_CONFIG_SETTING_CYCLE_SIGNAL_PBS :Path signals only +STR_CONFIG_SETTING_CYCLE_SIGNAL_ALL :All + +STR_CONFIG_SETTING_TOWN_LAYOUT :Road layout for new towns: {STRING2} +STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT :Layout for the road network of towns +STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT :Original +STR_CONFIG_SETTING_TOWN_LAYOUT_BETTER_ROADS :Better roads +STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :2x2 grid +STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :3x3 grid +STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :Random +STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :Towns are allowed to build roads: {STRING2} +STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :Allow towns to build roads for growth. Disable to prevent town authorities from building roads themselves +STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :Towns are allowed to build level crossings: {STRING2} +STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :Enabling this setting allows towns to build level crossings +STR_CONFIG_SETTING_NOISE_LEVEL :Allow town controlled noise level for airports: {STRING2} +STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT :With this setting disabled, there can be two airports in each town. With this setting enabled, the number of airports in a city is limited by the noise acceptance of the town, which depends on population and airport size and distance +STR_CONFIG_SETTING_TOWN_FOUNDING :Founding towns in game: {STRING2} +STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Enabling this setting allows players to found new towns in the game +STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Forbidden +STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Allowed +STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Allowed, custom town layout + +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :In game placement of trees: {STRING2} +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Control random appearance of trees during the game. This might affect industries which rely on tree growth, for example lumber mills +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE :None {RED}(breaks lumber mill) +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_RAINFOREST :Only in rain forests +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_ALL :Everywhere + +STR_CONFIG_SETTING_TOOLBAR_POS :Position of main toolbar: {STRING2} +STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Horizontal position of the main toolbar at the top of the screen +STR_CONFIG_SETTING_STATUSBAR_POS :Position of status bar: {STRING2} +STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT :Horizontal position of the status bar at the bottom of the screen +STR_CONFIG_SETTING_SNAP_RADIUS :Window snap radius: {STRING2} +STR_CONFIG_SETTING_SNAP_RADIUS_HELPTEXT :Distance between windows before the window being moved is automatically aligned to nearby windows +STR_CONFIG_SETTING_SNAP_RADIUS_VALUE :{COMMA} pixel{P 0 "" s} +STR_CONFIG_SETTING_SNAP_RADIUS_DISABLED :Disabled +STR_CONFIG_SETTING_SOFT_LIMIT :Maximum number of non-sticky windows: {STRING2} +STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Number of non-sticky open windows before old windows get automatically closed to make room for new windows +STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} +STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :disabled +STR_CONFIG_SETTING_ZOOM_MIN :Maximum zoom in level: {STRING2} +STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :The maximum zoom-in level for viewports. Note that enabling higher zoom-in levels increases memory requirements +STR_CONFIG_SETTING_ZOOM_MAX :Maximum zoom out level: {STRING2} +STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :The maximum zoom-out level for viewports. Higher zoom-out levels might cause lag when used +STR_CONFIG_SETTING_ZOOM_LVL_MIN :4x +STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2x +STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :Normal +STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :2x +STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :4x +STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :8x +STR_CONFIG_SETTING_TOWN_GROWTH :Town growth speed: {STRING2} +STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Speed of town growth +STR_CONFIG_SETTING_TOWN_GROWTH_NONE :None +STR_CONFIG_SETTING_TOWN_GROWTH_SLOW :Slow +STR_CONFIG_SETTING_TOWN_GROWTH_NORMAL :Normal +STR_CONFIG_SETTING_TOWN_GROWTH_FAST :Fast +STR_CONFIG_SETTING_TOWN_GROWTH_VERY_FAST :Very fast +STR_CONFIG_SETTING_LARGER_TOWNS :Proportion of towns that will become cities: {STRING2} +STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Amount of towns which will become a city, thus a town which starts out larger and grows faster +STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 in {COMMA} +STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :None +STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Initial city size multiplier: {STRING2} +STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Average size of cities relative to normal towns at start of the game +STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD :Remove absurd road-elements during the road construction: {STRING2} +STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD_HELPTEXT :Remove dead road ends during funded road reconstruction + +STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Update distribution graph every {STRING2} day{P 0:2 "" s} +STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Time between subsequent recalculations of the link graph. Each recalculation calculates the plans for one component of the graph. That means that a value X for this setting does not mean the whole graph will be updated every X days. Only some component will. The shorter you set it the more CPU time will be necessary to calculate it. The longer you set it the longer it will take until the cargo distribution starts on new routes. +STR_CONFIG_SETTING_LINKGRAPH_TIME :Take {STRING2} day{P 0:2 "" s} for recalculation of distribution graph +STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT :Time taken for each recalculation of a link graph component. When a recalculation is started, a thread is spawned which is allowed to run for this number of days. The shorter you set this the more likely it is that the thread is not finished when it's supposed to. Then the game stops until it is ("lag"). The longer you set it the longer it takes for the distribution to be updated when routes change. +STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manual +STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asymmetric +STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :symmetric +STR_CONFIG_SETTING_DISTRIBUTION_PAX :Distribution mode for passengers: {STRING2} +STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :"symmetric" means that roughly the same number of passengers will go from a station A to a station B as from B to A. "asymmetric" means that arbitrary numbers of passengers can go in either direction. "manual" means that no automatic distribution will take place for passengers. +STR_CONFIG_SETTING_DISTRIBUTION_MAIL :Distribution mode for mail: {STRING2} +STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :"symmetric" means that roughly the same amount of mail will be sent from a station A to a station B as from B to A. "asymmetric" means that arbitrary amounts of mail can be sent in either direction. "manual" means that no automatic distribution will take place for mail. +STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED :Distribution mode for the ARMOURED cargo class: {STRING2} +STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :The ARMOURED cargo class contains valuables in the temperate, diamonds in the subtropical or gold in subarctic climate. NewGRFs may change that. "symmetric" means that roughly the same amount of that cargo will be sent from a station A to a station B as from B to A. "asymmetric" means that arbitrary of that cargo can be sent in either direction. "manual" means that no automatic distribution will take place for that cargo. It is recommended to set this to asymmetric or manual when playing subarctic, as banks won't send any gold back to gold mines. For temperate and subtropical you can also choose symmetric as banks will send valuables back to the origin bank of some load of valuables. +STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Distribution mode for other cargo classes: {STRING2} +STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"asymmetric" means that arbitrary amounts of cargo can be sent in either direction. "manual" means that no automatic distribution will take place for those cargoes. +STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Distribution accuracy: {STRING2} +STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :The higher you set this the more CPU time the calculation of the link graph will take. If it takes too long you may notice lag. If you set it to a low value, however, the distribution will be inaccurate, and you may notice cargo not being sent to the places you expect it to go. +STR_CONFIG_SETTING_DEMAND_DISTANCE :Effect of distance on demands: {STRING2} +STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :If you set this to a value higher than 0, the distance between the origin station A of some cargo and a possible destination B will have an effect on the amount of cargo sent from A to B. The further away B is from A the less cargo will be sent. The higher you set it, the less cargo will be sent to far away stations and the more cargo will be sent to near stations. +STR_CONFIG_SETTING_DEMAND_SIZE :Amount of returning cargo for symmetric mode: {STRING2} +STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Setting this to less than 100% makes the symmetric distribution behave more like the asymmetric one. Less cargo will be forcibly sent back if a certain amount is sent to a station. If you set it to 0% the symmetric distribution behaves just like the asymmetric one. +STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Saturation of short paths before using high-capacity paths: {STRING2} +STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Frequently there are multiple paths between two given stations. Cargodist will saturate the shortest path first, then use the second shortest path until that is saturated and so on. Saturation is determined by an estimation of capacity and planned usage. Once it has saturated all paths, if there is still demand left, it will overload all paths, prefering the ones with high capacity. Most of the time the algorithm will not estimate the capacity accurately, though. This setting allows you to specify up to which percentage a shorter path must be saturated in the first pass before choosing the next longer one. Set it to less than 100% to avoid overcrowded stations in case of overestimated capacity. + +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Speed units: {STRING2} +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Whenever a speed is shown in the user interface, show it in the selected units +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Imperial (mph) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metric (km/h) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s) + +STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Vehicle power units: {STRING2} +STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Whenever a vehicle's power is shown in the user interface, show it in the selected units +STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :Imperial (hp) +STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :Metric (hp) +STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :SI (kW) + +STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :Weights units: {STRING2} +STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :Whenever weights are shown in the user interface, show it in the selected units +STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :Imperial (short t/ton) +STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :Metric (t/tonne) +STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :SI (kg) + +STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :Volumes units: {STRING2} +STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :Whenever volumes are shown in the user interface, show it in the selected units +STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :Imperial (gal) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :Metric (l) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :SI (m³) + +STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :Tractive effort units: {STRING2} +STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :Whenever tractive effort, also known as tractive force, is shown in the user interface, show it in the selected units +STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :Imperial (lbf) +STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :Metric (kgf) +STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :SI (kN) + +STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :Heights units: {STRING2} +STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :Whenever heights are shown in the user interface, show it in the selected units +STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :Imperial (ft) +STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :Metric (m) +STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI (m) + +STR_CONFIG_SETTING_GUI :{ORANGE}Interface +STR_CONFIG_SETTING_LOCALISATION :{ORANGE}Localisation +STR_CONFIG_SETTING_CONSTRUCTION :{ORANGE}Construction +STR_CONFIG_SETTING_VEHICLES :{ORANGE}Vehicles +STR_CONFIG_SETTING_STATIONS :{ORANGE}Stations +STR_CONFIG_SETTING_ECONOMY :{ORANGE}Economy +STR_CONFIG_SETTING_LINKGRAPH :{ORANGE}Cargo Distribution +STR_CONFIG_SETTING_AI :{ORANGE}Competitors +STR_CONFIG_SETTING_DISPLAY_OPTIONS :{ORANGE}Display options +STR_CONFIG_SETTING_INTERACTION :{ORANGE}Interaction +STR_CONFIG_SETTING_SOUND :{ORANGE}Sound effects +STR_CONFIG_SETTING_NEWS :{ORANGE}News and messages +STR_CONFIG_SETTING_CONSTRUCTION_SIGNALS :{ORANGE}Signals +STR_CONFIG_SETTING_STATIONS_CARGOHANDLING :{ORANGE}Cargo handling +STR_CONFIG_SETTING_AI_NPC :{ORANGE}Computer players +STR_CONFIG_SETTING_VEHICLES_AUTORENEW :{ORANGE}Autorenew +STR_CONFIG_SETTING_VEHICLES_SERVICING :{ORANGE}Servicing +STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}Routing +STR_CONFIG_SETTING_VEHICLES_TRAINS :{ORANGE}Trains +STR_CONFIG_SETTING_ECONOMY_TOWNS :{ORANGE}Towns +STR_CONFIG_SETTING_ECONOMY_INDUSTRIES :{ORANGE}Industries + +STR_CONFIG_SETTING_PATHFINDER_OPF :Original +STR_CONFIG_SETTING_PATHFINDER_NPF :NPF +STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Recommended) + +STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS :Pathfinder for trains: {STRING2} +STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT :Path finder to use for trains +STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES :Pathfinder for road vehicles: {STRING2} +STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES_HELPTEXT :Path finder to use for road vehicles +STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS :Pathfinder for ships: {STRING2} +STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT :Path finder to use for ships +STR_CONFIG_SETTING_REVERSE_AT_SIGNALS :Automatic reversing at signals: {STRING2} +STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Allow trains to reverse on a signal, if they waited there a long time + +STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Change setting value + +# Config errors +STR_CONFIG_ERROR :{WHITE}Error with the configuration file... +STR_CONFIG_ERROR_ARRAY :{WHITE}... error in array '{RAW_STRING}' +STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... invalid value '{RAW_STRING}' for '{RAW_STRING}' +STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... trailing characters at end of setting '{RAW_STRING}' +STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... ignoring NewGRF '{RAW_STRING}': duplicate GRF ID with '{RAW_STRING}' +STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... ignoring invalid NewGRF '{RAW_STRING}': {STRING} +STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :not found +STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :unsafe for static use +STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :system NewGRF +STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :incompatible to this version of OpenTTD +STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :unknown +STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... compression level '{RAW_STRING}' is not valid +STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... savegame format '{RAW_STRING}' is not available. Reverting to '{RAW_STRING}' +STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... ignoring Base Graphics set '{RAW_STRING}': not found +STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... ignoring Base Sounds set '{RAW_STRING}': not found +STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... ignoring Base Music set '{RAW_STRING}': not found +STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Out of memory +STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}Allocating {BYTES} of spritecache failed. The spritecache was reduced to {BYTES}. This will reduce the performance of OpenTTD. To reduce memory requirements you can try to disable 32bpp graphics and/or zoom-in levels + +# Intro window +STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} + +STR_INTRO_NEW_GAME :{BLACK}New Game +STR_INTRO_LOAD_GAME :{BLACK}Load Game +STR_INTRO_PLAY_SCENARIO :{BLACK}Play Scenario +STR_INTRO_PLAY_HEIGHTMAP :{BLACK}Play Heightmap +STR_INTRO_SCENARIO_EDITOR :{BLACK}Scenario Editor +STR_INTRO_MULTIPLAYER :{BLACK}Multiplayer + +STR_INTRO_GAME_OPTIONS :{BLACK}Game Options +STR_INTRO_HIGHSCORE :{BLACK}Highscore Table +STR_INTRO_ADVANCED_SETTINGS :{BLACK}Advanced Settings +STR_INTRO_NEWGRF_SETTINGS :{BLACK}NewGRF Settings +STR_INTRO_ONLINE_CONTENT :{BLACK}Check Online Content +STR_INTRO_SCRIPT_SETTINGS :{BLACK}AI/Game Script Settings +STR_INTRO_QUIT :{BLACK}Exit + +STR_INTRO_TOOLTIP_NEW_GAME :{BLACK}Start a new game. Ctrl+Click skips map configuration +STR_INTRO_TOOLTIP_LOAD_GAME :{BLACK}Load a saved game +STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP :{BLACK}Start a new game, using a heightmap as landscape +STR_INTRO_TOOLTIP_PLAY_SCENARIO :{BLACK}Start a new game, using a customised scenario +STR_INTRO_TOOLTIP_SCENARIO_EDITOR :{BLACK}Create a customised game world/scenario +STR_INTRO_TOOLTIP_MULTIPLAYER :{BLACK}Start a multiplayer game + +STR_INTRO_TOOLTIP_TEMPERATE :{BLACK}Select 'temperate' landscape style +STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE :{BLACK}Select 'sub-arctic' landscape style +STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE :{BLACK}Select 'sub-tropical' landscape style +STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Select 'toyland' landscape style + +STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Display game options +STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Display highscore table +STR_INTRO_TOOLTIP_ADVANCED_SETTINGS :{BLACK}Display advanced settings +STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Display NewGRF settings +STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Check for new and updated content to download +STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}Display AI/Game script settings +STR_INTRO_TOOLTIP_QUIT :{BLACK}Exit 'OpenTTD' + +STR_INTRO_TRANSLATION :{BLACK}This translation misses {NUM} string{P "" s}. Please help make OpenTTD better by signing up as translator. See readme.txt for details. + +# Quit window +STR_QUIT_CAPTION :{WHITE}Exit +STR_QUIT_ARE_YOU_SURE_YOU_WANT_TO_EXIT_OPENTTD :{YELLOW}Are you sure you want to exit OpenTTD and return to {STRING}? +STR_QUIT_YES :{BLACK}Yes +STR_QUIT_NO :{BLACK}No + +# Supported OSes +STR_OSNAME_WINDOWS :Windows +STR_OSNAME_DOS :DOS +STR_OSNAME_UNIX :Unix +STR_OSNAME_OSX :OS{NBSP}X +STR_OSNAME_BEOS :BeOS +STR_OSNAME_HAIKU :Haiku +STR_OSNAME_MORPHOS :MorphOS +STR_OSNAME_AMIGAOS :AmigaOS +STR_OSNAME_OS2 :OS/2 +STR_OSNAME_SUNOS :SunOS + +# Abandon game +STR_ABANDON_GAME_CAPTION :{WHITE}Abandon Game +STR_ABANDON_GAME_QUERY :{YELLOW}Are you sure you want to abandon this game? +STR_ABANDON_SCENARIO_QUERY :{YELLOW}Are you sure you want to abandon this scenario? + +# Cheat window +STR_CHEATS :{WHITE}Cheats +STR_CHEATS_TOOLTIP :{BLACK}Checkboxes indicate if you have used this cheat before +STR_CHEATS_WARNING :{BLACK}Warning! You are about to betray your fellow competitors. Keep in mind that such a disgrace will be remembered for eternity +STR_CHEAT_MONEY :{LTBLUE}Increase money by {CURRENCY_LONG} +STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Playing as company: {ORANGE}{COMMA} +STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Magic bulldozer (remove industries, unmovable objects): {ORANGE}{STRING1} +STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}Tunnels may cross each other: {ORANGE}{STRING1} +STR_CHEAT_NO_JETCRASH :{LTBLUE}Jetplanes will not crash (frequently) on small airports: {ORANGE}{STRING} +STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE :Temperate landscape +STR_CHEAT_SWITCH_CLIMATE_SUB_ARCTIC_LANDSCAPE :Sub-arctic landscape +STR_CHEAT_SWITCH_CLIMATE_SUB_TROPICAL_LANDSCAPE :Sub-tropical landscape +STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE :Toyland landscape +STR_CHEAT_CHANGE_DATE :{LTBLUE}Change date: {ORANGE}{DATE_SHORT} +STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Change current year +STR_CHEAT_SETUP_PROD :{LTBLUE}Enable modifying production values: {ORANGE}{STRING1} + +# Livery window +STR_LIVERY_CAPTION :{WHITE}New Colour Scheme + +STR_LIVERY_GENERAL_TOOLTIP :{BLACK}Show general colour schemes +STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Show train colour schemes +STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Show road vehicle colour schemes +STR_LIVERY_SHIP_TOOLTIP :{BLACK}Show ship colour schemes +STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Show aircraft colour schemes +STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Choose the primary colour for the selected scheme. Ctrl+Click will set this colour for every scheme +STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Choose the secondary colour for the selected scheme. Ctrl+Click will set this colour for every scheme +STR_LIVERY_PANEL_TOOLTIP :{BLACK}Select a colour scheme to change, or multiple schemes with Ctrl+Click. Click on the box to toggle use of the scheme + +STR_LIVERY_DEFAULT :Standard Livery +STR_LIVERY_STEAM :Steam Engine +STR_LIVERY_DIESEL :Diesel Engine +STR_LIVERY_ELECTRIC :Electric Engine +STR_LIVERY_MONORAIL :Monorail Engine +STR_LIVERY_MAGLEV :Maglev Engine +STR_LIVERY_DMU :DMU +STR_LIVERY_EMU :EMU +STR_LIVERY_PASSENGER_WAGON_STEAM :Passenger Coach (Steam) +STR_LIVERY_PASSENGER_WAGON_DIESEL :Passenger Coach (Diesel) +STR_LIVERY_PASSENGER_WAGON_ELECTRIC :Passenger Coach (Electric) +STR_LIVERY_PASSENGER_WAGON_MONORAIL :Passenger Coach (Monorail) +STR_LIVERY_PASSENGER_WAGON_MAGLEV :Passenger Coach (Maglev) +STR_LIVERY_FREIGHT_WAGON :Freight Wagon +STR_LIVERY_BUS :Bus +STR_LIVERY_TRUCK :Lorry +STR_LIVERY_PASSENGER_SHIP :Passenger Ferry +STR_LIVERY_FREIGHT_SHIP :Freight Ship +STR_LIVERY_HELICOPTER :Helicopter +STR_LIVERY_SMALL_PLANE :Small Aeroplane +STR_LIVERY_LARGE_PLANE :Large Aeroplane +STR_LIVERY_PASSENGER_TRAM :Passenger Tram +STR_LIVERY_FREIGHT_TRAM :Freight Tram + +# Face selection window +STR_FACE_CAPTION :{WHITE}Face Selection +STR_FACE_CANCEL_TOOLTIP :{BLACK}Cancel new face selection +STR_FACE_OK_TOOLTIP :{BLACK}Accept new face selection + +STR_FACE_MALE_BUTTON :{BLACK}Male +STR_FACE_MALE_TOOLTIP :{BLACK}Select male faces +STR_FACE_FEMALE_BUTTON :{BLACK}Female +STR_FACE_FEMALE_TOOLTIP :{BLACK}Select female faces +STR_FACE_NEW_FACE_BUTTON :{BLACK}New Face +STR_FACE_NEW_FACE_TOOLTIP :{BLACK}Generate random new face +STR_FACE_ADVANCED :{BLACK}Advanced +STR_FACE_ADVANCED_TOOLTIP :{BLACK}Advanced face selection +STR_FACE_SIMPLE :{BLACK}Simple +STR_FACE_SIMPLE_TOOLTIP :{BLACK}Simple face selection +STR_FACE_LOAD :{BLACK}Load +STR_FACE_LOAD_TOOLTIP :{BLACK}Load favourite face +STR_FACE_LOAD_DONE :{WHITE}Your favourite face has been loaded from the OpenTTD configuration file +STR_FACE_FACECODE :{BLACK}Player face no. +STR_FACE_FACECODE_TOOLTIP :{BLACK}View and/or set face number of the company president +STR_FACE_FACECODE_CAPTION :{WHITE}View and/or set president face number +STR_FACE_FACECODE_SET :{WHITE}New face number code has been set +STR_FACE_FACECODE_ERR :{WHITE}Couldn't set president face number - must be a number between 0 and 4,294,967,295! +STR_FACE_SAVE :{BLACK}Save +STR_FACE_SAVE_TOOLTIP :{BLACK}Save favourite face +STR_FACE_SAVE_DONE :{WHITE}This face will be saved as your favourite in the OpenTTD configuration file +STR_FACE_EUROPEAN :{BLACK}European +STR_FACE_SELECT_EUROPEAN :{BLACK}Select European faces +STR_FACE_AFRICAN :{BLACK}African +STR_FACE_SELECT_AFRICAN :{BLACK}Select African faces +STR_FACE_YES :Yes +STR_FACE_NO :No +STR_FACE_MOUSTACHE_EARRING_TOOLTIP :{BLACK}Enable moustache or earring +STR_FACE_HAIR :Hair: +STR_FACE_HAIR_TOOLTIP :{BLACK}Change hair +STR_FACE_EYEBROWS :Eyebrows: +STR_FACE_EYEBROWS_TOOLTIP :{BLACK}Change eyebrows +STR_FACE_EYECOLOUR :Eye colour: +STR_FACE_EYECOLOUR_TOOLTIP :{BLACK}Change eye colour +STR_FACE_GLASSES :Glasses: +STR_FACE_GLASSES_TOOLTIP :{BLACK}Enable glasses +STR_FACE_GLASSES_TOOLTIP_2 :{BLACK}Change glasses +STR_FACE_NOSE :Nose: +STR_FACE_NOSE_TOOLTIP :{BLACK}Change nose +STR_FACE_LIPS :Lips: +STR_FACE_MOUSTACHE :Moustache: +STR_FACE_LIPS_MOUSTACHE_TOOLTIP :{BLACK}Change lips or moustache +STR_FACE_CHIN :Chin: +STR_FACE_CHIN_TOOLTIP :{BLACK}Change chin +STR_FACE_JACKET :Jacket: +STR_FACE_JACKET_TOOLTIP :{BLACK}Change jacket +STR_FACE_COLLAR :Collar: +STR_FACE_COLLAR_TOOLTIP :{BLACK}Change collar +STR_FACE_TIE :Tie: +STR_FACE_EARRING :Earring: +STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Change tie or earring + +# Network server list +STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer +STR_NETWORK_SERVER_LIST_ADVERTISED :{BLACK}Advertised +STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP :{BLACK}Choose between an advertised (internet) and a not advertised (Local Area Network, LAN) game +STR_NETWORK_SERVER_LIST_ADVERTISED_NO :No +STR_NETWORK_SERVER_LIST_ADVERTISED_YES :Yes +STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Player name: +STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP :{BLACK}This is the name other players will identify you by + +STR_NETWORK_SERVER_LIST_GAME_NAME :{BLACK}Name +STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP :{BLACK}Name of the game +STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} +STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION :{BLACK}Clients +STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP :{BLACK}Clients online / clients max{}Companies online / companies max +STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x{COMMA} +STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION :{BLACK}Map size +STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP :{BLACK}Map size of the game{}Click to sort by area +STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}Date +STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}Current date +STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}Years +STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}Number of years{}the game is running +STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Language, server version, etc. + +STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}Click a game from the list to select it +STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER :{BLACK}The server you joined last time: +STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST :{BLACK}Click to select the server you played last time + +STR_NETWORK_SERVER_LIST_GAME_INFO :{SILVER}GAME INFO +STR_NETWORK_SERVER_LIST_CLIENTS :{SILVER}Clients: {WHITE}{COMMA} / {COMMA} - {COMMA} / {COMMA} +STR_NETWORK_SERVER_LIST_LANGUAGE :{SILVER}Language: {WHITE}{STRING} +STR_NETWORK_SERVER_LIST_LANDSCAPE :{SILVER}Landscape: {WHITE}{STRING} +STR_NETWORK_SERVER_LIST_MAP_SIZE :{SILVER}Map size: {WHITE}{COMMA}x{COMMA} +STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}Server version: {WHITE}{RAW_STRING} +STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Server address: {WHITE}{RAW_STRING} +STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Start date: {WHITE}{DATE_SHORT} +STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Current date: {WHITE}{DATE_SHORT} +STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Password protected! +STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}SERVER OFFLINE +STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}SERVER FULL +STR_NETWORK_SERVER_LIST_VERSION_MISMATCH :{SILVER}VERSION MISMATCH +STR_NETWORK_SERVER_LIST_GRF_MISMATCH :{SILVER}NEWGRF MISMATCH + +STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Join game +STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Refresh server +STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Refresh the server info + +STR_NETWORK_SERVER_LIST_FIND_SERVER :{BLACK}Find server +STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP :{BLACK}Search network for a server +STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Add server +STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Adds a server to the list which will always be checked for running games +STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Start server +STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}Start your own server + +STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Enter your name +STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Enter the address of the host + +# Start new multiplayer server +STR_NETWORK_START_SERVER_CAPTION :{WHITE}Start new multiplayer game + +STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}Game name: +STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}The game name will be displayed to other players in the multiplayer game selection menu +STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Set password +STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protect your game with a password if you don't want it to be publicly accessible + +STR_NETWORK_START_SERVER_UNADVERTISED :No +STR_NETWORK_START_SERVER_ADVERTISED :Yes +STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} client{P "" s} +STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Max clients: +STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Choose the maximum number of clients. Not all slots need to be filled +STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} compan{P y ies} +STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Max companies: +STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}Limit the server to a certain amount of companies +STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} spectator{P "" s} +STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Max spectators: +STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}Limit the server to a certain amount of spectators +STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Language spoken: +STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Other players will know which language is spoken on the server + +STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Enter a name for the network game + +# Network game languages +############ Leave those lines in this order!! +STR_NETWORK_LANG_ANY :Any +STR_NETWORK_LANG_ENGLISH :English +STR_NETWORK_LANG_GERMAN :German +STR_NETWORK_LANG_FRENCH :French +STR_NETWORK_LANG_BRAZILIAN :Brazilian +STR_NETWORK_LANG_BULGARIAN :Bulgarian +STR_NETWORK_LANG_CHINESE :Chinese +STR_NETWORK_LANG_CZECH :Czech +STR_NETWORK_LANG_DANISH :Danish +STR_NETWORK_LANG_DUTCH :Dutch +STR_NETWORK_LANG_ESPERANTO :Esperanto +STR_NETWORK_LANG_FINNISH :Finnish +STR_NETWORK_LANG_HUNGARIAN :Hungarian +STR_NETWORK_LANG_ICELANDIC :Icelandic +STR_NETWORK_LANG_ITALIAN :Italian +STR_NETWORK_LANG_JAPANESE :Japanese +STR_NETWORK_LANG_KOREAN :Korean +STR_NETWORK_LANG_LITHUANIAN :Lithuanian +STR_NETWORK_LANG_NORWEGIAN :Norwegian +STR_NETWORK_LANG_POLISH :Polish +STR_NETWORK_LANG_PORTUGUESE :Portuguese +STR_NETWORK_LANG_ROMANIAN :Romanian +STR_NETWORK_LANG_RUSSIAN :Russian +STR_NETWORK_LANG_SLOVAK :Slovak +STR_NETWORK_LANG_SLOVENIAN :Slovenian +STR_NETWORK_LANG_SPANISH :Spanish +STR_NETWORK_LANG_SWEDISH :Swedish +STR_NETWORK_LANG_TURKISH :Turkish +STR_NETWORK_LANG_UKRAINIAN :Ukrainian +STR_NETWORK_LANG_AFRIKAANS :Afrikaans +STR_NETWORK_LANG_CROATIAN :Croatian +STR_NETWORK_LANG_CATALAN :Catalan +STR_NETWORK_LANG_ESTONIAN :Estonian +STR_NETWORK_LANG_GALICIAN :Galician +STR_NETWORK_LANG_GREEK :Greek +STR_NETWORK_LANG_LATVIAN :Latvian +############ End of leave-in-this-order + +# Network game lobby +STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Multiplayer game lobby + +STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}Preparing to join: {ORANGE}{RAW_STRING} +STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}A list of all companies currently in this game. You can either join one or start a new one if there is a free company slot + +STR_NETWORK_GAME_LOBBY_COMPANY_INFO :{SILVER}COMPANY INFO +STR_NETWORK_GAME_LOBBY_COMPANY_NAME :{SILVER}Company name: {WHITE}{RAW_STRING} +STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR :{SILVER}Inauguration: {WHITE}{NUM} +STR_NETWORK_GAME_LOBBY_VALUE :{SILVER}Company value: {WHITE}{CURRENCY_LONG} +STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE :{SILVER}Current balance: {WHITE}{CURRENCY_LONG} +STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME :{SILVER}Last year's income: {WHITE}{CURRENCY_LONG} +STR_NETWORK_GAME_LOBBY_PERFORMANCE :{SILVER}Performance: {WHITE}{NUM} + +STR_NETWORK_GAME_LOBBY_VEHICLES :{SILVER}Vehicles: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} +STR_NETWORK_GAME_LOBBY_STATIONS :{SILVER}Stations: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} +STR_NETWORK_GAME_LOBBY_PLAYERS :{SILVER}Players: {WHITE}{RAW_STRING} + +STR_NETWORK_GAME_LOBBY_NEW_COMPANY :{BLACK}New company +STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP :{BLACK}Create a new company +STR_NETWORK_GAME_LOBBY_SPECTATE_GAME :{BLACK}Spectate game +STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP :{BLACK}Watch the game as a spectator +STR_NETWORK_GAME_LOBBY_JOIN_COMPANY :{BLACK}Join company +STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP :{BLACK}Help manage this company + +# Network connecting window +STR_NETWORK_CONNECTING_CAPTION :{WHITE}Connecting... + +############ Leave those lines in this order!! +STR_NETWORK_CONNECTING_1 :{BLACK}(1/6) Connecting... +STR_NETWORK_CONNECTING_2 :{BLACK}(2/6) Authorising... +STR_NETWORK_CONNECTING_3 :{BLACK}(3/6) Waiting... +STR_NETWORK_CONNECTING_4 :{BLACK}(4/6) Downloading map... +STR_NETWORK_CONNECTING_5 :{BLACK}(5/6) Processing data... +STR_NETWORK_CONNECTING_6 :{BLACK}(6/6) Registering... + +STR_NETWORK_CONNECTING_SPECIAL_1 :{BLACK}Fetching game info... +STR_NETWORK_CONNECTING_SPECIAL_2 :{BLACK}Fetching company info... +############ End of leave-in-this-order +STR_NETWORK_CONNECTING_WAITING :{BLACK}{NUM} client{P "" s} in front of you +STR_NETWORK_CONNECTING_DOWNLOADING_1 :{BLACK}{BYTES} downloaded so far +STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} / {BYTES} downloaded so far + +STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Disconnect + +STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server is protected. Enter password +STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Company is protected. Enter password + +# Network company list added strings +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}Client list +STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}Spectate +STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}New company + +# Network client list +STR_NETWORK_CLIENTLIST_KICK :Kick +STR_NETWORK_CLIENTLIST_BAN :Ban +STR_NETWORK_CLIENTLIST_GIVE_MONEY :Give money +STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Speak to all +STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Speak to company +STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Private message + +STR_NETWORK_SERVER :Server +STR_NETWORK_CLIENT :Client +STR_NETWORK_SPECTATORS :Spectators + +STR_NETWORK_GIVE_MONEY_CAPTION :{WHITE}Enter the amount of money you want to give +STR_NETWORK_TOOLBAR_LIST_SPECTATOR :{BLACK}Spectator + +# Network set password +STR_COMPANY_PASSWORD_CANCEL :{BLACK}Do not save the entered password +STR_COMPANY_PASSWORD_OK :{BLACK}Give the company the new password +STR_COMPANY_PASSWORD_CAPTION :{WHITE}Company password +STR_COMPANY_PASSWORD_MAKE_DEFAULT :{BLACK}Default company password +STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}Use this company password as default for new companies + +# Network company info join/password +STR_COMPANY_VIEW_JOIN :{BLACK}Join +STR_COMPANY_VIEW_JOIN_TOOLTIP :{BLACK}Join and play as this company +STR_COMPANY_VIEW_PASSWORD :{BLACK}Password +STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}Password-protect your company to prevent unauthorised users from joining +STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}Set company password + +# Network chat +STR_NETWORK_CHAT_SEND :{BLACK}Send +STR_NETWORK_CHAT_COMPANY_CAPTION :[Team] : +STR_NETWORK_CHAT_CLIENT_CAPTION :[Private] {RAW_STRING}: +STR_NETWORK_CHAT_ALL_CAPTION :[All] : + +STR_NETWORK_CHAT_COMPANY :[Team] {RAW_STRING}: {WHITE}{RAW_STRING} +STR_NETWORK_CHAT_TO_COMPANY :[Team] To {RAW_STRING}: {WHITE}{RAW_STRING} +STR_NETWORK_CHAT_CLIENT :[Private] {RAW_STRING}: {WHITE}{RAW_STRING} +STR_NETWORK_CHAT_TO_CLIENT :[Private] To {RAW_STRING}: {WHITE}{RAW_STRING} +STR_NETWORK_CHAT_ALL :[All] {RAW_STRING}: {WHITE}{RAW_STRING} +STR_NETWORK_CHAT_OSKTITLE :{BLACK}Enter text for network chat + +# Network messages +STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}No network devices found or compiled without ENABLE_NETWORK +STR_NETWORK_ERROR_NOSERVER :{WHITE}Could not find any network games +STR_NETWORK_ERROR_NOCONNECTION :{WHITE}The server didn't answer the request +STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Could not connect due to NewGRF mismatch +STR_NETWORK_ERROR_DESYNC :{WHITE}Network-Game synchronisation failed +STR_NETWORK_ERROR_LOSTCONNECTION :{WHITE}Network-Game connection lost +STR_NETWORK_ERROR_SAVEGAMEERROR :{WHITE}Could not load savegame +STR_NETWORK_ERROR_SERVER_START :{WHITE}Could not start the server +STR_NETWORK_ERROR_CLIENT_START :{WHITE}Could not connect +STR_NETWORK_ERROR_TIMEOUT :{WHITE}Connection #{NUM} timed out +STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}A protocol error was detected and the connection was closed +STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}The revision of this client does not match the server's revision +STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Wrong password +STR_NETWORK_ERROR_SERVER_FULL :{WHITE}The server is full +STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}You are banned from this server +STR_NETWORK_ERROR_KICKED :{WHITE}You were kicked out of the game +STR_NETWORK_ERROR_CHEATER :{WHITE}Cheating is not allowed on this server +STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}You were sending too many commands to the server +STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}You took too long to enter the password +STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Your computer is too slow to keep up with the server +STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Your computer took too long to download the map +STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Your computer took too long to join the server + +############ Leave those lines in this order!! +STR_NETWORK_ERROR_CLIENT_GENERAL :general error +STR_NETWORK_ERROR_CLIENT_DESYNC :desync error +STR_NETWORK_ERROR_CLIENT_SAVEGAME :could not load map +STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST :connection lost +STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR :protocol error +STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH :NewGRF mismatch +STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED :not authorized +STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED :received invalid or unexpected packet +STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :wrong revision +STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :name already in use +STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :wrong password +STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :wrong company in DoCommand +STR_NETWORK_ERROR_CLIENT_KICKED :kicked by server +STR_NETWORK_ERROR_CLIENT_CHEATER :was trying to use a cheat +STR_NETWORK_ERROR_CLIENT_SERVER_FULL :server full +STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS :was sending too many commands +STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :received no password in time +STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :general timeout +STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :downloading map took too long +STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :processing map took too long +############ End of leave-in-this-order + +STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible connection loss +STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}The last {NUM} second{P "" s} no data has arrived from the server + +# Network related errors +STR_NETWORK_SERVER_MESSAGE :*** {1:RAW_STRING} +############ Leave those lines in this order!! +STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED :Game paused ({STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Game still paused ({STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Game still paused ({STRING}, {STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Game still paused ({STRING}, {STRING}, {STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Game still paused ({STRING}, {STRING}, {STRING}, {STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Game unpaused ({STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :number of players +STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :connecting clients +STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :manual +STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :game script +############ End of leave-in-this-order +STR_NETWORK_MESSAGE_CLIENT_LEAVING :leaving +STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {RAW_STRING} has joined the game +STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {RAW_STRING} has joined the game (Client #{2:NUM}) +STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {RAW_STRING} has joined company #{2:NUM} +STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {RAW_STRING} has joined spectators +STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {RAW_STRING} has started a new company (#{2:NUM}) +STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {RAW_STRING} has left the game ({2:STRING}) +STR_NETWORK_MESSAGE_NAME_CHANGE :*** {RAW_STRING} has changed his/her name to {RAW_STRING} +STR_NETWORK_MESSAGE_GIVE_MONEY :*** {RAW_STRING} gave your company {2:CURRENCY_LONG} +STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** You gave {1:RAW_STRING} {2:CURRENCY_LONG} +STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}The server closed the session +STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}The server is restarting...{}Please wait... + +# Content downloading window +STR_CONTENT_TITLE :{WHITE}Content downloading +STR_CONTENT_TYPE_CAPTION :{BLACK}Type +STR_CONTENT_TYPE_CAPTION_TOOLTIP :{BLACK}Type of the content +STR_CONTENT_NAME_CAPTION :{BLACK}Name +STR_CONTENT_NAME_CAPTION_TOOLTIP :{BLACK}Name of the content +STR_CONTENT_MATRIX_TOOLTIP :{BLACK}Click on a line to see the details{}Click on the checkbox to select it for downloading +STR_CONTENT_SELECT_ALL_CAPTION :{BLACK}Select all +STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP :{BLACK}Mark all content to be downloaded +STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}Select upgrades +STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP :{BLACK}Mark all content that is an upgrade for existing content to be downloaded +STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}Unselect all +STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP :{BLACK}Mark all content to be not downloaded +STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Search external websites +STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}Search content not available on OpenTTD's content service on websites not associated to OpenTTD +STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}You are leaving OpenTTD! +STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}The terms and conditions for downloading content from external websites vary.{}You will have to refer to the external sites for instructions how to install the content into OpenTTD.{}Do you want to continue? +STR_CONTENT_FILTER_TITLE :{BLACK}Tag/name filter: +STR_CONTENT_OPEN_URL :{BLACK}Visit website +STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Visit the website for this content +STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Download +STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}Start downloading the selected content +STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}Total download size: {WHITE}{BYTES} +STR_CONTENT_DETAIL_TITLE :{SILVER}CONTENT INFO +STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}You have not selected this to be downloaded +STR_CONTENT_DETAIL_SUBTITLE_SELECTED :{SILVER}You have selected this to be downloaded +STR_CONTENT_DETAIL_SUBTITLE_AUTOSELECTED :{SILVER}This dependency has been selected to be downloaded +STR_CONTENT_DETAIL_SUBTITLE_ALREADY_HERE :{SILVER}You already have this +STR_CONTENT_DETAIL_SUBTITLE_DOES_NOT_EXIST :{SILVER}This content is unknown and can't be downloaded in OpenTTD +STR_CONTENT_DETAIL_UPDATE :{SILVER}This is a replacement for an existing {STRING} +STR_CONTENT_DETAIL_NAME :{SILVER}Name: {WHITE}{RAW_STRING} +STR_CONTENT_DETAIL_VERSION :{SILVER}Version: {WHITE}{RAW_STRING} +STR_CONTENT_DETAIL_DESCRIPTION :{SILVER}Description: {WHITE}{RAW_STRING} +STR_CONTENT_DETAIL_URL :{SILVER}URL: {WHITE}{RAW_STRING} +STR_CONTENT_DETAIL_TYPE :{SILVER}Type: {WHITE}{STRING} +STR_CONTENT_DETAIL_FILESIZE :{SILVER}Download size: {WHITE}{BYTES} +STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF :{SILVER}Selected because of: {WHITE}{RAW_STRING} +STR_CONTENT_DETAIL_DEPENDENCIES :{SILVER}Dependencies: {WHITE}{RAW_STRING} +STR_CONTENT_DETAIL_TAGS :{SILVER}Tags: {WHITE}{RAW_STRING} +STR_CONTENT_NO_ZLIB :{WHITE}OpenTTD is built without "zlib" support... +STR_CONTENT_NO_ZLIB_SUB :{WHITE}... downloading content is not possible! + +# Order of these is important! +STR_CONTENT_TYPE_BASE_GRAPHICS :Base graphics +STR_CONTENT_TYPE_NEWGRF :NewGRF +STR_CONTENT_TYPE_AI :AI +STR_CONTENT_TYPE_AI_LIBRARY :AI library +STR_CONTENT_TYPE_SCENARIO :Scenario +STR_CONTENT_TYPE_HEIGHTMAP :Heightmap +STR_CONTENT_TYPE_BASE_SOUNDS :Base sounds +STR_CONTENT_TYPE_BASE_MUSIC :Base music +STR_CONTENT_TYPE_GAME_SCRIPT :Game script +STR_CONTENT_TYPE_GS_LIBRARY :GS library + +# Content downloading progress window +STR_CONTENT_DOWNLOAD_TITLE :{WHITE}Downloading content... +STR_CONTENT_DOWNLOAD_INITIALISE :{WHITE}Requesting files... +STR_CONTENT_DOWNLOAD_FILE :{WHITE}Currently downloading {RAW_STRING} ({NUM} of {NUM}) +STR_CONTENT_DOWNLOAD_COMPLETE :{WHITE}Download complete +STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} of {BYTES} downloaded ({NUM} %) + +# Content downloading error messages +STR_CONTENT_ERROR_COULD_NOT_CONNECT :{WHITE}Could not connect to the content server... +STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}Downloading failed... +STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_CONNECTION_LOST :{WHITE}... connection lost +STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... file not writable +STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}Could not decompress the downloaded file + +STR_MISSING_GRAPHICS_SET_CAPTION :{WHITE}Missing graphics +STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}OpenTTD requires graphics to function but none could be found. Do you allow OpenTTD to download and install these graphics? +STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}Yes, download the graphics +STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}No, exit OpenTTD + +# Transparency settings window +STR_TRANSPARENCY_CAPTION :{WHITE}Transparency Options +STR_TRANSPARENT_SIGNS_TOOLTIP :{BLACK}Toggle transparency for signs. Ctrl+Click to lock +STR_TRANSPARENT_TREES_TOOLTIP :{BLACK}Toggle transparency for trees. Ctrl+Click to lock +STR_TRANSPARENT_HOUSES_TOOLTIP :{BLACK}Toggle transparency for houses. Ctrl+Click to lock +STR_TRANSPARENT_INDUSTRIES_TOOLTIP :{BLACK}Toggle transparency for industries. Ctrl+Click to lock +STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Toggle transparency for buildables like stations, depots and waypoints. Ctrl+Click to lock +STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Toggle transparency for bridges. Ctrl+Click to lock +STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Toggle transparency for structures like lighthouses and antennas. Ctrl+Click to lock +STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Toggle transparency for catenary. Ctrl+Click to lock +STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Toggle transparency for loading indicators. Ctrl+Click to lock +STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Set objects invisible instead of transparent + +# Linkgraph legend window +STR_LINKGRAPH_LEGEND_CAPTION :{BLACK}Cargo Flow Legend +STR_LINKGRAPH_LEGEND_ALL :{BLACK}All +STR_LINKGRAPH_LEGEND_NONE :{BLACK}None +STR_LINKGRAPH_LEGEND_SELECT_COMPANIES :{BLACK}Select companies to be displayed + +# Linkgraph legend window and linkgraph legend in smallmap +STR_LINKGRAPH_LEGEND_UNUSED :{TINY_FONT}{BLACK}unused +STR_LINKGRAPH_LEGEND_SATURATED :{TINY_FONT}{BLACK}saturated +STR_LINKGRAPH_LEGEND_OVERLOADED :{TINY_FONT}{BLACK}overloaded + +# Base for station construction window(s) +STR_STATION_BUILD_COVERAGE_AREA_TITLE :{BLACK}Coverage area highlight +STR_STATION_BUILD_COVERAGE_OFF :{BLACK}Off +STR_STATION_BUILD_COVERAGE_ON :{BLACK}On +STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP :{BLACK}Don't highlight coverage area of proposed site +STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP :{BLACK}Highlight coverage area of proposed site +STR_STATION_BUILD_ACCEPTS_CARGO :{BLACK}Accepts: {GOLD}{CARGO_LIST} +STR_STATION_BUILD_SUPPLIES_CARGO :{BLACK}Supplies: {GOLD}{CARGO_LIST} + +# Join station window +STR_JOIN_STATION_CAPTION :{WHITE}Join station +STR_JOIN_STATION_CREATE_SPLITTED_STATION :{YELLOW}Build a separate station + +STR_JOIN_WAYPOINT_CAPTION :{WHITE}Join waypoint +STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT :{YELLOW}Build a separate waypoint + +# Rail construction toolbar +STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION :Railway Construction +STR_RAIL_TOOLBAR_ELRAIL_CONSTRUCTION_CAPTION :Electrified Railway Construction +STR_RAIL_TOOLBAR_MONORAIL_CONSTRUCTION_CAPTION :Monorail Construction +STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :Maglev Construction + +STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Build railway track. Ctrl toggles build/remove for railway construction. Shift toggles building/showing cost estimate +STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}Build railway track using the Autorail mode. Ctrl toggles build/remove for railway construction. Shift toggles building/showing cost estimate +STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Build train depot (for buying and servicing trains). Shift toggles building/showing cost estimate +STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Convert rail to waypoint. Ctrl enables joining waypoints. Shift toggles building/showing cost estimate +STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}Build railway station. Ctrl enables joining stations. Shift toggles building/showing cost estimate +STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Build railway signals. Ctrl toggles semaphore/light signals{}Dragging builds signals along a straight stretch of rail. Ctrl builds signals till the next junction{}Ctrl+Click toggles opening the signal selection window. Shift toggles building/showing cost estimate +STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}Build railway bridge. Shift toggles building/showing cost estimate +STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}Build railway tunnel. Shift toggles building/showing cost estimate +STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Toggle build/remove for railway track, signals, waypoints and stations. Hold Ctrl to also remove the rail of waypoints and stations +STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL :{BLACK}Convert/Upgrade the type of rail. Shift toggles building/showing cost estimate + +STR_RAIL_NAME_RAILROAD :Railway +STR_RAIL_NAME_ELRAIL :Electrified railway +STR_RAIL_NAME_MONORAIL :Monorail +STR_RAIL_NAME_MAGLEV :Maglev + +# Rail depot construction window +STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION :{WHITE}Train Depot Orientation +STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP :{BLACK}Select railway depot orientation + +# Rail waypoint construction window +STR_WAYPOINT_CAPTION :{WHITE}Waypoint +STR_WAYPOINT_GRAPHICS_TOOLTIP :{BLACK}Select waypoint type + +# Rail station construction window +STR_STATION_BUILD_RAIL_CAPTION :{WHITE}Rail Station Selection +STR_STATION_BUILD_ORIENTATION :{BLACK}Orientation +STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP :{BLACK}Select railway station orientation +STR_STATION_BUILD_NUMBER_OF_TRACKS :{BLACK}Number of tracks +STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP :{BLACK}Select number of platforms for railway station +STR_STATION_BUILD_PLATFORM_LENGTH :{BLACK}Platform length +STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP :{BLACK}Select length of railway station +STR_STATION_BUILD_DRAG_DROP :{BLACK}Drag & Drop +STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Build a station using drag & drop + +STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Select a station class to display +STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Select the station type to build + +STR_STATION_CLASS_DFLT :Default station +STR_STATION_CLASS_WAYP :Waypoints + +# Signal window +STR_BUILD_SIGNAL_CAPTION :{WHITE}Signal Selection +STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP :{BLACK}Block Signal (semaphore){}This is the most basic type of signal, allowing only one train to be in the same block at the same time +STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP :{BLACK}Entry Signal (semaphore){}Green as long as there is one or more green exit-signal from the following section of track. Otherwise it shows red +STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP :{BLACK}Exit Signal (semaphore){}Behaves in the same way as a block signal but is necessary to trigger the correct colour on entry & combo pre-signals +STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP :{BLACK}Combo Signal (semaphore){}The combo signal simply acts as both an entry and exit signal. This allows you to build large "trees" of pre-signals +STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP :{BLACK}Path Signal (semaphore){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. Standard path signals can be passed from the back side +STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP :{BLACK}One-way Path Signal (semaphore){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. One-way path signals can't be passed from the back side +STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP :{BLACK}Block Signal (electric){}This is the most basic type of signal, allowing only one train to be in the same block at the same time +STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP :{BLACK}Entry Signal (electric){}Green as long as there is one or more green exit-signal from the following section of track. Otherwise it shows red +STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP :{BLACK}Exit Signal (electric){}Behaves in the same way as a block signal but is necessary to trigger the correct colour on entry & combo pre-signals +STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Combo Signal (electric){}The combo signal simply acts as both an entry and exit signal. This allows you to build large "trees" of pre-signals +STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}Path Signal (electric){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. Standard path signals can be passed from the back side +STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}One-way Path Signal (electric){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. One-way path signals can't be passed from the back side +STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Signal Convert{}When selected, clicking an existing signal will convert it to the selected signal type and variant. Ctrl+Click will toggle the existing variant. Shift+Click shows estimated conversion cost +STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Dragging signal density +STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Decrease dragging signal density +STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Increase dragging signal density + +# Bridge selection window +STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Select Rail Bridge +STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Select Road Bridge +STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Bridge selection - click on your preferred bridge to build it +STR_SELECT_BRIDGE_INFO :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} +STR_SELECT_BRIDGE_SCENEDIT_INFO :{GOLD}{STRING},{} {VELOCITY} +STR_BRIDGE_NAME_SUSPENSION_STEEL :Suspension, Steel +STR_BRIDGE_NAME_GIRDER_STEEL :Girder, Steel +STR_BRIDGE_NAME_CANTILEVER_STEEL :Cantilever, Steel +STR_BRIDGE_NAME_SUSPENSION_CONCRETE :Suspension, Concrete +STR_BRIDGE_NAME_WOODEN :Wooden +STR_BRIDGE_NAME_CONCRETE :Concrete +STR_BRIDGE_NAME_TUBULAR_STEEL :Tubular, Steel +STR_BRIDGE_TUBULAR_SILICON :Tubular, Silicon + + +# Road construction toolbar +STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION :{WHITE}Road Construction +STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}Tramway Construction +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}Build road section. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}Build tramway section. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}Build road section using the Autoroad mode. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Build tramway section using the Autotram mode. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Build road vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Build tram vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}Build bus station. Ctrl enables joining stations. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}Build passenger tram station. Ctrl enables joining stations. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}Build lorry loading bay. Ctrl enables joining stations. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION :{BLACK}Build freight tram station. Ctrl enables joining stations. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD :{BLACK}Activate/Deactivate one way roads +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE :{BLACK}Build road bridge. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE :{BLACK}Build tramway bridge. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Build road tunnel. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Build tramway tunnel. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Toggle build/remove for road construction +STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Toggle build/remove for tramway construction + +# Road depot construction window +STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Road Depot Orientation +STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Select road vehicle depot orientation +STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION :{WHITE}Tram Depot Orientation +STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Select tram vehicle depot orientation + +# Road vehicle station construction window +STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}Bus Station Orientation +STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP :{BLACK}Select bus station orientation +STR_STATION_BUILD_TRUCK_ORIENTATION :{WHITE}Lorry Station Orientation +STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Select lorry loading bay orientation +STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION :{WHITE}Passenger Tram Station Orientation +STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP :{BLACK}Select passenger tram station orientation +STR_STATION_BUILD_CARGO_TRAM_ORIENTATION :{WHITE}Freight Tram Station Orientation +STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP :{BLACK}Select freight tram station orientation + +# Waterways toolbar (last two for SE only) +STR_WATERWAYS_TOOLBAR_CAPTION :{WHITE}Waterways Construction +STR_WATERWAYS_TOOLBAR_CAPTION_SE :{WHITE}Waterways +STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Build canals. Shift toggles building/showing cost estimate +STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}Build locks. Shift toggles building/showing cost estimate +STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}Build ship depot (for buying and servicing ships). Shift toggles building/showing cost estimate +STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Build ship dock. Ctrl enables joining stations. Shift toggles building/showing cost estimate +STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Place a buoy which can be used as a waypoint. Shift toggles building/showing cost estimate +STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Build aqueduct. Shift toggles building/showing cost estimate +STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Define water area.{}Make a canal, unless Ctrl is held down at sea level, when it will flood the surroundings instead +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Place rivers + +# Ship depot construction window +STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Ship Depot Orientation +STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP :{BLACK}Select ship depot orientation + +# Dock construction window +STR_STATION_BUILD_DOCK_CAPTION :{WHITE}Dock + +# Airport toolbar +STR_TOOLBAR_AIRCRAFT_CAPTION :{WHITE}Airports +STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP :{BLACK}Build airport. Ctrl enables joining stations. Shift toggles building/showing cost estimate + +# Airport construction window +STR_STATION_BUILD_AIRPORT_CAPTION :{WHITE}Airport Selection +STR_STATION_BUILD_AIRPORT_TOOLTIP :{BLACK}Select size/type of airport +STR_STATION_BUILD_AIRPORT_CLASS_LABEL :{BLACK}Airport class +STR_STATION_BUILD_AIRPORT_LAYOUT_NAME :{BLACK}Layout {NUM} + +STR_AIRPORT_SMALL :Small +STR_AIRPORT_CITY :City +STR_AIRPORT_METRO :Metropolitan +STR_AIRPORT_INTERNATIONAL :International +STR_AIRPORT_COMMUTER :Commuter +STR_AIRPORT_INTERCONTINENTAL :Intercontinental +STR_AIRPORT_HELIPORT :Heliport +STR_AIRPORT_HELIDEPOT :Helidepot +STR_AIRPORT_HELISTATION :Helistation + +STR_AIRPORT_CLASS_SMALL :Small airports +STR_AIRPORT_CLASS_LARGE :Large airports +STR_AIRPORT_CLASS_HUB :Hub airports +STR_AIRPORT_CLASS_HELIPORTS :Helicopter airports + +STR_STATION_BUILD_NOISE :{BLACK}Noise generated: {GOLD}{COMMA} + +# Landscaping toolbar +STR_LANDSCAPING_TOOLBAR :{WHITE}Landscaping +STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}Lower a corner of land. Dragging lowers the first selected corner and levels the selected area to the new corner height. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate +STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Raise a corner of land. Dragging raises the first selected corner and levels the selected area to the new corner height. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate +STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Level an area of land to the height of the first selected corner. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate +STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Purchase land for future use. Shift toggles building/showing cost estimate + +# Object construction window +STR_OBJECT_BUILD_CAPTION :{WHITE}Object Selection +STR_OBJECT_BUILD_TOOLTIP :{BLACK}Select object to build. Shift toggles building/showing cost estimate +STR_OBJECT_BUILD_CLASS_TOOLTIP :{BLACK}Select class of the object to build +STR_OBJECT_BUILD_PREVIEW_TOOLTIP :{BLACK}Preview of the object +STR_OBJECT_BUILD_SIZE :{BLACK}Size: {GOLD}{NUM} x {NUM} tiles + +STR_OBJECT_CLASS_LTHS :Lighthouses +STR_OBJECT_CLASS_TRNS :Transmitters + +# Tree planting window (last two for SE only) +STR_PLANT_TREE_CAPTION :{WHITE}Trees +STR_PLANT_TREE_TOOLTIP :{BLACK}Select tree type to plant. If the tile already has a tree, this will add more trees of mixed types independent of the selected type +STR_TREES_RANDOM_TYPE :{BLACK}Trees of random type +STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Place trees of random type. Shift toggles building/showing cost estimate +STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Random Trees +STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Plant trees randomly throughout the landscape + +# Land generation window (SE) +STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Land Generation +STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}Place rocky areas on landscape +STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA :{BLACK}Define desert area.{}Hold Ctrl to remove it +STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Increase area of land to lower/raise +STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Decrease area of land to lower/raise +STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND :{BLACK}Generate random land +STR_TERRAFORM_SE_NEW_WORLD :{BLACK}Create new scenario +STR_TERRAFORM_RESET_LANDSCAPE :{BLACK}Reset landscape +STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP :{BLACK}Remove all company-owned property from the map + +STR_QUERY_RESET_LANDSCAPE_CAPTION :{WHITE}Reset Landscape +STR_RESET_LANDSCAPE_CONFIRMATION_TEXT :{WHITE}Are you sure you want to remove all company-owned property? + +# Town generation window (SE) +STR_FOUND_TOWN_CAPTION :{WHITE}Town Generation +STR_FOUND_TOWN_NEW_TOWN_BUTTON :{BLACK}New Town +STR_FOUND_TOWN_NEW_TOWN_TOOLTIP :{BLACK}Found new town. Shift+Click shows only estimated cost +STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Random Town +STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Found town in random location +STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Many random towns +STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Cover the map with randomly placed towns + +STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Town name: +STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Enter town name +STR_FOUND_TOWN_NAME_EDITOR_HELP :{BLACK}Click to enter town name +STR_FOUND_TOWN_NAME_RANDOM_BUTTON :{BLACK}Random name +STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP :{BLACK}Generate new random name + +STR_FOUND_TOWN_INITIAL_SIZE_TITLE :{YELLOW}Town size: +STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON :{BLACK}Small +STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON :{BLACK}Medium +STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON :{BLACK}Large +STR_FOUND_TOWN_SIZE_RANDOM :{BLACK}Random +STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Select town size +STR_FOUND_TOWN_CITY :{BLACK}City +STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Cities grow faster than regular towns{}Depending on settings, they are bigger when founded + +STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Town road layout: +STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT :{BLACK}Select road layout used for this town +STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL :{BLACK}Original +STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS :{BLACK}Better roads +STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID :{BLACK}2x2 grid +STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID :{BLACK}3x3 grid +STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM :{BLACK}Random + +# Fund new industry window +STR_FUND_INDUSTRY_CAPTION :{WHITE}Fund new industry +STR_FUND_INDUSTRY_SELECTION_TOOLTIP :{BLACK}Choose the appropriate industry from this list +STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :Many random industries +STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}Cover the map with randomly placed industries +STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}Cost: {YELLOW}{CURRENCY_LONG} +STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Prospect +STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}Build +STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}Fund + +# Industry cargoes window +STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}Industry chain for {STRING} industry +STR_INDUSTRY_CARGOES_CARGO_CAPTION :{WHITE}Industry chain for {STRING} cargo +STR_INDUSTRY_CARGOES_PRODUCERS :{WHITE}Producing industries +STR_INDUSTRY_CARGOES_CUSTOMERS :{WHITE}Accepting industries +STR_INDUSTRY_CARGOES_HOUSES :{WHITE}Houses +STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP :{BLACK}Click at the industry to see its suppliers and customers +STR_INDUSTRY_CARGOES_CARGO_TOOLTIP :{BLACK}{STRING}{}Click at the cargo to see its suppliers and customers +STR_INDUSTRY_DISPLAY_CHAIN :{BLACK}Display chain +STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP :{BLACK}Display cargo supplying and accepting industries +STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP :{BLACK}Link to smallmap +STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP :{BLACK}Select the displayed industries at the smallmap as well +STR_INDUSTRY_CARGOES_SELECT_CARGO :{BLACK}Select cargo +STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP :{BLACK}Select the cargo you want to display +STR_INDUSTRY_CARGOES_SELECT_INDUSTRY :{BLACK}Select industry +STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}Select the industry you want to display + +# Land area window +STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}Land Area Information +STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Cost to clear: {LTBLUE}N/A +STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Cost to clear: {RED}{CURRENCY_LONG} +STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}Revenue when cleared: {LTBLUE}{CURRENCY_LONG} +STR_LAND_AREA_INFORMATION_OWNER_N_A :N/A +STR_LAND_AREA_INFORMATION_OWNER :{BLACK}Owner: {LTBLUE}{STRING1} +STR_LAND_AREA_INFORMATION_ROAD_OWNER :{BLACK}Road owner: {LTBLUE}{STRING1} +STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tramway owner: {LTBLUE}{STRING1} +STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Railway owner: {LTBLUE}{STRING1} +STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Local authority: {LTBLUE}{STRING1} +STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :None +STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinates: {LTBLUE}{NUM} x {NUM} x {NUM} ({RAW_STRING}) +STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built: {LTBLUE}{DATE_LONG} +STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Station class: {LTBLUE}{STRING} +STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Station type: {LTBLUE}{STRING} +STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Airport class: {LTBLUE}{STRING} +STR_LAND_AREA_INFORMATION_AIRPORT_NAME :{BLACK}Airport name: {LTBLUE}{STRING} +STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}Airport tile name: {LTBLUE}{STRING} +STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: {LTBLUE}{RAW_STRING} +STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Cargo accepted: {LTBLUE} +STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) +STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Rail speed limit: {LTBLUE}{VELOCITY} +STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Road speed limit: {LTBLUE}{VELOCITY} + +# Description of land area of different tiles +STR_LAI_CLEAR_DESCRIPTION_ROCKS :Rocks +STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND :Rough land +STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Bare land +STR_LAI_CLEAR_DESCRIPTION_GRASS :Grass +STR_LAI_CLEAR_DESCRIPTION_FIELDS :Fields +STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND :Snow-covered land +STR_LAI_CLEAR_DESCRIPTION_DESERT :Desert + +STR_LAI_RAIL_DESCRIPTION_TRACK :{STRING} track +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :{STRING} track with block signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS :{STRING} track with pre-signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS :{STRING} track with exit-signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS :{STRING} track with combo-signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS :{STRING} track with path signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS :{STRING} track with one-way path signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS :{STRING} track with block and pre-signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS :{STRING} track with block and exit-signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS :{STRING} track with block and combo-signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS :{STRING} track with block and path signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS :{STRING} track with block and one-way path signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS :{STRING} track with pre- and exit-signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS :{STRING} track with pre- and combo-signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS :{STRING} track with pre- and path signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS :{STRING} track with pre- and one-way path signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS :{STRING} track with exit- and combo-signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS :{STRING} track with exit- and path signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS :{STRING} track with exit- and one-way path signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS :{STRING} track with combo- and path signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :{STRING} track with combo- and one-way path signals +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :{STRING} track with path and one-way path signals +STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :{STRING} train depot + +STR_LAI_ROAD_DESCRIPTION_ROAD :Road +STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Road with street lights +STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Tree-lined road +STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT :Road vehicle depot +STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING :Road/rail level crossing +STR_LAI_ROAD_DESCRIPTION_TRAMWAY :Tramway + +# Houses come directly from their building names +STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION :{STRING} (under construction) + +STR_LAI_TREE_NAME_TREES :Trees +STR_LAI_TREE_NAME_RAINFOREST :Rainforest +STR_LAI_TREE_NAME_CACTUS_PLANTS :Cactus plants + +STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION :Railway station +STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR :Aircraft hangar +STR_LAI_STATION_DESCRIPTION_AIRPORT :Airport +STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Lorry loading area +STR_LAI_STATION_DESCRIPTION_BUS_STATION :Bus station +STR_LAI_STATION_DESCRIPTION_SHIP_DOCK :Ship dock +STR_LAI_STATION_DESCRIPTION_BUOY :Buoy +STR_LAI_STATION_DESCRIPTION_WAYPOINT :Waypoint + +STR_LAI_WATER_DESCRIPTION_WATER :Water +STR_LAI_WATER_DESCRIPTION_CANAL :Canal +STR_LAI_WATER_DESCRIPTION_LOCK :Lock +STR_LAI_WATER_DESCRIPTION_RIVER :River +STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK :Coast or riverbank +STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Ship depot + +# Industries come directly from their industry names + +STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :Railway tunnel +STR_LAI_TUNNEL_DESCRIPTION_ROAD :Road tunnel + +STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Steel suspension rail bridge +STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :Steel girder rail bridge +STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL :Steel cantilever rail bridge +STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE :Reinforced concrete suspension rail bridge +STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN :Wooden rail bridge +STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE :Concrete rail bridge +STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL :Tubular rail bridge + +STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL :Steel suspension road bridge +STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL :Steel girder road bridge +STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL :Steel cantilever road bridge +STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE :Reinforced concrete suspension road bridge +STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN :Wooden road bridge +STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE :Concrete road bridge +STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL :Tubular road bridge + +STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT :Aqueduct + +STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER :Transmitter +STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE :Lighthouse +STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS :Company headquarters +STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :Company-owned land + +# About OpenTTD window +STR_ABOUT_OPENTTD :{WHITE}About OpenTTD +STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Original copyright {COPYRIGHT} 1995 Chris Sawyer, All rights reserved +STR_ABOUT_VERSION :{BLACK}OpenTTD version {REV} +STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT} 2002-2014 The OpenTTD team + +# Save/load game/scenario +STR_SAVELOAD_SAVE_CAPTION :{WHITE}Save Game +STR_SAVELOAD_LOAD_CAPTION :{WHITE}Load Game +STR_SAVELOAD_SAVE_SCENARIO :{WHITE}Save Scenario +STR_SAVELOAD_LOAD_SCENARIO :{WHITE}Load Scenario +STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}Load Heightmap +STR_SAVELOAD_SAVE_HEIGHTMAP :{WHITE}Save Heightmap +STR_SAVELOAD_HOME_BUTTON :{BLACK}Click here to jump to the current default save/load directory +STR_SAVELOAD_BYTES_FREE :{BLACK}{BYTES} free +STR_SAVELOAD_LIST_TOOLTIP :{BLACK}List of drives, directories and saved-game files +STR_SAVELOAD_EDITBOX_TOOLTIP :{BLACK}Currently selected name for saved-game +STR_SAVELOAD_DELETE_BUTTON :{BLACK}Delete +STR_SAVELOAD_DELETE_TOOLTIP :{BLACK}Delete the currently selected saved-game +STR_SAVELOAD_SAVE_BUTTON :{BLACK}Save +STR_SAVELOAD_SAVE_TOOLTIP :{BLACK}Save the current game, using the selected name +STR_SAVELOAD_LOAD_BUTTON :{BLACK}Load +STR_SAVELOAD_LOAD_TOOLTIP :{BLACK}Load the selected game +STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Game Details +STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}No information available +STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING1} +STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} + +STR_SAVELOAD_OSKTITLE :{BLACK}Enter a name for the savegame + +# World generation +STR_MAPGEN_WORLD_GENERATION_CAPTION :{WHITE}World Generation +STR_MAPGEN_MAPSIZE :{BLACK}Map size: +STR_MAPGEN_MAPSIZE_TOOLTIP :{BLACK}Select the size of the map in tiles. The number of available tiles will be slightly smaller +STR_MAPGEN_BY :{BLACK}* +STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}No. of towns: +STR_MAPGEN_DATE :{BLACK}Date: +STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}No. of industries: +STR_MAPGEN_SNOW_LINE_HEIGHT :{BLACK}Snow line height: +STR_MAPGEN_SNOW_LINE_UP :{BLACK}Move the snow line height one up +STR_MAPGEN_SNOW_LINE_DOWN :{BLACK}Move the snow line height one down +STR_MAPGEN_RANDOM_SEED :{BLACK}Random seed: +STR_MAPGEN_RANDOM_SEED_HELP :{BLACK}Click to enter a random seed +STR_MAPGEN_RANDOM :{BLACK}Randomise +STR_MAPGEN_RANDOM_HELP :{BLACK}Change the random seed used for Terrain Generation +STR_MAPGEN_LAND_GENERATOR :{BLACK}Land generator: +STR_MAPGEN_TREE_PLACER :{BLACK}Tree algorithm: +STR_MAPGEN_TERRAIN_TYPE :{BLACK}Terrain type: +STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}Sea level: +STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}Rivers: +STR_MAPGEN_SMOOTHNESS :{BLACK}Smoothness: +STR_MAPGEN_VARIETY :{BLACK}Variety distribution: +STR_MAPGEN_GENERATE :{WHITE}Generate + +# Strings for map borders at game generation +STR_MAPGEN_BORDER_TYPE :{BLACK}Map edges: +STR_MAPGEN_NORTHWEST :{BLACK}Northwest +STR_MAPGEN_NORTHEAST :{BLACK}Northeast +STR_MAPGEN_SOUTHEAST :{BLACK}Southeast +STR_MAPGEN_SOUTHWEST :{BLACK}Southwest +STR_MAPGEN_BORDER_FREEFORM :{BLACK}Freeform +STR_MAPGEN_BORDER_WATER :{BLACK}Water +STR_MAPGEN_BORDER_RANDOM :{BLACK}Random +STR_MAPGEN_BORDER_RANDOMIZE :{BLACK}Random +STR_MAPGEN_BORDER_MANUAL :{BLACK}Manual + +STR_MAPGEN_HEIGHTMAP_ROTATION :{BLACK}Heightmap rotation: +STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}Heightmap name: +STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}Size: +STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} x {NUM} + +STR_MAPGEN_RANDOM_SEED_OSKTITLE :{BLACK}Enter a random seed +STR_MAPGEN_SNOW_LINE_QUERY_CAPT :{WHITE}Change snow line height +STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}Change starting year + +# SE Map generation +STR_SE_MAPGEN_CAPTION :{WHITE}Scenario Type +STR_SE_MAPGEN_FLAT_WORLD :{WHITE}Flat land +STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP :{BLACK}Generate a flat land +STR_SE_MAPGEN_RANDOM_LAND :{WHITE}Random land +STR_SE_MAPGEN_FLAT_WORLD_HEIGHT :{BLACK}Height of flat land: +STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_DOWN :{BLACK}Move the height of flat land one down +STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_UP :{BLACK}Move the height of flat land one up + +STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Change height of flat land + +# Map generation progress +STR_GENERATION_WORLD :{WHITE}Generating World... +STR_GENERATION_ABORT :{BLACK}Abort +STR_GENERATION_ABORT_CAPTION :{WHITE}Abort World Generation +STR_GENERATION_ABORT_MESSAGE :{YELLOW}Do you really want to abort the generation? +STR_GENERATION_PROGRESS :{WHITE}{NUM}% complete +STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM} +STR_GENERATION_WORLD_GENERATION :{BLACK}World generation +STR_GENERATION_RIVER_GENERATION :{BLACK}River generation +STR_GENERATION_TREE_GENERATION :{BLACK}Tree generation +STR_GENERATION_OBJECT_GENERATION :{BLACK}Object generation +STR_GENERATION_CLEARING_TILES :{BLACK}Rough and rocky area generation +STR_GENERATION_SETTINGUP_GAME :{BLACK}Setting up game +STR_GENERATION_PREPARING_TILELOOP :{BLACK}Running tile-loop +STR_GENERATION_PREPARING_SCRIPT :{BLACK}Running script +STR_GENERATION_PREPARING_GAME :{BLACK}Preparing game + +# NewGRF settings +STR_NEWGRF_SETTINGS_CAPTION :{WHITE}NewGRF Settings +STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}Detailed NewGRF information +STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}Active NewGRF files +STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}Inactive NewGRF files +STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}Select preset: +STR_NEWGRF_FILTER_TITLE :{ORANGE}Filter string: +STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}Load the selected preset +STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}Save preset +STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}Save the current list as a preset +STR_NEWGRF_SETTINGS_PRESET_SAVE_QUERY :{BLACK}Enter name for preset +STR_NEWGRF_SETTINGS_PRESET_DELETE :{BLACK}Delete preset +STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP :{BLACK}Delete the currently selected preset +STR_NEWGRF_SETTINGS_ADD :{BLACK}Add +STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP :{BLACK}Add the selected NewGRF file to your configuration +STR_NEWGRF_SETTINGS_RESCAN_FILES :{BLACK}Rescan files +STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP :{BLACK}Update the list of available NewGRF files +STR_NEWGRF_SETTINGS_REMOVE :{BLACK}Remove +STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP :{BLACK}Remove the selected NewGRF file from the list +STR_NEWGRF_SETTINGS_MOVEUP :{BLACK}Move Up +STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP :{BLACK}Move the selected NewGRF file up the list +STR_NEWGRF_SETTINGS_MOVEDOWN :{BLACK}Move Down +STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP :{BLACK}Move the selected NewGRF file down the list +STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}A list of the NewGRF files that are installed + +STR_NEWGRF_SETTINGS_SET_PARAMETERS :{BLACK}Set parameters +STR_NEWGRF_SETTINGS_SHOW_PARAMETERS :{BLACK}Show parameters +STR_NEWGRF_SETTINGS_TOGGLE_PALETTE :{BLACK}Toggle palette +STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP :{BLACK}Toggle the palette of the selected NewGRF.{}Do this when the graphics from this NewGRF look pink in-game +STR_NEWGRF_SETTINGS_APPLY_CHANGES :{BLACK}Apply changes + +STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON :{BLACK}Find missing content online +STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP :{BLACK}Check whether the missing content can be found online + +STR_NEWGRF_SETTINGS_FILENAME :{BLACK}Filename: {SILVER}{RAW_STRING} +STR_NEWGRF_SETTINGS_GRF_ID :{BLACK}GRF ID: {SILVER}{RAW_STRING} +STR_NEWGRF_SETTINGS_VERSION :{BLACK}Version: {SILVER}{NUM} +STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}Min. compatible version: {SILVER}{NUM} +STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{RAW_STRING} +STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Palette: {SILVER}{RAW_STRING} +STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parameters: {SILVER}{STRING1} + +STR_NEWGRF_SETTINGS_NO_INFO :{BLACK}No information available +STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}Matching file not found +STR_NEWGRF_SETTINGS_DISABLED :{RED}Disabled +STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}Incompatible with this version of OpenTTD + +# NewGRF parameters window +STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Change NewGRF parameters +STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Close +STR_NEWGRF_PARAMETERS_RESET :{BLACK}Reset +STR_NEWGRF_PARAMETERS_RESET_TOOLTIP :{BLACK}Set all parameters to their default value +STR_NEWGRF_PARAMETERS_DEFAULT_NAME :Parameter {NUM} +STR_NEWGRF_PARAMETERS_SETTING :{STRING1}: {ORANGE}{STRING1} +STR_NEWGRF_PARAMETERS_NUM_PARAM :{LTBLUE}Number of parameters: {ORANGE}{NUM} + +# NewGRF inspect window +STR_NEWGRF_INSPECT_CAPTION :{WHITE}Inspect - {STRING5} +STR_NEWGRF_INSPECT_PARENT_BUTTON :{BLACK}Parent +STR_NEWGRF_INSPECT_PARENT_TOOLTIP :{BLACK}Inspect the object of the parent scope + +STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING1} at {HEX} +STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT :Object +STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :Rail type + +STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF variable 60+x parameter (hexadecimal) + +# Sprite aligner window +STR_SPRITE_ALIGNER_CAPTION :{WHITE}Aligning sprite {COMMA} ({RAW_STRING}) +STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Next sprite +STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Proceed to the next normal sprite, skipping any pseudo/recolour/font sprites and wrapping around at the end +STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Go to sprite +STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}Go to the given sprite. If the sprite is not a normal sprite, proceed to the next normal sprite +STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Previous sprite +STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Proceed to the previous normal sprite, skipping any pseudo/recolour/font sprites and wrapping around at the begin +STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Representation of the currently selected sprite. The alignment is ignored when drawing this sprite +STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Move the sprite around, changing the X and Y offsets +STR_SPRITE_ALIGNER_OFFSETS :{BLACK}X offset: {NUM}, Y offset: {NUM} +STR_SPRITE_ALIGNER_PICKER_BUTTON :{BLACK}Pick sprite +STR_SPRITE_ALIGNER_PICKER_TOOLTIP :{BLACK}Pick a sprite from anywhere on the screen + +STR_SPRITE_ALIGNER_GOTO_CAPTION :{WHITE}Go to sprite + +# NewGRF (self) generated warnings/errors +STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{RAW_STRING} +STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warning: {SILVER}{RAW_STRING} +STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{RAW_STRING} +STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{RAW_STRING} +STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}A fatal NewGRF error has occurred: {}{STRING5} +STR_NEWGRF_ERROR_VERSION_NUMBER :{1:RAW_STRING} will not work with the TTDPatch version reported by OpenTTD +STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:RAW_STRING} is for the {RAW_STRING} version of TTD +STR_NEWGRF_ERROR_UNSET_SWITCH :{1:RAW_STRING} is designed to be used with {RAW_STRING} +STR_NEWGRF_ERROR_INVALID_PARAMETER :Invalid parameter for {1:RAW_STRING}: parameter {RAW_STRING} ({NUM}) +STR_NEWGRF_ERROR_LOAD_BEFORE :{1:RAW_STRING} must be loaded before {RAW_STRING} +STR_NEWGRF_ERROR_LOAD_AFTER :{1:RAW_STRING} must be loaded after {RAW_STRING} +STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:RAW_STRING} requires OpenTTD version {RAW_STRING} or better +STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :the GRF file it was designed to translate +STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :Too many NewGRFs are loaded +STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Loading {1:RAW_STRING} as static NewGRF with {RAW_STRING} could cause desyncs +STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Unexpected sprite (sprite {3:NUM}) +STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Unknown Action 0 property {4:HEX} (sprite {3:NUM}) +STR_NEWGRF_ERROR_INVALID_ID :Attempt to use invalid ID (sprite {3:NUM}) +STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}{RAW_STRING} contains a corrupt sprite. All corrupt sprites will be shown as a red question mark (?) +STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Contains multiple Action 8 entries (sprite {3:NUM}) +STR_NEWGRF_ERROR_READ_BOUNDS :Read past end of pseudo-sprite (sprite {3:NUM}) +STR_NEWGRF_ERROR_MISSING_SPRITES :{WHITE}The currently used base graphics set is missing a number of sprites.{}Please update the base graphics set +STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE :{WHITE}The currently used base graphics set is missing a number of sprites.{}Please update the base graphics set.{}Since you are playing a {YELLOW}development snapshot of OpenTTD{WHITE}, you might also need a {YELLOW}development snapshot of the base graphics{WHITE} +STR_NEWGRF_ERROR_GRM_FAILED :Requested GRF resources not available (sprite {3:NUM}) +STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:RAW_STRING} was disabled by {2:RAW_STRING} +STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Invalid/unknown sprite layout format (sprite {3:NUM}) + +# NewGRF related 'general' warnings +STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}Caution! +STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}You are about to make changes to a running game. This can crash OpenTTD or break the game state. Do not file bug reports about these issues.{}Are you absolutely sure about this? + +STR_NEWGRF_DUPLICATE_GRFID :{WHITE}Can't add file: duplicate GRF ID +STR_NEWGRF_COMPATIBLE_LOADED :{ORANGE}Matching file not found (compatible GRF loaded) +STR_NEWGRF_TOO_MANY_NEWGRFS :{WHITE}Can't add file: NewGRF file limit reached + +STR_NEWGRF_COMPATIBLE_LOAD_WARNING :{WHITE}Compatible GRF(s) loaded for missing files +STR_NEWGRF_DISABLED_WARNING :{WHITE}Missing GRF file(s) have been disabled +STR_NEWGRF_UNPAUSE_WARNING_TITLE :{YELLOW}Missing GRF file(s) +STR_NEWGRF_UNPAUSE_WARNING :{WHITE}Unpausing can crash OpenTTD. Do not file bug reports for subsequent crashes.{}Do you really want to unpause? + +# NewGRF status +STR_NEWGRF_LIST_NONE :None +STR_NEWGRF_LIST_ALL_FOUND :All files present +STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Found compatible files +STR_NEWGRF_LIST_MISSING :{RED}Missing files + +# NewGRF 'it's broken' warnings +STR_NEWGRF_BROKEN :{WHITE}Behaviour of NewGRF '{0:RAW_STRING}' is likely to cause desyncs and/or crashes +STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}It changed powered-wagon state for '{1:ENGINE}' when not inside a depot +STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}It changed vehicle length for '{1:ENGINE}' when not inside a depot +STR_NEWGRF_BROKEN_CAPACITY :{WHITE}It changed vehicle capacity for '{1:ENGINE}' when not inside a depot or refitting +STR_BROKEN_VEHICLE_LENGTH :{WHITE}Train '{VEHICLE}' belonging to '{COMPANY}' has invalid length. It is probably caused by problems with NewGRFs. Game may desync or crash + +STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:RAW_STRING}' provides incorrect information +STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Cargo/refit information for '{1:ENGINE}' differs from purchase list after construction. This might cause autorenew/-replace to fail refitting correctly +STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' caused an endless loop in the production callback +STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Callback {1:HEX} returned unknown/invalid result {2:HEX} + +# 'User removed essential NewGRFs'-placeholders for stuff without specs +STR_NEWGRF_INVALID_CARGO : +STR_NEWGRF_INVALID_CARGO_ABBREV :?? +STR_NEWGRF_INVALID_CARGO_QUANTITY :{COMMA} of +STR_NEWGRF_INVALID_ENGINE : +STR_NEWGRF_INVALID_INDUSTRYTYPE : + +# Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script). +STR_INVALID_VEHICLE : + +# NewGRF scanning window +STR_NEWGRF_SCAN_CAPTION :{WHITE}Scanning NewGRFs +STR_NEWGRF_SCAN_MESSAGE :{BLACK}Scanning NewGRFs. Depending on the amount this can take a while... +STR_NEWGRF_SCAN_STATUS :{BLACK}{NUM} NewGRF{P "" s} scanned out of an estimated {NUM} NewGRF{P "" s} +STR_NEWGRF_SCAN_ARCHIVES :Scanning for archives + +# Sign list window +STR_SIGN_LIST_CAPTION :{WHITE}Sign List - {COMMA} Sign{P "" s} +STR_SIGN_LIST_MATCH_CASE :{BLACK}Match case +STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}Toggle matching case when comparing sign names against the filter string + +# Sign window +STR_EDIT_SIGN_CAPTION :{WHITE}Edit sign text +STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}Go to next sign +STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}Go to previous sign + +STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}Enter a name for the sign + +# Town directory window +STR_TOWN_DIRECTORY_CAPTION :{WHITE}Towns +STR_TOWN_DIRECTORY_NONE :{ORANGE}- None - +STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ({COMMA}) +STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}Town names - click on name to centre main view on town. Ctrl+Click opens a new viewport on town location +STR_TOWN_POPULATION :{BLACK}World population: {COMMA} + +# Town view window +STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} +STR_TOWN_VIEW_CITY_CAPTION :{WHITE}{TOWN} (City) +STR_TOWN_VIEW_POPULATION_HOUSES :{BLACK}Population: {ORANGE}{COMMA}{BLACK} Houses: {ORANGE}{COMMA} +STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX :{BLACK}Passengers last month: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} +STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX :{BLACK}Mail last month: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} +STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH :{BLACK}Cargo needed for town growth: +STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL :{ORANGE}{STRING}{RED} required +STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER :{ORANGE}{STRING}{BLACK} required in winter +STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL :{ORANGE}{STRING}{GREEN} delivered +STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{RED} (still required) +STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{GREEN} (delivered) +STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}Town grows every {ORANGE}{COMMA}{BLACK} day{P "" s} +STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}Town grows every {ORANGE}{COMMA}{BLACK} day{P "" s} (funded) +STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}Town is {RED}not{BLACK} growing +STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}Noise limit in town: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} +STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Centre the main view on town location. Ctrl+Click opens a new viewport on town location +STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Local authority +STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}Show information on local authority +STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Change town name + +STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Expand +STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Increase size of town +STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Delete +STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Delete this town completely + +STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Rename Town + +# Town local authority window +STR_LOCAL_AUTHORITY_CAPTION :{WHITE}{TOWN} local authority +STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Transport company ratings: +STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} +STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Actions available: +STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP :{BLACK}List of things to do at this town - click on item for more details +STR_LOCAL_AUTHORITY_DO_IT_BUTTON :{BLACK}Do it +STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP :{BLACK}Carry out the highlighted action in the list above + +STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN :Small advertising campaign +STR_LOCAL_AUTHORITY_ACTION_MEDIUM_ADVERTISING_CAMPAIGN :Medium advertising campaign +STR_LOCAL_AUTHORITY_ACTION_LARGE_ADVERTISING_CAMPAIGN :Large advertising campaign +STR_LOCAL_AUTHORITY_ACTION_ROAD_RECONSTRUCTION :Fund local road reconstruction +STR_LOCAL_AUTHORITY_ACTION_STATUE_OF_COMPANY :Build statue of company owner +STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :Fund new buildings +STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :Buy exclusive transport rights +STR_LOCAL_AUTHORITY_ACTION_BRIBE :Bribe the local authority + +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Initiate a small local advertising campaign, to attract more passengers and cargo to your transport services.{}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Initiate a medium local advertising campaign, to attract more passengers and cargo to your transport services.{}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Initiate a large local advertising campaign, to attract more passengers and cargo to your transport services.{}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}Fund the reconstruction of the urban road network. Causes considerable disruption to road traffic for up to 6 months.{}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}Build a statue in honour of your company.{}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}Fund the construction of new commercial buildings in the town.{}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Buy 1 year's exclusive transport rights in town. Town authority will only allow passengers and cargo to use your company's stations.{}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Bribe the local authority to increase your rating, at the risk of a severe penalty if caught.{}Cost: {CURRENCY_LONG} + +# Goal window +STR_GOALS_CAPTION :{WHITE}{COMPANY} Goals +STR_GOALS_SPECTATOR_CAPTION :{WHITE}Global Goals +STR_GOALS_GLOBAL_TITLE :{BLACK}Global goals: +STR_GOALS_TEXT :{ORANGE}{RAW_STRING} +STR_GOALS_NONE :{ORANGE}- None - +STR_GOALS_SPECTATOR_NONE :{ORANGE}- Not applicable - +STR_GOALS_PROGRESS :{ORANGE}{RAW_STRING} +STR_GOALS_PROGRESS_COMPLETE :{GREEN}{RAW_STRING} +STR_GOALS_COMPANY_TITLE :{BLACK}Company goals: +STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Click on goal to centre main view on industry/town/tile. Ctrl+Click opens a new viewport on industry/town/tile location + +# Goal question window +STR_GOAL_QUESTION_CAPTION_QUESTION :Question +STR_GOAL_QUESTION_CAPTION_INFORMATION :Information +STR_GOAL_QUESTION_CAPTION_WARNING :Warning +STR_GOAL_QUESTION_CAPTION_ERROR :Error + +### Start of Goal Question button list +STR_GOAL_QUESTION_BUTTON_CANCEL :Cancel +STR_GOAL_QUESTION_BUTTON_OK :OK +STR_GOAL_QUESTION_BUTTON_NO :No +STR_GOAL_QUESTION_BUTTON_YES :Yes +STR_GOAL_QUESTION_BUTTON_DECLINE :Decline +STR_GOAL_QUESTION_BUTTON_ACCEPT :Accept +STR_GOAL_QUESTION_BUTTON_IGNORE :Ignore +STR_GOAL_QUESTION_BUTTON_RETRY :Retry +STR_GOAL_QUESTION_BUTTON_PREVIOUS :Previous +STR_GOAL_QUESTION_BUTTON_NEXT :Next +STR_GOAL_QUESTION_BUTTON_STOP :Stop +STR_GOAL_QUESTION_BUTTON_START :Start +STR_GOAL_QUESTION_BUTTON_GO :Go +STR_GOAL_QUESTION_BUTTON_CONTINUE :Continue +STR_GOAL_QUESTION_BUTTON_RESTART :Restart +STR_GOAL_QUESTION_BUTTON_POSTPONE :Postpone +STR_GOAL_QUESTION_BUTTON_SURRENDER :Surrender +STR_GOAL_QUESTION_BUTTON_CLOSE :Close + +# Subsidies window +STR_SUBSIDIES_CAPTION :{WHITE}Subsidies +STR_SUBSIDIES_OFFERED_TITLE :{BLACK}Subsidies on offer for services taking: +STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING} from {STRING2} to {STRING2}{YELLOW} (by {DATE_SHORT}) +STR_SUBSIDIES_NONE :{ORANGE}- None - +STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Services already subsidised: +STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} from {STRING2} to {STRING2}{YELLOW} ({COMPANY}{YELLOW}, until {DATE_SHORT}) +STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Click on service to centre main view on industry/town. Ctrl+Click opens a new viewport on industry/town location + +# Story book window +STR_STORY_BOOK_CAPTION :{WHITE}{COMPANY} Story Book +STR_STORY_BOOK_SPECTATOR_CAPTION :{WHITE}Global Story Book +STR_STORY_BOOK_TITLE :{YELLOW}{RAW_STRING} +STR_STORY_BOOK_GENERIC_PAGE_ITEM :Page {NUM} +STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}Jump to a specific page by selecting it in this drop down list. +STR_STORY_BOOK_PREV_PAGE :{BLACK}Previous +STR_STORY_BOOK_PREV_PAGE_TOOLTIP :{BLACK}Go to previous page +STR_STORY_BOOK_NEXT_PAGE :{BLACK}Next +STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}Go to next page +STR_STORY_BOOK_INVALID_GOAL_REF :{RED}Invalid goal reference + +# Station list window +STR_STATION_LIST_TOOLTIP :{BLACK}Station names - click on name to centre main view on station. Ctrl+Click opens a new viewport on station location +STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE :{BLACK}Hold Ctrl to select more than one item +STR_STATION_LIST_CAPTION :{WHITE}{COMPANY} - {COMMA} Station{P "" s} +STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATION_FEATURES} +STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT} +STR_STATION_LIST_NONE :{YELLOW}- None - +STR_STATION_LIST_SELECT_ALL_FACILITIES :{BLACK}Select all facilities +STR_STATION_LIST_SELECT_ALL_TYPES :{BLACK}Select all cargo types (including no waiting cargo) +STR_STATION_LIST_NO_WAITING_CARGO :{BLACK}No cargo of any type is waiting + +# Station view window +STR_STATION_VIEW_CAPTION :{WHITE}{STATION} {STATION_FEATURES} +STR_STATION_VIEW_WAITING_TITLE :{BLACK}Waiting: {WHITE}{STRING} +STR_STATION_VIEW_WAITING_CARGO :{WHITE}{CARGO_LONG} +STR_STATION_VIEW_EN_ROUTE_FROM :{YELLOW}({CARGO_SHORT} from {STATION}) +STR_STATION_VIEW_RESERVED :{YELLOW}({CARGO_SHORT} reserved for loading) + +STR_STATION_VIEW_ACCEPTS_BUTTON :{BLACK}Accepts +STR_STATION_VIEW_ACCEPTS_TOOLTIP :{BLACK}Show list of accepted cargo +STR_STATION_VIEW_ACCEPTS_CARGO :{BLACK}Accepts: {WHITE}{CARGO_LIST} + +STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF :{BLACK}This station has exclusive transport rights in this town. +STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY :{YELLOW}{COMPANY}{BLACK} bought exclusive transport rights in this town. + +STR_STATION_VIEW_RATINGS_BUTTON :{BLACK}Ratings +STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Show station ratings +STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}Monthly supply and local rating: +STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%) + +STR_STATION_VIEW_GROUP :{BLACK}Group by +STR_STATION_VIEW_WAITING_STATION :Station: Waiting +STR_STATION_VIEW_WAITING_AMOUNT :Amount: Waiting +STR_STATION_VIEW_PLANNED_STATION :Station: Planned +STR_STATION_VIEW_PLANNED_AMOUNT :Amount: Planned +STR_STATION_VIEW_FROM :{YELLOW}{CARGO_SHORT} from {STATION} +STR_STATION_VIEW_VIA :{YELLOW}{CARGO_SHORT} via {STATION} +STR_STATION_VIEW_TO :{YELLOW}{CARGO_SHORT} to {STATION} +STR_STATION_VIEW_FROM_ANY :{RED}{CARGO_SHORT} from unknown station +STR_STATION_VIEW_TO_ANY :{RED}{CARGO_SHORT} to any station +STR_STATION_VIEW_VIA_ANY :{RED}{CARGO_SHORT} via any station +STR_STATION_VIEW_FROM_HERE :{GREEN}{CARGO_SHORT} from this station +STR_STATION_VIEW_VIA_HERE :{GREEN}{CARGO_SHORT} stopping at this station +STR_STATION_VIEW_TO_HERE :{GREEN}{CARGO_SHORT} to this station +STR_STATION_VIEW_NONSTOP :{YELLOW}{CARGO_SHORT} non-stop + +STR_STATION_VIEW_GROUP_S_V_D :Source-Via-Destination +STR_STATION_VIEW_GROUP_S_D_V :Source-Destination-Via +STR_STATION_VIEW_GROUP_V_S_D :Via-Source-Destination +STR_STATION_VIEW_GROUP_V_D_S :Via-Destination-Source +STR_STATION_VIEW_GROUP_D_S_V :Destination-Source-Via +STR_STATION_VIEW_GROUP_D_V_S :Destination-Via-Source + +############ range for rating starts +STR_CARGO_RATING_APPALLING :Appalling +STR_CARGO_RATING_VERY_POOR :Very Poor +STR_CARGO_RATING_POOR :Poor +STR_CARGO_RATING_MEDIOCRE :Mediocre +STR_CARGO_RATING_GOOD :Good +STR_CARGO_RATING_VERY_GOOD :Very Good +STR_CARGO_RATING_EXCELLENT :Excellent +STR_CARGO_RATING_OUTSTANDING :Outstanding +############ range for rating ends + +STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}Centre main view on station location. Ctrl+Click opens a new viewport on station location +STR_STATION_VIEW_RENAME_TOOLTIP :{BLACK}Change name of station + +STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP :{BLACK}Show all trains which have this station on their schedule +STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP :{BLACK}Show all road vehicles which have this station on their schedule +STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP :{BLACK}Show all aircraft which have this station on their schedule +STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP :{BLACK}Show all ships which have this station on their schedule + +STR_STATION_VIEW_RENAME_STATION_CAPTION :Rename station/loading area + +STR_STATION_VIEW_CLOSE_AIRPORT :{BLACK}Close airport +STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}Prevent aircraft from landing on this airport + +# Waypoint/buoy view window +STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT} +STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Centre main view on waypoint location. Ctrl+Click opens a new viewport on waypoint location +STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}Change waypoint name +STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}Centre main view on buoy location. Ctrl+Click opens a new viewport on buoy location +STR_BUOY_VIEW_CHANGE_BUOY_NAME :{BLACK}Change buoy name + +STR_EDIT_WAYPOINT_NAME :{WHITE}Edit waypoint name + +# Finances window +STR_FINANCES_CAPTION :{WHITE}{COMPANY} Finances {BLACK}{COMPANY_NUM} +STR_FINANCES_EXPENDITURE_INCOME_TITLE :{WHITE}Expenditure/Income +STR_FINANCES_YEAR :{WHITE}{NUM} +STR_FINANCES_SECTION_CONSTRUCTION :{GOLD}Construction +STR_FINANCES_SECTION_NEW_VEHICLES :{GOLD}New Vehicles +STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS :{GOLD}Train Running Costs +STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS :{GOLD}Road Vehicle Running Costs +STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS :{GOLD}Aircraft Running Costs +STR_FINANCES_SECTION_SHIP_RUNNING_COSTS :{GOLD}Ship Running Costs +STR_FINANCES_SECTION_PROPERTY_MAINTENANCE :{GOLD}Property Maintenance +STR_FINANCES_SECTION_TRAIN_INCOME :{GOLD}Train Income +STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME :{GOLD}Road Vehicle Income +STR_FINANCES_SECTION_AIRCRAFT_INCOME :{GOLD}Aircraft Income +STR_FINANCES_SECTION_SHIP_INCOME :{GOLD}Ship Income +STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Loan Interest +STR_FINANCES_SECTION_OTHER :{GOLD}Other +STR_FINANCES_NEGATIVE_INCOME :{BLACK}-{CURRENCY_LONG} +STR_FINANCES_POSITIVE_INCOME :{BLACK}+{CURRENCY_LONG} +STR_FINANCES_TOTAL_CAPTION :{WHITE}Total: +STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Bank Balance +STR_FINANCES_LOAN_TITLE :{WHITE}Loan +STR_FINANCES_MAX_LOAN :{WHITE}Max Loan: {BLACK}{CURRENCY_LONG} +STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} +STR_FINANCES_BORROW_BUTTON :{BLACK}Borrow {CURRENCY_LONG} +STR_FINANCES_BORROW_TOOLTIP :{BLACK}Increase size of loan. Ctrl+Click borrows as much as possible +STR_FINANCES_REPAY_BUTTON :{BLACK}Repay {CURRENCY_LONG} +STR_FINANCES_REPAY_TOOLTIP :{BLACK}Repay part of loan. Ctrl+Click repays as much loan as possible +STR_FINANCES_INFRASTRUCTURE_BUTTON :{BLACK}Infrastructure + +# Company view +STR_COMPANY_VIEW_CAPTION :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM} +STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE :{WHITE}{PRESIDENT_NAME}{}{GOLD}(Manager) + +STR_COMPANY_VIEW_INAUGURATED_TITLE :{GOLD}Inaugurated: {WHITE}{NUM} +STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE :{GOLD}Colour Scheme: +STR_COMPANY_VIEW_VEHICLES_TITLE :{GOLD}Vehicles: +STR_COMPANY_VIEW_TRAINS :{WHITE}{COMMA} train{P "" s} +STR_COMPANY_VIEW_ROAD_VEHICLES :{WHITE}{COMMA} road vehicle{P "" s} +STR_COMPANY_VIEW_AIRCRAFT :{WHITE}{COMMA} aircraft +STR_COMPANY_VIEW_SHIPS :{WHITE}{COMMA} ship{P "" s} +STR_COMPANY_VIEW_VEHICLES_NONE :{WHITE}None +STR_COMPANY_VIEW_COMPANY_VALUE :{GOLD}Company value: {WHITE}{CURRENCY_LONG} +STR_COMPANY_VIEW_SHARES_OWNED_BY :{WHITE}({COMMA}% owned by {COMPANY}) +STR_COMPANY_VIEW_INFRASTRUCTURE :{GOLD}Infrastructure: +STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL :{WHITE}{COMMA} rail piece{P "" s} +STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD :{WHITE}{COMMA} road piece{P "" s} +STR_COMPANY_VIEW_INFRASTRUCTURE_WATER :{WHITE}{COMMA} water tile{P "" s} +STR_COMPANY_VIEW_INFRASTRUCTURE_STATION :{WHITE}{COMMA} station tile{P "" s} +STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT :{WHITE}{COMMA} airport{P "" s} +STR_COMPANY_VIEW_INFRASTRUCTURE_NONE :{WHITE}None + +STR_COMPANY_VIEW_BUILD_HQ_BUTTON :{BLACK}Build HQ +STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP :{BLACK}Build company headquarters +STR_COMPANY_VIEW_VIEW_HQ_BUTTON :{BLACK}View HQ +STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP :{BLACK}View company headquarters +STR_COMPANY_VIEW_RELOCATE_HQ :{BLACK}Relocate HQ +STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}Rebuild company headquarters elsewhere for 1% cost of company value. Shift+Click shows estimated cost without relocating HQ +STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}Details +STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}View detailed infrastructure counts + +STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}New Face +STR_COMPANY_VIEW_NEW_FACE_TOOLTIP :{BLACK}Select new face for manager +STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON :{BLACK}Colour Scheme +STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP :{BLACK}Change the company vehicle livery +STR_COMPANY_VIEW_COMPANY_NAME_BUTTON :{BLACK}Company Name +STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP :{BLACK}Change the company name +STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON :{BLACK}Manager Name +STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP :{BLACK}Change the manager's name + +STR_COMPANY_VIEW_BUY_SHARE_BUTTON :{BLACK}Buy 25% share in company +STR_COMPANY_VIEW_SELL_SHARE_BUTTON :{BLACK}Sell 25% share in company +STR_COMPANY_VIEW_BUY_SHARE_TOOLTIP :{BLACK}Buy 25% share in this company. Shift+Click shows estimated cost without purchasing any share +STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP :{BLACK}Sell 25% share in this company. Shift+Click shows estimated income without selling any share + +STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION :Company Name +STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION :Manager's Name + +STR_BUY_COMPANY_MESSAGE :{WHITE}We are looking for a transport company to take-over our company.{}{}Do you want to purchase {COMPANY} for {CURRENCY_LONG}? + +# Company infrastructure window +STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastructure of {COMPANY} +STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Rail pieces: +STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signals +STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Road pieces: +STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Road +STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramway +STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Water tiles: +STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canals +STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations: +STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Station tiles +STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}Airports +STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG}/yr + +# Industry directory +STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Industries +STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- None - +STR_INDUSTRY_DIRECTORY_ITEM :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{RAW_STRING}){YELLOW} ({COMMA}% transported) +STR_INDUSTRY_DIRECTORY_ITEM_TWO :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{RAW_STRING}/{CARGO_LONG}{RAW_STRING}){YELLOW} ({COMMA}%/{COMMA}% transported) +STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} +STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Industry names - click on name to centre main view on industry. Ctrl+Click opens a new viewport on industry location + +# Industry view +STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} +STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Production last month: +STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{RAW_STRING}{BLACK} ({COMMA}% transported) +STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Centre the main view on industry location. Ctrl+Click opens a new viewport on industry location +STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Production level: {YELLOW}{COMMA}% +STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}The industry has announced imminent closure! + +############ range for requires starts +STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}Requires: {YELLOW}{STRING}{RAW_STRING} +STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO :{BLACK}Requires: {YELLOW}{STRING}{RAW_STRING}, {STRING}{RAW_STRING} +STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO_CARGO :{BLACK}Requires: {YELLOW}{STRING}{RAW_STRING}, {STRING}{RAW_STRING}, {STRING}{RAW_STRING} +############ range for requires ends + +############ range for produces starts +STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING :{BLACK}Cargo waiting to be processed: +STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO :{YELLOW}{CARGO_LONG}{RAW_STRING}{BLACK} +STR_INDUSTRY_VIEW_PRODUCES_CARGO :{BLACK}Produces: {YELLOW}{STRING}{RAW_STRING} +STR_INDUSTRY_VIEW_PRODUCES_CARGO_CARGO :{BLACK}Produces: {YELLOW}{STRING}{RAW_STRING}, {STRING}{RAW_STRING} +############ range for produces ends + +STR_CONFIG_GAME_PRODUCTION :{WHITE}Change production (multiple of 8, up to 2040) +STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Change production level (percentage, up to 800%) + +# Vehicle lists +STR_VEHICLE_LIST_TRAIN_CAPTION :{WHITE}{STRING2} - {COMMA} Train{P "" s} +STR_VEHICLE_LIST_ROAD_VEHICLE_CAPTION :{WHITE}{STRING2} - {COMMA} Road Vehicle{P "" s} +STR_VEHICLE_LIST_SHIP_CAPTION :{WHITE}{STRING2} - {COMMA} Ship{P "" s} +STR_VEHICLE_LIST_AIRCRAFT_CAPTION :{WHITE}{STRING2} - {COMMA} Aircraft + +STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP :{BLACK}Trains - click on train for information +STR_VEHICLE_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Road vehicles - click on vehicle for information +STR_VEHICLE_LIST_SHIP_TOOLTIP :{BLACK}Ships - click on ship for information +STR_VEHICLE_LIST_AIRCRAFT_TOOLTIP :{BLACK}Aircraft - click on aircraft for information + +STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}Profit this year: {CURRENCY_LONG} (last year: {CURRENCY_LONG}) + +STR_VEHICLE_LIST_AVAILABLE_TRAINS :Available Trains +STR_VEHICLE_LIST_AVAILABLE_ROAD_VEHICLES :Available Vehicles +STR_VEHICLE_LIST_AVAILABLE_SHIPS :Available Ships +STR_VEHICLE_LIST_AVAILABLE_AIRCRAFT :Available Aircraft +STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP :{BLACK}See a list of available engine designs for this vehicle type + +STR_VEHICLE_LIST_MANAGE_LIST :{BLACK}Manage list +STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}Send instructions to all vehicles in this list +STR_VEHICLE_LIST_REPLACE_VEHICLES :Replace vehicles +STR_VEHICLE_LIST_SEND_FOR_SERVICING :Send for Servicing + +STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :Send to Depot +STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :Send to Depot +STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT :Send to Depot +STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR :Send to Hangar + +STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP :{BLACK}Click to stop all the vehicles in the list +STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP :{BLACK}Click to start all the vehicles in the list + +STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION :{WHITE}Shared orders of {COMMA} Vehicle{P "" s} + +# Group window +STR_GROUP_ALL_TRAINS :All trains +STR_GROUP_ALL_ROAD_VEHICLES :All road vehicles +STR_GROUP_ALL_SHIPS :All ships +STR_GROUP_ALL_AIRCRAFTS :All aircraft + +STR_GROUP_DEFAULT_TRAINS :Ungrouped trains +STR_GROUP_DEFAULT_ROAD_VEHICLES :Ungrouped road vehicles +STR_GROUP_DEFAULT_SHIPS :Ungrouped ships +STR_GROUP_DEFAULT_AIRCRAFTS :Ungrouped aircraft + +STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Groups - click on a group to list all vehicles of this group +STR_GROUP_CREATE_TOOLTIP :{BLACK}Click to create a group +STR_GROUP_DELETE_TOOLTIP :{BLACK}Delete the selected group +STR_GROUP_RENAME_TOOLTIP :{BLACK}Rename the selected group +STR_GROUP_REPLACE_PROTECTION_TOOLTIP :{BLACK}Click to protect this group from global autoreplace + +STR_GROUP_ADD_SHARED_VEHICLE :Add shared vehicles +STR_GROUP_REMOVE_ALL_VEHICLES :Remove all vehicles + +STR_GROUP_RENAME_CAPTION :{BLACK}Rename a group + +# Build vehicle window +STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION :New Rail Vehicles +STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :New Electric Rail Vehicles +STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :New Monorail Vehicles +STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :New Maglev Vehicles + +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :New Rail Vehicles +STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :New Road Vehicles +STR_BUY_VEHICLE_SHIP_CAPTION :New Ships +STR_BUY_VEHICLE_AIRCRAFT_CAPTION :New Aircraft + +STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Weight: {GOLD}{WEIGHT_SHORT} +STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Speed: {GOLD}{VELOCITY}{BLACK} Power: {GOLD}{POWER} +STR_PURCHASE_INFO_SPEED :{BLACK}Speed: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Speed on ocean: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}Speed on canal/river: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Running Cost: {GOLD}{CURRENCY_LONG}/yr +STR_PURCHASE_INFO_CAPACITY :{BLACK}Capacity: {GOLD}{CARGO_LONG} {STRING} +STR_PURCHASE_INFO_REFITTABLE :(refittable) +STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Designed: {GOLD}{NUM}{BLACK} Life: {GOLD}{COMMA} year{P "" s} +STR_PURCHASE_INFO_RELIABILITY :{BLACK}Max. Reliability: {GOLD}{COMMA}% +STR_PURCHASE_INFO_COST :{BLACK}Cost: {GOLD}{CURRENCY_LONG} +STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Weight: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) +STR_PURCHASE_INFO_COST_SPEED :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Speed: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Capacity: {GOLD}{CARGO_LONG}, {CARGO_LONG} +STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Powered Wagons: {GOLD}+{POWER}{BLACK} Weight: {GOLD}+{WEIGHT_SHORT} +STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Refittable to: {GOLD}{STRING2} +STR_PURCHASE_INFO_ALL_TYPES :All cargo types +STR_PURCHASE_INFO_ALL_BUT :All but {CARGO_LIST} +STR_PURCHASE_INFO_MAX_TE :{BLACK}Max. Tractive Effort: {GOLD}{FORCE} +STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Range: {GOLD}{COMMA} tiles + +STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}Train vehicle selection list - click on vehicle for information +STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Road vehicle selection list - click on vehicle for information +STR_BUY_VEHICLE_SHIP_LIST_TOOLTIP :{BLACK}Ship selection list - click on ship for information +STR_BUY_VEHICLE_AIRCRAFT_LIST_TOOLTIP :{BLACK}Aircraft selection list - click on aircraft for information + +STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON :{BLACK}Buy Vehicle +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Buy Vehicle +STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Buy Ship +STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Buy Aircraft + +STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted train vehicle. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted road vehicle. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted ship. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted aircraft. Shift+Click shows estimated cost without purchase + +STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Rename +STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Rename +STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Rename +STR_BUY_VEHICLE_AIRCRAFT_RENAME_BUTTON :{BLACK}Rename + +STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP :{BLACK}Rename train vehicle type +STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}Rename road vehicle type +STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}Rename ship type +STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}Rename aircraft type + +STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}Rename train vehicle type +STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}Rename road vehicle type +STR_QUERY_RENAME_SHIP_TYPE_CAPTION :{WHITE}Rename ship type +STR_QUERY_RENAME_AIRCRAFT_TYPE_CAPTION :{WHITE}Rename aircraft type + +# Depot window +STR_DEPOT_CAPTION :{WHITE}{DEPOT} + +STR_DEPOT_RENAME_TOOLTIP :{BLACK}Change name of depot +STR_DEPOT_RENAME_DEPOT_CAPTION :Rename depot + +STR_DEPOT_NO_ENGINE :{BLACK}- +STR_DEPOT_VEHICLE_TOOLTIP :{BLACK}{ENGINE}{RAW_STRING} +STR_DEPOT_VEHICLE_TOOLTIP_CHAIN :{BLACK}{NUM} vehicle{P "" s}{RAW_STRING} +STR_DEPOT_VEHICLE_TOOLTIP_CARGO :{}{CARGO_LONG} ({CARGO_SHORT}) + +STR_DEPOT_TRAIN_LIST_TOOLTIP :{BLACK}Trains - drag vehicle with left-click to add/remove from train, right-click for information. Hold Ctrl to make both functions apply to the following chain +STR_DEPOT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Vehicles - right-click on vehicle for information +STR_DEPOT_SHIP_LIST_TOOLTIP :{BLACK}Ships - right-click on ship for information +STR_DEPOT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Aircraft - right-click on aircraft for information + +STR_DEPOT_TRAIN_SELL_TOOLTIP :{BLACK}Drag train vehicle to here to sell it +STR_DEPOT_ROAD_VEHICLE_SELL_TOOLTIP :{BLACK}Drag road vehicle to here to sell it +STR_DEPOT_SHIP_SELL_TOOLTIP :{BLACK}Drag ship to here to sell it +STR_DEPOT_AIRCRAFT_SELL_TOOLTIP :{BLACK}Drag aircraft to here to sell it + +STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP :{BLACK}Drag train engine here to sell the whole train + +STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TOOLTIP :{BLACK}Sell all trains in the depot +STR_DEPOT_SELL_ALL_BUTTON_ROAD_VEHICLE_TOOLTIP :{BLACK}Sell all road vehicles in the depot +STR_DEPOT_SELL_ALL_BUTTON_SHIP_TOOLTIP :{BLACK}Sell all ships in the depot +STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TOOLTIP :{BLACK}Sell all aircraft in the hangar + +STR_DEPOT_AUTOREPLACE_TRAIN_TOOLTIP :{BLACK}Autoreplace all trains in the depot +STR_DEPOT_AUTOREPLACE_ROAD_VEHICLE_TOOLTIP :{BLACK}Autoreplace all road vehicles in the depot +STR_DEPOT_AUTOREPLACE_SHIP_TOOLTIP :{BLACK}Autoreplace all ships in the depot +STR_DEPOT_AUTOREPLACE_AIRCRAFT_TOOLTIP :{BLACK}Autoreplace all aircraft in the hangar + +STR_DEPOT_TRAIN_NEW_VEHICLES_BUTTON :{BLACK}New Vehicles +STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_BUTTON :{BLACK}New Vehicles +STR_DEPOT_SHIP_NEW_VEHICLES_BUTTON :{BLACK}New Ships +STR_DEPOT_AIRCRAFT_NEW_VEHICLES_BUTTON :{BLACK}New Aircraft + +STR_DEPOT_TRAIN_NEW_VEHICLES_TOOLTIP :{BLACK}Buy new train vehicle +STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_TOOLTIP :{BLACK}Buy new road vehicle +STR_DEPOT_SHIP_NEW_VEHICLES_TOOLTIP :{BLACK}Buy new ship +STR_DEPOT_AIRCRAFT_NEW_VEHICLES_TOOLTIP :{BLACK}Buy new aircraft + +STR_DEPOT_CLONE_TRAIN :{BLACK}Clone Train +STR_DEPOT_CLONE_ROAD_VEHICLE :{BLACK}Clone Vehicle +STR_DEPOT_CLONE_SHIP :{BLACK}Clone Ship +STR_DEPOT_CLONE_AIRCRAFT :{BLACK}Clone Aircraft + +STR_DEPOT_CLONE_TRAIN_DEPOT_INFO :{BLACK}This will buy a copy of a train including all cars. Click this button and then on a train inside or outside the depot. Ctrl+Click share the orders. Shift+Click shows estimated cost without purchase +STR_DEPOT_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}This will buy a copy of a road vehicle. Click this button and then on a road vehicle inside or outside the depot. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase +STR_DEPOT_CLONE_SHIP_DEPOT_INFO :{BLACK}This will buy a copy of a ship. Click this button and then on a ship inside or outside the depot. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase +STR_DEPOT_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}This will buy a copy of an aircraft. Click this button and then on an aircraft inside or outside the hangar. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase + +STR_DEPOT_TRAIN_LOCATION_TOOLTIP :{BLACK}Centre main view on train depot location. Ctrl+Click opens a new viewport on train depot location +STR_DEPOT_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Centre main view on road vehicle depot location. Ctrl+Click opens a new viewport on road depot location +STR_DEPOT_SHIP_LOCATION_TOOLTIP :{BLACK}Centre main view on ship depot location. Ctrl+Click opens a new viewport on ship depot location +STR_DEPOT_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Centre main view on hangar location. Ctrl+Click opens a new viewport on hangar location + +STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TOOLTIP :{BLACK}Get a list of all trains with the current depot in their orders +STR_DEPOT_VEHICLE_ORDER_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Get a list of all road vehicles with the current depot in their orders +STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TOOLTIP :{BLACK}Get a list of all ships with the current depot in their orders +STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TOOLTIP :{BLACK}Get a list of all aircraft with any hangar at this airport in their orders + +STR_DEPOT_MASS_STOP_DEPOT_TRAIN_TOOLTIP :{BLACK}Click to stop all the trains inside the depot +STR_DEPOT_MASS_STOP_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Click to stop all the road vehicles inside the depot +STR_DEPOT_MASS_STOP_DEPOT_SHIP_TOOLTIP :{BLACK}Click to stop all the ships inside the depot +STR_DEPOT_MASS_STOP_HANGAR_TOOLTIP :{BLACK}Click to stop all the aircraft inside the hangar + +STR_DEPOT_MASS_START_DEPOT_TRAIN_TOOLTIP :{BLACK}Click to start all the trains inside the depot +STR_DEPOT_MASS_START_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Click to start all the road vehicles inside the depot +STR_DEPOT_MASS_START_DEPOT_SHIP_TOOLTIP :{BLACK}Click to start all the ships inside the depot +STR_DEPOT_MASS_START_HANGAR_TOOLTIP :{BLACK}Click to start all the aircraft inside the hangar + +STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}You are about to sell all the vehicles in the depot. Are you sure? + +# Engine preview window +STR_ENGINE_PREVIEW_CAPTION :{WHITE}Message from vehicle manufacturer +STR_ENGINE_PREVIEW_MESSAGE :{GOLD}We have just designed a new {STRING} - would you be interested in a year's exclusive use of this vehicle, so we can see how it performs before making it universally available? +STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :railway locomotive +STR_ENGINE_PREVIEW_ROAD_VEHICLE :road vehicle +STR_ENGINE_PREVIEW_AIRCRAFT :aircraft +STR_ENGINE_PREVIEW_SHIP :ship +STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monorail locomotive +STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev locomotive + +STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER}{}Running Cost: {CURRENCY_LONG}/yr{}Capacity: {CARGO_LONG} +STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER} Max. T.E.: {6:FORCE}{}Running Cost: {4:CURRENCY_LONG}/yr{}Capacity: {5:CARGO_LONG} +STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY}{}Capacity: {CARGO_LONG}, {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr +STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY}{}Capacity: {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr +STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST:{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY} Range: {COMMA} tiles{}Capacity: {CARGO_LONG}, {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr +STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY} Range: {COMMA} tiles{}Capacity: {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr + +# Autoreplace window +STR_REPLACE_VEHICLES_WHITE :{WHITE}Replace {STRING} - {STRING1} +STR_REPLACE_VEHICLE_TRAIN :Train +STR_REPLACE_VEHICLE_ROAD_VEHICLE :Road Vehicle +STR_REPLACE_VEHICLE_SHIP :Ship +STR_REPLACE_VEHICLE_AIRCRAFT :Aircraft + +STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Select the engine type to replace +STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Select the new engine type you would like to use in place of the left selected engine type + +STR_REPLACE_VEHICLES_START :{BLACK}Start Replacing Vehicles +STR_REPLACE_VEHICLES_NOW :Replace all vehicles now +STR_REPLACE_VEHICLES_WHEN_OLD :Replace only old vehicles +STR_REPLACE_HELP_START_BUTTON :{BLACK}Press to begin replacement of the left selected engine type with the right selected engine type +STR_REPLACE_NOT_REPLACING :{BLACK}Not replacing +STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}No vehicle selected +STR_REPLACE_REPLACING_WHEN_OLD :{ENGINE} when old +STR_REPLACE_VEHICLES_STOP :{BLACK}Stop Replacing Vehicles +STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Press to stop the replacement of the engine type selected on the left + +STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Replacing: {ORANGE}{STRING} +STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Switch between engine and wagon replacement windows +STR_REPLACE_ENGINES :Engines +STR_REPLACE_WAGONS :Wagons + +STR_REPLACE_HELP_RAILTYPE :{BLACK}Choose the rail type you want to replace engines for +STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Displays which engine the left selected engine is being replaced with, if any +STR_REPLACE_RAIL_VEHICLES :Rail Vehicles +STR_REPLACE_ELRAIL_VEHICLES :Electrified Rail Vehicles +STR_REPLACE_MONORAIL_VEHICLES :Monorail Vehicles +STR_REPLACE_MAGLEV_VEHICLES :Maglev Vehicles + +STR_REPLACE_REMOVE_WAGON :{BLACK}Wagon removal: {ORANGE}{STRING} +STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Make autoreplace keep the length of a train the same by removing wagons (starting at the front), if replacing the engine would make the train longer + +# Vehicle view +STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} + +STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP :{BLACK}Centre main view on train's location. Ctrl+Click will follow train in main view +STR_VEHICLE_VIEW_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Centre main view on vehicle's location. Ctrl+Click will follow vehicle in main view +STR_VEHICLE_VIEW_SHIP_LOCATION_TOOLTIP :{BLACK}Centre main view on ship's location. Ctrl+Click will follow ship in main view +STR_VEHICLE_VIEW_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Centre main view on aircraft's location. Ctrl+Click will follow aircraft in main view + +STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send train to depot. Ctrl+Click will only service +STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send vehicle to depot. Ctrl+Click will only service +STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send ship to depot. Ctrl+Click will only service +STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send aircraft to hangar. Ctrl+Click will only service + +STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}This will buy a copy of the train including all cars. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase +STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}This will buy a copy of the road vehicle. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase +STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}This will buy a copy of the ship. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase +STR_VEHICLE_VIEW_CLONE_AIRCRAFT_INFO :{BLACK}This will buy a copy of the aircraft. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase + +STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP :{BLACK}Force train to proceed without waiting for signal to clear it + +STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP :{BLACK}Refit train to carry a different cargo type +STR_VEHICLE_VIEW_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Refit road vehicle to carry a different cargo type +STR_VEHICLE_VIEW_SHIP_REFIT_TOOLTIP :{BLACK}Refit ship to carry a different cargo type +STR_VEHICLE_VIEW_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Refit aircraft to carry a different cargo type + +STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP :{BLACK}Reverse direction of train +STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP :{BLACK}Force vehicle to turn around + +STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP :{BLACK}Show train's orders. Ctrl+Click to show train's timetable +STR_VEHICLE_VIEW_ROAD_VEHICLE_ORDERS_TOOLTIP :{BLACK}Show vehicle's orders. Ctrl+Click to show vehicle's timetable +STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Show ship's orders. Ctrl+Click to show ship's timetable +STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Show aircraft's orders. Ctrl+Click to show aircraft's timetable + +STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Show train details +STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Show road vehicle details +STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Show ship details +STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Show aircraft details + +STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP :{BLACK}Current train action - click to stop/start train. Ctrl+Click to scroll to destination +STR_VEHICLE_VIEW_ROAD_VEHICLE_STATE_START_STOP_TOOLTIP :{BLACK}Current vehicle action - click to stop/start vehicle. Ctrl+Click to scroll to destination +STR_VEHICLE_VIEW_SHIP_STATE_START_STOP_TOOLTIP :{BLACK}Current ship action - click to stop/start ship. Ctrl+Click to scroll to destination +STR_VEHICLE_VIEW_AIRCRAFT_STATE_START_STOP_TOOLTIP :{BLACK}Current aircraft action - click to stop/start aircraft. Ctrl+Click to scroll to destination + +# Messages in the start stop button in the vehicle view +STR_VEHICLE_STATUS_LOADING_UNLOADING :{LTBLUE}Loading / Unloading +STR_VEHICLE_STATUS_LEAVING :{LTBLUE}Leaving +STR_VEHICLE_STATUS_CRASHED :{RED}Crashed! +STR_VEHICLE_STATUS_BROKEN_DOWN :{RED}Broken down +STR_VEHICLE_STATUS_STOPPED :{RED}Stopped +STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}Stopping, {VELOCITY} +STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}No power +STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}Waiting for free path +STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}Too far to next destination + +STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL :{LTBLUE}Heading for {STATION}, {VELOCITY} +STR_VEHICLE_STATUS_NO_ORDERS_VEL :{LTBLUE}No orders, {VELOCITY} +STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL :{LTBLUE}Heading for {WAYPOINT}, {VELOCITY} +STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL :{ORANGE}Heading for {DEPOT}, {VELOCITY} +STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL :{LTBLUE}Service at {DEPOT}, {VELOCITY} + +# Vehicle stopped/started animations +STR_VEHICLE_COMMAND_STOPPED_SMALL :{TINY_FONT}{RED}Stopped +STR_VEHICLE_COMMAND_STOPPED :{RED}Stopped +STR_VEHICLE_COMMAND_STARTED_SMALL :{TINY_FONT}{GREEN}Started +STR_VEHICLE_COMMAND_STARTED :{GREEN}Started + +# Vehicle details +STR_VEHICLE_DETAILS_CAPTION :{WHITE}{VEHICLE} (Details) +STR_VEHICLE_NAME_BUTTON :{BLACK}Name + +STR_VEHICLE_DETAILS_TRAIN_RENAME :{BLACK}Name train +STR_VEHICLE_DETAILS_ROAD_VEHICLE_RENAME :{BLACK}Name road vehicle +STR_VEHICLE_DETAILS_SHIP_RENAME :{BLACK}Name ship +STR_VEHICLE_DETAILS_AIRCRAFT_RENAME :{BLACK}Name aircraft + +STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}Age: {LTBLUE}{STRING2}{BLACK} Running Cost: {LTBLUE}{CURRENCY_LONG}/yr +# The next two need to stay in this order +STR_VEHICLE_INFO_AGE :{COMMA} year{P "" s} ({COMMA}) +STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} year{P "" s} ({COMMA}) + +STR_VEHICLE_INFO_MAX_SPEED :{BLACK}Max. speed: {LTBLUE}{VELOCITY} +STR_VEHICLE_INFO_MAX_SPEED_RANGE :{BLACK}Max. speed: {LTBLUE}{VELOCITY} {BLACK}Range: {LTBLUE}{COMMA} tiles +STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Weight: {LTBLUE}{WEIGHT_SHORT} {BLACK}Power: {LTBLUE}{POWER}{BLACK} Max. speed: {LTBLUE}{VELOCITY} +STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Weight: {LTBLUE}{WEIGHT_SHORT} {BLACK}Power: {LTBLUE}{POWER}{BLACK} Max. speed: {LTBLUE}{VELOCITY} {BLACK}Max. T.E.: {LTBLUE}{FORCE} + +STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Profit this year: {LTBLUE}{CURRENCY_LONG} (last year: {CURRENCY_LONG}) +STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Reliability: {LTBLUE}{COMMA}% {BLACK}Breakdowns since last service: {LTBLUE}{COMMA} + +STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} +STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}Capacity: {LTBLUE}None{STRING} +STR_VEHICLE_INFO_CAPACITY :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}{3:STRING} +STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM}) +STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}, {CARGO_LONG}{STRING} + +STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}Transfer Credits: {LTBLUE}{CURRENCY_LONG} + +STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}Servicing interval: {LTBLUE}{COMMA}days{BLACK} Last service: {LTBLUE}{DATE_LONG} +STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}Servicing interval: {LTBLUE}{COMMA}%{BLACK} Last service: {LTBLUE}{DATE_LONG} +STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Increase servicing interval by 10. Ctrl+Click increases servicing interval by 5 +STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Decrease servicing interval by 10. Ctrl+Click decreases servicing interval by 5 + +STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}Change servicing interval type +STR_VEHICLE_DETAILS_DEFAULT :Default +STR_VEHICLE_DETAILS_DAYS :Days +STR_VEHICLE_DETAILS_PERCENT :Percentage + +STR_QUERY_RENAME_TRAIN_CAPTION :{WHITE}Name train +STR_QUERY_RENAME_ROAD_VEHICLE_CAPTION :{WHITE}Name road vehicle +STR_QUERY_RENAME_SHIP_CAPTION :{WHITE}Name ship +STR_QUERY_RENAME_AIRCRAFT_CAPTION :{WHITE}Name aircraft + +# Extra buttons for train details windows +STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE :{LTBLUE}{ENGINE}{BLACK} Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} +STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE :{LTBLUE}{ENGINE}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} + +STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT :{BLACK}Total cargo capacity of this train: +STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) +STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) (x{NUM}) + +STR_VEHICLE_DETAILS_CARGO_EMPTY :{LTBLUE}Empty +STR_VEHICLE_DETAILS_CARGO_FROM :{LTBLUE}{CARGO_LONG} from {STATION} +STR_VEHICLE_DETAILS_CARGO_FROM_MULT :{LTBLUE}{CARGO_LONG} from {STATION} (x{NUM}) + +STR_VEHICLE_DETAIL_TAB_CARGO :{BLACK}Cargo +STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP :{BLACK}Show details of cargo carried +STR_VEHICLE_DETAIL_TAB_INFORMATION :{BLACK}Information +STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP :{BLACK}Show details of train vehicles +STR_VEHICLE_DETAIL_TAB_CAPACITIES :{BLACK}Capacities +STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP :{BLACK}Show capacities of each vehicle +STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO :{BLACK}Total Cargo +STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP :{BLACK}Show total capacity of train, split by cargo type + +STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}Capacity: {LTBLUE} + +# Vehicle refit +STR_REFIT_CAPTION :{WHITE}{VEHICLE} (Refit) +STR_REFIT_TITLE :{GOLD}Select cargo type to carry: +STR_REFIT_NEW_CAPACITY_COST_OF_REFIT :{BLACK}New capacity: {GOLD}{CARGO_LONG}{}{BLACK}Cost of refit: {RED}{CURRENCY_LONG} +STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT :{BLACK}New capacity: {GOLD}{CARGO_LONG}{}{BLACK}Income from refit: {GREEN}{CURRENCY_LONG} +STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}New capacity: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Cost of refit: {RED}{CURRENCY_LONG} +STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT :{BLACK}New capacity: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Income from refit: {GREEN}{CURRENCY_LONG} +STR_REFIT_SELECT_VEHICLES_TOOLTIP :{BLACK}Select the vehicles to refit. Dragging with the mouse allows to select multiple vehicles. Clicking on an empty space will select the whole vehicle. Ctrl+Click will select a vehicle and the following chain + +STR_REFIT_TRAIN_LIST_TOOLTIP :{BLACK}Select type of cargo for train to carry +STR_REFIT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Select type of cargo for road vehicle to carry +STR_REFIT_SHIP_LIST_TOOLTIP :{BLACK}Select type of cargo for ship to carry +STR_REFIT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Select type of cargo for aircraft to carry + +STR_REFIT_TRAIN_REFIT_BUTTON :{BLACK}Refit train +STR_REFIT_ROAD_VEHICLE_REFIT_BUTTON :{BLACK}Refit road vehicle +STR_REFIT_SHIP_REFIT_BUTTON :{BLACK}Refit ship +STR_REFIT_AIRCRAFT_REFIT_BUTTON :{BLACK}Refit aircraft + +STR_REFIT_TRAIN_REFIT_TOOLTIP :{BLACK}Refit train to carry highlighted cargo type +STR_REFIT_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Refit road vehicle to carry highlighted cargo type +STR_REFIT_SHIP_REFIT_TOOLTIP :{BLACK}Refit ship to carry highlighted cargo type +STR_REFIT_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Refit aircraft to carry highlighted cargo type + +# Order view +STR_ORDERS_CAPTION :{WHITE}{VEHICLE} (Orders) +STR_ORDERS_TIMETABLE_VIEW :{BLACK}Timetable +STR_ORDERS_TIMETABLE_VIEW_TOOLTIP :{BLACK}Switch to the timetable view + +STR_ORDERS_LIST_TOOLTIP :{BLACK}Order list - click on an order to highlight it. Ctrl+Click scrolls to the order's destination +STR_ORDER_INDEX :{COMMA}:{NBSP} +STR_ORDER_TEXT :{STRING4} {STRING2} {STRING} + +STR_ORDERS_END_OF_ORDERS :- - End of Orders - - +STR_ORDERS_END_OF_SHARED_ORDERS :- - End of Shared Orders - - + +# Order bottom buttons +STR_ORDER_NON_STOP :{BLACK}Non-stop +STR_ORDER_GO_TO :Go to +STR_ORDER_GO_NON_STOP_TO :Go non-stop to +STR_ORDER_GO_VIA :Go via +STR_ORDER_GO_NON_STOP_VIA :Go non-stop via +STR_ORDER_TOOLTIP_NON_STOP :{BLACK}Change the stopping behaviour of the highlighted order + +STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}Full load any cargo +STR_ORDER_DROP_LOAD_IF_POSSIBLE :Load if available +STR_ORDER_DROP_FULL_LOAD_ALL :Full load all cargo +STR_ORDER_DROP_FULL_LOAD_ANY :Full load any cargo +STR_ORDER_DROP_NO_LOADING :No loading +STR_ORDER_TOOLTIP_FULL_LOAD :{BLACK}Change the loading behaviour of the highlighted order + +STR_ORDER_TOGGLE_UNLOAD :{BLACK}Unload all +STR_ORDER_DROP_UNLOAD_IF_ACCEPTED :Unload if accepted +STR_ORDER_DROP_UNLOAD :Unload all +STR_ORDER_DROP_TRANSFER :Transfer +STR_ORDER_DROP_NO_UNLOADING :No unloading +STR_ORDER_TOOLTIP_UNLOAD :{BLACK}Change the unloading behaviour of the highlighted order + +STR_ORDER_REFIT :{BLACK}Refit +STR_ORDER_REFIT_TOOLTIP :{BLACK}Select what cargo type to refit to in this order. Ctrl+Click to remove refit instruction +STR_ORDER_REFIT_AUTO :{BLACK}Auto-refit +STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}Select what cargo type to auto-refit to in this order. Ctrl+Click to remove refit instruction. Auto-refitting will only be done if the vehicle allows it +STR_ORDER_DROP_REFIT_AUTO :Fixed cargo +STR_ORDER_DROP_REFIT_AUTO_ANY :Available cargo + +STR_ORDER_SERVICE :{BLACK}Service +STR_ORDER_DROP_GO_ALWAYS_DEPOT :Always go +STR_ORDER_DROP_SERVICE_DEPOT :Service if needed +STR_ORDER_DROP_HALT_DEPOT :Stop +STR_ORDER_SERVICE_TOOLTIP :{BLACK}Skip this order unless a service is needed + +STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP :{BLACK}Vehicle data to base jumping on + +# Conditional order variables, must follow order of OrderConditionVariable enum +STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE :Load percentage +STR_ORDER_CONDITIONAL_RELIABILITY :Reliability +STR_ORDER_CONDITIONAL_MAX_SPEED :Maximum speed +STR_ORDER_CONDITIONAL_AGE :Age (years) +STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :Requires service +STR_ORDER_CONDITIONAL_UNCONDITIONALLY :Always +STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :Remaining lifetime (years) + +STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}How to compare the vehicle data to the given value +STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :is equal to +STR_ORDER_CONDITIONAL_COMPARATOR_NOT_EQUALS :is not equal to +STR_ORDER_CONDITIONAL_COMPARATOR_LESS_THAN :is less than +STR_ORDER_CONDITIONAL_COMPARATOR_LESS_EQUALS :is less or equal to +STR_ORDER_CONDITIONAL_COMPARATOR_MORE_THAN :is more than +STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS :is more or equal to +STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE :is true +STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE :is false + +STR_ORDER_CONDITIONAL_VALUE_TOOLTIP :{BLACK}The value to compare the vehicle data against +STR_ORDER_CONDITIONAL_VALUE_CAPT :{WHITE}Enter value to compare against + +STR_ORDERS_SKIP_BUTTON :{BLACK}Skip +STR_ORDERS_SKIP_TOOLTIP :{BLACK}Skip the current order, and start the next. Ctrl+Click skips to the selected order + +STR_ORDERS_DELETE_BUTTON :{BLACK}Delete +STR_ORDERS_DELETE_TOOLTIP :{BLACK}Delete the highlighted order +STR_ORDERS_DELETE_ALL_TOOLTIP :{BLACK}Delete all orders +STR_ORDERS_STOP_SHARING_BUTTON :{BLACK}Stop sharing +STR_ORDERS_STOP_SHARING_TOOLTIP :{BLACK}Stop sharing the order list. Ctrl+Click additionally deletes all orders for this vehicle + +STR_ORDERS_GO_TO_BUTTON :{BLACK}Go To +STR_ORDER_GO_TO_NEAREST_DEPOT :Go to nearest depot +STR_ORDER_GO_TO_NEAREST_HANGAR :Go to nearest hangar +STR_ORDER_CONDITIONAL :Conditional order jump +STR_ORDER_SHARE :Share orders +STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Insert a new order before the highlighted order, or add to end of list. Ctrl makes station orders 'full load any cargo', waypoint orders 'non-stop' and depot orders 'service'. 'Share orders' or Ctrl lets this vehicle share orders with the selected vehicle. Clicking a vehicle copies the orders from that vehicle. A depot order disables automatic servicing of the vehicle + +STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Show all vehicles that share this schedule + +# String parts to build the order string +STR_ORDER_GO_TO_WAYPOINT :Go via {WAYPOINT} +STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Go non-stop via {WAYPOINT} + +STR_ORDER_SERVICE_AT :Service at +STR_ORDER_SERVICE_NON_STOP_AT :Service non-stop at + +STR_ORDER_NEAREST_DEPOT :the nearest +STR_ORDER_NEAREST_HANGAR :the nearest Hangar +STR_ORDER_TRAIN_DEPOT :Train Depot +STR_ORDER_ROAD_VEHICLE_DEPOT :Road Vehicle Depot +STR_ORDER_SHIP_DEPOT :Ship Depot +STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} {STRING} {STRING} +STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} + +STR_ORDER_REFIT_ORDER :(Refit to {STRING}) +STR_ORDER_REFIT_STOP_ORDER :(Refit to {STRING} and stop) +STR_ORDER_STOP_ORDER :(Stop) + +STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING} + +STR_ORDER_IMPLICIT :(Implicit) + +STR_ORDER_FULL_LOAD :(Full load) +STR_ORDER_FULL_LOAD_ANY :(Full load any cargo) +STR_ORDER_NO_LOAD :(No loading) +STR_ORDER_UNLOAD :(Unload and take cargo) +STR_ORDER_UNLOAD_FULL_LOAD :(Unload and wait for full load) +STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Unload and wait for any full load) +STR_ORDER_UNLOAD_NO_LOAD :(Unload and leave empty) +STR_ORDER_TRANSFER :(Transfer and take cargo) +STR_ORDER_TRANSFER_FULL_LOAD :(Transfer and wait for full load) +STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Transfer and wait for any full load) +STR_ORDER_TRANSFER_NO_LOAD :(Transfer and leave empty) +STR_ORDER_NO_UNLOAD :(No unloading and take cargo) +STR_ORDER_NO_UNLOAD_FULL_LOAD :(No unloading and wait for full load) +STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(No unloading and wait for any full load) +STR_ORDER_NO_UNLOAD_NO_LOAD :(No unloading and no loading) + +STR_ORDER_AUTO_REFIT :(Auto-refit to {STRING}) +STR_ORDER_FULL_LOAD_REFIT :(Full load with auto-refit to {STRING}) +STR_ORDER_FULL_LOAD_ANY_REFIT :(Full load any cargo with auto-refit to {STRING}) +STR_ORDER_UNLOAD_REFIT :(Unload and take cargo with auto-refit to {STRING}) +STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Unload and wait for full load with auto-refit to {STRING}) +STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Unload and wait for any full load with auto-refit to {STRING}) +STR_ORDER_TRANSFER_REFIT :(Transfer and take cargo with auto-refit to {STRING}) +STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Transfer and wait for full load with auto-refit to {STRING}) +STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Transfer and wait for any full load with auto-refit to {STRING}) +STR_ORDER_NO_UNLOAD_REFIT :(No unloading and take cargo with auto-refit to {STRING}) +STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(No unloading and wait for full load with auto-refit to {STRING}) +STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(No unloading and wait for any full load with auto-refit to {STRING}) + +STR_ORDER_AUTO_REFIT_ANY :available cargo + +STR_ORDER_STOP_LOCATION_NEAR_END :[near end] +STR_ORDER_STOP_LOCATION_MIDDLE :[middle] +STR_ORDER_STOP_LOCATION_FAR_END :[far end] + +STR_ORDER_OUT_OF_RANGE :{RED} (Next destination is out of range) + +STR_ORDER_CONDITIONAL_UNCONDITIONAL :Jump to order {COMMA} +STR_ORDER_CONDITIONAL_NUM :Jump to order {COMMA} when {STRING} {STRING} {COMMA} +STR_ORDER_CONDITIONAL_TRUE_FALSE :Jump to order {COMMA} when {STRING} {STRING} + +STR_INVALID_ORDER :{RED} (Invalid Order) + +# Time table window +STR_TIMETABLE_TITLE :{WHITE}{VEHICLE} (Timetable) +STR_TIMETABLE_ORDER_VIEW :{BLACK}Orders +STR_TIMETABLE_ORDER_VIEW_TOOLTIP :{BLACK}Switch to the order view + +STR_TIMETABLE_TOOLTIP :{BLACK}Timetable - click on an order to highlight it + +STR_TIMETABLE_NO_TRAVEL :No travel +STR_TIMETABLE_NOT_TIMETABLEABLE :Travel (automatic; timetabled by next manual order) +STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Travel (not timetabled) +STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Travel with at most {2:VELOCITY} (not timetabled) +STR_TIMETABLE_TRAVEL_FOR :Travel for {STRING1} +STR_TIMETABLE_TRAVEL_FOR_SPEED :Travel for {STRING1} with at most {VELOCITY} +STR_TIMETABLE_STAY_FOR :and stay for {STRING1} +STR_TIMETABLE_AND_TRAVEL_FOR :and travel for {STRING1} +STR_TIMETABLE_DAYS :{COMMA} day{P "" s} +STR_TIMETABLE_TICKS :{COMMA} tick{P "" s} + +STR_TIMETABLE_TOTAL_TIME :{BLACK}This timetable will take {STRING1} to complete +STR_TIMETABLE_TOTAL_TIME_INCOMPLETE :{BLACK}This timetable will take at least {STRING1} to complete (not all timetabled) + +STR_TIMETABLE_STATUS_ON_TIME :{BLACK}This vehicle is currently running on time +STR_TIMETABLE_STATUS_LATE :{BLACK}This vehicle is currently running {STRING1} late +STR_TIMETABLE_STATUS_EARLY :{BLACK}This vehicle is currently running {STRING1} early +STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}This timetable has not yet started +STR_TIMETABLE_STATUS_START_AT :{BLACK}This timetable will start at {STRING1} + +STR_TIMETABLE_STARTING_DATE :{BLACK}Start date +STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Select a date as starting point of this timetable. Ctrl+Click sets the starting point of this timetable and distributes all vehicles sharing this order evenly based on their relative order, if the order is completely timetabled + +STR_TIMETABLE_CHANGE_TIME :{BLACK}Change Time +STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Change the amount of time that the highlighted order should take + +STR_TIMETABLE_CLEAR_TIME :{BLACK}Clear Time +STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Clear the amount of time for the highlighted order + +STR_TIMETABLE_CHANGE_SPEED :{BLACK}Change Speed Limit +STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Change the maximum travel speed of the highlighted order + +STR_TIMETABLE_CLEAR_SPEED :{BLACK}Clear Speed Limit +STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Clear the maximum travel speed of the highlighted order + +STR_TIMETABLE_RESET_LATENESS :{BLACK}Reset Late Counter +STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Reset the lateness counter, so the vehicle will be on time + +STR_TIMETABLE_AUTOFILL :{BLACK}Autofill +STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the timetable automatically with the values from the next journey (Ctrl+Click to try to keep waiting times) + +STR_TIMETABLE_EXPECTED :{BLACK}Expected +STR_TIMETABLE_SCHEDULED :{BLACK}Scheduled +STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Switch between expected and scheduled + +STR_TIMETABLE_ARRIVAL_ABBREVIATION :A: +STR_TIMETABLE_DEPARTURE_ABBREVIATION :D: + + +# Date window (for timetable) +STR_DATE_CAPTION :{WHITE}Set date +STR_DATE_SET_DATE :{BLACK}Set date +STR_DATE_SET_DATE_TOOLTIP :{BLACK}Use the selected date as starting date for the timetable +STR_DATE_DAY_TOOLTIP :{BLACK}Select day +STR_DATE_MONTH_TOOLTIP :{BLACK}Select month +STR_DATE_YEAR_TOOLTIP :{BLACK}Select year + + +# AI debug window +STR_AI_DEBUG :{WHITE}AI/Game Script Debug +STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{RAW_STRING} (v{NUM}) +STR_AI_DEBUG_NAME_TOOLTIP :{BLACK}Name of the script +STR_AI_DEBUG_SETTINGS :{BLACK}Settings +STR_AI_DEBUG_SETTINGS_TOOLTIP :{BLACK}Change the settings of the script +STR_AI_DEBUG_RELOAD :{BLACK}Reload AI +STR_AI_DEBUG_RELOAD_TOOLTIP :{BLACK}Kill the AI, reload the script, and restart the AI +STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK}Enable/disable breaking when an AI log message matches the break string +STR_AI_DEBUG_BREAK_ON_LABEL :{BLACK}Break on: +STR_AI_DEBUG_BREAK_STR_OSKTITLE :{BLACK}Break on +STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}When an AI log message matches this string, the game is paused +STR_AI_DEBUG_MATCH_CASE :{BLACK}Match case +STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Toggle matching case when comparing AI log messages against the break string +STR_AI_DEBUG_CONTINUE :{BLACK}Continue +STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Unpause and continue the AI +STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}View debug output of this AI +STR_AI_GAME_SCRIPT :{BLACK}Game Script +STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Check the Game Script log + +STR_ERROR_AI_NO_AI_FOUND :No suitable AI found to load.{}This AI is a dummy AI and won't do anything.{}You can download several AIs via the 'Online Content' system +STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}One of the running scripts crashed. Please report this to the script author with a screenshot of the AI/Game Script Debug Window +STR_ERROR_AI_DEBUG_SERVER_ONLY :{YELLOW}AI/Game Script Debug window is only available for the server + +# AI configuration window +STR_AI_CONFIG_CAPTION :{WHITE}AI/Game Script Configuration +STR_AI_CONFIG_GAMELIST_TOOLTIP :{BLACK}The Game Script that will be loaded in the next game +STR_AI_CONFIG_AILIST_TOOLTIP :{BLACK}The AIs that will be loaded in the next game +STR_AI_CONFIG_HUMAN_PLAYER :Human player +STR_AI_CONFIG_RANDOM_AI :Random AI +STR_AI_CONFIG_NONE :(none) + +STR_AI_CONFIG_MOVE_UP :{BLACK}Move Up +STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}Move selected AI up in the list +STR_AI_CONFIG_MOVE_DOWN :{BLACK}Move Down +STR_AI_CONFIG_MOVE_DOWN_TOOLTIP :{BLACK}Move selected AI down in the list + +STR_AI_CONFIG_GAMESCRIPT :{SILVER}Game Script +STR_AI_CONFIG_AI :{SILVER}AIs + +STR_AI_CONFIG_CHANGE :{BLACK}Select {STRING} +STR_AI_CONFIG_CHANGE_NONE : +STR_AI_CONFIG_CHANGE_AI :AI +STR_AI_CONFIG_CHANGE_GAMESCRIPT :Game Script +STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}Load another script +STR_AI_CONFIG_CONFIGURE :{BLACK}Configure +STR_AI_CONFIG_CONFIGURE_TOOLTIP :{BLACK}Configure the parameters of the Script + +# Available AIs window +STR_AI_LIST_CAPTION :{WHITE}Available {STRING} +STR_AI_LIST_CAPTION_AI :AIs +STR_AI_LIST_CAPTION_GAMESCRIPT :Game Scripts +STR_AI_LIST_TOOLTIP :{BLACK}Click to select a script + +STR_AI_LIST_AUTHOR :{LTBLUE}Author: {ORANGE}{RAW_STRING} +STR_AI_LIST_VERSION :{LTBLUE}Version: {ORANGE}{NUM} +STR_AI_LIST_URL :{LTBLUE}URL: {ORANGE}{RAW_STRING} + +STR_AI_LIST_ACCEPT :{BLACK}Accept +STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}Select highlighted script +STR_AI_LIST_CANCEL :{BLACK}Cancel +STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Don't change the script + +# AI Parameters +STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parameters +STR_AI_SETTINGS_CAPTION_AI :AI +STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Game Script +STR_AI_SETTINGS_CLOSE :{BLACK}Close +STR_AI_SETTINGS_RESET :{BLACK}Reset +STR_AI_SETTINGS_SETTING :{RAW_STRING}: {ORANGE}{STRING1} +STR_AI_SETTINGS_START_DELAY :Number of days to start this AI after the previous one (give or take): {ORANGE}{STRING1} + + +# Textfile window +STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme of {RAW_STRING} +STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} changelog of {RAW_STRING} +STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licence of {RAW_STRING} +STR_TEXTFILE_WRAP_TEXT :{WHITE}Wrap text +STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Wrap the text of the window so it all fits without having to scroll +STR_TEXTFILE_VIEW_README :{BLACK}View readme +STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Changelog +STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licence + + +# Vehicle loading indicators +STR_PERCENT_UP_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW} +STR_PERCENT_UP :{WHITE}{NUM}%{UP_ARROW} +STR_PERCENT_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{DOWN_ARROW} +STR_PERCENT_DOWN :{WHITE}{NUM}%{DOWN_ARROW} +STR_PERCENT_UP_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} +STR_PERCENT_UP_DOWN :{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} +STR_PERCENT_NONE_SMALL :{TINY_FONT}{WHITE}{NUM}% +STR_PERCENT_NONE :{WHITE}{NUM}% + +# Income 'floats' +STR_INCOME_FLOAT_COST_SMALL :{TINY_FONT}{RED}Cost: {CURRENCY_LONG} +STR_INCOME_FLOAT_COST :{RED}Cost: {CURRENCY_LONG} +STR_INCOME_FLOAT_INCOME_SMALL :{TINY_FONT}{GREEN}Income: {CURRENCY_LONG} +STR_INCOME_FLOAT_INCOME :{GREEN}Income: {CURRENCY_LONG} +STR_FEEDER_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG} +STR_FEEDER :{YELLOW}Transfer: {CURRENCY_LONG} +STR_FEEDER_INCOME_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {GREEN}Income: {CURRENCY_LONG} +STR_FEEDER_INCOME :{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {GREEN}Income: {CURRENCY_LONG} +STR_FEEDER_COST_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {RED}Cost: {CURRENCY_LONG} +STR_FEEDER_COST :{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {RED}Cost: {CURRENCY_LONG} +STR_MESSAGE_ESTIMATED_COST :{WHITE}Estimated Cost: {CURRENCY_LONG} +STR_MESSAGE_ESTIMATED_INCOME :{WHITE}Estimated Income: {CURRENCY_LONG} + +# Saveload messages +STR_ERROR_SAVE_STILL_IN_PROGRESS :{WHITE}Saving still in progress,{}please wait until it is finished! +STR_ERROR_AUTOSAVE_FAILED :{WHITE}Autosave failed +STR_ERROR_UNABLE_TO_READ_DRIVE :{BLACK}Unable to read drive +STR_ERROR_GAME_SAVE_FAILED :{WHITE}Game Save Failed{}{STRING} +STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}Unable to delete file +STR_ERROR_GAME_LOAD_FAILED :{WHITE}Game Load Failed{}{STRING} +STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR :Internal error: {RAW_STRING} +STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Broken savegame - {RAW_STRING} +STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Savegame is made with newer version +STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :File not readable +STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :File not writeable +STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Data integrity check failed +STR_GAME_SAVELOAD_NOT_AVAILABLE : +STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Game was saved in version without tram support. All trams have been removed + +# Map generation messages +STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Map generation aborted...{}... no suitable town locations +STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... there is no town in this scenario + +STR_ERROR_PNGMAP :{WHITE}Can't load landscape from PNG... +STR_ERROR_PNGMAP_FILE_NOT_FOUND :{WHITE}... file not found +STR_ERROR_PNGMAP_IMAGE_TYPE :{WHITE}... could not convert image type. 8 or 24-bit PNG image needed +STR_ERROR_PNGMAP_MISC :{WHITE}... something just went wrong (probably corrupted file) + +STR_ERROR_BMPMAP :{WHITE}Can't load landscape from BMP... +STR_ERROR_BMPMAP_IMAGE_TYPE :{WHITE}... could not convert image type + +STR_ERROR_HEIGHTMAP_TOO_LARGE :{WHITE}... image is too large + +STR_WARNING_HEIGHTMAP_SCALE_CAPTION :{WHITE}Scale warning +STR_WARNING_HEIGHTMAP_SCALE_MESSAGE :{YELLOW}Resizing source map too much is not recommended. Continue with the generation? + +# Soundset messages +STR_WARNING_FALLBACK_SOUNDSET :{WHITE}Only a fallback sound set was found. If you want sounds, install a sound set via the content download system + +# Screenshot related messages +STR_WARNING_SCREENSHOT_SIZE_CAPTION :{WHITE}Huge screenshot +STR_WARNING_SCREENSHOT_SIZE_MESSAGE :{YELLOW}The screenshot will have a resolution of {COMMA} x {COMMA} pixels. Taking the screenshot may take a while. Do you want to continue? + +STR_MESSAGE_SCREENSHOT_SUCCESSFULLY :{WHITE}Screenshot successfully saved as '{RAW_STRING}' +STR_ERROR_SCREENSHOT_FAILED :{WHITE}Screenshot failed! + +# Error message titles +STR_ERROR_MESSAGE_CAPTION :{YELLOW}Message +STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}Message from {STRING1} + +# Generic construction errors +STR_ERROR_OFF_EDGE_OF_MAP :{WHITE}Off edge of map +STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}Too close to edge of map +STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY :{WHITE}Not enough cash - requires {CURRENCY_LONG} +STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Flat land required +STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Land sloped in wrong direction +STR_ERROR_CAN_T_DO_THIS :{WHITE}Can't do this... +STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Building must be demolished first +STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Can't clear this area... +STR_ERROR_SITE_UNSUITABLE :{WHITE}... site unsuitable +STR_ERROR_ALREADY_BUILT :{WHITE}... already built +STR_ERROR_OWNED_BY :{WHITE}... owned by {STRING2} +STR_ERROR_AREA_IS_OWNED_BY_ANOTHER :{WHITE}... area is owned by another company +STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... landscaping limit reached +STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... tile clearing limit reached +STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... tree planting limit reached +STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Name must be unique +STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} in the way +STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Not allowed while paused + +# Local authority errors +STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS :{WHITE}{TOWN} local authority refuses to allow this +STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT :{WHITE}{TOWN} local authority refuses to allow another airport to be built in this town +STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE :{WHITE}{TOWN} local authority refuses permission for airport due to noise concerns +STR_ERROR_BRIBE_FAILED :{WHITE}Your attempted bribe has been discovered by a regional investigator + +# Levelling errors +STR_ERROR_CAN_T_RAISE_LAND_HERE :{WHITE}Can't raise land here... +STR_ERROR_CAN_T_LOWER_LAND_HERE :{WHITE}Can't lower land here... +STR_ERROR_CAN_T_LEVEL_LAND_HERE :{WHITE}Can't level land here... +STR_ERROR_EXCAVATION_WOULD_DAMAGE :{WHITE}Excavation would damage tunnel +STR_ERROR_ALREADY_AT_SEA_LEVEL :{WHITE}... already at sea level +STR_ERROR_TOO_HIGH :{WHITE}... too high +STR_ERROR_ALREADY_LEVELLED :{WHITE}... already flat + +# Company related errors +STR_ERROR_CAN_T_CHANGE_COMPANY_NAME :{WHITE}Can't change company name... +STR_ERROR_CAN_T_CHANGE_PRESIDENT :{WHITE}Can't change manager's name... + +STR_ERROR_MAXIMUM_PERMITTED_LOAN :{WHITE}... maximum permitted loan size is {CURRENCY_LONG} +STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY :{WHITE}Can't borrow any more money... +STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}... no loan to repay +STR_ERROR_CURRENCY_REQUIRED :{WHITE}... {CURRENCY_LONG} required +STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}Can't repay loan... +STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}Can't give away money that is loaned from the bank... +STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}Can't buy company... +STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Can't build company headquarters... +STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Can't buy 25% share in this company... +STR_ERROR_CAN_T_SELL_25_SHARE_IN :{WHITE}Can't sell 25% share in this company... +STR_ERROR_PROTECTED :{WHITE}This company is not old enough to trade shares yet... + +# Town related errors +STR_ERROR_CAN_T_GENERATE_TOWN :{WHITE}Can't build any towns +STR_ERROR_CAN_T_RENAME_TOWN :{WHITE}Can't rename town... +STR_ERROR_CAN_T_FOUND_TOWN_HERE :{WHITE}Can't found town here... +STR_ERROR_CAN_T_EXPAND_TOWN :{WHITE}Can't expand town... +STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB :{WHITE}... too close to edge of map +STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... too close to another town +STR_ERROR_TOO_MANY_TOWNS :{WHITE}... too many towns +STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... there is no more space on the map +STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS :{WHITE}The town will not build roads. You can enable building of roads via Advanced Settings->Economy->Towns +STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Road works in progress +STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Can't delete this town...{}A station or depot is referring to the town or a town owned tile can't be removed +STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... there is no suitable place for a statue in the centre of this town + +# Industry related errors +STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... too many industries +STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Can't generate industries... +STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Can't build {STRING} here... +STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Can't construct this industry type here... +STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... too close to another industry +STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... must found town first +STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... only one allowed per town +STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 :{WHITE}... can only be built in towns with a population of at least 1200 +STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}... can only be built in rainforest areas +STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}... can only be built in desert areas +STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}... can only be built in towns (replacing houses) +STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER :{WHITE}... can only be built near the center of towns +STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS :{WHITE}... can only be built in low areas +STR_ERROR_CAN_ONLY_BE_POSITIONED :{WHITE}... can only be positioned near edges of map +STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... forest can only be planted above snow-line +STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... can only be built above the snow-line +STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... can only be built below the snow-line + +# Station construction related errors +STR_ERROR_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Can't build railway station here... +STR_ERROR_CAN_T_BUILD_BUS_STATION :{WHITE}Can't build bus station... +STR_ERROR_CAN_T_BUILD_TRUCK_STATION :{WHITE}Can't build lorry station... +STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION :{WHITE}Can't build passenger tram station... +STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Can't build freight tram station... +STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}Can't build dock here... +STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Can't build airport here... + +STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Adjoins more than one existing station/loading area +STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}... station too spread out +STR_ERROR_TOO_MANY_STATIONS_LOADING :{WHITE}Too many stations/loading areas +STR_ERROR_TOO_MANY_STATION_SPECS :{WHITE}Too many railway station parts +STR_ERROR_TOO_MANY_BUS_STOPS :{WHITE}Too many bus stops +STR_ERROR_TOO_MANY_TRUCK_STOPS :{WHITE}Too many lorry stations +STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}Too close to another station/loading area +STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Too close to another dock +STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}Too close to another airport +STR_ERROR_CAN_T_RENAME_STATION :{WHITE}Can't rename station... +STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... this is a town owned road +STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... road facing in the wrong direction +STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... drive through stops can't have corners +STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... drive through stops can't have junctions + +# Station destruction related errors +STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Can't remove part of station... +STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}Must remove railway station first +STR_ERROR_CAN_T_REMOVE_BUS_STATION :{WHITE}Can't remove bus station... +STR_ERROR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}Can't remove lorry station... +STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION :{WHITE}Can't remove passenger tram station... +STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION :{WHITE}Can't remove freight tram station... +STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST :{WHITE}Must remove road stop first +STR_ERROR_THERE_IS_NO_STATION :{WHITE}... there is no station here + +STR_ERROR_MUST_DEMOLISH_RAILROAD :{WHITE}Must demolish railway station first +STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST :{WHITE}Must demolish bus station first +STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST :{WHITE}Must demolish lorry station first +STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST :{WHITE}Must demolish passenger tram station first +STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST :{WHITE}Must demolish freight tram station first +STR_ERROR_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Must demolish dock first +STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}Must demolish airport first + +# Waypoint related errors +STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Adjoins more than one existing waypoint +STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT :{WHITE}Too close to another waypoint + +STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT :{WHITE}Can't build train waypoint here... +STR_ERROR_CAN_T_POSITION_BUOY_HERE :{WHITE}Can't place buoy here... +STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME :{WHITE}Can't change waypoint name... + +STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT :{WHITE}Can't remove train waypoint here... +STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST :{WHITE}Must remove rail waypoint first +STR_ERROR_BUOY_IN_THE_WAY :{WHITE}... buoy in the way +STR_ERROR_BUOY_IS_IN_USE :{WHITE}... buoy is in use by another company! + +# Depot related errors +STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}Can't build train depot here... +STR_ERROR_CAN_T_BUILD_ROAD_DEPOT :{WHITE}Can't build road vehicle depot here... +STR_ERROR_CAN_T_BUILD_TRAM_DEPOT :{WHITE}Can't build tram vehicle depot here... +STR_ERROR_CAN_T_BUILD_SHIP_DEPOT :{WHITE}Can't build ship depot here... + +STR_ERROR_CAN_T_RENAME_DEPOT :{WHITE}Can't rename depot... + +STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... must be stopped inside a depot +STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... must be stopped inside a depot +STR_ERROR_SHIP_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... must be stopped inside a depot +STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR :{WHITE}... must be stopped inside a hangar + +STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT :{WHITE}Trains can only be altered when stopped inside a depot +STR_ERROR_TRAIN_TOO_LONG :{WHITE}Train too long +STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE :{WHITE}Can't reverse direction of vehicle... +STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS :{WHITE}... consists of multiple units +STR_ERROR_INCOMPATIBLE_RAIL_TYPES :Incompatible rail types + +STR_ERROR_CAN_T_MOVE_VEHICLE :{WHITE}Can't move vehicle... +STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}The rear engine will always follow its front counterpart +STR_ERROR_UNABLE_TO_FIND_ROUTE_TO :{WHITE}Unable to find route to local depot +STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}Unable to find local depot + +STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :Wrong depot type + +# Autoreplace related errors +STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE} is too long after replacement +STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}No autoreplace/renew rules applied +STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(money limit) + +# Rail construction errors +STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}Impossible track combination +STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Must remove signals first +STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}No suitable railway track +STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Must remove railway track first +STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Road is one way or blocked +STR_ERROR_CROSSING_DISALLOWED :{WHITE}Level crossings not allowed for this rail type +STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Can't build signals here... +STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Can't build railway track here... +STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Can't remove railway track from here... +STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Can't remove signals from here... +STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE :{WHITE}Can't convert signals here... +STR_ERROR_THERE_IS_NO_RAILROAD_TRACK :{WHITE}... there is no railway track +STR_ERROR_THERE_ARE_NO_SIGNALS :{WHITE}... there are no signals + +STR_ERROR_CAN_T_CONVERT_RAIL :{WHITE}Can't convert rail type here... + +# Road construction errors +STR_ERROR_MUST_REMOVE_ROAD_FIRST :{WHITE}Must remove road first +STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... one way roads can't have junctions +STR_ERROR_CAN_T_BUILD_ROAD_HERE :{WHITE}Can't build road here... +STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}Can't build tramway here... +STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Can't remove road from here... +STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Can't remove tramway from here... +STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... there is no road +STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... there is no tramway + +# Waterway construction errors +STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Can't build canals here... +STR_ERROR_CAN_T_BUILD_LOCKS :{WHITE}Can't build locks here... +STR_ERROR_CAN_T_PLACE_RIVERS :{WHITE}Can't place rivers here... +STR_ERROR_MUST_BE_BUILT_ON_WATER :{WHITE}... must be built on water +STR_ERROR_CAN_T_BUILD_ON_WATER :{WHITE}... can't build on water +STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}... can't build on open sea +STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... can't build on canal +STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... can't build on river +STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}Must demolish canal first +STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Can't build aqueduct here... + +# Tree related errors +STR_ERROR_TREE_ALREADY_HERE :{WHITE}... tree already here +STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE :{WHITE}... wrong terrain for tree type +STR_ERROR_CAN_T_PLANT_TREE_HERE :{WHITE}Can't plant tree here... + +# Bridge related errors +STR_ERROR_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Can't build bridge here... +STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST :{WHITE}Must demolish bridge first +STR_ERROR_CAN_T_START_AND_END_ON :{WHITE}Can't start and end in the same spot +STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT :{WHITE}Bridge heads not at the same level +STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN :{WHITE}Bridge is too low for the terrain +STR_ERROR_START_AND_END_MUST_BE_IN :{WHITE}Start and end must be in line +STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}... ends of bridge must both be on land +STR_ERROR_BRIDGE_TOO_LONG :{WHITE}... bridge too long +STR_ERROR_BRIDGE_THROUGH_MAP_BORDER :{WHITE}Bridge would end out of the map + +# Tunnel related errors +STR_ERROR_CAN_T_BUILD_TUNNEL_HERE :{WHITE}Can't build tunnel here... +STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL :{WHITE}Site unsuitable for tunnel entrance +STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST :{WHITE}Must demolish tunnel first +STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY :{WHITE}Another tunnel in the way +STR_ERROR_TUNNEL_THROUGH_MAP_BORDER :{WHITE}Tunnel would end out of the map +STR_ERROR_UNABLE_TO_EXCAVATE_LAND :{WHITE}Unable to excavate land for other end of tunnel +STR_ERROR_TUNNEL_TOO_LONG :{WHITE}... tunnel too long + +# Object related errors +STR_ERROR_TOO_MANY_OBJECTS :{WHITE}... too many objects +STR_ERROR_CAN_T_BUILD_OBJECT :{WHITE}Can't build object... +STR_ERROR_OBJECT_IN_THE_WAY :{WHITE}Object in the way +STR_ERROR_COMPANY_HEADQUARTERS_IN :{WHITE}... company headquarters in the way +STR_ERROR_CAN_T_PURCHASE_THIS_LAND :{WHITE}Can't purchase this land area... +STR_ERROR_YOU_ALREADY_OWN_IT :{WHITE}... you already own it! + +# Group related errors +STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Can't create group... +STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Can't delete this group... +STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Can't rename group... +STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Can't remove all vehicles from this group... +STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Can't add the vehicle to this group... +STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Can't add shared vehicles to group... + +# Generic vehicle errors +STR_ERROR_TRAIN_IN_THE_WAY :{WHITE}Train in the way +STR_ERROR_ROAD_VEHICLE_IN_THE_WAY :{WHITE}Road vehicle in the way +STR_ERROR_SHIP_IN_THE_WAY :{WHITE}Ship in the way +STR_ERROR_AIRCRAFT_IN_THE_WAY :{WHITE}Aircraft in the way + +STR_ERROR_CAN_T_REFIT_TRAIN :{WHITE}Can't refit train... +STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE :{WHITE}Can't refit road vehicle... +STR_ERROR_CAN_T_REFIT_SHIP :{WHITE}Can't refit ship... +STR_ERROR_CAN_T_REFIT_AIRCRAFT :{WHITE}Can't refit aircraft... + +STR_ERROR_CAN_T_RENAME_TRAIN :{WHITE}Can't name train... +STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE :{WHITE}Can't name road vehicle... +STR_ERROR_CAN_T_RENAME_SHIP :{WHITE}Can't name ship... +STR_ERROR_CAN_T_RENAME_AIRCRAFT :{WHITE}Can't name aircraft... + +STR_ERROR_CAN_T_STOP_START_TRAIN :{WHITE}Can't stop/start train... +STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE :{WHITE}Can't stop/start road vehicle... +STR_ERROR_CAN_T_STOP_START_SHIP :{WHITE}Can't stop/start ship... +STR_ERROR_CAN_T_STOP_START_AIRCRAFT :{WHITE}Can't stop/start aircraft... + +STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}Can't send train to depot... +STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT :{WHITE}Can't send road vehicle to depot... +STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT :{WHITE}Can't send ship to depot... +STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR :{WHITE}Can't send aircraft to hangar... + +STR_ERROR_CAN_T_BUY_TRAIN :{WHITE}Can't buy railway vehicle... +STR_ERROR_CAN_T_BUY_ROAD_VEHICLE :{WHITE}Can't buy road vehicle... +STR_ERROR_CAN_T_BUY_SHIP :{WHITE}Can't buy ship... +STR_ERROR_CAN_T_BUY_AIRCRAFT :{WHITE}Can't buy aircraft... + +STR_ERROR_CAN_T_RENAME_TRAIN_TYPE :{WHITE}Can't rename train vehicle type... +STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE_TYPE :{WHITE}Can't rename road vehicle type... +STR_ERROR_CAN_T_RENAME_SHIP_TYPE :{WHITE}Can't rename ship type... +STR_ERROR_CAN_T_RENAME_AIRCRAFT_TYPE :{WHITE}Can't rename aircraft type... + +STR_ERROR_CAN_T_SELL_TRAIN :{WHITE}Can't sell railway vehicle... +STR_ERROR_CAN_T_SELL_ROAD_VEHICLE :{WHITE}Can't sell road vehicle... +STR_ERROR_CAN_T_SELL_SHIP :{WHITE}Can't sell ship... +STR_ERROR_CAN_T_SELL_AIRCRAFT :{WHITE}Can't sell aircraft... + +STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE :{WHITE}Vehicle is not available +STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE :{WHITE}Vehicle is not available +STR_ERROR_SHIP_NOT_AVAILABLE :{WHITE}Ship is not available +STR_ERROR_AIRCRAFT_NOT_AVAILABLE :{WHITE}Aircraft is not available + +STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Too many vehicles in game +STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}Can't change servicing interval... + +STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... vehicle is destroyed + +STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}No vehicles will be available at all +STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Change your NewGRF configuration +STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}No vehicles are available yet +STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Start a new game after {DATE_SHORT} or use a NewGRF that provides early vehicles + +# Specific vehicle errors +STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Can't make train pass signal at danger... +STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Can't reverse direction of train... +STR_ERROR_TRAIN_START_NO_POWER :Train has no power + +STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN :{WHITE}Can't make road vehicle turn around... + +STR_ERROR_AIRCRAFT_IS_IN_FLIGHT :{WHITE}Aircraft is in flight + +# Order related errors +STR_ERROR_NO_MORE_SPACE_FOR_ORDERS :{WHITE}No more space for orders +STR_ERROR_TOO_MANY_ORDERS :{WHITE}Too many orders +STR_ERROR_CAN_T_INSERT_NEW_ORDER :{WHITE}Can't insert new order... +STR_ERROR_CAN_T_DELETE_THIS_ORDER :{WHITE}Can't delete this order... +STR_ERROR_CAN_T_MODIFY_THIS_ORDER :{WHITE}Can't modify this order... +STR_ERROR_CAN_T_MOVE_THIS_ORDER :{WHITE}Can't move this order... +STR_ERROR_CAN_T_SKIP_ORDER :{WHITE}Can't skip current order... +STR_ERROR_CAN_T_SKIP_TO_ORDER :{WHITE}Can't skip to selected order... +STR_ERROR_CAN_T_COPY_SHARE_ORDER :{WHITE}... vehicle can't go to all stations +STR_ERROR_CAN_T_ADD_ORDER :{WHITE}... vehicle can't go to that station +STR_ERROR_CAN_T_ADD_ORDER_SHARED :{WHITE}... a vehicle sharing this order can't go to that station + +STR_ERROR_CAN_T_SHARE_ORDER_LIST :{WHITE}Can't share order list... +STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST :{WHITE}Can't stop sharing order list... +STR_ERROR_CAN_T_COPY_ORDER_LIST :{WHITE}Can't copy order list... +STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION :{WHITE}... too far from previous destination +STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... aircraft has not enough range + +# Timetable related errors +STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Can't timetable vehicle... +STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Vehicles can only wait at stations +STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}This vehicle is not stopping at this station + +# Sign related errors +STR_ERROR_TOO_MANY_SIGNS :{WHITE}... too many signs +STR_ERROR_CAN_T_PLACE_SIGN_HERE :{WHITE}Can't place sign here... +STR_ERROR_CAN_T_CHANGE_SIGN_NAME :{WHITE}Can't change sign name... +STR_ERROR_CAN_T_DELETE_SIGN :{WHITE}Can't delete sign... + +# Translatable comment for OpenTTD's desktop shortcut +STR_DESKTOP_SHORTCUT_COMMENT :A simulation game based on Transport Tycoon Deluxe + +# Translatable descriptions in media/baseset/*.ob* files +STR_BASEGRAPHICS_DOS_DESCRIPTION :Original Transport Tycoon Deluxe DOS edition graphics. +STR_BASEGRAPHICS_DOS_DE_DESCRIPTION :Original Transport Tycoon Deluxe DOS (German) edition graphics. +STR_BASEGRAPHICS_WIN_DESCRIPTION :Original Transport Tycoon Deluxe Windows edition graphics. +STR_BASESOUNDS_DOS_DESCRIPTION :Original Transport Tycoon Deluxe DOS edition sounds. +STR_BASESOUNDS_WIN_DESCRIPTION :Original Transport Tycoon Deluxe Windows edition sounds. +STR_BASESOUNDS_NONE_DESCRIPTION :A sound pack without any sounds. +STR_BASEMUSIC_WIN_DESCRIPTION :Original Transport Tycoon Deluxe Windows edition music. +STR_BASEMUSIC_NONE_DESCRIPTION :A music pack without actual music. + +##id 0x2000 +# Town building names +STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1 :Tall office block +STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1 :Office block +STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1 :Small block of flats +STR_TOWN_BUILDING_NAME_CHURCH_1 :Church +STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1 :Large office block +STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1 :Town houses +STR_TOWN_BUILDING_NAME_HOTEL_1 :Hotel +STR_TOWN_BUILDING_NAME_STATUE_1 :Statue +STR_TOWN_BUILDING_NAME_FOUNTAIN_1 :Fountain +STR_TOWN_BUILDING_NAME_PARK_1 :Park +STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2 :Office block +STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1 :Shops and offices +STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1 :Modern office building +STR_TOWN_BUILDING_NAME_WAREHOUSE_1 :Warehouse +STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3 :Office block +STR_TOWN_BUILDING_NAME_STADIUM_1 :Stadium +STR_TOWN_BUILDING_NAME_OLD_HOUSES_1 :Old houses +STR_TOWN_BUILDING_NAME_COTTAGES_1 :Cottages +STR_TOWN_BUILDING_NAME_HOUSES_1 :Houses +STR_TOWN_BUILDING_NAME_FLATS_1 :Flats +STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2 :Tall office block +STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2 :Shops and offices +STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3 :Shops and offices +STR_TOWN_BUILDING_NAME_THEATER_1 :Theatre +STR_TOWN_BUILDING_NAME_STADIUM_2 :Stadium +STR_TOWN_BUILDING_NAME_OFFICES_1 :Offices +STR_TOWN_BUILDING_NAME_HOUSES_2 :Houses +STR_TOWN_BUILDING_NAME_CINEMA_1 :Cinema +STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1 :Shopping centre +STR_TOWN_BUILDING_NAME_IGLOO_1 :Igloo +STR_TOWN_BUILDING_NAME_TEPEES_1 :Tepees +STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1 :Teapot-House +STR_TOWN_BUILDING_NAME_PIGGY_BANK_1 :Piggy-Bank + +##id 0x4800 +# industry names +STR_INDUSTRY_NAME_COAL_MINE :Coal Mine +STR_INDUSTRY_NAME_POWER_STATION :Power Station +STR_INDUSTRY_NAME_SAWMILL :Sawmill +STR_INDUSTRY_NAME_FOREST :Forest +STR_INDUSTRY_NAME_OIL_REFINERY :Oil Refinery +STR_INDUSTRY_NAME_OIL_RIG :Oil Rig +STR_INDUSTRY_NAME_FACTORY :Factory +STR_INDUSTRY_NAME_PRINTING_WORKS :Printing Works +STR_INDUSTRY_NAME_STEEL_MILL :Steel Mill +STR_INDUSTRY_NAME_FARM :Farm +STR_INDUSTRY_NAME_COPPER_ORE_MINE :Copper Ore Mine +STR_INDUSTRY_NAME_OIL_WELLS :Oil Wells +STR_INDUSTRY_NAME_BANK :Bank +STR_INDUSTRY_NAME_FOOD_PROCESSING_PLANT :Food Processing Plant +STR_INDUSTRY_NAME_PAPER_MILL :Paper Mill +STR_INDUSTRY_NAME_GOLD_MINE :Gold Mine +STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC :Bank +STR_INDUSTRY_NAME_DIAMOND_MINE :Diamond Mine +STR_INDUSTRY_NAME_IRON_ORE_MINE :Iron Ore Mine +STR_INDUSTRY_NAME_FRUIT_PLANTATION :Fruit Plantation +STR_INDUSTRY_NAME_RUBBER_PLANTATION :Rubber Plantation +STR_INDUSTRY_NAME_WATER_SUPPLY :Water Supply +STR_INDUSTRY_NAME_WATER_TOWER :Water Tower +STR_INDUSTRY_NAME_FACTORY_2 :Factory +STR_INDUSTRY_NAME_FARM_2 :Farm +STR_INDUSTRY_NAME_LUMBER_MILL :Lumber Mill +STR_INDUSTRY_NAME_COTTON_CANDY_FOREST :Candyfloss Forest +STR_INDUSTRY_NAME_CANDY_FACTORY :Sweet Factory +STR_INDUSTRY_NAME_BATTERY_FARM :Battery Farm +STR_INDUSTRY_NAME_COLA_WELLS :Cola Wells +STR_INDUSTRY_NAME_TOY_SHOP :Toy Shop +STR_INDUSTRY_NAME_TOY_FACTORY :Toy Factory +STR_INDUSTRY_NAME_PLASTIC_FOUNTAINS :Plastic Fountains +STR_INDUSTRY_NAME_FIZZY_DRINK_FACTORY :Fizzy Drink Factory +STR_INDUSTRY_NAME_BUBBLE_GENERATOR :Bubble Generator +STR_INDUSTRY_NAME_TOFFEE_QUARRY :Toffee Quarry +STR_INDUSTRY_NAME_SUGAR_MINE :Sugar Mine + +############ WARNING, using range 0x6000 for strings that are stored in the savegame +############ These strings may never get a new id, or savegames will break! +##id 0x6000 +STR_SV_EMPTY : +STR_SV_UNNAMED :Unnamed +STR_SV_TRAIN_NAME :Train {COMMA} +STR_SV_ROAD_VEHICLE_NAME :Road Vehicle {COMMA} +STR_SV_SHIP_NAME :Ship {COMMA} +STR_SV_AIRCRAFT_NAME :Aircraft {COMMA} + +STR_SV_STNAME :{STRING1} +STR_SV_STNAME_NORTH :{STRING1} North +STR_SV_STNAME_SOUTH :{STRING1} South +STR_SV_STNAME_EAST :{STRING1} East +STR_SV_STNAME_WEST :{STRING1} West +STR_SV_STNAME_CENTRAL :{STRING1} Central +STR_SV_STNAME_TRANSFER :{STRING1} Transfer +STR_SV_STNAME_HALT :{STRING1} Halt +STR_SV_STNAME_VALLEY :{STRING1} Valley +STR_SV_STNAME_HEIGHTS :{STRING1} Heights +STR_SV_STNAME_WOODS :{STRING1} Woods +STR_SV_STNAME_LAKESIDE :{STRING1} Lakeside +STR_SV_STNAME_EXCHANGE :{STRING1} Exchange +STR_SV_STNAME_AIRPORT :{STRING1} Airport +STR_SV_STNAME_OILFIELD :{STRING1} Oilfield +STR_SV_STNAME_MINES :{STRING1} Mines +STR_SV_STNAME_DOCKS :{STRING1} Docks +STR_SV_STNAME_BUOY :{STRING2} +STR_SV_STNAME_WAYPOINT :{STRING2} +##id 0x6020 +STR_SV_STNAME_ANNEXE :{STRING1} Annexe +STR_SV_STNAME_SIDINGS :{STRING1} Sidings +STR_SV_STNAME_BRANCH :{STRING1} Branch +STR_SV_STNAME_UPPER :Upper {STRING1} +STR_SV_STNAME_LOWER :Lower {STRING1} +STR_SV_STNAME_HELIPORT :{STRING1} Heliport +STR_SV_STNAME_FOREST :{STRING1} Forest +STR_SV_STNAME_FALLBACK :{STRING1} Station #{NUM} +############ end of savegame specific region! + +##id 0x8000 +# Vehicle names +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM :Kirby Paul Tank (Steam) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_250_DIESEL :MJS 250 (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_CHOO_CHOO :Ploddyphut Choo-Choo +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_CHOO_CHOO :Powernaut Choo-Choo +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MIGHTYMOVER_CHOO_CHOO :MightyMover Choo-Choo +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_DIESEL :Ploddyphut Diesel +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_DIESEL :Powernaut Diesel +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_WILLS_2_8_0_STEAM :Wills 2-8-0 (Steam) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CHANEY_JUBILEE_STEAM :Chaney 'Jubilee' (Steam) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_GINZU_A4_STEAM :Ginzu 'A4' (Steam) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_8P_STEAM :SH '8P' (Steam) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MANLEY_MOREL_DMU_DIESEL :Manley-Morel DMU (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_DASH_DIESEL :'Dash' (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_HENDRY_25_DIESEL :SH/Hendry '25' (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_UU_37_DIESEL :UU '37' (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_FLOSS_47_DIESEL :Floss '47' (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_4000_DIESEL :CS 4000 (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_2400_DIESEL :CS 2400 (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CENTENNIAL_DIESEL :Centennial (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KELLING_3100_DIESEL :Kelling 3100 (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_TURNER_TURBO_DIESEL :Turner Turbo (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_1000_DIESEL :MJS 1000 (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_125_DIESEL :SH '125' (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_30_ELECTRIC :SH '30' (Electric) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_40_ELECTRIC :SH '40' (Electric) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_T_I_M_ELECTRIC :'T.I.M.' (Electric) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_ASIASTAR_ELECTRIC :'AsiaStar' (Electric) +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PASSENGER_CAR :Passenger Carriage +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_MAIL_VAN :Mail Van +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COAL_CAR :Coal Truck +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_OIL_TANKER :Oil Tanker +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_LIVESTOCK_VAN :Livestock Van +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GOODS_VAN :Goods Van +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GRAIN_HOPPER :Grain Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WOOD_TRUCK :Wood Truck +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_IRON_ORE_HOPPER :Iron Ore Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_STEEL_TRUCK :Steel Truck +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_ARMORED_VAN :Armoured Van +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FOOD_VAN :Food Van +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PAPER_TRUCK :Paper Truck +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COPPER_ORE_HOPPER :Copper Ore Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WATER_TANKER :Water Tanker +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FRUIT_TRUCK :Fruit Truck +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_RUBBER_TRUCK :Rubber Truck +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_SUGAR_TRUCK :Sugar Truck +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COTTON_CANDY_HOPPER :Candyfloss Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOFFEE_HOPPER :Toffee Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BUBBLE_VAN :Bubble Van +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COLA_TANKER :Cola Tanker +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_CANDY_VAN :Sweet Van +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOY_VAN :Toy Van +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BATTERY_TRUCK :Battery Truck +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FIZZY_DRINK_TRUCK :Fizzy Drink Truck +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PLASTIC_TRUCK :Plastic Truck +STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_X2001_ELECTRIC :'X2001' (Electric) +STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_MILLENNIUM_Z1_ELECTRIC :'Millennium Z1' (Electric) +STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_WIZZOWOW_Z99 :Wizzowow Z99 +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PASSENGER_CAR :Passenger Carriage +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_MAIL_VAN :Mail Van +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COAL_CAR :Coal Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_OIL_TANKER :Oil Tanker +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_LIVESTOCK_VAN :Livestock Van +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GOODS_VAN :Goods Van +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GRAIN_HOPPER :Grain Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WOOD_TRUCK :Wood Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_IRON_ORE_HOPPER :Iron Ore Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_STEEL_TRUCK :Steel Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_ARMORED_VAN :Armoured Van +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FOOD_VAN :Food Van +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PAPER_TRUCK :Paper Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COPPER_ORE_HOPPER :Copper Ore Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WATER_TANKER :Water Tanker +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FRUIT_TRUCK :Fruit Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_RUBBER_TRUCK :Rubber Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_SUGAR_TRUCK :Sugar Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COTTON_CANDY_HOPPER :Candyfloss Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOFFEE_HOPPER :Toffee Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BUBBLE_VAN :Bubble Van +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COLA_TANKER :Cola Tanker +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_CANDY_VAN :Sweet Van +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOY_VAN :Toy Van +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BATTERY_TRUCK :Battery Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FIZZY_DRINK_TRUCK :Fizzy Drink Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PLASTIC_TRUCK :Plastic Truck +STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV1_LEVIATHAN_ELECTRIC :Lev1 'Leviathan' (Electric) +STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV2_CYCLOPS_ELECTRIC :Lev2 'Cyclops' (Electric) +STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV3_PEGASUS_ELECTRIC :Lev3 'Pegasus' (Electric) +STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV4_CHIMAERA_ELECTRIC :Lev4 'Chimaera' (Electric) +STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_WIZZOWOW_ROCKETEER :Wizzowow Rocketeer +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PASSENGER_CAR :Passenger Carriage +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_MAIL_VAN :Mail Van +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COAL_CAR :Coal Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_OIL_TANKER :Oil Tanker +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_LIVESTOCK_VAN :Livestock Van +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GOODS_VAN :Goods Van +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GRAIN_HOPPER :Grain Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WOOD_TRUCK :Wood Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_IRON_ORE_HOPPER :Iron Ore Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_STEEL_TRUCK :Steel Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_ARMORED_VAN :Armoured Van +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FOOD_VAN :Food Van +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PAPER_TRUCK :Paper Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COPPER_ORE_HOPPER :Copper Ore Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WATER_TANKER :Water Tanker +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FRUIT_TRUCK :Fruit Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_RUBBER_TRUCK :Rubber Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_SUGAR_TRUCK :Sugar Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COTTON_CANDY_HOPPER :Candyfloss Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOFFEE_HOPPER :Toffee Hopper +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BUBBLE_VAN :Bubble Van +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COLA_TANKER :Cola Tanker +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_CANDY_VAN :Sweet Van +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOY_VAN :Toy Van +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BATTERY_TRUCK :Battery Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FIZZY_DRINK_TRUCK :Fizzy Drink Truck +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PLASTIC_TRUCK :Plastic Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS :MPS Regal Bus +STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_LEOPARD_BUS :Hereford Leopard Bus +STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_BUS :Foster Bus +STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_MKII_SUPERBUS :Foster MkII Superbus +STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKI_BUS :Ploddyphut MkI Bus +STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKII_BUS :Ploddyphut MkII Bus +STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKIII_BUS :Ploddyphut MkIII Bus +STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_COAL_TRUCK :Balogh Coal Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COAL_TRUCK :Uhl Coal Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_DW_COAL_TRUCK :DW Coal Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_MAIL_TRUCK :MPS Mail Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_REYNARD_MAIL_TRUCK :Reynard Mail Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_MAIL_TRUCK :Perry Mail Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_MAIL_TRUCK :MightyMover Mail Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_MAIL_TRUCK :Powernaught Mail Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_MAIL_TRUCK :Wizzowow Mail Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_OIL_TANKER :Witcombe Oil Tanker +STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_OIL_TANKER :Foster Oil Tanker +STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_OIL_TANKER :Perry Oil Tanker +STR_VEHICLE_NAME_ROAD_VEHICLE_TALBOTT_LIVESTOCK_VAN :Talbott Livestock Van +STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_LIVESTOCK_VAN :Uhl Livestock Van +STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_LIVESTOCK_VAN :Foster Livestock Van +STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_GOODS_TRUCK :Balogh Goods Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_CRAIGHEAD_GOODS_TRUCK :Craighead Goods Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GOODS_TRUCK :Goss Goods Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_GRAIN_TRUCK :Hereford Grain Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_THOMAS_GRAIN_TRUCK :Thomas Grain Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GRAIN_TRUCK :Goss Grain Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_WOOD_TRUCK :Witcombe Wood Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_WOOD_TRUCK :Foster Wood Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MORELAND_WOOD_TRUCK :Moreland Wood Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_IRON_ORE_TRUCK :MPS Iron Ore Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_IRON_ORE_TRUCK :Uhl Iron Ore Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_IRON_ORE_TRUCK :Chippy Iron Ore Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_STEEL_TRUCK :Balogh Steel Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_STEEL_TRUCK :Uhl Steel Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_STEEL_TRUCK :Kelling Steel Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_ARMORED_TRUCK :Balogh Armoured Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_ARMORED_TRUCK :Uhl Armoured Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_ARMORED_TRUCK :Foster Armoured Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_FOOD_VAN :Foster Food Van +STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_FOOD_VAN :Perry Food Van +STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_FOOD_VAN :Chippy Food Van +STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_PAPER_TRUCK :Uhl Paper Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_PAPER_TRUCK :Balogh Paper Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_PAPER_TRUCK :MPS Paper Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_COPPER_ORE_TRUCK :MPS Copper Ore Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COPPER_ORE_TRUCK :Uhl Copper Ore Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_COPPER_ORE_TRUCK :Goss Copper Ore Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_WATER_TANKER :Uhl Water Tanker +STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_WATER_TANKER :Balogh Water Tanker +STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_WATER_TANKER :MPS Water Tanker +STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_FRUIT_TRUCK :Balogh Fruit Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_FRUIT_TRUCK :Uhl Fruit Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_FRUIT_TRUCK :Kelling Fruit Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_RUBBER_TRUCK :Balogh Rubber Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_RUBBER_TRUCK :Uhl Rubber Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_RMT_RUBBER_TRUCK :RMT Rubber Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_SUGAR_TRUCK :MightyMover Sugar Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_SUGAR_TRUCK :Powernaught Sugar Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_SUGAR_TRUCK :Wizzowow Sugar Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COLA_TRUCK :MightyMover Cola Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COLA_TRUCK :Powernaught Cola Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COLA_TRUCK :Wizzowow Cola Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COTTON_CANDY :MightyMover Candyfloss Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COTTON_CANDY :Powernaught Candyfloss Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COTTON_CANDY_TRUCK :Wizzowow Candyfloss Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOFFEE_TRUCK :MightyMover Toffee Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOFFEE_TRUCK :Powernaught Toffee Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOFFEE_TRUCK :Wizzowow Toffee Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOY_VAN :MightyMover Toy Van +STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOY_VAN :Powernaught Toy Van +STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOY_VAN :Wizzowow Toy Van +STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_CANDY_TRUCK :MightyMover Sweet Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_CANDY_TRUCK :Powernaught Sweet Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_CANDY_TRUCK :Wizzowow Sweet Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BATTERY_TRUCK :MightyMover Battery Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BATTERY_TRUCK :Powernaught Battery Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BATTERY_TRUCK :Wizzowow Battery Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_FIZZY_DRINK :MightyMover Fizzy Drink Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_FIZZY_DRINK :Powernaught Fizzy Drink Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_FIZZY_DRINK_TRUCK :Wizzowow Fizzy Drink Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_PLASTIC_TRUCK :MightyMover Plastic Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_PLASTIC_TRUCK :Powernaught Plastic Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_PLASTIC_TRUCK :Wizzowow Plastic Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BUBBLE_TRUCK :MightyMover Bubble Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BUBBLE_TRUCK :Powernaught Bubble Truck +STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BUBBLE_TRUCK :Wizzowow Bubble Truck +STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER :MPS Oil Tanker +STR_VEHICLE_NAME_SHIP_CS_INC_OIL_TANKER :CS-Inc. Oil Tanker +STR_VEHICLE_NAME_SHIP_MPS_PASSENGER_FERRY :MPS Passenger Ferry +STR_VEHICLE_NAME_SHIP_FFP_PASSENGER_FERRY :FFP Passenger Ferry +STR_VEHICLE_NAME_SHIP_BAKEWELL_300_HOVERCRAFT :Bakewell 300 Hovercraft +STR_VEHICLE_NAME_SHIP_CHUGGER_CHUG_PASSENGER :Chugger-Chug Passenger Ferry +STR_VEHICLE_NAME_SHIP_SHIVERSHAKE_PASSENGER_FERRY :Shivershake Passenger Ferry +STR_VEHICLE_NAME_SHIP_YATE_CARGO_SHIP :Yate Cargo Ship +STR_VEHICLE_NAME_SHIP_BAKEWELL_CARGO_SHIP :Bakewell Cargo Ship +STR_VEHICLE_NAME_SHIP_MIGHTYMOVER_CARGO_SHIP :MightyMover Cargo Ship +STR_VEHICLE_NAME_SHIP_POWERNAUT_CARGO_SHIP :Powernaut Cargo Ship +STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 :Sampson U52 +STR_VEHICLE_NAME_AIRCRAFT_COLEMAN_COUNT :Coleman Count +STR_VEHICLE_NAME_AIRCRAFT_FFP_DART :FFP Dart +STR_VEHICLE_NAME_AIRCRAFT_YATE_HAUGAN :Yate Haugan +STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_COTSWALD_LB_3 :Bakewell Cotswald LB-3 +STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_8 :Bakewell Luckett LB-8 +STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_9 :Bakewell Luckett LB-9 +STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB80 :Bakewell Luckett LB80 +STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_10 :Bakewell Luckett LB-10 +STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_11 :Bakewell Luckett LB-11 +STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAC_1_11 :Yate Aerospace YAC 1-11 +STR_VEHICLE_NAME_AIRCRAFT_DARWIN_100 :Darwin 100 +STR_VEHICLE_NAME_AIRCRAFT_DARWIN_200 :Darwin 200 +STR_VEHICLE_NAME_AIRCRAFT_DARWIN_300 :Darwin 300 +STR_VEHICLE_NAME_AIRCRAFT_DARWIN_400 :Darwin 400 +STR_VEHICLE_NAME_AIRCRAFT_DARWIN_500 :Darwin 500 +STR_VEHICLE_NAME_AIRCRAFT_DARWIN_600 :Darwin 600 +STR_VEHICLE_NAME_AIRCRAFT_GURU_GALAXY :Guru Galaxy +STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A21 :Airtaxi A21 +STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A31 :Airtaxi A31 +STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A32 :Airtaxi A32 +STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A33 :Airtaxi A33 +STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAE46 :Yate Aerospace YAe46 +STR_VEHICLE_NAME_AIRCRAFT_DINGER_100 :Dinger 100 +STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A34_1000 :AirTaxi A34-1000 +STR_VEHICLE_NAME_AIRCRAFT_YATE_Z_SHUTTLE :Yate Z-Shuttle +STR_VEHICLE_NAME_AIRCRAFT_KELLING_K1 :Kelling K1 +STR_VEHICLE_NAME_AIRCRAFT_KELLING_K6 :Kelling K6 +STR_VEHICLE_NAME_AIRCRAFT_KELLING_K7 :Kelling K7 +STR_VEHICLE_NAME_AIRCRAFT_DARWIN_700 :Darwin 700 +STR_VEHICLE_NAME_AIRCRAFT_FFP_HYPERDART_2 :FFP Hyperdart 2 +STR_VEHICLE_NAME_AIRCRAFT_DINGER_200 :Dinger 200 +STR_VEHICLE_NAME_AIRCRAFT_DINGER_1000 :Dinger 1000 +STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_100 :Ploddyphut 100 +STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_500 :Ploddyphut 500 +STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_X1 :Flashbang X1 +STR_VEHICLE_NAME_AIRCRAFT_JUGGERPLANE_M1 :Juggerplane M1 +STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_WIZZER :Flashbang Wizzer +STR_VEHICLE_NAME_AIRCRAFT_TRICARIO_HELICOPTER :Tricario Helicopter +STR_VEHICLE_NAME_AIRCRAFT_GURU_X2_HELICOPTER :Guru X2 Helicopter +STR_VEHICLE_NAME_AIRCRAFT_POWERNAUT_HELICOPTER :Powernaut Helicopter + +##id 0x8800 +# Formatting of some strings +STR_FORMAT_DATE_TINY :{RAW_STRING}-{RAW_STRING}-{NUM} +STR_FORMAT_DATE_SHORT :{STRING} {NUM} +STR_FORMAT_DATE_LONG :{STRING} {STRING} {NUM} +STR_FORMAT_DATE_ISO :{2:NUM}-{1:RAW_STRING}-{0:RAW_STRING} + +STR_FORMAT_BUOY_NAME :{TOWN} Buoy +STR_FORMAT_BUOY_NAME_SERIAL :{TOWN} Buoy #{COMMA} +STR_FORMAT_COMPANY_NUM :(Company {COMMA}) +STR_FORMAT_GROUP_NAME :Group {COMMA} +STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING} +STR_FORMAT_WAYPOINT_NAME :{TOWN} Waypoint +STR_FORMAT_WAYPOINT_NAME_SERIAL :{TOWN} Waypoint #{COMMA} + +STR_FORMAT_DEPOT_NAME_TRAIN :{TOWN} Train Depot +STR_FORMAT_DEPOT_NAME_TRAIN_SERIAL :{TOWN} Train Depot #{COMMA} +STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE :{TOWN} Road Vehicle Depot +STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE_SERIAL :{TOWN} Road Vehicle Depot #{COMMA} +STR_FORMAT_DEPOT_NAME_SHIP :{TOWN} Ship Depot +STR_FORMAT_DEPOT_NAME_SHIP_SERIAL :{TOWN} Ship Depot #{COMMA} +STR_FORMAT_DEPOT_NAME_AIRCRAFT :{STATION} Hangar + +STR_UNKNOWN_STATION :unknown station +STR_DEFAULT_SIGN_NAME :Sign +STR_COMPANY_SOMEONE :someone + +STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STRING1} +STR_SAVEGAME_NAME_SPECTATOR :Spectator, {1:STRING1} + +# Viewport strings +STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) +STR_VIEWPORT_TOWN :{WHITE}{TOWN} +STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN} +STR_VIEWPORT_TOWN_TINY_WHITE :{TINY_FONT}{WHITE}{TOWN} + +STR_VIEWPORT_SIGN_SMALL_BLACK :{TINY_FONT}{BLACK}{SIGN} +STR_VIEWPORT_SIGN_SMALL_WHITE :{TINY_FONT}{WHITE}{SIGN} + +STR_VIEWPORT_STATION :{STATION} {STATION_FEATURES} +STR_VIEWPORT_STATION_TINY :{TINY_FONT}{STATION} + +STR_VIEWPORT_WAYPOINT :{WAYPOINT} +STR_VIEWPORT_WAYPOINT_TINY :{TINY_FONT}{WAYPOINT} + +# Simple strings to get specific types of data +STR_COMPANY_NAME :{COMPANY} +STR_COMPANY_NAME_COMPANY_NUM :{COMPANY} {COMPANY_NUM} +STR_DEPOT_NAME :{DEPOT} +STR_ENGINE_NAME :{ENGINE} +STR_GROUP_NAME :{GROUP} +STR_INDUSTRY_NAME :{INDUSTRY} +STR_PRESIDENT_NAME :{PRESIDENT_NAME} +STR_SIGN_NAME :{SIGN} +STR_STATION_NAME :{STATION} +STR_TOWN_NAME :{TOWN} +STR_VEHICLE_NAME :{VEHICLE} +STR_WAYPOINT_NAME :{WAYPOINT} + +STR_JUST_CARGO :{CARGO_LONG} +STR_JUST_CHECKMARK :{CHECKMARK} +STR_JUST_COMMA :{COMMA} +STR_JUST_CURRENCY_SHORT :{CURRENCY_SHORT} +STR_JUST_CURRENCY_LONG :{CURRENCY_LONG} +STR_JUST_CARGO_LIST :{CARGO_LIST} +STR_JUST_INT :{NUM} +STR_JUST_DATE_TINY :{DATE_TINY} +STR_JUST_DATE_SHORT :{DATE_SHORT} +STR_JUST_DATE_LONG :{DATE_LONG} +STR_JUST_DATE_ISO :{DATE_ISO} +STR_JUST_STRING :{STRING} +STR_JUST_STRING_STRING :{STRING}{STRING} +STR_JUST_RAW_STRING :{RAW_STRING} +STR_JUST_BIG_RAW_STRING :{BIG_FONT}{RAW_STRING} + +# Slightly 'raw' stringcodes with colour or size +STR_BLACK_COMMA :{BLACK}{COMMA} +STR_TINY_BLACK_COMA :{TINY_FONT}{BLACK}{COMMA} +STR_TINY_COMMA :{TINY_FONT}{COMMA} +STR_BLUE_COMMA :{BLUE}{COMMA} +STR_RED_COMMA :{RED}{COMMA} +STR_WHITE_COMMA :{WHITE}{COMMA} +STR_TINY_BLACK_DECIMAL :{TINY_FONT}{BLACK}{DECIMAL} +STR_COMPANY_MONEY :{WHITE}{CURRENCY_LONG} +STR_BLACK_DATE_LONG :{BLACK}{DATE_LONG} +STR_BLACK_CROSS :{BLACK}{CROSS} +STR_SILVER_CROSS :{SILVER}{CROSS} +STR_WHITE_DATE_LONG :{WHITE}{DATE_LONG} +STR_SHORT_DATE :{WHITE}{DATE_TINY} +STR_DATE_LONG_SMALL :{TINY_FONT}{BLACK}{DATE_LONG} +STR_TINY_GROUP :{TINY_FONT}{GROUP} +STR_BLACK_INT :{BLACK}{NUM} +STR_ORANGE_INT :{ORANGE}{NUM} +STR_WHITE_SIGN :{WHITE}{SIGN} +STR_TINY_BLACK_STATION :{TINY_FONT}{BLACK}{STATION} +STR_BLACK_STRING :{BLACK}{STRING} +STR_BLACK_RAW_STRING :{BLACK}{RAW_STRING} +STR_GREEN_STRING :{GREEN}{STRING} +STR_ORANGE_STRING :{ORANGE}{STRING} +STR_RED_STRING :{RED}{STRING} +STR_LTBLUE_STRING :{LTBLUE}{STRING} +STR_WHITE_STRING :{WHITE}{STRING} +STR_ORANGE_STRING1_WHITE :{ORANGE}{STRING1}{WHITE} +STR_ORANGE_STRING1_LTBLUE :{ORANGE}{STRING1}{LTBLUE} +STR_TINY_BLACK_HEIGHT :{TINY_FONT}{BLACK}{HEIGHT} +STR_TINY_BLACK_VEHICLE :{TINY_FONT}{BLACK}{VEHICLE} +STR_TINY_RIGHT_ARROW :{TINY_FONT}{RIGHT_ARROW} + +STR_BLACK_1 :{BLACK}1 +STR_BLACK_2 :{BLACK}2 +STR_BLACK_3 :{BLACK}3 +STR_BLACK_4 :{BLACK}4 +STR_BLACK_5 :{BLACK}5 +STR_BLACK_6 :{BLACK}6 +STR_BLACK_7 :{BLACK}7 + +STR_TRAIN :{BLACK}{TRAIN} +STR_BUS :{BLACK}{BUS} +STR_LORRY :{BLACK}{LORRY} +STR_PLANE :{BLACK}{PLANE} +STR_SHIP :{BLACK}{SHIP} + +STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) diff --git a/src/misc_gui.cpp.orig b/src/misc_gui.cpp.orig new file mode 100644 index 0000000000..d0075fe038 --- /dev/null +++ b/src/misc_gui.cpp.orig @@ -0,0 +1,1213 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file misc_gui.cpp GUIs for a number of misc windows. */ + +#include "stdafx.h" +#include "debug.h" +#include "landscape.h" +#include "error.h" +#include "gui.h" +#include "command_func.h" +#include "company_func.h" +#include "town.h" +#include "string_func.h" +#include "company_base.h" +#include "texteff.hpp" +#include "strings_func.h" +#include "window_func.h" +#include "querystring_gui.h" +#include "core/geometry_func.hpp" +#include "newgrf_debug.h" + +#include "widgets/misc_widget.h" + +#include "table/strings.h" + +/** Method to open the OSK. */ +enum OskActivation { + OSKA_DISABLED, ///< The OSK shall not be activated at all. + OSKA_DOUBLE_CLICK, ///< Double click on the edit box opens OSK. + OSKA_SINGLE_CLICK, ///< Single click after focus click opens OSK. + OSKA_IMMEDIATELY, ///< Focusing click already opens OSK. +}; + + +static const NWidgetPart _nested_land_info_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_LAND_AREA_INFORMATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_DEBUGBOX, COLOUR_GREY), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_LI_BACKGROUND), EndContainer(), +}; + +static WindowDesc _land_info_desc( + WDP_AUTO, "land_info", 0, 0, + WC_LAND_INFO, WC_NONE, + 0, + _nested_land_info_widgets, lengthof(_nested_land_info_widgets) +); + +class LandInfoWindow : public Window { + enum LandInfoLines { + LAND_INFO_CENTERED_LINES = 32, ///< Up to 32 centered lines (arbitrary limit) + LAND_INFO_MULTICENTER_LINE = LAND_INFO_CENTERED_LINES, ///< One multicenter line + LAND_INFO_LINE_END, + }; + + static const uint LAND_INFO_LINE_BUFF_SIZE = 512; + +public: + char landinfo_data[LAND_INFO_LINE_END][LAND_INFO_LINE_BUFF_SIZE]; + TileIndex tile; + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_LI_BACKGROUND) return; + + uint y = r.top + WD_TEXTPANEL_TOP; + for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) { + if (StrEmpty(this->landinfo_data[i])) break; + + DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, this->landinfo_data[i], i == 0 ? TC_LIGHT_BLUE : TC_FROMSTRING, SA_HOR_CENTER); + y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + if (i == 0) y += 4; + } + + if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) { + SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]); + DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, r.bottom - WD_TEXTPANEL_BOTTOM, STR_JUST_RAW_STRING, TC_FROMSTRING, SA_CENTER); + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget != WID_LI_BACKGROUND) return; + + size->height = WD_TEXTPANEL_TOP + WD_TEXTPANEL_BOTTOM; + for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) { + if (StrEmpty(this->landinfo_data[i])) break; + + uint width = GetStringBoundingBox(this->landinfo_data[i]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; + size->width = max(size->width, width); + + size->height += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + if (i == 0) size->height += 4; + } + + if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) { + uint width = GetStringBoundingBox(this->landinfo_data[LAND_INFO_MULTICENTER_LINE]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; + size->width = max(size->width, min(300u, width)); + SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]); + size->height += GetStringHeight(STR_JUST_RAW_STRING, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT); + } + } + + LandInfoWindow(TileIndex tile) : Window(&_land_info_desc), tile(tile) + { + this->InitNested(); + +#if defined(_DEBUG) +# define LANDINFOD_LEVEL 0 +#else +# define LANDINFOD_LEVEL 1 +#endif + DEBUG(misc, LANDINFOD_LEVEL, "TILE: %#x (%i,%i)", tile, TileX(tile), TileY(tile)); + DEBUG(misc, LANDINFOD_LEVEL, "type_height = %#x", _m[tile].type_height); + DEBUG(misc, LANDINFOD_LEVEL, "m1 = %#x", _m[tile].m1); + DEBUG(misc, LANDINFOD_LEVEL, "m2 = %#x", _m[tile].m2); + DEBUG(misc, LANDINFOD_LEVEL, "m3 = %#x", _m[tile].m3); + DEBUG(misc, LANDINFOD_LEVEL, "m4 = %#x", _m[tile].m4); + DEBUG(misc, LANDINFOD_LEVEL, "m5 = %#x", _m[tile].m5); + DEBUG(misc, LANDINFOD_LEVEL, "m6 = %#x", _m[tile].m6); + DEBUG(misc, LANDINFOD_LEVEL, "m7 = %#x", _me[tile].m7); +#undef LANDINFOD_LEVEL + } + + virtual void OnInit() + { + Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); + + /* Because build_date is not set yet in every TileDesc, we make sure it is empty */ + TileDesc td; + + td.build_date = INVALID_DATE; + + /* Most tiles have only one owner, but + * - drivethrough roadstops can be build on town owned roads (up to 2 owners) and + * - roads can have up to four owners (railroad, road, tram, 3rd-roadtype "highway"). + */ + td.owner_type[0] = STR_LAND_AREA_INFORMATION_OWNER; // At least one owner is displayed, though it might be "N/A". + td.owner_type[1] = STR_NULL; // STR_NULL results in skipping the owner + td.owner_type[2] = STR_NULL; + td.owner_type[3] = STR_NULL; + td.owner[0] = OWNER_NONE; + td.owner[1] = OWNER_NONE; + td.owner[2] = OWNER_NONE; + td.owner[3] = OWNER_NONE; + + td.station_class = STR_NULL; + td.station_name = STR_NULL; + td.airport_class = STR_NULL; + td.airport_name = STR_NULL; + td.airport_tile_name = STR_NULL; + td.rail_speed = 0; + td.road_speed = 0; + + td.grf = NULL; + + CargoArray acceptance; + AddAcceptedCargo(tile, acceptance, NULL); + GetTileDesc(tile, &td); + + uint line_nr = 0; + + /* Tiletype */ + SetDParam(0, td.dparam[0]); + GetString(this->landinfo_data[line_nr], td.str, lastof(this->landinfo_data[line_nr])); + line_nr++; + + /* Up to four owners */ + for (uint i = 0; i < 4; i++) { + if (td.owner_type[i] == STR_NULL) continue; + + SetDParam(0, STR_LAND_AREA_INFORMATION_OWNER_N_A); + if (td.owner[i] != OWNER_NONE && td.owner[i] != OWNER_WATER) GetNameOfOwner(td.owner[i], tile); + GetString(this->landinfo_data[line_nr], td.owner_type[i], lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Cost to clear/revenue when cleared */ + StringID str = STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A; + Company *c = Company::GetIfValid(_local_company); + if (c != NULL) { + Money old_money = c->money; + c->money = INT64_MAX; + assert(_current_company == _local_company); + CommandCost costclear = DoCommand(tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR); + c->money = old_money; + if (costclear.Succeeded()) { + Money cost = costclear.GetCost(); + if (cost < 0) { + cost = -cost; // Negate negative cost to a positive revenue + str = STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED; + } else { + str = STR_LAND_AREA_INFORMATION_COST_TO_CLEAR; + } + SetDParam(0, cost); + } + } + GetString(this->landinfo_data[line_nr], str, lastof(this->landinfo_data[line_nr])); + line_nr++; + + /* Location */ + char tmp[16]; + snprintf(tmp, lengthof(tmp), "0x%.4X", tile); + SetDParam(0, TileX(tile)); + SetDParam(1, TileY(tile)); + SetDParam(2, GetTileZ(tile)); + SetDParamStr(3, tmp); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_LANDINFO_COORDS, lastof(this->landinfo_data[line_nr])); + line_nr++; + + /* Local authority */ + SetDParam(0, STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE); + if (t != NULL) { + SetDParam(0, STR_TOWN_NAME); + SetDParam(1, t->index); + } + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY, lastof(this->landinfo_data[line_nr])); + line_nr++; + + /* Build date */ + if (td.build_date != INVALID_DATE) { + SetDParam(0, td.build_date); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_BUILD_DATE, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Station class */ + if (td.station_class != STR_NULL) { + SetDParam(0, td.station_class); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_STATION_CLASS, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Station type name */ + if (td.station_name != STR_NULL) { + SetDParam(0, td.station_name); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_STATION_TYPE, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Airport class */ + if (td.airport_class != STR_NULL) { + SetDParam(0, td.airport_class); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORT_CLASS, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Airport name */ + if (td.airport_name != STR_NULL) { + SetDParam(0, td.airport_name); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORT_NAME, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Airport tile name */ + if (td.airport_tile_name != STR_NULL) { + SetDParam(0, td.airport_tile_name); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Rail speed limit */ + if (td.rail_speed != 0) { + SetDParam(0, td.rail_speed); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Road speed limit */ + if (td.road_speed != 0) { + SetDParam(0, td.road_speed); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* NewGRF name */ + if (td.grf != NULL) { + SetDParamStr(0, td.grf); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_NEWGRF_NAME, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + assert(line_nr < LAND_INFO_CENTERED_LINES); + + /* Mark last line empty */ + this->landinfo_data[line_nr][0] = '\0'; + + /* Cargo acceptance is displayed in a extra multiline */ + char *strp = GetString(this->landinfo_data[LAND_INFO_MULTICENTER_LINE], STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); + bool found = false; + + for (CargoID i = 0; i < NUM_CARGO; ++i) { + if (acceptance[i] > 0) { + /* Add a comma between each item. */ + if (found) { + *strp++ = ','; + *strp++ = ' '; + } + found = true; + + /* If the accepted value is less than 8, show it in 1/8:ths */ + if (acceptance[i] < 8) { + SetDParam(0, acceptance[i]); + SetDParam(1, CargoSpec::Get(i)->name); + strp = GetString(strp, STR_LAND_AREA_INFORMATION_CARGO_EIGHTS, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); + } else { + strp = GetString(strp, CargoSpec::Get(i)->name, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); + } + } + } + if (!found) this->landinfo_data[LAND_INFO_MULTICENTER_LINE][0] = '\0'; + } + + virtual bool IsNewGRFInspectable() const + { + return ::IsNewGRFInspectable(GetGrfSpecFeature(this->tile), this->tile); + } + + virtual void ShowNewGRFInspectWindow() const + { + ::ShowNewGRFInspectWindow(GetGrfSpecFeature(this->tile), this->tile); + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + switch (data) { + case 1: + /* ReInit, "debug" sprite might have changed */ + this->ReInit(); + break; + } + } +}; + +/** + * Show land information window. + * @param tile The tile to show information about. + */ +void ShowLandInfo(TileIndex tile) +{ + DeleteWindowById(WC_LAND_INFO, 0); + new LandInfoWindow(tile); +} + +static const NWidgetPart _nested_about_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_ABOUT_OPENTTD, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), SetPIP(4, 2, 4), + NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_ABOUT_ORIGINAL_COPYRIGHT, STR_NULL), + NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_ABOUT_VERSION, STR_NULL), + NWidget(WWT_FRAME, COLOUR_GREY), SetPadding(0, 5, 1, 5), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_A_SCROLLING_TEXT), + EndContainer(), + NWidget(WWT_LABEL, COLOUR_GREY, WID_A_WEBSITE), SetDataTip(STR_BLACK_RAW_STRING, STR_NULL), + NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_ABOUT_COPYRIGHT_OPENTTD, STR_NULL), + EndContainer(), +}; + +static WindowDesc _about_desc( + WDP_CENTER, NULL, 0, 0, + WC_GAME_OPTIONS, WC_NONE, + 0, + _nested_about_widgets, lengthof(_nested_about_widgets) +); + +static const char * const _credits[] = { + "Original design by Chris Sawyer", + "Original graphics by Simon Foster", + "", + "The OpenTTD team (in alphabetical order):", + " Albert Hofkamp (Alberth) - GUI expert", + " Jean-Fran\xC3\xA7ois Claeys (Belugas) - GUI, newindustries and more", + " Matthijs Kooijman (blathijs) - Pathfinder-guru, pool rework", + " Christoph Elsenhans (frosch) - General coding", + " Ulf Hermann (fonsinchen) - Cargo Distribution", + " Lo\xC3\xAF""c Guilloux (glx) - Windows Expert", + " Michael Lutz (michi_cc) - Path based signals", + " Owen Rudge (orudge) - Forum host, OS/2 port", + " Peter Nelson (peter1138) - Spiritual descendant from NewGRF gods", + " Ingo von Borstel (planetmaker) - Support", + " Remko Bijker (Rubidium) - Lead coder and way more", + " Zden\xC4\x9Bk Sojka (SmatZ) - Bug finder and fixer", + " Jos\xC3\xA9 Soler (Terkhen) - General coding", + " Thijs Marinussen (Yexo) - AI Framework", + " Leif Linse (Zuu) - AI/Game Script", + "", + "Inactive Developers:", + " Bjarni Corfitzen (Bjarni) - MacOSX port, coder and vehicles", + " Victor Fischer (Celestar) - Programming everywhere you need him to", + " Tam\xC3\xA1s Farag\xC3\xB3 (Darkvater) - Ex-Lead coder", + " Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;)", + " Jonathan Coome (Maedhros) - High priest of the NewGRF Temple", + " Attila B\xC3\xA1n (MiHaMiX) - Developer WebTranslator 1 and 2", + " Christoph Mallon (Tron) - Programmer, code correctness police", + "", + "Retired Developers:", + " Ludvig Strigeus (ludde) - OpenTTD author, main coder (0.1 - 0.3.3)", + " Serge Paquet (vurlix) - Assistant project manager, coder (0.1 - 0.3.3)", + " Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3.0 - 0.3.6)", + " Benedikt Br\xC3\xBCggemeier (skidd13) - Bug fixer and code reworker", + " Patric Stout (TrueBrain) - NoProgrammer (0.3 - 1.2), sys op (active)", + "", + "Special thanks go out to:", + " Josef Drexler - For his great work on TTDPatch", + " Marcin Grzegorczyk - Track foundations and for describing TTD internals", + " Petr Baudi\xC5\xA1 (pasky) - Many patches, newGRF support", + " Simon Sasburg (HackyKid) - Many bugfixes he has blessed us with", + " Stefan Mei\xC3\x9Fner (sign_de) - For his work on the console", + " Mike Ragsdale - OpenTTD installer", + " Cian Duffy (MYOB) - BeOS port / manual writing", + " Christian Rosentreter (tokai) - MorphOS / AmigaOS port", + " Richard Kempton (richK) - additional airports, initial TGP implementation", + "", + " Alberto Demichelis - Squirrel scripting language \xC2\xA9 2003-2008", + " L. Peter Deutsch - MD5 implementation \xC2\xA9 1999, 2000, 2002", + " Michael Blunck - Pre-signals and semaphores \xC2\xA9 2003", + " George - Canal/Lock graphics \xC2\xA9 2003-2004", + " Andrew Parkhouse (andythenorth) - River graphics", + " David Dallaston (Pikka) - Tram tracks", + " All Translators - Who made OpenTTD a truly international game", + " Bug Reporters - Without whom OpenTTD would still be full of bugs!", + "", + "", + "And last but not least:", + " Chris Sawyer - For an amazing game!" +}; + +struct AboutWindow : public Window { + int text_position; ///< The top of the scrolling text + byte counter; ///< Used to scroll the text every 5 ticks + int line_height; ///< The height of a single line + static const int num_visible_lines = 19; ///< The number of lines visible simultaneously + + AboutWindow() : Window(&_about_desc) + { + this->InitNested(WN_GAME_OPTIONS_ABOUT); + + this->counter = 5; + this->text_position = this->GetWidget(WID_A_SCROLLING_TEXT)->pos_y + this->GetWidget(WID_A_SCROLLING_TEXT)->current_y; + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_A_WEBSITE) SetDParamStr(0, "Website: http://www.openttd.org"); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget != WID_A_SCROLLING_TEXT) return; + + this->line_height = FONT_HEIGHT_NORMAL; + + Dimension d; + d.height = this->line_height * num_visible_lines; + + d.width = 0; + for (uint i = 0; i < lengthof(_credits); i++) { + d.width = max(d.width, GetStringBoundingBox(_credits[i]).width); + } + *size = maxdim(*size, d); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_A_SCROLLING_TEXT) return; + + int y = this->text_position; + + /* Show all scrolling _credits */ + for (uint i = 0; i < lengthof(_credits); i++) { + if (y >= r.top + 7 && y < r.bottom - this->line_height) { + DrawString(r.left, r.right, y, _credits[i], TC_BLACK, SA_LEFT | SA_FORCE); + } + y += this->line_height; + } + } + + virtual void OnTick() + { + if (--this->counter == 0) { + this->counter = 5; + this->text_position--; + /* If the last text has scrolled start a new from the start */ + if (this->text_position < (int)(this->GetWidget(WID_A_SCROLLING_TEXT)->pos_y - lengthof(_credits) * this->line_height)) { + this->text_position = this->GetWidget(WID_A_SCROLLING_TEXT)->pos_y + this->GetWidget(WID_A_SCROLLING_TEXT)->current_y; + } + this->SetDirty(); + } + } +}; + +void ShowAboutWindow() +{ + DeleteWindowByClass(WC_GAME_OPTIONS); + new AboutWindow(); +} + +/** + * Display estimated costs. + * @param cost Estimated cost (or income if negative). + * @param x X position of the notification window. + * @param y Y position of the notification window. + */ +void ShowEstimatedCostOrIncome(Money cost, int x, int y) +{ + StringID msg = STR_MESSAGE_ESTIMATED_COST; + + if (cost < 0) { + cost = -cost; + msg = STR_MESSAGE_ESTIMATED_INCOME; + } + SetDParam(0, cost); + ShowErrorMessage(msg, INVALID_STRING_ID, WL_INFO, x, y); +} + +/** + * Display animated income or costs on the map. + * @param x World X position of the animation location. + * @param y World Y position of the animation location. + * @param z World Z position of the animation location. + * @param cost Estimated cost (or income if negative). + */ +void ShowCostOrIncomeAnimation(int x, int y, int z, Money cost) +{ + Point pt = RemapCoords(x, y, z); + StringID msg = STR_INCOME_FLOAT_COST; + + if (cost < 0) { + cost = -cost; + msg = STR_INCOME_FLOAT_INCOME; + } + SetDParam(0, cost); + AddTextEffect(msg, pt.x, pt.y, DAY_TICKS, TE_RISING); +} + +/** + * Display animated feeder income. + * @param x World X position of the animation location. + * @param y World Y position of the animation location. + * @param z World Z position of the animation location. + * @param transfer Estimated feeder income. + * @param income Real income from goods being delivered to their final destination. + */ +void ShowFeederIncomeAnimation(int x, int y, int z, Money transfer, Money income) +{ + Point pt = RemapCoords(x, y, z); + + SetDParam(0, transfer); + if (income == 0) { + AddTextEffect(STR_FEEDER, pt.x, pt.y, DAY_TICKS, TE_RISING); + } else { + StringID msg = STR_FEEDER_COST; + if (income < 0) { + income = -income; + msg = STR_FEEDER_INCOME; + } + SetDParam(1, income); + AddTextEffect(msg, pt.x, pt.y, DAY_TICKS, TE_RISING); + } +} + +/** + * Display vehicle loading indicators. + * @param x World X position of the animation location. + * @param y World Y position of the animation location. + * @param z World Z position of the animation location. + * @param percent Estimated feeder income. + * @param string String which is drawn on the map. + * @return TextEffectID to be used for future updates of the loading indicators. + */ +TextEffectID ShowFillingPercent(int x, int y, int z, uint8 percent, StringID string) +{ + Point pt = RemapCoords(x, y, z); + + assert(string != STR_NULL); + + SetDParam(0, percent); + return AddTextEffect(string, pt.x, pt.y, 0, TE_STATIC); +} + +/** + * Update vehicle loading indicators. + * @param te_id TextEffectID to be updated. + * @param string String wich is printed. + */ +void UpdateFillingPercent(TextEffectID te_id, uint8 percent, StringID string) +{ + assert(string != STR_NULL); + + SetDParam(0, percent); + UpdateTextEffect(te_id, string); +} + +/** + * Hide vehicle loading indicators. + * @param *te_id TextEffectID which is supposed to be hidden. + */ +void HideFillingPercent(TextEffectID *te_id) +{ + if (*te_id == INVALID_TE_ID) return; + + RemoveTextEffect(*te_id); + *te_id = INVALID_TE_ID; +} + +static const NWidgetPart _nested_tooltips_widgets[] = { + NWidget(WWT_PANEL, COLOUR_GREY, WID_TT_BACKGROUND), SetMinimalSize(200, 32), EndContainer(), +}; + +static WindowDesc _tool_tips_desc( + WDP_MANUAL, NULL, 0, 0, // Coordinates and sizes are not used, + WC_TOOLTIPS, WC_NONE, + 0, + _nested_tooltips_widgets, lengthof(_nested_tooltips_widgets) +); + +uint _tooltip_width = 194; + +/** Window for displaying a tooltip. */ +struct TooltipsWindow : public Window +{ + StringID string_id; ///< String to display as tooltip. + byte paramcount; ///< Number of string parameters in #string_id. + uint64 params[5]; ///< The string parameters. + TooltipCloseCondition close_cond; ///< Condition for closing the window. + + TooltipsWindow(Window *parent, StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_tooltip) : Window(&_tool_tips_desc) + { + this->parent = parent; + this->string_id = str; + assert_compile(sizeof(this->params[0]) == sizeof(params[0])); + assert(paramcount <= lengthof(this->params)); + memcpy(this->params, params, sizeof(this->params[0]) * paramcount); + this->paramcount = paramcount; + this->close_cond = close_tooltip; + + this->InitNested(); + + CLRBITS(this->flags, WF_WHITE_BORDER); + } + + virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + { + /* Find the free screen space between the main toolbar at the top, and the statusbar at the bottom. + * Add a fixed distance 2 so the tooltip floats free from both bars. + */ + int scr_top = GetMainViewTop() + 2; + int scr_bot = GetMainViewBottom() - 2; + + Point pt; + + /* Correctly position the tooltip position, watch out for window and cursor size + * Clamp value to below main toolbar and above statusbar. If tooltip would + * go below window, flip it so it is shown above the cursor */ + pt.y = Clamp(_cursor.pos.y + _cursor.size.y + _cursor.offs.y + 5, scr_top, scr_bot); + if (pt.y + sm_height > scr_bot) pt.y = min(_cursor.pos.y + _cursor.offs.y - 5, scr_bot) - sm_height; + pt.x = sm_width >= _screen.width ? 0 : Clamp(_cursor.pos.x - (sm_width >> 1), 0, _screen.width - sm_width); + + return pt; + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + /* There is only one widget. */ + for (uint i = 0; i != this->paramcount; i++) SetDParam(i, this->params[i]); + + size->width = min(GetStringBoundingBox(this->string_id).width, _tooltip_width); + size->height = GetStringHeight(this->string_id, size->width); + + /* Increase slightly to have some space around the box. */ + size->width += 2 + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + size->height += 2 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + /* There is only one widget. */ + GfxFillRect(r.left, r.top, r.right, r.bottom, PC_BLACK); + GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_LIGHT_YELLOW); + + for (uint arg = 0; arg < this->paramcount; arg++) { + SetDParam(arg, this->params[arg]); + } + DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, this->string_id, TC_FROMSTRING, SA_CENTER); + } + + virtual void OnMouseLoop() + { + /* Always close tooltips when the cursor is not in our window. */ + if (!_cursor.in_window) { + delete this; + return; + } + + /* We can show tooltips while dragging tools. These are shown as long as + * we are dragging the tool. Normal tooltips work with hover or rmb. */ + switch (this->close_cond) { + case TCC_RIGHT_CLICK: if (!_right_button_down) delete this; break; + case TCC_LEFT_CLICK: if (!_left_button_down) delete this; break; + case TCC_HOVER: if (!_mouse_hovering) delete this; break; + } + } +}; + +/** + * Shows a tooltip + * @param parent The window this tooltip is related to. + * @param str String to be displayed + * @param paramcount number of params to deal with + * @param params (optional) up to 5 pieces of additional information that may be added to a tooltip + * @param use_left_mouse_button close the tooltip when the left (true) or right (false) mouse button is released + */ +void GuiShowTooltips(Window *parent, StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_tooltip) +{ + DeleteWindowById(WC_TOOLTIPS, 0); + + if (str == STR_NULL) return; + + new TooltipsWindow(parent, str, paramcount, params, close_tooltip); +} + +void QueryString::HandleEditBox(Window *w, int wid) +{ + if (w->IsWidgetGloballyFocused(wid) && this->text.HandleCaret()) { + w->SetWidgetDirty(wid); + + /* For the OSK also invalidate the parent window */ + if (w->window_class == WC_OSK) w->InvalidateData(); + } +} + +void QueryString::DrawEditBox(const Window *w, int wid) const +{ + const NWidgetLeaf *wi = w->GetWidget(wid); + + assert((wi->type & WWT_MASK) == WWT_EDITBOX); + + bool rtl = _current_text_dir == TD_RTL; + Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); + int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; + + int clearbtn_left = wi->pos_x + (rtl ? 0 : wi->current_x - clearbtn_width); + int clearbtn_right = wi->pos_x + (rtl ? clearbtn_width : wi->current_x) - 1; + int left = wi->pos_x + (rtl ? clearbtn_width : 0); + int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; + + int top = wi->pos_y; + int bottom = wi->pos_y + wi->current_y - 1; + + DrawFrameRect(clearbtn_left, top, clearbtn_right, bottom, wi->colour, wi->IsLowered() ? FR_LOWERED : FR_NONE); + DrawSprite(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT, PAL_NONE, clearbtn_left + WD_IMGBTN_LEFT + (wi->IsLowered() ? 1 : 0), (top + bottom - sprite_size.height) / 2 + (wi->IsLowered() ? 1 : 0)); + if (this->text.bytes == 1) GfxFillRect(clearbtn_left + 1, top + 1, clearbtn_right - 1, bottom - 1, _colour_gradient[wi->colour & 0xF][2], FILLRECT_CHECKER); + + DrawFrameRect(left, top, right, bottom, wi->colour, FR_LOWERED | FR_DARKENED); + GfxFillRect(left + 1, top + 1, right - 1, bottom - 1, PC_BLACK); + + /* Limit the drawing of the string inside the widget boundaries */ + DrawPixelInfo dpi; + if (!FillDrawPixelInfo(&dpi, left + WD_FRAMERECT_LEFT, top + WD_FRAMERECT_TOP, right - left - WD_FRAMERECT_RIGHT, bottom - top - WD_FRAMERECT_BOTTOM)) return; + + DrawPixelInfo *old_dpi = _cur_dpi; + _cur_dpi = &dpi; + + /* We will take the current widget length as maximum width, with a small + * space reserved at the end for the caret to show */ + const Textbuf *tb = &this->text; + int delta = min(0, (right - left) - tb->pixels - 10); + + if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; + + /* If we have a marked area, draw a background highlight. */ + if (tb->marklength != 0) GfxFillRect(delta + tb->markxoffs, 0, delta + tb->markxoffs + tb->marklength - 1, bottom - top, PC_GREY); + + DrawString(delta, tb->pixels, Center(0, bottom - top), tb->buf, TC_YELLOW); + + bool focussed = w->IsWidgetGloballyFocused(wid) || IsOSKOpenedFor(w, wid); + if (focussed && tb->caret) { + int caret_width = GetStringBoundingBox("_").width; + DrawString(tb->caretxoffs + delta, tb->caretxoffs + delta + caret_width, Center(0, bottom - top), "_", TC_WHITE); + } + + _cur_dpi = old_dpi; +} + +/** + * Get the current caret position. + * @param w Window the edit box is in. + * @param wid Widget index. + * @return Top-left location of the caret, relative to the window. + */ +Point QueryString::GetCaretPosition(const Window *w, int wid) const +{ + const NWidgetLeaf *wi = w->GetWidget(wid); + + assert((wi->type & WWT_MASK) == WWT_EDITBOX); + + bool rtl = _current_text_dir == TD_RTL; + Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); + int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; + + int left = wi->pos_x + (rtl ? clearbtn_width : 0); + int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; + + /* Clamp caret position to be inside out current width. */ + const Textbuf *tb = &this->text; + int delta = min(0, (right - left) - tb->pixels - 10); + if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; + + Point pt = {left + WD_FRAMERECT_LEFT + tb->caretxoffs + delta, wi->pos_y + WD_FRAMERECT_TOP}; + return pt; +} + +/** + * Get the bounding rectangle for a range of the query string. + * @param w Window the edit box is in. + * @param wid Widget index. + * @param from Start of the string range. + * @param to End of the string range. + * @return Rectangle encompassing the string range, relative to the window. + */ +Rect QueryString::GetBoundingRect(const Window *w, int wid, const char *from, const char *to) const +{ + const NWidgetLeaf *wi = w->GetWidget(wid); + + assert((wi->type & WWT_MASK) == WWT_EDITBOX); + + bool rtl = _current_text_dir == TD_RTL; + Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); + int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; + + int left = wi->pos_x + (rtl ? clearbtn_width : 0); + int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; + + int top = wi->pos_y + WD_FRAMERECT_TOP; + int bottom = wi->pos_y + wi->current_y - 1 - WD_FRAMERECT_BOTTOM; + + /* Clamp caret position to be inside our current width. */ + const Textbuf *tb = &this->text; + int delta = min(0, (right - left) - tb->pixels - 10); + if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; + + /* Get location of first and last character. */ + Point p1 = GetCharPosInString(tb->buf, from, FS_NORMAL); + Point p2 = from != to ? GetCharPosInString(tb->buf, to, FS_NORMAL) : p1; + + Rect r = { Clamp(left + p1.x + delta + WD_FRAMERECT_LEFT, left, right), top, Clamp(left + p2.x + delta + WD_FRAMERECT_LEFT, left, right - WD_FRAMERECT_RIGHT), bottom }; + + return r; +} + +/** + * Get the character that is rendered at a position. + * @param w Window the edit box is in. + * @param wid Widget index. + * @param pt Position to test. + * @return Pointer to the character at the position or NULL if no character is at the position. + */ +const char *QueryString::GetCharAtPosition(const Window *w, int wid, const Point &pt) const +{ + const NWidgetLeaf *wi = w->GetWidget(wid); + + assert((wi->type & WWT_MASK) == WWT_EDITBOX); + + bool rtl = _current_text_dir == TD_RTL; + Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); + int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; + + int left = wi->pos_x + (rtl ? clearbtn_width : 0); + int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; + + int top = wi->pos_y + WD_FRAMERECT_TOP; + int bottom = wi->pos_y + wi->current_y - 1 - WD_FRAMERECT_BOTTOM; + + if (!IsInsideMM(pt.y, top, bottom)) return NULL; + + /* Clamp caret position to be inside our current width. */ + const Textbuf *tb = &this->text; + int delta = min(0, (right - left) - tb->pixels - 10); + if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; + + return ::GetCharAtPosition(tb->buf, pt.x - delta - left); +} + +void QueryString::ClickEditBox(Window *w, Point pt, int wid, int click_count, bool focus_changed) +{ + const NWidgetLeaf *wi = w->GetWidget(wid); + + assert((wi->type & WWT_MASK) == WWT_EDITBOX); + + bool rtl = _current_text_dir == TD_RTL; + int clearbtn_width = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT).width; + + int clearbtn_left = wi->pos_x + (rtl ? 0 : wi->current_x - clearbtn_width); + + if (IsInsideBS(pt.x, clearbtn_left, clearbtn_width)) { + if (this->text.bytes > 1) { + this->text.DeleteAll(); + w->HandleButtonClick(wid); + w->OnEditboxChanged(wid); + } + return; + } + + if (w->window_class != WC_OSK && _settings_client.gui.osk_activation != OSKA_DISABLED && + (!focus_changed || _settings_client.gui.osk_activation == OSKA_IMMEDIATELY) && + (click_count == 2 || _settings_client.gui.osk_activation != OSKA_DOUBLE_CLICK)) { + /* Open the OSK window */ + ShowOnScreenKeyboard(w, wid); + } +} + +/** Class for the string query window. */ +struct QueryStringWindow : public Window +{ + QueryString editbox; ///< Editbox. + QueryStringFlags flags; ///< Flags controlling behaviour of the window. + + QueryStringWindow(StringID str, StringID caption, uint max_bytes, uint max_chars, WindowDesc *desc, Window *parent, CharSetFilter afilter, QueryStringFlags flags) : + Window(desc), editbox(max_bytes, max_chars) + { + char *last_of = &this->editbox.text.buf[this->editbox.text.max_bytes - 1]; + GetString(this->editbox.text.buf, str, last_of); + str_validate(this->editbox.text.buf, last_of, SVS_NONE); + + /* Make sure the name isn't too long for the text buffer in the number of + * characters (not bytes). max_chars also counts the '\0' characters. */ + while (Utf8StringLength(this->editbox.text.buf) + 1 > this->editbox.text.max_chars) { + *Utf8PrevChar(this->editbox.text.buf + strlen(this->editbox.text.buf)) = '\0'; + } + + this->editbox.text.UpdateSize(); + + if ((flags & QSF_ACCEPT_UNCHANGED) == 0) this->editbox.orig = strdup(this->editbox.text.buf); + + this->querystrings[WID_QS_TEXT] = &this->editbox; + this->editbox.caption = caption; + this->editbox.cancel_button = WID_QS_CANCEL; + this->editbox.ok_button = WID_QS_OK; + this->editbox.text.afilter = afilter; + this->flags = flags; + + this->InitNested(WN_QUERY_STRING); + + this->parent = parent; + + this->SetFocusedWidget(WID_QS_TEXT); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget == WID_QS_DEFAULT && (this->flags & QSF_ENABLE_DEFAULT) == 0) { + /* We don't want this widget to show! */ + fill->width = 0; + resize->width = 0; + size->width = 0; + } + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_QS_CAPTION) SetDParam(0, this->editbox.caption); + } + + void OnOk() + { + if (this->editbox.orig == NULL || strcmp(this->editbox.text.buf, this->editbox.orig) != 0) { + /* If the parent is NULL, the editbox is handled by general function + * HandleOnEditText */ + if (this->parent != NULL) { + this->parent->OnQueryTextFinished(this->editbox.text.buf); + } else { + HandleOnEditText(this->editbox.text.buf); + } + this->editbox.handled = true; + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_QS_DEFAULT: + this->editbox.text.DeleteAll(); + /* FALL THROUGH */ + case WID_QS_OK: + this->OnOk(); + /* FALL THROUGH */ + case WID_QS_CANCEL: + delete this; + break; + } + } + + ~QueryStringWindow() + { + if (!this->editbox.handled && this->parent != NULL) { + Window *parent = this->parent; + this->parent = NULL; // so parent doesn't try to delete us again + parent->OnQueryTextFinished(NULL); + } + } +}; + +static const NWidgetPart _nested_query_string_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_QS_CAPTION), SetDataTip(STR_WHITE_STRING, STR_NULL), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(WWT_EDITBOX, COLOUR_GREY, WID_QS_TEXT), SetMinimalSize(256, 12), SetFill(1, 1), SetPadding(2, 2, 2, 2), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_DEFAULT), SetMinimalSize(87, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_DEFAULT, STR_NULL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_CANCEL), SetMinimalSize(86, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_OK), SetMinimalSize(87, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_OK, STR_NULL), + EndContainer(), +}; + +static WindowDesc _query_string_desc( + WDP_CENTER, "query_string", 0, 0, + WC_QUERY_STRING, WC_NONE, + 0, + _nested_query_string_widgets, lengthof(_nested_query_string_widgets) +); + +/** + * Show a query popup window with a textbox in it. + * @param str StringID for the text shown in the textbox + * @param caption StringID of text shown in caption of querywindow + * @param maxsize maximum size in bytes or characters (including terminating '\0') depending on flags + * @param parent pointer to a Window that will handle the events (ok/cancel) of this + * window. If NULL, results are handled by global function HandleOnEditText + * @param afilter filters out unwanted character input + * @param flags various flags, @see QueryStringFlags + */ +void ShowQueryString(StringID str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags) +{ + DeleteWindowByClass(WC_QUERY_STRING); + new QueryStringWindow(str, caption, ((flags & QSF_LEN_IN_CHARS) ? MAX_CHAR_LENGTH : 1) * maxsize, maxsize, &_query_string_desc, parent, afilter, flags); +} + +/** + * Window used for asking the user a YES/NO question. + */ +struct QueryWindow : public Window { + QueryCallbackProc *proc; ///< callback function executed on closing of popup. Window* points to parent, bool is true if 'yes' clicked, false otherwise + uint64 params[10]; ///< local copy of _decode_parameters + StringID message; ///< message shown for query window + StringID caption; ///< title of window + + QueryWindow(WindowDesc *desc, StringID caption, StringID message, Window *parent, QueryCallbackProc *callback) : Window(desc) + { + /* Create a backup of the variadic arguments to strings because it will be + * overridden pretty often. We will copy these back for drawing */ + CopyOutDParam(this->params, 0, lengthof(this->params)); + this->caption = caption; + this->message = message; + this->proc = callback; + + this->InitNested(WN_CONFIRM_POPUP_QUERY); + + this->parent = parent; + this->left = parent->left + (parent->width / 2) - (this->width / 2); + this->top = parent->top + (parent->height / 2) - (this->height / 2); + } + + ~QueryWindow() + { + if (this->proc != NULL) this->proc(this->parent, false); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_Q_CAPTION: + CopyInDParam(1, this->params, lengthof(this->params)); + SetDParam(0, this->caption); + break; + + case WID_Q_TEXT: + CopyInDParam(0, this->params, lengthof(this->params)); + break; + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget != WID_Q_TEXT) return; + + size->width = GetMinSizing(NWST_WINDOW_LENGTH, size->width); + Dimension d = GetStringMultiLineBoundingBox(this->message, *size); + d.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; + d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + *size = d; + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_Q_TEXT) return; + + DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, + this->message, TC_FROMSTRING, SA_CENTER); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_Q_YES: { + /* in the Generate New World window, clicking 'Yes' causes + * DeleteNonVitalWindows() to be called - we shouldn't be in a window then */ + QueryCallbackProc *proc = this->proc; + Window *parent = this->parent; + /* Prevent the destructor calling the callback function */ + this->proc = NULL; + delete this; + if (proc != NULL) { + proc(parent, true); + proc = NULL; + } + break; + } + case WID_Q_NO: + delete this; + break; + } + } + + virtual EventState OnKeyPress(WChar key, uint16 keycode) + { + /* ESC closes the window, Enter confirms the action */ + switch (keycode) { + case WKC_RETURN: + case WKC_NUM_ENTER: + if (this->proc != NULL) { + this->proc(this->parent, true); + this->proc = NULL; + } + /* FALL THROUGH */ + case WKC_ESC: + delete this; + return ES_HANDLED; + } + return ES_NOT_HANDLED; + } +}; + +static const NWidgetPart _nested_query_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_RED), + NWidget(WWT_CAPTION, COLOUR_RED, WID_Q_CAPTION), SetDataTip(STR_JUST_STRING, STR_NULL), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_RED), SetPIP(8, 15, 8), + NWidget(WWT_TEXT, COLOUR_RED, WID_Q_TEXT), SetMinimalSize(200, 12), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY), SetFill(1, 1), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(20, 29, 20), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_Q_NO), SetMinimalSize(71, 12), SetDataTip(STR_QUIT_NO, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_Q_YES), SetMinimalSize(71, 12), SetDataTip(STR_QUIT_YES, STR_NULL), + EndContainer(), + NWidget(WWT_EMPTY), SetFill(1, 1), + EndContainer(), + EndContainer(), +}; + +static WindowDesc _query_desc( + WDP_CENTER, NULL, 0, 0, + WC_CONFIRM_POPUP_QUERY, WC_NONE, + WDF_MODAL, + _nested_query_widgets, lengthof(_nested_query_widgets) +); + +/** + * Show a modal confirmation window with standard 'yes' and 'no' buttons + * The window is aligned to the centre of its parent. + * @param caption string shown as window caption + * @param message string that will be shown for the window + * @param parent pointer to parent window, if this pointer is NULL the parent becomes + * the main window WC_MAIN_WINDOW + * @param callback callback function pointer to set in the window descriptor + */ +void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallbackProc *callback) +{ + if (parent == NULL) parent = FindWindowById(WC_MAIN_WINDOW, 0); + + const Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class != WC_CONFIRM_POPUP_QUERY) continue; + + const QueryWindow *qw = (const QueryWindow *)w; + if (qw->parent != parent || qw->proc != callback) continue; + + delete qw; + break; + } + + new QueryWindow(&_query_desc, caption, message, parent, callback); +} diff --git a/src/osk_gui.cpp.orig b/src/osk_gui.cpp.orig new file mode 100644 index 0000000000..9445595ec2 --- /dev/null +++ b/src/osk_gui.cpp.orig @@ -0,0 +1,460 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file osk_gui.cpp The On Screen Keyboard GUI */ + +#include "stdafx.h" +#include "string_func.h" +#include "strings_func.h" +#include "debug.h" +#include "window_func.h" +#include "gfx_func.h" +#include "querystring_gui.h" +#include "video/video_driver.hpp" + +#include "widgets/osk_widget.h" + +#include "table/sprites.h" +#include "table/strings.h" +#ifdef __ANDROID__ +#include +#endif + +char _keyboard_opt[2][OSK_KEYBOARD_ENTRIES * 4 + 1]; +static WChar _keyboard[2][OSK_KEYBOARD_ENTRIES]; + +enum KeyStateBits { + KEYS_NONE, + KEYS_SHIFT, + KEYS_CAPS +}; +static byte _keystate = KEYS_NONE; + +struct OskWindow : public Window { + StringID caption; ///< the caption for this window. + QueryString *qs; ///< text-input + int text_btn; ///< widget number of parent's text field + Textbuf *text; ///< pointer to parent's textbuffer (to update caret position) + char *orig_str_buf; ///< Original string. + bool shift; ///< Is the shift effectively pressed? + + OskWindow(WindowDesc *desc, Window *parent, int button) : Window(desc) + { + this->parent = parent; + assert(parent != NULL); + + NWidgetCore *par_wid = parent->GetWidget(button); + assert(par_wid != NULL); + + assert(parent->querystrings.Contains(button)); + this->qs = parent->querystrings.Find(button)->second; + this->caption = (par_wid->widget_data != STR_NULL) ? par_wid->widget_data : this->qs->caption; + this->text_btn = button; + this->text = &this->qs->text; + this->querystrings[WID_OSK_TEXT] = this->qs; + + /* make a copy in case we need to reset later */ + this->orig_str_buf = strdup(this->qs->text.buf); + + this->InitNested(0); + this->SetFocusedWidget(WID_OSK_TEXT); + + /* Not needed by default. */ + this->DisableWidget(WID_OSK_SPECIAL); + + this->UpdateOskState(); + } + + ~OskWindow() + { + free(this->orig_str_buf); + } + + /** + * Only show valid characters; do not show characters that would + * only insert a space when we have a spacebar to do that or + * characters that are not allowed to be entered. + */ + void UpdateOskState() + { + this->shift = HasBit(_keystate, KEYS_CAPS) ^ HasBit(_keystate, KEYS_SHIFT); + + for (uint i = 0; i < OSK_KEYBOARD_ENTRIES; i++) { + this->SetWidgetDisabledState(WID_OSK_LETTERS + i, + !IsValidChar(_keyboard[this->shift][i], this->qs->text.afilter) || _keyboard[this->shift][i] == ' '); + } + this->SetWidgetDisabledState(WID_OSK_SPACE, !IsValidChar(' ', this->qs->text.afilter)); + + this->SetWidgetLoweredState(WID_OSK_SHIFT, HasBit(_keystate, KEYS_SHIFT)); + this->SetWidgetLoweredState(WID_OSK_CAPS, HasBit(_keystate, KEYS_CAPS)); + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_OSK_CAPTION) SetDParam(0, this->caption); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget < WID_OSK_LETTERS) return; + + widget -= WID_OSK_LETTERS; + DrawCharCentered(_keyboard[this->shift][widget], + r.left + 8, + r.top + 3, + TC_BLACK); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + /* clicked a letter */ + if (widget >= WID_OSK_LETTERS) { + WChar c = _keyboard[this->shift][widget - WID_OSK_LETTERS]; + + if (!IsValidChar(c, this->qs->text.afilter)) return; + + if (this->qs->text.InsertChar(c)) this->OnEditboxChanged(WID_OSK_TEXT); + + if (HasBit(_keystate, KEYS_SHIFT)) { + ToggleBit(_keystate, KEYS_SHIFT); + this->UpdateOskState(); + this->SetDirty(); + } + return; + } + + switch (widget) { + case WID_OSK_BACKSPACE: + if (this->qs->text.DeleteChar(WKC_BACKSPACE)) this->OnEditboxChanged(WID_OSK_TEXT); + break; + + case WID_OSK_SPECIAL: + /* + * Anything device specific can go here. + * The button itself is hidden by default, and when you need it you + * can not hide it in the create event. + */ + break; + + case WID_OSK_CAPS: + ToggleBit(_keystate, KEYS_CAPS); + this->UpdateOskState(); + this->SetDirty(); + break; + + case WID_OSK_SHIFT: + ToggleBit(_keystate, KEYS_SHIFT); + this->UpdateOskState(); + this->SetDirty(); + break; + + case WID_OSK_SPACE: + if (this->qs->text.InsertChar(' ')) this->OnEditboxChanged(WID_OSK_TEXT); + break; + + case WID_OSK_LEFT: + if (this->qs->text.MovePos(WKC_LEFT)) this->InvalidateData(); + break; + + case WID_OSK_RIGHT: + if (this->qs->text.MovePos(WKC_RIGHT)) this->InvalidateData(); + break; + + case WID_OSK_OK: + if (this->qs->orig == NULL || strcmp(this->qs->text.buf, this->qs->orig) != 0) { + /* pass information by simulating a button press on parent window */ + if (this->qs->ok_button >= 0) { + this->parent->OnClick(pt, this->qs->ok_button, 1); + /* Window gets deleted when the parent window removes itself. */ + return; + } + } + delete this; + break; + + case WID_OSK_CANCEL: + if (this->qs->cancel_button >= 0) { // pass a cancel event to the parent window + this->parent->OnClick(pt, this->qs->cancel_button, 1); + /* Window gets deleted when the parent window removes itself. */ + return; + } else { // or reset to original string + qs->text.Assign(this->orig_str_buf); + qs->text.MovePos(WKC_END); + this->OnEditboxChanged(WID_OSK_TEXT); + delete this; + } + break; + } + } + + virtual void OnEditboxChanged(int widget) + { + this->SetWidgetDirty(WID_OSK_TEXT); + this->parent->OnEditboxChanged(this->text_btn); + this->parent->SetWidgetDirty(this->text_btn); + } + + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + this->SetWidgetDirty(WID_OSK_TEXT); + this->parent->SetWidgetDirty(this->text_btn); + } + + virtual void OnFocusLost() + { + _video_driver->EditBoxLostFocus(); + delete this; + } +}; + +static const int HALF_KEY_WIDTH = 7; // Width of 1/2 key in pixels. +static const int INTER_KEY_SPACE = 2; // Number of pixels between two keys. + +/** + * Add a key widget to a row of the keyboard. + * @param hor Row container to add key widget to. + * @param height Height of the key (all keys in a row should have equal height). + * @param num_half Number of 1/2 key widths that this key has. + * @param widtype Widget type of the key. Must be either \c NWID_SPACER for an invisible key, or a \c WWT_* widget. + * @param widnum Widget number of the key. + * @param widdata Data value of the key widget. + * @param biggest_index Collected biggest widget index so far. + * @note Key width is measured in 1/2 keys to allow for 1/2 key shifting between rows. + */ +static void AddKey(NWidgetHorizontal *hor, int height, int num_half, WidgetType widtype, int widnum, uint16 widdata, int *biggest_index) +{ + int min_half_key = max(GetMinSizing(NWST_BUTTON) / 2, HALF_KEY_WIDTH); + int key_width = min_half_key + (INTER_KEY_SPACE + min_half_key) * (num_half - 1); + + if (widtype == NWID_SPACER) { + if (!hor->IsEmpty()) key_width += INTER_KEY_SPACE; + NWidgetSpacer *spc = new NWidgetSpacer(key_width, height); + hor->Add(spc); + } else { + if (!hor->IsEmpty()) { + NWidgetSpacer *spc = new NWidgetSpacer(INTER_KEY_SPACE, height); + hor->Add(spc); + } + NWidgetLeaf *leaf = new NWidgetLeaf(widtype, COLOUR_GREY, widnum, widdata, STR_NULL); + leaf->SetMinimalSize(key_width, height); + hor->Add(leaf); + } + + *biggest_index = max(*biggest_index, widnum); +} + +/** Construct the top row keys (cancel, ok, backspace). */ +static NWidgetBase *MakeTopKeys(int *biggest_index) +{ + NWidgetHorizontal *hor = new NWidgetHorizontal(); + int key_height = FONT_HEIGHT_NORMAL + 2; + + AddKey(hor, key_height, 6 * 2, WWT_TEXTBTN, WID_OSK_CANCEL, STR_BUTTON_CANCEL, biggest_index); + AddKey(hor, key_height, 6 * 2, WWT_TEXTBTN, WID_OSK_OK, STR_BUTTON_OK, biggest_index); + AddKey(hor, key_height, 2 * 2, WWT_PUSHIMGBTN, WID_OSK_BACKSPACE, SPR_OSK_BACKSPACE, biggest_index); + return hor; +} + +/** Construct the row containing the digit keys. */ +static NWidgetBase *MakeNumberKeys(int *biggest_index) +{ + NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); + int key_height = FONT_HEIGHT_NORMAL + 6; + + for (int widnum = WID_OSK_NUMBERS_FIRST; widnum <= WID_OSK_NUMBERS_LAST; widnum++) { + AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); + } + return hor; +} + +/** Construct the qwerty row keys. */ +static NWidgetBase *MakeQwertyKeys(int *biggest_index) +{ + NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); + int key_height = FONT_HEIGHT_NORMAL + 6; + + AddKey(hor, key_height, 3, WWT_PUSHIMGBTN, WID_OSK_SPECIAL, SPR_OSK_SPECIAL, biggest_index); + for (int widnum = WID_OSK_QWERTY_FIRST; widnum <= WID_OSK_QWERTY_LAST; widnum++) { + AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); + } + AddKey(hor, key_height, 1, NWID_SPACER, 0, 0, biggest_index); + return hor; +} + +/** Construct the asdfg row keys. */ +static NWidgetBase *MakeAsdfgKeys(int *biggest_index) +{ + NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); + int key_height = FONT_HEIGHT_NORMAL + 6; + + AddKey(hor, key_height, 4, WWT_IMGBTN, WID_OSK_CAPS, SPR_OSK_CAPS, biggest_index); + for (int widnum = WID_OSK_ASDFG_FIRST; widnum <= WID_OSK_ASDFG_LAST; widnum++) { + AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); + } + return hor; +} + +/** Construct the zxcvb row keys. */ +static NWidgetBase *MakeZxcvbKeys(int *biggest_index) +{ + NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); + int key_height = FONT_HEIGHT_NORMAL + 6; + + AddKey(hor, key_height, 3, WWT_IMGBTN, WID_OSK_SHIFT, SPR_OSK_SHIFT, biggest_index); + for (int widnum = WID_OSK_ZXCVB_FIRST; widnum <= WID_OSK_ZXCVB_LAST; widnum++) { + AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); + } + AddKey(hor, key_height, 1, NWID_SPACER, 0, 0, biggest_index); + return hor; +} + +/** Construct the spacebar row keys. */ +static NWidgetBase *MakeSpacebarKeys(int *biggest_index) +{ + NWidgetHorizontal *hor = new NWidgetHorizontal(); + int key_height = FONT_HEIGHT_NORMAL + 6; + + AddKey(hor, key_height, 8, NWID_SPACER, 0, 0, biggest_index); + AddKey(hor, key_height, 13, WWT_PUSHTXTBTN, WID_OSK_SPACE, STR_EMPTY, biggest_index); + AddKey(hor, key_height, 3, NWID_SPACER, 0, 0, biggest_index); + AddKey(hor, key_height, 2, WWT_PUSHIMGBTN, WID_OSK_LEFT, SPR_OSK_LEFT, biggest_index); + AddKey(hor, key_height, 2, WWT_PUSHIMGBTN, WID_OSK_RIGHT, SPR_OSK_RIGHT, biggest_index); + return hor; +} + + +static const NWidgetPart _nested_osk_widgets[] = { + NWidget(WWT_CAPTION, COLOUR_GREY, WID_OSK_CAPTION), SetSizingType(NWST_BUTTON), SetDataTip(STR_WHITE_STRING, STR_NULL), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(WWT_EDITBOX, COLOUR_GREY, WID_OSK_TEXT), SetMinimalSize(252, 12), SetPadding(2, 2, 2, 2), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), SetPIP(5, 2, 3), + NWidgetFunction(MakeTopKeys), SetPadding(0, 3, 0, 3), + NWidgetFunction(MakeNumberKeys), SetPadding(0, 3, 0, 3), + NWidgetFunction(MakeQwertyKeys), SetPadding(0, 3, 0, 3), + NWidgetFunction(MakeAsdfgKeys), SetPadding(0, 3, 0, 3), + NWidgetFunction(MakeZxcvbKeys), SetPadding(0, 3, 0, 3), + NWidgetFunction(MakeSpacebarKeys), SetPadding(0, 3, 0, 3), + EndContainer(), +}; + +static WindowDesc _osk_desc( + WDP_CENTER, "query_osk", 0, 0, + WC_OSK, WC_NONE, + 0, + _nested_osk_widgets, lengthof(_nested_osk_widgets) +); + +/** + * Retrieve keyboard layout from language string or (if set) config file. + * Also check for invalid characters. + */ +void GetKeyboardLayout() +{ + char keyboard[2][OSK_KEYBOARD_ENTRIES * 4 + 1]; + char errormark[2][OSK_KEYBOARD_ENTRIES + 1]; // used for marking invalid chars + bool has_error = false; // true when an invalid char is detected + + if (StrEmpty(_keyboard_opt[0])) { + GetString(keyboard[0], STR_OSK_KEYBOARD_LAYOUT, lastof(keyboard[0])); + } else { + strecpy(keyboard[0], _keyboard_opt[0], lastof(keyboard[0])); + } + + if (StrEmpty(_keyboard_opt[1])) { + GetString(keyboard[1], STR_OSK_KEYBOARD_LAYOUT_CAPS, lastof(keyboard[1])); + } else { + strecpy(keyboard[1], _keyboard_opt[1], lastof(keyboard[1])); + } + + for (uint j = 0; j < 2; j++) { + const char *kbd = keyboard[j]; + bool ended = false; + for (uint i = 0; i < OSK_KEYBOARD_ENTRIES; i++) { + _keyboard[j][i] = Utf8Consume(&kbd); + + /* Be lenient when the last characters are missing (is quite normal) */ + if (_keyboard[j][i] == '\0' || ended) { + ended = true; + _keyboard[j][i] = ' '; + continue; + } + + if (IsPrintable(_keyboard[j][i])) { + errormark[j][i] = ' '; + } else { + has_error = true; + errormark[j][i] = '^'; + _keyboard[j][i] = ' '; + } + } + } + + if (has_error) { + ShowInfoF("The keyboard layout you selected contains invalid chars. Please check those chars marked with ^."); + ShowInfoF("Normal keyboard: %s", keyboard[0]); + ShowInfoF(" %s", errormark[0]); + ShowInfoF("Caps Lock: %s", keyboard[1]); + ShowInfoF(" %s", errormark[1]); + } +} + +/** + * Show the on-screen keyboard (osk) associated with a given textbox + * @param parent pointer to the Window where this keyboard originated from + * @param button widget number of parent's textbox + */ +void ShowOnScreenKeyboard(Window *parent, int button) +{ + DeleteWindowById(WC_OSK, 0); + + GetKeyboardLayout(); + new OskWindow(&_osk_desc, parent, button); +#ifdef __ANDROID__ + char text[256]; + SDL_ANDROID_GetScreenKeyboardTextInput(text, sizeof(text) - 1); /* Invoke Android built-in screen keyboard */ + OskWindow *osk = dynamic_cast(FindWindowById(WC_OSK, 0)); + osk->qs->text.Assign(text); + free(osk->orig_str_buf); + osk->orig_str_buf = strdup(osk->qs->text.buf); + + osk->SetDirty(); +#endif +} + +/** + * Updates the original text of the OSK so when the 'parent' changes the + * original and you press on cancel you won't get the 'old' original text + * but the updated one. + * @param parent window that just updated its orignal text + * @param button widget number of parent's textbox to update + */ +void UpdateOSKOriginalText(const Window *parent, int button) +{ + OskWindow *osk = dynamic_cast(FindWindowById(WC_OSK, 0)); + if (osk == NULL || osk->parent != parent || osk->text_btn != button) return; + + free(osk->orig_str_buf); + osk->orig_str_buf = strdup(osk->qs->text.buf); + + osk->SetDirty(); +} + +/** + * Check whether the OSK is opened for a specific editbox. + * @parent w Window to check for + * @param button Editbox of \a w to check for + * @return true if the OSK is oppened for \a button. + */ +bool IsOSKOpenedFor(const Window *w, int button) +{ + OskWindow *osk = dynamic_cast(FindWindowById(WC_OSK, 0)); + return osk != NULL && osk->parent == w && osk->text_btn == button; +} diff --git a/src/rail_gui.cpp.orig b/src/rail_gui.cpp.orig new file mode 100644 index 0000000000..cb4f16f12f --- /dev/null +++ b/src/rail_gui.cpp.orig @@ -0,0 +1,1991 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file rail_gui.cpp %File for dealing with rail construction user interface */ + +#include "stdafx.h" +#include "gui.h" +#include "window_gui.h" +#include "station_gui.h" +#include "terraform_gui.h" +#include "viewport_func.h" +#include "command_func.h" +#include "waypoint_func.h" +#include "newgrf_station.h" +#include "company_base.h" +#include "strings_func.h" +#include "window_func.h" +#include "date_func.h" +#include "sound_func.h" +#include "company_func.h" +#include "widgets/dropdown_type.h" +#include "tunnelbridge.h" +#include "tilehighlight_func.h" +#include "spritecache.h" +#include "core/geometry_func.hpp" +#include "hotkeys.h" +#include "engine_base.h" +#include "vehicle_func.h" +#include "zoom_func.h" +#include "rail_gui.h" + +#include "station_map.h" +#include "tunnelbridge_map.h" + +#include "widgets/rail_widget.h" + + +static RailType _cur_railtype; ///< Rail type of the current build-rail toolbar. +static bool _remove_button_clicked; ///< Flag whether 'remove' toggle-button is currently enabled +static DiagDirection _build_depot_direction; ///< Currently selected depot direction +static byte _waypoint_count = 1; ///< Number of waypoint types +static byte _cur_waypoint_type; ///< Currently selected waypoint type +static bool _convert_signal_button; ///< convert signal button in the signal GUI pressed +static SignalVariant _cur_signal_variant; ///< set the signal variant (for signal GUI) +static SignalType _cur_signal_type; ///< set the signal type (for signal GUI) + +/* Map the setting: default_signal_type to the corresponding signal type */ +static const SignalType _default_signal_type[] = {SIGTYPE_NORMAL, SIGTYPE_PBS, SIGTYPE_PBS_ONEWAY}; + +struct RailStationGUISettings { + Axis orientation; ///< Currently selected rail station orientation + + bool newstations; ///< Are custom station definitions available? + StationClassID station_class; ///< Currently selected custom station class (if newstations is \c true ) + byte station_type; ///< %Station type within the currently selected custom station class (if newstations is \c true ) + byte station_count; ///< Number of custom stations (if newstations is \c true ) +}; +static RailStationGUISettings _railstation; ///< Settings of the station builder GUI + + +static void HandleStationPlacement(TileIndex start, TileIndex end); +static void ShowBuildTrainDepotPicker(Window *parent); +static void ShowBuildWaypointPicker(Window *parent); +static void ShowStationBuilder(Window *parent); +static void ShowSignalBuilder(Window *parent); + +/** + * Check whether a station type can be build. + * @return true if building is allowed. + */ +static bool IsStationAvailable(const StationSpec *statspec) +{ + if (statspec == NULL || !HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) return true; + + uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE); + if (cb_res == CALLBACK_FAILED) return true; + + return Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res); +} + +void CcPlaySound1E(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_2, tile); +} + +static void GenericPlaceRail(TileIndex tile, int cmd) +{ + DoCommandP(tile, _cur_railtype, cmd, + _remove_button_clicked ? + CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) : + CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), + CcPlaySound1E); +} + +/** + * Try to add an additional rail-track at the entrance of a depot + * @param tile Tile to use for adding the rail-track + * @param dir Direction to check for already present tracks + * @param track Track to add + * @see CcRailDepot() + */ +static void PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Track track) +{ + if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return; + if ((GetTrackBits(tile) & DiagdirReachesTracks(dir)) == 0) return; + + DoCommandP(tile, _cur_railtype, track, CMD_BUILD_SINGLE_RAIL); +} + +/** Additional pieces of track to add at the entrance of a depot. */ +static const Track _place_depot_extra_track[12] = { + TRACK_LEFT, TRACK_UPPER, TRACK_UPPER, TRACK_RIGHT, // First additional track for directions 0..3 + TRACK_X, TRACK_Y, TRACK_X, TRACK_Y, // Second additional track + TRACK_LOWER, TRACK_LEFT, TRACK_RIGHT, TRACK_LOWER, // Third additional track +}; + +/** Direction to check for existing track pieces. */ +static const DiagDirection _place_depot_extra_dir[12] = { + DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE, DIAGDIR_SW, + DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_SE, + DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_NW, DIAGDIR_NE, +}; + +void CcRailDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + + DiagDirection dir = (DiagDirection)p2; + + if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_2, tile); + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + + tile += TileOffsByDiagDir(dir); + + if (IsTileType(tile, MP_RAILWAY)) { + PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]); + PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 4], _place_depot_extra_track[dir + 4]); + PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 8], _place_depot_extra_track[dir + 8]); + } +} + +/** + * Place a rail waypoint. + * @param tile Position to start dragging a waypoint. + */ +static void PlaceRail_Waypoint(TileIndex tile) +{ + if (_remove_button_clicked) { + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_STATION); + return; + } + + Axis axis = GetAxisForNewWaypoint(tile); + if (IsValidAxis(axis)) { + /* Valid tile for waypoints */ + VpStartPlaceSizing(tile, axis == AXIS_X ? VPM_FIX_X : VPM_FIX_Y, DDSP_BUILD_STATION); + } else { + /* Tile where we can't build rail waypoints. This is always going to fail, + * but provides the user with a proper error message. */ + DoCommandP(tile, 1 << 8 | 1 << 16, STAT_CLASS_WAYP | INVALID_STATION << 16, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT)); + } +} + +void CcStation(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + + if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_2, tile); + /* Only close the station builder window if the default station and non persistent building is chosen. */ + if (_railstation.station_class == STAT_CLASS_DFLT && _railstation.station_type == 0 && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); +} + +/** + * Place a rail station. + * @param tile Position to place or start dragging a station. + */ +static void PlaceRail_Station(TileIndex tile) +{ + if (_remove_button_clicked) { + VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_REMOVE_STATION); + VpSetPlaceSizingLimit(-1); + } else if (_settings_client.gui.station_dragdrop) { + VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_STATION); + VpSetPlaceSizingLimit(_settings_game.station.station_spread); + } else { + uint32 p1 = _cur_railtype | _railstation.orientation << 4 | _settings_client.gui.station_numtracks << 8 | _settings_client.gui.station_platlength << 16 | _ctrl_pressed << 24; + uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16; + + int w = _settings_client.gui.station_numtracks; + int h = _settings_client.gui.station_platlength; + if (!_railstation.orientation) Swap(w, h); + + CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" }; + ShowSelectStationIfNeeded(cmdcont, TileArea(tile, w, h)); + } +} + +/** + * Build a new signal or edit/remove a present signal, use CmdBuildSingleSignal() or CmdRemoveSingleSignal() in rail_cmd.cpp + * + * @param tile The tile where the signal will build or edit + */ +static void GenericPlaceSignals(TileIndex tile) +{ + TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)); + + if (trackbits & TRACK_BIT_VERT) { // N-S direction + trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT; + } + + if (trackbits & TRACK_BIT_HORZ) { // E-W direction + trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER; + } + + Track track = FindFirstTrack(trackbits); + + if (_remove_button_clicked) { + DoCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E); + } else { + const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); + + /* Map the setting cycle_signal_types to the lower and upper allowed signal type. */ + static const uint cycle_bounds[] = {SIGTYPE_NORMAL | (SIGTYPE_LAST_NOPBS << 3), SIGTYPE_PBS | (SIGTYPE_LAST << 3), SIGTYPE_NORMAL | (SIGTYPE_LAST << 3)}; + + /* various bitstuffed elements for CmdBuildSingleSignal() */ + uint32 p1 = track; + + if (w != NULL) { + /* signal GUI is used */ + SB(p1, 3, 1, _ctrl_pressed); + SB(p1, 4, 1, _cur_signal_variant); + SB(p1, 5, 3, _cur_signal_type); + SB(p1, 8, 1, _convert_signal_button); + SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]); + } else { + SB(p1, 3, 1, _ctrl_pressed); + SB(p1, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC)); + SB(p1, 5, 3, _default_signal_type[_settings_client.gui.default_signal_type]); + SB(p1, 8, 1, 0); + SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]); + } + + DoCommandP(tile, p1, 0, CMD_BUILD_SIGNALS | + CMD_MSG((w != NULL && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), + CcPlaySound1E); + } +} + +/** + * Start placing a rail bridge. + * @param tile Position of the first tile of the bridge. + * @param w Rail toolbar window. + */ +static void PlaceRail_Bridge(TileIndex tile, Window *w) +{ + if (IsBridgeTile(tile)) { + TileIndex other_tile = GetOtherTunnelBridgeEnd(tile); + Point pt = {0, 0}; + w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile); + } else { + VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE); + } +} + +/** Command callback for building a tunnel */ +void CcBuildRailTunnel(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Succeeded()) { + if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_2, tile); + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + } else { + SetRedErrorSquare(_build_tunnel_endtile); + } +} + +/** + * Toggles state of the Remove button of Build rail toolbar + * @param w window the button belongs to + */ +static void ToggleRailButton_Remove(Window *w) +{ + DeleteWindowById(WC_SELECT_STATION, 0); + w->ToggleWidgetLoweredState(WID_RAT_REMOVE); + w->SetWidgetDirty(WID_RAT_REMOVE); + _remove_button_clicked = w->IsWidgetLowered(WID_RAT_REMOVE); + SetSelectionRed(_remove_button_clicked); +} + +/** + * Updates the Remove button because of Ctrl state change + * @param w window the button belongs to + * @return true iff the remove button was changed + */ +static bool RailToolbar_CtrlChanged(Window *w) +{ + if (w->IsWidgetDisabled(WID_RAT_REMOVE)) return false; + + /* allow ctrl to switch remove mode only for these widgets */ + for (uint i = WID_RAT_BUILD_NS; i <= WID_RAT_BUILD_STATION; i++) { + if ((i <= WID_RAT_AUTORAIL || i >= WID_RAT_BUILD_WAYPOINT) && w->IsWidgetLowered(i)) { + ToggleRailButton_Remove(w); + return true; + } + } + + return false; +} + + +/** + * The "remove"-button click proc of the build-rail toolbar. + * @param w Build-rail toolbar window + * @see BuildRailToolbarWindow::OnClick() + */ +static void BuildRailClick_Remove(Window *w) +{ + if (w->IsWidgetDisabled(WID_RAT_REMOVE)) return; + ToggleRailButton_Remove(w); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + + /* handle station builder */ + if (w->IsWidgetLowered(WID_RAT_BUILD_STATION)) { + if (_remove_button_clicked) { + /* starting drag & drop remove */ + if (!_settings_client.gui.station_dragdrop) { + SetTileSelectSize(1, 1); + } else { + VpSetPlaceSizingLimit(-1); + } + } else { + /* starting station build mode */ + if (!_settings_client.gui.station_dragdrop) { + int x = _settings_client.gui.station_numtracks; + int y = _settings_client.gui.station_platlength; + if (_railstation.orientation == 0) Swap(x, y); + SetTileSelectSize(x, y); + } else { + VpSetPlaceSizingLimit(_settings_game.station.station_spread); + } + } + } +} + +static void DoRailroadTrack(int mode) +{ + DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), + _remove_button_clicked ? + CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) : + CMD_BUILD_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), + CcPlaySound1E); +} + +static void HandleAutodirPlacement() +{ + int trackstat = _thd.drawstyle & HT_DIR_MASK; // 0..5 + + if (_thd.drawstyle & HT_RAIL) { // one tile case + GenericPlaceRail(TileVirtXY(_thd.selend.x, _thd.selend.y), trackstat); + return; + } + + DoRailroadTrack(trackstat); +} + +/** + * Build new signals or remove signals or (if only one tile marked) edit a signal. + * + * If one tile marked abort and use GenericPlaceSignals() + * else use CmdBuildSingleSignal() or CmdRemoveSingleSignal() in rail_cmd.cpp to build many signals + */ +static void HandleAutoSignalPlacement() +{ + uint32 p2 = GB(_thd.drawstyle, 0, 3); // 0..5 + + if ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT) { // one tile case + GenericPlaceSignals(TileVirtXY(_thd.selend.x, _thd.selend.y)); + return; + } + + const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); + + if (w != NULL) { + /* signal GUI is used */ + SB(p2, 3, 1, 0); + SB(p2, 4, 1, _cur_signal_variant); + SB(p2, 6, 1, _ctrl_pressed); + SB(p2, 7, 3, _cur_signal_type); + SB(p2, 24, 8, _settings_client.gui.drag_signals_density); + SB(p2, 10, 1, !_settings_client.gui.drag_signals_fixed_distance); + } else { + SB(p2, 3, 1, 0); + SB(p2, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC)); + SB(p2, 6, 1, _ctrl_pressed); + SB(p2, 7, 3, _default_signal_type[_settings_client.gui.default_signal_type]); + SB(p2, 24, 8, _settings_client.gui.drag_signals_density); + SB(p2, 10, 1, !_settings_client.gui.drag_signals_fixed_distance); + } + + /* _settings_client.gui.drag_signals_density is given as a parameter such that each user + * in a network game can specify his/her own signal density */ + DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, + _remove_button_clicked ? + CMD_REMOVE_SIGNAL_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM) : + CMD_BUILD_SIGNAL_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), + CcPlaySound1E); +} + + +/** Rail toolbar management class. */ +struct BuildRailToolbarWindow : Window { + RailType railtype; ///< Rail type to build. + int last_user_action; ///< Last started user action. + + BuildRailToolbarWindow(WindowDesc *desc, RailType railtype) : Window(desc) + { + this->InitNested(TRANSPORT_RAIL); + this->SetupRailToolbar(railtype); + this->DisableWidget(WID_RAT_REMOVE); + this->last_user_action = WIDGET_LIST_END; + + if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); + } + + ~BuildRailToolbarWindow() + { + if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); + } + + /** + * Configures the rail toolbar for railtype given + * @param railtype the railtype to display + */ + void SetupRailToolbar(RailType railtype) + { + this->railtype = railtype; + const RailtypeInfo *rti = GetRailTypeInfo(railtype); + + assert(railtype < RAILTYPE_END); + this->GetWidget(WID_RAT_BUILD_NS)->widget_data = rti->gui_sprites.build_ns_rail; + this->GetWidget(WID_RAT_BUILD_X)->widget_data = rti->gui_sprites.build_x_rail; + this->GetWidget(WID_RAT_BUILD_EW)->widget_data = rti->gui_sprites.build_ew_rail; + this->GetWidget(WID_RAT_BUILD_Y)->widget_data = rti->gui_sprites.build_y_rail; + this->GetWidget(WID_RAT_AUTORAIL)->widget_data = rti->gui_sprites.auto_rail; + this->GetWidget(WID_RAT_BUILD_DEPOT)->widget_data = rti->gui_sprites.build_depot; + this->GetWidget(WID_RAT_CONVERT_RAIL)->widget_data = rti->gui_sprites.convert_rail; + this->GetWidget(WID_RAT_BUILD_TUNNEL)->widget_data = rti->gui_sprites.build_tunnel; + } + + /** + * Switch to another rail type. + * @param railtype New rail type. + */ + void ModifyRailType(RailType railtype) + { + this->SetupRailToolbar(railtype); + this->ReInit(); + } + + void UpdateRemoveWidgetStatus(int clicked_widget) + { + switch (clicked_widget) { + case WID_RAT_REMOVE: + /* If it is the removal button that has been clicked, do nothing, + * as it is up to the other buttons to drive removal status */ + return; + + case WID_RAT_BUILD_NS: + case WID_RAT_BUILD_X: + case WID_RAT_BUILD_EW: + case WID_RAT_BUILD_Y: + case WID_RAT_AUTORAIL: + case WID_RAT_BUILD_WAYPOINT: + case WID_RAT_BUILD_STATION: + case WID_RAT_BUILD_SIGNALS: + /* Removal button is enabled only if the rail/signal/waypoint/station + * button is still lowered. Once raised, it has to be disabled */ + this->SetWidgetDisabledState(WID_RAT_REMOVE, !this->IsWidgetLowered(clicked_widget)); + break; + + default: + /* When any other buttons than rail/signal/waypoint/station, raise and + * disable the removal button */ + this->DisableWidget(WID_RAT_REMOVE); + this->RaiseWidget(WID_RAT_REMOVE); + break; + } + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_RAT_CAPTION) { + const RailtypeInfo *rti = GetRailTypeInfo(this->railtype); + if (rti->max_speed > 0) { + SetDParam(0, STR_TOOLBAR_RAILTYPE_VELOCITY); + SetDParam(1, rti->strings.toolbar_caption); + SetDParam(2, rti->max_speed); + } else { + SetDParam(0, rti->strings.toolbar_caption); + } + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + if (widget < WID_RAT_BUILD_NS) return; + + _remove_button_clicked = false; + switch (widget) { + case WID_RAT_BUILD_NS: + HandlePlacePushButton(this, WID_RAT_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, HT_LINE | HT_DIR_VL); + this->last_user_action = widget; + break; + + case WID_RAT_BUILD_X: + HandlePlacePushButton(this, WID_RAT_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, HT_LINE | HT_DIR_X); + this->last_user_action = widget; + break; + + case WID_RAT_BUILD_EW: + HandlePlacePushButton(this, WID_RAT_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, HT_LINE | HT_DIR_HL); + this->last_user_action = widget; + break; + + case WID_RAT_BUILD_Y: + HandlePlacePushButton(this, WID_RAT_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, HT_LINE | HT_DIR_Y); + this->last_user_action = widget; + break; + + case WID_RAT_AUTORAIL: + HandlePlacePushButton(this, WID_RAT_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, HT_RAIL); + this->last_user_action = widget; + break; + + case WID_RAT_DEMOLISH: + HandlePlacePushButton(this, WID_RAT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); + this->last_user_action = widget; + break; + + case WID_RAT_BUILD_DEPOT: + if (HandlePlacePushButton(this, WID_RAT_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, HT_RECT)) { + ShowBuildTrainDepotPicker(this); + this->last_user_action = widget; + } + break; + + case WID_RAT_BUILD_WAYPOINT: + this->last_user_action = widget; + _waypoint_count = StationClass::Get(STAT_CLASS_WAYP)->GetSpecCount(); + if (HandlePlacePushButton(this, WID_RAT_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, HT_RECT) && _waypoint_count > 1) { + ShowBuildWaypointPicker(this); + } + break; + + case WID_RAT_BUILD_STATION: + if (HandlePlacePushButton(this, WID_RAT_BUILD_STATION, SPR_CURSOR_RAIL_STATION, HT_RECT)) { + ShowStationBuilder(this); + this->last_user_action = widget; + } + break; + + case WID_RAT_BUILD_SIGNALS: { + this->last_user_action = widget; + bool started = HandlePlacePushButton(this, WID_RAT_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, HT_RECT); + if (started && _settings_client.gui.enable_signal_gui != _ctrl_pressed) { + ShowSignalBuilder(this); + } + break; + } + + case WID_RAT_BUILD_BRIDGE: + HandlePlacePushButton(this, WID_RAT_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT); + this->last_user_action = widget; + break; + + case WID_RAT_BUILD_TUNNEL: + HandlePlacePushButton(this, WID_RAT_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, HT_SPECIAL); + this->last_user_action = widget; + break; + + case WID_RAT_REMOVE: + BuildRailClick_Remove(this); + break; + + case WID_RAT_CONVERT_RAIL: + HandlePlacePushButton(this, WID_RAT_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, HT_RECT | HT_DIAGONAL); + this->last_user_action = widget; + break; + + default: NOT_REACHED(); + } + this->UpdateRemoveWidgetStatus(widget); + if (_ctrl_pressed) RailToolbar_CtrlChanged(this); + } + + virtual EventState OnHotkey(int hotkey) + { + MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection + return Window::OnHotkey(hotkey); + } + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + switch (this->last_user_action) { + case WID_RAT_BUILD_NS: + VpStartPlaceSizing(tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL); + break; + + case WID_RAT_BUILD_X: + VpStartPlaceSizing(tile, VPM_FIX_Y | VPM_RAILDIRS, DDSP_PLACE_RAIL); + break; + + case WID_RAT_BUILD_EW: + VpStartPlaceSizing(tile, VPM_FIX_HORIZONTAL | VPM_RAILDIRS, DDSP_PLACE_RAIL); + break; + + case WID_RAT_BUILD_Y: + VpStartPlaceSizing(tile, VPM_FIX_X | VPM_RAILDIRS, DDSP_PLACE_RAIL); + break; + + case WID_RAT_AUTORAIL: + VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_RAIL); + break; + + case WID_RAT_DEMOLISH: + PlaceProc_DemolishArea(tile); + break; + + case WID_RAT_BUILD_DEPOT: + DoCommandP(tile, _cur_railtype, _build_depot_direction, + CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT), + CcRailDepot); + break; + + case WID_RAT_BUILD_WAYPOINT: + PlaceRail_Waypoint(tile); + break; + + case WID_RAT_BUILD_STATION: + PlaceRail_Station(tile); + break; + + case WID_RAT_BUILD_SIGNALS: + VpStartPlaceSizing(tile, VPM_SIGNALDIRS, DDSP_BUILD_SIGNALS); + break; + + case WID_RAT_BUILD_BRIDGE: + PlaceRail_Bridge(tile, this); + break; + + case WID_RAT_BUILD_TUNNEL: + DoCommandP(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel); + break; + + case WID_RAT_CONVERT_RAIL: + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_RAIL); + break; + + default: NOT_REACHED(); + } + } + + virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + { + /* no dragging if you have pressed the convert button */ + if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && this->IsWidgetLowered(WID_RAT_BUILD_SIGNALS)) return; + + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + } + + virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + { + if (pt.x != -1) { + switch (select_proc) { + default: NOT_REACHED(); + case DDSP_BUILD_BRIDGE: + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype); + break; + + case DDSP_PLACE_RAIL: + HandleAutodirPlacement(); + break; + + case DDSP_BUILD_SIGNALS: + HandleAutoSignalPlacement(); + break; + + case DDSP_DEMOLISH_AREA: + GUIPlaceProcDragXY(select_proc, start_tile, end_tile); + break; + + case DDSP_CONVERT_RAIL: + DoCommandP(end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 0x10 : 0), CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound10); + break; + + case DDSP_REMOVE_STATION: + case DDSP_BUILD_STATION: + if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) { + /* Station */ + if (_remove_button_clicked) { + DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION), CcPlaySound1E); + } else { + HandleStationPlacement(start_tile, end_tile); + } + } else { + /* Waypoint */ + if (_remove_button_clicked) { + DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT), CcPlaySound1E); + } else { + TileArea ta(start_tile, end_tile); + uint32 p1 = _cur_railtype | (select_method == VPM_FIX_X ? AXIS_X : AXIS_Y) << 4 | ta.w << 8 | ta.h << 16 | _ctrl_pressed << 24; + uint32 p2 = STAT_CLASS_WAYP | _cur_waypoint_type << 8 | INVALID_STATION << 16; + + CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT), CcPlaySound1E, "" }; + ShowSelectWaypointIfNeeded(cmdcont, ta); + } + } + break; + } + } + } + + virtual void OnPlaceObjectAbort() + { + this->RaiseButtons(); + this->DisableWidget(WID_RAT_REMOVE); + this->SetWidgetDirty(WID_RAT_REMOVE); + + DeleteWindowById(WC_BUILD_SIGNAL, TRANSPORT_RAIL); + DeleteWindowById(WC_BUILD_STATION, TRANSPORT_RAIL); + DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_RAIL); + DeleteWindowById(WC_BUILD_WAYPOINT, TRANSPORT_RAIL); + DeleteWindowById(WC_SELECT_STATION, 0); + DeleteWindowByClass(WC_BUILD_BRIDGE); + } + + virtual void OnPlacePresize(Point pt, TileIndex tile) + { + DoCommand(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); + VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); + } + + virtual EventState OnCTRLStateChange() + { + /* do not toggle Remove button by Ctrl when placing station */ + if (!this->IsWidgetLowered(WID_RAT_BUILD_STATION) && !this->IsWidgetLowered(WID_RAT_BUILD_WAYPOINT) && RailToolbar_CtrlChanged(this)) return ES_HANDLED; + return ES_NOT_HANDLED; + } + + static HotkeyList hotkeys; +}; + +/** + * Handler for global hotkeys of the BuildRailToolbarWindow. + * @param hotkey Hotkey + * @return ES_HANDLED if hotkey was accepted. + */ +static EventState RailToolbarGlobalHotkeys(int hotkey) +{ + if (_game_mode != GM_NORMAL || !CanBuildVehicleInfrastructure(VEH_TRAIN)) return ES_NOT_HANDLED; + extern RailType _last_built_railtype; + Window *w = ShowBuildRailToolbar(_last_built_railtype); + if (w == NULL) return ES_NOT_HANDLED; + return w->OnHotkey(hotkey); +} + +const uint16 _railtoolbar_autorail_keys[] = {'5', 'A' | WKC_GLOBAL_HOTKEY, 0}; + +static Hotkey railtoolbar_hotkeys[] = { + Hotkey('1', "build_ns", WID_RAT_BUILD_NS), + Hotkey('2', "build_x", WID_RAT_BUILD_X), + Hotkey('3', "build_ew", WID_RAT_BUILD_EW), + Hotkey('4', "build_y", WID_RAT_BUILD_Y), + Hotkey(_railtoolbar_autorail_keys, "autorail", WID_RAT_AUTORAIL), + Hotkey('6', "demolish", WID_RAT_DEMOLISH), + Hotkey('7', "depot", WID_RAT_BUILD_DEPOT), + Hotkey('8', "waypoint", WID_RAT_BUILD_WAYPOINT), + Hotkey('9', "station", WID_RAT_BUILD_STATION), + Hotkey('S', "signal", WID_RAT_BUILD_SIGNALS), + Hotkey('B', "bridge", WID_RAT_BUILD_BRIDGE), + Hotkey('T', "tunnel", WID_RAT_BUILD_TUNNEL), + Hotkey('R', "remove", WID_RAT_REMOVE), + Hotkey('C', "convert", WID_RAT_CONVERT_RAIL), + HOTKEY_LIST_END +}; +HotkeyList BuildRailToolbarWindow::hotkeys("railtoolbar", railtoolbar_hotkeys, RailToolbarGlobalHotkeys); + +static const NWidgetPart _nested_build_rail_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_RAT_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_NS), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NS, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_X), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NE, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_EW), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_EW, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_Y), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NW, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_AUTORAIL), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTORAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL), + + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetDataTip(0x0, STR_NULL), EndContainer(), + + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_DEMOLISH), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_DEPOT), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DEPOT_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_WAYPOINT), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_WAYPOINT, STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_STATION), + SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_RAIL_STATION, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_SIGNALS), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_SIGNALS, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_BRIDGE), + SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_BRIDGE, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_TUNNEL), + SetFill(0, 1), SetMinimalSize(20, 22), SetDataTip(SPR_IMG_TUNNEL_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_REMOVE), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_CONVERT_RAIL), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL), + EndContainer(), +}; + +static WindowDesc _build_rail_desc( + WDP_ALIGN_TOOLBAR, "toolbar_rail", 0, 0, + WC_BUILD_TOOLBAR, WC_NONE, + WDF_CONSTRUCTION, + _nested_build_rail_widgets, lengthof(_nested_build_rail_widgets), + &BuildRailToolbarWindow::hotkeys +); + + +/** + * Open the build rail toolbar window for a specific rail type. + * + * If the terraform toolbar is linked to the toolbar, that window is also opened. + * + * @param railtype Rail type to open the window for + * @return newly opened rail toolbar, or NULL if the toolbar could not be opened. + */ +Window *ShowBuildRailToolbar(RailType railtype) +{ + if (!Company::IsValidID(_local_company)) return NULL; + if (!ValParamRailtype(railtype)) return NULL; + + DeleteWindowByClass(WC_BUILD_TOOLBAR); + _cur_railtype = railtype; + _remove_button_clicked = false; + return new BuildRailToolbarWindow(&_build_rail_desc, railtype); +} + +/* TODO: For custom stations, respect their allowed platforms/lengths bitmasks! + * --pasky */ + +static void HandleStationPlacement(TileIndex start, TileIndex end) +{ + TileArea ta(start, end); + uint numtracks = ta.w; + uint platlength = ta.h; + + if (_railstation.orientation == AXIS_X) Swap(numtracks, platlength); + + uint32 p1 = _cur_railtype | _railstation.orientation << 4 | numtracks << 8 | platlength << 16 | _ctrl_pressed << 24; + uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16; + + CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" }; + ShowSelectStationIfNeeded(cmdcont, ta); +} + +struct BuildRailStationWindow : public PickerWindowBase { +private: + uint line_height; ///< Height of a single line in the newstation selection matrix (#WID_BRAS_NEWST_LIST widget). + uint coverage_height; ///< Height of the coverage texts. + Scrollbar *vscroll; ///< Vertical scrollbar of the new station list. + Scrollbar *vscroll2; ///< Vertical scrollbar of the matrix with new stations. + + /** + * Verify whether the currently selected station size is allowed after selecting a new station class/type. + * If not, change the station size variables ( _settings_client.gui.station_numtracks and _settings_client.gui.station_platlength ). + * @param statspec Specification of the new station class/type + */ + void CheckSelectedSize(const StationSpec *statspec) + { + if (statspec == NULL || _settings_client.gui.station_dragdrop) return; + + /* If current number of tracks is not allowed, make it as big as possible */ + if (HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { + this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); + _settings_client.gui.station_numtracks = 1; + if (statspec->disallowed_platforms != UINT8_MAX) { + while (HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { + _settings_client.gui.station_numtracks++; + } + this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); + } + } + + if (HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { + this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); + _settings_client.gui.station_platlength = 1; + if (statspec->disallowed_lengths != UINT8_MAX) { + while (HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { + _settings_client.gui.station_platlength++; + } + this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); + } + } + } + +public: + BuildRailStationWindow(WindowDesc *desc, Window *parent, bool newstation) : PickerWindowBase(desc, parent) + { + this->coverage_height = 2 * FONT_HEIGHT_NORMAL + 3 * WD_PAR_VSEP_NORMAL; + this->vscroll = NULL; + _railstation.newstations = newstation; + + this->CreateNestedTree(); + NWidgetStacked *newst_additions = this->GetWidget(WID_BRAS_SHOW_NEWST_ADDITIONS); + newst_additions->SetDisplayedPlane(newstation ? 0 : SZSP_NONE); + newst_additions = this->GetWidget(WID_BRAS_SHOW_NEWST_MATRIX); + newst_additions->SetDisplayedPlane(newstation ? 0 : SZSP_NONE); + newst_additions = this->GetWidget(WID_BRAS_SHOW_NEWST_DEFSIZE); + newst_additions->SetDisplayedPlane(newstation ? 0 : SZSP_NONE); + newst_additions = this->GetWidget(WID_BRAS_SHOW_NEWST_RESIZE); + newst_additions->SetDisplayedPlane(newstation ? 0 : SZSP_NONE); + if (newstation) { + this->vscroll = this->GetScrollbar(WID_BRAS_NEWST_SCROLL); + this->vscroll2 = this->GetScrollbar(WID_BRAS_MATRIX_SCROLL); + } + this->FinishInitNested(TRANSPORT_RAIL); + + this->LowerWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X); + if (_settings_client.gui.station_dragdrop) { + this->LowerWidget(WID_BRAS_PLATFORM_DRAG_N_DROP); + } else { + this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); + this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); + } + this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_OFF, !_settings_client.gui.station_show_coverage); + this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_ON, _settings_client.gui.station_show_coverage); + + if (!newstation || _railstation.station_class >= (int)StationClass::GetClassCount()) { + /* New stations are not available or changed, so ensure the default station + * type is 'selected'. */ + _railstation.station_class = STAT_CLASS_DFLT; + _railstation.station_type = 0; + this->vscroll2 = NULL; + } + if (newstation) { + _railstation.station_count = StationClass::Get(_railstation.station_class)->GetSpecCount(); + _railstation.station_type = min(_railstation.station_type, _railstation.station_count - 1); + + int count = 0; + for (uint i = 0; i < StationClass::GetClassCount(); i++) { + if (i == STAT_CLASS_WAYP) continue; + count++; + } + this->vscroll->SetCount(count); + this->vscroll->SetPosition(Clamp(_railstation.station_class - 2, 0, max(this->vscroll->GetCount() - this->vscroll->GetCapacity(), 0))); + + NWidgetMatrix *matrix = this->GetWidget(WID_BRAS_MATRIX); + matrix->SetScrollbar(this->vscroll2); + matrix->SetCount(_railstation.station_count); + matrix->SetClicked(_railstation.station_type); + } + } + + virtual ~BuildRailStationWindow() + { + DeleteWindowById(WC_SELECT_STATION, 0); + } + + virtual void OnPaint() + { + bool newstations = _railstation.newstations; + const StationSpec *statspec = newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; + + if (_settings_client.gui.station_dragdrop) { + SetTileSelectSize(1, 1); + } else { + int x = _settings_client.gui.station_numtracks; + int y = _settings_client.gui.station_platlength; + if (_railstation.orientation == AXIS_X) Swap(x, y); + if (!_remove_button_clicked) { + SetTileSelectSize(x, y); + } + } + + int rad = (_settings_game.station.modified_catchment) ? CA_TRAIN : CA_UNMODIFIED; + + if (_settings_client.gui.station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); + + for (uint bits = 0; bits < 7; bits++) { + bool disable = bits >= _settings_game.station.station_spread; + if (statspec == NULL) { + this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_NUM_1, disable); + this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_LEN_1, disable); + } else { + this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_NUM_1, HasBit(statspec->disallowed_platforms, bits) || disable); + this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_LEN_1, HasBit(statspec->disallowed_lengths, bits) || disable); + } + } + + this->DrawWidgets(); + + /* 'Accepts' and 'Supplies' texts. */ + NWidgetBase *cov = this->GetWidget(WID_BRAS_COVERAGE_TEXTS); + int top = cov->pos_y + WD_PAR_VSEP_NORMAL; + int left = cov->pos_x + WD_FRAMERECT_LEFT; + int right = cov->pos_x + cov->current_x - WD_FRAMERECT_RIGHT; + int bottom = cov->pos_y + cov->current_y; + top = DrawStationCoverageAreaText(left, right, top, SCT_ALL, rad, false) + WD_PAR_VSEP_NORMAL; + top = DrawStationCoverageAreaText(left, right, top, SCT_ALL, rad, true) + WD_PAR_VSEP_NORMAL; + /* Resize background if the window is too small. + * Never make the window smaller to avoid oscillating if the size change affects the acceptance. + * (This is the case, if making the window bigger moves the mouse into the window.) */ + if (top > bottom) { + this->coverage_height += top - bottom; + this->ReInit(); + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_BRAS_NEWST_LIST: { + Dimension d = {0, 0}; + for (uint i = 0; i < StationClass::GetClassCount(); i++) { + if (i == STAT_CLASS_WAYP) continue; + SetDParam(0, StationClass::Get((StationClassID)i)->name); + d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING)); + } + size->width = max(size->width, d.width + padding.width); + this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + size->height = 5 * this->line_height; + resize->height = this->line_height; + break; + } + + case WID_BRAS_SHOW_NEWST_TYPE: { + if (!_railstation.newstations) { + size->width = 0; + size->height = 0; + break; + } + + /* If newstations exist, compute the non-zero minimal size. */ + Dimension d = {0, 0}; + StringID str = this->GetWidget(widget)->widget_data; + for (StationClassID statclass = STAT_CLASS_BEGIN; statclass < (StationClassID)StationClass::GetClassCount(); statclass++) { + if (statclass == STAT_CLASS_WAYP) continue; + StationClass *stclass = StationClass::Get(statclass); + for (uint16 j = 0; j < stclass->GetSpecCount(); j++) { + const StationSpec *statspec = stclass->GetSpec(j); + SetDParam(0, (statspec != NULL && statspec->name != 0) ? statspec->name : STR_STATION_CLASS_DFLT); + d = maxdim(d, GetStringBoundingBox(str)); + } + } + size->width = max(size->width, d.width + padding.width); + break; + } + + case WID_BRAS_COVERAGE_TEXTS: + size->height = this->coverage_height; + break; + + case WID_BRAS_MATRIX: + fill->height = 1; + resize->height = 1; + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + DrawPixelInfo tmp_dpi; + + switch (GB(widget, 0, 16)) { + case WID_BRAS_PLATFORM_DIR_X: + /* Set up a clipping area for the '/' station preview */ + if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { + DrawPixelInfo *old_dpi = _cur_dpi; + _cur_dpi = &tmp_dpi; + if (!DrawStationTile(32, 28, _cur_railtype, AXIS_X, _railstation.station_class, _railstation.station_type)) { + StationPickerDrawSprite(32, 28, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2); + } + _cur_dpi = old_dpi; + } + break; + + case WID_BRAS_PLATFORM_DIR_Y: + /* Set up a clipping area for the '\' station preview */ + if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { + DrawPixelInfo *old_dpi = _cur_dpi; + _cur_dpi = &tmp_dpi; + if (!DrawStationTile(32, 28, _cur_railtype, AXIS_Y, _railstation.station_class, _railstation.station_type)) { + StationPickerDrawSprite(32, 28, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 3); + } + _cur_dpi = old_dpi; + } + break; + + case WID_BRAS_NEWST_LIST: { + uint statclass = 0; + uint row = 0; + for (uint i = 0; i < StationClass::GetClassCount(); i++) { + if (i == STAT_CLASS_WAYP) continue; + if (this->vscroll->IsVisible(statclass)) { + SetDParam(0, StationClass::Get((StationClassID)i)->name); + DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, row * this->line_height + r.top + WD_MATRIX_TOP, STR_JUST_STRING, + (StationClassID)i == _railstation.station_class ? TC_WHITE : TC_BLACK); + row++; + } + statclass++; + } + break; + } + + case WID_BRAS_IMAGE: { + byte type = GB(widget, 16, 16); + assert(type < _railstation.station_count); + /* Check station availability callback */ + const StationSpec *statspec = StationClass::Get(_railstation.station_class)->GetSpec(type); + if (!IsStationAvailable(statspec)) { + GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER); + } + + /* Set up a clipping area for the station preview. */ + if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { + DrawPixelInfo *old_dpi = _cur_dpi; + _cur_dpi = &tmp_dpi; + if (!DrawStationTile(32, 28, _cur_railtype, _railstation.orientation, _railstation.station_class, type)) { + StationPickerDrawSprite(32, 28, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2 + _railstation.orientation); + } + _cur_dpi = old_dpi; + } + break; + } + } + } + + virtual void OnResize() + { + if (this->vscroll != NULL) { // New stations available. + this->vscroll->SetCapacityFromWidget(this, WID_BRAS_NEWST_LIST); + } + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_BRAS_SHOW_NEWST_TYPE) { + const StationSpec *statspec = StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type); + SetDParam(0, (statspec != NULL && statspec->name != 0) ? statspec->name : STR_STATION_CLASS_DFLT); + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (GB(widget, 0, 16)) { + case WID_BRAS_PLATFORM_DIR_X: + case WID_BRAS_PLATFORM_DIR_Y: + this->RaiseWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X); + _railstation.orientation = (Axis)(widget - WID_BRAS_PLATFORM_DIR_X); + this->LowerWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + DeleteWindowById(WC_SELECT_STATION, 0); + break; + + case WID_BRAS_PLATFORM_NUM_1: + case WID_BRAS_PLATFORM_NUM_2: + case WID_BRAS_PLATFORM_NUM_3: + case WID_BRAS_PLATFORM_NUM_4: + case WID_BRAS_PLATFORM_NUM_5: + case WID_BRAS_PLATFORM_NUM_6: + case WID_BRAS_PLATFORM_NUM_7: { + this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); + this->RaiseWidget(WID_BRAS_PLATFORM_DRAG_N_DROP); + + _settings_client.gui.station_numtracks = widget - WID_BRAS_PLATFORM_NUM_BEGIN; + _settings_client.gui.station_dragdrop = false; + + _settings_client.gui.station_dragdrop = false; + + const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; + if (statspec != NULL && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { + /* The previously selected number of platforms in invalid */ + for (uint i = 0; i < 7; i++) { + if (!HasBit(statspec->disallowed_lengths, i)) { + this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); + _settings_client.gui.station_platlength = i + 1; + break; + } + } + } + + this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); + this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + DeleteWindowById(WC_SELECT_STATION, 0); + break; + } + + case WID_BRAS_PLATFORM_LEN_1: + case WID_BRAS_PLATFORM_LEN_2: + case WID_BRAS_PLATFORM_LEN_3: + case WID_BRAS_PLATFORM_LEN_4: + case WID_BRAS_PLATFORM_LEN_5: + case WID_BRAS_PLATFORM_LEN_6: + case WID_BRAS_PLATFORM_LEN_7: { + this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); + this->RaiseWidget(WID_BRAS_PLATFORM_DRAG_N_DROP); + + _settings_client.gui.station_platlength = widget - WID_BRAS_PLATFORM_LEN_BEGIN; + _settings_client.gui.station_dragdrop = false; + + _settings_client.gui.station_dragdrop = false; + + const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; + if (statspec != NULL && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { + /* The previously selected number of tracks in invalid */ + for (uint i = 0; i < 7; i++) { + if (!HasBit(statspec->disallowed_platforms, i)) { + this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); + _settings_client.gui.station_numtracks = i + 1; + break; + } + } + } + + this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); + this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + DeleteWindowById(WC_SELECT_STATION, 0); + break; + } + + case WID_BRAS_PLATFORM_DRAG_N_DROP: { + _settings_client.gui.station_dragdrop ^= true; + + this->ToggleWidgetLoweredState(WID_BRAS_PLATFORM_DRAG_N_DROP); + + /* get the first allowed length/number of platforms */ + const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; + if (statspec != NULL && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { + for (uint i = 0; i < 7; i++) { + if (!HasBit(statspec->disallowed_lengths, i)) { + this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); + _settings_client.gui.station_platlength = i + 1; + break; + } + } + } + if (statspec != NULL && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { + for (uint i = 0; i < 7; i++) { + if (!HasBit(statspec->disallowed_platforms, i)) { + this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); + _settings_client.gui.station_numtracks = i + 1; + break; + } + } + } + + this->SetWidgetLoweredState(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN, !_settings_client.gui.station_dragdrop); + this->SetWidgetLoweredState(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN, !_settings_client.gui.station_dragdrop); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + DeleteWindowById(WC_SELECT_STATION, 0); + break; + } + + case WID_BRAS_HIGHLIGHT_OFF: + case WID_BRAS_HIGHLIGHT_ON: + _settings_client.gui.station_show_coverage = (widget != WID_BRAS_HIGHLIGHT_OFF); + + this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_OFF, !_settings_client.gui.station_show_coverage); + this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_ON, _settings_client.gui.station_show_coverage); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + break; + + case WID_BRAS_NEWST_LIST: { + int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BRAS_NEWST_LIST, 0, this->line_height); + if (y >= (int)StationClass::GetClassCount()) return; + for (uint i = 0; i < StationClass::GetClassCount(); i++) { + if (i == STAT_CLASS_WAYP) continue; + if (y == 0) { + if (_railstation.station_class != (StationClassID)i) { + _railstation.station_class = (StationClassID)i; + StationClass *stclass = StationClass::Get(_railstation.station_class); + _railstation.station_count = stclass->GetSpecCount(); + _railstation.station_type = min((int)_railstation.station_type, max(0, (int)_railstation.station_count - 1)); + + this->CheckSelectedSize(stclass->GetSpec(_railstation.station_type)); + + NWidgetMatrix *matrix = this->GetWidget(WID_BRAS_MATRIX); + matrix->SetCount(_railstation.station_count); + matrix->SetClicked(_railstation.station_type); + } + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + DeleteWindowById(WC_SELECT_STATION, 0); + break; + } + y--; + } + break; + } + + case WID_BRAS_IMAGE: { + int y = GB(widget, 16, 16); + if (y >= _railstation.station_count) return; + + /* Check station availability callback */ + const StationSpec *statspec = StationClass::Get(_railstation.station_class)->GetSpec(y); + if (!IsStationAvailable(statspec)) return; + + _railstation.station_type = y; + + this->CheckSelectedSize(statspec); + this->GetWidget(WID_BRAS_MATRIX)->SetClicked(_railstation.station_type); + + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + DeleteWindowById(WC_SELECT_STATION, 0); + break; + } + } + } + + virtual void OnTick() + { + CheckRedrawStationCoverage(this); + } +}; + +static const NWidgetPart _nested_station_builder_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_RAIL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_DEFSIZE), + NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), + EndContainer(), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_VERTICAL), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_ADDITIONS), + NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7), SetPadding(2, 0, 1, 0), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_BRAS_NEWST_LIST), SetMinimalSize(122, 71), SetFill(1, 0), + SetMatrixDataTip(1, 0, STR_STATION_BUILD_STATION_CLASS_TOOLTIP), SetScrollbar(WID_BRAS_NEWST_SCROLL), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BRAS_NEWST_SCROLL), + EndContainer(), + EndContainer(), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetPadding(1, 2, 0, 2), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_X), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_Y), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0), + EndContainer(), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BRAS_SHOW_NEWST_TYPE), SetMinimalSize(144, 11), SetDataTip(STR_ORANGE_STRING, STR_NULL), SetPadding(1, 2, 4, 2), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_NUMBER_OF_TRACKS, STR_NULL), SetPadding(0, 2, 0, 2), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_PLATFORM_LENGTH, STR_NULL), SetPadding(2, 2, 0, 2), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_DRAG_N_DROP), SetMinimalSize(75, 12), SetDataTip(STR_STATION_BUILD_DRAG_DROP, STR_STATION_BUILD_DRAG_DROP_TOOLTIP), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), + EndContainer(), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetPadding(3, 2, 0, 2), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_HIGHLIGHT_OFF), SetMinimalSize(60, 12), + SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_HIGHLIGHT_ON), SetMinimalSize(60, 12), + SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), + EndContainer(), + EndContainer(), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_MATRIX), + /* We need an additional background for the matrix, as the matrix cannot handle the scrollbar due to not being an NWidgetCore. */ + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BRAS_MATRIX_SCROLL), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BRAS_MATRIX), SetScrollbar(WID_BRAS_MATRIX_SCROLL), SetPIP(0, 2, 0), SetPadding(2, 0, 0, 0), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BRAS_IMAGE), SetMinimalSize(66, 60), + SetFill(0, 0), SetResize(0, 0), SetDataTip(0x0, STR_STATION_BUILD_STATION_TYPE_TOOLTIP), SetScrollbar(WID_BRAS_MATRIX_SCROLL), + EndContainer(), + EndContainer(), + NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_BRAS_MATRIX_SCROLL), + EndContainer(), + EndContainer(), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BRAS_COVERAGE_TEXTS), SetFill(1, 1), SetResize(1, 0), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_RESIZE), + NWidget(NWID_VERTICAL), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(0, 1), EndContainer(), + NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), + EndContainer(), + EndContainer(), + EndContainer(), + EndContainer(), +}; + +/** High level window description of the station-build window (default & newGRF) */ +static WindowDesc _station_builder_desc( + WDP_AUTO, "build_station_rail", 350, 0, + WC_BUILD_STATION, WC_BUILD_TOOLBAR, + WDF_CONSTRUCTION, + _nested_station_builder_widgets, lengthof(_nested_station_builder_widgets) +); + +/** Open station build window */ +static void ShowStationBuilder(Window *parent) +{ + bool newstations = StationClass::GetClassCount() > 2 || StationClass::Get(STAT_CLASS_DFLT)->GetSpecCount() != 1; + new BuildRailStationWindow(&_station_builder_desc, parent, newstations); +} + +struct BuildSignalWindow : public PickerWindowBase { +private: + Dimension sig_sprite_size; ///< Maximum size of signal GUI sprites. + int sig_sprite_bottom_offset; ///< Maximum extent of signal GUI sprite from reference point towards bottom. + + /** + * Draw dynamic a signal-sprite in a button in the signal GUI + * Draw the sprite +1px to the right and down if the button is lowered + * + * @param widget_index index of this widget in the window + * @param image the sprite to draw + */ + void DrawSignalSprite(byte widget_index, SpriteID image) const + { + Point offset; + Dimension sprite_size = GetSpriteSize(image, &offset); + const NWidgetBase *widget = this->GetWidget(widget_index); + int x = widget->pos_x - offset.x + + (widget->current_x - sprite_size.width + offset.x) / 2; // centered + int y = widget->pos_y - sig_sprite_bottom_offset + WD_IMGBTN_TOP + + (widget->current_y - WD_IMGBTN_TOP - WD_IMGBTN_BOTTOM + sig_sprite_size.height) / 2; // aligned to bottom + + DrawSprite(image, PAL_NONE, + x + this->IsWidgetLowered(widget_index), + y + this->IsWidgetLowered(widget_index)); + } + +public: + BuildSignalWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) + { + this->InitNested(TRANSPORT_RAIL); + this->OnInvalidateData(); + } + + ~BuildSignalWindow() + { + _convert_signal_button = false; + } + + virtual void OnInit() + { + /* Calculate maximum signal sprite size. */ + this->sig_sprite_size.width = 0; + this->sig_sprite_size.height = 0; + this->sig_sprite_bottom_offset = 0; + const RailtypeInfo *rti = GetRailTypeInfo(_cur_railtype); + for (uint type = SIGTYPE_NORMAL; type < SIGTYPE_END; type++) { + for (uint variant = SIG_ELECTRIC; variant <= SIG_SEMAPHORE; variant++) { + for (uint lowered = 0; lowered < 2; lowered++) { + Point offset; + Dimension sprite_size = GetSpriteSize(rti->gui_sprites.signals[type][variant][lowered], &offset); + this->sig_sprite_bottom_offset = max(this->sig_sprite_bottom_offset, sprite_size.height); + this->sig_sprite_size.width = max(this->sig_sprite_size.width, sprite_size.width - offset.x); + this->sig_sprite_size.height = max(this->sig_sprite_size.height, sprite_size.height - offset.y); + } + } + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget == WID_BS_DRAG_SIGNALS_DENSITY_LABEL) { + /* Two digits for signals density. */ + size->width = max(size->width, 2 * GetDigitWidth() + padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT); + } else if (IsInsideMM(widget, WID_BS_SEMAPHORE_NORM, WID_BS_ELECTRIC_PBS_OWAY + 1)) { + size->width = max(size->width, this->sig_sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT); + size->height = max(size->height, this->sig_sprite_size.height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM); + } + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_BS_DRAG_SIGNALS_DENSITY_LABEL: + SetDParam(0, _settings_client.gui.drag_signals_density); + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (IsInsideMM(widget, WID_BS_SEMAPHORE_NORM, WID_BS_ELECTRIC_PBS_OWAY + 1)) { + /* Extract signal from widget number. */ + int type = (widget - WID_BS_SEMAPHORE_NORM) % SIGTYPE_END; + int var = SIG_SEMAPHORE - (widget - WID_BS_SEMAPHORE_NORM) / SIGTYPE_END; // SignalVariant order is reversed compared to the widgets. + SpriteID sprite = GetRailTypeInfo(_cur_railtype)->gui_sprites.signals[type][var][this->IsWidgetLowered(widget)]; + + this->DrawSignalSprite(widget, sprite); + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_BS_SEMAPHORE_NORM: + case WID_BS_SEMAPHORE_ENTRY: + case WID_BS_SEMAPHORE_EXIT: + case WID_BS_SEMAPHORE_COMBO: + case WID_BS_SEMAPHORE_PBS: + case WID_BS_SEMAPHORE_PBS_OWAY: + case WID_BS_ELECTRIC_NORM: + case WID_BS_ELECTRIC_ENTRY: + case WID_BS_ELECTRIC_EXIT: + case WID_BS_ELECTRIC_COMBO: + case WID_BS_ELECTRIC_PBS: + case WID_BS_ELECTRIC_PBS_OWAY: + this->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type); + + _cur_signal_type = (SignalType)((uint)((widget - WID_BS_SEMAPHORE_NORM) % (SIGTYPE_LAST + 1))); + _cur_signal_variant = widget >= WID_BS_ELECTRIC_NORM ? SIG_ELECTRIC : SIG_SEMAPHORE; + + /* If 'remove' button of rail build toolbar is active, disable it. */ + if (_remove_button_clicked) { + Window *w = FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL); + if (w != NULL) ToggleRailButton_Remove(w); + } + + break; + + case WID_BS_CONVERT: + _convert_signal_button = !_convert_signal_button; + break; + + case WID_BS_DRAG_SIGNALS_DENSITY_DECREASE: + if (_settings_client.gui.drag_signals_density > 1) { + _settings_client.gui.drag_signals_density--; + SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_SETTINGS); + } + break; + + case WID_BS_DRAG_SIGNALS_DENSITY_INCREASE: + if (_settings_client.gui.drag_signals_density < 20) { + _settings_client.gui.drag_signals_density++; + SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_SETTINGS); + } + break; + + default: break; + } + + this->InvalidateData(); + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + this->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type); + + this->SetWidgetLoweredState(WID_BS_CONVERT, _convert_signal_button); + + this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, _settings_client.gui.drag_signals_density == 1); + this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, _settings_client.gui.drag_signals_density == 20); + } +}; + +/** Nested widget definition of the build signal window */ +static const NWidgetPart _nested_signal_builder_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_BUILD_SIGNAL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(NWID_VERTICAL, NC_EQUALSIZE), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_CONVERT), SetDataTip(SPR_IMG_SIGNAL_CONVERT, STR_BUILD_SIGNAL_CONVERT_TOOLTIP), SetFill(1, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BS_DRAG_SIGNALS_DENSITY_LABEL), SetDataTip(STR_ORANGE_INT, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), + NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_DECREASE), SetSizingType(NWST_STEP), SetMinimalSize(9, 12), SetDataTip(AWV_DECREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_INCREASE), SetSizingType(NWST_STEP), SetMinimalSize(9, 12), SetDataTip(AWV_INCREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0), + EndContainer(), + EndContainer(), + EndContainer(), +}; + +/** Signal selection window description */ +static WindowDesc _signal_builder_desc( + WDP_AUTO, "build_signal", 0, 0, + WC_BUILD_SIGNAL, WC_BUILD_TOOLBAR, + WDF_CONSTRUCTION, + _nested_signal_builder_widgets, lengthof(_nested_signal_builder_widgets) +); + +/** + * Open the signal selection window + */ +static void ShowSignalBuilder(Window *parent) +{ + new BuildSignalWindow(&_signal_builder_desc, parent); +} + +struct BuildRailDepotWindow : public PickerWindowBase { + BuildRailDepotWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) + { + this->InitNested(TRANSPORT_RAIL); + this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (!IsInsideMM(widget, WID_BRAD_DEPOT_NE, WID_BRAD_DEPOT_NW + 1)) return; + + DrawTrainDepotSprite(r.left - 1, r.top, widget - WID_BRAD_DEPOT_NE + DIAGDIR_NE, _cur_railtype); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_BRAD_DEPOT_NE: + case WID_BRAD_DEPOT_SE: + case WID_BRAD_DEPOT_SW: + case WID_BRAD_DEPOT_NW: + this->RaiseWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); + _build_depot_direction = (DiagDirection)(widget - WID_BRAD_DEPOT_NE); + this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + break; + } + } +}; + +/** Nested widget definition of the build rail depot window */ +static const NWidgetPart _nested_build_depot_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), + NWidget(NWID_SPACER), SetMinimalSize(0, 3), + NWidget(NWID_HORIZONTAL_LTR), + NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), + NWidget(NWID_VERTICAL), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), + NWidget(NWID_VERTICAL), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 3), + EndContainer(), +}; + +static WindowDesc _build_depot_desc( + WDP_AUTO, NULL, 0, 0, + WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, + WDF_CONSTRUCTION, + _nested_build_depot_widgets, lengthof(_nested_build_depot_widgets) +); + +static void ShowBuildTrainDepotPicker(Window *parent) +{ + new BuildRailDepotWindow(&_build_depot_desc, parent); +} + +struct BuildRailWaypointWindow : PickerWindowBase { + BuildRailWaypointWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) + { + this->CreateNestedTree(); + + NWidgetMatrix *matrix = this->GetWidget(WID_BRW_WAYPOINT_MATRIX); + matrix->SetScrollbar(this->GetScrollbar(WID_BRW_SCROLL)); + + this->FinishInitNested(TRANSPORT_RAIL); + + matrix->SetCount(_waypoint_count); + matrix->SetClicked(_cur_waypoint_type); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_BRW_WAYPOINT_MATRIX: + /* Three blobs high and wide. */ + size->width += resize->width * 2; + size->height += resize->height * 2; + + /* Resizing in X direction only at blob size, but at pixel level in Y. */ + resize->height = 1; + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (GB(widget, 0, 16)) { + case WID_BRW_WAYPOINT: { + byte type = GB(widget, 16, 16); + const StationSpec *statspec = StationClass::Get(STAT_CLASS_WAYP)->GetSpec(type); + DrawWaypointSprite(r.left + TILE_PIXELS, r.bottom - TILE_PIXELS, type, _cur_railtype); + + if (!IsStationAvailable(statspec)) { + GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER); + } + } + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (GB(widget, 0, 16)) { + case WID_BRW_WAYPOINT: { + byte type = GB(widget, 16, 16); + this->GetWidget(WID_BRW_WAYPOINT_MATRIX)->SetClicked(_cur_waypoint_type); + + /* Check station availability callback */ + const StationSpec *statspec = StationClass::Get(STAT_CLASS_WAYP)->GetSpec(type); + if (!IsStationAvailable(statspec)) return; + + _cur_waypoint_type = type; + this->GetWidget(WID_BRW_WAYPOINT_MATRIX)->SetClicked(_cur_waypoint_type); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + break; + } + } + } +}; + +/** Nested widget definition for the build NewGRF rail waypoint window */ +static const NWidgetPart _nested_build_waypoint_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_WAYPOINT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BRW_WAYPOINT_MATRIX), SetPIP(3, 2, 3), SetScrollbar(WID_BRW_SCROLL), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BRW_WAYPOINT), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), SetScrollbar(WID_BRW_SCROLL), EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_BRW_SCROLL), + NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), + EndContainer(), + EndContainer(), +}; + +static WindowDesc _build_waypoint_desc( + WDP_AUTO, "build_waypoint", 0, 0, + WC_BUILD_WAYPOINT, WC_BUILD_TOOLBAR, + WDF_CONSTRUCTION, + _nested_build_waypoint_widgets, lengthof(_nested_build_waypoint_widgets) +); + +static void ShowBuildWaypointPicker(Window *parent) +{ + new BuildRailWaypointWindow(&_build_waypoint_desc, parent); +} + +/** + * Initialize rail building GUI settings + */ +void InitializeRailGui() +{ + _build_depot_direction = DIAGDIR_NW; +} + +/** + * Re-initialize rail-build toolbar after toggling support for electric trains + * @param disable Boolean whether electric trains are disabled (removed from the game) + */ +void ReinitGuiAfterToggleElrail(bool disable) +{ + extern RailType _last_built_railtype; + if (disable && _last_built_railtype == RAILTYPE_ELECTRIC) { + _last_built_railtype = _cur_railtype = RAILTYPE_RAIL; + BuildRailToolbarWindow *w = dynamic_cast(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL)); + if (w != NULL) w->ModifyRailType(_cur_railtype); + } + MarkWholeScreenDirty(); +} + +/** Set the initial (default) railtype to use */ +static void SetDefaultRailGui() +{ + if (_local_company == COMPANY_SPECTATOR || !Company::IsValidID(_local_company)) return; + + extern RailType _last_built_railtype; + RailType rt = (RailType)(_settings_client.gui.default_rail_type + RAILTYPE_END); + if (rt == DEF_RAILTYPE_MOST_USED) { + /* Find the most used rail type */ + RailType count[RAILTYPE_END]; + memset(count, 0, sizeof(count)); + for (TileIndex t = 0; t < MapSize(); t++) { + if (IsTileType(t, MP_RAILWAY) || IsLevelCrossingTile(t) || HasStationTileRail(t) || + (IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL)) { + count[GetRailType(t)]++; + } + } + + rt = RAILTYPE_RAIL; + for (RailType r = RAILTYPE_ELECTRIC; r < RAILTYPE_END; r++) { + if (count[r] >= count[rt]) rt = r; + } + + /* No rail, just get the first available one */ + if (count[rt] == 0) rt = DEF_RAILTYPE_FIRST; + } + switch (rt) { + case DEF_RAILTYPE_FIRST: + rt = RAILTYPE_RAIL; + while (rt < RAILTYPE_END && !HasRailtypeAvail(_local_company, rt)) rt++; + break; + + case DEF_RAILTYPE_LAST: + rt = GetBestRailtype(_local_company); + break; + + default: + break; + } + + _last_built_railtype = _cur_railtype = rt; + BuildRailToolbarWindow *w = dynamic_cast(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL)); + if (w != NULL) w->ModifyRailType(_cur_railtype); +} + +/** + * Updates the current signal variant used in the signal GUI + * to the one adequate to current year. + * @param p needed to be called when a setting changes + * @return success, needed for settings + */ +bool ResetSignalVariant(int32 p) +{ + SignalVariant new_variant = (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC); + + if (new_variant != _cur_signal_variant) { + Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); + if (w != NULL) { + w->SetDirty(); + w->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type); + } + _cur_signal_variant = new_variant; + } + + return true; +} + +/** + * Resets the rail GUI - sets default railtype to build + * and resets the signal GUI + */ +void InitializeRailGUI() +{ + SetDefaultRailGui(); + + _convert_signal_button = false; + _cur_signal_type = _default_signal_type[_settings_client.gui.default_signal_type]; + ResetSignalVariant(); +} + +/** + * Compare railtypes based on their sorting order. + * @param first The railtype to compare to. + * @param second The railtype to compare. + * @return True iff the first should be sorted before the second. + */ +static int CDECL CompareRailTypes(const DropDownListItem * const *first, const DropDownListItem * const *second) +{ + return GetRailTypeInfo((RailType)(*first)->result)->sorting_order - GetRailTypeInfo((RailType)(*second)->result)->sorting_order; +} + +/** + * Create a drop down list for all the rail types of the local company. + * @param for_replacement Whether this list is for the replacement window. + * @return The populated and sorted #DropDownList. + */ +DropDownList *GetRailTypeDropDownList(bool for_replacement) +{ + RailTypes used_railtypes = RAILTYPES_NONE; + + /* Find the used railtypes. */ + Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { + if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; + + used_railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes; + } + + /* Get the date introduced railtypes as well. */ + used_railtypes = AddDateIntroducedRailTypes(used_railtypes, MAX_DAY); + + const Company *c = Company::Get(_local_company); + DropDownList *list = new DropDownList(); + for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + /* If it's not used ever, don't show it to the user. */ + if (!HasBit(used_railtypes, rt)) continue; + + const RailtypeInfo *rti = GetRailTypeInfo(rt); + /* Skip rail type if it has no label */ + if (rti->label == 0) continue; + + StringID str = for_replacement ? rti->strings.replace_text : (rti->max_speed > 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY : STR_JUST_STRING); + DropDownListParamStringItem *item = new DropDownListParamStringItem(str, rt, !HasBit(c->avail_railtypes, rt)); + item->SetParam(0, rti->strings.menu_text); + item->SetParam(1, rti->max_speed); + *list->Append() = item; + } + QSortT(list->Begin(), list->Length(), CompareRailTypes); + return list; +} diff --git a/src/road_gui.cpp.orig b/src/road_gui.cpp.orig new file mode 100644 index 0000000000..04387cbb7d --- /dev/null +++ b/src/road_gui.cpp.orig @@ -0,0 +1,1092 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file road_gui.cpp GUI for building roads. */ + +#include "stdafx.h" +#include "gui.h" +#include "window_gui.h" +#include "station_gui.h" +#include "terraform_gui.h" +#include "viewport_func.h" +#include "command_func.h" +#include "road_cmd.h" +#include "station_func.h" +#include "window_func.h" +#include "vehicle_func.h" +#include "sound_func.h" +#include "company_func.h" +#include "tunnelbridge.h" +#include "tunnelbridge_map.h" +#include "tilehighlight_func.h" +#include "company_base.h" +#include "hotkeys.h" +#include "road_gui.h" + +#include "widgets/road_widget.h" + +#include "table/strings.h" + +static void ShowRVStationPicker(Window *parent, RoadStopType rs); +static void ShowRoadDepotPicker(Window *parent); + +static bool _remove_button_clicked; +static bool _one_way_button_clicked; + +/** + * Define the values of the RoadFlags + * @see CmdBuildLongRoad + */ +enum RoadFlags { + RF_NONE = 0x00, + RF_START_HALFROAD_Y = 0x01, // The start tile in Y-dir should have only a half road + RF_END_HALFROAD_Y = 0x02, // The end tile in Y-dir should have only a half road + RF_DIR_Y = 0x04, // The direction is Y-dir + RF_DIR_X = RF_NONE, // Dummy; Dir X is set when RF_DIR_Y is not set + RF_START_HALFROAD_X = 0x08, // The start tile in X-dir should have only a half road + RF_END_HALFROAD_X = 0x10, // The end tile in X-dir should have only a half road +}; +DECLARE_ENUM_AS_BIT_SET(RoadFlags) + +static RoadFlags _place_road_flag; + +static RoadType _cur_roadtype; + +static DiagDirection _road_depot_orientation; +static DiagDirection _road_station_picker_orientation; + +void CcPlaySound1D(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); +} + +/** + * Callback to start placing a bridge. + * @param tile Start tile of the bridge. + */ +static void PlaceRoad_Bridge(TileIndex tile, Window *w) +{ + if (IsBridgeTile(tile)) { + TileIndex other_tile = GetOtherTunnelBridgeEnd(tile); + Point pt = {0, 0}; + w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile); + } else { + VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE); + } +} + +/** + * Callback executed after a build road tunnel command has been called. + * + * @param result Whether the build succeeded. + * @param start_tile Starting tile of the tunnel. + * @param p1 bit 0-3 railtype or roadtypes + * bit 8-9 transport type + * @param p2 unused + */ +void CcBuildRoadTunnel(const CommandCost &result, TileIndex start_tile, uint32 p1, uint32 p2) +{ + if (result.Succeeded()) { + if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_2, start_tile); + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + + DiagDirection start_direction = ReverseDiagDir(GetTunnelBridgeDirection(start_tile)); + ConnectRoadToStructure(start_tile, start_direction); + + TileIndex end_tile = GetOtherTunnelBridgeEnd(start_tile); + DiagDirection end_direction = ReverseDiagDir(GetTunnelBridgeDirection(end_tile)); + ConnectRoadToStructure(end_tile, end_direction); + } else { + SetRedErrorSquare(_build_tunnel_endtile); + } +} + +/** Structure holding information per roadtype for several functions */ +struct RoadTypeInfo { + StringID err_build_road; ///< Building a normal piece of road + StringID err_remove_road; ///< Removing a normal piece of road + StringID err_depot; ///< Building a depot + StringID err_build_station[2]; ///< Building a bus or truck station + StringID err_remove_station[2]; ///< Removing of a bus or truck station + + StringID picker_title[2]; ///< Title for the station picker for bus or truck stations + StringID picker_tooltip[2]; ///< Tooltip for the station picker for bus or truck stations + + SpriteID cursor_nesw; ///< Cursor for building NE and SW bits + SpriteID cursor_nwse; ///< Cursor for building NW and SE bits + SpriteID cursor_autoroad; ///< Cursor for building autoroad +}; + +/** What errors/cursors must be shown for several types of roads */ +static const RoadTypeInfo _road_type_infos[] = { + { + STR_ERROR_CAN_T_BUILD_ROAD_HERE, + STR_ERROR_CAN_T_REMOVE_ROAD_FROM, + STR_ERROR_CAN_T_BUILD_ROAD_DEPOT, + { STR_ERROR_CAN_T_BUILD_BUS_STATION, STR_ERROR_CAN_T_BUILD_TRUCK_STATION }, + { STR_ERROR_CAN_T_REMOVE_BUS_STATION, STR_ERROR_CAN_T_REMOVE_TRUCK_STATION }, + { STR_STATION_BUILD_BUS_ORIENTATION, STR_STATION_BUILD_TRUCK_ORIENTATION }, + { STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP, STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP }, + + SPR_CURSOR_ROAD_NESW, + SPR_CURSOR_ROAD_NWSE, + SPR_CURSOR_AUTOROAD, + }, + { + STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE, + STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM, + STR_ERROR_CAN_T_BUILD_TRAM_DEPOT, + { STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION }, + { STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION }, + { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION }, + { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP }, + + SPR_CURSOR_TRAMWAY_NESW, + SPR_CURSOR_TRAMWAY_NWSE, + SPR_CURSOR_AUTOTRAM, + }, +}; + +/** + * If required, connects a new structure to an existing road or tram by building the missing roadbit. + * @param tile Tile containing the structure to connect. + * @param direction Direction to check. + */ +void ConnectRoadToStructure(TileIndex tile, DiagDirection direction) +{ + tile += TileOffsByDiagDir(direction); + /* if there is a roadpiece just outside of the station entrance, build a connecting route */ + if (IsNormalRoadTile(tile)) { + if (GetRoadBits(tile, _cur_roadtype) != ROAD_NONE) { + DoCommandP(tile, _cur_roadtype << 4 | DiagDirToRoadBits(ReverseDiagDir(direction)), 0, CMD_BUILD_ROAD); + } + } +} + +void CcRoadDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + + DiagDirection dir = (DiagDirection)GB(p1, 0, 2); + if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + ConnectRoadToStructure(tile, dir); +} + +/** + * Command callback for building road stops. + * @param result Result of the build road stop command. + * @param tile Start tile. + * @param p1 bit 0..7: Width of the road stop. + * bit 8..15: Length of the road stop. + * @param p2 bit 0: 0 For bus stops, 1 for truck stops. + * bit 1: 0 For normal stops, 1 for drive-through. + * bit 2..3: The roadtypes. + * bit 5: Allow stations directly adjacent to other stations. + * bit 6..7: Entrance direction (#DiagDirection). + * bit 16..31: Station ID to join (NEW_STATION if build new one). + * @see CmdBuildRoadStop + */ +void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + + DiagDirection dir = (DiagDirection)GB(p2, 6, 2); + if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + TileArea roadstop_area(tile, GB(p1, 0, 8), GB(p1, 8, 8)); + TILE_AREA_LOOP(cur_tile, roadstop_area) { + ConnectRoadToStructure(cur_tile, dir); + /* For a drive-through road stop build connecting road for other entrance. */ + if (HasBit(p2, 1)) ConnectRoadToStructure(cur_tile, ReverseDiagDir(dir)); + } +} + +/** + * Place a new road stop. + * @param start_tile First tile of the area. + * @param end_tile Last tile of the area. + * @param p2 bit 0: 0 For bus stops, 1 for truck stops. + * bit 2..3: The roadtypes. + * bit 5: Allow stations directly adjacent to other stations. + * @param cmd Command to use. + * @see CcRoadStop() + */ +static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, uint32 cmd) +{ + uint8 ddir = _road_station_picker_orientation; + SB(p2, 16, 16, INVALID_STATION); // no station to join + + if (ddir >= DIAGDIR_END) { + SetBit(p2, 1); // It's a drive-through stop. + ddir -= DIAGDIR_END; // Adjust picker result to actual direction. + } + p2 |= ddir << 6; // Set the DiagDirecion into p2 bits 6 and 7. + + TileArea ta(start_tile, end_tile); + CommandContainer cmdcont = { ta.tile, ta.w | ta.h << 8, p2, cmd, CcRoadStop, "" }; + ShowSelectStationIfNeeded(cmdcont, ta); +} + +/** + * Callback for placing a bus station. + * @param tile Position to place the station. + */ +static void PlaceRoad_BusStation(TileIndex tile) +{ + if (_remove_button_clicked) { + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_BUSSTOP); + } else { + if (_road_station_picker_orientation < DIAGDIR_END) { // Not a drive-through stop. + VpStartPlaceSizing(tile, (DiagDirToAxis(_road_station_picker_orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_BUSSTOP); + } else { + VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_BUSSTOP); + } + VpSetPlaceSizingLimit(_settings_game.station.station_spread); + } +} + +/** + * Callback for placing a truck station. + * @param tile Position to place the station. + */ +static void PlaceRoad_TruckStation(TileIndex tile) +{ + if (_remove_button_clicked) { + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_TRUCKSTOP); + } else { + if (_road_station_picker_orientation < DIAGDIR_END) { // Not a drive-through stop. + VpStartPlaceSizing(tile, (DiagDirToAxis(_road_station_picker_orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_TRUCKSTOP); + } else { + VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_TRUCKSTOP); + } + VpSetPlaceSizingLimit(_settings_game.station.station_spread); + } +} + +typedef void OnButtonClick(Window *w); + +/** + * Toggles state of the Remove button of Build road toolbar + * @param w window the button belongs to + */ +static void ToggleRoadButton_Remove(Window *w) +{ + w->ToggleWidgetLoweredState(WID_ROT_REMOVE); + w->SetWidgetDirty(WID_ROT_REMOVE); + _remove_button_clicked = w->IsWidgetLowered(WID_ROT_REMOVE); + SetSelectionRed(_remove_button_clicked); +} + +/** + * Updates the Remove button because of Ctrl state change + * @param w window the button belongs to + * @return true iff the remove button was changed + */ +static bool RoadToolbar_CtrlChanged(Window *w) +{ + if (w->IsWidgetDisabled(WID_ROT_REMOVE)) return false; + + /* allow ctrl to switch remove mode only for these widgets */ + for (uint i = WID_ROT_ROAD_X; i <= WID_ROT_AUTOROAD; i++) { + if (w->IsWidgetLowered(i)) { + ToggleRoadButton_Remove(w); + return true; + } + } + + return false; +} + +/** Road toolbar window handler. */ +struct BuildRoadToolbarWindow : Window { + int last_started_action; ///< Last started user action. + + BuildRoadToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->InitNested(window_number); + this->SetWidgetsDisabledState(true, + WID_ROT_REMOVE, + WID_ROT_ONE_WAY, + WIDGET_LIST_END); + + this->OnInvalidateData(); + this->last_started_action = WIDGET_LIST_END; + + if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); + } + + ~BuildRoadToolbarWindow() + { + if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_ROAD), + WID_ROT_DEPOT, + WID_ROT_BUS_STATION, + WID_ROT_TRUCK_STATION, + WIDGET_LIST_END); + } + + /** + * Update the remove button lowered state of the road toolbar + * + * @param clicked_widget The widget which the client clicked just now + */ + void UpdateOptionWidgetStatus(RoadToolbarWidgets clicked_widget) + { + /* The remove and the one way button state is driven + * by the other buttons so they don't act on themselves. + * Both are only valid if they are able to apply as options. */ + switch (clicked_widget) { + case WID_ROT_REMOVE: + this->RaiseWidget(WID_ROT_ONE_WAY); + this->SetWidgetDirty(WID_ROT_ONE_WAY); + break; + + case WID_ROT_ONE_WAY: + this->RaiseWidget(WID_ROT_REMOVE); + this->SetWidgetDirty(WID_ROT_REMOVE); + break; + + case WID_ROT_BUS_STATION: + case WID_ROT_TRUCK_STATION: + this->DisableWidget(WID_ROT_ONE_WAY); + this->SetWidgetDisabledState(WID_ROT_REMOVE, !this->IsWidgetLowered(clicked_widget)); + break; + + case WID_ROT_ROAD_X: + case WID_ROT_ROAD_Y: + case WID_ROT_AUTOROAD: + this->SetWidgetsDisabledState(!this->IsWidgetLowered(clicked_widget), + WID_ROT_REMOVE, + WID_ROT_ONE_WAY, + WIDGET_LIST_END); + break; + + default: + /* When any other buttons than road/station, raise and + * disable the removal button */ + this->SetWidgetsDisabledState(true, + WID_ROT_REMOVE, + WID_ROT_ONE_WAY, + WIDGET_LIST_END); + this->SetWidgetsLoweredState(false, + WID_ROT_REMOVE, + WID_ROT_ONE_WAY, + WIDGET_LIST_END); + break; + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + _remove_button_clicked = false; + _one_way_button_clicked = false; + switch (widget) { + case WID_ROT_ROAD_X: + HandlePlacePushButton(this, WID_ROT_ROAD_X, _road_type_infos[_cur_roadtype].cursor_nwse, HT_RECT); + this->last_started_action = widget; + break; + + case WID_ROT_ROAD_Y: + HandlePlacePushButton(this, WID_ROT_ROAD_Y, _road_type_infos[_cur_roadtype].cursor_nesw, HT_RECT); + this->last_started_action = widget; + break; + + case WID_ROT_AUTOROAD: + HandlePlacePushButton(this, WID_ROT_AUTOROAD, _road_type_infos[_cur_roadtype].cursor_autoroad, HT_RECT); + this->last_started_action = widget; + break; + + case WID_ROT_DEMOLISH: + HandlePlacePushButton(this, WID_ROT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); + this->last_started_action = widget; + break; + + case WID_ROT_DEPOT: + if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; + if (HandlePlacePushButton(this, WID_ROT_DEPOT, SPR_CURSOR_ROAD_DEPOT, HT_RECT)) { + ShowRoadDepotPicker(this); + this->last_started_action = widget; + } + break; + + case WID_ROT_BUS_STATION: + if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; + if (HandlePlacePushButton(this, WID_ROT_BUS_STATION, SPR_CURSOR_BUS_STATION, HT_RECT)) { + ShowRVStationPicker(this, ROADSTOP_BUS); + this->last_started_action = widget; + } + break; + + case WID_ROT_TRUCK_STATION: + if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; + if (HandlePlacePushButton(this, WID_ROT_TRUCK_STATION, SPR_CURSOR_TRUCK_STATION, HT_RECT)) { + ShowRVStationPicker(this, ROADSTOP_TRUCK); + this->last_started_action = widget; + } + break; + + case WID_ROT_ONE_WAY: + if (this->IsWidgetDisabled(WID_ROT_ONE_WAY)) return; + this->SetDirty(); + this->ToggleWidgetLoweredState(WID_ROT_ONE_WAY); + SetSelectionRed(false); + break; + + case WID_ROT_BUILD_BRIDGE: + HandlePlacePushButton(this, WID_ROT_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT); + this->last_started_action = widget; + break; + + case WID_ROT_BUILD_TUNNEL: + HandlePlacePushButton(this, WID_ROT_BUILD_TUNNEL, SPR_CURSOR_ROAD_TUNNEL, HT_SPECIAL); + this->last_started_action = widget; + break; + + case WID_ROT_REMOVE: + if (this->IsWidgetDisabled(WID_ROT_REMOVE)) return; + + DeleteWindowById(WC_SELECT_STATION, 0); + ToggleRoadButton_Remove(this); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + break; + + default: NOT_REACHED(); + } + this->UpdateOptionWidgetStatus((RoadToolbarWidgets)widget); + if (_ctrl_pressed) RoadToolbar_CtrlChanged(this); + } + + virtual EventState OnHotkey(int hotkey) + { + MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection + return Window::OnHotkey(hotkey); + } + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + _remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE); + _one_way_button_clicked = this->IsWidgetLowered(WID_ROT_ONE_WAY); + switch (this->last_started_action) { + case WID_ROT_ROAD_X: + _place_road_flag = RF_DIR_X; + if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X; + VpStartPlaceSizing(tile, VPM_FIX_Y, DDSP_PLACE_ROAD_X_DIR); + break; + + case WID_ROT_ROAD_Y: + _place_road_flag = RF_DIR_Y; + if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y; + VpStartPlaceSizing(tile, VPM_FIX_X, DDSP_PLACE_ROAD_Y_DIR); + break; + + case WID_ROT_AUTOROAD: + _place_road_flag = RF_NONE; + if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X; + if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y; + VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_AUTOROAD); + break; + + case WID_ROT_DEMOLISH: + PlaceProc_DemolishArea(tile); + break; + + case WID_ROT_DEPOT: + DoCommandP(tile, _cur_roadtype << 2 | _road_depot_orientation, 0, + CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot); + break; + + case WID_ROT_BUS_STATION: + PlaceRoad_BusStation(tile); + break; + + case WID_ROT_TRUCK_STATION: + PlaceRoad_TruckStation(tile); + break; + + case WID_ROT_BUILD_BRIDGE: + PlaceRoad_Bridge(tile, this); + break; + + case WID_ROT_BUILD_TUNNEL: + DoCommandP(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, + CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRoadTunnel); + break; + + default: NOT_REACHED(); + } + } + + virtual void OnPlaceObjectAbort() + { + this->RaiseButtons(); + this->SetWidgetsDisabledState(true, + WID_ROT_REMOVE, + WID_ROT_ONE_WAY, + WIDGET_LIST_END); + this->SetWidgetDirty(WID_ROT_REMOVE); + this->SetWidgetDirty(WID_ROT_ONE_WAY); + + DeleteWindowById(WC_BUS_STATION, TRANSPORT_ROAD); + DeleteWindowById(WC_TRUCK_STATION, TRANSPORT_ROAD); + DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_ROAD); + DeleteWindowById(WC_SELECT_STATION, 0); + DeleteWindowByClass(WC_BUILD_BRIDGE); + } + + virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + { + /* Here we update the end tile flags + * of the road placement actions. + * At first we reset the end halfroad + * bits and if needed we set them again. */ + switch (select_proc) { + case DDSP_PLACE_ROAD_X_DIR: + _place_road_flag &= ~RF_END_HALFROAD_X; + if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X; + break; + + case DDSP_PLACE_ROAD_Y_DIR: + _place_road_flag &= ~RF_END_HALFROAD_Y; + if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y; + break; + + case DDSP_PLACE_AUTOROAD: + _place_road_flag &= ~(RF_END_HALFROAD_Y | RF_END_HALFROAD_X); + if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y; + if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X; + + /* For autoroad we need to update the + * direction of the road */ + if (_thd.size.x > _thd.size.y || (_thd.size.x == _thd.size.y && + ( (_tile_fract_coords.x < _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) < 16) || + (_tile_fract_coords.x > _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) > 16) ))) { + /* Set dir = X */ + _place_road_flag &= ~RF_DIR_Y; + } else { + /* Set dir = Y */ + _place_road_flag |= RF_DIR_Y; + } + + break; + + default: + break; + } + + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + } + + virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + { + if (pt.x != -1) { + switch (select_proc) { + default: NOT_REACHED(); + case DDSP_BUILD_BRIDGE: + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype)); + break; + + case DDSP_DEMOLISH_AREA: + GUIPlaceProcDragXY(select_proc, start_tile, end_tile); + break; + + case DDSP_PLACE_ROAD_X_DIR: + case DDSP_PLACE_ROAD_Y_DIR: + case DDSP_PLACE_AUTOROAD: + /* Flag description: + * Use the first three bits (0x07) if dir == Y + * else use the last 2 bits (X dir has + * not the 3rd bit set) */ + _place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3)); + + DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), + _remove_button_clicked ? + CMD_REMOVE_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) : + CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound1D); + break; + + case DDSP_BUILD_BUSSTOP: + PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_BUS])); + break; + + case DDSP_BUILD_TRUCKSTOP: + PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_TRUCK, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_TRUCK])); + break; + + case DDSP_REMOVE_BUSSTOP: { + TileArea ta(start_tile, end_tile); + DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound1D); + break; + } + + case DDSP_REMOVE_TRUCKSTOP: { + TileArea ta(start_tile, end_tile); + DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound1D); + break; + } + } + } + } + + virtual void OnPlacePresize(Point pt, TileIndex tile) + { + DoCommand(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); + VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); + } + + virtual EventState OnCTRLStateChange() + { + if (RoadToolbar_CtrlChanged(this)) return ES_HANDLED; + return ES_NOT_HANDLED; + } + + static HotkeyList hotkeys; +}; + +/** + * Handler for global hotkeys of the BuildRoadToolbarWindow. + * @param hotkey Hotkey + * @return ES_HANDLED if hotkey was accepted. + */ +static EventState RoadToolbarGlobalHotkeys(int hotkey) +{ + Window *w = NULL; + switch (_game_mode) { + case GM_NORMAL: { + extern RoadType _last_built_roadtype; + w = ShowBuildRoadToolbar(_last_built_roadtype); + break; + } + + case GM_EDITOR: + w = ShowBuildRoadScenToolbar(); + break; + + default: + break; + } + + if (w == NULL) return ES_NOT_HANDLED; + return w->OnHotkey(hotkey); +} + +static Hotkey roadtoolbar_hotkeys[] = { + Hotkey('1', "build_x", WID_ROT_ROAD_X), + Hotkey('2', "build_y", WID_ROT_ROAD_Y), + Hotkey('3', "autoroad", WID_ROT_AUTOROAD), + Hotkey('4', "demolish", WID_ROT_DEMOLISH), + Hotkey('5', "depot", WID_ROT_DEPOT), + Hotkey('6', "bus_station", WID_ROT_BUS_STATION), + Hotkey('7', "truck_station", WID_ROT_TRUCK_STATION), + Hotkey('8', "oneway", WID_ROT_ONE_WAY), + Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE), + Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL), + Hotkey('R', "remove", WID_ROT_REMOVE), + HOTKEY_LIST_END +}; +HotkeyList BuildRoadToolbarWindow::hotkeys("roadtoolbar", roadtoolbar_hotkeys, RoadToolbarGlobalHotkeys); + + +static const NWidgetPart _nested_build_road_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), + SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD), + EndContainer(), +}; + +static WindowDesc _build_road_desc( + WDP_ALIGN_TOOLBAR, "toolbar_road", 0, 0, + WC_BUILD_TOOLBAR, WC_NONE, + WDF_CONSTRUCTION, + _nested_build_road_widgets, lengthof(_nested_build_road_widgets), + &BuildRoadToolbarWindow::hotkeys +); + +static const NWidgetPart _nested_build_tramway_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOTRAM, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), + NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), SetMinimalSize(0, 0), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), + SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS), + EndContainer(), +}; + +static WindowDesc _build_tramway_desc( + WDP_ALIGN_TOOLBAR, "toolbar_tramway", 0, 0, + WC_BUILD_TOOLBAR, WC_NONE, + WDF_CONSTRUCTION, + _nested_build_tramway_widgets, lengthof(_nested_build_tramway_widgets), + &BuildRoadToolbarWindow::hotkeys +); + +/** + * Open the build road toolbar window + * + * If the terraform toolbar is linked to the toolbar, that window is also opened. + * + * @return newly opened road toolbar, or NULL if the toolbar could not be opened. + */ +Window *ShowBuildRoadToolbar(RoadType roadtype) +{ + if (!Company::IsValidID(_local_company)) return NULL; + _cur_roadtype = roadtype; + + DeleteWindowByClass(WC_BUILD_TOOLBAR); + return AllocateWindowDescFront(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD); +} + +static const NWidgetPart _nested_build_road_scen_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), + SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD), + EndContainer(), +}; + +static WindowDesc _build_road_scen_desc( + WDP_AUTO, "toolbar_road_scen", 0, 0, + WC_SCEN_BUILD_TOOLBAR, WC_NONE, + WDF_CONSTRUCTION, + _nested_build_road_scen_widgets, lengthof(_nested_build_road_scen_widgets), + &BuildRoadToolbarWindow::hotkeys +); + +/** + * Show the road building toolbar in the scenario editor. + * @return The just opened toolbar. + */ +Window *ShowBuildRoadScenToolbar() +{ + _cur_roadtype = ROADTYPE_ROAD; + return AllocateWindowDescFront(&_build_road_scen_desc, TRANSPORT_ROAD); +} + +struct BuildRoadDepotWindow : public PickerWindowBase { + BuildRoadDepotWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) + { + this->CreateNestedTree(); + + this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); + if ( _cur_roadtype == ROADTYPE_TRAM) { + this->GetWidget(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION; + for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_NW; i++) this->GetWidget(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP; + } + + this->FinishInitNested(TRANSPORT_ROAD); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (!IsInsideMM(widget, WID_BROD_DEPOT_NE, WID_BROD_DEPOT_NW + 1)) return; + + DrawRoadDepotSprite(r.left - 1, r.top, (DiagDirection)(widget - WID_BROD_DEPOT_NE + DIAGDIR_NE), _cur_roadtype); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_BROD_DEPOT_NW: + case WID_BROD_DEPOT_NE: + case WID_BROD_DEPOT_SW: + case WID_BROD_DEPOT_SE: + this->RaiseWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); + _road_depot_orientation = (DiagDirection)(widget - WID_BROD_DEPOT_NE); + this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + break; + + default: + break; + } + } +}; + +static const NWidgetPart _nested_build_road_depot_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROD_CAPTION), SetDataTip(STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), + NWidget(NWID_SPACER), SetMinimalSize(0, 3), + NWidget(NWID_HORIZONTAL_LTR), + NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), + NWidget(NWID_VERTICAL), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), + NWidget(NWID_VERTICAL), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 3), + EndContainer(), +}; + +static WindowDesc _build_road_depot_desc( + WDP_AUTO, NULL, 0, 0, + WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, + WDF_CONSTRUCTION, + _nested_build_road_depot_widgets, lengthof(_nested_build_road_depot_widgets) +); + +static void ShowRoadDepotPicker(Window *parent) +{ + new BuildRoadDepotWindow(&_build_road_depot_desc, parent); +} + +struct BuildRoadStationWindow : public PickerWindowBase { + BuildRoadStationWindow(WindowDesc *desc, Window *parent, RoadStopType rs) : PickerWindowBase(desc, parent) + { + this->CreateNestedTree(); + + /* Trams don't have non-drivethrough stations */ + if (_cur_roadtype == ROADTYPE_TRAM && _road_station_picker_orientation < DIAGDIR_END) { + _road_station_picker_orientation = DIAGDIR_END; + } + this->SetWidgetsDisabledState(_cur_roadtype == ROADTYPE_TRAM, + WID_BROS_STATION_NE, + WID_BROS_STATION_SE, + WID_BROS_STATION_SW, + WID_BROS_STATION_NW, + WIDGET_LIST_END); + + this->GetWidget(WID_BROS_CAPTION)->widget_data = _road_type_infos[_cur_roadtype].picker_title[rs]; + for (uint i = WID_BROS_STATION_NE; i < WID_BROS_LT_OFF; i++) this->GetWidget(i)->tool_tip = _road_type_infos[_cur_roadtype].picker_tooltip[rs]; + + this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); + this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF); + + this->FinishInitNested(TRANSPORT_ROAD); + + this->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION; + } + + virtual ~BuildRoadStationWindow() + { + DeleteWindowById(WC_SELECT_STATION, 0); + } + + virtual void OnPaint() + { + this->DrawWidgets(); + + int rad = _settings_game.station.modified_catchment ? ((this->window_class == WC_BUS_STATION) ? CA_BUS : CA_TRUCK) : CA_UNMODIFIED; + if (_settings_client.gui.station_show_coverage) { + SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); + } else { + SetTileSelectSize(1, 1); + } + + /* 'Accepts' and 'Supplies' texts. */ + StationCoverageType sct = (this->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY; + int top = this->GetWidget(WID_BROS_LT_ON)->pos_y + this->GetWidget(WID_BROS_LT_ON)->current_y + WD_PAR_VSEP_NORMAL; + NWidgetBase *back_nwi = this->GetWidget(WID_BROS_BACKGROUND); + int right = back_nwi->pos_x + back_nwi->current_x; + int bottom = back_nwi->pos_y + back_nwi->current_y; + top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, false) + WD_PAR_VSEP_NORMAL; + top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, true) + WD_PAR_VSEP_NORMAL; + /* Resize background if the window is too small. + * Never make the window smaller to avoid oscillating if the size change affects the acceptance. + * (This is the case, if making the window bigger moves the mouse into the window.) */ + if (top > bottom) { + ResizeWindow(this, 0, top - bottom); + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return; + + StationType st = (this->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK; + StationPickerDrawSprite(r.left + TILE_PIXELS, r.bottom - TILE_PIXELS, st, INVALID_RAILTYPE, widget < WID_BROS_STATION_X ? ROADTYPE_ROAD : _cur_roadtype, widget - WID_BROS_STATION_NE); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_BROS_STATION_NE: + case WID_BROS_STATION_SE: + case WID_BROS_STATION_SW: + case WID_BROS_STATION_NW: + case WID_BROS_STATION_X: + case WID_BROS_STATION_Y: + this->RaiseWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); + _road_station_picker_orientation = (DiagDirection)(widget - WID_BROS_STATION_NE); + this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + DeleteWindowById(WC_SELECT_STATION, 0); + break; + + case WID_BROS_LT_OFF: + case WID_BROS_LT_ON: + this->RaiseWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF); + _settings_client.gui.station_show_coverage = (widget != WID_BROS_LT_OFF); + this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + break; + + default: + break; + } + } + + virtual void OnTick() + { + CheckRedrawStationCoverage(this); + } +}; + +/** Widget definition of the build road station window */ +static const NWidgetPart _nested_rv_station_picker_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROS_CAPTION), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_BACKGROUND), + NWidget(NWID_SPACER), SetMinimalSize(0, 3), + NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 1), + NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_INFO), SetMinimalSize(140, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_OFF), SetMinimalSize(60, 12), + SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_ON), SetMinimalSize(60, 12), + SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1), + EndContainer(), +}; + +static WindowDesc _rv_station_picker_desc( + WDP_AUTO, NULL, 0, 0, + WC_BUS_STATION, WC_BUILD_TOOLBAR, + WDF_CONSTRUCTION, + _nested_rv_station_picker_widgets, lengthof(_nested_rv_station_picker_widgets) +); + +static void ShowRVStationPicker(Window *parent, RoadStopType rs) +{ + new BuildRoadStationWindow(&_rv_station_picker_desc, parent, rs); +} + +void InitializeRoadGui() +{ + _road_depot_orientation = DIAGDIR_NW; + _road_station_picker_orientation = DIAGDIR_NW; +} diff --git a/src/script/api/game/game_window.hpp.sq.orig b/src/script/api/game/game_window.hpp.sq.orig new file mode 100644 index 0000000000..280bf1e532 --- /dev/null +++ b/src/script/api/game/game_window.hpp.sq.orig @@ -0,0 +1,1328 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ + +#include "../script_window.hpp" +#include "../template/template_window.hpp.sq" + + +template <> const char *GetClassName() { return "GSWindow"; } + +void SQGSWindow_Register(Squirrel *engine) +{ + DefSQClass SQGSWindow("GSWindow"); + SQGSWindow.PreRegister(engine); + SQGSWindow.AddConstructor(engine, "x"); + + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_AI, "WN_GAME_OPTIONS_AI"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_ABOUT, "WN_GAME_OPTIONS_ABOUT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_NEWGRF_STATE, "WN_GAME_OPTIONS_NEWGRF_STATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_GAME_OPTIONS, "WN_GAME_OPTIONS_GAME_OPTIONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_GAME_SETTINGS, "WN_GAME_OPTIONS_GAME_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_QUERY_STRING, "WN_QUERY_STRING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_QUERY_STRING_SIGN, "WN_QUERY_STRING_SIGN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_CONFIRM_POPUP_QUERY, "WN_CONFIRM_POPUP_QUERY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_CONFIRM_POPUP_QUERY_BOOTSTRAP, "WN_CONFIRM_POPUP_QUERY_BOOTSTRAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_GAME, "WN_NETWORK_WINDOW_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_LOBBY, "WN_NETWORK_WINDOW_LOBBY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_CONTENT_LIST, "WN_NETWORK_WINDOW_CONTENT_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_START, "WN_NETWORK_WINDOW_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_STATUS_WINDOW_JOIN, "WN_NETWORK_STATUS_WINDOW_JOIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD, "WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NONE, "WC_NONE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_WINDOW, "WC_MAIN_WINDOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_TOOLBAR, "WC_MAIN_TOOLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATUS_BAR, "WC_STATUS_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TOOLBAR, "WC_BUILD_TOOLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_BUILD_TOOLBAR, "WC_SCEN_BUILD_TOOLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TREES, "WC_BUILD_TREES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRANSPARENCY_TOOLBAR, "WC_TRANSPARENCY_TOOLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_SIGNAL, "WC_BUILD_SIGNAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SMALLMAP, "WC_SMALLMAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ERRMSG, "WC_ERRMSG"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOOLTIPS, "WC_TOOLTIPS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_QUERY_STRING, "WC_QUERY_STRING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CONFIRM_POPUP_QUERY, "WC_CONFIRM_POPUP_QUERY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GOAL_QUESTION, "WC_GOAL_QUESTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SAVELOAD, "WC_SAVELOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_LAND_INFO, "WC_LAND_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_DROPDOWN_MENU, "WC_DROPDOWN_MENU"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_OSK, "WC_OSK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SET_DATE, "WC_SET_DATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_SETTINGS, "WC_AI_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GRF_PARAMETERS, "WC_GRF_PARAMETERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TEXTFILE, "WC_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_AUTHORITY, "WC_TOWN_AUTHORITY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_DETAILS, "WC_VEHICLE_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_REFIT, "WC_VEHICLE_REFIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_ORDERS, "WC_VEHICLE_ORDERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_REPLACE_VEHICLE, "WC_REPLACE_VEHICLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_TIMETABLE, "WC_VEHICLE_TIMETABLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_COLOUR, "WC_COMPANY_COLOUR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_MANAGER_FACE, "WC_COMPANY_MANAGER_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_STATION, "WC_SELECT_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NEWS_WINDOW, "WC_NEWS_WINDOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_DIRECTORY, "WC_TOWN_DIRECTORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SUBSIDIES_LIST, "WC_SUBSIDIES_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_DIRECTORY, "WC_INDUSTRY_DIRECTORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MESSAGE_HISTORY, "WC_MESSAGE_HISTORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SIGN_LIST, "WC_SIGN_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_LIST, "WC_AI_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GOALS_LIST, "WC_GOALS_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STORY_BOOK, "WC_STORY_BOOK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATION_LIST, "WC_STATION_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRAINS_LIST, "WC_TRAINS_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ROADVEH_LIST, "WC_ROADVEH_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SHIPS_LIST, "WC_SHIPS_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AIRCRAFT_LIST, "WC_AIRCRAFT_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_VIEW, "WC_TOWN_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_VIEW, "WC_VEHICLE_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATION_VIEW, "WC_STATION_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_DEPOT, "WC_VEHICLE_DEPOT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_WAYPOINT_VIEW, "WC_WAYPOINT_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_VIEW, "WC_INDUSTRY_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY, "WC_COMPANY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_OBJECT, "WC_BUILD_OBJECT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_VEHICLE, "WC_BUILD_VEHICLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_BRIDGE, "WC_BUILD_BRIDGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_STATION, "WC_BUILD_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUS_STATION, "WC_BUS_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRUCK_STATION, "WC_TRUCK_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_DEPOT, "WC_BUILD_DEPOT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_WAYPOINT, "WC_BUILD_WAYPOINT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_FOUND_TOWN, "WC_FOUND_TOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_INDUSTRY, "WC_BUILD_INDUSTRY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_GAME, "WC_SELECT_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_LAND_GEN, "WC_SCEN_LAND_GEN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GENERATE_LANDSCAPE, "WC_GENERATE_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MODAL_PROGRESS, "WC_MODAL_PROGRESS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NETWORK_WINDOW, "WC_NETWORK_WINDOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CLIENT_LIST, "WC_CLIENT_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CLIENT_LIST_POPUP, "WC_CLIENT_LIST_POPUP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NETWORK_STATUS_WINDOW, "WC_NETWORK_STATUS_WINDOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SEND_NETWORK_MSG, "WC_SEND_NETWORK_MSG"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_PASSWORD_WINDOW, "WC_COMPANY_PASSWORD_WINDOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_CARGOES, "WC_INDUSTRY_CARGOES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GRAPH_LEGEND, "WC_GRAPH_LEGEND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_FINANCES, "WC_FINANCES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INCOME_GRAPH, "WC_INCOME_GRAPH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_OPERATING_PROFIT, "WC_OPERATING_PROFIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_DELIVERED_CARGO, "WC_DELIVERED_CARGO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PERFORMANCE_HISTORY, "WC_PERFORMANCE_HISTORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_VALUE, "WC_COMPANY_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_LEAGUE, "WC_COMPANY_LEAGUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PAYMENT_RATES, "WC_PAYMENT_RATES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PERFORMANCE_DETAIL, "WC_PERFORMANCE_DETAIL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_INFRASTRUCTURE, "WC_COMPANY_INFRASTRUCTURE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUY_COMPANY, "WC_BUY_COMPANY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ENGINE_PREVIEW, "WC_ENGINE_PREVIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MUSIC_WINDOW, "WC_MUSIC_WINDOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MUSIC_TRACK_SELECTION, "WC_MUSIC_TRACK_SELECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GAME_OPTIONS, "WC_GAME_OPTIONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CUSTOM_CURRENCY, "WC_CUSTOM_CURRENCY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CHEATS, "WC_CHEATS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_EXTRA_VIEW_PORT, "WC_EXTRA_VIEW_PORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CONSOLE, "WC_CONSOLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BOOTSTRAP, "WC_BOOTSTRAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_HIGHSCORE, "WC_HIGHSCORE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ENDSCREEN, "WC_ENDSCREEN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_DEBUG, "WC_AI_DEBUG"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NEWGRF_INSPECT, "WC_NEWGRF_INSPECT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SPRITE_ALIGNER, "WC_SPRITE_ALIGNER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_LINKGRAPH_LEGEND, "WC_LINKGRAPH_LEGEND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INVALID, "WC_INVALID"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BLUE, "TC_BLUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_SILVER, "TC_SILVER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GOLD, "TC_GOLD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_RED, "TC_RED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_PURPLE, "TC_PURPLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_LIGHT_BROWN, "TC_LIGHT_BROWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_ORANGE, "TC_ORANGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GREEN, "TC_GREEN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_YELLOW, "TC_YELLOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_DARK_GREEN, "TC_DARK_GREEN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_CREAM, "TC_CREAM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BROWN, "TC_BROWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_WHITE, "TC_WHITE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_LIGHT_BLUE, "TC_LIGHT_BLUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GREY, "TC_GREY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_DARK_BLUE, "TC_DARK_BLUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BLACK, "TC_BLACK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_INVALID, "TC_INVALID"); + SQGSWindow.DefSQConst(engine, ScriptWindow::NUMBER_ALL, "NUMBER_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WIDGET_ALL, "WIDGET_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_CAPTION, "WID_AIL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_LIST, "WID_AIL_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_SCROLLBAR, "WID_AIL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_INFO_BG, "WID_AIL_INFO_BG"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_ACCEPT, "WID_AIL_ACCEPT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_CANCEL, "WID_AIL_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_CAPTION, "WID_AIS_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_BACKGROUND, "WID_AIS_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_SCROLLBAR, "WID_AIS_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_ACCEPT, "WID_AIS_ACCEPT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_RESET, "WID_AIS_RESET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_BACKGROUND, "WID_AIC_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_DECREASE, "WID_AIC_DECREASE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_INCREASE, "WID_AIC_INCREASE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_NUMBER, "WID_AIC_NUMBER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_GAMELIST, "WID_AIC_GAMELIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_LIST, "WID_AIC_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_SCROLLBAR, "WID_AIC_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_MOVE_UP, "WID_AIC_MOVE_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_MOVE_DOWN, "WID_AIC_MOVE_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CHANGE, "WID_AIC_CHANGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CONFIGURE, "WID_AIC_CONFIGURE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CLOSE, "WID_AIC_CLOSE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_TEXTFILE, "WID_AIC_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CONTENT_DOWNLOAD, "WID_AIC_CONTENT_DOWNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_VIEW, "WID_AID_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_NAME_TEXT, "WID_AID_NAME_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SETTINGS, "WID_AID_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SCRIPT_GAME, "WID_AID_SCRIPT_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_RELOAD_TOGGLE, "WID_AID_RELOAD_TOGGLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_LOG_PANEL, "WID_AID_LOG_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SCROLLBAR, "WID_AID_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_COMPANY_BUTTON_START, "WID_AID_COMPANY_BUTTON_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_COMPANY_BUTTON_END, "WID_AID_COMPANY_BUTTON_END"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STRING_WIDGETS, "WID_AID_BREAK_STRING_WIDGETS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STR_ON_OFF_BTN, "WID_AID_BREAK_STR_ON_OFF_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STR_EDIT_BOX, "WID_AID_BREAK_STR_EDIT_BOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_MATCH_CASE_BTN, "WID_AID_MATCH_CASE_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_CONTINUE_BTN, "WID_AID_CONTINUE_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AT_AIRPORT, "WID_AT_AIRPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AT_DEMOLISH, "WID_AT_DEMOLISH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_CLASS_DROPDOWN, "WID_AP_CLASS_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_AIRPORT_LIST, "WID_AP_AIRPORT_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_SCROLLBAR, "WID_AP_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_NUM, "WID_AP_LAYOUT_NUM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_DECREASE, "WID_AP_LAYOUT_DECREASE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_INCREASE, "WID_AP_LAYOUT_INCREASE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_AIRPORT_SPRITE, "WID_AP_AIRPORT_SPRITE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_EXTRA_TEXT, "WID_AP_EXTRA_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BOTTOMPANEL, "WID_AP_BOTTOMPANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_COVERAGE_LABEL, "WID_AP_COVERAGE_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BTN_DONTHILIGHT, "WID_AP_BTN_DONTHILIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BTN_DOHILIGHT, "WID_AP_BTN_DOHILIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_CAPTION, "WID_RV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_MATRIX, "WID_RV_LEFT_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_SCROLLBAR, "WID_RV_LEFT_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_MATRIX, "WID_RV_RIGHT_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_SCROLLBAR, "WID_RV_RIGHT_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_DETAILS, "WID_RV_LEFT_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_DETAILS, "WID_RV_RIGHT_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_START_REPLACE, "WID_RV_START_REPLACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_INFO_TAB, "WID_RV_INFO_TAB"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_STOP_REPLACE, "WID_RV_STOP_REPLACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_ENGINEWAGON_TOGGLE, "WID_RV_TRAIN_ENGINEWAGON_TOGGLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_FLUFF_LEFT, "WID_RV_TRAIN_FLUFF_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_RAILTYPE_DROPDOWN, "WID_RV_TRAIN_RAILTYPE_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_FLUFF_RIGHT, "WID_RV_TRAIN_FLUFF_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_WAGONREMOVE_TOGGLE, "WID_RV_TRAIN_WAGONREMOVE_TOGGLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BB_BACKGROUND, "WID_BB_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_QUESTION, "WID_BAFD_QUESTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_YES, "WID_BAFD_YES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_NO, "WID_BAFD_NO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_CAPTION, "WID_BBS_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_DROPDOWN_ORDER, "WID_BBS_DROPDOWN_ORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_DROPDOWN_CRITERIA, "WID_BBS_DROPDOWN_CRITERIA"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_BRIDGE_LIST, "WID_BBS_BRIDGE_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_SCROLLBAR, "WID_BBS_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_CAPTION, "WID_BV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SORT_ASSENDING_DESCENDING, "WID_BV_SORT_ASSENDING_DESCENDING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SORT_DROPDOWN, "WID_BV_SORT_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_CARGO_FILTER_DROPDOWN, "WID_BV_CARGO_FILTER_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_LIST, "WID_BV_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SCROLLBAR, "WID_BV_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_PANEL, "WID_BV_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_BUILD, "WID_BV_BUILD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_BUILD_SEL, "WID_BV_BUILD_SEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_RENAME, "WID_BV_RENAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_PANEL, "WID_C_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_CAPTION, "WID_C_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_FACE, "WID_C_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_FACE_TITLE, "WID_C_FACE_TITLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INAUGURATION, "WID_C_DESC_INAUGURATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COLOUR_SCHEME, "WID_C_DESC_COLOUR_SCHEME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COLOUR_SCHEME_EXAMPLE, "WID_C_DESC_COLOUR_SCHEME_EXAMPLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_VEHICLE, "WID_C_DESC_VEHICLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_VEHICLE_COUNTS, "WID_C_DESC_VEHICLE_COUNTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COMPANY_VALUE, "WID_C_DESC_COMPANY_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INFRASTRUCTURE, "WID_C_DESC_INFRASTRUCTURE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INFRASTRUCTURE_COUNTS, "WID_C_DESC_INFRASTRUCTURE_COUNTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_DESC_OWNERS, "WID_C_SELECT_DESC_OWNERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_OWNERS, "WID_C_DESC_OWNERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_BUTTONS, "WID_C_SELECT_BUTTONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_NEW_FACE, "WID_C_NEW_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COLOUR_SCHEME, "WID_C_COLOUR_SCHEME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_PRESIDENT_NAME, "WID_C_PRESIDENT_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_NAME, "WID_C_COMPANY_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BUY_SHARE, "WID_C_BUY_SHARE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELL_SHARE, "WID_C_SELL_SHARE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_VIEW_BUILD_HQ, "WID_C_SELECT_VIEW_BUILD_HQ"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_VIEW_HQ, "WID_C_VIEW_HQ"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BUILD_HQ, "WID_C_BUILD_HQ"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_RELOCATE, "WID_C_SELECT_RELOCATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_RELOCATE_HQ, "WID_C_RELOCATE_HQ"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_VIEW_INFRASTRUCTURE, "WID_C_VIEW_INFRASTRUCTURE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_HAS_PASSWORD, "WID_C_HAS_PASSWORD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_MULTIPLAYER, "WID_C_SELECT_MULTIPLAYER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_PASSWORD, "WID_C_COMPANY_PASSWORD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_JOIN, "WID_C_COMPANY_JOIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_CAPTION, "WID_CF_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOGGLE_SIZE, "WID_CF_TOGGLE_SIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_PANEL, "WID_CF_SEL_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_CATEGORY, "WID_CF_EXPS_CATEGORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE1, "WID_CF_EXPS_PRICE1"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE2, "WID_CF_EXPS_PRICE2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE3, "WID_CF_EXPS_PRICE3"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOTAL_PANEL, "WID_CF_TOTAL_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_MAXLOAN, "WID_CF_SEL_MAXLOAN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_BALANCE_VALUE, "WID_CF_BALANCE_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_LOAN_VALUE, "WID_CF_LOAN_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_LOAN_LINE, "WID_CF_LOAN_LINE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOTAL_VALUE, "WID_CF_TOTAL_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_MAXLOAN_GAP, "WID_CF_MAXLOAN_GAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_MAXLOAN_VALUE, "WID_CF_MAXLOAN_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_BUTTONS, "WID_CF_SEL_BUTTONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_INCREASE_LOAN, "WID_CF_INCREASE_LOAN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_REPAY_LOAN, "WID_CF_REPAY_LOAN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_INFRASTRUCTURE, "WID_CF_INFRASTRUCTURE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CAPTION, "WID_SCL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_GENERAL, "WID_SCL_CLASS_GENERAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_RAIL, "WID_SCL_CLASS_RAIL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_ROAD, "WID_SCL_CLASS_ROAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_SHIP, "WID_SCL_CLASS_SHIP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_AIRCRAFT, "WID_SCL_CLASS_AIRCRAFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_SPACER_DROPDOWN, "WID_SCL_SPACER_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_PRI_COL_DROPDOWN, "WID_SCL_PRI_COL_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_SEC_COL_DROPDOWN, "WID_SCL_SEC_COL_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_MATRIX, "WID_SCL_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CAPTION, "WID_SCMF_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TOGGLE_LARGE_SMALL, "WID_SCMF_TOGGLE_LARGE_SMALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SELECT_FACE, "WID_SCMF_SELECT_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CANCEL, "WID_SCMF_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ACCEPT, "WID_SCMF_ACCEPT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_MALE, "WID_SCMF_MALE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FEMALE, "WID_SCMF_FEMALE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_MALE2, "WID_SCMF_MALE2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FEMALE2, "WID_SCMF_FEMALE2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_LOADSAVE, "WID_SCMF_SEL_LOADSAVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_MALEFEMALE, "WID_SCMF_SEL_MALEFEMALE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_PARTS, "WID_SCMF_SEL_PARTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_RANDOM_NEW_FACE, "WID_SCMF_RANDOM_NEW_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON, "WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FACE, "WID_SCMF_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LOAD, "WID_SCMF_LOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FACECODE, "WID_SCMF_FACECODE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SAVE, "WID_SCMF_SAVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT, "WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_TEXT, "WID_SCMF_TIE_EARRING_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_TEXT, "WID_SCMF_LIPS_MOUSTACHE_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_GLASSES_TEXT, "WID_SCMF_HAS_GLASSES_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_TEXT, "WID_SCMF_HAIR_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_TEXT, "WID_SCMF_EYEBROWS_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_TEXT, "WID_SCMF_EYECOLOUR_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_TEXT, "WID_SCMF_GLASSES_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_TEXT, "WID_SCMF_NOSE_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_TEXT, "WID_SCMF_CHIN_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_TEXT, "WID_SCMF_JACKET_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_TEXT, "WID_SCMF_COLLAR_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ETHNICITY_EUR, "WID_SCMF_ETHNICITY_EUR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ETHNICITY_AFR, "WID_SCMF_ETHNICITY_AFR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_MOUSTACHE_EARRING, "WID_SCMF_HAS_MOUSTACHE_EARRING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_GLASSES, "WID_SCMF_HAS_GLASSES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_L, "WID_SCMF_EYECOLOUR_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR, "WID_SCMF_EYECOLOUR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_R, "WID_SCMF_EYECOLOUR_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_L, "WID_SCMF_CHIN_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN, "WID_SCMF_CHIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_R, "WID_SCMF_CHIN_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_L, "WID_SCMF_EYEBROWS_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS, "WID_SCMF_EYEBROWS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_R, "WID_SCMF_EYEBROWS_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_L, "WID_SCMF_LIPS_MOUSTACHE_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE, "WID_SCMF_LIPS_MOUSTACHE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_R, "WID_SCMF_LIPS_MOUSTACHE_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_L, "WID_SCMF_NOSE_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE, "WID_SCMF_NOSE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_R, "WID_SCMF_NOSE_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_L, "WID_SCMF_HAIR_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR, "WID_SCMF_HAIR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_R, "WID_SCMF_HAIR_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_L, "WID_SCMF_JACKET_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET, "WID_SCMF_JACKET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_R, "WID_SCMF_JACKET_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_L, "WID_SCMF_COLLAR_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR, "WID_SCMF_COLLAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_R, "WID_SCMF_COLLAR_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_L, "WID_SCMF_TIE_EARRING_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING, "WID_SCMF_TIE_EARRING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_R, "WID_SCMF_TIE_EARRING_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_L, "WID_SCMF_GLASSES_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES, "WID_SCMF_GLASSES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_R, "WID_SCMF_GLASSES_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_CAPTION, "WID_CI_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_RAIL_DESC, "WID_CI_RAIL_DESC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_RAIL_COUNT, "WID_CI_RAIL_COUNT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_DESC, "WID_CI_ROAD_DESC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_COUNT, "WID_CI_ROAD_COUNT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_DESC, "WID_CI_WATER_DESC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_COUNT, "WID_CI_WATER_COUNT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_STATION_DESC, "WID_CI_STATION_DESC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_STATION_COUNT, "WID_CI_STATION_COUNT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TOTAL_DESC, "WID_CI_TOTAL_DESC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TOTAL, "WID_CI_TOTAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_CAPTION, "WID_BC_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_FACE, "WID_BC_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_QUESTION, "WID_BC_QUESTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_NO, "WID_BC_NO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_YES, "WID_BC_YES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BACKGROUND, "WID_C_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_DAY, "WID_SD_DAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_MONTH, "WID_SD_MONTH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_YEAR, "WID_SD_YEAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_SET_DATE, "WID_SD_SET_DATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_CAPTION, "WID_D_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL, "WID_D_SELL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_SELL_CHAIN, "WID_D_SHOW_SELL_CHAIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL_CHAIN, "WID_D_SELL_CHAIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL_ALL, "WID_D_SELL_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_AUTOREPLACE, "WID_D_AUTOREPLACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_MATRIX, "WID_D_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_V_SCROLL, "WID_D_V_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_H_SCROLL, "WID_D_SHOW_H_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_H_SCROLL, "WID_D_H_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_BUILD, "WID_D_BUILD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_CLONE, "WID_D_CLONE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_LOCATION, "WID_D_LOCATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_RENAME, "WID_D_SHOW_RENAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_RENAME, "WID_D_RENAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_VEHICLE_LIST, "WID_D_VEHICLE_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_STOP_ALL, "WID_D_STOP_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_START_ALL, "WID_D_START_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_BACKGROUND, "WID_BDD_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_X, "WID_BDD_X"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_Y, "WID_BDD_Y"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_CANAL, "WID_DT_CANAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_LOCK, "WID_DT_LOCK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_DEMOLISH, "WID_DT_DEMOLISH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_DEPOT, "WID_DT_DEPOT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_STATION, "WID_DT_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_BUOY, "WID_DT_BUOY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_RIVER, "WID_DT_RIVER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_BUILD_AQUEDUCT, "WID_DT_BUILD_AQUEDUCT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_INVALID, "WID_DT_INVALID"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_ITEMS, "WID_DM_ITEMS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_SHOW_SCROLL, "WID_DM_SHOW_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_SCROLL, "WID_DM_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_QUESTION, "WID_EP_QUESTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_NO, "WID_EP_NO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_YES, "WID_EP_YES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_CAPTION, "WID_EM_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_FACE, "WID_EM_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_MESSAGE, "WID_EM_MESSAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CAPTION, "WID_SL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SORT_BYNAME, "WID_SL_SORT_BYNAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SORT_BYDATE, "WID_SL_SORT_BYDATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_BACKGROUND, "WID_SL_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_FILE_BACKGROUND, "WID_SL_FILE_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_HOME_BUTTON, "WID_SL_HOME_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DRIVES_DIRECTORIES_LIST, "WID_SL_DRIVES_DIRECTORIES_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SCROLLBAR, "WID_SL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CONTENT_DOWNLOAD, "WID_SL_CONTENT_DOWNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SAVE_OSK_TITLE, "WID_SL_SAVE_OSK_TITLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DELETE_SELECTION, "WID_SL_DELETE_SELECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SAVE_GAME, "WID_SL_SAVE_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CONTENT_DOWNLOAD_SEL, "WID_SL_CONTENT_DOWNLOAD_SEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DETAILS, "WID_SL_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_NEWGRF_INFO, "WID_SL_NEWGRF_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_LOAD_BUTTON, "WID_SL_LOAD_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_MISSING_NEWGRFS, "WID_SL_MISSING_NEWGRFS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TEMPERATE, "WID_GL_TEMPERATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_ARCTIC, "WID_GL_ARCTIC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TROPICAL, "WID_GL_TROPICAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TOYLAND, "WID_GL_TOYLAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAPSIZE_X_PULLDOWN, "WID_GL_MAPSIZE_X_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAPSIZE_Y_PULLDOWN, "WID_GL_MAPSIZE_Y_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TOWN_PULLDOWN, "WID_GL_TOWN_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_INDUSTRY_PULLDOWN, "WID_GL_INDUSTRY_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RANDOM_EDITBOX, "WID_GL_RANDOM_EDITBOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RANDOM_BUTTON, "WID_GL_RANDOM_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_GENERATE_BUTTON, "WID_GL_GENERATE_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_DOWN, "WID_GL_START_DATE_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_TEXT, "WID_GL_START_DATE_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_UP, "WID_GL_START_DATE_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_DOWN, "WID_GL_SNOW_LEVEL_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_TEXT, "WID_GL_SNOW_LEVEL_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_UP, "WID_GL_SNOW_LEVEL_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TREE_PULLDOWN, "WID_GL_TREE_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LANDSCAPE_PULLDOWN, "WID_GL_LANDSCAPE_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_NAME_TEXT, "WID_GL_HEIGHTMAP_NAME_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_SIZE_TEXT, "WID_GL_HEIGHTMAP_SIZE_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_ROTATION_PULLDOWN, "WID_GL_HEIGHTMAP_ROTATION_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TERRAIN_PULLDOWN, "WID_GL_TERRAIN_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_PULLDOWN, "WID_GL_WATER_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RIVER_PULLDOWN, "WID_GL_RIVER_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SMOOTHNESS_PULLDOWN, "WID_GL_SMOOTHNESS_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_VARIETY_PULLDOWN, "WID_GL_VARIETY_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_BORDERS_RANDOM, "WID_GL_BORDERS_RANDOM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_NW, "WID_GL_WATER_NW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_NE, "WID_GL_WATER_NE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_SE, "WID_GL_WATER_SE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_SW, "WID_GL_WATER_SW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TEMPERATE, "WID_CS_TEMPERATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_ARCTIC, "WID_CS_ARCTIC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TROPICAL, "WID_CS_TROPICAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TOYLAND, "WID_CS_TOYLAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_EMPTY_WORLD, "WID_CS_EMPTY_WORLD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_RANDOM_WORLD, "WID_CS_RANDOM_WORLD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_MAPSIZE_X_PULLDOWN, "WID_CS_MAPSIZE_X_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_MAPSIZE_Y_PULLDOWN, "WID_CS_MAPSIZE_Y_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_DOWN, "WID_CS_START_DATE_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_TEXT, "WID_CS_START_DATE_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_UP, "WID_CS_START_DATE_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_DOWN, "WID_CS_FLAT_LAND_HEIGHT_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_TEXT, "WID_CS_FLAT_LAND_HEIGHT_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_UP, "WID_CS_FLAT_LAND_HEIGHT_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_PROGRESS_BAR, "WID_GP_PROGRESS_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_PROGRESS_TEXT, "WID_GP_PROGRESS_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_ABORT, "WID_GP_ABORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_CAPTION, "WID_GOAL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_LIST, "WID_GOAL_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_SCROLLBAR, "WID_GOAL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_CAPTION, "WID_GQ_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_QUESTION, "WID_GQ_QUESTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTONS, "WID_GQ_BUTTONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_1, "WID_GQ_BUTTON_1"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_2, "WID_GQ_BUTTON_2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_3, "WID_GQ_BUTTON_3"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_BACKGROUND, "WID_GL_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_FIRST_COMPANY, "WID_GL_FIRST_COMPANY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LAST_COMPANY, "WID_GL_LAST_COMPANY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_KEY_BUTTON, "WID_CV_KEY_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_BACKGROUND, "WID_CV_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_GRAPH, "WID_CV_GRAPH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_RESIZE, "WID_CV_RESIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_KEY, "WID_PHG_KEY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_DETAILED_PERFORMANCE, "WID_PHG_DETAILED_PERFORMANCE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_BACKGROUND, "WID_PHG_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_GRAPH, "WID_PHG_GRAPH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_RESIZE, "WID_PHG_RESIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_BACKGROUND, "WID_CPR_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_HEADER, "WID_CPR_HEADER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_GRAPH, "WID_CPR_GRAPH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_RESIZE, "WID_CPR_RESIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_FOOTER, "WID_CPR_FOOTER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_ENABLE_CARGOES, "WID_CPR_ENABLE_CARGOES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_DISABLE_CARGOES, "WID_CPR_DISABLE_CARGOES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_CARGO_FIRST, "WID_CPR_CARGO_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CL_BACKGROUND, "WID_CL_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_SCORE_FIRST, "WID_PRD_SCORE_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_SCORE_LAST, "WID_PRD_SCORE_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_COMPANY_FIRST, "WID_PRD_COMPANY_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_COMPANY_LAST, "WID_PRD_COMPANY_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_CAPTION, "WID_GL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SORT_BY_ORDER, "WID_GL_SORT_BY_ORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SORT_BY_DROPDOWN, "WID_GL_SORT_BY_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_VEHICLE, "WID_GL_LIST_VEHICLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_VEHICLE_SCROLLBAR, "WID_GL_LIST_VEHICLE_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_AVAILABLE_VEHICLES, "WID_GL_AVAILABLE_VEHICLES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MANAGE_VEHICLES_DROPDOWN, "WID_GL_MANAGE_VEHICLES_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_STOP_ALL, "WID_GL_STOP_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_ALL, "WID_GL_START_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_ALL_VEHICLES, "WID_GL_ALL_VEHICLES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_DEFAULT_VEHICLES, "WID_GL_DEFAULT_VEHICLES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_GROUP, "WID_GL_LIST_GROUP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_GROUP_SCROLLBAR, "WID_GL_LIST_GROUP_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_CREATE_GROUP, "WID_GL_CREATE_GROUP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_DELETE_GROUP, "WID_GL_DELETE_GROUP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RENAME_GROUP, "WID_GL_RENAME_GROUP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_REPLACE_PROTECTION, "WID_GL_REPLACE_PROTECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_H_BACKGROUND, "WID_H_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_MATRIX_WIDGET, "WID_DPI_MATRIX_WIDGET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_SCROLLBAR, "WID_DPI_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_INFOPANEL, "WID_DPI_INFOPANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_DISPLAY_WIDGET, "WID_DPI_DISPLAY_WIDGET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_FUND_WIDGET, "WID_DPI_FUND_WIDGET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_CAPTION, "WID_IV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_VIEWPORT, "WID_IV_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_INFO, "WID_IV_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_GOTO, "WID_IV_GOTO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_DISPLAY, "WID_IV_DISPLAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_DROPDOWN_ORDER, "WID_ID_DROPDOWN_ORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_DROPDOWN_CRITERIA, "WID_ID_DROPDOWN_CRITERIA"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_INDUSTRY_LIST, "WID_ID_INDUSTRY_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_SCROLLBAR, "WID_ID_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_CAPTION, "WID_IC_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_NOTIFY, "WID_IC_NOTIFY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_PANEL, "WID_IC_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_SCROLLBAR, "WID_IC_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_CARGO_DROPDOWN, "WID_IC_CARGO_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_IND_DROPDOWN, "WID_IC_IND_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_GENERATE_GAME, "WID_SGI_GENERATE_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_LOAD_GAME, "WID_SGI_LOAD_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_SCENARIO, "WID_SGI_PLAY_SCENARIO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_HEIGHTMAP, "WID_SGI_PLAY_HEIGHTMAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_EDIT_SCENARIO, "WID_SGI_EDIT_SCENARIO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_NETWORK, "WID_SGI_PLAY_NETWORK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TEMPERATE_LANDSCAPE, "WID_SGI_TEMPERATE_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_ARCTIC_LANDSCAPE, "WID_SGI_ARCTIC_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TROPIC_LANDSCAPE, "WID_SGI_TROPIC_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TOYLAND_LANDSCAPE, "WID_SGI_TOYLAND_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TRANSLATION_SELECTION, "WID_SGI_TRANSLATION_SELECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TRANSLATION, "WID_SGI_TRANSLATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_OPTIONS, "WID_SGI_OPTIONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_HIGHSCORE, "WID_SGI_HIGHSCORE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_SETTINGS_OPTIONS, "WID_SGI_SETTINGS_OPTIONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_GRF_SETTINGS, "WID_SGI_GRF_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_CONTENT_DOWNLOAD, "WID_SGI_CONTENT_DOWNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_AI_SETTINGS, "WID_SGI_AI_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_EXIT, "WID_SGI_EXIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CAPTION, "WID_LGL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION, "WID_LGL_SATURATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION_FIRST, "WID_LGL_SATURATION_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION_LAST, "WID_LGL_SATURATION_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES, "WID_LGL_COMPANIES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANY_FIRST, "WID_LGL_COMPANY_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANY_LAST, "WID_LGL_COMPANY_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES_ALL, "WID_LGL_COMPANIES_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES_NONE, "WID_LGL_COMPANIES_NONE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES, "WID_LGL_CARGOES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGO_FIRST, "WID_LGL_CARGO_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGO_LAST, "WID_LGL_CARGO_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES_ALL, "WID_LGL_CARGOES_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES_NONE, "WID_LGL_CARGOES_NONE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_VIEWPORT, "WID_M_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LI_BACKGROUND, "WID_LI_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BACKGROUND, "WID_TT_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_A_SCROLLING_TEXT, "WID_A_SCROLLING_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_A_WEBSITE, "WID_A_WEBSITE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_CAPTION, "WID_QS_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_TEXT, "WID_QS_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_DEFAULT, "WID_QS_DEFAULT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_CANCEL, "WID_QS_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_OK, "WID_QS_OK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_CAPTION, "WID_Q_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_TEXT, "WID_Q_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_NO, "WID_Q_NO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_YES, "WID_Q_YES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_CAPTION, "WID_TF_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_WRAPTEXT, "WID_TF_WRAPTEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_BACKGROUND, "WID_TF_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_VSCROLLBAR, "WID_TF_VSCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_HSCROLLBAR, "WID_TF_HSCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LIST_LEFT, "WID_MTS_LIST_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LEFT_SCROLLBAR, "WID_MTS_LEFT_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_PLAYLIST, "WID_MTS_PLAYLIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LIST_RIGHT, "WID_MTS_LIST_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_RIGHT_SCROLLBAR, "WID_MTS_RIGHT_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_ALL, "WID_MTS_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_OLD, "WID_MTS_OLD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_NEW, "WID_MTS_NEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_EZY, "WID_MTS_EZY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CUSTOM1, "WID_MTS_CUSTOM1"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CUSTOM2, "WID_MTS_CUSTOM2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CLEAR, "WID_MTS_CLEAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PREV, "WID_M_PREV"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_NEXT, "WID_M_NEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_STOP, "WID_M_STOP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PLAY, "WID_M_PLAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_SLIDERS, "WID_M_SLIDERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_MUSIC_VOL, "WID_M_MUSIC_VOL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_EFFECT_VOL, "WID_M_EFFECT_VOL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_BACKGROUND, "WID_M_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK, "WID_M_TRACK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_NR, "WID_M_TRACK_NR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_TITLE, "WID_M_TRACK_TITLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_NAME, "WID_M_TRACK_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_SHUFFLE, "WID_M_SHUFFLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PROGRAMME, "WID_M_PROGRAMME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_ALL, "WID_M_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_OLD, "WID_M_OLD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_NEW, "WID_M_NEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_EZY, "WID_M_EZY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_CUSTOM1, "WID_M_CUSTOM1"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_CUSTOM2, "WID_M_CUSTOM2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_CLOSE, "WID_NC_CLOSE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_BACKGROUND, "WID_NC_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_DESTINATION, "WID_NC_DESTINATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_TEXTBOX, "WID_NC_TEXTBOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_SENDBUTTON, "WID_NC_SENDBUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCDS_BACKGROUND, "WID_NCDS_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCDS_CANCELOK, "WID_NCDS_CANCELOK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_BACKGROUND, "WID_NCL_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_FILTER_CAPT, "WID_NCL_FILTER_CAPT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_FILTER, "WID_NCL_FILTER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_CHECKBOX, "WID_NCL_CHECKBOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_TYPE, "WID_NCL_TYPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_NAME, "WID_NCL_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_MATRIX, "WID_NCL_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SCROLLBAR, "WID_NCL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_DETAILS, "WID_NCL_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_TEXTFILE, "WID_NCL_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SELECT_ALL, "WID_NCL_SELECT_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SELECT_UPDATE, "WID_NCL_SELECT_UPDATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_UNSELECT, "WID_NCL_UNSELECT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_OPEN_URL, "WID_NCL_OPEN_URL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_CANCEL, "WID_NCL_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_DOWNLOAD, "WID_NCL_DOWNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SEL_ALL_UPDATE, "WID_NCL_SEL_ALL_UPDATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SEARCH_EXTERNAL, "WID_NCL_SEARCH_EXTERNAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MAIN, "WID_NG_MAIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CONNECTION, "WID_NG_CONNECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CONN_BTN, "WID_NG_CONN_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENT_LABEL, "WID_NG_CLIENT_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENT, "WID_NG_CLIENT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FILTER_LABEL, "WID_NG_FILTER_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FILTER, "WID_NG_FILTER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_HEADER, "WID_NG_HEADER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NAME, "WID_NG_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENTS, "WID_NG_CLIENTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MAPSIZE, "WID_NG_MAPSIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DATE, "WID_NG_DATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_YEARS, "WID_NG_YEARS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_INFO, "WID_NG_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MATRIX, "WID_NG_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_SCROLLBAR, "WID_NG_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED_LABEL, "WID_NG_LASTJOINED_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED, "WID_NG_LASTJOINED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED_SPACER, "WID_NG_LASTJOINED_SPACER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DETAILS, "WID_NG_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DETAILS_SPACER, "WID_NG_DETAILS_SPACER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_JOIN, "WID_NG_JOIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_REFRESH, "WID_NG_REFRESH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF, "WID_NG_NEWGRF"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_SEL, "WID_NG_NEWGRF_SEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_MISSING, "WID_NG_NEWGRF_MISSING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_MISSING_SEL, "WID_NG_NEWGRF_MISSING_SEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FIND, "WID_NG_FIND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_ADD, "WID_NG_ADD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_START, "WID_NG_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CANCEL, "WID_NG_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_BACKGROUND, "WID_NSS_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GAMENAME_LABEL, "WID_NSS_GAMENAME_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GAMENAME, "WID_NSS_GAMENAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SETPWD, "WID_NSS_SETPWD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CONNTYPE_LABEL, "WID_NSS_CONNTYPE_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CONNTYPE_BTN, "WID_NSS_CONNTYPE_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_LABEL, "WID_NSS_CLIENTS_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_BTND, "WID_NSS_CLIENTS_BTND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_TXT, "WID_NSS_CLIENTS_TXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_BTNU, "WID_NSS_CLIENTS_BTNU"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_LABEL, "WID_NSS_COMPANIES_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_BTND, "WID_NSS_COMPANIES_BTND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_TXT, "WID_NSS_COMPANIES_TXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_BTNU, "WID_NSS_COMPANIES_BTNU"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_LABEL, "WID_NSS_SPECTATORS_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_BTND, "WID_NSS_SPECTATORS_BTND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_TXT, "WID_NSS_SPECTATORS_TXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_BTNU, "WID_NSS_SPECTATORS_BTNU"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LANGUAGE_LABEL, "WID_NSS_LANGUAGE_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LANGUAGE_BTN, "WID_NSS_LANGUAGE_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GENERATE_GAME, "WID_NSS_GENERATE_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LOAD_GAME, "WID_NSS_LOAD_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_PLAY_SCENARIO, "WID_NSS_PLAY_SCENARIO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_PLAY_HEIGHTMAP, "WID_NSS_PLAY_HEIGHTMAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CANCEL, "WID_NSS_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_BACKGROUND, "WID_NL_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_TEXT, "WID_NL_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_HEADER, "WID_NL_HEADER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_MATRIX, "WID_NL_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_SCROLLBAR, "WID_NL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_DETAILS, "WID_NL_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_JOIN, "WID_NL_JOIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_NEW, "WID_NL_NEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_SPECTATE, "WID_NL_SPECTATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_REFRESH, "WID_NL_REFRESH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_CANCEL, "WID_NL_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CL_PANEL, "WID_CL_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CLP_PANEL, "WID_CLP_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NJS_BACKGROUND, "WID_NJS_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NJS_CANCELOK, "WID_NJS_CANCELOK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_BACKGROUND, "WID_NCP_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_LABEL, "WID_NCP_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_PASSWORD, "WID_NCP_PASSWORD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_SAVE_AS_DEFAULT_PASSWORD, "WID_NCP_SAVE_AS_DEFAULT_PASSWORD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_CANCEL, "WID_NCP_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_OK, "WID_NCP_OK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_CAPTION, "WID_NGRFI_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_PARENT, "WID_NGRFI_PARENT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_PREV, "WID_NGRFI_VEH_PREV"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_NEXT, "WID_NGRFI_VEH_NEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_CHAIN, "WID_NGRFI_VEH_CHAIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_MAINPANEL, "WID_NGRFI_MAINPANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_SCROLLBAR, "WID_NGRFI_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_CAPTION, "WID_SA_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_PREVIOUS, "WID_SA_PREVIOUS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_GOTO, "WID_SA_GOTO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_NEXT, "WID_SA_NEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_UP, "WID_SA_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_LEFT, "WID_SA_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_RIGHT, "WID_SA_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_DOWN, "WID_SA_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_SPRITE, "WID_SA_SPRITE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_OFFSETS, "WID_SA_OFFSETS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_PICKER, "WID_SA_PICKER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_LIST, "WID_SA_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_SCROLLBAR, "WID_SA_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SHOW_NUMPAR, "WID_NP_SHOW_NUMPAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_DEC, "WID_NP_NUMPAR_DEC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_INC, "WID_NP_NUMPAR_INC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR, "WID_NP_NUMPAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_TEXT, "WID_NP_NUMPAR_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_BACKGROUND, "WID_NP_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SCROLLBAR, "WID_NP_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_ACCEPT, "WID_NP_ACCEPT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_RESET, "WID_NP_RESET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SHOW_DESCRIPTION, "WID_NP_SHOW_DESCRIPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_DESCRIPTION, "WID_NP_DESCRIPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_LIST, "WID_NS_PRESET_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_SAVE, "WID_NS_PRESET_SAVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_DELETE, "WID_NS_PRESET_DELETE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_ADD, "WID_NS_ADD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_REMOVE, "WID_NS_REMOVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_MOVE_UP, "WID_NS_MOVE_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_MOVE_DOWN, "WID_NS_MOVE_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_FILTER, "WID_NS_FILTER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_FILE_LIST, "WID_NS_FILE_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SCROLLBAR, "WID_NS_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_AVAIL_LIST, "WID_NS_AVAIL_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SCROLL2BAR, "WID_NS_SCROLL2BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_INFO_TITLE, "WID_NS_NEWGRF_INFO_TITLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_INFO, "WID_NS_NEWGRF_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_OPEN_URL, "WID_NS_OPEN_URL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_TEXTFILE, "WID_NS_NEWGRF_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SET_PARAMETERS, "WID_NS_SET_PARAMETERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_VIEW_PARAMETERS, "WID_NS_VIEW_PARAMETERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_TOGGLE_PALETTE, "WID_NS_TOGGLE_PALETTE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_APPLY_CHANGES, "WID_NS_APPLY_CHANGES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_RESCAN_FILES, "WID_NS_RESCAN_FILES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_RESCAN_FILES2, "WID_NS_RESCAN_FILES2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_CONTENT_DOWNLOAD, "WID_NS_CONTENT_DOWNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_CONTENT_DOWNLOAD2, "WID_NS_CONTENT_DOWNLOAD2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SHOW_REMOVE, "WID_NS_SHOW_REMOVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SHOW_APPLY, "WID_NS_SHOW_APPLY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SP_PROGRESS_BAR, "WID_SP_PROGRESS_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SP_PROGRESS_TEXT, "WID_SP_PROGRESS_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_PANEL, "WID_N_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_TITLE, "WID_N_TITLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_HEADLINE, "WID_N_HEADLINE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_CLOSEBOX, "WID_N_CLOSEBOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_DATE, "WID_N_DATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_CAPTION, "WID_N_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_INSET, "WID_N_INSET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VIEWPORT, "WID_N_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_COMPANY_MSG, "WID_N_COMPANY_MSG"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MESSAGE, "WID_N_MESSAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MGR_FACE, "WID_N_MGR_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MGR_NAME, "WID_N_MGR_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_TITLE, "WID_N_VEH_TITLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_BKGND, "WID_N_VEH_BKGND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_NAME, "WID_N_VEH_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_SPR, "WID_N_VEH_SPR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_INFO, "WID_N_VEH_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_STICKYBOX, "WID_MH_STICKYBOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_BACKGROUND, "WID_MH_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_SCROLLBAR, "WID_MH_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_CLASS_LIST, "WID_BO_CLASS_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SCROLLBAR, "WID_BO_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_MATRIX, "WID_BO_OBJECT_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_SPRITE, "WID_BO_OBJECT_SPRITE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_NAME, "WID_BO_OBJECT_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_SIZE, "WID_BO_OBJECT_SIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_INFO, "WID_BO_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_MATRIX, "WID_BO_SELECT_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_IMAGE, "WID_BO_SELECT_IMAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_SCROLL, "WID_BO_SELECT_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_CAPTION, "WID_O_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_TIMETABLE_VIEW, "WID_O_TIMETABLE_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_ORDER_LIST, "WID_O_ORDER_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SCROLLBAR, "WID_O_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SKIP, "WID_O_SKIP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_DELETE, "WID_O_DELETE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_STOP_SHARING, "WID_O_STOP_SHARING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_NON_STOP, "WID_O_NON_STOP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_GOTO, "WID_O_GOTO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_FULL_LOAD, "WID_O_FULL_LOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_UNLOAD, "WID_O_UNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_REFIT, "WID_O_REFIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SERVICE, "WID_O_SERVICE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_EMPTY, "WID_O_EMPTY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_REFIT_DROPDOWN, "WID_O_REFIT_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_VARIABLE, "WID_O_COND_VARIABLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_COMPARATOR, "WID_O_COND_COMPARATOR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_VALUE, "WID_O_COND_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_LEFT, "WID_O_SEL_TOP_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_MIDDLE, "WID_O_SEL_TOP_MIDDLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_RIGHT, "WID_O_SEL_TOP_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_ROW_GROUNDVEHICLE, "WID_O_SEL_TOP_ROW_GROUNDVEHICLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_ROW, "WID_O_SEL_TOP_ROW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_BOTTOM_MIDDLE, "WID_O_SEL_BOTTOM_MIDDLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SHARED_ORDER_LIST, "WID_O_SHARED_ORDER_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CAPTION, "WID_OSK_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_TEXT, "WID_OSK_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CANCEL, "WID_OSK_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_OK, "WID_OSK_OK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_BACKSPACE, "WID_OSK_BACKSPACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SPECIAL, "WID_OSK_SPECIAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CAPS, "WID_OSK_CAPS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SHIFT, "WID_OSK_SHIFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SPACE, "WID_OSK_SPACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_LEFT, "WID_OSK_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_RIGHT, "WID_OSK_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_LETTERS, "WID_OSK_LETTERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_NUMBERS_FIRST, "WID_OSK_NUMBERS_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_NUMBERS_LAST, "WID_OSK_NUMBERS_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_QWERTY_FIRST, "WID_OSK_QWERTY_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_QWERTY_LAST, "WID_OSK_QWERTY_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ASDFG_FIRST, "WID_OSK_ASDFG_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ASDFG_LAST, "WID_OSK_ASDFG_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ZXCVB_FIRST, "WID_OSK_ZXCVB_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ZXCVB_LAST, "WID_OSK_ZXCVB_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_CAPTION, "WID_RAT_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_NS, "WID_RAT_BUILD_NS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_X, "WID_RAT_BUILD_X"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_EW, "WID_RAT_BUILD_EW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_Y, "WID_RAT_BUILD_Y"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_AUTORAIL, "WID_RAT_AUTORAIL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_DEMOLISH, "WID_RAT_DEMOLISH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_DEPOT, "WID_RAT_BUILD_DEPOT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_WAYPOINT, "WID_RAT_BUILD_WAYPOINT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_STATION, "WID_RAT_BUILD_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_SIGNALS, "WID_RAT_BUILD_SIGNALS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_BRIDGE, "WID_RAT_BUILD_BRIDGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_TUNNEL, "WID_RAT_BUILD_TUNNEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_REMOVE, "WID_RAT_REMOVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_CONVERT_RAIL, "WID_RAT_CONVERT_RAIL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DIR_X, "WID_BRAS_PLATFORM_DIR_X"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DIR_Y, "WID_BRAS_PLATFORM_DIR_Y"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_1, "WID_BRAS_PLATFORM_NUM_1"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_2, "WID_BRAS_PLATFORM_NUM_2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_3, "WID_BRAS_PLATFORM_NUM_3"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_4, "WID_BRAS_PLATFORM_NUM_4"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_5, "WID_BRAS_PLATFORM_NUM_5"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_6, "WID_BRAS_PLATFORM_NUM_6"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_7, "WID_BRAS_PLATFORM_NUM_7"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_1, "WID_BRAS_PLATFORM_LEN_1"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_2, "WID_BRAS_PLATFORM_LEN_2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_3, "WID_BRAS_PLATFORM_LEN_3"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_4, "WID_BRAS_PLATFORM_LEN_4"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_5, "WID_BRAS_PLATFORM_LEN_5"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_6, "WID_BRAS_PLATFORM_LEN_6"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_7, "WID_BRAS_PLATFORM_LEN_7"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DRAG_N_DROP, "WID_BRAS_PLATFORM_DRAG_N_DROP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_HIGHLIGHT_OFF, "WID_BRAS_HIGHLIGHT_OFF"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_HIGHLIGHT_ON, "WID_BRAS_HIGHLIGHT_ON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_COVERAGE_TEXTS, "WID_BRAS_COVERAGE_TEXTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_MATRIX, "WID_BRAS_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_IMAGE, "WID_BRAS_IMAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_MATRIX_SCROLL, "WID_BRAS_MATRIX_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_DEFSIZE, "WID_BRAS_SHOW_NEWST_DEFSIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_ADDITIONS, "WID_BRAS_SHOW_NEWST_ADDITIONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_MATRIX, "WID_BRAS_SHOW_NEWST_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_RESIZE, "WID_BRAS_SHOW_NEWST_RESIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_TYPE, "WID_BRAS_SHOW_NEWST_TYPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_NEWST_LIST, "WID_BRAS_NEWST_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_NEWST_SCROLL, "WID_BRAS_NEWST_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_BEGIN, "WID_BRAS_PLATFORM_NUM_BEGIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_BEGIN, "WID_BRAS_PLATFORM_LEN_BEGIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_NORM, "WID_BS_SEMAPHORE_NORM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_ENTRY, "WID_BS_SEMAPHORE_ENTRY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_EXIT, "WID_BS_SEMAPHORE_EXIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_COMBO, "WID_BS_SEMAPHORE_COMBO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_PBS, "WID_BS_SEMAPHORE_PBS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_PBS_OWAY, "WID_BS_SEMAPHORE_PBS_OWAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_NORM, "WID_BS_ELECTRIC_NORM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_ENTRY, "WID_BS_ELECTRIC_ENTRY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_EXIT, "WID_BS_ELECTRIC_EXIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_COMBO, "WID_BS_ELECTRIC_COMBO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_PBS, "WID_BS_ELECTRIC_PBS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_PBS_OWAY, "WID_BS_ELECTRIC_PBS_OWAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_CONVERT, "WID_BS_CONVERT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_LABEL, "WID_BS_DRAG_SIGNALS_DENSITY_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, "WID_BS_DRAG_SIGNALS_DENSITY_DECREASE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, "WID_BS_DRAG_SIGNALS_DENSITY_INCREASE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_NE, "WID_BRAD_DEPOT_NE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_SE, "WID_BRAD_DEPOT_SE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_SW, "WID_BRAD_DEPOT_SW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_NW, "WID_BRAD_DEPOT_NW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT_MATRIX, "WID_BRW_WAYPOINT_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT, "WID_BRW_WAYPOINT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_SCROLL, "WID_BRW_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_X, "WID_ROT_ROAD_X"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_Y, "WID_ROT_ROAD_Y"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_AUTOROAD, "WID_ROT_AUTOROAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_DEMOLISH, "WID_ROT_DEMOLISH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_DEPOT, "WID_ROT_DEPOT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUS_STATION, "WID_ROT_BUS_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_TRUCK_STATION, "WID_ROT_TRUCK_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ONE_WAY, "WID_ROT_ONE_WAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_BRIDGE, "WID_ROT_BUILD_BRIDGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_TUNNEL, "WID_ROT_BUILD_TUNNEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_REMOVE, "WID_ROT_REMOVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_CAPTION, "WID_BROD_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_NE, "WID_BROD_DEPOT_NE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_SE, "WID_BROD_DEPOT_SE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_SW, "WID_BROD_DEPOT_SW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_NW, "WID_BROD_DEPOT_NW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_CAPTION, "WID_BROS_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_BACKGROUND, "WID_BROS_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_NE, "WID_BROS_STATION_NE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_SE, "WID_BROS_STATION_SE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_SW, "WID_BROS_STATION_SW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_NW, "WID_BROS_STATION_NW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_X, "WID_BROS_STATION_X"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_Y, "WID_BROS_STATION_Y"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_LT_OFF, "WID_BROS_LT_OFF"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_LT_ON, "WID_BROS_LT_ON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_INFO, "WID_BROS_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BACKGROUND, "WID_GO_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_CURRENCY_DROPDOWN, "WID_GO_CURRENCY_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_DISTANCE_DROPDOWN, "WID_GO_DISTANCE_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_ROADSIDE_DROPDOWN, "WID_GO_ROADSIDE_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_TOWNNAME_DROPDOWN, "WID_GO_TOWNNAME_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_AUTOSAVE_DROPDOWN, "WID_GO_AUTOSAVE_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_LANG_DROPDOWN, "WID_GO_LANG_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_RESOLUTION_DROPDOWN, "WID_GO_RESOLUTION_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_FULLSCREEN_BUTTON, "WID_GO_FULLSCREEN_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_SCREENSHOT_DROPDOWN, "WID_GO_SCREENSHOT_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_DROPDOWN, "WID_GO_BASE_GRF_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_STATUS, "WID_GO_BASE_GRF_STATUS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_TEXTFILE, "WID_GO_BASE_GRF_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_DESCRIPTION, "WID_GO_BASE_GRF_DESCRIPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_DROPDOWN, "WID_GO_BASE_SFX_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_TEXTFILE, "WID_GO_BASE_SFX_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_DESCRIPTION, "WID_GO_BASE_SFX_DESCRIPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_DROPDOWN, "WID_GO_BASE_MUSIC_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_STATUS, "WID_GO_BASE_MUSIC_STATUS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_TEXTFILE, "WID_GO_BASE_MUSIC_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_DESCRIPTION, "WID_GO_BASE_MUSIC_DESCRIPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_FILTER, "WID_GS_FILTER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_OPTIONSPANEL, "WID_GS_OPTIONSPANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_SCROLLBAR, "WID_GS_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_HELP_TEXT, "WID_GS_HELP_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_EXPAND_ALL, "WID_GS_EXPAND_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_COLLAPSE_ALL, "WID_GS_COLLAPSE_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_CATEGORY, "WID_GS_RESTRICT_CATEGORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_TYPE, "WID_GS_RESTRICT_TYPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_DROPDOWN, "WID_GS_RESTRICT_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_TYPE_DROPDOWN, "WID_GS_TYPE_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE_DOWN, "WID_CC_RATE_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE_UP, "WID_CC_RATE_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE, "WID_CC_RATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SEPARATOR_EDIT, "WID_CC_SEPARATOR_EDIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SEPARATOR, "WID_CC_SEPARATOR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREFIX_EDIT, "WID_CC_PREFIX_EDIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREFIX, "WID_CC_PREFIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SUFFIX_EDIT, "WID_CC_SUFFIX_EDIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SUFFIX, "WID_CC_SUFFIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR_DOWN, "WID_CC_YEAR_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR_UP, "WID_CC_YEAR_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR, "WID_CC_YEAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREVIEW, "WID_CC_PREVIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_CAPTION, "WID_SIL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_LIST, "WID_SIL_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_SCROLLBAR, "WID_SIL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_TEXT, "WID_SIL_FILTER_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_MATCH_CASE_BTN, "WID_SIL_FILTER_MATCH_CASE_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_ENTER_BTN, "WID_SIL_FILTER_ENTER_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_CAPTION, "WID_QES_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_TEXT, "WID_QES_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_OK, "WID_QES_OK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_CANCEL, "WID_QES_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_DELETE, "WID_QES_DELETE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_PREVIOUS, "WID_QES_PREVIOUS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_NEXT, "WID_QES_NEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CAPTION, "WID_SM_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_MAP_BORDER, "WID_SM_MAP_BORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_MAP, "WID_SM_MAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_LEGEND, "WID_SM_LEGEND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_BLANK, "WID_SM_BLANK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ZOOM_IN, "WID_SM_ZOOM_IN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ZOOM_OUT, "WID_SM_ZOOM_OUT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CONTOUR, "WID_SM_CONTOUR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_VEHICLES, "WID_SM_VEHICLES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_INDUSTRIES, "WID_SM_INDUSTRIES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_LINKSTATS, "WID_SM_LINKSTATS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ROUTES, "WID_SM_ROUTES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_VEGETATION, "WID_SM_VEGETATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_OWNERS, "WID_SM_OWNERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CENTERMAP, "WID_SM_CENTERMAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_TOGGLETOWNNAME, "WID_SM_TOGGLETOWNNAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_SELECT_BUTTONS, "WID_SM_SELECT_BUTTONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ENABLE_ALL, "WID_SM_ENABLE_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_DISABLE_ALL, "WID_SM_DISABLE_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_SHOW_HEIGHT, "WID_SM_SHOW_HEIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_CAPTION, "WID_SV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SORT_ORDER, "WID_SV_SORT_ORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SORT_BY, "WID_SV_SORT_BY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_GROUP, "WID_SV_GROUP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_GROUP_BY, "WID_SV_GROUP_BY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_WAITING, "WID_SV_WAITING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SCROLLBAR, "WID_SV_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ACCEPT_RATING_LIST, "WID_SV_ACCEPT_RATING_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_LOCATION, "WID_SV_LOCATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ACCEPTS_RATINGS, "WID_SV_ACCEPTS_RATINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_RENAME, "WID_SV_RENAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_CLOSE_AIRPORT, "WID_SV_CLOSE_AIRPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_TRAINS, "WID_SV_TRAINS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ROADVEHS, "WID_SV_ROADVEHS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SHIPS, "WID_SV_SHIPS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_PLANES, "WID_SV_PLANES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CAPTION, "WID_STL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_LIST, "WID_STL_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SCROLLBAR, "WID_STL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_TRAIN, "WID_STL_TRAIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_TRUCK, "WID_STL_TRUCK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_BUS, "WID_STL_BUS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_AIRPLANE, "WID_STL_AIRPLANE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SHIP, "WID_STL_SHIP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_FACILALL, "WID_STL_FACILALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_NOCARGOWAITING, "WID_STL_NOCARGOWAITING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CARGOALL, "WID_STL_CARGOALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SORTBY, "WID_STL_SORTBY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SORTDROPBTN, "WID_STL_SORTDROPBTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CARGOSTART, "WID_STL_CARGOSTART"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_CAPTION, "WID_JS_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_PANEL, "WID_JS_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_SCROLLBAR, "WID_JS_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_LEFT, "WID_S_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_MIDDLE, "WID_S_MIDDLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_RIGHT, "WID_S_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_CAPTION, "WID_SB_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_SEL_PAGE, "WID_SB_SEL_PAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_PAGE_PANEL, "WID_SB_PAGE_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_SCROLLBAR, "WID_SB_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_PREV_PAGE, "WID_SB_PREV_PAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_NEXT_PAGE, "WID_SB_NEXT_PAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SUL_PANEL, "WID_SUL_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SUL_SCROLLBAR, "WID_SUL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SHOW_PLACE_OBJECT, "WID_TT_SHOW_PLACE_OBJECT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUTTONS_START, "WID_TT_BUTTONS_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LOWER_LAND, "WID_TT_LOWER_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_RAISE_LAND, "WID_TT_RAISE_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LEVEL_LAND, "WID_TT_LEVEL_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_DEMOLISH, "WID_TT_DEMOLISH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUY_LAND, "WID_TT_BUY_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLANT_TREES, "WID_TT_PLANT_TREES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLACE_SIGN, "WID_TT_PLACE_SIGN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLACE_OBJECT, "WID_TT_PLACE_OBJECT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_SHOW_PLACE_DESERT, "WID_ETT_SHOW_PLACE_DESERT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_START, "WID_ETT_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DOTS, "WID_ETT_DOTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_BUTTONS_START, "WID_ETT_BUTTONS_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DEMOLISH, "WID_ETT_DEMOLISH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_LOWER_LAND, "WID_ETT_LOWER_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_RAISE_LAND, "WID_ETT_RAISE_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_LEVEL_LAND, "WID_ETT_LEVEL_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_ROCKS, "WID_ETT_PLACE_ROCKS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_DESERT, "WID_ETT_PLACE_DESERT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_OBJECT, "WID_ETT_PLACE_OBJECT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_BUTTONS_END, "WID_ETT_BUTTONS_END"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_INCREASE_SIZE, "WID_ETT_INCREASE_SIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DECREASE_SIZE, "WID_ETT_DECREASE_SIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_NEW_SCENARIO, "WID_ETT_NEW_SCENARIO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_RESET_LANDSCAPE, "WID_ETT_RESET_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CAPTION, "WID_VT_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ORDER_VIEW, "WID_VT_ORDER_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_TIMETABLE_PANEL, "WID_VT_TIMETABLE_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ARRIVAL_DEPARTURE_PANEL, "WID_VT_ARRIVAL_DEPARTURE_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SCROLLBAR, "WID_VT_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SUMMARY_PANEL, "WID_VT_SUMMARY_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_START_DATE, "WID_VT_START_DATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CHANGE_TIME, "WID_VT_CHANGE_TIME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CLEAR_TIME, "WID_VT_CLEAR_TIME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_RESET_LATENESS, "WID_VT_RESET_LATENESS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_AUTOFILL, "WID_VT_AUTOFILL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_EXPECTED, "WID_VT_EXPECTED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SHARED_ORDER_LIST, "WID_VT_SHARED_ORDER_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ARRIVAL_DEPARTURE_SELECTION, "WID_VT_ARRIVAL_DEPARTURE_SELECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_EXPECTED_SELECTION, "WID_VT_EXPECTED_SELECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CHANGE_SPEED, "WID_VT_CHANGE_SPEED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CLEAR_SPEED, "WID_VT_CLEAR_SPEED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_PAUSE, "WID_TN_PAUSE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_FAST_FORWARD, "WID_TN_FAST_FORWARD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SETTINGS, "WID_TN_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SAVE, "WID_TN_SAVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SMALL_MAP, "WID_TN_SMALL_MAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_TOWNS, "WID_TN_TOWNS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SUBSIDIES, "WID_TN_SUBSIDIES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_STATIONS, "WID_TN_STATIONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_FINANCES, "WID_TN_FINANCES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_COMPANIES, "WID_TN_COMPANIES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_STORY, "WID_TN_STORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_GOAL, "WID_TN_GOAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_GRAPHS, "WID_TN_GRAPHS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_LEAGUE, "WID_TN_LEAGUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_INDUSTRIES, "WID_TN_INDUSTRIES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_VEHICLE_START, "WID_TN_VEHICLE_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_TRAINS, "WID_TN_TRAINS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ROADVEHS, "WID_TN_ROADVEHS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SHIPS, "WID_TN_SHIPS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_AIRCRAFTS, "WID_TN_AIRCRAFTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ZOOM_IN, "WID_TN_ZOOM_IN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ZOOM_OUT, "WID_TN_ZOOM_OUT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_RAILS, "WID_TN_RAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ROADS, "WID_TN_ROADS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_WATER, "WID_TN_WATER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_AIR, "WID_TN_AIR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_LANDSCAPE, "WID_TN_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_MUSIC_SOUND, "WID_TN_MUSIC_SOUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_MESSAGES, "WID_TN_MESSAGES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_HELP, "WID_TN_HELP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SWITCH_BAR, "WID_TN_SWITCH_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_END, "WID_TN_END"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_PAUSE, "WID_TE_PAUSE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_FAST_FORWARD, "WID_TE_FAST_FORWARD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SETTINGS, "WID_TE_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SAVE, "WID_TE_SAVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SPACER, "WID_TE_SPACER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE, "WID_TE_DATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_BACKWARD, "WID_TE_DATE_BACKWARD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_FORWARD, "WID_TE_DATE_FORWARD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SMALL_MAP, "WID_TE_SMALL_MAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ZOOM_IN, "WID_TE_ZOOM_IN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ZOOM_OUT, "WID_TE_ZOOM_OUT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_LAND_GENERATE, "WID_TE_LAND_GENERATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TOWN_GENERATE, "WID_TE_TOWN_GENERATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_INDUSTRY, "WID_TE_INDUSTRY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ROADS, "WID_TE_ROADS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_WATER, "WID_TE_WATER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TREES, "WID_TE_TREES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SIGNS, "WID_TE_SIGNS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_PANEL, "WID_TE_DATE_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_MUSIC_SOUND, "WID_TE_MUSIC_SOUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_HELP, "WID_TE_HELP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SWITCH_BAR, "WID_TE_SWITCH_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_ORDER, "WID_TD_SORT_ORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_CRITERIA, "WID_TD_SORT_CRITERIA"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_LIST, "WID_TD_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SCROLLBAR, "WID_TD_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_WORLD_POPULATION, "WID_TD_WORLD_POPULATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_CAPTION, "WID_TA_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_RATING_INFO, "WID_TA_RATING_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_COMMAND_LIST, "WID_TA_COMMAND_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_SCROLLBAR, "WID_TA_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_ACTION_INFO, "WID_TA_ACTION_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_EXECUTE, "WID_TA_EXECUTE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CAPTION, "WID_TV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_VIEWPORT, "WID_TV_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_INFO, "WID_TV_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CENTER_VIEW, "WID_TV_CENTER_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_SHOW_AUTHORITY, "WID_TV_SHOW_AUTHORITY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CHANGE_NAME, "WID_TV_CHANGE_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_EXPAND, "WID_TV_EXPAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_DELETE, "WID_TV_DELETE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_NEW_TOWN, "WID_TF_NEW_TOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_RANDOM_TOWN, "WID_TF_RANDOM_TOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_MANY_RANDOM_TOWNS, "WID_TF_MANY_RANDOM_TOWNS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_TOWN_NAME_EDITBOX, "WID_TF_TOWN_NAME_EDITBOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_TOWN_NAME_RANDOM, "WID_TF_TOWN_NAME_RANDOM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_SMALL, "WID_TF_SIZE_SMALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_MEDIUM, "WID_TF_SIZE_MEDIUM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_LARGE, "WID_TF_SIZE_LARGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_RANDOM, "WID_TF_SIZE_RANDOM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_CITY, "WID_TF_CITY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_ORIGINAL, "WID_TF_LAYOUT_ORIGINAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_BETTER, "WID_TF_LAYOUT_BETTER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_GRID2, "WID_TF_LAYOUT_GRID2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_GRID3, "WID_TF_LAYOUT_GRID3"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_RANDOM, "WID_TF_LAYOUT_RANDOM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BEGIN, "WID_TT_BEGIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SIGNS, "WID_TT_SIGNS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_TREES, "WID_TT_TREES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_HOUSES, "WID_TT_HOUSES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_INDUSTRIES, "WID_TT_INDUSTRIES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUILDINGS, "WID_TT_BUILDINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BRIDGES, "WID_TT_BRIDGES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_STRUCTURES, "WID_TT_STRUCTURES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_CATENARY, "WID_TT_CATENARY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LOADING, "WID_TT_LOADING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_END, "WID_TT_END"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUTTONS, "WID_TT_BUTTONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_11, "WID_BT_TYPE_11"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_12, "WID_BT_TYPE_12"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_13, "WID_BT_TYPE_13"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_14, "WID_BT_TYPE_14"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_21, "WID_BT_TYPE_21"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_22, "WID_BT_TYPE_22"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_23, "WID_BT_TYPE_23"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_24, "WID_BT_TYPE_24"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_31, "WID_BT_TYPE_31"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_32, "WID_BT_TYPE_32"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_33, "WID_BT_TYPE_33"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_34, "WID_BT_TYPE_34"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_RANDOM, "WID_BT_TYPE_RANDOM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_MANY_RANDOM, "WID_BT_MANY_RANDOM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CAPTION, "WID_VV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_VIEWPORT, "WID_VV_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_START_STOP, "WID_VV_START_STOP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CENTER_MAIN_VIEW, "WID_VV_CENTER_MAIN_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_GOTO_DEPOT, "WID_VV_GOTO_DEPOT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_REFIT, "WID_VV_REFIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SHOW_ORDERS, "WID_VV_SHOW_ORDERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SHOW_DETAILS, "WID_VV_SHOW_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CLONE, "WID_VV_CLONE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SELECT_DEPOT_CLONE, "WID_VV_SELECT_DEPOT_CLONE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SELECT_REFIT_TURN, "WID_VV_SELECT_REFIT_TURN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_TURN_AROUND, "WID_VV_TURN_AROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_FORCE_PROCEED, "WID_VV_FORCE_PROCEED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_CAPTION, "WID_VR_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_VEHICLE_PANEL_DISPLAY, "WID_VR_VEHICLE_PANEL_DISPLAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SHOW_HSCROLLBAR, "WID_VR_SHOW_HSCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_HSCROLLBAR, "WID_VR_HSCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SELECT_HEADER, "WID_VR_SELECT_HEADER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_MATRIX, "WID_VR_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SCROLLBAR, "WID_VR_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_INFO, "WID_VR_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_REFIT, "WID_VR_REFIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_CAPTION, "WID_VD_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_RENAME_VEHICLE, "WID_VD_RENAME_VEHICLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_TOP_DETAILS, "WID_VD_TOP_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_INCREASE_SERVICING_INTERVAL, "WID_VD_INCREASE_SERVICING_INTERVAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DECREASE_SERVICING_INTERVAL, "WID_VD_DECREASE_SERVICING_INTERVAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SERVICE_INTERVAL_DROPDOWN, "WID_VD_SERVICE_INTERVAL_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SERVICING_INTERVAL, "WID_VD_SERVICING_INTERVAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_MIDDLE_DETAILS, "WID_VD_MIDDLE_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_MATRIX, "WID_VD_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SCROLLBAR, "WID_VD_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_CARGO_CARRIED, "WID_VD_DETAILS_CARGO_CARRIED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_TRAIN_VEHICLES, "WID_VD_DETAILS_TRAIN_VEHICLES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_CAPACITY_OF_EACH, "WID_VD_DETAILS_CAPACITY_OF_EACH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_TOTAL_CARGO, "WID_VD_DETAILS_TOTAL_CARGO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_CAPTION, "WID_VL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SORT_ORDER, "WID_VL_SORT_ORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SORT_BY_PULLDOWN, "WID_VL_SORT_BY_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_LIST, "WID_VL_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SCROLLBAR, "WID_VL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_HIDE_BUTTONS, "WID_VL_HIDE_BUTTONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_AVAILABLE_VEHICLES, "WID_VL_AVAILABLE_VEHICLES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_MANAGE_VEHICLES_DROPDOWN, "WID_VL_MANAGE_VEHICLES_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_STOP_ALL, "WID_VL_STOP_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_START_ALL, "WID_VL_START_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_CAPTION, "WID_EV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_VIEWPORT, "WID_EV_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_ZOOM_IN, "WID_EV_ZOOM_IN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_ZOOM_OUT, "WID_EV_ZOOM_OUT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_MAIN_TO_VIEW, "WID_EV_MAIN_TO_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_VIEW_TO_MAIN, "WID_EV_VIEW_TO_MAIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_CAPTION, "WID_W_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_VIEWPORT, "WID_W_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_CENTER_VIEW, "WID_W_CENTER_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_RENAME, "WID_W_RENAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_SHOW_VEHICLES, "WID_W_SHOW_VEHICLES"); + + SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::Close, "Close", 3, ".ii"); + SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::IsOpen, "IsOpen", 3, ".ii"); + SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::Highlight, "Highlight", 5, ".iiii"); + + SQGSWindow.PostRegister(engine); +} diff --git a/src/script/api/script_window.hpp.orig b/src/script/api/script_window.hpp.orig new file mode 100644 index 0000000000..f8bb2a3e42 --- /dev/null +++ b/src/script/api/script_window.hpp.orig @@ -0,0 +1,2579 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file script_window.hpp Everything to handle window interaction. */ + +#ifndef SCRIPT_WINDOW_HPP +#define SCRIPT_WINDOW_HPP + +#include "script_object.hpp" +#include "../../window_type.h" +#include "../../gfx_type.h" + +#include "../../widgets/ai_widget.h" +#include "../../widgets/airport_widget.h" +#include "../../widgets/autoreplace_widget.h" +#include "../../widgets/bootstrap_widget.h" +#include "../../widgets/bridge_widget.h" +#include "../../widgets/build_vehicle_widget.h" +#include "../../widgets/cheat_widget.h" +#include "../../widgets/company_widget.h" +#include "../../widgets/console_widget.h" +#include "../../widgets/date_widget.h" +#include "../../widgets/depot_widget.h" +#include "../../widgets/dock_widget.h" +#include "../../widgets/dropdown_widget.h" +#include "../../widgets/engine_widget.h" +#include "../../widgets/error_widget.h" +#include "../../widgets/fios_widget.h" +#include "../../widgets/genworld_widget.h" +#include "../../widgets/goal_widget.h" +#include "../../widgets/graph_widget.h" +#include "../../widgets/group_widget.h" +#include "../../widgets/highscore_widget.h" +#include "../../widgets/industry_widget.h" +#include "../../widgets/intro_widget.h" +#include "../../widgets/main_widget.h" +#include "../../widgets/misc_widget.h" +#include "../../widgets/music_widget.h" +#include "../../widgets/network_chat_widget.h" +#include "../../widgets/network_content_widget.h" +#include "../../widgets/network_widget.h" +#include "../../widgets/newgrf_debug_widget.h" +#include "../../widgets/newgrf_widget.h" +#include "../../widgets/news_widget.h" +#include "../../widgets/object_widget.h" +#include "../../widgets/order_widget.h" +#include "../../widgets/osk_widget.h" +#include "../../widgets/rail_widget.h" +#include "../../widgets/road_widget.h" +#include "../../widgets/settings_widget.h" +#include "../../widgets/sign_widget.h" +#include "../../widgets/smallmap_widget.h" +#include "../../widgets/station_widget.h" +#include "../../widgets/statusbar_widget.h" +#include "../../widgets/subsidy_widget.h" +#include "../../widgets/terraform_widget.h" +#include "../../widgets/timetable_widget.h" +#include "../../widgets/toolbar_widget.h" +#include "../../widgets/town_widget.h" +#include "../../widgets/transparency_widget.h" +#include "../../widgets/tree_widget.h" +#include "../../widgets/vehicle_widget.h" +#include "../../widgets/viewport_widget.h" +#include "../../widgets/waypoint_widget.h" +#include "../../widgets/link_graph_legend_widget.h" +#include "../../widgets/story_widget.h" + +/** + * Class that handles window interaction. A Window in OpenTTD has two imporant + * values. The WindowClass, and a Window number. The first indicates roughly + * which window it is. WC_TOWN_VIEW for example, is the view of a town. + * The Window number is a bit more complex, as it depends mostly on the + * WindowClass. For example for WC_TOWN_VIEW it is the TownID. In general a + * good rule of thumb is: either the number is always 0, or the ID of the + * object in question. + * In the comment at the widget enum, it is mentioned how the number is used. + * + * Note, that the detailed window layout is very version specific. + * Enum values might be added, changed or removed in future versions without notice + * in the changelog, and there won't be any means of compatibility. + * + * @api game + */ +class ScriptWindow : public ScriptObject { +public: + // @enum WindowNumberEnum ../../window_type.h + /* automatically generated from ../../window_type.h */ + /** %Window numbers. */ + enum WindowNumberEnum { + WN_GAME_OPTIONS_AI = ::WN_GAME_OPTIONS_AI, ///< AI settings. + WN_GAME_OPTIONS_ABOUT = ::WN_GAME_OPTIONS_ABOUT, ///< About window. + WN_GAME_OPTIONS_NEWGRF_STATE = ::WN_GAME_OPTIONS_NEWGRF_STATE, ///< NewGRF settings. + WN_GAME_OPTIONS_GAME_OPTIONS = ::WN_GAME_OPTIONS_GAME_OPTIONS, ///< Game options. + WN_GAME_OPTIONS_GAME_SETTINGS = ::WN_GAME_OPTIONS_GAME_SETTINGS, ///< Game settings. + + WN_QUERY_STRING = ::WN_QUERY_STRING, ///< Query string. + WN_QUERY_STRING_SIGN = ::WN_QUERY_STRING_SIGN, ///< Query string for signs. + + WN_CONFIRM_POPUP_QUERY = ::WN_CONFIRM_POPUP_QUERY, ///< Query popup confirm. + WN_CONFIRM_POPUP_QUERY_BOOTSTRAP = ::WN_CONFIRM_POPUP_QUERY_BOOTSTRAP, ///< Query popup confirm for bootstrap. + + WN_NETWORK_WINDOW_GAME = ::WN_NETWORK_WINDOW_GAME, ///< Network game window. + WN_NETWORK_WINDOW_LOBBY = ::WN_NETWORK_WINDOW_LOBBY, ///< Network lobby window. + WN_NETWORK_WINDOW_CONTENT_LIST = ::WN_NETWORK_WINDOW_CONTENT_LIST, ///< Network content list. + WN_NETWORK_WINDOW_START = ::WN_NETWORK_WINDOW_START, ///< Network start server. + + WN_NETWORK_STATUS_WINDOW_JOIN = ::WN_NETWORK_STATUS_WINDOW_JOIN, ///< Network join status. + WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD = ::WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD, ///< Network content download status. + }; + + // @endenum + + // @enum WindowClass ../../window_type.h + /* automatically generated from ../../window_type.h */ + /** %Window classes. */ + enum WindowClass { + WC_NONE = ::WC_NONE, ///< No window, redirects to WC_MAIN_WINDOW. + + /** + * Main window; %Window numbers: + * - 0 = #MainWidgets + */ + WC_MAIN_WINDOW = ::WC_MAIN_WINDOW, + + /** + * Main toolbar (the long bar at the top); %Window numbers: + * - 0 = #ToolbarNormalWidgets + * - 0 = #ToolbarEditorWidgets + */ + WC_MAIN_TOOLBAR = ::WC_MAIN_TOOLBAR, + + /** + * Statusbar (at the bottom of your screen); %Window numbers: + * - 0 = #StatusbarWidgets + */ + WC_STATUS_BAR = ::WC_STATUS_BAR, + + /** + * Build toolbar; %Window numbers: + * - #TRANSPORT_RAIL = #RailToolbarWidgets + * - #TRANSPORT_AIR = #AirportToolbarWidgets + * - #TRANSPORT_WATER = #DockToolbarWidgets + * - #TRANSPORT_ROAD = #RoadToolbarWidgets + */ + WC_BUILD_TOOLBAR = ::WC_BUILD_TOOLBAR, + + /** + * Scenario build toolbar; %Window numbers: + * - #TRANSPORT_WATER = #DockToolbarWidgets + * - #TRANSPORT_ROAD = #RoadToolbarWidgets + */ + WC_SCEN_BUILD_TOOLBAR = ::WC_SCEN_BUILD_TOOLBAR, + + /** + * Build trees toolbar; %Window numbers: + * - 0 = #BuildTreesWidgets + */ + WC_BUILD_TREES = ::WC_BUILD_TREES, + + /** + * Transparency toolbar; %Window numbers: + * - 0 = #TransparencyToolbarWidgets + */ + WC_TRANSPARENCY_TOOLBAR = ::WC_TRANSPARENCY_TOOLBAR, + + /** + * Build signal toolbar; %Window numbers: + * - #TRANSPORT_RAIL = #BuildSignalWidgets + */ + WC_BUILD_SIGNAL = ::WC_BUILD_SIGNAL, + + /** + * Small map; %Window numbers: + * - 0 = #SmallMapWidgets + */ + WC_SMALLMAP = ::WC_SMALLMAP, + + /** + * Error message; %Window numbers: + * - 0 = #ErrorMessageWidgets + */ + WC_ERRMSG = ::WC_ERRMSG, + + /** + * Tooltip window; %Window numbers: + * - 0 = #ToolTipsWidgets + */ + WC_TOOLTIPS = ::WC_TOOLTIPS, + + /** + * Query string window; %Window numbers: + * - #WN_QUERY_STRING = #QueryStringWidgets + * - #WN_QUERY_STRING_SIGN = #QueryEditSignWidgets + */ + WC_QUERY_STRING = ::WC_QUERY_STRING, + + /** + * Popup with confirm question; %Window numbers: + * - #WN_CONFIRM_POPUP_QUERY = #QueryWidgets + * - #WN_CONFIRM_POPUP_QUERY_BOOTSTRAP = #BootstrapAskForDownloadWidgets + */ + WC_CONFIRM_POPUP_QUERY = ::WC_CONFIRM_POPUP_QUERY, + + /** + * Popup with a set of buttons, designed to ask the user a question + * from a GameScript. %Window numbers: + * - uniqueid = #GoalQuestionWidgets + */ + WC_GOAL_QUESTION = ::WC_GOAL_QUESTION, + + + /** + * Saveload window; %Window numbers: + * - 0 = #SaveLoadWidgets + */ + WC_SAVELOAD = ::WC_SAVELOAD, + + /** + * Land info window; %Window numbers: + * - 0 = #LandInfoWidgets + */ + WC_LAND_INFO = ::WC_LAND_INFO, + + /** + * Drop down menu; %Window numbers: + * - 0 = #DropdownMenuWidgets + */ + WC_DROPDOWN_MENU = ::WC_DROPDOWN_MENU, + + /** + * On Screen Keyboard; %Window numbers: + * - 0 = #OnScreenKeyboardWidgets + */ + WC_OSK = ::WC_OSK, + + /** + * Set date; %Window numbers: + * - #VehicleID = #SetDateWidgets + */ + WC_SET_DATE = ::WC_SET_DATE, + + + /** + * AI settings; %Window numbers: + * - 0 = #AISettingsWidgets + */ + WC_AI_SETTINGS = ::WC_AI_SETTINGS, + + /** + * NewGRF parameters; %Window numbers: + * - 0 = #NewGRFParametersWidgets + */ + WC_GRF_PARAMETERS = ::WC_GRF_PARAMETERS, + + /** + * textfile; %Window numbers: + * - 0 = #TextfileWidgets + */ + WC_TEXTFILE = ::WC_TEXTFILE, + + + /** + * Town authority; %Window numbers: + * - #TownID = #TownAuthorityWidgets + */ + WC_TOWN_AUTHORITY = ::WC_TOWN_AUTHORITY, + + /** + * Vehicle details; %Window numbers: + * - #VehicleID = #VehicleDetailsWidgets + */ + WC_VEHICLE_DETAILS = ::WC_VEHICLE_DETAILS, + + /** + * Vehicle refit; %Window numbers: + * - #VehicleID = #VehicleRefitWidgets + */ + WC_VEHICLE_REFIT = ::WC_VEHICLE_REFIT, + + /** + * Vehicle orders; %Window numbers: + * - #VehicleID = #OrderWidgets + */ + WC_VEHICLE_ORDERS = ::WC_VEHICLE_ORDERS, + + /** + * Replace vehicle window; %Window numbers: + * - #VehicleType = #ReplaceVehicleWidgets + */ + WC_REPLACE_VEHICLE = ::WC_REPLACE_VEHICLE, + + /** + * Vehicle timetable; %Window numbers: + * - #VehicleID = #VehicleTimetableWidgets + */ + WC_VEHICLE_TIMETABLE = ::WC_VEHICLE_TIMETABLE, + + /** + * Company colour selection; %Window numbers: + * - #CompanyID = #SelectCompanyLiveryWidgets + */ + WC_COMPANY_COLOUR = ::WC_COMPANY_COLOUR, + + /** + * Alter company face window; %Window numbers: + * - #CompanyID = #SelectCompanyManagerFaceWidgets + */ + WC_COMPANY_MANAGER_FACE = ::WC_COMPANY_MANAGER_FACE, + + /** + * Select station (when joining stations); %Window numbers: + * - 0 = #JoinStationWidgets + */ + WC_SELECT_STATION = ::WC_SELECT_STATION, + + /** + * News window; %Window numbers: + * - 0 = #NewsWidgets + */ + WC_NEWS_WINDOW = ::WC_NEWS_WINDOW, + + /** + * Town directory; %Window numbers: + * - 0 = #TownDirectoryWidgets + */ + WC_TOWN_DIRECTORY = ::WC_TOWN_DIRECTORY, + + /** + * Subsidies list; %Window numbers: + * - 0 = #SubsidyListWidgets + */ + WC_SUBSIDIES_LIST = ::WC_SUBSIDIES_LIST, + + /** + * Industry directory; %Window numbers: + * - 0 = #IndustryDirectoryWidgets + */ + WC_INDUSTRY_DIRECTORY = ::WC_INDUSTRY_DIRECTORY, + + /** + * News history list; %Window numbers: + * - 0 = #MessageHistoryWidgets + */ + WC_MESSAGE_HISTORY = ::WC_MESSAGE_HISTORY, + + /** + * Sign list; %Window numbers: + * - 0 = #SignListWidgets + */ + WC_SIGN_LIST = ::WC_SIGN_LIST, + + /** + * AI list; %Window numbers: + * - 0 = #AIListWidgets + */ + WC_AI_LIST = ::WC_AI_LIST, + + /** + * Goals list; %Window numbers: + * - 0 ; #GoalListWidgets + */ + WC_GOALS_LIST = ::WC_GOALS_LIST, + + /** + * Story book; %Window numbers: + * - CompanyID = #StoryBookWidgets + */ + WC_STORY_BOOK = ::WC_STORY_BOOK, + + /** + * Station list; %Window numbers: + * - #CompanyID = #StationListWidgets + */ + WC_STATION_LIST = ::WC_STATION_LIST, + + /** + * Trains list; %Window numbers: + * - Packed value = #GroupListWidgets / #VehicleListWidgets + */ + WC_TRAINS_LIST = ::WC_TRAINS_LIST, + + /** + * Road vehicle list; %Window numbers: + * - Packed value = #GroupListWidgets / #VehicleListWidgets + */ + WC_ROADVEH_LIST = ::WC_ROADVEH_LIST, + + /** + * Ships list; %Window numbers: + * - Packed value = #GroupListWidgets / #VehicleListWidgets + */ + WC_SHIPS_LIST = ::WC_SHIPS_LIST, + + /** + * Aircraft list; %Window numbers: + * - Packed value = #GroupListWidgets / #VehicleListWidgets + */ + WC_AIRCRAFT_LIST = ::WC_AIRCRAFT_LIST, + + + /** + * Town view; %Window numbers: + * - #TownID = #TownViewWidgets + */ + WC_TOWN_VIEW = ::WC_TOWN_VIEW, + + /** + * Vehicle view; %Window numbers: + * - #VehicleID = #VehicleViewWidgets + */ + WC_VEHICLE_VIEW = ::WC_VEHICLE_VIEW, + + /** + * Station view; %Window numbers: + * - #StationID = #StationViewWidgets + */ + WC_STATION_VIEW = ::WC_STATION_VIEW, + + /** + * Depot view; %Window numbers: + * - #TileIndex = #DepotWidgets + */ + WC_VEHICLE_DEPOT = ::WC_VEHICLE_DEPOT, + + /** + * Waypoint view; %Window numbers: + * - #WaypointID = #WaypointWidgets + */ + WC_WAYPOINT_VIEW = ::WC_WAYPOINT_VIEW, + + /** + * Industry view; %Window numbers: + * - #IndustryID = #IndustryViewWidgets + */ + WC_INDUSTRY_VIEW = ::WC_INDUSTRY_VIEW, + + /** + * Company view; %Window numbers: + * - #CompanyID = #CompanyWidgets + */ + WC_COMPANY = ::WC_COMPANY, + + + /** + * Build object; %Window numbers: + * - 0 = #BuildObjectWidgets + */ + WC_BUILD_OBJECT = ::WC_BUILD_OBJECT, + + /** + * Build vehicle; %Window numbers: + * - #VehicleType = #BuildVehicleWidgets + * - #TileIndex = #BuildVehicleWidgets + */ + WC_BUILD_VEHICLE = ::WC_BUILD_VEHICLE, + + /** + * Build bridge; %Window numbers: + * - #TransportType = #BuildBridgeSelectionWidgets + */ + WC_BUILD_BRIDGE = ::WC_BUILD_BRIDGE, + + /** + * Build station; %Window numbers: + * - #TRANSPORT_AIR = #AirportPickerWidgets + * - #TRANSPORT_WATER = #DockToolbarWidgets + * - #TRANSPORT_RAIL = #BuildRailStationWidgets + */ + WC_BUILD_STATION = ::WC_BUILD_STATION, + + /** + * Build bus station; %Window numbers: + * - #TRANSPORT_ROAD = #BuildRoadStationWidgets + */ + WC_BUS_STATION = ::WC_BUS_STATION, + + /** + * Build truck station; %Window numbers: + * - #TRANSPORT_ROAD = #BuildRoadStationWidgets + */ + WC_TRUCK_STATION = ::WC_TRUCK_STATION, + + /** + * Build depot; %Window numbers: + * - #TRANSPORT_WATER = #BuildDockDepotWidgets + * - #TRANSPORT_RAIL = #BuildRailDepotWidgets + * - #TRANSPORT_ROAD = #BuildRoadDepotWidgets + */ + WC_BUILD_DEPOT = ::WC_BUILD_DEPOT, + + /** + * Build waypoint; %Window numbers: + * - #TRANSPORT_RAIL = #BuildRailWaypointWidgets + */ + WC_BUILD_WAYPOINT = ::WC_BUILD_WAYPOINT, + + /** + * Found a town; %Window numbers: + * - 0 = #TownFoundingWidgets + */ + WC_FOUND_TOWN = ::WC_FOUND_TOWN, + + /** + * Build industry; %Window numbers: + * - 0 = #DynamicPlaceIndustriesWidgets + */ + WC_BUILD_INDUSTRY = ::WC_BUILD_INDUSTRY, + + + /** + * Select game window; %Window numbers: + * - 0 = #SelectGameIntroWidgets + */ + WC_SELECT_GAME = ::WC_SELECT_GAME, + + /** + * Landscape generation (in Scenario Editor); %Window numbers: + * - 0 = #TerraformToolbarWidgets + * - 0 = #EditorTerraformToolbarWidgets + */ + WC_SCEN_LAND_GEN = ::WC_SCEN_LAND_GEN, + + /** + * Generate landscape (newgame); %Window numbers: + * - GLWM_SCENARIO = #CreateScenarioWidgets + * - #GenenerateLandscapeWindowMode = #GenerateLandscapeWidgets + */ + WC_GENERATE_LANDSCAPE = ::WC_GENERATE_LANDSCAPE, + + /** + * Progress report of landscape generation; %Window numbers: + * - 0 = #GenerationProgressWidgets + * - 1 = #ScanProgressWidgets + */ + WC_MODAL_PROGRESS = ::WC_MODAL_PROGRESS, + + + /** + * Network window; %Window numbers: + * - #WN_NETWORK_WINDOW_GAME = #NetworkGameWidgets + * - #WN_NETWORK_WINDOW_LOBBY = #NetworkLobbyWidgets + * - #WN_NETWORK_WINDOW_CONTENT_LIST = #NetworkContentListWidgets + * - #WN_NETWORK_WINDOW_START = #NetworkStartServerWidgets + */ + WC_NETWORK_WINDOW = ::WC_NETWORK_WINDOW, + + /** + * Client list; %Window numbers: + * - 0 = #ClientListWidgets + */ + WC_CLIENT_LIST = ::WC_CLIENT_LIST, + + /** + * Popup for the client list; %Window numbers: + * - #ClientID = #ClientListPopupWidgets + */ + WC_CLIENT_LIST_POPUP = ::WC_CLIENT_LIST_POPUP, + + /** + * Network status window; %Window numbers: + * - #WN_NETWORK_STATUS_WINDOW_JOIN = #NetworkJoinStatusWidgets + * - #WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD = #NetworkContentDownloadStatusWidgets + */ + WC_NETWORK_STATUS_WINDOW = ::WC_NETWORK_STATUS_WINDOW, + + /** + * Chatbox; %Window numbers: + * - #DestType = #NetWorkChatWidgets + */ + WC_SEND_NETWORK_MSG = ::WC_SEND_NETWORK_MSG, + + /** + * Company password query; %Window numbers: + * - 0 = #NetworkCompanyPasswordWidgets + */ + WC_COMPANY_PASSWORD_WINDOW = ::WC_COMPANY_PASSWORD_WINDOW, + + + /** + * Industry cargoes chain; %Window numbers: + * - 0 = #IndustryCargoesWidgets + */ + WC_INDUSTRY_CARGOES = ::WC_INDUSTRY_CARGOES, + + /** + * Legend for graphs; %Window numbers: + * - 0 = #GraphLegendWidgets + */ + WC_GRAPH_LEGEND = ::WC_GRAPH_LEGEND, + + /** + * Finances of a company; %Window numbers: + * - #CompanyID = #CompanyWidgets + */ + WC_FINANCES = ::WC_FINANCES, + + /** + * Income graph; %Window numbers: + * - 0 = #CompanyValueWidgets + */ + WC_INCOME_GRAPH = ::WC_INCOME_GRAPH, + + /** + * Operating profit graph; %Window numbers: + * - 0 = #CompanyValueWidgets + */ + WC_OPERATING_PROFIT = ::WC_OPERATING_PROFIT, + + /** + * Delivered cargo graph; %Window numbers: + * - 0 = #CompanyValueWidgets + */ + WC_DELIVERED_CARGO = ::WC_DELIVERED_CARGO, + + /** + * Performance history graph; %Window numbers: + * - 0 = #PerformanceHistoryGraphWidgets + */ + WC_PERFORMANCE_HISTORY = ::WC_PERFORMANCE_HISTORY, + + /** + * Company value graph; %Window numbers: + * - 0 = #CompanyValueWidgets + */ + WC_COMPANY_VALUE = ::WC_COMPANY_VALUE, + + /** + * Company league window; %Window numbers: + * - 0 = #CompanyLeagueWidgets + */ + WC_COMPANY_LEAGUE = ::WC_COMPANY_LEAGUE, + + /** + * Payment rates graph; %Window numbers: + * - 0 = #CargoPaymentRatesWidgets + */ + WC_PAYMENT_RATES = ::WC_PAYMENT_RATES, + + /** + * Performance detail window; %Window numbers: + * - 0 = #PerformanceRatingDetailsWidgets + */ + WC_PERFORMANCE_DETAIL = ::WC_PERFORMANCE_DETAIL, + + /** + * Company infrastructure overview; %Window numbers: + * - #CompanyID = #CompanyInfrastructureWidgets + */ + WC_COMPANY_INFRASTRUCTURE = ::WC_COMPANY_INFRASTRUCTURE, + + + /** + * Buyout company (merger); %Window numbers: + * - #CompanyID = #BuyCompanyWidgets + */ + WC_BUY_COMPANY = ::WC_BUY_COMPANY, + + /** + * Engine preview window; %Window numbers: + * - #EngineID = #EnginePreviewWidgets + */ + WC_ENGINE_PREVIEW = ::WC_ENGINE_PREVIEW, + + + /** + * Music window; %Window numbers: + * - 0 = #MusicWidgets + */ + WC_MUSIC_WINDOW = ::WC_MUSIC_WINDOW, + + /** + * Music track selection; %Window numbers: + * - 0 = MusicTrackSelectionWidgets + */ + WC_MUSIC_TRACK_SELECTION = ::WC_MUSIC_TRACK_SELECTION, + + /** + * Game options window; %Window numbers: + * - #WN_GAME_OPTIONS_AI = #AIConfigWidgets + * - #WN_GAME_OPTIONS_ABOUT = #AboutWidgets + * - #WN_GAME_OPTIONS_NEWGRF_STATE = #NewGRFStateWidgets + * - #WN_GAME_OPTIONS_GAME_OPTIONS = #GameOptionsWidgets + * - #WN_GAME_OPTIONS_GAME_SETTINGS = #GameSettingsWidgets + */ + WC_GAME_OPTIONS = ::WC_GAME_OPTIONS, + + /** + * Custom currency; %Window numbers: + * - 0 = #CustomCurrencyWidgets + */ + WC_CUSTOM_CURRENCY = ::WC_CUSTOM_CURRENCY, + + /** + * Cheat window; %Window numbers: + * - 0 = #CheatWidgets + */ + WC_CHEATS = ::WC_CHEATS, + + /** + * Extra viewport; %Window numbers: + * - Ascending value = #ExtraViewportWidgets + */ + WC_EXTRA_VIEW_PORT = ::WC_EXTRA_VIEW_PORT, + + + /** + * Console; %Window numbers: + * - 0 = #ConsoleWidgets + */ + WC_CONSOLE = ::WC_CONSOLE, + + /** + * Bootstrap; %Window numbers: + * - 0 = #BootstrapBackgroundWidgets + */ + WC_BOOTSTRAP = ::WC_BOOTSTRAP, + + /** + * Highscore; %Window numbers: + * - 0 = #HighscoreWidgets + */ + WC_HIGHSCORE = ::WC_HIGHSCORE, + + /** + * Endscreen; %Window numbers: + * - 0 = #HighscoreWidgets + */ + WC_ENDSCREEN = ::WC_ENDSCREEN, + + + /** + * AI debug window; %Window numbers: + * - 0 = #AIDebugWidgets + */ + WC_AI_DEBUG = ::WC_AI_DEBUG, + + /** + * NewGRF inspect (debug); %Window numbers: + * - Packed value = #NewGRFInspectWidgets + */ + WC_NEWGRF_INSPECT = ::WC_NEWGRF_INSPECT, + + /** + * Sprite aligner (debug); %Window numbers: + * - 0 = #SpriteAlignerWidgets + */ + WC_SPRITE_ALIGNER = ::WC_SPRITE_ALIGNER, + + /** + * Linkgraph legend; Window numbers: + * - 0 = #LinkGraphWidgets + */ + WC_LINKGRAPH_LEGEND = ::WC_LINKGRAPH_LEGEND, + + WC_INVALID = ::WC_INVALID, ///< Invalid window. + }; + + // @endenum + + /** + * The colours in the game which you can use for text and highlights. + */ + enum TextColour { + /* Note: these values represent part of the in-game TextColour enum */ + TC_BLUE = ::TC_BLUE, ///< Blue colour. + TC_SILVER = ::TC_SILVER, ///< Silver colour. + TC_GOLD = ::TC_GOLD, ///< Gold colour. + TC_RED = ::TC_RED, ///< Red colour. + TC_PURPLE = ::TC_PURPLE, ///< Purple colour. + TC_LIGHT_BROWN = ::TC_LIGHT_BROWN, ///< Light brown colour. + TC_ORANGE = ::TC_ORANGE, ///< Orange colour. + TC_GREEN = ::TC_GREEN, ///< Green colour. + TC_YELLOW = ::TC_YELLOW, ///< Yellow colour. + TC_DARK_GREEN = ::TC_DARK_GREEN, ///< Dark green colour. + TC_CREAM = ::TC_CREAM, ///< Cream colour. + TC_BROWN = ::TC_BROWN, ///< Brown colour. + TC_WHITE = ::TC_WHITE, ///< White colour. + TC_LIGHT_BLUE = ::TC_LIGHT_BLUE, ///< Light blue colour. + TC_GREY = ::TC_GREY, ///< Grey colour. + TC_DARK_BLUE = ::TC_DARK_BLUE, ///< Dark blue colour. + TC_BLACK = ::TC_BLACK, ///< Black colour. + TC_INVALID = ::TC_INVALID, ///< Invalid colour. + }; + + /** + * Special number values. + */ + enum NumberType { + NUMBER_ALL = 0xFFFFFFFF, ///< Value to select all windows of a class. + }; + + /** + * Special widget values. + */ + enum WidgetType { + WIDGET_ALL = 0xFF, ///< Value to select all widgets of a window. + }; + + /** + * Close a window. + * @param window The class of the window to close. + * @param number The number of the window to close, or NUMBER_ALL to close all of this class. + * @pre !ScriptGame::IsMultiplayer(). + */ + static void Close(WindowClass window, uint32 number); + + /** + * Check if a window is open. + * @param window The class of the window to check for. + * @param number The number of the window to check for, or NUMBER_ALL to check for any in the class. + * @pre !ScriptGame::IsMultiplayer(). + * @return True if the window is open. + */ + static bool IsOpen(WindowClass window, uint32 number); + + /** + * Highlight a widget in a window. + * @param window The class of the window to highlight a widget in. + * @param number The number of the window to highlight a widget in. + * @param widget The widget in the window to highlight, or WIDGET_ALL (in combination with TC_INVALID) to disable all widget highlighting on this window. + * @param colour The colour of the highlight, or TC_INVALID for disabling. + * @pre !ScriptGame::IsMultiplayer(). + * @pre number != NUMBER_ALL. + * @pre colour < TC_END || (widget == WIDGET_ALL && colour == TC_INVALID). + * @pre IsOpen(window, number). + */ + static void Highlight(WindowClass window, uint32 number, uint8 widget, TextColour colour); + + // @enum .*Widgets ../../widgets/*_widget.h + /* automatically generated from ../../widgets/ai_widget.h */ + /** Widgets of the #AIListWindow class. */ + enum AIListWidgets { + WID_AIL_CAPTION = ::WID_AIL_CAPTION, ///< Caption of the window. + WID_AIL_LIST = ::WID_AIL_LIST, ///< The matrix with all available AIs. + WID_AIL_SCROLLBAR = ::WID_AIL_SCROLLBAR, ///< Scrollbar next to the AI list. + WID_AIL_INFO_BG = ::WID_AIL_INFO_BG, ///< Panel to draw some AI information on. + WID_AIL_ACCEPT = ::WID_AIL_ACCEPT, ///< Accept button. + WID_AIL_CANCEL = ::WID_AIL_CANCEL, ///< Cancel button. + }; + + /** Widgets of the #AISettingsWindow class. */ + enum AISettingsWidgets { + WID_AIS_CAPTION = ::WID_AIS_CAPTION, ///< Caption of the window. + WID_AIS_BACKGROUND = ::WID_AIS_BACKGROUND, ///< Panel to draw the settings on. + WID_AIS_SCROLLBAR = ::WID_AIS_SCROLLBAR, ///< Scrollbar to scroll through all settings. + WID_AIS_ACCEPT = ::WID_AIS_ACCEPT, ///< Accept button. + WID_AIS_RESET = ::WID_AIS_RESET, ///< Reset button. + }; + + /** Widgets of the #AIConfigWindow class. */ + enum AIConfigWidgets { + WID_AIC_BACKGROUND = ::WID_AIC_BACKGROUND, ///< Window background. + WID_AIC_DECREASE = ::WID_AIC_DECREASE, ///< Decrease the number of AIs. + WID_AIC_INCREASE = ::WID_AIC_INCREASE, ///< Increase the number of AIs. + WID_AIC_NUMBER = ::WID_AIC_NUMBER, ///< Number of AIs. + WID_AIC_GAMELIST = ::WID_AIC_GAMELIST, ///< List with current selected GameScript. + WID_AIC_LIST = ::WID_AIC_LIST, ///< List with currently selected AIs. + WID_AIC_SCROLLBAR = ::WID_AIC_SCROLLBAR, ///< Scrollbar to scroll through the selected AIs. + WID_AIC_MOVE_UP = ::WID_AIC_MOVE_UP, ///< Move up button. + WID_AIC_MOVE_DOWN = ::WID_AIC_MOVE_DOWN, ///< Move down button. + WID_AIC_CHANGE = ::WID_AIC_CHANGE, ///< Select another AI button. + WID_AIC_CONFIGURE = ::WID_AIC_CONFIGURE, ///< Change AI settings button. + WID_AIC_CLOSE = ::WID_AIC_CLOSE, ///< Close window button. + WID_AIC_TEXTFILE = ::WID_AIC_TEXTFILE, ///< Open AI readme, changelog (+1) or license (+2). + WID_AIC_CONTENT_DOWNLOAD = ::WID_AIC_CONTENT_DOWNLOAD, ///< Download content button. + }; + + /** Widgets of the #AIDebugWindow class. */ + enum AIDebugWidgets { + WID_AID_VIEW = ::WID_AID_VIEW, ///< The row of company buttons. + WID_AID_NAME_TEXT = ::WID_AID_NAME_TEXT, ///< Name of the current selected. + WID_AID_SETTINGS = ::WID_AID_SETTINGS, ///< Settings button. + WID_AID_SCRIPT_GAME = ::WID_AID_SCRIPT_GAME, ///< Game Script button. + WID_AID_RELOAD_TOGGLE = ::WID_AID_RELOAD_TOGGLE, ///< Reload button. + WID_AID_LOG_PANEL = ::WID_AID_LOG_PANEL, ///< Panel where the log is in. + WID_AID_SCROLLBAR = ::WID_AID_SCROLLBAR, ///< Scrollbar of the log panel. + WID_AID_COMPANY_BUTTON_START = ::WID_AID_COMPANY_BUTTON_START, ///< Buttons in the VIEW. + WID_AID_COMPANY_BUTTON_END = ::WID_AID_COMPANY_BUTTON_END, ///< Last possible button in the VIEW. + WID_AID_BREAK_STRING_WIDGETS = ::WID_AID_BREAK_STRING_WIDGETS, ///< The panel to handle the breaking on string. + WID_AID_BREAK_STR_ON_OFF_BTN = ::WID_AID_BREAK_STR_ON_OFF_BTN, ///< Enable breaking on string. + WID_AID_BREAK_STR_EDIT_BOX = ::WID_AID_BREAK_STR_EDIT_BOX, ///< Edit box for the string to break on. + WID_AID_MATCH_CASE_BTN = ::WID_AID_MATCH_CASE_BTN, ///< Checkbox to use match caching or not. + WID_AID_CONTINUE_BTN = ::WID_AID_CONTINUE_BTN, ///< Continue button. + }; + + /* automatically generated from ../../widgets/airport_widget.h */ + /** Widgets of the #BuildAirToolbarWindow class. */ + enum AirportToolbarWidgets { + WID_AT_AIRPORT = ::WID_AT_AIRPORT, ///< Build airport button. + WID_AT_DEMOLISH = ::WID_AT_DEMOLISH, ///< Demolish button. + }; + + /** Widgets of the #BuildAirportWindow class. */ + enum AirportPickerWidgets { + WID_AP_CLASS_DROPDOWN = ::WID_AP_CLASS_DROPDOWN, ///< Dropdown of airport classes. + WID_AP_AIRPORT_LIST = ::WID_AP_AIRPORT_LIST, ///< List of airports. + WID_AP_SCROLLBAR = ::WID_AP_SCROLLBAR, ///< Scrollbar of the list. + WID_AP_LAYOUT_NUM = ::WID_AP_LAYOUT_NUM, ///< Current number of the layout. + WID_AP_LAYOUT_DECREASE = ::WID_AP_LAYOUT_DECREASE, ///< Decrease the layout number. + WID_AP_LAYOUT_INCREASE = ::WID_AP_LAYOUT_INCREASE, ///< Increase the layout number. + WID_AP_AIRPORT_SPRITE = ::WID_AP_AIRPORT_SPRITE, ///< A visual display of the airport currently selected. + WID_AP_EXTRA_TEXT = ::WID_AP_EXTRA_TEXT, ///< Additional text about the airport. + WID_AP_BOTTOMPANEL = ::WID_AP_BOTTOMPANEL, ///< Panel at the bottom. + WID_AP_COVERAGE_LABEL = ::WID_AP_COVERAGE_LABEL, ///< Label if you want to see the coverage. + WID_AP_BTN_DONTHILIGHT = ::WID_AP_BTN_DONTHILIGHT, ///< Don't show the coverage button. + WID_AP_BTN_DOHILIGHT = ::WID_AP_BTN_DOHILIGHT, ///< Show the coverage button. + }; + + /* automatically generated from ../../widgets/autoreplace_widget.h */ + /** Widgets of the #ReplaceVehicleWindow class. */ + enum ReplaceVehicleWidgets { + WID_RV_CAPTION = ::WID_RV_CAPTION, ///< Caption of the window. + + /* Left and right matrix + details. */ + WID_RV_LEFT_MATRIX = ::WID_RV_LEFT_MATRIX, ///< The matrix on the left. + WID_RV_LEFT_SCROLLBAR = ::WID_RV_LEFT_SCROLLBAR, ///< The scrollbar for the matrix on the left. + WID_RV_RIGHT_MATRIX = ::WID_RV_RIGHT_MATRIX, ///< The matrix on the right. + WID_RV_RIGHT_SCROLLBAR = ::WID_RV_RIGHT_SCROLLBAR, ///< The scrollbar for the matrix on the right. + WID_RV_LEFT_DETAILS = ::WID_RV_LEFT_DETAILS, ///< Details of the entry on the left. + WID_RV_RIGHT_DETAILS = ::WID_RV_RIGHT_DETAILS, ///< Details of the entry on the right. + + /* Button row. */ + WID_RV_START_REPLACE = ::WID_RV_START_REPLACE, ///< Start Replacing button. + WID_RV_INFO_TAB = ::WID_RV_INFO_TAB, ///< Info tab. + WID_RV_STOP_REPLACE = ::WID_RV_STOP_REPLACE, ///< Stop Replacing button. + + /* Train only widgets. */ + WID_RV_TRAIN_ENGINEWAGON_TOGGLE = ::WID_RV_TRAIN_ENGINEWAGON_TOGGLE, ///< Button to toggle engines and/or wagons. + WID_RV_TRAIN_FLUFF_LEFT = ::WID_RV_TRAIN_FLUFF_LEFT, ///< The fluff on the left. + WID_RV_TRAIN_RAILTYPE_DROPDOWN = ::WID_RV_TRAIN_RAILTYPE_DROPDOWN, ///< Dropdown menu about the railtype. + WID_RV_TRAIN_FLUFF_RIGHT = ::WID_RV_TRAIN_FLUFF_RIGHT, ///< The fluff on the right. + WID_RV_TRAIN_WAGONREMOVE_TOGGLE = ::WID_RV_TRAIN_WAGONREMOVE_TOGGLE, ///< Button to toggle removing wagons. + }; + + /* automatically generated from ../../widgets/bootstrap_widget.h */ + /** Widgets of the #BootstrapBackground class. */ + enum BootstrapBackgroundWidgets { + WID_BB_BACKGROUND = ::WID_BB_BACKGROUND, ///< Background of the window. + }; + + /** Widgets of the #BootstrapContentDownloadStatusWindow class. */ + enum BootstrapAskForDownloadWidgets { + WID_BAFD_QUESTION = ::WID_BAFD_QUESTION, ///< The question whether to download. + WID_BAFD_YES = ::WID_BAFD_YES, ///< An affirmative answer to the question. + WID_BAFD_NO = ::WID_BAFD_NO, ///< An negative answer to the question. + }; + + /* automatically generated from ../../widgets/bridge_widget.h */ + /** Widgets of the #BuildBridgeWindow class. */ + enum BuildBridgeSelectionWidgets { + WID_BBS_CAPTION = ::WID_BBS_CAPTION, ///< Caption of the window. + WID_BBS_DROPDOWN_ORDER = ::WID_BBS_DROPDOWN_ORDER, ///< Direction of sort dropdown. + WID_BBS_DROPDOWN_CRITERIA = ::WID_BBS_DROPDOWN_CRITERIA, ///< Criteria of sort dropdown. + WID_BBS_BRIDGE_LIST = ::WID_BBS_BRIDGE_LIST, ///< List of bridges. + WID_BBS_SCROLLBAR = ::WID_BBS_SCROLLBAR, ///< Scrollbar of the list. + }; + + /* automatically generated from ../../widgets/build_vehicle_widget.h */ + /** Widgets of the #BuildVehicleWindow class. */ + enum BuildVehicleWidgets { + WID_BV_CAPTION = ::WID_BV_CAPTION, ///< Caption of window. + WID_BV_SORT_ASSENDING_DESCENDING = ::WID_BV_SORT_ASSENDING_DESCENDING, ///< Sort direction. + WID_BV_SORT_DROPDOWN = ::WID_BV_SORT_DROPDOWN, ///< Criteria of sorting dropdown. + WID_BV_CARGO_FILTER_DROPDOWN = ::WID_BV_CARGO_FILTER_DROPDOWN, ///< Cargo filter dropdown. + WID_BV_LIST = ::WID_BV_LIST, ///< List of vehicles. + WID_BV_SCROLLBAR = ::WID_BV_SCROLLBAR, ///< Scrollbar of list. + WID_BV_PANEL = ::WID_BV_PANEL, ///< Button panel. + WID_BV_BUILD = ::WID_BV_BUILD, ///< Build panel. + WID_BV_BUILD_SEL = ::WID_BV_BUILD_SEL, ///< Build button. + WID_BV_RENAME = ::WID_BV_RENAME, ///< Rename button. + }; + + /* automatically generated from ../../widgets/cheat_widget.h */ + /** Widgets of the #CheatWindow class.. */ + enum CheatWidgets { + WID_C_PANEL = ::WID_C_PANEL, ///< Panel where all cheats are shown in. + }; + + /* automatically generated from ../../widgets/company_widget.h */ + /** Widgets of the #CompanyWindow class. */ + enum CompanyWidgets { + WID_C_CAPTION = ::WID_C_CAPTION, ///< Caption of the window. + + WID_C_FACE = ::WID_C_FACE, ///< View of the face. + WID_C_FACE_TITLE = ::WID_C_FACE_TITLE, ///< Title for the face. + + WID_C_DESC_INAUGURATION = ::WID_C_DESC_INAUGURATION, ///< Inauguration. + WID_C_DESC_COLOUR_SCHEME = ::WID_C_DESC_COLOUR_SCHEME, ///< Colour scheme. + WID_C_DESC_COLOUR_SCHEME_EXAMPLE = ::WID_C_DESC_COLOUR_SCHEME_EXAMPLE, ///< Colour scheme example. + WID_C_DESC_VEHICLE = ::WID_C_DESC_VEHICLE, ///< Vehicles. + WID_C_DESC_VEHICLE_COUNTS = ::WID_C_DESC_VEHICLE_COUNTS, ///< Vehicle count. + WID_C_DESC_COMPANY_VALUE = ::WID_C_DESC_COMPANY_VALUE, ///< Company value. + WID_C_DESC_INFRASTRUCTURE = ::WID_C_DESC_INFRASTRUCTURE, ///< Infrastructure. + WID_C_DESC_INFRASTRUCTURE_COUNTS = ::WID_C_DESC_INFRASTRUCTURE_COUNTS, ///< Infrastructure count. + + WID_C_SELECT_DESC_OWNERS = ::WID_C_SELECT_DESC_OWNERS, ///< Owners. + WID_C_DESC_OWNERS = ::WID_C_DESC_OWNERS, ///< Owner in Owners. + + WID_C_SELECT_BUTTONS = ::WID_C_SELECT_BUTTONS, ///< Selection widget for the button bar. + WID_C_NEW_FACE = ::WID_C_NEW_FACE, ///< Button to make new face. + WID_C_COLOUR_SCHEME = ::WID_C_COLOUR_SCHEME, ///< Button to change colour scheme. + WID_C_PRESIDENT_NAME = ::WID_C_PRESIDENT_NAME, ///< Button to change president name. + WID_C_COMPANY_NAME = ::WID_C_COMPANY_NAME, ///< Button to change company name. + WID_C_BUY_SHARE = ::WID_C_BUY_SHARE, ///< Button to buy a share. + WID_C_SELL_SHARE = ::WID_C_SELL_SHARE, ///< Button to sell a share. + + WID_C_SELECT_VIEW_BUILD_HQ = ::WID_C_SELECT_VIEW_BUILD_HQ, ///< Panel about HQ. + WID_C_VIEW_HQ = ::WID_C_VIEW_HQ, ///< Button to view the HQ. + WID_C_BUILD_HQ = ::WID_C_BUILD_HQ, ///< Button to build the HQ. + + WID_C_SELECT_RELOCATE = ::WID_C_SELECT_RELOCATE, ///< Panel about 'Relocate HQ'. + WID_C_RELOCATE_HQ = ::WID_C_RELOCATE_HQ, ///< Button to relocate the HQ. + + WID_C_VIEW_INFRASTRUCTURE = ::WID_C_VIEW_INFRASTRUCTURE, ///< Panel about infrastructure. + + WID_C_HAS_PASSWORD = ::WID_C_HAS_PASSWORD, ///< Has company password lock. + WID_C_SELECT_MULTIPLAYER = ::WID_C_SELECT_MULTIPLAYER, ///< Multiplayer selection panel. + WID_C_COMPANY_PASSWORD = ::WID_C_COMPANY_PASSWORD, ///< Button to set company password. + WID_C_COMPANY_JOIN = ::WID_C_COMPANY_JOIN, ///< Button to join company. + }; + + /** Widgets of the #CompanyFinancesWindow class. */ + enum CompanyFinancesWidgets { + WID_CF_CAPTION = ::WID_CF_CAPTION, ///< Caption of the window. + WID_CF_TOGGLE_SIZE = ::WID_CF_TOGGLE_SIZE, ///< Toggle windows size. + WID_CF_SEL_PANEL = ::WID_CF_SEL_PANEL, ///< Select panel or nothing. + WID_CF_EXPS_CATEGORY = ::WID_CF_EXPS_CATEGORY, ///< Column for expenses category strings. + WID_CF_EXPS_PRICE1 = ::WID_CF_EXPS_PRICE1, ///< Column for year Y-2 expenses. + WID_CF_EXPS_PRICE2 = ::WID_CF_EXPS_PRICE2, ///< Column for year Y-1 expenses. + WID_CF_EXPS_PRICE3 = ::WID_CF_EXPS_PRICE3, ///< Column for year Y expenses. + WID_CF_TOTAL_PANEL = ::WID_CF_TOTAL_PANEL, ///< Panel for totals. + WID_CF_SEL_MAXLOAN = ::WID_CF_SEL_MAXLOAN, ///< Selection of maxloan column. + WID_CF_BALANCE_VALUE = ::WID_CF_BALANCE_VALUE, ///< Bank balance value. + WID_CF_LOAN_VALUE = ::WID_CF_LOAN_VALUE, ///< Loan. + WID_CF_LOAN_LINE = ::WID_CF_LOAN_LINE, ///< Line for summing bank balance and loan. + WID_CF_TOTAL_VALUE = ::WID_CF_TOTAL_VALUE, ///< Total. + WID_CF_MAXLOAN_GAP = ::WID_CF_MAXLOAN_GAP, ///< Gap above max loan widget. + WID_CF_MAXLOAN_VALUE = ::WID_CF_MAXLOAN_VALUE, ///< Max loan widget. + WID_CF_SEL_BUTTONS = ::WID_CF_SEL_BUTTONS, ///< Selection of buttons. + WID_CF_INCREASE_LOAN = ::WID_CF_INCREASE_LOAN, ///< Increase loan. + WID_CF_REPAY_LOAN = ::WID_CF_REPAY_LOAN, ///< Decrease loan.. + WID_CF_INFRASTRUCTURE = ::WID_CF_INFRASTRUCTURE, ///< View company infrastructure. + }; + + /** Widgets of the #SelectCompanyLiveryWindow class. */ + enum SelectCompanyLiveryWidgets { + WID_SCL_CAPTION = ::WID_SCL_CAPTION, ///< Caption of window. + WID_SCL_CLASS_GENERAL = ::WID_SCL_CLASS_GENERAL, ///< Class general. + WID_SCL_CLASS_RAIL = ::WID_SCL_CLASS_RAIL, ///< Class rail. + WID_SCL_CLASS_ROAD = ::WID_SCL_CLASS_ROAD, ///< Class road. + WID_SCL_CLASS_SHIP = ::WID_SCL_CLASS_SHIP, ///< Class ship. + WID_SCL_CLASS_AIRCRAFT = ::WID_SCL_CLASS_AIRCRAFT, ///< Class aircraft. + WID_SCL_SPACER_DROPDOWN = ::WID_SCL_SPACER_DROPDOWN, ///< Spacer for dropdown. + WID_SCL_PRI_COL_DROPDOWN = ::WID_SCL_PRI_COL_DROPDOWN, ///< Dropdown for primary colour. + WID_SCL_SEC_COL_DROPDOWN = ::WID_SCL_SEC_COL_DROPDOWN, ///< Dropdown for secondary colour. + WID_SCL_MATRIX = ::WID_SCL_MATRIX, ///< Matrix. + }; + + /** + * Widgets of the #SelectCompanyManagerFaceWindow class. + * Do not change the order of the widgets from WID_SCMF_HAS_MOUSTACHE_EARRING to WID_SCMF_GLASSES_R, + * this order is needed for the WE_CLICK event of DrawFaceStringLabel(). + */ + enum SelectCompanyManagerFaceWidgets { + WID_SCMF_CAPTION = ::WID_SCMF_CAPTION, ///< Caption of window. + WID_SCMF_TOGGLE_LARGE_SMALL = ::WID_SCMF_TOGGLE_LARGE_SMALL, ///< Toggle for large or small. + WID_SCMF_SELECT_FACE = ::WID_SCMF_SELECT_FACE, ///< Select face. + WID_SCMF_CANCEL = ::WID_SCMF_CANCEL, ///< Cancel. + WID_SCMF_ACCEPT = ::WID_SCMF_ACCEPT, ///< Accept. + WID_SCMF_MALE = ::WID_SCMF_MALE, ///< Male button in the simple view. + WID_SCMF_FEMALE = ::WID_SCMF_FEMALE, ///< Female button in the simple view. + WID_SCMF_MALE2 = ::WID_SCMF_MALE2, ///< Male button in the advanced view. + WID_SCMF_FEMALE2 = ::WID_SCMF_FEMALE2, ///< Female button in the advanced view. + WID_SCMF_SEL_LOADSAVE = ::WID_SCMF_SEL_LOADSAVE, ///< Selection to display the load/save/number buttons in the advanced view. + WID_SCMF_SEL_MALEFEMALE = ::WID_SCMF_SEL_MALEFEMALE, ///< Selection to display the male/female buttons in the simple view. + WID_SCMF_SEL_PARTS = ::WID_SCMF_SEL_PARTS, ///< Selection to display the buttons for setting each part of the face in the advanced view. + WID_SCMF_RANDOM_NEW_FACE = ::WID_SCMF_RANDOM_NEW_FACE, ///< Create random new face. + WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON = ::WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON, ///< Toggle for large or small. + WID_SCMF_FACE = ::WID_SCMF_FACE, ///< Current face. + WID_SCMF_LOAD = ::WID_SCMF_LOAD, ///< Load face. + WID_SCMF_FACECODE = ::WID_SCMF_FACECODE, ///< Get the face code. + WID_SCMF_SAVE = ::WID_SCMF_SAVE, ///< Save face. + WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT = ::WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT, ///< Text about moustache and earring. + WID_SCMF_TIE_EARRING_TEXT = ::WID_SCMF_TIE_EARRING_TEXT, ///< Text about tie and earring. + WID_SCMF_LIPS_MOUSTACHE_TEXT = ::WID_SCMF_LIPS_MOUSTACHE_TEXT, ///< Text about lips and moustache. + WID_SCMF_HAS_GLASSES_TEXT = ::WID_SCMF_HAS_GLASSES_TEXT, ///< Text about glasses. + WID_SCMF_HAIR_TEXT = ::WID_SCMF_HAIR_TEXT, ///< Text about hair. + WID_SCMF_EYEBROWS_TEXT = ::WID_SCMF_EYEBROWS_TEXT, ///< Text about eyebrows. + WID_SCMF_EYECOLOUR_TEXT = ::WID_SCMF_EYECOLOUR_TEXT, ///< Text about eyecolour. + WID_SCMF_GLASSES_TEXT = ::WID_SCMF_GLASSES_TEXT, ///< Text about glasses. + WID_SCMF_NOSE_TEXT = ::WID_SCMF_NOSE_TEXT, ///< Text about nose. + WID_SCMF_CHIN_TEXT = ::WID_SCMF_CHIN_TEXT, ///< Text about chin. + WID_SCMF_JACKET_TEXT = ::WID_SCMF_JACKET_TEXT, ///< Text about jacket. + WID_SCMF_COLLAR_TEXT = ::WID_SCMF_COLLAR_TEXT, ///< Text about collar. + WID_SCMF_ETHNICITY_EUR = ::WID_SCMF_ETHNICITY_EUR, ///< Text about ethnicity european. + WID_SCMF_ETHNICITY_AFR = ::WID_SCMF_ETHNICITY_AFR, ///< Text about ethnicity african. + WID_SCMF_HAS_MOUSTACHE_EARRING = ::WID_SCMF_HAS_MOUSTACHE_EARRING, ///< Has moustache or earring. + WID_SCMF_HAS_GLASSES = ::WID_SCMF_HAS_GLASSES, ///< Has glasses. + WID_SCMF_EYECOLOUR_L = ::WID_SCMF_EYECOLOUR_L, ///< Eyecolour left. + WID_SCMF_EYECOLOUR = ::WID_SCMF_EYECOLOUR, ///< Eyecolour. + WID_SCMF_EYECOLOUR_R = ::WID_SCMF_EYECOLOUR_R, ///< Eyecolour right. + WID_SCMF_CHIN_L = ::WID_SCMF_CHIN_L, ///< Chin left. + WID_SCMF_CHIN = ::WID_SCMF_CHIN, ///< Chin. + WID_SCMF_CHIN_R = ::WID_SCMF_CHIN_R, ///< Chin right. + WID_SCMF_EYEBROWS_L = ::WID_SCMF_EYEBROWS_L, ///< Eyebrows left. + WID_SCMF_EYEBROWS = ::WID_SCMF_EYEBROWS, ///< Eyebrows. + WID_SCMF_EYEBROWS_R = ::WID_SCMF_EYEBROWS_R, ///< Eyebrows right. + WID_SCMF_LIPS_MOUSTACHE_L = ::WID_SCMF_LIPS_MOUSTACHE_L, ///< Lips / Moustache left. + WID_SCMF_LIPS_MOUSTACHE = ::WID_SCMF_LIPS_MOUSTACHE, ///< Lips / Moustache. + WID_SCMF_LIPS_MOUSTACHE_R = ::WID_SCMF_LIPS_MOUSTACHE_R, ///< Lips / Moustache right. + WID_SCMF_NOSE_L = ::WID_SCMF_NOSE_L, ///< Nose left. + WID_SCMF_NOSE = ::WID_SCMF_NOSE, ///< Nose. + WID_SCMF_NOSE_R = ::WID_SCMF_NOSE_R, ///< Nose right. + WID_SCMF_HAIR_L = ::WID_SCMF_HAIR_L, ///< Hair left. + WID_SCMF_HAIR = ::WID_SCMF_HAIR, ///< Hair. + WID_SCMF_HAIR_R = ::WID_SCMF_HAIR_R, ///< Hair right. + WID_SCMF_JACKET_L = ::WID_SCMF_JACKET_L, ///< Jacket left. + WID_SCMF_JACKET = ::WID_SCMF_JACKET, ///< Jacket. + WID_SCMF_JACKET_R = ::WID_SCMF_JACKET_R, ///< Jacket right. + WID_SCMF_COLLAR_L = ::WID_SCMF_COLLAR_L, ///< Collar left. + WID_SCMF_COLLAR = ::WID_SCMF_COLLAR, ///< Collar. + WID_SCMF_COLLAR_R = ::WID_SCMF_COLLAR_R, ///< Collar right. + WID_SCMF_TIE_EARRING_L = ::WID_SCMF_TIE_EARRING_L, ///< Tie / Earring left. + WID_SCMF_TIE_EARRING = ::WID_SCMF_TIE_EARRING, ///< Tie / Earring. + WID_SCMF_TIE_EARRING_R = ::WID_SCMF_TIE_EARRING_R, ///< Tie / Earring right. + WID_SCMF_GLASSES_L = ::WID_SCMF_GLASSES_L, ///< Glasses left. + WID_SCMF_GLASSES = ::WID_SCMF_GLASSES, ///< Glasses. + WID_SCMF_GLASSES_R = ::WID_SCMF_GLASSES_R, ///< Glasses right. + }; + + /** Widgets of the #CompanyInfrastructureWindow class. */ + enum CompanyInfrastructureWidgets { + WID_CI_CAPTION = ::WID_CI_CAPTION, ///< Caption of window. + WID_CI_RAIL_DESC = ::WID_CI_RAIL_DESC, ///< Description of rail. + WID_CI_RAIL_COUNT = ::WID_CI_RAIL_COUNT, ///< Count of rail. + WID_CI_ROAD_DESC = ::WID_CI_ROAD_DESC, ///< Description of road. + WID_CI_ROAD_COUNT = ::WID_CI_ROAD_COUNT, ///< Count of road. + WID_CI_WATER_DESC = ::WID_CI_WATER_DESC, ///< Description of water. + WID_CI_WATER_COUNT = ::WID_CI_WATER_COUNT, ///< Count of water. + WID_CI_STATION_DESC = ::WID_CI_STATION_DESC, ///< Description of station. + WID_CI_STATION_COUNT = ::WID_CI_STATION_COUNT, ///< Count of station. + WID_CI_TOTAL_DESC = ::WID_CI_TOTAL_DESC, ///< Description of total. + WID_CI_TOTAL = ::WID_CI_TOTAL, ///< Count of total. + }; + + /** Widgets of the #BuyCompanyWindow class. */ + enum BuyCompanyWidgets { + WID_BC_CAPTION = ::WID_BC_CAPTION, ///< Caption of window. + WID_BC_FACE = ::WID_BC_FACE, ///< Face button. + WID_BC_QUESTION = ::WID_BC_QUESTION, ///< Question text. + WID_BC_NO = ::WID_BC_NO, ///< No button. + WID_BC_YES = ::WID_BC_YES, ///< Yes button. + }; + + /* automatically generated from ../../widgets/console_widget.h */ + /** Widgets of the #IConsoleWindow class. */ + enum ConsoleWidgets { + WID_C_BACKGROUND = ::WID_C_BACKGROUND, ///< Background of the console. + }; + + /* automatically generated from ../../widgets/date_widget.h */ + /** Widgets of the #SetDateWindow class. */ + enum SetDateWidgets { + WID_SD_DAY = ::WID_SD_DAY, ///< Dropdown for the day. + WID_SD_MONTH = ::WID_SD_MONTH, ///< Dropdown for the month. + WID_SD_YEAR = ::WID_SD_YEAR, ///< Dropdown for the year. + WID_SD_SET_DATE = ::WID_SD_SET_DATE, ///< Actually set the date. + }; + + /* automatically generated from ../../widgets/depot_widget.h */ + /** Widgets of the #DepotWindow class. */ + enum DepotWidgets { + WID_D_CAPTION = ::WID_D_CAPTION, ///< Caption of window. + WID_D_SELL = ::WID_D_SELL, ///< Sell button. + WID_D_SHOW_SELL_CHAIN = ::WID_D_SHOW_SELL_CHAIN, ///< Show sell chain panel. + WID_D_SELL_CHAIN = ::WID_D_SELL_CHAIN, ///< Sell chain button. + WID_D_SELL_ALL = ::WID_D_SELL_ALL, ///< Sell all button. + WID_D_AUTOREPLACE = ::WID_D_AUTOREPLACE, ///< Autoreplace button. + WID_D_MATRIX = ::WID_D_MATRIX, ///< Matrix of vehicles. + WID_D_V_SCROLL = ::WID_D_V_SCROLL, ///< Vertical scrollbar. + WID_D_SHOW_H_SCROLL = ::WID_D_SHOW_H_SCROLL, ///< Show horizontal scrollbar panel. + WID_D_H_SCROLL = ::WID_D_H_SCROLL, ///< Horizontal scrollbar. + WID_D_BUILD = ::WID_D_BUILD, ///< Build button. + WID_D_CLONE = ::WID_D_CLONE, ///< Clone button. + WID_D_LOCATION = ::WID_D_LOCATION, ///< Location button. + WID_D_SHOW_RENAME = ::WID_D_SHOW_RENAME, ///< Show rename panel. + WID_D_RENAME = ::WID_D_RENAME, ///< Rename button. + WID_D_VEHICLE_LIST = ::WID_D_VEHICLE_LIST, ///< List of vehicles. + WID_D_STOP_ALL = ::WID_D_STOP_ALL, ///< Stop all button. + WID_D_START_ALL = ::WID_D_START_ALL, ///< Start all button. + }; + + /* automatically generated from ../../widgets/dock_widget.h */ + /** Widgets of the #BuildDocksDepotWindow class. */ + enum BuildDockDepotWidgets { + WID_BDD_BACKGROUND = ::WID_BDD_BACKGROUND, ///< Background of the window. + WID_BDD_X = ::WID_BDD_X, ///< X-direction button. + WID_BDD_Y = ::WID_BDD_Y, ///< Y-direction button. + }; + + /** Widgets of the #BuildDocksToolbarWindow class. */ + enum DockToolbarWidgets { + WID_DT_CANAL = ::WID_DT_CANAL, ///< Build canal button. + WID_DT_LOCK = ::WID_DT_LOCK, ///< Build lock button. + WID_DT_DEMOLISH = ::WID_DT_DEMOLISH, ///< Demolish aka dynamite button. + WID_DT_DEPOT = ::WID_DT_DEPOT, ///< Build depot button. + WID_DT_STATION = ::WID_DT_STATION, ///< Build station button. + WID_DT_BUOY = ::WID_DT_BUOY, ///< Build buoy button. + WID_DT_RIVER = ::WID_DT_RIVER, ///< Build river button (in scenario editor). + WID_DT_BUILD_AQUEDUCT = ::WID_DT_BUILD_AQUEDUCT, ///< Build aqueduct button. + + WID_DT_INVALID = ::WID_DT_INVALID, ///< Used to initialize a variable. + }; + + /* automatically generated from ../../widgets/dropdown_widget.h */ + /** Widgets of the #DropdownWindow class. */ + enum DropdownMenuWidgets { + WID_DM_ITEMS = ::WID_DM_ITEMS, ///< Panel showing the dropdown items. + WID_DM_SHOW_SCROLL = ::WID_DM_SHOW_SCROLL, ///< Hide scrollbar if too few items. + WID_DM_SCROLL = ::WID_DM_SCROLL, ///< Scrollbar. + }; + + /* automatically generated from ../../widgets/engine_widget.h */ + /** Widgets of the #EnginePreviewWindow class. */ + enum EnginePreviewWidgets { + WID_EP_QUESTION = ::WID_EP_QUESTION, ///< The container for the question. + WID_EP_NO = ::WID_EP_NO, ///< No button. + WID_EP_YES = ::WID_EP_YES, ///< Yes button. + }; + + /* automatically generated from ../../widgets/error_widget.h */ + /** Widgets of the #ErrmsgWindow class. */ + enum ErrorMessageWidgets { + WID_EM_CAPTION = ::WID_EM_CAPTION, ///< Caption of the window. + WID_EM_FACE = ::WID_EM_FACE, ///< Error title. + WID_EM_MESSAGE = ::WID_EM_MESSAGE, ///< Error message. + }; + + /* automatically generated from ../../widgets/fios_widget.h */ + /** Widgets of the #SaveLoadWindow class. */ + enum SaveLoadWidgets { + WID_SL_CAPTION = ::WID_SL_CAPTION, ///< Caption of the window. + WID_SL_SORT_BYNAME = ::WID_SL_SORT_BYNAME, ///< Sort by name button. + WID_SL_SORT_BYDATE = ::WID_SL_SORT_BYDATE, ///< Sort by date button. + WID_SL_BACKGROUND = ::WID_SL_BACKGROUND, ///< Background of window. + WID_SL_FILE_BACKGROUND = ::WID_SL_FILE_BACKGROUND, ///< Background of file selection. + WID_SL_HOME_BUTTON = ::WID_SL_HOME_BUTTON, ///< Home button. + WID_SL_DRIVES_DIRECTORIES_LIST = ::WID_SL_DRIVES_DIRECTORIES_LIST, ///< Drives list. + WID_SL_SCROLLBAR = ::WID_SL_SCROLLBAR, ///< Scrollbar of the file list. + WID_SL_CONTENT_DOWNLOAD = ::WID_SL_CONTENT_DOWNLOAD, ///< Content download button, only available for play scenario/heightmap. + WID_SL_SAVE_OSK_TITLE = ::WID_SL_SAVE_OSK_TITLE, ///< Title textbox, only available for save operations. + WID_SL_DELETE_SELECTION = ::WID_SL_DELETE_SELECTION, ///< Delete button, only available for save operations. + WID_SL_SAVE_GAME = ::WID_SL_SAVE_GAME, ///< Save button, only available for save operations. + WID_SL_CONTENT_DOWNLOAD_SEL = ::WID_SL_CONTENT_DOWNLOAD_SEL, ///< Selection 'stack' to 'hide' the content download. + WID_SL_DETAILS = ::WID_SL_DETAILS, ///< Panel with game details. + WID_SL_NEWGRF_INFO = ::WID_SL_NEWGRF_INFO, ///< Button to open NewGgrf configuration. + WID_SL_LOAD_BUTTON = ::WID_SL_LOAD_BUTTON, ///< Button to load game/scenario. + WID_SL_MISSING_NEWGRFS = ::WID_SL_MISSING_NEWGRFS, ///< Button to find missing NewGRFs online. + }; + + /* automatically generated from ../../widgets/genworld_widget.h */ + /** Widgets of the #GenerateLandscapeWindow class. */ + enum GenerateLandscapeWidgets { + WID_GL_TEMPERATE = ::WID_GL_TEMPERATE, ///< Button with icon "Temperate". + WID_GL_ARCTIC = ::WID_GL_ARCTIC, ///< Button with icon "Arctic". + WID_GL_TROPICAL = ::WID_GL_TROPICAL, ///< Button with icon "Tropical". + WID_GL_TOYLAND = ::WID_GL_TOYLAND, ///< Button with icon "Toyland". + + WID_GL_MAPSIZE_X_PULLDOWN = ::WID_GL_MAPSIZE_X_PULLDOWN, ///< Dropdown 'map X size'. + WID_GL_MAPSIZE_Y_PULLDOWN = ::WID_GL_MAPSIZE_Y_PULLDOWN, ///< Dropdown 'map Y size'. + + WID_GL_TOWN_PULLDOWN = ::WID_GL_TOWN_PULLDOWN, ///< Dropdown 'No. of towns'. + WID_GL_INDUSTRY_PULLDOWN = ::WID_GL_INDUSTRY_PULLDOWN, ///< Dropdown 'No. of industries'. + + WID_GL_RANDOM_EDITBOX = ::WID_GL_RANDOM_EDITBOX, ///< 'Random seed' editbox. + WID_GL_RANDOM_BUTTON = ::WID_GL_RANDOM_BUTTON, ///< 'Randomise' button. + + WID_GL_GENERATE_BUTTON = ::WID_GL_GENERATE_BUTTON, ///< 'Generate' button. + + WID_GL_START_DATE_DOWN = ::WID_GL_START_DATE_DOWN, ///< Decrease start year. + WID_GL_START_DATE_TEXT = ::WID_GL_START_DATE_TEXT, ///< Start year. + WID_GL_START_DATE_UP = ::WID_GL_START_DATE_UP, ///< Increase start year. + + WID_GL_SNOW_LEVEL_DOWN = ::WID_GL_SNOW_LEVEL_DOWN, ///< Decrease snow level. + WID_GL_SNOW_LEVEL_TEXT = ::WID_GL_SNOW_LEVEL_TEXT, ///< Snow level. + WID_GL_SNOW_LEVEL_UP = ::WID_GL_SNOW_LEVEL_UP, ///< Increase snow level. + + WID_GL_TREE_PULLDOWN = ::WID_GL_TREE_PULLDOWN, ///< Dropdown 'Tree algorithm'. + WID_GL_LANDSCAPE_PULLDOWN = ::WID_GL_LANDSCAPE_PULLDOWN, ///< Dropdown 'Land generator'. + + WID_GL_HEIGHTMAP_NAME_TEXT = ::WID_GL_HEIGHTMAP_NAME_TEXT, ///< Heightmap name. + WID_GL_HEIGHTMAP_SIZE_TEXT = ::WID_GL_HEIGHTMAP_SIZE_TEXT, ///< Size of heightmap. + WID_GL_HEIGHTMAP_ROTATION_PULLDOWN = ::WID_GL_HEIGHTMAP_ROTATION_PULLDOWN, ///< Dropdown 'Heightmap rotation'. + + WID_GL_TERRAIN_PULLDOWN = ::WID_GL_TERRAIN_PULLDOWN, ///< Dropdown 'Terrain type'. + WID_GL_WATER_PULLDOWN = ::WID_GL_WATER_PULLDOWN, ///< Dropdown 'Sea level'. + WID_GL_RIVER_PULLDOWN = ::WID_GL_RIVER_PULLDOWN, ///< Dropdown 'Rivers'. + WID_GL_SMOOTHNESS_PULLDOWN = ::WID_GL_SMOOTHNESS_PULLDOWN, ///< Dropdown 'Smoothness'. + WID_GL_VARIETY_PULLDOWN = ::WID_GL_VARIETY_PULLDOWN, ///< Dropdown 'Variety distribution'. + + WID_GL_BORDERS_RANDOM = ::WID_GL_BORDERS_RANDOM, ///< 'Random'/'Manual' borders. + WID_GL_WATER_NW = ::WID_GL_WATER_NW, ///< NW 'Water'/'Freeform'. + WID_GL_WATER_NE = ::WID_GL_WATER_NE, ///< NE 'Water'/'Freeform'. + WID_GL_WATER_SE = ::WID_GL_WATER_SE, ///< SE 'Water'/'Freeform'. + WID_GL_WATER_SW = ::WID_GL_WATER_SW, ///< SW 'Water'/'Freeform'. + }; + + /** Widgets of the #CreateScenarioWindow class. */ + enum CreateScenarioWidgets { + WID_CS_TEMPERATE = ::WID_CS_TEMPERATE, ///< Select temperate landscape style. + WID_CS_ARCTIC = ::WID_CS_ARCTIC, ///< Select arctic landscape style. + WID_CS_TROPICAL = ::WID_CS_TROPICAL, ///< Select tropical landscape style. + WID_CS_TOYLAND = ::WID_CS_TOYLAND, ///< Select toy-land landscape style. + WID_CS_EMPTY_WORLD = ::WID_CS_EMPTY_WORLD, ///< Generate an empty flat world. + WID_CS_RANDOM_WORLD = ::WID_CS_RANDOM_WORLD, ///< Generate random land button + WID_CS_MAPSIZE_X_PULLDOWN = ::WID_CS_MAPSIZE_X_PULLDOWN, ///< Pull-down arrow for x map size. + WID_CS_MAPSIZE_Y_PULLDOWN = ::WID_CS_MAPSIZE_Y_PULLDOWN, ///< Pull-down arrow for y map size. + WID_CS_START_DATE_DOWN = ::WID_CS_START_DATE_DOWN, ///< Decrease start year (start earlier). + WID_CS_START_DATE_TEXT = ::WID_CS_START_DATE_TEXT, ///< Clickable start date value. + WID_CS_START_DATE_UP = ::WID_CS_START_DATE_UP, ///< Increase start year (start later). + WID_CS_FLAT_LAND_HEIGHT_DOWN = ::WID_CS_FLAT_LAND_HEIGHT_DOWN, ///< Decrease flat land height. + WID_CS_FLAT_LAND_HEIGHT_TEXT = ::WID_CS_FLAT_LAND_HEIGHT_TEXT, ///< Clickable flat land height value. + WID_CS_FLAT_LAND_HEIGHT_UP = ::WID_CS_FLAT_LAND_HEIGHT_UP, ///< Increase flat land height. + }; + + /** Widgets of the #GenerateProgressWindow class. */ + enum GenerationProgressWidgets { + WID_GP_PROGRESS_BAR = ::WID_GP_PROGRESS_BAR, ///< Progress bar. + WID_GP_PROGRESS_TEXT = ::WID_GP_PROGRESS_TEXT, ///< Text with the progress bar. + WID_GP_ABORT = ::WID_GP_ABORT, ///< Abort button. + }; + + /* automatically generated from ../../widgets/goal_widget.h */ + /** Widgets of the #GoalListWindow class. */ + enum GoalListWidgets { + WID_GOAL_CAPTION = ::WID_GOAL_CAPTION, ///< Caption of the window. + WID_GOAL_LIST = ::WID_GOAL_LIST, ///< Goal list. + WID_GOAL_SCROLLBAR = ::WID_GOAL_SCROLLBAR, ///< Scrollbar of the goal list. + }; + + /** Widgets of the #GoalQuestionWindow class. */ + enum GoalQuestionWidgets { + WID_GQ_CAPTION = ::WID_GQ_CAPTION, ///< Caption of the window. + WID_GQ_QUESTION = ::WID_GQ_QUESTION, ///< Question text. + WID_GQ_BUTTONS = ::WID_GQ_BUTTONS, ///< Buttons selection (between 1, 2 or 3). + WID_GQ_BUTTON_1 = ::WID_GQ_BUTTON_1, ///< First button. + WID_GQ_BUTTON_2 = ::WID_GQ_BUTTON_2, ///< Second button. + WID_GQ_BUTTON_3 = ::WID_GQ_BUTTON_3, ///< Third button. + }; + + /* automatically generated from ../../widgets/graph_widget.h */ + /** Widgets of the #GraphLegendWindow class. */ + enum GraphLegendWidgets { + WID_GL_BACKGROUND = ::WID_GL_BACKGROUND, ///< Background of the window. + + WID_GL_FIRST_COMPANY = ::WID_GL_FIRST_COMPANY, ///< First company in the legend. + WID_GL_LAST_COMPANY = ::WID_GL_LAST_COMPANY, ///< Last company in the legend. + }; + + /** Widgets of the #OperatingProfitGraphWindow class, #IncomeGraphWindow class, #DeliveredCargoGraphWindow class, and #CompanyValueGraphWindow class. */ + enum CompanyValueWidgets { + WID_CV_KEY_BUTTON = ::WID_CV_KEY_BUTTON, ///< Key button. + WID_CV_BACKGROUND = ::WID_CV_BACKGROUND, ///< Background of the window. + WID_CV_GRAPH = ::WID_CV_GRAPH, ///< Graph itself. + WID_CV_RESIZE = ::WID_CV_RESIZE, ///< Resize button. + }; + + /** Widget of the #PerformanceHistoryGraphWindow class. */ + enum PerformanceHistoryGraphWidgets { + WID_PHG_KEY = ::WID_PHG_KEY, ///< Key button. + WID_PHG_DETAILED_PERFORMANCE = ::WID_PHG_DETAILED_PERFORMANCE, ///< Detailed performance. + WID_PHG_BACKGROUND = ::WID_PHG_BACKGROUND, ///< Background of the window. + WID_PHG_GRAPH = ::WID_PHG_GRAPH, ///< Graph itself. + WID_PHG_RESIZE = ::WID_PHG_RESIZE, ///< Resize button. + }; + + /** Widget of the #PaymentRatesGraphWindow class. */ + enum CargoPaymentRatesWidgets { + WID_CPR_BACKGROUND = ::WID_CPR_BACKGROUND, ///< Background of the window. + WID_CPR_HEADER = ::WID_CPR_HEADER, ///< Header. + WID_CPR_GRAPH = ::WID_CPR_GRAPH, ///< Graph itself. + WID_CPR_RESIZE = ::WID_CPR_RESIZE, ///< Resize button. + WID_CPR_FOOTER = ::WID_CPR_FOOTER, ///< Footer. + WID_CPR_ENABLE_CARGOES = ::WID_CPR_ENABLE_CARGOES, ///< Enable cargoes button. + WID_CPR_DISABLE_CARGOES = ::WID_CPR_DISABLE_CARGOES, ///< Disable cargoes button. + WID_CPR_CARGO_FIRST = ::WID_CPR_CARGO_FIRST, ///< First cargo in the list. + }; + + /** Widget of the #CompanyLeagueWindow class. */ + enum CompanyLeagueWidgets { + WID_CL_BACKGROUND = ::WID_CL_BACKGROUND, ///< Background of the window. + }; + + /** Widget of the #PerformanceRatingDetailWindow class. */ + enum PerformanceRatingDetailsWidgets { + WID_PRD_SCORE_FIRST = ::WID_PRD_SCORE_FIRST, ///< First entry in the score list. + WID_PRD_SCORE_LAST = ::WID_PRD_SCORE_LAST, ///< Last entry in the score list. + + WID_PRD_COMPANY_FIRST = ::WID_PRD_COMPANY_FIRST, ///< First company. + WID_PRD_COMPANY_LAST = ::WID_PRD_COMPANY_LAST, ///< Last company. + }; + + /* automatically generated from ../../widgets/group_widget.h */ + /** Widgets of the #VehicleGroupWindow class. */ + enum GroupListWidgets { + WID_GL_CAPTION = ::WID_GL_CAPTION, ///< Caption of the window. + WID_GL_SORT_BY_ORDER = ::WID_GL_SORT_BY_ORDER, ///< Sort order. + WID_GL_SORT_BY_DROPDOWN = ::WID_GL_SORT_BY_DROPDOWN, ///< Sort by dropdown list. + WID_GL_LIST_VEHICLE = ::WID_GL_LIST_VEHICLE, ///< List of the vehicles. + WID_GL_LIST_VEHICLE_SCROLLBAR = ::WID_GL_LIST_VEHICLE_SCROLLBAR, ///< Scrollbar for the list. + WID_GL_AVAILABLE_VEHICLES = ::WID_GL_AVAILABLE_VEHICLES, ///< Available vehicles. + WID_GL_MANAGE_VEHICLES_DROPDOWN = ::WID_GL_MANAGE_VEHICLES_DROPDOWN, ///< Manage vehicles dropdown list. + WID_GL_STOP_ALL = ::WID_GL_STOP_ALL, ///< Stop all button. + WID_GL_START_ALL = ::WID_GL_START_ALL, ///< Start all button. + + WID_GL_ALL_VEHICLES = ::WID_GL_ALL_VEHICLES, ///< All vehicles entry. + WID_GL_DEFAULT_VEHICLES = ::WID_GL_DEFAULT_VEHICLES, ///< Default vehicles entry. + WID_GL_LIST_GROUP = ::WID_GL_LIST_GROUP, ///< List of the groups. + WID_GL_LIST_GROUP_SCROLLBAR = ::WID_GL_LIST_GROUP_SCROLLBAR, ///< Scrollbar for the list. + WID_GL_CREATE_GROUP = ::WID_GL_CREATE_GROUP, ///< Create group button. + WID_GL_DELETE_GROUP = ::WID_GL_DELETE_GROUP, ///< Delete group button. + WID_GL_RENAME_GROUP = ::WID_GL_RENAME_GROUP, ///< Rename group button. + WID_GL_REPLACE_PROTECTION = ::WID_GL_REPLACE_PROTECTION, ///< Replace protection button. + }; + + /* automatically generated from ../../widgets/highscore_widget.h */ + /** Widgets of the #EndGameHighScoreBaseWindow class and #HighScoreWindow class. */ + enum HighscoreWidgets { + WID_H_BACKGROUND = ::WID_H_BACKGROUND, ///< Background of the window. + }; + + /* automatically generated from ../../widgets/industry_widget.h */ + /** Widgets of the #BuildIndustryWindow class. */ + enum DynamicPlaceIndustriesWidgets { + WID_DPI_MATRIX_WIDGET = ::WID_DPI_MATRIX_WIDGET, ///< Matrix of the industries. + WID_DPI_SCROLLBAR = ::WID_DPI_SCROLLBAR, ///< Scrollbar of the matrix. + WID_DPI_INFOPANEL = ::WID_DPI_INFOPANEL, ///< Info panel about the industry. + WID_DPI_DISPLAY_WIDGET = ::WID_DPI_DISPLAY_WIDGET, ///< Display chain button. + WID_DPI_FUND_WIDGET = ::WID_DPI_FUND_WIDGET, ///< Fund button. + }; + + /** Widgets of the #IndustryViewWindow class. */ + enum IndustryViewWidgets { + WID_IV_CAPTION = ::WID_IV_CAPTION, ///< Caption of the window. + WID_IV_VIEWPORT = ::WID_IV_VIEWPORT, ///< Viewport of the industry. + WID_IV_INFO = ::WID_IV_INFO, ///< Info of the industry. + WID_IV_GOTO = ::WID_IV_GOTO, ///< Goto button. + WID_IV_DISPLAY = ::WID_IV_DISPLAY, ///< Display chain button. + }; + + /** Widgets of the #IndustryDirectoryWindow class. */ + enum IndustryDirectoryWidgets { + WID_ID_DROPDOWN_ORDER = ::WID_ID_DROPDOWN_ORDER, ///< Dropdown for the order of the sort. + WID_ID_DROPDOWN_CRITERIA = ::WID_ID_DROPDOWN_CRITERIA, ///< Dropdown for the criteria of the sort. + WID_ID_INDUSTRY_LIST = ::WID_ID_INDUSTRY_LIST, ///< Industry list. + WID_ID_SCROLLBAR = ::WID_ID_SCROLLBAR, ///< Scrollbar of the list. + }; + + /** Widgets of the #IndustryCargoesWindow class */ + enum IndustryCargoesWidgets { + WID_IC_CAPTION = ::WID_IC_CAPTION, ///< Caption of the window. + WID_IC_NOTIFY = ::WID_IC_NOTIFY, ///< Row of buttons at the bottom. + WID_IC_PANEL = ::WID_IC_PANEL, ///< Panel that shows the chain. + WID_IC_SCROLLBAR = ::WID_IC_SCROLLBAR, ///< Scrollbar of the panel. + WID_IC_CARGO_DROPDOWN = ::WID_IC_CARGO_DROPDOWN, ///< Select cargo dropdown. + WID_IC_IND_DROPDOWN = ::WID_IC_IND_DROPDOWN, ///< Select industry dropdown. + }; + + /* automatically generated from ../../widgets/intro_widget.h */ + /** Widgets of the #SelectGameWindow class. */ + enum SelectGameIntroWidgets { + WID_SGI_GENERATE_GAME = ::WID_SGI_GENERATE_GAME, ///< Generate game button. + WID_SGI_LOAD_GAME = ::WID_SGI_LOAD_GAME, ///< Load game button. + WID_SGI_PLAY_SCENARIO = ::WID_SGI_PLAY_SCENARIO, ///< Play scenario button. + WID_SGI_PLAY_HEIGHTMAP = ::WID_SGI_PLAY_HEIGHTMAP, ///< Play heightmap button. + WID_SGI_EDIT_SCENARIO = ::WID_SGI_EDIT_SCENARIO, ///< Edit scenario button. + WID_SGI_PLAY_NETWORK = ::WID_SGI_PLAY_NETWORK, ///< Play network button. + WID_SGI_TEMPERATE_LANDSCAPE = ::WID_SGI_TEMPERATE_LANDSCAPE, ///< Select temperate landscape button. + WID_SGI_ARCTIC_LANDSCAPE = ::WID_SGI_ARCTIC_LANDSCAPE, ///< Select arctic landscape button. + WID_SGI_TROPIC_LANDSCAPE = ::WID_SGI_TROPIC_LANDSCAPE, ///< Select tropic landscape button. + WID_SGI_TOYLAND_LANDSCAPE = ::WID_SGI_TOYLAND_LANDSCAPE, ///< Select toyland landscape button. + WID_SGI_TRANSLATION_SELECTION = ::WID_SGI_TRANSLATION_SELECTION, ///< Translation selection. + WID_SGI_TRANSLATION = ::WID_SGI_TRANSLATION, ///< Translation. + WID_SGI_OPTIONS = ::WID_SGI_OPTIONS, ///< Options button. + WID_SGI_HIGHSCORE = ::WID_SGI_HIGHSCORE, ///< Highscore button. + WID_SGI_SETTINGS_OPTIONS = ::WID_SGI_SETTINGS_OPTIONS, ///< Settings button. + WID_SGI_GRF_SETTINGS = ::WID_SGI_GRF_SETTINGS, ///< NewGRF button. + WID_SGI_CONTENT_DOWNLOAD = ::WID_SGI_CONTENT_DOWNLOAD, ///< Content Download button. + WID_SGI_AI_SETTINGS = ::WID_SGI_AI_SETTINGS, ///< AI button. + WID_SGI_EXIT = ::WID_SGI_EXIT, ///< Exit button. + }; + + /* automatically generated from ../../widgets/link_graph_legend_widget.h */ + /** Widgets of the WC_LINKGRAPH_LEGEND. */ + enum LinkGraphLegendWidgets { + WID_LGL_CAPTION = ::WID_LGL_CAPTION, ///< Caption widget. + WID_LGL_SATURATION = ::WID_LGL_SATURATION, ///< Saturation legend. + WID_LGL_SATURATION_FIRST = ::WID_LGL_SATURATION_FIRST, + WID_LGL_SATURATION_LAST = ::WID_LGL_SATURATION_LAST, + WID_LGL_COMPANIES = ::WID_LGL_COMPANIES, ///< Company selection widget. + WID_LGL_COMPANY_FIRST = ::WID_LGL_COMPANY_FIRST, + WID_LGL_COMPANY_LAST = ::WID_LGL_COMPANY_LAST, + WID_LGL_COMPANIES_ALL = ::WID_LGL_COMPANIES_ALL, + WID_LGL_COMPANIES_NONE = ::WID_LGL_COMPANIES_NONE, + WID_LGL_CARGOES = ::WID_LGL_CARGOES, ///< Cargo selection widget. + WID_LGL_CARGO_FIRST = ::WID_LGL_CARGO_FIRST, + WID_LGL_CARGO_LAST = ::WID_LGL_CARGO_LAST, + WID_LGL_CARGOES_ALL = ::WID_LGL_CARGOES_ALL, + WID_LGL_CARGOES_NONE = ::WID_LGL_CARGOES_NONE, + }; + + /* automatically generated from ../../widgets/main_widget.h */ + /** Widgets of the #MainWindow class. */ + enum MainWidgets { + WID_M_VIEWPORT = ::WID_M_VIEWPORT, ///< Main window viewport. + }; + + /* automatically generated from ../../widgets/misc_widget.h */ + /** Widgets of the #LandInfoWindow class. */ + enum LandInfoWidgets { + WID_LI_BACKGROUND = ::WID_LI_BACKGROUND, ///< Background of the window. + }; + + /** Widgets of the #TooltipsWindow class. */ + enum ToolTipsWidgets { + WID_TT_BACKGROUND = ::WID_TT_BACKGROUND, ///< Background of the window. + }; + + /** Widgets of the #AboutWindow class. */ + enum AboutWidgets { + WID_A_SCROLLING_TEXT = ::WID_A_SCROLLING_TEXT, ///< The actually scrolling text. + WID_A_WEBSITE = ::WID_A_WEBSITE, ///< URL of OpenTTD website. + }; + + /** Widgets of the #QueryStringWindow class. */ + enum QueryStringWidgets { + WID_QS_CAPTION = ::WID_QS_CAPTION, ///< Caption of the window. + WID_QS_TEXT = ::WID_QS_TEXT, ///< Text of the query. + WID_QS_DEFAULT = ::WID_QS_DEFAULT, ///< Default button. + WID_QS_CANCEL = ::WID_QS_CANCEL, ///< Cancel button. + WID_QS_OK = ::WID_QS_OK, ///< OK button. + }; + + /** Widgets of the #QueryWindow class. */ + enum QueryWidgets { + WID_Q_CAPTION = ::WID_Q_CAPTION, ///< Caption of the window. + WID_Q_TEXT = ::WID_Q_TEXT, ///< Text of the query. + WID_Q_NO = ::WID_Q_NO, ///< Yes button. + WID_Q_YES = ::WID_Q_YES, ///< No button. + }; + + /** Widgets of the #TextfileWindow class. */ + enum TextfileWidgets { + WID_TF_CAPTION = ::WID_TF_CAPTION, ///< The caption of the window. + WID_TF_WRAPTEXT = ::WID_TF_WRAPTEXT, ///< Whether or not to wrap the text. + WID_TF_BACKGROUND = ::WID_TF_BACKGROUND, ///< Panel to draw the textfile on. + WID_TF_VSCROLLBAR = ::WID_TF_VSCROLLBAR, ///< Vertical scrollbar to scroll through the textfile up-and-down. + WID_TF_HSCROLLBAR = ::WID_TF_HSCROLLBAR, ///< Horizontal scrollbar to scroll through the textfile left-to-right. + }; + + /* automatically generated from ../../widgets/music_widget.h */ + /** Widgets of the #MusicTrackSelectionWindow class. */ + enum MusicTrackSelectionWidgets { + WID_MTS_LIST_LEFT = ::WID_MTS_LIST_LEFT, ///< Left list. + WID_MTS_LEFT_SCROLLBAR = ::WID_MTS_LEFT_SCROLLBAR, ///< Scrollbar of left list. + WID_MTS_PLAYLIST = ::WID_MTS_PLAYLIST, ///< Playlist name. + WID_MTS_LIST_RIGHT = ::WID_MTS_LIST_RIGHT, ///< Right list. + WID_MTS_RIGHT_SCROLLBAR = ::WID_MTS_RIGHT_SCROLLBAR, ///< Scrollbar of right list. + WID_MTS_ALL = ::WID_MTS_ALL, ///< All button. + WID_MTS_OLD = ::WID_MTS_OLD, ///< Old button. + WID_MTS_NEW = ::WID_MTS_NEW, ///< New button. + WID_MTS_EZY = ::WID_MTS_EZY, ///< Ezy button. + WID_MTS_CUSTOM1 = ::WID_MTS_CUSTOM1, ///< Custom1 button. + WID_MTS_CUSTOM2 = ::WID_MTS_CUSTOM2, ///< Custom2 button. + WID_MTS_CLEAR = ::WID_MTS_CLEAR, ///< Clear button. + }; + + /** Widgets of the #MusicWindow class. */ + enum MusicWidgets { + WID_M_PREV = ::WID_M_PREV, ///< Previous button. + WID_M_NEXT = ::WID_M_NEXT, ///< Next button. + WID_M_STOP = ::WID_M_STOP, ///< Stop button. + WID_M_PLAY = ::WID_M_PLAY, ///< Play button. + WID_M_SLIDERS = ::WID_M_SLIDERS, ///< Sliders. + WID_M_MUSIC_VOL = ::WID_M_MUSIC_VOL, ///< Music volume. + WID_M_EFFECT_VOL = ::WID_M_EFFECT_VOL, ///< Effect volume. + WID_M_BACKGROUND = ::WID_M_BACKGROUND, ///< Background of the window. + WID_M_TRACK = ::WID_M_TRACK, ///< Track playing. + WID_M_TRACK_NR = ::WID_M_TRACK_NR, ///< Track number. + WID_M_TRACK_TITLE = ::WID_M_TRACK_TITLE, ///< Track title. + WID_M_TRACK_NAME = ::WID_M_TRACK_NAME, ///< Track name. + WID_M_SHUFFLE = ::WID_M_SHUFFLE, ///< Shuffle button. + WID_M_PROGRAMME = ::WID_M_PROGRAMME, ///< Program button. + WID_M_ALL = ::WID_M_ALL, ///< All button. + WID_M_OLD = ::WID_M_OLD, ///< Old button. + WID_M_NEW = ::WID_M_NEW, ///< New button. + WID_M_EZY = ::WID_M_EZY, ///< Ezy button. + WID_M_CUSTOM1 = ::WID_M_CUSTOM1, ///< Custom1 button. + WID_M_CUSTOM2 = ::WID_M_CUSTOM2, ///< Custom2 button. + }; + + /* automatically generated from ../../widgets/network_chat_widget.h */ + /** Widgets of the #NetworkChatWindow class. */ + enum NetWorkChatWidgets { + WID_NC_CLOSE = ::WID_NC_CLOSE, ///< Close button. + WID_NC_BACKGROUND = ::WID_NC_BACKGROUND, ///< Background of the window. + WID_NC_DESTINATION = ::WID_NC_DESTINATION, ///< Destination. + WID_NC_TEXTBOX = ::WID_NC_TEXTBOX, ///< Textbox. + WID_NC_SENDBUTTON = ::WID_NC_SENDBUTTON, ///< Send button. + }; + + /* automatically generated from ../../widgets/network_content_widget.h */ + /** Widgets of the #NetworkContentDownloadStatusWindow class. */ + enum NetworkContentDownloadStatusWidgets { + WID_NCDS_BACKGROUND = ::WID_NCDS_BACKGROUND, ///< Background of the window. + WID_NCDS_CANCELOK = ::WID_NCDS_CANCELOK, ///< (Optional) Cancel/OK button. + }; + + /** Widgets of the #NetworkContentListWindow class. */ + enum NetworkContentListWidgets { + WID_NCL_BACKGROUND = ::WID_NCL_BACKGROUND, ///< Resize button. + + WID_NCL_FILTER_CAPT = ::WID_NCL_FILTER_CAPT, ///< Caption for the filter editbox. + WID_NCL_FILTER = ::WID_NCL_FILTER, ///< Filter editbox. + + WID_NCL_CHECKBOX = ::WID_NCL_CHECKBOX, ///< Button above checkboxes. + WID_NCL_TYPE = ::WID_NCL_TYPE, ///< 'Type' button. + WID_NCL_NAME = ::WID_NCL_NAME, ///< 'Name' button. + + WID_NCL_MATRIX = ::WID_NCL_MATRIX, ///< Panel with list of content. + WID_NCL_SCROLLBAR = ::WID_NCL_SCROLLBAR, ///< Scrollbar of matrix. + + WID_NCL_DETAILS = ::WID_NCL_DETAILS, ///< Panel with content details. + WID_NCL_TEXTFILE = ::WID_NCL_TEXTFILE, ///< Open readme, changelog (+1) or license (+2) of a file in the content window. + + WID_NCL_SELECT_ALL = ::WID_NCL_SELECT_ALL, ///< 'Select all' button. + WID_NCL_SELECT_UPDATE = ::WID_NCL_SELECT_UPDATE, ///< 'Select updates' button. + WID_NCL_UNSELECT = ::WID_NCL_UNSELECT, ///< 'Unselect all' button. + WID_NCL_OPEN_URL = ::WID_NCL_OPEN_URL, ///< 'Open url' button. + WID_NCL_CANCEL = ::WID_NCL_CANCEL, ///< 'Cancel' button. + WID_NCL_DOWNLOAD = ::WID_NCL_DOWNLOAD, ///< 'Download' button. + + WID_NCL_SEL_ALL_UPDATE = ::WID_NCL_SEL_ALL_UPDATE, ///< #NWID_SELECTION widget for select all/update buttons.. + WID_NCL_SEARCH_EXTERNAL = ::WID_NCL_SEARCH_EXTERNAL, ///< Search external sites for missing NewGRF. + }; + + /* automatically generated from ../../widgets/network_widget.h */ + /** Widgets of the #NetworkGameWindow class. */ + enum NetworkGameWidgets { + WID_NG_MAIN = ::WID_NG_MAIN, ///< Main panel. + + WID_NG_CONNECTION = ::WID_NG_CONNECTION, ///< Label in front of connection droplist. + WID_NG_CONN_BTN = ::WID_NG_CONN_BTN, ///< 'Connection' droplist button. + WID_NG_CLIENT_LABEL = ::WID_NG_CLIENT_LABEL, ///< Label in front of client name edit box. + WID_NG_CLIENT = ::WID_NG_CLIENT, ///< Panel with editbox to set client name. + WID_NG_FILTER_LABEL = ::WID_NG_FILTER_LABEL, ///< Label in front of the filter/search edit box. + WID_NG_FILTER = ::WID_NG_FILTER, ///< Panel with the edit box to enter the search text. + + WID_NG_HEADER = ::WID_NG_HEADER, ///< Header container of the matrix. + WID_NG_NAME = ::WID_NG_NAME, ///< 'Name' button. + WID_NG_CLIENTS = ::WID_NG_CLIENTS, ///< 'Clients' button. + WID_NG_MAPSIZE = ::WID_NG_MAPSIZE, ///< 'Map size' button. + WID_NG_DATE = ::WID_NG_DATE, ///< 'Date' button. + WID_NG_YEARS = ::WID_NG_YEARS, ///< 'Years' button. + WID_NG_INFO = ::WID_NG_INFO, ///< Third button in the game list panel. + + WID_NG_MATRIX = ::WID_NG_MATRIX, ///< Panel with list of games. + WID_NG_SCROLLBAR = ::WID_NG_SCROLLBAR, ///< Scrollbar of matrix. + + WID_NG_LASTJOINED_LABEL = ::WID_NG_LASTJOINED_LABEL, ///< Label "Last joined server:". + WID_NG_LASTJOINED = ::WID_NG_LASTJOINED, ///< Info about the last joined server. + WID_NG_LASTJOINED_SPACER = ::WID_NG_LASTJOINED_SPACER, ///< Spacer after last joined server panel. + + WID_NG_DETAILS = ::WID_NG_DETAILS, ///< Panel with game details. + WID_NG_DETAILS_SPACER = ::WID_NG_DETAILS_SPACER, ///< Spacer for game actual details. + WID_NG_JOIN = ::WID_NG_JOIN, ///< 'Join game' button. + WID_NG_REFRESH = ::WID_NG_REFRESH, ///< 'Refresh server' button. + WID_NG_NEWGRF = ::WID_NG_NEWGRF, ///< 'NewGRF Settings' button. + WID_NG_NEWGRF_SEL = ::WID_NG_NEWGRF_SEL, ///< Selection 'widget' to hide the NewGRF settings. + WID_NG_NEWGRF_MISSING = ::WID_NG_NEWGRF_MISSING, ///< 'Find missing NewGRF online' button. + WID_NG_NEWGRF_MISSING_SEL = ::WID_NG_NEWGRF_MISSING_SEL, ///< Selection widget for the above button. + + WID_NG_FIND = ::WID_NG_FIND, ///< 'Find server' button. + WID_NG_ADD = ::WID_NG_ADD, ///< 'Add server' button. + WID_NG_START = ::WID_NG_START, ///< 'Start server' button. + WID_NG_CANCEL = ::WID_NG_CANCEL, ///< 'Cancel' button. + }; + + /** Widgets of the #NetworkStartServerWindow class. */ + enum NetworkStartServerWidgets { + WID_NSS_BACKGROUND = ::WID_NSS_BACKGROUND, ///< Background of the window. + WID_NSS_GAMENAME_LABEL = ::WID_NSS_GAMENAME_LABEL, ///< Label for the game name. + WID_NSS_GAMENAME = ::WID_NSS_GAMENAME, ///< Background for editbox to set game name. + WID_NSS_SETPWD = ::WID_NSS_SETPWD, ///< 'Set password' button. + WID_NSS_CONNTYPE_LABEL = ::WID_NSS_CONNTYPE_LABEL, ///< Label for 'connection type'. + WID_NSS_CONNTYPE_BTN = ::WID_NSS_CONNTYPE_BTN, ///< 'Connection type' droplist button. + WID_NSS_CLIENTS_LABEL = ::WID_NSS_CLIENTS_LABEL, ///< Label for 'max clients'. + WID_NSS_CLIENTS_BTND = ::WID_NSS_CLIENTS_BTND, ///< 'Max clients' downarrow. + WID_NSS_CLIENTS_TXT = ::WID_NSS_CLIENTS_TXT, ///< 'Max clients' text. + WID_NSS_CLIENTS_BTNU = ::WID_NSS_CLIENTS_BTNU, ///< 'Max clients' uparrow. + WID_NSS_COMPANIES_LABEL = ::WID_NSS_COMPANIES_LABEL, ///< Label for 'max companies'. + WID_NSS_COMPANIES_BTND = ::WID_NSS_COMPANIES_BTND, ///< 'Max companies' downarrow. + WID_NSS_COMPANIES_TXT = ::WID_NSS_COMPANIES_TXT, ///< 'Max companies' text. + WID_NSS_COMPANIES_BTNU = ::WID_NSS_COMPANIES_BTNU, ///< 'Max companies' uparrow. + WID_NSS_SPECTATORS_LABEL = ::WID_NSS_SPECTATORS_LABEL, ///< Label for 'max spectators'. + WID_NSS_SPECTATORS_BTND = ::WID_NSS_SPECTATORS_BTND, ///< 'Max spectators' downarrow. + WID_NSS_SPECTATORS_TXT = ::WID_NSS_SPECTATORS_TXT, ///< 'Max spectators' text. + WID_NSS_SPECTATORS_BTNU = ::WID_NSS_SPECTATORS_BTNU, ///< 'Max spectators' uparrow. + + WID_NSS_LANGUAGE_LABEL = ::WID_NSS_LANGUAGE_LABEL, ///< Label for 'language spoken'. + WID_NSS_LANGUAGE_BTN = ::WID_NSS_LANGUAGE_BTN, ///< 'Language spoken' droplist button. + + WID_NSS_GENERATE_GAME = ::WID_NSS_GENERATE_GAME, ///< New game button. + WID_NSS_LOAD_GAME = ::WID_NSS_LOAD_GAME, ///< Load game button. + WID_NSS_PLAY_SCENARIO = ::WID_NSS_PLAY_SCENARIO, ///< Play scenario button. + WID_NSS_PLAY_HEIGHTMAP = ::WID_NSS_PLAY_HEIGHTMAP, ///< Play heightmap button. + + WID_NSS_CANCEL = ::WID_NSS_CANCEL, ///< 'Cancel' button. + }; + + /** Widgets of the #NetworkLobbyWindow class. */ + enum NetworkLobbyWidgets { + WID_NL_BACKGROUND = ::WID_NL_BACKGROUND, ///< Background of the window. + WID_NL_TEXT = ::WID_NL_TEXT, ///< Heading text. + WID_NL_HEADER = ::WID_NL_HEADER, ///< Header above list of companies. + WID_NL_MATRIX = ::WID_NL_MATRIX, ///< List of companies. + WID_NL_SCROLLBAR = ::WID_NL_SCROLLBAR, ///< Scroll bar. + WID_NL_DETAILS = ::WID_NL_DETAILS, ///< Company details. + WID_NL_JOIN = ::WID_NL_JOIN, ///< 'Join company' button. + WID_NL_NEW = ::WID_NL_NEW, ///< 'New company' button. + WID_NL_SPECTATE = ::WID_NL_SPECTATE, ///< 'Spectate game' button. + WID_NL_REFRESH = ::WID_NL_REFRESH, ///< 'Refresh server' button. + WID_NL_CANCEL = ::WID_NL_CANCEL, ///< 'Cancel' button. + }; + + /** Widgets of the #NetworkClientListWindow class. */ + enum ClientListWidgets { + WID_CL_PANEL = ::WID_CL_PANEL, ///< Panel of the window. + }; + + /** Widgets of the #NetworkClientListPopupWindow class. */ + enum ClientListPopupWidgets { + WID_CLP_PANEL = ::WID_CLP_PANEL, ///< Panel of the window. + }; + + /** Widgets of the #NetworkJoinStatusWindow class. */ + enum NetworkJoinStatusWidgets { + WID_NJS_BACKGROUND = ::WID_NJS_BACKGROUND, ///< Background of the window. + WID_NJS_CANCELOK = ::WID_NJS_CANCELOK, ///< Cancel / OK button. + }; + + /** Widgets of the #NetworkCompanyPasswordWindow class. */ + enum NetworkCompanyPasswordWidgets { + WID_NCP_BACKGROUND = ::WID_NCP_BACKGROUND, ///< Background of the window. + WID_NCP_LABEL = ::WID_NCP_LABEL, ///< Label in front of the password field. + WID_NCP_PASSWORD = ::WID_NCP_PASSWORD, ///< Input field for the password. + WID_NCP_SAVE_AS_DEFAULT_PASSWORD = ::WID_NCP_SAVE_AS_DEFAULT_PASSWORD, ///< Toggle 'button' for saving the current password as default password. + WID_NCP_CANCEL = ::WID_NCP_CANCEL, ///< Close the window without changing anything. + WID_NCP_OK = ::WID_NCP_OK, ///< Safe the password etc. + }; + + /* automatically generated from ../../widgets/newgrf_debug_widget.h */ + /** Widgets of the #NewGRFInspectWindow class. */ + enum NewGRFInspectWidgets { + WID_NGRFI_CAPTION = ::WID_NGRFI_CAPTION, ///< The caption bar of course. + WID_NGRFI_PARENT = ::WID_NGRFI_PARENT, ///< Inspect the parent. + WID_NGRFI_VEH_PREV = ::WID_NGRFI_VEH_PREV, ///< Go to previous vehicle in chain. + WID_NGRFI_VEH_NEXT = ::WID_NGRFI_VEH_NEXT, ///< Go to next vehicle in chain. + WID_NGRFI_VEH_CHAIN = ::WID_NGRFI_VEH_CHAIN, ///< Display for vehicle chain. + WID_NGRFI_MAINPANEL = ::WID_NGRFI_MAINPANEL, ///< Panel widget containing the actual data. + WID_NGRFI_SCROLLBAR = ::WID_NGRFI_SCROLLBAR, ///< Scrollbar. + }; + + /** Widgets of the #SpriteAlignerWindow class. */ + enum SpriteAlignerWidgets { + WID_SA_CAPTION = ::WID_SA_CAPTION, ///< Caption of the window. + WID_SA_PREVIOUS = ::WID_SA_PREVIOUS, ///< Skip to the previous sprite. + WID_SA_GOTO = ::WID_SA_GOTO, ///< Go to a given sprite. + WID_SA_NEXT = ::WID_SA_NEXT, ///< Skip to the next sprite. + WID_SA_UP = ::WID_SA_UP, ///< Move the sprite up. + WID_SA_LEFT = ::WID_SA_LEFT, ///< Move the sprite to the left. + WID_SA_RIGHT = ::WID_SA_RIGHT, ///< Move the sprite to the right. + WID_SA_DOWN = ::WID_SA_DOWN, ///< Move the sprite down. + WID_SA_SPRITE = ::WID_SA_SPRITE, ///< The actual sprite. + WID_SA_OFFSETS = ::WID_SA_OFFSETS, ///< The sprite offsets. + WID_SA_PICKER = ::WID_SA_PICKER, ///< Sprite picker. + WID_SA_LIST = ::WID_SA_LIST, ///< Queried sprite list. + WID_SA_SCROLLBAR = ::WID_SA_SCROLLBAR, ///< Scrollbar for sprite list. + }; + + /* automatically generated from ../../widgets/newgrf_widget.h */ + /** Widgets of the #NewGRFParametersWindow class. */ + enum NewGRFParametersWidgets { + WID_NP_SHOW_NUMPAR = ::WID_NP_SHOW_NUMPAR, ///< #NWID_SELECTION to optionally display #WID_NP_NUMPAR. + WID_NP_NUMPAR_DEC = ::WID_NP_NUMPAR_DEC, ///< Button to decrease number of parameters. + WID_NP_NUMPAR_INC = ::WID_NP_NUMPAR_INC, ///< Button to increase number of parameters. + WID_NP_NUMPAR = ::WID_NP_NUMPAR, ///< Optional number of parameters. + WID_NP_NUMPAR_TEXT = ::WID_NP_NUMPAR_TEXT, ///< Text description. + WID_NP_BACKGROUND = ::WID_NP_BACKGROUND, ///< Panel to draw the settings on. + WID_NP_SCROLLBAR = ::WID_NP_SCROLLBAR, ///< Scrollbar to scroll through all settings. + WID_NP_ACCEPT = ::WID_NP_ACCEPT, ///< Accept button. + WID_NP_RESET = ::WID_NP_RESET, ///< Reset button. + WID_NP_SHOW_DESCRIPTION = ::WID_NP_SHOW_DESCRIPTION, ///< #NWID_SELECTION to optionally display parameter descriptions. + WID_NP_DESCRIPTION = ::WID_NP_DESCRIPTION, ///< Multi-line description of a parameter. + }; + + /** Widgets of the #NewGRFWindow class. */ + enum NewGRFStateWidgets { + WID_NS_PRESET_LIST = ::WID_NS_PRESET_LIST, ///< Active NewGRF preset. + WID_NS_PRESET_SAVE = ::WID_NS_PRESET_SAVE, ///< Save list of active NewGRFs as presets. + WID_NS_PRESET_DELETE = ::WID_NS_PRESET_DELETE, ///< Delete active preset. + WID_NS_ADD = ::WID_NS_ADD, ///< Add NewGRF to active list. + WID_NS_REMOVE = ::WID_NS_REMOVE, ///< Remove NewGRF from active list. + WID_NS_MOVE_UP = ::WID_NS_MOVE_UP, ///< Move NewGRF up in active list. + WID_NS_MOVE_DOWN = ::WID_NS_MOVE_DOWN, ///< Move NewGRF down in active list. + WID_NS_FILTER = ::WID_NS_FILTER, ///< Filter list of available NewGRFs. + WID_NS_FILE_LIST = ::WID_NS_FILE_LIST, ///< List window of active NewGRFs. + WID_NS_SCROLLBAR = ::WID_NS_SCROLLBAR, ///< Scrollbar for active NewGRF list. + WID_NS_AVAIL_LIST = ::WID_NS_AVAIL_LIST, ///< List window of available NewGRFs. + WID_NS_SCROLL2BAR = ::WID_NS_SCROLL2BAR, ///< Scrollbar for available NewGRF list. + WID_NS_NEWGRF_INFO_TITLE = ::WID_NS_NEWGRF_INFO_TITLE, ///< Title for Info on selected NewGRF. + WID_NS_NEWGRF_INFO = ::WID_NS_NEWGRF_INFO, ///< Panel for Info on selected NewGRF. + WID_NS_OPEN_URL = ::WID_NS_OPEN_URL, ///< Open URL of NewGRF. + WID_NS_NEWGRF_TEXTFILE = ::WID_NS_NEWGRF_TEXTFILE, ///< Open NewGRF readme, changelog (+1) or license (+2). + WID_NS_SET_PARAMETERS = ::WID_NS_SET_PARAMETERS, ///< Open Parameters Window for selected NewGRF for editing parameters. + WID_NS_VIEW_PARAMETERS = ::WID_NS_VIEW_PARAMETERS, ///< Open Parameters Window for selected NewGRF for viewing parameters. + WID_NS_TOGGLE_PALETTE = ::WID_NS_TOGGLE_PALETTE, ///< Toggle Palette of selected, active NewGRF. + WID_NS_APPLY_CHANGES = ::WID_NS_APPLY_CHANGES, ///< Apply changes to NewGRF config. + WID_NS_RESCAN_FILES = ::WID_NS_RESCAN_FILES, ///< Rescan files (available NewGRFs). + WID_NS_RESCAN_FILES2 = ::WID_NS_RESCAN_FILES2, ///< Rescan files (active NewGRFs). + WID_NS_CONTENT_DOWNLOAD = ::WID_NS_CONTENT_DOWNLOAD, ///< Open content download (available NewGRFs). + WID_NS_CONTENT_DOWNLOAD2 = ::WID_NS_CONTENT_DOWNLOAD2, ///< Open content download (active NewGRFs). + WID_NS_SHOW_REMOVE = ::WID_NS_SHOW_REMOVE, ///< Select active list buttons (0, 1 = simple layout). + WID_NS_SHOW_APPLY = ::WID_NS_SHOW_APPLY, ///< Select display of the buttons below the 'details'. + }; + + /** Widgets of the #ScanProgressWindow class. */ + enum ScanProgressWidgets { + WID_SP_PROGRESS_BAR = ::WID_SP_PROGRESS_BAR, ///< Simple progress bar. + WID_SP_PROGRESS_TEXT = ::WID_SP_PROGRESS_TEXT, ///< Text explaining what is happening. + }; + + /* automatically generated from ../../widgets/news_widget.h */ + /** Widgets of the #NewsWindow class. */ + enum NewsWidgets { + WID_N_PANEL = ::WID_N_PANEL, ///< Panel of the window. + WID_N_TITLE = ::WID_N_TITLE, ///< Title of the company news. + WID_N_HEADLINE = ::WID_N_HEADLINE, ///< The news headline. + WID_N_CLOSEBOX = ::WID_N_CLOSEBOX, ///< Close the window. + WID_N_DATE = ::WID_N_DATE, ///< Date of the news item. + WID_N_CAPTION = ::WID_N_CAPTION, ///< Title bar of the window. Only used in small news items. + WID_N_INSET = ::WID_N_INSET, ///< Inset around the viewport in the window. Only used in small news items. + WID_N_VIEWPORT = ::WID_N_VIEWPORT, ///< Viewport in the window. + WID_N_COMPANY_MSG = ::WID_N_COMPANY_MSG, ///< Message in company news items. + WID_N_MESSAGE = ::WID_N_MESSAGE, ///< Space for displaying the message. Only used in small news items. + WID_N_MGR_FACE = ::WID_N_MGR_FACE, ///< Face of the manager. + WID_N_MGR_NAME = ::WID_N_MGR_NAME, ///< Name of the manager. + WID_N_VEH_TITLE = ::WID_N_VEH_TITLE, ///< Vehicle new title. + WID_N_VEH_BKGND = ::WID_N_VEH_BKGND, ///< Dark background of new vehicle news. + WID_N_VEH_NAME = ::WID_N_VEH_NAME, ///< Name of the new vehicle. + WID_N_VEH_SPR = ::WID_N_VEH_SPR, ///< Graphical display of the new vehicle. + WID_N_VEH_INFO = ::WID_N_VEH_INFO, ///< Some technical data of the new vehicle. + }; + + /** Widgets of the #MessageHistoryWindow class. */ + enum MessageHistoryWidgets { + WID_MH_STICKYBOX = ::WID_MH_STICKYBOX, ///< Stickybox. + WID_MH_BACKGROUND = ::WID_MH_BACKGROUND, ///< Background of the window. + WID_MH_SCROLLBAR = ::WID_MH_SCROLLBAR, ///< Scrollbar for the list. + }; + + /* automatically generated from ../../widgets/object_widget.h */ + /** Widgets of the #BuildObjectWindow class. */ + enum BuildObjectWidgets { + WID_BO_CLASS_LIST = ::WID_BO_CLASS_LIST, ///< The list with classes. + WID_BO_SCROLLBAR = ::WID_BO_SCROLLBAR, ///< The scrollbar associated with the list. + WID_BO_OBJECT_MATRIX = ::WID_BO_OBJECT_MATRIX, ///< The matrix with preview sprites. + WID_BO_OBJECT_SPRITE = ::WID_BO_OBJECT_SPRITE, ///< A preview sprite of the object. + WID_BO_OBJECT_NAME = ::WID_BO_OBJECT_NAME, ///< The name of the selected object. + WID_BO_OBJECT_SIZE = ::WID_BO_OBJECT_SIZE, ///< The size of the selected object. + WID_BO_INFO = ::WID_BO_INFO, ///< Other information about the object (from the NewGRF). + + WID_BO_SELECT_MATRIX = ::WID_BO_SELECT_MATRIX, ///< Selection preview matrix of objects of a given class. + WID_BO_SELECT_IMAGE = ::WID_BO_SELECT_IMAGE, ///< Preview image in the #WID_BO_SELECT_MATRIX. + WID_BO_SELECT_SCROLL = ::WID_BO_SELECT_SCROLL, ///< Scrollbar next to the #WID_BO_SELECT_MATRIX. + }; + + /* automatically generated from ../../widgets/order_widget.h */ + /** Widgets of the #OrdersWindow class. */ + enum OrderWidgets { + WID_O_CAPTION = ::WID_O_CAPTION, ///< Caption of the window. + WID_O_TIMETABLE_VIEW = ::WID_O_TIMETABLE_VIEW, ///< Toggle timetable view. + WID_O_ORDER_LIST = ::WID_O_ORDER_LIST, ///< Order list panel. + WID_O_SCROLLBAR = ::WID_O_SCROLLBAR, ///< Order list scrollbar. + WID_O_SKIP = ::WID_O_SKIP, ///< Skip current order. + WID_O_DELETE = ::WID_O_DELETE, ///< Delete selected order. + WID_O_STOP_SHARING = ::WID_O_STOP_SHARING, ///< Stop sharing orders. + WID_O_NON_STOP = ::WID_O_NON_STOP, ///< Goto non-stop to destination. + WID_O_GOTO = ::WID_O_GOTO, ///< Goto destination. + WID_O_FULL_LOAD = ::WID_O_FULL_LOAD, ///< Select full load. + WID_O_UNLOAD = ::WID_O_UNLOAD, ///< Select unload. + WID_O_REFIT = ::WID_O_REFIT, ///< Select refit. + WID_O_SERVICE = ::WID_O_SERVICE, ///< Select service (at depot). + WID_O_EMPTY = ::WID_O_EMPTY, ///< Placeholder for refit dropdown when not owner. + WID_O_REFIT_DROPDOWN = ::WID_O_REFIT_DROPDOWN, ///< Open refit options. + WID_O_COND_VARIABLE = ::WID_O_COND_VARIABLE, ///< Choose condition variable. + WID_O_COND_COMPARATOR = ::WID_O_COND_COMPARATOR, ///< Choose condition type. + WID_O_COND_VALUE = ::WID_O_COND_VALUE, ///< Choose condition value. + WID_O_SEL_TOP_LEFT = ::WID_O_SEL_TOP_LEFT, ///< #NWID_SELECTION widget for left part of the top row of the 'your train' order window. + WID_O_SEL_TOP_MIDDLE = ::WID_O_SEL_TOP_MIDDLE, ///< #NWID_SELECTION widget for middle part of the top row of the 'your train' order window. + WID_O_SEL_TOP_RIGHT = ::WID_O_SEL_TOP_RIGHT, ///< #NWID_SELECTION widget for right part of the top row of the 'your train' order window. + WID_O_SEL_TOP_ROW_GROUNDVEHICLE = ::WID_O_SEL_TOP_ROW_GROUNDVEHICLE, ///< #NWID_SELECTION widget for the top row of the 'your train' order window. + WID_O_SEL_TOP_ROW = ::WID_O_SEL_TOP_ROW, ///< #NWID_SELECTION widget for the top row of the 'your non-trains' order window. + WID_O_SEL_BOTTOM_MIDDLE = ::WID_O_SEL_BOTTOM_MIDDLE, ///< #NWID_SELECTION widget for the middle part of the bottom row of the 'your train' order window. + WID_O_SHARED_ORDER_LIST = ::WID_O_SHARED_ORDER_LIST, ///< Open list of shared vehicles. + }; + + /* automatically generated from ../../widgets/osk_widget.h */ + /** Widgets of the #OskWindow class. */ + enum OnScreenKeyboardWidgets { + WID_OSK_CAPTION = ::WID_OSK_CAPTION, ///< Caption of window. + WID_OSK_TEXT = ::WID_OSK_TEXT, ///< Edit box. + WID_OSK_CANCEL = ::WID_OSK_CANCEL, ///< Cancel key. + WID_OSK_OK = ::WID_OSK_OK, ///< Ok key. + WID_OSK_BACKSPACE = ::WID_OSK_BACKSPACE, ///< Backspace key. + WID_OSK_SPECIAL = ::WID_OSK_SPECIAL, ///< Special key (at keyboards often used for tab key). + WID_OSK_CAPS = ::WID_OSK_CAPS, ///< Capslock key. + WID_OSK_SHIFT = ::WID_OSK_SHIFT, ///< Shift(lock) key. + WID_OSK_SPACE = ::WID_OSK_SPACE, ///< Space bar. + WID_OSK_LEFT = ::WID_OSK_LEFT, ///< Cursor left key. + WID_OSK_RIGHT = ::WID_OSK_RIGHT, ///< Cursor right key. + WID_OSK_LETTERS = ::WID_OSK_LETTERS, ///< First widget of the 'normal' keys. + + WID_OSK_NUMBERS_FIRST = ::WID_OSK_NUMBERS_FIRST, ///< First widget of the numbers row. + WID_OSK_NUMBERS_LAST = ::WID_OSK_NUMBERS_LAST, ///< Last widget of the numbers row. + + WID_OSK_QWERTY_FIRST = ::WID_OSK_QWERTY_FIRST, ///< First widget of the qwerty row. + WID_OSK_QWERTY_LAST = ::WID_OSK_QWERTY_LAST, ///< Last widget of the qwerty row. + + WID_OSK_ASDFG_FIRST = ::WID_OSK_ASDFG_FIRST, ///< First widget of the asdfg row. + WID_OSK_ASDFG_LAST = ::WID_OSK_ASDFG_LAST, ///< Last widget of the asdfg row. + + WID_OSK_ZXCVB_FIRST = ::WID_OSK_ZXCVB_FIRST, ///< First widget of the zxcvb row. + WID_OSK_ZXCVB_LAST = ::WID_OSK_ZXCVB_LAST, ///< Last widget of the zxcvb row. + }; + + /* automatically generated from ../../widgets/rail_widget.h */ + /** Widgets of the #BuildRailToolbarWindow class. */ + enum RailToolbarWidgets { + /* Name starts with RA instead of R, because of collision with RoadToolbarWidgets */ + WID_RAT_CAPTION = ::WID_RAT_CAPTION, ///< Caption of the window. + WID_RAT_BUILD_NS = ::WID_RAT_BUILD_NS, ///< Build rail along the game view Y axis. + WID_RAT_BUILD_X = ::WID_RAT_BUILD_X, ///< Build rail along the game grid X axis. + WID_RAT_BUILD_EW = ::WID_RAT_BUILD_EW, ///< Build rail along the game view X axis. + WID_RAT_BUILD_Y = ::WID_RAT_BUILD_Y, ///< Build rail along the game grid Y axis. + WID_RAT_AUTORAIL = ::WID_RAT_AUTORAIL, ///< Autorail tool. + WID_RAT_DEMOLISH = ::WID_RAT_DEMOLISH, ///< Destroy something with dynamite! + WID_RAT_BUILD_DEPOT = ::WID_RAT_BUILD_DEPOT, ///< Build a depot. + WID_RAT_BUILD_WAYPOINT = ::WID_RAT_BUILD_WAYPOINT, ///< Build a waypoint. + WID_RAT_BUILD_STATION = ::WID_RAT_BUILD_STATION, ///< Build a station. + WID_RAT_BUILD_SIGNALS = ::WID_RAT_BUILD_SIGNALS, ///< Build signals. + WID_RAT_BUILD_BRIDGE = ::WID_RAT_BUILD_BRIDGE, ///< Build a bridge. + WID_RAT_BUILD_TUNNEL = ::WID_RAT_BUILD_TUNNEL, ///< Build a tunnel. + WID_RAT_REMOVE = ::WID_RAT_REMOVE, ///< Bulldozer to remove rail. + WID_RAT_CONVERT_RAIL = ::WID_RAT_CONVERT_RAIL, ///< Convert other rail to this type. + }; + + /** Widgets of the #BuildRailStationWindow class. */ + enum BuildRailStationWidgets { + /* Name starts with BRA instead of BR, because of collision with BuildRoadStationWidgets */ + WID_BRAS_PLATFORM_DIR_X = ::WID_BRAS_PLATFORM_DIR_X, ///< Button to select '/' view. + WID_BRAS_PLATFORM_DIR_Y = ::WID_BRAS_PLATFORM_DIR_Y, ///< Button to select '\' view. + + WID_BRAS_PLATFORM_NUM_1 = ::WID_BRAS_PLATFORM_NUM_1, ///< Button to select stations with a single platform. + WID_BRAS_PLATFORM_NUM_2 = ::WID_BRAS_PLATFORM_NUM_2, ///< Button to select stations with 2 platforms. + WID_BRAS_PLATFORM_NUM_3 = ::WID_BRAS_PLATFORM_NUM_3, ///< Button to select stations with 3 platforms. + WID_BRAS_PLATFORM_NUM_4 = ::WID_BRAS_PLATFORM_NUM_4, ///< Button to select stations with 4 platforms. + WID_BRAS_PLATFORM_NUM_5 = ::WID_BRAS_PLATFORM_NUM_5, ///< Button to select stations with 5 platforms. + WID_BRAS_PLATFORM_NUM_6 = ::WID_BRAS_PLATFORM_NUM_6, ///< Button to select stations with 6 platforms. + WID_BRAS_PLATFORM_NUM_7 = ::WID_BRAS_PLATFORM_NUM_7, ///< Button to select stations with 7 platforms. + + WID_BRAS_PLATFORM_LEN_1 = ::WID_BRAS_PLATFORM_LEN_1, ///< Button to select single tile length station platforms. + WID_BRAS_PLATFORM_LEN_2 = ::WID_BRAS_PLATFORM_LEN_2, ///< Button to select 2 tiles length station platforms. + WID_BRAS_PLATFORM_LEN_3 = ::WID_BRAS_PLATFORM_LEN_3, ///< Button to select 3 tiles length station platforms. + WID_BRAS_PLATFORM_LEN_4 = ::WID_BRAS_PLATFORM_LEN_4, ///< Button to select 4 tiles length station platforms. + WID_BRAS_PLATFORM_LEN_5 = ::WID_BRAS_PLATFORM_LEN_5, ///< Button to select 5 tiles length station platforms. + WID_BRAS_PLATFORM_LEN_6 = ::WID_BRAS_PLATFORM_LEN_6, ///< Button to select 6 tiles length station platforms. + WID_BRAS_PLATFORM_LEN_7 = ::WID_BRAS_PLATFORM_LEN_7, ///< Button to select 7 tiles length station platforms. + + WID_BRAS_PLATFORM_DRAG_N_DROP = ::WID_BRAS_PLATFORM_DRAG_N_DROP, ///< Button to enable drag and drop type station placement. + + WID_BRAS_HIGHLIGHT_OFF = ::WID_BRAS_HIGHLIGHT_OFF, ///< Button for turning coverage highlighting off. + WID_BRAS_HIGHLIGHT_ON = ::WID_BRAS_HIGHLIGHT_ON, ///< Button for turning coverage highlighting on. + WID_BRAS_COVERAGE_TEXTS = ::WID_BRAS_COVERAGE_TEXTS, ///< Empty space for the coverage texts. + + WID_BRAS_MATRIX = ::WID_BRAS_MATRIX, ///< Matrix widget displaying the available stations. + WID_BRAS_IMAGE = ::WID_BRAS_IMAGE, ///< Panel used at each cell of the matrix. + WID_BRAS_MATRIX_SCROLL = ::WID_BRAS_MATRIX_SCROLL, ///< Scrollbar of the matrix widget. + + WID_BRAS_SHOW_NEWST_DEFSIZE = ::WID_BRAS_SHOW_NEWST_DEFSIZE, ///< Selection for default-size button for newstation. + WID_BRAS_SHOW_NEWST_ADDITIONS = ::WID_BRAS_SHOW_NEWST_ADDITIONS, ///< Selection for newstation class selection list. + WID_BRAS_SHOW_NEWST_MATRIX = ::WID_BRAS_SHOW_NEWST_MATRIX, ///< Selection for newstation image matrix. + WID_BRAS_SHOW_NEWST_RESIZE = ::WID_BRAS_SHOW_NEWST_RESIZE, ///< Selection for panel and resize at bottom right for newstation. + WID_BRAS_SHOW_NEWST_TYPE = ::WID_BRAS_SHOW_NEWST_TYPE, ///< Display of selected station type. + WID_BRAS_NEWST_LIST = ::WID_BRAS_NEWST_LIST, ///< List with available newstation classes. + WID_BRAS_NEWST_SCROLL = ::WID_BRAS_NEWST_SCROLL, ///< Scrollbar of the #WID_BRAS_NEWST_LIST. + + WID_BRAS_PLATFORM_NUM_BEGIN = ::WID_BRAS_PLATFORM_NUM_BEGIN, ///< Helper for determining the chosen platform width. + WID_BRAS_PLATFORM_LEN_BEGIN = ::WID_BRAS_PLATFORM_LEN_BEGIN, ///< Helper for determining the chosen platform length. + }; + + /** Widgets of the #BuildSignalWindow class. */ + enum BuildSignalWidgets { + WID_BS_SEMAPHORE_NORM = ::WID_BS_SEMAPHORE_NORM, ///< Build a semaphore normal block signal + WID_BS_SEMAPHORE_ENTRY = ::WID_BS_SEMAPHORE_ENTRY, ///< Build a semaphore entry block signal + WID_BS_SEMAPHORE_EXIT = ::WID_BS_SEMAPHORE_EXIT, ///< Build a semaphore exit block signal + WID_BS_SEMAPHORE_COMBO = ::WID_BS_SEMAPHORE_COMBO, ///< Build a semaphore combo block signal + WID_BS_SEMAPHORE_PBS = ::WID_BS_SEMAPHORE_PBS, ///< Build a semaphore path signal. + WID_BS_SEMAPHORE_PBS_OWAY = ::WID_BS_SEMAPHORE_PBS_OWAY, ///< Build a semaphore one way path signal. + WID_BS_ELECTRIC_NORM = ::WID_BS_ELECTRIC_NORM, ///< Build an electric normal block signal + WID_BS_ELECTRIC_ENTRY = ::WID_BS_ELECTRIC_ENTRY, ///< Build an electric entry block signal + WID_BS_ELECTRIC_EXIT = ::WID_BS_ELECTRIC_EXIT, ///< Build an electric exit block signal + WID_BS_ELECTRIC_COMBO = ::WID_BS_ELECTRIC_COMBO, ///< Build an electric combo block signal + WID_BS_ELECTRIC_PBS = ::WID_BS_ELECTRIC_PBS, ///< Build an electric path signal. + WID_BS_ELECTRIC_PBS_OWAY = ::WID_BS_ELECTRIC_PBS_OWAY, ///< Build an electric one way path signal. + WID_BS_CONVERT = ::WID_BS_CONVERT, ///< Convert the signal. + WID_BS_DRAG_SIGNALS_DENSITY_LABEL = ::WID_BS_DRAG_SIGNALS_DENSITY_LABEL, ///< The current signal density. + WID_BS_DRAG_SIGNALS_DENSITY_DECREASE = ::WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, ///< Decrease the signal density. + WID_BS_DRAG_SIGNALS_DENSITY_INCREASE = ::WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, ///< Increase the signal density. + }; + + /** Widgets of the #BuildRailDepotWindow class. */ + enum BuildRailDepotWidgets { + /* Name starts with BRA instead of BR, because of collision with BuildRoadDepotWidgets */ + WID_BRAD_DEPOT_NE = ::WID_BRAD_DEPOT_NE, ///< Build a depot with the entrance in the north east. + WID_BRAD_DEPOT_SE = ::WID_BRAD_DEPOT_SE, ///< Build a depot with the entrance in the south east. + WID_BRAD_DEPOT_SW = ::WID_BRAD_DEPOT_SW, ///< Build a depot with the entrance in the south west. + WID_BRAD_DEPOT_NW = ::WID_BRAD_DEPOT_NW, ///< Build a depot with the entrance in the north west. + }; + + /** Widgets of the #BuildRailWaypointWindow class. */ + enum BuildRailWaypointWidgets { + WID_BRW_WAYPOINT_MATRIX = ::WID_BRW_WAYPOINT_MATRIX, ///< Matrix with waypoints. + WID_BRW_WAYPOINT = ::WID_BRW_WAYPOINT, ///< A single waypoint. + WID_BRW_SCROLL = ::WID_BRW_SCROLL, ///< Scrollbar for the matrix. + }; + + /* automatically generated from ../../widgets/road_widget.h */ + /** Widgets of the #BuildRoadToolbarWindow class. */ + enum RoadToolbarWidgets { + /* Name starts with RO instead of R, because of collision with RailToolbarWidgets */ + WID_ROT_ROAD_X = ::WID_ROT_ROAD_X, ///< Build road in x-direction. + WID_ROT_ROAD_Y = ::WID_ROT_ROAD_Y, ///< Build road in y-direction. + WID_ROT_AUTOROAD = ::WID_ROT_AUTOROAD, ///< Autorail. + WID_ROT_DEMOLISH = ::WID_ROT_DEMOLISH, ///< Demolish. + WID_ROT_DEPOT = ::WID_ROT_DEPOT, ///< Build depot. + WID_ROT_BUS_STATION = ::WID_ROT_BUS_STATION, ///< Build bus station. + WID_ROT_TRUCK_STATION = ::WID_ROT_TRUCK_STATION, ///< Build truck station. + WID_ROT_ONE_WAY = ::WID_ROT_ONE_WAY, ///< Build one-way road. + WID_ROT_BUILD_BRIDGE = ::WID_ROT_BUILD_BRIDGE, ///< Build bridge. + WID_ROT_BUILD_TUNNEL = ::WID_ROT_BUILD_TUNNEL, ///< Build tunnel. + WID_ROT_REMOVE = ::WID_ROT_REMOVE, ///< Remove road. + }; + + /** Widgets of the #BuildRoadDepotWindow class. */ + enum BuildRoadDepotWidgets { + /* Name starts with BRO instead of BR, because of collision with BuildRailDepotWidgets */ + WID_BROD_CAPTION = ::WID_BROD_CAPTION, ///< Caption of the window. + WID_BROD_DEPOT_NE = ::WID_BROD_DEPOT_NE, ///< Depot with NE entry. + WID_BROD_DEPOT_SE = ::WID_BROD_DEPOT_SE, ///< Depot with SE entry. + WID_BROD_DEPOT_SW = ::WID_BROD_DEPOT_SW, ///< Depot with SW entry. + WID_BROD_DEPOT_NW = ::WID_BROD_DEPOT_NW, ///< Depot with NW entry. + }; + + /** Widgets of the #BuildRoadStationWindow class. */ + enum BuildRoadStationWidgets { + /* Name starts with BRO instead of BR, because of collision with BuildRailStationWidgets */ + WID_BROS_CAPTION = ::WID_BROS_CAPTION, ///< Caption of the window. + WID_BROS_BACKGROUND = ::WID_BROS_BACKGROUND, ///< Background of the window. + WID_BROS_STATION_NE = ::WID_BROS_STATION_NE, ///< Terminal station with NE entry. + WID_BROS_STATION_SE = ::WID_BROS_STATION_SE, ///< Terminal station with SE entry. + WID_BROS_STATION_SW = ::WID_BROS_STATION_SW, ///< Terminal station with SW entry. + WID_BROS_STATION_NW = ::WID_BROS_STATION_NW, ///< Terminal station with NW entry. + WID_BROS_STATION_X = ::WID_BROS_STATION_X, ///< Drive-through station in x-direction. + WID_BROS_STATION_Y = ::WID_BROS_STATION_Y, ///< Drive-through station in y-direction. + WID_BROS_LT_OFF = ::WID_BROS_LT_OFF, ///< Turn off area highlight. + WID_BROS_LT_ON = ::WID_BROS_LT_ON, ///< Turn on area highlight. + WID_BROS_INFO = ::WID_BROS_INFO, ///< Station acceptance info. + }; + + /* automatically generated from ../../widgets/settings_widget.h */ + /** Widgets of the #GameOptionsWindow class. */ + enum GameOptionsWidgets { + WID_GO_BACKGROUND = ::WID_GO_BACKGROUND, ///< Background of the window. + WID_GO_CURRENCY_DROPDOWN = ::WID_GO_CURRENCY_DROPDOWN, ///< Currency dropdown. + WID_GO_DISTANCE_DROPDOWN = ::WID_GO_DISTANCE_DROPDOWN, ///< Measuring unit dropdown. + WID_GO_ROADSIDE_DROPDOWN = ::WID_GO_ROADSIDE_DROPDOWN, ///< Dropdown to select the road side (to set the right side ;)). + WID_GO_TOWNNAME_DROPDOWN = ::WID_GO_TOWNNAME_DROPDOWN, ///< Town name dropdown. + WID_GO_AUTOSAVE_DROPDOWN = ::WID_GO_AUTOSAVE_DROPDOWN, ///< Dropdown to say how often to autosave. + WID_GO_LANG_DROPDOWN = ::WID_GO_LANG_DROPDOWN, ///< Language dropdown. + WID_GO_RESOLUTION_DROPDOWN = ::WID_GO_RESOLUTION_DROPDOWN, ///< Dropdown for the resolution. + WID_GO_FULLSCREEN_BUTTON = ::WID_GO_FULLSCREEN_BUTTON, ///< Toggle fullscreen. + WID_GO_SCREENSHOT_DROPDOWN = ::WID_GO_SCREENSHOT_DROPDOWN, ///< Select the screenshot type... please use PNG!. + WID_GO_BASE_GRF_DROPDOWN = ::WID_GO_BASE_GRF_DROPDOWN, ///< Use to select a base GRF. + WID_GO_BASE_GRF_STATUS = ::WID_GO_BASE_GRF_STATUS, ///< Info about missing files etc. + WID_GO_BASE_GRF_TEXTFILE = ::WID_GO_BASE_GRF_TEXTFILE, ///< Open base GRF readme, changelog (+1) or license (+2). + WID_GO_BASE_GRF_DESCRIPTION = ::WID_GO_BASE_GRF_DESCRIPTION, ///< Description of selected base GRF. + WID_GO_BASE_SFX_DROPDOWN = ::WID_GO_BASE_SFX_DROPDOWN, ///< Use to select a base SFX. + WID_GO_BASE_SFX_TEXTFILE = ::WID_GO_BASE_SFX_TEXTFILE, ///< Open base SFX readme, changelog (+1) or license (+2). + WID_GO_BASE_SFX_DESCRIPTION = ::WID_GO_BASE_SFX_DESCRIPTION, ///< Description of selected base SFX. + WID_GO_BASE_MUSIC_DROPDOWN = ::WID_GO_BASE_MUSIC_DROPDOWN, ///< Use to select a base music set. + WID_GO_BASE_MUSIC_STATUS = ::WID_GO_BASE_MUSIC_STATUS, ///< Info about corrupted files etc. + WID_GO_BASE_MUSIC_TEXTFILE = ::WID_GO_BASE_MUSIC_TEXTFILE, ///< Open base music readme, changelog (+1) or license (+2). + WID_GO_BASE_MUSIC_DESCRIPTION = ::WID_GO_BASE_MUSIC_DESCRIPTION, ///< Description of selected base music set. + }; + + /** Widgets of the #GameSettingsWindow class. */ + enum GameSettingsWidgets { + WID_GS_FILTER = ::WID_GS_FILTER, ///< Text filter. + WID_GS_OPTIONSPANEL = ::WID_GS_OPTIONSPANEL, ///< Panel widget containing the option lists. + WID_GS_SCROLLBAR = ::WID_GS_SCROLLBAR, ///< Scrollbar. + WID_GS_HELP_TEXT = ::WID_GS_HELP_TEXT, ///< Information area to display help text of the selected option. + WID_GS_EXPAND_ALL = ::WID_GS_EXPAND_ALL, ///< Expand all button. + WID_GS_COLLAPSE_ALL = ::WID_GS_COLLAPSE_ALL, ///< Collapse all button. + WID_GS_RESTRICT_CATEGORY = ::WID_GS_RESTRICT_CATEGORY, ///< Label upfront to the category drop-down box to restrict the list of settings to show + WID_GS_RESTRICT_TYPE = ::WID_GS_RESTRICT_TYPE, ///< Label upfront to the type drop-down box to restrict the list of settings to show + WID_GS_RESTRICT_DROPDOWN = ::WID_GS_RESTRICT_DROPDOWN, ///< The drop down box to restrict the list of settings + WID_GS_TYPE_DROPDOWN = ::WID_GS_TYPE_DROPDOWN, ///< The drop down box to choose client/game/company/all settings + }; + + /** Widgets of the #CustomCurrencyWindow class. */ + enum CustomCurrencyWidgets { + WID_CC_RATE_DOWN = ::WID_CC_RATE_DOWN, ///< Down button. + WID_CC_RATE_UP = ::WID_CC_RATE_UP, ///< Up button. + WID_CC_RATE = ::WID_CC_RATE, ///< Rate of currency. + WID_CC_SEPARATOR_EDIT = ::WID_CC_SEPARATOR_EDIT, ///< Separator edit button. + WID_CC_SEPARATOR = ::WID_CC_SEPARATOR, ///< Current separator. + WID_CC_PREFIX_EDIT = ::WID_CC_PREFIX_EDIT, ///< Prefix edit button. + WID_CC_PREFIX = ::WID_CC_PREFIX, ///< Current prefix. + WID_CC_SUFFIX_EDIT = ::WID_CC_SUFFIX_EDIT, ///< Suffix edit button. + WID_CC_SUFFIX = ::WID_CC_SUFFIX, ///< Current suffix. + WID_CC_YEAR_DOWN = ::WID_CC_YEAR_DOWN, ///< Down button. + WID_CC_YEAR_UP = ::WID_CC_YEAR_UP, ///< Up button. + WID_CC_YEAR = ::WID_CC_YEAR, ///< Year of introduction. + WID_CC_PREVIEW = ::WID_CC_PREVIEW, ///< Preview. + }; + + /* automatically generated from ../../widgets/sign_widget.h */ + /** Widgets of the #SignListWindow class. */ + enum SignListWidgets { + /* Name starts with SI instead of S, because of collision with SaveLoadWidgets */ + WID_SIL_CAPTION = ::WID_SIL_CAPTION, ///< Caption of the window. + WID_SIL_LIST = ::WID_SIL_LIST, ///< List of signs. + WID_SIL_SCROLLBAR = ::WID_SIL_SCROLLBAR, ///< Scrollbar of list. + WID_SIL_FILTER_TEXT = ::WID_SIL_FILTER_TEXT, ///< Text box for typing a filter string. + WID_SIL_FILTER_MATCH_CASE_BTN = ::WID_SIL_FILTER_MATCH_CASE_BTN, ///< Button to toggle if case sensitive filtering should be used. + WID_SIL_FILTER_ENTER_BTN = ::WID_SIL_FILTER_ENTER_BTN, ///< Scroll to first sign. + }; + + /** Widgets of the #SignWindow class. */ + enum QueryEditSignWidgets { + WID_QES_CAPTION = ::WID_QES_CAPTION, ///< Caption of the window. + WID_QES_TEXT = ::WID_QES_TEXT, ///< Text of the query. + WID_QES_OK = ::WID_QES_OK, ///< OK button. + WID_QES_CANCEL = ::WID_QES_CANCEL, ///< Cancel button. + WID_QES_DELETE = ::WID_QES_DELETE, ///< Delete button. + WID_QES_PREVIOUS = ::WID_QES_PREVIOUS, ///< Previous button. + WID_QES_NEXT = ::WID_QES_NEXT, ///< Next button. + }; + + /* automatically generated from ../../widgets/smallmap_widget.h */ + /** Widgets of the #SmallMapWindow class. */ + enum SmallMapWidgets { + WID_SM_CAPTION = ::WID_SM_CAPTION, ///< Caption of the window. + WID_SM_MAP_BORDER = ::WID_SM_MAP_BORDER, ///< Border around the smallmap. + WID_SM_MAP = ::WID_SM_MAP, ///< Panel containing the smallmap. + WID_SM_LEGEND = ::WID_SM_LEGEND, ///< Bottom panel to display smallmap legends. + WID_SM_BLANK = ::WID_SM_BLANK, ///< Empty button as placeholder. + WID_SM_ZOOM_IN = ::WID_SM_ZOOM_IN, ///< Button to zoom in one step. + WID_SM_ZOOM_OUT = ::WID_SM_ZOOM_OUT, ///< Button to zoom out one step. + WID_SM_CONTOUR = ::WID_SM_CONTOUR, ///< Button to select the contour view (height map). + WID_SM_VEHICLES = ::WID_SM_VEHICLES, ///< Button to select the vehicles view. + WID_SM_INDUSTRIES = ::WID_SM_INDUSTRIES, ///< Button to select the industries view. + WID_SM_LINKSTATS = ::WID_SM_LINKSTATS, ///< Button to select the link stats view. + WID_SM_ROUTES = ::WID_SM_ROUTES, ///< Button to select the routes view. + WID_SM_VEGETATION = ::WID_SM_VEGETATION, ///< Button to select the vegetation view. + WID_SM_OWNERS = ::WID_SM_OWNERS, ///< Button to select the owners view. + WID_SM_CENTERMAP = ::WID_SM_CENTERMAP, ///< Button to move smallmap center to main window center. + WID_SM_TOGGLETOWNNAME = ::WID_SM_TOGGLETOWNNAME, ///< Toggle button to display town names. + WID_SM_SELECT_BUTTONS = ::WID_SM_SELECT_BUTTONS, ///< Selection widget for the buttons present in some smallmap modes. + WID_SM_ENABLE_ALL = ::WID_SM_ENABLE_ALL, ///< Button to enable display of all legend entries. + WID_SM_DISABLE_ALL = ::WID_SM_DISABLE_ALL, ///< Button to disable display of all legend entries. + WID_SM_SHOW_HEIGHT = ::WID_SM_SHOW_HEIGHT, ///< Show heightmap toggle button. + }; + + /* automatically generated from ../../widgets/station_widget.h */ + /** Widgets of the #StationViewWindow class. */ + enum StationViewWidgets { + WID_SV_CAPTION = ::WID_SV_CAPTION, ///< Caption of the window. + WID_SV_SORT_ORDER = ::WID_SV_SORT_ORDER, ///< 'Sort order' button + WID_SV_SORT_BY = ::WID_SV_SORT_BY, ///< 'Sort by' button + WID_SV_GROUP = ::WID_SV_GROUP, ///< label for "group by" + WID_SV_GROUP_BY = ::WID_SV_GROUP_BY, ///< 'Group by' button + WID_SV_WAITING = ::WID_SV_WAITING, ///< List of waiting cargo. + WID_SV_SCROLLBAR = ::WID_SV_SCROLLBAR, ///< Scrollbar. + WID_SV_ACCEPT_RATING_LIST = ::WID_SV_ACCEPT_RATING_LIST, ///< List of accepted cargoes / rating of cargoes. + WID_SV_LOCATION = ::WID_SV_LOCATION, ///< 'Location' button. + WID_SV_ACCEPTS_RATINGS = ::WID_SV_ACCEPTS_RATINGS, ///< 'Accepts' / 'Ratings' button. + WID_SV_RENAME = ::WID_SV_RENAME, ///< 'Rename' button. + WID_SV_CLOSE_AIRPORT = ::WID_SV_CLOSE_AIRPORT, ///< 'Close airport' button. + WID_SV_TRAINS = ::WID_SV_TRAINS, ///< List of scheduled trains button. + WID_SV_ROADVEHS = ::WID_SV_ROADVEHS, ///< List of scheduled road vehs button. + WID_SV_SHIPS = ::WID_SV_SHIPS, ///< List of scheduled ships button. + WID_SV_PLANES = ::WID_SV_PLANES, ///< List of scheduled planes button. + }; + + /** Widgets of the #CompanyStationsWindow class. */ + enum StationListWidgets { + /* Name starts with ST instead of S, because of collision with SaveLoadWidgets */ + WID_STL_CAPTION = ::WID_STL_CAPTION, ///< Caption of the window. + WID_STL_LIST = ::WID_STL_LIST, ///< The main panel, list of stations. + WID_STL_SCROLLBAR = ::WID_STL_SCROLLBAR, ///< Scrollbar next to the main panel. + + /* Vehicletypes need to be in order of StationFacility due to bit magic */ + WID_STL_TRAIN = ::WID_STL_TRAIN, ///< 'TRAIN' button - list only facilities where is a railroad station. + WID_STL_TRUCK = ::WID_STL_TRUCK, ///< 'TRUCK' button - list only facilities where is a truck stop. + WID_STL_BUS = ::WID_STL_BUS, ///< 'BUS' button - list only facilities where is a bus stop. + WID_STL_AIRPLANE = ::WID_STL_AIRPLANE, ///< 'AIRPLANE' button - list only facilities where is an airport. + WID_STL_SHIP = ::WID_STL_SHIP, ///< 'SHIP' button - list only facilities where is a dock. + WID_STL_FACILALL = ::WID_STL_FACILALL, ///< 'ALL' button - list all facilities. + + WID_STL_NOCARGOWAITING = ::WID_STL_NOCARGOWAITING, ///< 'NO' button - list stations where no cargo is waiting. + WID_STL_CARGOALL = ::WID_STL_CARGOALL, ///< 'ALL' button - list all stations. + + WID_STL_SORTBY = ::WID_STL_SORTBY, ///< 'Sort by' button - reverse sort direction. + WID_STL_SORTDROPBTN = ::WID_STL_SORTDROPBTN, ///< Dropdown button. + + WID_STL_CARGOSTART = ::WID_STL_CARGOSTART, ///< Widget numbers used for list of cargo types (not present in _company_stations_widgets). + }; + + /** Widgets of the #SelectStationWindow class. */ + enum JoinStationWidgets { + WID_JS_CAPTION = ::WID_JS_CAPTION, // Caption of the window. + WID_JS_PANEL = ::WID_JS_PANEL, // Main panel. + WID_JS_SCROLLBAR = ::WID_JS_SCROLLBAR, // Scrollbar of the panel. + }; + + /* automatically generated from ../../widgets/statusbar_widget.h */ + /** Widgets of the #StatusBarWindow class. */ + enum StatusbarWidgets { + WID_S_LEFT = ::WID_S_LEFT, ///< Left part of the statusbar; date is shown there. + WID_S_MIDDLE = ::WID_S_MIDDLE, ///< Middle part; current news or company name or *** SAVING *** or *** PAUSED ***. + WID_S_RIGHT = ::WID_S_RIGHT, ///< Right part; bank balance. + }; + + /* automatically generated from ../../widgets/story_widget.h */ + /** Widgets of the #GoalListWindow class. */ + enum StoryBookWidgets { + WID_SB_CAPTION = ::WID_SB_CAPTION, ///< Caption of the window. + WID_SB_SEL_PAGE = ::WID_SB_SEL_PAGE, ///< Page selector. + WID_SB_PAGE_PANEL = ::WID_SB_PAGE_PANEL, ///< Page body. + WID_SB_SCROLLBAR = ::WID_SB_SCROLLBAR, ///< Scrollbar of the goal list. + WID_SB_PREV_PAGE = ::WID_SB_PREV_PAGE, ///< Prev button. + WID_SB_NEXT_PAGE = ::WID_SB_NEXT_PAGE, ///< Next button. + }; + + /* automatically generated from ../../widgets/subsidy_widget.h */ + /** Widgets of the #SubsidyListWindow class. */ + enum SubsidyListWidgets { + /* Name starts with SU instead of S, because of collision with SaveLoadWidgets. */ + WID_SUL_PANEL = ::WID_SUL_PANEL, ///< Main panel of window. + WID_SUL_SCROLLBAR = ::WID_SUL_SCROLLBAR, ///< Scrollbar of panel. + }; + + /* automatically generated from ../../widgets/terraform_widget.h */ + /** Widgets of the #TerraformToolbarWindow class. */ + enum TerraformToolbarWidgets { + WID_TT_SHOW_PLACE_OBJECT = ::WID_TT_SHOW_PLACE_OBJECT, ///< Should the place object button be shown? + WID_TT_BUTTONS_START = ::WID_TT_BUTTONS_START, ///< Start of pushable buttons. + WID_TT_LOWER_LAND = ::WID_TT_LOWER_LAND, ///< Lower land button. + WID_TT_RAISE_LAND = ::WID_TT_RAISE_LAND, ///< Raise land button. + WID_TT_LEVEL_LAND = ::WID_TT_LEVEL_LAND, ///< Level land button. + WID_TT_DEMOLISH = ::WID_TT_DEMOLISH, ///< Demolish aka dynamite button. + WID_TT_BUY_LAND = ::WID_TT_BUY_LAND, ///< Buy land button. + WID_TT_PLANT_TREES = ::WID_TT_PLANT_TREES, ///< Plant trees button (note: opens separate window, no place-push-button). + WID_TT_PLACE_SIGN = ::WID_TT_PLACE_SIGN, ///< Place sign button. + WID_TT_PLACE_OBJECT = ::WID_TT_PLACE_OBJECT, ///< Place object button. + }; + + /** Widgets of the #ScenarioEditorLandscapeGenerationWindow class. */ + enum EditorTerraformToolbarWidgets { + WID_ETT_SHOW_PLACE_DESERT = ::WID_ETT_SHOW_PLACE_DESERT, ///< Should the place desert button be shown? + WID_ETT_START = ::WID_ETT_START, ///< Used for iterations. + WID_ETT_DOTS = ::WID_ETT_DOTS, ///< Invisible widget for rendering the terraform size on. + WID_ETT_BUTTONS_START = ::WID_ETT_BUTTONS_START, ///< Start of pushable buttons. + WID_ETT_DEMOLISH = ::WID_ETT_DEMOLISH, ///< Demolish aka dynamite button. + WID_ETT_LOWER_LAND = ::WID_ETT_LOWER_LAND, ///< Lower land button. + WID_ETT_RAISE_LAND = ::WID_ETT_RAISE_LAND, ///< Raise land button. + WID_ETT_LEVEL_LAND = ::WID_ETT_LEVEL_LAND, ///< Level land button. + WID_ETT_PLACE_ROCKS = ::WID_ETT_PLACE_ROCKS, ///< Place rocks button. + WID_ETT_PLACE_DESERT = ::WID_ETT_PLACE_DESERT, ///< Place desert button (in tropical climate). + WID_ETT_PLACE_OBJECT = ::WID_ETT_PLACE_OBJECT, ///< Place transmitter button. + WID_ETT_BUTTONS_END = ::WID_ETT_BUTTONS_END, ///< End of pushable buttons. + WID_ETT_INCREASE_SIZE = ::WID_ETT_INCREASE_SIZE, ///< Upwards arrow button to increase terraforming size. + WID_ETT_DECREASE_SIZE = ::WID_ETT_DECREASE_SIZE, ///< Downwards arrow button to decrease terraforming size. + WID_ETT_NEW_SCENARIO = ::WID_ETT_NEW_SCENARIO, ///< Button for generating a new scenario. + WID_ETT_RESET_LANDSCAPE = ::WID_ETT_RESET_LANDSCAPE, ///< Button for removing all company-owned property. + }; + + /* automatically generated from ../../widgets/timetable_widget.h */ + /** Widgets of the #TimetableWindow class. */ + enum VehicleTimetableWidgets { + WID_VT_CAPTION = ::WID_VT_CAPTION, ///< Caption of the window. + WID_VT_ORDER_VIEW = ::WID_VT_ORDER_VIEW, ///< Order view. + WID_VT_TIMETABLE_PANEL = ::WID_VT_TIMETABLE_PANEL, ///< Timetable panel. + WID_VT_ARRIVAL_DEPARTURE_PANEL = ::WID_VT_ARRIVAL_DEPARTURE_PANEL, ///< Panel with the expected/scheduled arrivals. + WID_VT_SCROLLBAR = ::WID_VT_SCROLLBAR, ///< Scrollbar for the panel. + WID_VT_SUMMARY_PANEL = ::WID_VT_SUMMARY_PANEL, ///< Summary panel. + WID_VT_START_DATE = ::WID_VT_START_DATE, ///< Start date button. + WID_VT_CHANGE_TIME = ::WID_VT_CHANGE_TIME, ///< Change time button. + WID_VT_CLEAR_TIME = ::WID_VT_CLEAR_TIME, ///< Clear time button. + WID_VT_RESET_LATENESS = ::WID_VT_RESET_LATENESS, ///< Reset lateness button. + WID_VT_AUTOFILL = ::WID_VT_AUTOFILL, ///< Autofill button. + WID_VT_EXPECTED = ::WID_VT_EXPECTED, ///< Toggle between expected and scheduled arrivals. + WID_VT_SHARED_ORDER_LIST = ::WID_VT_SHARED_ORDER_LIST, ///< Show the shared order list. + WID_VT_ARRIVAL_DEPARTURE_SELECTION = ::WID_VT_ARRIVAL_DEPARTURE_SELECTION, ///< Disable/hide the arrival departure panel. + WID_VT_EXPECTED_SELECTION = ::WID_VT_EXPECTED_SELECTION, ///< Disable/hide the expected selection button. + WID_VT_CHANGE_SPEED = ::WID_VT_CHANGE_SPEED, ///< Change speed limit button. + WID_VT_CLEAR_SPEED = ::WID_VT_CLEAR_SPEED, ///< Clear speed limit button. + }; + + /* automatically generated from ../../widgets/toolbar_widget.h */ + /** Widgets of the #MainToolbarWindow class. */ + enum ToolbarNormalWidgets { + WID_TN_PAUSE = ::WID_TN_PAUSE, ///< Pause the game. + WID_TN_FAST_FORWARD = ::WID_TN_FAST_FORWARD, ///< Fast forward the game. + WID_TN_SETTINGS = ::WID_TN_SETTINGS, ///< Settings menu. + WID_TN_SAVE = ::WID_TN_SAVE, ///< Save menu. + WID_TN_SMALL_MAP = ::WID_TN_SMALL_MAP, ///< Small map menu. + WID_TN_TOWNS = ::WID_TN_TOWNS, ///< Town menu. + WID_TN_SUBSIDIES = ::WID_TN_SUBSIDIES, ///< Subsidy menu. + WID_TN_STATIONS = ::WID_TN_STATIONS, ///< Station menu. + WID_TN_FINANCES = ::WID_TN_FINANCES, ///< Finance menu. + WID_TN_COMPANIES = ::WID_TN_COMPANIES, ///< Company menu. + WID_TN_STORY = ::WID_TN_STORY, ///< Story menu. + WID_TN_GOAL = ::WID_TN_GOAL, ///< Goal menu. + WID_TN_GRAPHS = ::WID_TN_GRAPHS, ///< Graph menu. + WID_TN_LEAGUE = ::WID_TN_LEAGUE, ///< Company league menu. + WID_TN_INDUSTRIES = ::WID_TN_INDUSTRIES, ///< Industry menu. + WID_TN_VEHICLE_START = ::WID_TN_VEHICLE_START, ///< Helper for the offset of the vehicle menus. + WID_TN_TRAINS = ::WID_TN_TRAINS, ///< Train menu. + WID_TN_ROADVEHS = ::WID_TN_ROADVEHS, ///< Road vehicle menu. + WID_TN_SHIPS = ::WID_TN_SHIPS, ///< Ship menu. + WID_TN_AIRCRAFTS = ::WID_TN_AIRCRAFTS, ///< Aircraft menu. + WID_TN_ZOOM_IN = ::WID_TN_ZOOM_IN, ///< Zoom in the main viewport. + WID_TN_ZOOM_OUT = ::WID_TN_ZOOM_OUT, ///< Zoom out the main viewport. + WID_TN_RAILS = ::WID_TN_RAILS, ///< Rail building menu. + WID_TN_ROADS = ::WID_TN_ROADS, ///< Road building menu. + WID_TN_WATER = ::WID_TN_WATER, ///< Water building toolbar. + WID_TN_AIR = ::WID_TN_AIR, ///< Airport building toolbar. + WID_TN_LANDSCAPE = ::WID_TN_LANDSCAPE, ///< Landscaping toolbar. + WID_TN_MUSIC_SOUND = ::WID_TN_MUSIC_SOUND, ///< Music/sound configuration menu. + WID_TN_MESSAGES = ::WID_TN_MESSAGES, ///< Messages menu. + WID_TN_HELP = ::WID_TN_HELP, ///< Help menu. + WID_TN_SWITCH_BAR = ::WID_TN_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. + WID_TN_END = ::WID_TN_END, ///< Helper for knowing the amount of widgets. + }; + + /** Widgets of the #ScenarioEditorToolbarWindow class. */ + enum ToolbarEditorWidgets { + WID_TE_PAUSE = ::WID_TE_PAUSE, ///< Pause the game. + WID_TE_FAST_FORWARD = ::WID_TE_FAST_FORWARD, ///< Fast forward the game. + WID_TE_SETTINGS = ::WID_TE_SETTINGS, ///< Settings menu. + WID_TE_SAVE = ::WID_TE_SAVE, ///< Save menu. + WID_TE_SPACER = ::WID_TE_SPACER, ///< Spacer with "scenario editor" text. + WID_TE_DATE = ::WID_TE_DATE, ///< The date of the scenario. + WID_TE_DATE_BACKWARD = ::WID_TE_DATE_BACKWARD, ///< Reduce the date of the scenario. + WID_TE_DATE_FORWARD = ::WID_TE_DATE_FORWARD, ///< Increase the date of the scenario. + WID_TE_SMALL_MAP = ::WID_TE_SMALL_MAP, ///< Small map menu. + WID_TE_ZOOM_IN = ::WID_TE_ZOOM_IN, ///< Zoom in the main viewport. + WID_TE_ZOOM_OUT = ::WID_TE_ZOOM_OUT, ///< Zoom out the main viewport. + WID_TE_LAND_GENERATE = ::WID_TE_LAND_GENERATE, ///< Land generation. + WID_TE_TOWN_GENERATE = ::WID_TE_TOWN_GENERATE, ///< Town building window. + WID_TE_INDUSTRY = ::WID_TE_INDUSTRY, ///< Industry building window. + WID_TE_ROADS = ::WID_TE_ROADS, ///< Road building menu. + WID_TE_WATER = ::WID_TE_WATER, ///< Water building toolbar. + WID_TE_TREES = ::WID_TE_TREES, ///< Tree building toolbar. + WID_TE_SIGNS = ::WID_TE_SIGNS, ///< Sign building. + WID_TE_DATE_PANEL = ::WID_TE_DATE_PANEL, ///< Container for the date widgets. + /* The following three need to have the same actual widget number as the normal toolbar due to shared code. */ + WID_TE_MUSIC_SOUND = ::WID_TE_MUSIC_SOUND, ///< Music/sound configuration menu. + WID_TE_HELP = ::WID_TE_HELP, ///< Help menu. + WID_TE_SWITCH_BAR = ::WID_TE_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. + }; + + /* automatically generated from ../../widgets/town_widget.h */ + /** Widgets of the #TownDirectoryWindow class. */ + enum TownDirectoryWidgets { + WID_TD_SORT_ORDER = ::WID_TD_SORT_ORDER, ///< Direction of sort dropdown. + WID_TD_SORT_CRITERIA = ::WID_TD_SORT_CRITERIA, ///< Criteria of sort dropdown. + WID_TD_LIST = ::WID_TD_LIST, ///< List of towns. + WID_TD_SCROLLBAR = ::WID_TD_SCROLLBAR, ///< Scrollbar for the town list. + WID_TD_WORLD_POPULATION = ::WID_TD_WORLD_POPULATION, ///< The world's population. + }; + + /** Widgets of the #TownAuthorityWindow class. */ + enum TownAuthorityWidgets { + WID_TA_CAPTION = ::WID_TA_CAPTION, ///< Caption of window. + WID_TA_RATING_INFO = ::WID_TA_RATING_INFO, ///< Overview with ratings for each company. + WID_TA_COMMAND_LIST = ::WID_TA_COMMAND_LIST, ///< List of commands for the player. + WID_TA_SCROLLBAR = ::WID_TA_SCROLLBAR, ///< Scrollbar of the list of commands. + WID_TA_ACTION_INFO = ::WID_TA_ACTION_INFO, ///< Additional information about the action. + WID_TA_EXECUTE = ::WID_TA_EXECUTE, ///< Do-it button. + }; + + /** Widgets of the #TownViewWindow class. */ + enum TownViewWidgets { + WID_TV_CAPTION = ::WID_TV_CAPTION, ///< Caption of window. + WID_TV_VIEWPORT = ::WID_TV_VIEWPORT, ///< View of the center of the town. + WID_TV_INFO = ::WID_TV_INFO, ///< General information about the town. + WID_TV_CENTER_VIEW = ::WID_TV_CENTER_VIEW, ///< Center the main view on this town. + WID_TV_SHOW_AUTHORITY = ::WID_TV_SHOW_AUTHORITY, ///< Show the town authority window. + WID_TV_CHANGE_NAME = ::WID_TV_CHANGE_NAME, ///< Change the name of this town. + WID_TV_EXPAND = ::WID_TV_EXPAND, ///< Expand this town (scenario editor only). + WID_TV_DELETE = ::WID_TV_DELETE, ///< Delete this town (scenario editor only). + }; + + /** Widgets of the #FoundTownWindow class. */ + enum TownFoundingWidgets { + WID_TF_NEW_TOWN = ::WID_TF_NEW_TOWN, ///< Create a new town. + WID_TF_RANDOM_TOWN = ::WID_TF_RANDOM_TOWN, ///< Randomly place a town. + WID_TF_MANY_RANDOM_TOWNS = ::WID_TF_MANY_RANDOM_TOWNS, ///< Randomly place many towns. + WID_TF_TOWN_NAME_EDITBOX = ::WID_TF_TOWN_NAME_EDITBOX, ///< Editor for the town name. + WID_TF_TOWN_NAME_RANDOM = ::WID_TF_TOWN_NAME_RANDOM, ///< Generate a random town name. + WID_TF_SIZE_SMALL = ::WID_TF_SIZE_SMALL, ///< Selection for a small town. + WID_TF_SIZE_MEDIUM = ::WID_TF_SIZE_MEDIUM, ///< Selection for a medium town. + WID_TF_SIZE_LARGE = ::WID_TF_SIZE_LARGE, ///< Selection for a large town. + WID_TF_SIZE_RANDOM = ::WID_TF_SIZE_RANDOM, ///< Selection for a randomly sized town. + WID_TF_CITY = ::WID_TF_CITY, ///< Selection for the town's city state. + WID_TF_LAYOUT_ORIGINAL = ::WID_TF_LAYOUT_ORIGINAL, ///< Selection for the original town layout. + WID_TF_LAYOUT_BETTER = ::WID_TF_LAYOUT_BETTER, ///< Selection for the better town layout. + WID_TF_LAYOUT_GRID2 = ::WID_TF_LAYOUT_GRID2, ///< Selection for the 2x2 grid town layout. + WID_TF_LAYOUT_GRID3 = ::WID_TF_LAYOUT_GRID3, ///< Selection for the 3x3 grid town layout. + WID_TF_LAYOUT_RANDOM = ::WID_TF_LAYOUT_RANDOM, ///< Selection for a randomly chosen town layout. + }; + + /* automatically generated from ../../widgets/transparency_widget.h */ + /** Widgets of the #TransparenciesWindow class. */ + enum TransparencyToolbarWidgets { + /* Button row. */ + WID_TT_BEGIN = ::WID_TT_BEGIN, ///< First toggle button. + WID_TT_SIGNS = ::WID_TT_SIGNS, ///< Signs background transparency toggle button. + WID_TT_TREES = ::WID_TT_TREES, ///< Trees transparency toggle button. + WID_TT_HOUSES = ::WID_TT_HOUSES, ///< Houses transparency toggle button. + WID_TT_INDUSTRIES = ::WID_TT_INDUSTRIES, ///< industries transparency toggle button. + WID_TT_BUILDINGS = ::WID_TT_BUILDINGS, ///< Company buildings and structures transparency toggle button. + WID_TT_BRIDGES = ::WID_TT_BRIDGES, ///< Bridges transparency toggle button. + WID_TT_STRUCTURES = ::WID_TT_STRUCTURES, ///< Object structure transparency toggle button. + WID_TT_CATENARY = ::WID_TT_CATENARY, ///< Catenary transparency toggle button. + WID_TT_LOADING = ::WID_TT_LOADING, ///< Loading indicators transparency toggle button. + WID_TT_END = ::WID_TT_END, ///< End of toggle buttons. + + /* Panel with buttons for invisibility */ + WID_TT_BUTTONS = ::WID_TT_BUTTONS, ///< Panel with 'invisibility' buttons. + }; + + /* automatically generated from ../../widgets/tree_widget.h */ + /** Widgets of the #BuildTreesWindow class. */ + enum BuildTreesWidgets { + WID_BT_TYPE_11 = ::WID_BT_TYPE_11, ///< Tree 1st column 1st row. + WID_BT_TYPE_12 = ::WID_BT_TYPE_12, ///< Tree 1st column 2nd row. + WID_BT_TYPE_13 = ::WID_BT_TYPE_13, ///< Tree 1st column 3rd row. + WID_BT_TYPE_14 = ::WID_BT_TYPE_14, ///< Tree 1st column 4th row. + WID_BT_TYPE_21 = ::WID_BT_TYPE_21, ///< Tree 2st column 1st row. + WID_BT_TYPE_22 = ::WID_BT_TYPE_22, ///< Tree 2st column 2nd row. + WID_BT_TYPE_23 = ::WID_BT_TYPE_23, ///< Tree 2st column 3rd row. + WID_BT_TYPE_24 = ::WID_BT_TYPE_24, ///< Tree 2st column 4th row. + WID_BT_TYPE_31 = ::WID_BT_TYPE_31, ///< Tree 3st column 1st row. + WID_BT_TYPE_32 = ::WID_BT_TYPE_32, ///< Tree 3st column 2nd row. + WID_BT_TYPE_33 = ::WID_BT_TYPE_33, ///< Tree 3st column 3rd row. + WID_BT_TYPE_34 = ::WID_BT_TYPE_34, ///< Tree 3st column 4th row. + WID_BT_TYPE_RANDOM = ::WID_BT_TYPE_RANDOM, ///< Button to build random type of tree. + WID_BT_MANY_RANDOM = ::WID_BT_MANY_RANDOM, ///< Button to build many random trees. + }; + + /* automatically generated from ../../widgets/vehicle_widget.h */ + /** Widgets of the #VehicleViewWindow class. */ + enum VehicleViewWidgets { + WID_VV_CAPTION = ::WID_VV_CAPTION, ///< Caption of window. + WID_VV_VIEWPORT = ::WID_VV_VIEWPORT, ///< Viewport widget. + WID_VV_START_STOP = ::WID_VV_START_STOP, ///< Start or stop this vehicle, and show information about the current state. + WID_VV_CENTER_MAIN_VIEW = ::WID_VV_CENTER_MAIN_VIEW, ///< Center the main view on this vehicle. + WID_VV_GOTO_DEPOT = ::WID_VV_GOTO_DEPOT, ///< Order this vehicle to go to the depot. + WID_VV_REFIT = ::WID_VV_REFIT, ///< Open the refit window. + WID_VV_SHOW_ORDERS = ::WID_VV_SHOW_ORDERS, ///< Show the orders of this vehicle. + WID_VV_SHOW_DETAILS = ::WID_VV_SHOW_DETAILS, ///< Show details of this vehicle. + WID_VV_CLONE = ::WID_VV_CLONE, ///< Clone this vehicle. + WID_VV_SELECT_DEPOT_CLONE = ::WID_VV_SELECT_DEPOT_CLONE, ///< Selection widget between 'goto depot', and 'clone vehicle' buttons. + WID_VV_SELECT_REFIT_TURN = ::WID_VV_SELECT_REFIT_TURN, ///< Selection widget between 'refit' and 'turn around' buttons. + WID_VV_TURN_AROUND = ::WID_VV_TURN_AROUND, ///< Turn this vehicle around. + WID_VV_FORCE_PROCEED = ::WID_VV_FORCE_PROCEED, ///< Force this vehicle to pass a signal at danger. + }; + + /** Widgets of the #RefitWindow class. */ + enum VehicleRefitWidgets { + WID_VR_CAPTION = ::WID_VR_CAPTION, ///< Caption of window. + WID_VR_VEHICLE_PANEL_DISPLAY = ::WID_VR_VEHICLE_PANEL_DISPLAY, ///< Display with a representation of the vehicle to refit. + WID_VR_SHOW_HSCROLLBAR = ::WID_VR_SHOW_HSCROLLBAR, ///< Selection widget for the horizontal scrollbar. + WID_VR_HSCROLLBAR = ::WID_VR_HSCROLLBAR, ///< Horizontal scrollbar or the vehicle display. + WID_VR_SELECT_HEADER = ::WID_VR_SELECT_HEADER, ///< Header with question about the cargo to carry. + WID_VR_MATRIX = ::WID_VR_MATRIX, ///< Options to refit to. + WID_VR_SCROLLBAR = ::WID_VR_SCROLLBAR, ///< Scrollbar for the refit options. + WID_VR_INFO = ::WID_VR_INFO, ///< Information about the currently selected refit option. + WID_VR_REFIT = ::WID_VR_REFIT, ///< Perform the refit. + }; + + /** Widgets of the #VehicleDetailsWindow class. */ + enum VehicleDetailsWidgets { + WID_VD_CAPTION = ::WID_VD_CAPTION, ///< Caption of window. + WID_VD_RENAME_VEHICLE = ::WID_VD_RENAME_VEHICLE, ///< Rename this vehicle. + WID_VD_TOP_DETAILS = ::WID_VD_TOP_DETAILS, ///< Panel with generic details. + WID_VD_INCREASE_SERVICING_INTERVAL = ::WID_VD_INCREASE_SERVICING_INTERVAL, ///< Increase the servicing interval. + WID_VD_DECREASE_SERVICING_INTERVAL = ::WID_VD_DECREASE_SERVICING_INTERVAL, ///< Decrease the servicing interval. + WID_VD_SERVICE_INTERVAL_DROPDOWN = ::WID_VD_SERVICE_INTERVAL_DROPDOWN, ///< Dropdown to select default/days/percent service interval. + WID_VD_SERVICING_INTERVAL = ::WID_VD_SERVICING_INTERVAL, ///< Information about the servicing interval. + WID_VD_MIDDLE_DETAILS = ::WID_VD_MIDDLE_DETAILS, ///< Details for non-trains. + WID_VD_MATRIX = ::WID_VD_MATRIX, ///< List of details for trains. + WID_VD_SCROLLBAR = ::WID_VD_SCROLLBAR, ///< Scrollbar for train details. + WID_VD_DETAILS_CARGO_CARRIED = ::WID_VD_DETAILS_CARGO_CARRIED, ///< Show carried cargo per part of the train. + WID_VD_DETAILS_TRAIN_VEHICLES = ::WID_VD_DETAILS_TRAIN_VEHICLES, ///< Show all parts of the train with their description. + WID_VD_DETAILS_CAPACITY_OF_EACH = ::WID_VD_DETAILS_CAPACITY_OF_EACH, ///< Show the capacity of all train parts. + WID_VD_DETAILS_TOTAL_CARGO = ::WID_VD_DETAILS_TOTAL_CARGO, ///< Show the capacity and carried cargo amounts aggregated per cargo of the train. + }; + + /** Widgets of the #VehicleListWindow class. */ + enum VehicleListWidgets { + WID_VL_CAPTION = ::WID_VL_CAPTION, ///< Caption of window. + WID_VL_SORT_ORDER = ::WID_VL_SORT_ORDER, ///< Sort order. + WID_VL_SORT_BY_PULLDOWN = ::WID_VL_SORT_BY_PULLDOWN, ///< Sort by dropdown list. + WID_VL_LIST = ::WID_VL_LIST, ///< List of the vehicles. + WID_VL_SCROLLBAR = ::WID_VL_SCROLLBAR, ///< Scrollbar for the list. + WID_VL_HIDE_BUTTONS = ::WID_VL_HIDE_BUTTONS, ///< Selection to hide the buttons. + WID_VL_AVAILABLE_VEHICLES = ::WID_VL_AVAILABLE_VEHICLES, ///< Available vehicles. + WID_VL_MANAGE_VEHICLES_DROPDOWN = ::WID_VL_MANAGE_VEHICLES_DROPDOWN, ///< Manage vehicles dropdown list. + WID_VL_STOP_ALL = ::WID_VL_STOP_ALL, ///< Stop all button. + WID_VL_START_ALL = ::WID_VL_START_ALL, ///< Start all button. + }; + + /* automatically generated from ../../widgets/viewport_widget.h */ + /** Widgets of the #ExtraViewportWindow class. */ + enum ExtraViewportWidgets { + WID_EV_CAPTION = ::WID_EV_CAPTION, ///< Caption of window. + WID_EV_VIEWPORT = ::WID_EV_VIEWPORT, ///< The viewport. + WID_EV_ZOOM_IN = ::WID_EV_ZOOM_IN, ///< Zoom in. + WID_EV_ZOOM_OUT = ::WID_EV_ZOOM_OUT, ///< Zoom out. + WID_EV_MAIN_TO_VIEW = ::WID_EV_MAIN_TO_VIEW, ///< Center the view of this viewport on the main view. + WID_EV_VIEW_TO_MAIN = ::WID_EV_VIEW_TO_MAIN, ///< Center the main view on the view of this viewport. + }; + + /* automatically generated from ../../widgets/waypoint_widget.h */ + /** Widgets of the #WaypointWindow class. */ + enum WaypointWidgets { + WID_W_CAPTION = ::WID_W_CAPTION, ///< Caption of window. + WID_W_VIEWPORT = ::WID_W_VIEWPORT, ///< The viewport on this waypoint. + WID_W_CENTER_VIEW = ::WID_W_CENTER_VIEW, ///< Center the main view on this waypoint. + WID_W_RENAME = ::WID_W_RENAME, ///< Rename this waypoint. + WID_W_SHOW_VEHICLES = ::WID_W_SHOW_VEHICLES, ///< Show the vehicles visiting this waypoint. + }; + + // @endenum +}; + +#endif /* SCRIPT_WINDOW_HPP */ diff --git a/src/script/api/template/template_window.hpp.sq.orig b/src/script/api/template/template_window.hpp.sq.orig new file mode 100644 index 0000000000..9f01e42d5a --- /dev/null +++ b/src/script/api/template/template_window.hpp.sq.orig @@ -0,0 +1,257 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ + +#include "../script_window.hpp" + +namespace SQConvert { + /* Allow enums to be used as Squirrel parameters */ + template <> inline ScriptWindow::WindowNumberEnum GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::WindowNumberEnum)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::WindowNumberEnum res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::WindowClass GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::WindowClass)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::WindowClass res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::TextColour GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TextColour)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TextColour res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NumberType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NumberType)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NumberType res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::WidgetType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::WidgetType)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::WidgetType res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::AIListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AIListWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AIListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::AISettingsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AISettingsWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AISettingsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::AIConfigWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AIConfigWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AIConfigWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::AIDebugWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AIDebugWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AIDebugWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::AirportToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AirportToolbarWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AirportToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::AirportPickerWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AirportPickerWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AirportPickerWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::ReplaceVehicleWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ReplaceVehicleWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ReplaceVehicleWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BootstrapBackgroundWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BootstrapBackgroundWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BootstrapBackgroundWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BootstrapAskForDownloadWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BootstrapAskForDownloadWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BootstrapAskForDownloadWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BuildBridgeSelectionWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildBridgeSelectionWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildBridgeSelectionWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BuildVehicleWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildVehicleWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildVehicleWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::CheatWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CheatWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CheatWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::CompanyWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::CompanyFinancesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyFinancesWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyFinancesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::SelectCompanyLiveryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SelectCompanyLiveryWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SelectCompanyLiveryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::SelectCompanyManagerFaceWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SelectCompanyManagerFaceWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SelectCompanyManagerFaceWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::CompanyInfrastructureWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyInfrastructureWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyInfrastructureWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BuyCompanyWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuyCompanyWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuyCompanyWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::ConsoleWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ConsoleWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ConsoleWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::SetDateWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SetDateWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SetDateWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::DepotWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DepotWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::DepotWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BuildDockDepotWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildDockDepotWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildDockDepotWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::DockToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DockToolbarWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::DockToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::DropdownMenuWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DropdownMenuWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::DropdownMenuWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::EnginePreviewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::EnginePreviewWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::EnginePreviewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::ErrorMessageWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ErrorMessageWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ErrorMessageWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::SaveLoadWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SaveLoadWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SaveLoadWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::GenerateLandscapeWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GenerateLandscapeWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GenerateLandscapeWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::CreateScenarioWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CreateScenarioWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CreateScenarioWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::GenerationProgressWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GenerationProgressWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GenerationProgressWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::GoalListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GoalListWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GoalListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::GoalQuestionWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GoalQuestionWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GoalQuestionWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::GraphLegendWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GraphLegendWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GraphLegendWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::CompanyValueWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyValueWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyValueWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::PerformanceHistoryGraphWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::PerformanceHistoryGraphWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::PerformanceHistoryGraphWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::CargoPaymentRatesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CargoPaymentRatesWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CargoPaymentRatesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::CompanyLeagueWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyLeagueWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyLeagueWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::PerformanceRatingDetailsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::PerformanceRatingDetailsWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::PerformanceRatingDetailsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::GroupListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GroupListWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GroupListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::HighscoreWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::HighscoreWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::HighscoreWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::DynamicPlaceIndustriesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DynamicPlaceIndustriesWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::DynamicPlaceIndustriesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::IndustryViewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::IndustryViewWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::IndustryViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::IndustryDirectoryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::IndustryDirectoryWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::IndustryDirectoryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::IndustryCargoesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::IndustryCargoesWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::IndustryCargoesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::SelectGameIntroWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SelectGameIntroWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SelectGameIntroWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::LinkGraphLegendWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::LinkGraphLegendWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::LinkGraphLegendWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::MainWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MainWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::MainWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::LandInfoWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::LandInfoWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::LandInfoWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::ToolTipsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolTipsWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolTipsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::AboutWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AboutWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AboutWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::QueryStringWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::QueryStringWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::QueryStringWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::QueryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::QueryWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::QueryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::TextfileWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TextfileWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TextfileWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::MusicTrackSelectionWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MusicTrackSelectionWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::MusicTrackSelectionWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::MusicWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MusicWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::MusicWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NetWorkChatWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetWorkChatWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetWorkChatWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NetworkContentDownloadStatusWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkContentDownloadStatusWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkContentDownloadStatusWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NetworkContentListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkContentListWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkContentListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NetworkGameWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkGameWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkGameWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NetworkStartServerWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkStartServerWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkStartServerWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NetworkLobbyWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkLobbyWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkLobbyWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::ClientListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ClientListWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ClientListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::ClientListPopupWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ClientListPopupWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ClientListPopupWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NetworkJoinStatusWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkJoinStatusWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkJoinStatusWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NetworkCompanyPasswordWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkCompanyPasswordWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkCompanyPasswordWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NewGRFInspectWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewGRFInspectWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewGRFInspectWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::SpriteAlignerWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SpriteAlignerWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SpriteAlignerWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NewGRFParametersWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewGRFParametersWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewGRFParametersWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NewGRFStateWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewGRFStateWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewGRFStateWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::ScanProgressWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ScanProgressWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ScanProgressWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::NewsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewsWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::MessageHistoryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MessageHistoryWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::MessageHistoryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BuildObjectWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildObjectWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildObjectWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::OrderWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::OrderWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::OrderWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::OnScreenKeyboardWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::OnScreenKeyboardWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::OnScreenKeyboardWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::RailToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::RailToolbarWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::RailToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BuildRailStationWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRailStationWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRailStationWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BuildSignalWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildSignalWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildSignalWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BuildRailDepotWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRailDepotWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRailDepotWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BuildRailWaypointWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRailWaypointWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRailWaypointWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::RoadToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::RoadToolbarWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::RoadToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BuildRoadDepotWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRoadDepotWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRoadDepotWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BuildRoadStationWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRoadStationWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRoadStationWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::GameOptionsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GameOptionsWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GameOptionsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::GameSettingsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GameSettingsWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GameSettingsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::CustomCurrencyWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CustomCurrencyWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CustomCurrencyWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::SignListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SignListWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SignListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::QueryEditSignWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::QueryEditSignWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::QueryEditSignWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::SmallMapWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SmallMapWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SmallMapWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::StationViewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StationViewWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StationViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::StationListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StationListWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StationListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::JoinStationWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::JoinStationWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::JoinStationWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::StatusbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StatusbarWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StatusbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::StoryBookWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StoryBookWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StoryBookWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::SubsidyListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SubsidyListWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SubsidyListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::TerraformToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TerraformToolbarWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TerraformToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::EditorTerraformToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::EditorTerraformToolbarWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::EditorTerraformToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::VehicleTimetableWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleTimetableWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleTimetableWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::ToolbarNormalWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolbarNormalWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolbarNormalWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::ToolbarEditorWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolbarEditorWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolbarEditorWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::TownDirectoryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownDirectoryWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownDirectoryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::TownAuthorityWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownAuthorityWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownAuthorityWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::TownViewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownViewWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::TownFoundingWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownFoundingWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownFoundingWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::TransparencyToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TransparencyToolbarWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TransparencyToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::BuildTreesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildTreesWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildTreesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::VehicleViewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleViewWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::VehicleRefitWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleRefitWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleRefitWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::VehicleDetailsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleDetailsWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleDetailsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::VehicleListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleListWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::ExtraViewportWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ExtraViewportWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ExtraViewportWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::WaypointWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::WaypointWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::WaypointWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + + /* Allow ScriptWindow to be used as Squirrel parameter */ + template <> inline ScriptWindow *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWindow *)instance; } + template <> inline ScriptWindow &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWindow *)instance; } + template <> inline const ScriptWindow *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWindow *)instance; } + template <> inline const ScriptWindow &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWindow *)instance; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Window", res, NULL, DefSQDestructorCallback, true); return 1; } +} // namespace SQConvert diff --git a/src/settings.cpp.orig b/src/settings.cpp.orig new file mode 100644 index 0000000000..970c169b4a --- /dev/null +++ b/src/settings.cpp.orig @@ -0,0 +1,2174 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** + * @file settings.cpp + * All actions handling saving and loading of the settings/configuration goes on in this file. + * The file consists of three parts: + *
    + *
  1. Parsing the configuration file (openttd.cfg). This is achieved with the ini_ functions which + * handle various types, such as normal 'key = value' pairs, lists and value combinations of + * lists, strings, integers, 'bit'-masks and element selections. + *
  2. Handle reading and writing to the setting-structures from inside the game either from + * the console for example or through the gui with CMD_ functions. + *
  3. Handle saving/loading of the PATS chunk inside the savegame. + *
+ * @see SettingDesc + * @see SaveLoad + */ + +#include "stdafx.h" +#include "currency.h" +#include "screenshot.h" +#include "network/network.h" +#include "network/network_func.h" +#include "settings_internal.h" +#include "command_func.h" +#include "console_func.h" +#include "pathfinder/pathfinder_type.h" +#include "genworld.h" +#include "train.h" +#include "news_func.h" +#include "window_func.h" +#include "sound_func.h" +#include "company_func.h" +#include "rev.h" +#ifdef WITH_FREETYPE +#include "fontcache.h" +#endif +#include "textbuf_gui.h" +#include "rail_gui.h" +#include "elrail_func.h" +#include "error.h" +#include "town.h" +#include "video/video_driver.hpp" +#include "sound/sound_driver.hpp" +#include "music/music_driver.hpp" +#include "blitter/factory.hpp" +#include "base_media_base.h" +#include "gamelog.h" +#include "settings_func.h" +#include "ini_type.h" +#include "ai/ai_config.hpp" +#include "ai/ai.hpp" +#include "game/game_config.hpp" +#include "game/game.hpp" +#include "ship.h" +#include "smallmap_gui.h" +#include "roadveh.h" +#include "fios.h" +#include "strings_func.h" + +#include "void_map.h" +#include "station_base.h" + +#include "table/strings.h" +#include "table/settings.h" + +ClientSettings _settings_client; +GameSettings _settings_game; ///< Game settings of a running game or the scenario editor. +GameSettings _settings_newgame; ///< Game settings for new games (updated from the intro screen). +VehicleDefaultSettings _old_vds; ///< Used for loading default vehicles settings from old savegames +char *_config_file; ///< Configuration file of OpenTTD + +typedef std::list ErrorList; +static ErrorList _settings_error_list; ///< Errors while loading minimal settings. + + +typedef void SettingDescProc(IniFile *ini, const SettingDesc *desc, const char *grpname, void *object); +typedef void SettingDescProcList(IniFile *ini, const char *grpname, StringList *list); + +static bool IsSignedVarMemType(VarType vt); + +/** + * Groups in openttd.cfg that are actually lists. + */ +static const char * const _list_group_names[] = { + "bans", + "newgrf", + "servers", + "server_bind_addresses", + NULL +}; + +/** + * Find the index value of a ONEofMANY type in a string separated by | + * @param many full domain of values the ONEofMANY setting can have + * @param one the current value of the setting for which a value needs found + * @param onelen force calculation of the *one parameter + * @return the integer index of the full-list, or -1 if not found + */ +static size_t LookupOneOfMany(const char *many, const char *one, size_t onelen = 0) +{ + const char *s; + size_t idx; + + if (onelen == 0) onelen = strlen(one); + + /* check if it's an integer */ + if (*one >= '0' && *one <= '9') return strtoul(one, NULL, 0); + + idx = 0; + for (;;) { + /* find end of item */ + s = many; + while (*s != '|' && *s != 0) s++; + if ((size_t)(s - many) == onelen && !memcmp(one, many, onelen)) return idx; + if (*s == 0) return (size_t)-1; + many = s + 1; + idx++; + } +} + +/** + * Find the set-integer value MANYofMANY type in a string + * @param many full domain of values the MANYofMANY setting can have + * @param str the current string value of the setting, each individual + * of separated by a whitespace,tab or | character + * @return the 'fully' set integer, or -1 if a set is not found + */ +static size_t LookupManyOfMany(const char *many, const char *str) +{ + const char *s; + size_t r; + size_t res = 0; + + for (;;) { + /* skip "whitespace" */ + while (*str == ' ' || *str == '\t' || *str == '|') str++; + if (*str == 0) break; + + s = str; + while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++; + + r = LookupOneOfMany(many, str, s - str); + if (r == (size_t)-1) return r; + + SetBit(res, (uint8)r); // value found, set it + if (*s == 0) break; + str = s + 1; + } + return res; +} + +/** + * Parse an integerlist string and set each found value + * @param p the string to be parsed. Each element in the list is separated by a + * comma or a space character + * @param items pointer to the integerlist-array that will be filled with values + * @param maxitems the maximum number of elements the integerlist-array has + * @return returns the number of items found, or -1 on an error + */ +static int ParseIntList(const char *p, int *items, int maxitems) +{ + int n = 0; // number of items read so far + bool comma = false; // do we accept comma? + + while (*p != '\0') { + switch (*p) { + case ',': + /* Do not accept multiple commas between numbers */ + if (!comma) return -1; + comma = false; + /* FALL THROUGH */ + case ' ': + p++; + break; + + default: { + if (n == maxitems) return -1; // we don't accept that many numbers + char *end; + long v = strtol(p, &end, 0); + if (p == end) return -1; // invalid character (not a number) + if (sizeof(int) < sizeof(long)) v = ClampToI32(v); + items[n++] = v; + p = end; // first non-number + comma = true; // we accept comma now + break; + } + } + } + + /* If we have read comma but no number after it, fail. + * We have read comma when (n != 0) and comma is not allowed */ + if (n != 0 && !comma) return -1; + + return n; +} + +/** + * Load parsed string-values into an integer-array (intlist) + * @param str the string that contains the values (and will be parsed) + * @param array pointer to the integer-arrays that will be filled + * @param nelems the number of elements the array holds. Maximum is 64 elements + * @param type the type of elements the array holds (eg INT8, UINT16, etc.) + * @return return true on success and false on error + */ +static bool LoadIntList(const char *str, void *array, int nelems, VarType type) +{ + int items[64]; + int i, nitems; + + if (str == NULL) { + memset(items, 0, sizeof(items)); + nitems = nelems; + } else { + nitems = ParseIntList(str, items, lengthof(items)); + if (nitems != nelems) return false; + } + + switch (type) { + case SLE_VAR_BL: + case SLE_VAR_I8: + case SLE_VAR_U8: + for (i = 0; i != nitems; i++) ((byte*)array)[i] = items[i]; + break; + + case SLE_VAR_I16: + case SLE_VAR_U16: + for (i = 0; i != nitems; i++) ((uint16*)array)[i] = items[i]; + break; + + case SLE_VAR_I32: + case SLE_VAR_U32: + for (i = 0; i != nitems; i++) ((uint32*)array)[i] = items[i]; + break; + + default: NOT_REACHED(); + } + + return true; +} + +/** + * Convert an integer-array (intlist) to a string representation. Each value + * is separated by a comma or a space character + * @param buf output buffer where the string-representation will be stored + * @param last last item to write to in the output buffer + * @param array pointer to the integer-arrays that is read from + * @param nelems the number of elements the array holds. + * @param type the type of elements the array holds (eg INT8, UINT16, etc.) + */ +static void MakeIntList(char *buf, const char *last, const void *array, int nelems, VarType type) +{ + int i, v = 0; + const byte *p = (const byte *)array; + + for (i = 0; i != nelems; i++) { + switch (type) { + case SLE_VAR_BL: + case SLE_VAR_I8: v = *(const int8 *)p; p += 1; break; + case SLE_VAR_U8: v = *(const uint8 *)p; p += 1; break; + case SLE_VAR_I16: v = *(const int16 *)p; p += 2; break; + case SLE_VAR_U16: v = *(const uint16 *)p; p += 2; break; + case SLE_VAR_I32: v = *(const int32 *)p; p += 4; break; + case SLE_VAR_U32: v = *(const uint32 *)p; p += 4; break; + default: NOT_REACHED(); + } + buf += seprintf(buf, last, (i == 0) ? "%d" : ",%d", v); + } +} + +/** + * Convert a ONEofMANY structure to a string representation. + * @param buf output buffer where the string-representation will be stored + * @param last last item to write to in the output buffer + * @param many the full-domain string of possible values + * @param id the value of the variable and whose string-representation must be found + */ +static void MakeOneOfMany(char *buf, const char *last, const char *many, int id) +{ + int orig_id = id; + + /* Look for the id'th element */ + while (--id >= 0) { + for (; *many != '|'; many++) { + if (*many == '\0') { // not found + seprintf(buf, last, "%d", orig_id); + return; + } + } + many++; // pass the |-character + } + + /* copy string until next item (|) or the end of the list if this is the last one */ + while (*many != '\0' && *many != '|' && buf < last) *buf++ = *many++; + *buf = '\0'; +} + +/** + * Convert a MANYofMANY structure to a string representation. + * @param buf output buffer where the string-representation will be stored + * @param last last item to write to in the output buffer + * @param many the full-domain string of possible values + * @param x the value of the variable and whose string-representation must + * be found in the bitmasked many string + */ +static void MakeManyOfMany(char *buf, const char *last, const char *many, uint32 x) +{ + const char *start; + int i = 0; + bool init = true; + + for (; x != 0; x >>= 1, i++) { + start = many; + while (*many != 0 && *many != '|') many++; // advance to the next element + + if (HasBit(x, 0)) { // item found, copy it + if (!init) buf += seprintf(buf, last, "|"); + init = false; + if (start == many) { + buf += seprintf(buf, last, "%d", i); + } else { + memcpy(buf, start, many - start); + buf += many - start; + } + } + + if (*many == '|') many++; + } + + *buf = '\0'; +} + +/** + * Convert a string representation (external) of a setting to the internal rep. + * @param desc SettingDesc struct that holds all information about the variable + * @param orig_str input string that will be parsed based on the type of desc + * @return return the parsed value of the setting + */ +static const void *StringToVal(const SettingDescBase *desc, const char *orig_str) +{ + const char *str = orig_str == NULL ? "" : orig_str; + + switch (desc->cmd) { + case SDT_NUMX: { + char *end; + size_t val = strtoul(str, &end, 0); + if (end == str) { + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); + msg.SetDParamStr(0, str); + msg.SetDParamStr(1, desc->name); + _settings_error_list.push_back(msg); + return desc->def; + } + if (*end != '\0') { + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_TRAILING_CHARACTERS); + msg.SetDParamStr(0, desc->name); + _settings_error_list.push_back(msg); + } + return (void*)val; + } + + case SDT_ONEOFMANY: { + size_t r = LookupOneOfMany(desc->many, str); + /* if the first attempt of conversion from string to the appropriate value fails, + * look if we have defined a converter from old value to new value. */ + if (r == (size_t)-1 && desc->proc_cnvt != NULL) r = desc->proc_cnvt(str); + if (r != (size_t)-1) return (void*)r; // and here goes converted value + + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); + msg.SetDParamStr(0, str); + msg.SetDParamStr(1, desc->name); + _settings_error_list.push_back(msg); + return desc->def; + } + + case SDT_MANYOFMANY: { + size_t r = LookupManyOfMany(desc->many, str); + if (r != (size_t)-1) return (void*)r; + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); + msg.SetDParamStr(0, str); + msg.SetDParamStr(1, desc->name); + _settings_error_list.push_back(msg); + return desc->def; + } + + case SDT_BOOLX: { + if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return (void*)true; + if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return (void*)false; + + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); + msg.SetDParamStr(0, str); + msg.SetDParamStr(1, desc->name); + _settings_error_list.push_back(msg); + return desc->def; + } + + case SDT_STRING: return orig_str; + case SDT_INTLIST: return str; + default: break; + } + + return NULL; +} + +/** + * Set the value of a setting and if needed clamp the value to + * the preset minimum and maximum. + * @param ptr the variable itself + * @param sd pointer to the 'information'-database of the variable + * @param val signed long version of the new value + * @pre SettingDesc is of type SDT_BOOLX, SDT_NUMX, + * SDT_ONEOFMANY or SDT_MANYOFMANY. Other types are not supported as of now + */ +static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val) +{ + const SettingDescBase *sdb = &sd->desc; + + if (sdb->cmd != SDT_BOOLX && + sdb->cmd != SDT_NUMX && + sdb->cmd != SDT_ONEOFMANY && + sdb->cmd != SDT_MANYOFMANY) { + return; + } + + /* We cannot know the maximum value of a bitset variable, so just have faith */ + if (sdb->cmd != SDT_MANYOFMANY) { + /* We need to take special care of the uint32 type as we receive from the function + * a signed integer. While here also bail out on 64-bit settings as those are not + * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed + * 32-bit variable + * TODO: Support 64-bit settings/variables */ + switch (GetVarMemType(sd->save.conv)) { + case SLE_VAR_NULL: return; + case SLE_VAR_BL: + case SLE_VAR_I8: + case SLE_VAR_U8: + case SLE_VAR_I16: + case SLE_VAR_U16: + case SLE_VAR_I32: { + /* Override the minimum value. No value below sdb->min, except special value 0 */ + if (!(sdb->flags & SGF_0ISDISABLED) || val != 0) val = Clamp(val, sdb->min, sdb->max); + break; + } + case SLE_VAR_U32: { + /* Override the minimum value. No value below sdb->min, except special value 0 */ + uint min = ((sdb->flags & SGF_0ISDISABLED) && (uint)val <= (uint)sdb->min) ? 0 : sdb->min; + WriteValue(ptr, SLE_VAR_U32, (int64)ClampU(val, min, sdb->max)); + return; + } + case SLE_VAR_I64: + case SLE_VAR_U64: + default: NOT_REACHED(); + } + } + + WriteValue(ptr, sd->save.conv, (int64)val); +} + +/** + * Load values from a group of an IniFile structure into the internal representation + * @param ini pointer to IniFile structure that holds administrative information + * @param sd pointer to SettingDesc structure whose internally pointed variables will + * be given values + * @param grpname the group of the IniFile to search in for the new values + * @param object pointer to the object been loaded + */ +static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object) +{ + IniGroup *group; + IniGroup *group_def = ini->GetGroup(grpname); + IniItem *item; + const void *p; + void *ptr; + const char *s; + + for (; sd->save.cmd != SL_END; sd++) { + const SettingDescBase *sdb = &sd->desc; + const SaveLoad *sld = &sd->save; + + if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue; + + /* For settings.xx.yy load the settings from [xx] yy = ? */ + s = strchr(sdb->name, '.'); + if (s != NULL) { + group = ini->GetGroup(sdb->name, s - sdb->name); + s++; + } else { + s = sdb->name; + group = group_def; + } + + item = group->GetItem(s, false); + if (item == NULL && group != group_def) { + /* For settings.xx.yy load the settings from [settingss] yy = ? in case the previous + * did not exist (e.g. loading old config files with a [settings] section */ + item = group_def->GetItem(s, false); + } + if (item == NULL) { + /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous + * did not exist (e.g. loading old config files with a [yapf] section */ + const char *sc = strchr(s, '.'); + if (sc != NULL) item = ini->GetGroup(s, sc - s)->GetItem(sc + 1, false); + } + + p = (item == NULL) ? sdb->def : StringToVal(sdb, item->value); + ptr = GetVariableAddress(object, sld); + + switch (sdb->cmd) { + case SDT_BOOLX: // All four are various types of (integer) numbers + case SDT_NUMX: + case SDT_ONEOFMANY: + case SDT_MANYOFMANY: + Write_ValidateSetting(ptr, sd, (int32)(size_t)p); + break; + + case SDT_STRING: + switch (GetVarMemType(sld->conv)) { + case SLE_VAR_STRB: + case SLE_VAR_STRBQ: + if (p != NULL) ttd_strlcpy((char*)ptr, (const char*)p, sld->length); + break; + + case SLE_VAR_STR: + case SLE_VAR_STRQ: + free(*(char**)ptr); + *(char**)ptr = p == NULL ? NULL : strdup((const char*)p); + break; + + case SLE_VAR_CHAR: if (p != NULL) *(char *)ptr = *(const char *)p; break; + + default: NOT_REACHED(); + } + break; + + case SDT_INTLIST: { + if (!LoadIntList((const char*)p, ptr, sld->length, GetVarMemType(sld->conv))) { + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY); + msg.SetDParamStr(0, sdb->name); + _settings_error_list.push_back(msg); + + /* Use default */ + LoadIntList((const char*)sdb->def, ptr, sld->length, GetVarMemType(sld->conv)); + } else if (sd->desc.proc_cnvt != NULL) { + sd->desc.proc_cnvt((const char*)p); + } + break; + } + default: NOT_REACHED(); + } + } +} + +/** + * Save the values of settings to the inifile. + * @param ini pointer to IniFile structure + * @param sd read-only SettingDesc structure which contains the unmodified, + * loaded values of the configuration file and various information about it + * @param grpname holds the name of the group (eg. [network]) where these will be saved + * @param object pointer to the object been saved + * The function works as follows: for each item in the SettingDesc structure we + * have a look if the value has changed since we started the game (the original + * values are reloaded when saving). If settings indeed have changed, we get + * these and save them. + */ +static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object) +{ + IniGroup *group_def = NULL, *group; + IniItem *item; + char buf[512]; + const char *s; + void *ptr; + + for (; sd->save.cmd != SL_END; sd++) { + const SettingDescBase *sdb = &sd->desc; + const SaveLoad *sld = &sd->save; + + /* If the setting is not saved to the configuration + * file, just continue with the next setting */ + if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue; + if (sld->conv & SLF_NOT_IN_CONFIG) continue; + + /* XXX - wtf is this?? (group override?) */ + s = strchr(sdb->name, '.'); + if (s != NULL) { + group = ini->GetGroup(sdb->name, s - sdb->name); + s++; + } else { + if (group_def == NULL) group_def = ini->GetGroup(grpname); + s = sdb->name; + group = group_def; + } + + item = group->GetItem(s, true); + ptr = GetVariableAddress(object, sld); + + if (item->value != NULL) { + /* check if the value is the same as the old value */ + const void *p = StringToVal(sdb, item->value); + + /* The main type of a variable/setting is in bytes 8-15 + * The subtype (what kind of numbers do we have there) is in 0-7 */ + switch (sdb->cmd) { + case SDT_BOOLX: + case SDT_NUMX: + case SDT_ONEOFMANY: + case SDT_MANYOFMANY: + switch (GetVarMemType(sld->conv)) { + case SLE_VAR_BL: + if (*(bool*)ptr == (p != NULL)) continue; + break; + + case SLE_VAR_I8: + case SLE_VAR_U8: + if (*(byte*)ptr == (byte)(size_t)p) continue; + break; + + case SLE_VAR_I16: + case SLE_VAR_U16: + if (*(uint16*)ptr == (uint16)(size_t)p) continue; + break; + + case SLE_VAR_I32: + case SLE_VAR_U32: + if (*(uint32*)ptr == (uint32)(size_t)p) continue; + break; + + default: NOT_REACHED(); + } + break; + + default: break; // Assume the other types are always changed + } + } + + /* Value has changed, get the new value and put it into a buffer */ + switch (sdb->cmd) { + case SDT_BOOLX: + case SDT_NUMX: + case SDT_ONEOFMANY: + case SDT_MANYOFMANY: { + uint32 i = (uint32)ReadValue(ptr, sld->conv); + + switch (sdb->cmd) { + case SDT_BOOLX: strecpy(buf, (i != 0) ? "true" : "false", lastof(buf)); break; + case SDT_NUMX: seprintf(buf, lastof(buf), IsSignedVarMemType(sld->conv) ? "%d" : "%u", i); break; + case SDT_ONEOFMANY: MakeOneOfMany(buf, lastof(buf), sdb->many, i); break; + case SDT_MANYOFMANY: MakeManyOfMany(buf, lastof(buf), sdb->many, i); break; + default: NOT_REACHED(); + } + break; + } + + case SDT_STRING: + switch (GetVarMemType(sld->conv)) { + case SLE_VAR_STRB: strecpy(buf, (char*)ptr, lastof(buf)); break; + case SLE_VAR_STRBQ:seprintf(buf, lastof(buf), "\"%s\"", (char*)ptr); break; + case SLE_VAR_STR: strecpy(buf, *(char**)ptr, lastof(buf)); break; + + case SLE_VAR_STRQ: + if (*(char**)ptr == NULL) { + buf[0] = '\0'; + } else { + seprintf(buf, lastof(buf), "\"%s\"", *(char**)ptr); + } + break; + + case SLE_VAR_CHAR: buf[0] = *(char*)ptr; buf[1] = '\0'; break; + default: NOT_REACHED(); + } + break; + + case SDT_INTLIST: + MakeIntList(buf, lastof(buf), ptr, sld->length, GetVarMemType(sld->conv)); + break; + + default: NOT_REACHED(); + } + + /* The value is different, that means we have to write it to the ini */ + free(item->value); + item->value = strdup(buf); + } +} + +/** + * Loads all items from a 'grpname' section into a list + * The list parameter can be a NULL pointer, in this case nothing will be + * saved and a callback function should be defined that will take over the + * list-handling and store the data itself somewhere. + * @param ini IniFile handle to the ini file with the source data + * @param grpname character string identifying the section-header of the ini file that will be parsed + * @param list new list with entries of the given section + */ +static void IniLoadSettingList(IniFile *ini, const char *grpname, StringList *list) +{ + IniGroup *group = ini->GetGroup(grpname); + + if (group == NULL || list == NULL) return; + + list->Clear(); + + for (const IniItem *item = group->item; item != NULL; item = item->next) { + if (item->name != NULL) *list->Append() = strdup(item->name); + } +} + +/** + * Saves all items from a list into the 'grpname' section + * The list parameter can be a NULL pointer, in this case a callback function + * should be defined that will provide the source data to be saved. + * @param ini IniFile handle to the ini file where the destination data is saved + * @param grpname character string identifying the section-header of the ini file + * @param list pointer to an string(pointer) array that will be used as the + * source to be saved into the relevant ini section + */ +static void IniSaveSettingList(IniFile *ini, const char *grpname, StringList *list) +{ + IniGroup *group = ini->GetGroup(grpname); + + if (group == NULL || list == NULL) return; + group->Clear(); + + for (char **iter = list->Begin(); iter != list->End(); iter++) { + group->GetItem(*iter, true)->SetValue(""); + } +} + +/** + * Load a WindowDesc from config. + * @param ini IniFile handle to the ini file with the source data + * @param grpname character string identifying the section-header of the ini file that will be parsed + * @param desc Destination WindowDesc + */ +void IniLoadWindowSettings(IniFile *ini, const char *grpname, void *desc) +{ + IniLoadSettings(ini, _window_settings, grpname, desc); +} + +/** + * Save a WindowDesc to config. + * @param ini IniFile handle to the ini file where the destination data is saved + * @param grpname character string identifying the section-header of the ini file + * @param desc Source WindowDesc + */ +void IniSaveWindowSettings(IniFile *ini, const char *grpname, void *desc) +{ + IniSaveSettings(ini, _window_settings, grpname, desc); +} + +/** + * Check whether the setting is editable in the current gamemode. + * @param do_command true if this is about checking a command from the server. + * @return true if editable. + */ +bool SettingDesc::IsEditable(bool do_command) const +{ + if (!do_command && !(this->save.conv & SLF_NO_NETWORK_SYNC) && _networking && !_network_server && !(this->desc.flags & SGF_PER_COMPANY)) return false; + if ((this->desc.flags & SGF_NETWORK_ONLY) && !_networking && _game_mode != GM_MENU) return false; + if ((this->desc.flags & SGF_NO_NETWORK) && _networking) return false; + if ((this->desc.flags & SGF_NEWGAME_ONLY) && + (_game_mode == GM_NORMAL || + (_game_mode == GM_EDITOR && !(this->desc.flags & SGF_SCENEDIT_TOO)))) return false; + return true; +} + +/** + * Return the type of the setting. + * @return type of setting + */ +SettingType SettingDesc::GetType() const +{ + if (this->desc.flags & SGF_PER_COMPANY) return ST_COMPANY; + return (this->save.conv & SLF_NOT_IN_SAVE) ? ST_CLIENT : ST_GAME; +} + +/* Begin - Callback Functions for the various settings. */ + +/** Reposition the main toolbar as the setting changed. */ +static bool v_PositionMainToolbar(int32 p1) +{ + if (_game_mode != GM_MENU) PositionMainToolbar(NULL); + return true; +} + +/** Reposition the statusbar as the setting changed. */ +static bool v_PositionStatusbar(int32 p1) +{ + if (_game_mode != GM_MENU) { + PositionStatusbar(NULL); + PositionNewsMessage(NULL); + PositionNetworkChatWindow(NULL); + } + return true; +} + +static bool PopulationInLabelActive(int32 p1) +{ + UpdateAllTownVirtCoords(); + return true; +} + +static bool RedrawScreen(int32 p1) +{ + MarkWholeScreenDirty(); + return true; +} + +/** + * Redraw the smallmap after a colour scheme change. + * @param p1 Callback parameter. + * @return Always true. + */ +static bool RedrawSmallmap(int32 p1) +{ + BuildLandLegend(); + BuildOwnerLegend(); + SetWindowClassesDirty(WC_SMALLMAP); + return true; +} + +static bool InvalidateDetailsWindow(int32 p1) +{ + SetWindowClassesDirty(WC_VEHICLE_DETAILS); + return true; +} + +static bool StationSpreadChanged(int32 p1) +{ + InvalidateWindowData(WC_SELECT_STATION, 0); + InvalidateWindowData(WC_BUILD_STATION, 0); + return true; +} + +static bool InvalidateBuildIndustryWindow(int32 p1) +{ + InvalidateWindowData(WC_BUILD_INDUSTRY, 0); + return true; +} + +static bool CloseSignalGUI(int32 p1) +{ + if (p1 == 0) { + DeleteWindowByClass(WC_BUILD_SIGNAL); + } + return true; +} + +static bool InvalidateTownViewWindow(int32 p1) +{ + InvalidateWindowClassesData(WC_TOWN_VIEW, p1); + return true; +} + +static bool DeleteSelectStationWindow(int32 p1) +{ + DeleteWindowById(WC_SELECT_STATION, 0); + return true; +} + +static bool UpdateConsists(int32 p1) +{ + Train *t; + FOR_ALL_TRAINS(t) { + /* Update the consist of all trains so the maximum speed is set correctly. */ + if (t->IsFrontEngine() || t->IsFreeWagon()) t->ConsistChanged(CCF_TRACK); + } + InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0); + return true; +} + +/* Check service intervals of vehicles, p1 is value of % or day based servicing */ +static bool CheckInterval(int32 p1) +{ + bool update_vehicles; + VehicleDefaultSettings *vds; + if (_game_mode == GM_MENU || !Company::IsValidID(_current_company)) { + vds = &_settings_client.company.vehicle; + update_vehicles = false; + } else { + vds = &Company::Get(_current_company)->settings.vehicle; + update_vehicles = true; + } + + if (p1 != 0) { + vds->servint_trains = 50; + vds->servint_roadveh = 50; + vds->servint_aircraft = 50; + vds->servint_ships = 50; + } else { + vds->servint_trains = 150; + vds->servint_roadveh = 150; + vds->servint_aircraft = 100; + vds->servint_ships = 360; + } + + if (update_vehicles) { + const Company *c = Company::Get(_current_company); + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->owner == _current_company && v->IsPrimaryVehicle() && !v->ServiceIntervalIsCustom()) { + v->SetServiceInterval(CompanyServiceInterval(c, v->type)); + v->SetServiceIntervalIsPercent(p1 != 0); + } + } + } + + InvalidateDetailsWindow(0); + + return true; +} + +static bool UpdateInterval(VehicleType type, int32 p1) +{ + bool update_vehicles; + VehicleDefaultSettings *vds; + if (_game_mode == GM_MENU || !Company::IsValidID(_current_company)) { + vds = &_settings_client.company.vehicle; + update_vehicles = false; + } else { + vds = &Company::Get(_current_company)->settings.vehicle; + update_vehicles = true; + } + + /* Test if the interval is valid */ + uint16 interval = GetServiceIntervalClamped(p1, vds->servint_ispercent); + if (interval != p1) return false; + + if (update_vehicles) { + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->owner == _current_company && v->type == type && v->IsPrimaryVehicle() && !v->ServiceIntervalIsCustom()) { + v->SetServiceInterval(p1); + } + } + } + + InvalidateDetailsWindow(0); + + return true; +} + +static bool UpdateIntervalTrains(int32 p1) +{ + return UpdateInterval(VEH_TRAIN, p1); +} + +static bool UpdateIntervalRoadVeh(int32 p1) +{ + return UpdateInterval(VEH_ROAD, p1); +} + +static bool UpdateIntervalShips(int32 p1) +{ + return UpdateInterval(VEH_SHIP, p1); +} + +static bool UpdateIntervalAircraft(int32 p1) +{ + return UpdateInterval(VEH_AIRCRAFT, p1); +} + +static bool TrainAccelerationModelChanged(int32 p1) +{ + Train *t; + FOR_ALL_TRAINS(t) { + if (t->IsFrontEngine()) { + t->tcache.cached_max_curve_speed = t->GetCurveSpeedLimit(); + t->UpdateAcceleration(); + } + } + + /* These windows show acceleration values only when realistic acceleration is on. They must be redrawn after a setting change. */ + SetWindowClassesDirty(WC_ENGINE_PREVIEW); + InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0); + SetWindowClassesDirty(WC_VEHICLE_DETAILS); + + return true; +} + +/** + * This function updates the train acceleration cache after a steepness change. + * @param p1 Callback parameter. + * @return Always true. + */ +static bool TrainSlopeSteepnessChanged(int32 p1) +{ + Train *t; + FOR_ALL_TRAINS(t) { + if (t->IsFrontEngine()) t->CargoChanged(); + } + + return true; +} + +/** + * This function updates realistic acceleration caches when the setting "Road vehicle acceleration model" is set. + * @param p1 Callback parameter + * @return Always true + */ +static bool RoadVehAccelerationModelChanged(int32 p1) +{ + if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) { + RoadVehicle *rv; + FOR_ALL_ROADVEHICLES(rv) { + if (rv->IsFrontEngine()) { + rv->CargoChanged(); + } + } + } + + /* These windows show acceleration values only when realistic acceleration is on. They must be redrawn after a setting change. */ + SetWindowClassesDirty(WC_ENGINE_PREVIEW); + InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0); + SetWindowClassesDirty(WC_VEHICLE_DETAILS); + + return true; +} + +/** + * This function updates the road vehicle acceleration cache after a steepness change. + * @param p1 Callback parameter. + * @return Always true. + */ +static bool RoadVehSlopeSteepnessChanged(int32 p1) +{ + RoadVehicle *rv; + FOR_ALL_ROADVEHICLES(rv) { + if (rv->IsFrontEngine()) rv->CargoChanged(); + } + + return true; +} + +static bool DragSignalsDensityChanged(int32) +{ + InvalidateWindowData(WC_BUILD_SIGNAL, 0); + + return true; +} + +static bool TownFoundingChanged(int32 p1) +{ + if (_game_mode != GM_EDITOR && _settings_game.economy.found_town == TF_FORBIDDEN) { + DeleteWindowById(WC_FOUND_TOWN, 0); + return true; + } + InvalidateWindowData(WC_FOUND_TOWN, 0); + return true; +} + +static bool InvalidateVehTimetableWindow(int32 p1) +{ + InvalidateWindowClassesData(WC_VEHICLE_TIMETABLE, VIWD_MODIFY_ORDERS); + return true; +} + +static bool ZoomMinMaxChanged(int32 p1) +{ + extern void ConstrainAllViewportsZoom(); + ConstrainAllViewportsZoom(); + GfxClearSpriteCache(); + return true; +} + +/** + * Update any possible saveload window and delete any newgrf dialogue as + * its widget parts might change. Reinit all windows as it allows access to the + * newgrf debug button. + * @param p1 unused. + * @return Always true. + */ +static bool InvalidateNewGRFChangeWindows(int32 p1) +{ + InvalidateWindowClassesData(WC_SAVELOAD); + DeleteWindowByClass(WC_GAME_OPTIONS); + ReInitAllWindows(); + return true; +} + +static bool InvalidateCompanyLiveryWindow(int32 p1) +{ + InvalidateWindowClassesData(WC_COMPANY_COLOUR); + return RedrawScreen(p1); +} + +static bool InvalidateIndustryViewWindow(int32 p1) +{ + InvalidateWindowClassesData(WC_INDUSTRY_VIEW); + return true; +} + +static bool InvalidateAISettingsWindow(int32 p1) +{ + InvalidateWindowClassesData(WC_AI_SETTINGS); + return true; +} + +/** + * Update the town authority window after a town authority setting change. + * @param p1 Unused. + * @return Always true. + */ +static bool RedrawTownAuthority(int32 p1) +{ + SetWindowClassesDirty(WC_TOWN_AUTHORITY); + return true; +} + +/** + * Invalidate the company infrastructure details window after a infrastructure maintenance setting change. + * @param p1 Unused. + * @return Always true. + */ +static bool InvalidateCompanyInfrastructureWindow(int32 p1) +{ + InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); + return true; +} + +/** + * Invalidate the company details window after the shares setting changed. + * @param p1 Unused. + * @return Always true. + */ +static bool InvalidateCompanyWindow(int32 p1) +{ + InvalidateWindowClassesData(WC_COMPANY); + return true; +} + +/** Checks if any settings are set to incorrect values, and sets them to correct values in that case. */ +static void ValidateSettings() +{ + /* Do not allow a custom sea level with the original land generator. */ + if (_settings_newgame.game_creation.land_generator == 0 && + _settings_newgame.difficulty.quantity_sea_lakes == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) { + _settings_newgame.difficulty.quantity_sea_lakes = CUSTOM_SEA_LEVEL_MIN_PERCENTAGE; + } +} + +static bool DifficultyNoiseChange(int32 i) +{ + if (_game_mode == GM_NORMAL) { + UpdateAirportsNoise(); + if (_settings_game.economy.station_noise_level) { + InvalidateWindowClassesData(WC_TOWN_VIEW, 0); + } + } + + return true; +} + +static bool MaxNoAIsChange(int32 i) +{ + if (GetGameSettings().difficulty.max_no_competitors != 0 && + AI::GetInfoList()->size() == 0 && + (!_networking || _network_server)) { + ShowErrorMessage(STR_WARNING_NO_SUITABLE_AI, INVALID_STRING_ID, WL_CRITICAL); + } + + return true; +} + +/** + * Check whether the road side may be changed. + * @param p1 unused + * @return true if the road side may be changed. + */ +static bool CheckRoadSide(int p1) +{ + extern bool RoadVehiclesAreBuilt(); + return _game_mode == GM_MENU || !RoadVehiclesAreBuilt(); +} + +/** + * Conversion callback for _gameopt_settings_game.landscape + * It converts (or try) between old values and the new ones, + * without losing initial setting of the user + * @param value that was read from config file + * @return the "hopefully" converted value + */ +static size_t ConvertLandscape(const char *value) +{ + /* try with the old values */ + return LookupOneOfMany("normal|hilly|desert|candy", value); +} + +static bool CheckFreeformEdges(int32 p1) +{ + if (_game_mode == GM_MENU) return true; + if (p1 != 0) { + Ship *s; + FOR_ALL_SHIPS(s) { + /* Check if there is a ship on the northern border. */ + if (TileX(s->tile) == 0 || TileY(s->tile) == 0) { + ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, WL_ERROR); + return false; + } + } + BaseStation *st; + FOR_ALL_BASE_STATIONS(st) { + /* Check if there is a non-deleted buoy on the northern border. */ + if (st->IsInUse() && (TileX(st->xy) == 0 || TileY(st->xy) == 0)) { + ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, WL_ERROR); + return false; + } + } + for (uint i = 0; i < MapSizeX(); i++) MakeVoid(TileXY(i, 0)); + for (uint i = 0; i < MapSizeY(); i++) MakeVoid(TileXY(0, i)); + } else { + for (uint i = 0; i < MapMaxX(); i++) { + if (TileHeight(TileXY(i, 1)) != 0) { + ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR); + return false; + } + } + for (uint i = 1; i < MapMaxX(); i++) { + if (!IsTileType(TileXY(i, MapMaxY() - 1), MP_WATER) || TileHeight(TileXY(1, MapMaxY())) != 0) { + ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR); + return false; + } + } + for (uint i = 0; i < MapMaxY(); i++) { + if (TileHeight(TileXY(1, i)) != 0) { + ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR); + return false; + } + } + for (uint i = 1; i < MapMaxY(); i++) { + if (!IsTileType(TileXY(MapMaxX() - 1, i), MP_WATER) || TileHeight(TileXY(MapMaxX(), i)) != 0) { + ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR); + return false; + } + } + /* Make tiles at the border water again. */ + for (uint i = 0; i < MapMaxX(); i++) { + SetTileHeight(TileXY(i, 0), 0); + SetTileType(TileXY(i, 0), MP_WATER); + } + for (uint i = 0; i < MapMaxY(); i++) { + SetTileHeight(TileXY(0, i), 0); + SetTileType(TileXY(0, i), MP_WATER); + } + } + MarkWholeScreenDirty(); + return true; +} + +/** + * Changing the setting "allow multiple NewGRF sets" is not allowed + * if there are vehicles. + */ +static bool ChangeDynamicEngines(int32 p1) +{ + if (_game_mode == GM_MENU) return true; + + if (!EngineOverrideManager::ResetToCurrentNewGRFConfig()) { + ShowErrorMessage(STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES, INVALID_STRING_ID, WL_ERROR); + return false; + } + + return true; +} + +static bool StationCatchmentChanged(int32 p1) +{ + Station::RecomputeIndustriesNearForAll(); + return true; +} + + +#ifdef ENABLE_NETWORK + +static bool UpdateClientName(int32 p1) +{ + NetworkUpdateClientName(); + return true; +} + +static bool UpdateServerPassword(int32 p1) +{ + if (strcmp(_settings_client.network.server_password, "*") == 0) { + _settings_client.network.server_password[0] = '\0'; + } + + return true; +} + +static bool UpdateRconPassword(int32 p1) +{ + if (strcmp(_settings_client.network.rcon_password, "*") == 0) { + _settings_client.network.rcon_password[0] = '\0'; + } + + return true; +} + +static bool UpdateClientConfigValues(int32 p1) +{ + if (_network_server) NetworkServerSendConfigUpdate(); + + return true; +} + +#endif /* ENABLE_NETWORK */ + + +/* End - Callback Functions */ + +/** + * Prepare for reading and old diff_custom by zero-ing the memory. + */ +static void PrepareOldDiffCustom() +{ + memset(_old_diff_custom, 0, sizeof(_old_diff_custom)); +} + +/** + * Reading of the old diff_custom array and transforming it to the new format. + * @param savegame is it read from the config or savegame. In the latter case + * we are sure there is an array; in the former case we have + * to check that. + */ +static void HandleOldDiffCustom(bool savegame) +{ + uint options_to_load = GAME_DIFFICULTY_NUM - ((savegame && IsSavegameVersionBefore(4)) ? 1 : 0); + + if (!savegame) { + /* If we did read to old_diff_custom, then at least one value must be non 0. */ + bool old_diff_custom_used = false; + for (uint i = 0; i < options_to_load && !old_diff_custom_used; i++) { + old_diff_custom_used = (_old_diff_custom[i] != 0); + } + + if (!old_diff_custom_used) return; + } + + for (uint i = 0; i < options_to_load; i++) { + const SettingDesc *sd = &_settings[i]; + /* Skip deprecated options */ + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; + void *var = GetVariableAddress(savegame ? &_settings_game : &_settings_newgame, &sd->save); + Write_ValidateSetting(var, sd, (int32)((i == 4 ? 1000 : 1) * _old_diff_custom[i])); + } +} + +static void AILoadConfig(IniFile *ini, const char *grpname) +{ + IniGroup *group = ini->GetGroup(grpname); + IniItem *item; + + /* Clean any configured AI */ + for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { + AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME)->Change(NULL); + } + + /* If no group exists, return */ + if (group == NULL) return; + + CompanyID c = COMPANY_FIRST; + for (item = group->item; c < MAX_COMPANIES && item != NULL; c++, item = item->next) { + AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME); + + config->Change(item->name); + if (!config->HasScript()) { + if (strcmp(item->name, "none") != 0) { + DEBUG(script, 0, "The AI by the name '%s' was no longer found, and removed from the list.", item->name); + continue; + } + } + if (item->value != NULL) config->StringToSettings(item->value); + } +} + +static void GameLoadConfig(IniFile *ini, const char *grpname) +{ + IniGroup *group = ini->GetGroup(grpname); + IniItem *item; + + /* Clean any configured GameScript */ + GameConfig::GetConfig(GameConfig::SSS_FORCE_NEWGAME)->Change(NULL); + + /* If no group exists, return */ + if (group == NULL) return; + + item = group->item; + if (item == NULL) return; + + GameConfig *config = GameConfig::GetConfig(AIConfig::SSS_FORCE_NEWGAME); + + config->Change(item->name); + if (!config->HasScript()) { + if (strcmp(item->name, "none") != 0) { + DEBUG(script, 0, "The GameScript by the name '%s' was no longer found, and removed from the list.", item->name); + return; + } + } + if (item->value != NULL) config->StringToSettings(item->value); +} + +/** + * Load a GRF configuration + * @param ini The configuration to read from. + * @param grpname Group name containing the configuration of the GRF. + * @param is_static GRF is static. + */ +static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_static) +{ + IniGroup *group = ini->GetGroup(grpname); + IniItem *item; + GRFConfig *first = NULL; + GRFConfig **curr = &first; + + if (group == NULL) return NULL; + + for (item = group->item; item != NULL; item = item->next) { + GRFConfig *c = new GRFConfig(item->name); + + /* Parse parameters */ + if (!StrEmpty(item->value)) { + c->num_params = ParseIntList(item->value, (int*)c->param, lengthof(c->param)); + if (c->num_params == (byte)-1) { + SetDParamStr(0, item->name); + ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL); + c->num_params = 0; + } + } + + /* Check if item is valid */ + if (!FillGRFDetails(c, is_static) || HasBit(c->flags, GCF_INVALID)) { + if (c->status == GCS_NOT_FOUND) { + SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND); + } else if (HasBit(c->flags, GCF_UNSAFE)) { + SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNSAFE); + } else if (HasBit(c->flags, GCF_SYSTEM)) { + SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_SYSTEM); + } else if (HasBit(c->flags, GCF_INVALID)) { + SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE); + } else { + SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN); + } + + SetDParamStr(0, item->name); + ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL); + delete c; + continue; + } + + /* Check for duplicate GRFID (will also check for duplicate filenames) */ + bool duplicate = false; + for (const GRFConfig *gc = first; gc != NULL; gc = gc->next) { + if (gc->ident.grfid == c->ident.grfid) { + SetDParamStr(0, item->name); + SetDParamStr(1, gc->filename); + ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_DUPLICATE_GRFID, WL_CRITICAL); + duplicate = true; + break; + } + } + if (duplicate) { + delete c; + continue; + } + + /* Mark file as static to avoid saving in savegame. */ + if (is_static) SetBit(c->flags, GCF_STATIC); + + /* Add item to list */ + *curr = c; + curr = &c->next; + } + + return first; +} + +static void AISaveConfig(IniFile *ini, const char *grpname) +{ + IniGroup *group = ini->GetGroup(grpname); + + if (group == NULL) return; + group->Clear(); + + for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { + AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME); + const char *name; + char value[1024]; + config->SettingsToString(value, lengthof(value)); + + if (config->HasScript()) { + name = config->GetName(); + } else { + name = "none"; + } + + IniItem *item = new IniItem(group, name, strlen(name)); + item->SetValue(value); + } +} + +static void GameSaveConfig(IniFile *ini, const char *grpname) +{ + IniGroup *group = ini->GetGroup(grpname); + + if (group == NULL) return; + group->Clear(); + + GameConfig *config = GameConfig::GetConfig(AIConfig::SSS_FORCE_NEWGAME); + const char *name; + char value[1024]; + config->SettingsToString(value, lengthof(value)); + + if (config->HasScript()) { + name = config->GetName(); + } else { + name = "none"; + } + + IniItem *item = new IniItem(group, name, strlen(name)); + item->SetValue(value); +} + +/** + * Save the version of OpenTTD to the ini file. + * @param ini the ini to write to + */ +static void SaveVersionInConfig(IniFile *ini) +{ + IniGroup *group = ini->GetGroup("version"); + + char version[9]; + snprintf(version, lengthof(version), "%08X", _openttd_newgrf_version); + + const char * const versions[][2] = { + { "version_string", _openttd_revision }, + { "version_number", version } + }; + + for (uint i = 0; i < lengthof(versions); i++) { + group->GetItem(versions[i][0], true)->SetValue(versions[i][1]); + } +} + +/* Save a GRF configuration to the given group name */ +static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *list) +{ + ini->RemoveGroup(grpname); + IniGroup *group = ini->GetGroup(grpname); + const GRFConfig *c; + + for (c = list; c != NULL; c = c->next) { + char params[512]; + GRFBuildParamList(params, c, lastof(params)); + + group->GetItem(c->filename, true)->SetValue(params); + } +} + +/* Common handler for saving/loading variables to the configuration file */ +static void HandleSettingDescs(IniFile *ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool basic_settings = true, bool other_settings = true) +{ + if (basic_settings) { + proc(ini, (const SettingDesc*)_misc_settings, "misc", NULL); +#if defined(WIN32) && !defined(DEDICATED) + proc(ini, (const SettingDesc*)_win32_settings, "win32", NULL); +#endif /* WIN32 */ + } + + if (other_settings) { + proc(ini, _settings, "patches", &_settings_newgame); + proc(ini, _currency_settings,"currency", &_custom_currency); + proc(ini, _company_settings, "company", &_settings_client.company); + +#ifdef ENABLE_NETWORK + proc_list(ini, "server_bind_addresses", &_network_bind_list); + proc_list(ini, "servers", &_network_host_list); + proc_list(ini, "bans", &_network_ban_list); +#endif /* ENABLE_NETWORK */ + } +} + +static IniFile *IniLoadConfig() +{ + IniFile *ini = new IniFile(_list_group_names); + ini->LoadFromDisk(_config_file, BASE_DIR); + return ini; +} + +/** + * Load the values from the configuration files + * @param minimal Load the minimal amount of the configuration to "bootstrap" the blitter and such. + */ +void LoadFromConfig(bool minimal) +{ + IniFile *ini = IniLoadConfig(); + if (!minimal) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one + + /* Load basic settings only during bootstrap, load other settings not during bootstrap */ + HandleSettingDescs(ini, IniLoadSettings, IniLoadSettingList, minimal, !minimal); + + if (!minimal) { + _grfconfig_newgame = GRFLoadConfig(ini, "newgrf", false); + _grfconfig_static = GRFLoadConfig(ini, "newgrf-static", true); + AILoadConfig(ini, "ai_players"); + GameLoadConfig(ini, "game_scripts"); + + PrepareOldDiffCustom(); + IniLoadSettings(ini, _gameopt_settings, "gameopt", &_settings_newgame); + HandleOldDiffCustom(false); + + ValidateSettings(); + + /* Display sheduled errors */ + extern void ScheduleErrorMessage(ErrorList &datas); + ScheduleErrorMessage(_settings_error_list); + if (FindWindowById(WC_ERRMSG, 0) == NULL) ShowFirstError(); + } + + delete ini; +} + +/** Save the values to the configuration file */ +void SaveToConfig() +{ + IniFile *ini = IniLoadConfig(); + + /* Remove some obsolete groups. These have all been loaded into other groups. */ + ini->RemoveGroup("patches"); + ini->RemoveGroup("yapf"); + ini->RemoveGroup("gameopt"); + + HandleSettingDescs(ini, IniSaveSettings, IniSaveSettingList); + GRFSaveConfig(ini, "newgrf", _grfconfig_newgame); + GRFSaveConfig(ini, "newgrf-static", _grfconfig_static); + AISaveConfig(ini, "ai_players"); + GameSaveConfig(ini, "game_scripts"); + SaveVersionInConfig(ini); + ini->SaveToDisk(_config_file); + delete ini; +} + +/** + * Get the list of known NewGrf presets. + * @param list[inout] Pointer to list for storing the preset names. + */ +void GetGRFPresetList(GRFPresetList *list) +{ + list->Clear(); + + IniFile *ini = IniLoadConfig(); + IniGroup *group; + for (group = ini->group; group != NULL; group = group->next) { + if (strncmp(group->name, "preset-", 7) == 0) { + *list->Append() = strdup(group->name + 7); + } + } + + delete ini; +} + +/** + * Load a NewGRF configuration by preset-name. + * @param config_name Name of the preset. + * @return NewGRF configuration. + * @see GetGRFPresetList + */ +GRFConfig *LoadGRFPresetFromConfig(const char *config_name) +{ + char *section = (char*)alloca(strlen(config_name) + 8); + sprintf(section, "preset-%s", config_name); + + IniFile *ini = IniLoadConfig(); + GRFConfig *config = GRFLoadConfig(ini, section, false); + delete ini; + + return config; +} + +/** + * Save a NewGRF configuration with a preset name. + * @param config_name Name of the preset. + * @param config NewGRF configuration to save. + * @see GetGRFPresetList + */ +void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config) +{ + char *section = (char*)alloca(strlen(config_name) + 8); + sprintf(section, "preset-%s", config_name); + + IniFile *ini = IniLoadConfig(); + GRFSaveConfig(ini, section, config); + ini->SaveToDisk(_config_file); + delete ini; +} + +/** + * Delete a NewGRF configuration by preset name. + * @param config_name Name of the preset. + */ +void DeleteGRFPresetFromConfig(const char *config_name) +{ + char *section = (char*)alloca(strlen(config_name) + 8); + sprintf(section, "preset-%s", config_name); + + IniFile *ini = IniLoadConfig(); + ini->RemoveGroup(section); + ini->SaveToDisk(_config_file); + delete ini; +} + +const SettingDesc *GetSettingDescription(uint index) +{ + if (index >= lengthof(_settings)) return NULL; + return &_settings[index]; +} + +/** + * Network-safe changing of settings (server-only). + * @param tile unused + * @param flags operation to perform + * @param p1 the index of the setting in the SettingDesc array which identifies it + * @param p2 the new value for the setting + * The new value is properly clamped to its minimum/maximum when setting + * @param text unused + * @return the cost of this operation or an error + * @see _settings + */ +CommandCost CmdChangeSetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + const SettingDesc *sd = GetSettingDescription(p1); + + if (sd == NULL) return CMD_ERROR; + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) return CMD_ERROR; + + if (!sd->IsEditable(true)) return CMD_ERROR; + + if (flags & DC_EXEC) { + void *var = GetVariableAddress(&GetGameSettings(), &sd->save); + + int32 oldval = (int32)ReadValue(var, sd->save.conv); + int32 newval = (int32)p2; + + Write_ValidateSetting(var, sd, newval); + newval = (int32)ReadValue(var, sd->save.conv); + + if (oldval == newval) return CommandCost(); + + if (sd->desc.proc != NULL && !sd->desc.proc(newval)) { + WriteValue(var, sd->save.conv, (int64)oldval); + return CommandCost(); + } + + if (sd->desc.flags & SGF_NO_NETWORK) { + GamelogStartAction(GLAT_SETTING); + GamelogSetting(sd->desc.name, oldval, newval); + GamelogStopAction(); + } + + SetWindowClassesDirty(WC_GAME_OPTIONS); + } + + return CommandCost(); +} + +/** + * Change one of the per-company settings. + * @param tile unused + * @param flags operation to perform + * @param p1 the index of the setting in the _company_settings array which identifies it + * @param p2 the new value for the setting + * The new value is properly clamped to its minimum/maximum when setting + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdChangeCompanySetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + if (p1 >= lengthof(_company_settings)) return CMD_ERROR; + const SettingDesc *sd = &_company_settings[p1]; + + if (flags & DC_EXEC) { + void *var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save); + + int32 oldval = (int32)ReadValue(var, sd->save.conv); + int32 newval = (int32)p2; + + Write_ValidateSetting(var, sd, newval); + newval = (int32)ReadValue(var, sd->save.conv); + + if (oldval == newval) return CommandCost(); + + if (sd->desc.proc != NULL && !sd->desc.proc(newval)) { + WriteValue(var, sd->save.conv, (int64)oldval); + return CommandCost(); + } + + SetWindowClassesDirty(WC_GAME_OPTIONS); + } + + return CommandCost(); +} + +/** + * Top function to save the new value of an element of the Settings struct + * @param index offset in the SettingDesc array of the Settings struct which + * identifies the setting member we want to change + * @param value new value of the setting + * @param force_newgame force the newgame settings + */ +bool SetSettingValue(uint index, int32 value, bool force_newgame) +{ + const SettingDesc *sd = &_settings[index]; + /* If an item is company-based, we do not send it over the network + * (if any) to change. Also *hack*hack* we update the _newgame version + * of settings because changing a company-based setting in a game also + * changes its defaults. At least that is the convention we have chosen */ + if (sd->save.conv & SLF_NO_NETWORK_SYNC) { + void *var = GetVariableAddress(&GetGameSettings(), &sd->save); + Write_ValidateSetting(var, sd, value); + + if (_game_mode != GM_MENU) { + void *var2 = GetVariableAddress(&_settings_newgame, &sd->save); + Write_ValidateSetting(var2, sd, value); + } + if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv)); + + SetWindowClassesDirty(WC_GAME_OPTIONS); + + return true; + } + + if (force_newgame) { + void *var2 = GetVariableAddress(&_settings_newgame, &sd->save); + Write_ValidateSetting(var2, sd, value); + return true; + } + + /* send non-company-based settings over the network */ + if (!_networking || (_networking && _network_server)) { + return DoCommandP(0, index, value, CMD_CHANGE_SETTING); + } + return false; +} + +/** + * Top function to save the new value of an element of the Settings struct + * @param index offset in the SettingDesc array of the CompanySettings struct + * which identifies the setting member we want to change + * @param value new value of the setting + */ +void SetCompanySetting(uint index, int32 value) +{ + const SettingDesc *sd = &_company_settings[index]; + if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) { + DoCommandP(0, index, value, CMD_CHANGE_COMPANY_SETTING); + } else { + void *var = GetVariableAddress(&_settings_client.company, &sd->save); + Write_ValidateSetting(var, sd, value); + if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv)); + } +} + +/** + * Set the company settings for a new company to their default values. + */ +void SetDefaultCompanySettings(CompanyID cid) +{ + Company *c = Company::Get(cid); + const SettingDesc *sd; + for (sd = _company_settings; sd->save.cmd != SL_END; sd++) { + void *var = GetVariableAddress(&c->settings, &sd->save); + Write_ValidateSetting(var, sd, (int32)(size_t)sd->desc.def); + } +} + +#if defined(ENABLE_NETWORK) +/** + * Sync all company settings in a multiplayer game. + */ +void SyncCompanySettings() +{ + const SettingDesc *sd; + uint i = 0; + for (sd = _company_settings; sd->save.cmd != SL_END; sd++, i++) { + const void *old_var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save); + const void *new_var = GetVariableAddress(&_settings_client.company, &sd->save); + uint32 old_value = (uint32)ReadValue(old_var, sd->save.conv); + uint32 new_value = (uint32)ReadValue(new_var, sd->save.conv); + if (old_value != new_value) NetworkSendCommand(0, i, new_value, CMD_CHANGE_COMPANY_SETTING, NULL, NULL, _local_company); + } +} +#endif /* ENABLE_NETWORK */ + +/** + * Get the index in the _company_settings array of a setting + * @param name The name of the setting + * @return The index in the _company_settings array + */ +uint GetCompanySettingIndex(const char *name) +{ + uint i; + const SettingDesc *sd = GetSettingFromName(name, &i); + assert(sd != NULL && (sd->desc.flags & SGF_PER_COMPANY) != 0); + return i; +} + +/** + * Set a setting value with a string. + * @param index the settings index. + * @param value the value to write + * @param force_newgame force the newgame settings + * @note Strings WILL NOT be synced over the network + */ +bool SetSettingValue(uint index, const char *value, bool force_newgame) +{ + const SettingDesc *sd = &_settings[index]; + assert(sd->save.conv & SLF_NO_NETWORK_SYNC); + + if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ) { + char **var = (char**)GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); + free(*var); + *var = strcmp(value, "(null)") == 0 ? NULL : strdup(value); + } else { + char *var = (char*)GetVariableAddress(NULL, &sd->save); + ttd_strlcpy(var, value, sd->save.length); + } + if (sd->desc.proc != NULL) sd->desc.proc(0); + + return true; +} + +/** + * Given a name of setting, return a setting description of it. + * @param name Name of the setting to return a setting description of + * @param i Pointer to an integer that will contain the index of the setting after the call, if it is successful. + * @return Pointer to the setting description of setting \a name if it can be found, + * \c NULL indicates failure to obtain the description + */ +const SettingDesc *GetSettingFromName(const char *name, uint *i) +{ + const SettingDesc *sd; + + /* First check all full names */ + for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) { + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; + if (strcmp(sd->desc.name, name) == 0) return sd; + } + + /* Then check the shortcut variant of the name. */ + for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) { + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; + const char *short_name = strchr(sd->desc.name, '.'); + if (short_name != NULL) { + short_name++; + if (strcmp(short_name, name) == 0) return sd; + } + } + + if (strncmp(name, "company.", 8) == 0) name += 8; + /* And finally the company-based settings */ + for (*i = 0, sd = _company_settings; sd->save.cmd != SL_END; sd++, (*i)++) { + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; + if (strcmp(sd->desc.name, name) == 0) return sd; + } + + return NULL; +} + +/* Those 2 functions need to be here, else we have to make some stuff non-static + * and besides, it is also better to keep stuff like this at the same place */ +void IConsoleSetSetting(const char *name, const char *value, bool force_newgame) +{ + uint index; + const SettingDesc *sd = GetSettingFromName(name, &index); + + if (sd == NULL) { + IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name); + return; + } + + bool success; + if (sd->desc.cmd == SDT_STRING) { + success = SetSettingValue(index, value, force_newgame); + } else { + uint32 val; + extern bool GetArgumentInteger(uint32 *value, const char *arg); + success = GetArgumentInteger(&val, value); + if (!success) { + IConsolePrintF(CC_ERROR, "'%s' is not an integer.", value); + return; + } + + success = SetSettingValue(index, val, force_newgame); + } + + if (!success) { + if (_network_server) { + IConsoleError("This command/variable is not available during network games."); + } else { + IConsoleError("This command/variable is only available to a network server."); + } + } +} + +void IConsoleSetSetting(const char *name, int value) +{ + uint index; + const SettingDesc *sd = GetSettingFromName(name, &index); + assert(sd != NULL); + SetSettingValue(index, value); +} + +/** + * Output value of a specific setting to the console + * @param name Name of the setting to output its value + * @param force_newgame force the newgame settings + */ +void IConsoleGetSetting(const char *name, bool force_newgame) +{ + char value[20]; + uint index; + const SettingDesc *sd = GetSettingFromName(name, &index); + const void *ptr; + + if (sd == NULL) { + IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name); + return; + } + + ptr = GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); + + if (sd->desc.cmd == SDT_STRING) { + IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s'", name, (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ) ? *(const char * const *)ptr : (const char *)ptr); + } else { + if (sd->desc.cmd == SDT_BOOLX) { + snprintf(value, sizeof(value), (*(const bool*)ptr != 0) ? "on" : "off"); + } else { + snprintf(value, sizeof(value), sd->desc.min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd->save.conv)); + } + + IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s' (min: %s%d, max: %u)", + name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max); + } +} + +/** + * List all settings and their value to the console + * + * @param prefilter If not \c NULL, only list settings with names that begin with \a prefilter prefix + */ +void IConsoleListSettings(const char *prefilter) +{ + IConsolePrintF(CC_WARNING, "All settings with their current value:"); + + for (const SettingDesc *sd = _settings; sd->save.cmd != SL_END; sd++) { + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; + if (prefilter != NULL && strstr(sd->desc.name, prefilter) == NULL) continue; + char value[80]; + const void *ptr = GetVariableAddress(&GetGameSettings(), &sd->save); + + if (sd->desc.cmd == SDT_BOOLX) { + snprintf(value, lengthof(value), (*(const bool *)ptr != 0) ? "on" : "off"); + } else if (sd->desc.cmd == SDT_STRING) { + snprintf(value, sizeof(value), "%s", (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ) ? *(const char * const *)ptr : (const char *)ptr); + } else { + snprintf(value, lengthof(value), sd->desc.min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd->save.conv)); + } + IConsolePrintF(CC_DEFAULT, "%s = %s", sd->desc.name, value); + } + + IConsolePrintF(CC_WARNING, "Use 'setting' command to change a value"); +} + +/** + * Save and load handler for settings + * @param osd SettingDesc struct containing all information + * @param object can be either NULL in which case we load global variables or + * a pointer to a struct which is getting saved + */ +static void LoadSettings(const SettingDesc *osd, void *object) +{ + for (; osd->save.cmd != SL_END; osd++) { + const SaveLoad *sld = &osd->save; + void *ptr = GetVariableAddress(object, sld); + + if (!SlObjectMember(ptr, sld)) continue; + if (IsNumericType(sld->conv)) Write_ValidateSetting(ptr, osd, ReadValue(ptr, sld->conv)); + } +} + +/** + * Save and load handler for settings + * @param sd SettingDesc struct containing all information + * @param object can be either NULL in which case we load global variables or + * a pointer to a struct which is getting saved + */ +static void SaveSettings(const SettingDesc *sd, void *object) +{ + /* We need to write the CH_RIFF header, but unfortunately can't call + * SlCalcLength() because we have a different format. So do this manually */ + const SettingDesc *i; + size_t length = 0; + for (i = sd; i->save.cmd != SL_END; i++) { + length += SlCalcObjMemberLength(object, &i->save); + } + SlSetLength(length); + + for (i = sd; i->save.cmd != SL_END; i++) { + void *ptr = GetVariableAddress(object, &i->save); + SlObjectMember(ptr, &i->save); + } +} + +static void Load_OPTS() +{ + /* Copy over default setting since some might not get loaded in + * a networking environment. This ensures for example that the local + * autosave-frequency stays when joining a network-server */ + PrepareOldDiffCustom(); + LoadSettings(_gameopt_settings, &_settings_game); + HandleOldDiffCustom(true); +} + +static void Load_PATS() +{ + /* Copy over default setting since some might not get loaded in + * a networking environment. This ensures for example that the local + * currency setting stays when joining a network-server */ + LoadSettings(_settings, &_settings_game); +} + +static void Check_PATS() +{ + LoadSettings(_settings, &_load_check_data.settings); +} + +static void Save_PATS() +{ + SaveSettings(_settings, &_settings_game); +} + +void CheckConfig() +{ + /* + * Increase old default values for pf_maxdepth and pf_maxlength + * to support big networks. + */ + if (_settings_newgame.pf.opf.pf_maxdepth == 16 && _settings_newgame.pf.opf.pf_maxlength == 512) { + _settings_newgame.pf.opf.pf_maxdepth = 48; + _settings_newgame.pf.opf.pf_maxlength = 4096; + } +} + +extern const ChunkHandler _setting_chunk_handlers[] = { + { 'OPTS', NULL, Load_OPTS, NULL, NULL, CH_RIFF}, + { 'PATS', Save_PATS, Load_PATS, NULL, Check_PATS, CH_RIFF | CH_LAST}, +}; + +static bool IsSignedVarMemType(VarType vt) +{ + switch (GetVarMemType(vt)) { + case SLE_VAR_I8: + case SLE_VAR_I16: + case SLE_VAR_I32: + case SLE_VAR_I64: + return true; + } + return false; +} diff --git a/src/settings.cpp.rej b/src/settings.cpp.rej new file mode 100644 index 0000000000..9b84f848c1 --- /dev/null +++ b/src/settings.cpp.rej @@ -0,0 +1,11 @@ +--- src/settings.cpp ++++ src/settings.cpp +@@ -1092,7 +1092,7 @@ + + static bool TouchscreenModeChanged(int32 p1) + { +- //ResetTabletWindow(); ++ ResetTabletWindow(); + return true; + } + diff --git a/src/settings_gui.cpp.orig b/src/settings_gui.cpp.orig new file mode 100644 index 0000000000..755b829ff9 --- /dev/null +++ b/src/settings_gui.cpp.orig @@ -0,0 +1,2651 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file settings_gui.cpp GUI for settings. */ + +#include "stdafx.h" +#include "currency.h" +#include "error.h" +#include "settings_gui.h" +#include "textbuf_gui.h" +#include "command_func.h" +#include "screenshot.h" +#include "network/network.h" +#include "town.h" +#include "settings_internal.h" +#include "newgrf_townname.h" +#include "strings_func.h" +#include "window_func.h" +#include "string_func.h" +#include "widgets/dropdown_type.h" +#include "widgets/dropdown_func.h" +#include "highscore.h" +#include "base_media_base.h" +#include "company_base.h" +#include "company_func.h" +#include "viewport_func.h" +#include "core/geometry_func.hpp" +#include "ai/ai.hpp" +#include "blitter/factory.hpp" +#include "language.h" +#include "textfile_gui.h" +#include "stringfilter_type.h" +#include "querystring_gui.h" + + +static const StringID _driveside_dropdown[] = { + STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT, + STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT, + INVALID_STRING_ID +}; + +static const StringID _autosave_dropdown[] = { + STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF, + STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH, + STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS, + STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS, + STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS, + INVALID_STRING_ID, +}; + +int _nb_orig_names = SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1; ///< Number of original town names. +static StringID *_grf_names = NULL; ///< Pointer to town names defined by NewGRFs. +static int _nb_grf_names = 0; ///< Number of town names defined by NewGRFs. + +static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const SettingDesc *sd); + +/** Allocate memory for the NewGRF town names. */ +void InitGRFTownGeneratorNames() +{ + free(_grf_names); + _grf_names = GetGRFTownNameList(); + _nb_grf_names = 0; + for (StringID *s = _grf_names; *s != INVALID_STRING_ID; s++) _nb_grf_names++; +} + +/** + * Get a town name. + * @param town_name Number of the wanted town name. + * @return Name of the town as string ID. + */ +static inline StringID TownName(int town_name) +{ + if (town_name < _nb_orig_names) return STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH + town_name; + town_name -= _nb_orig_names; + if (town_name < _nb_grf_names) return _grf_names[town_name]; + return STR_UNDEFINED; +} + +/** + * Get index of the current screen resolution. + * @return Index of the current screen resolution if it is a known resolution, #_num_resolutions otherwise. + */ +static int GetCurRes() +{ + int i; + + for (i = 0; i != _num_resolutions; i++) { + if ((int)_resolutions[i].width == _screen.width && + (int)_resolutions[i].height == _screen.height) { + break; + } + } + return i; +} + +static void ShowCustCurrency(); + +template +static DropDownList *BuiltSetDropDownList(int *selected_index) +{ + int n = T::GetNumSets(); + *selected_index = T::GetIndexOfUsedSet(); + + DropDownList *list = new DropDownList(); + for (int i = 0; i < n; i++) { + *list->Append() = new DropDownListCharStringItem(T::GetSet(i)->name, i, (_game_mode == GM_MENU) ? false : (*selected_index != i)); + } + + return list; +} + +/** Window for displaying the textfile of a BaseSet. */ +template +struct BaseSetTextfileWindow : public TextfileWindow { + const TBaseSet* baseset; ///< View the textfile of this BaseSet. + StringID content_type; ///< STR_CONTENT_TYPE_xxx for title. + + BaseSetTextfileWindow(TextfileType file_type, const TBaseSet* baseset, StringID content_type) : TextfileWindow(file_type), baseset(baseset), content_type(content_type) + { + const char *textfile = this->baseset->GetTextfile(file_type); + this->LoadTextfile(textfile, BASESET_DIR); + } + + /* virtual */ void SetStringParameters(int widget) const + { + if (widget == WID_TF_CAPTION) { + SetDParam(0, content_type); + SetDParamStr(1, this->baseset->name); + } + } +}; + +/** + * Open the BaseSet version of the textfile window. + * @param file_type The type of textfile to display. + * @param baseset The BaseSet to use. + * @param content_type STR_CONTENT_TYPE_xxx for title. + */ +template +void ShowBaseSetTextfileWindow(TextfileType file_type, const TBaseSet* baseset, StringID content_type) +{ + DeleteWindowByClass(WC_TEXTFILE); + new BaseSetTextfileWindow(file_type, baseset, content_type); +} + +struct GameOptionsWindow : Window { + GameSettings *opt; + bool reload; + + GameOptionsWindow(WindowDesc *desc) : Window(desc) + { + this->opt = &GetGameSettings(); + this->reload = false; + + this->InitNested(WN_GAME_OPTIONS_GAME_OPTIONS); + this->OnInvalidateData(0); + } + + ~GameOptionsWindow() + { + DeleteWindowById(WC_CUSTOM_CURRENCY, 0); + if (this->reload) _switch_mode = SM_MENU; + } + + /** + * Build the dropdown list for a specific widget. + * @param widget Widget to build list for + * @param selected_index Currently selected item + * @return the built dropdown list, or NULL if the widget has no dropdown menu. + */ + DropDownList *BuildDropDownList(int widget, int *selected_index) const + { + DropDownList *list = NULL; + switch (widget) { + case WID_GO_CURRENCY_DROPDOWN: { // Setup currencies dropdown + list = new DropDownList(); + *selected_index = this->opt->locale.currency; + StringID *items = BuildCurrencyDropdown(); + uint64 disabled = _game_mode == GM_MENU ? 0LL : ~GetMaskOfAllowedCurrencies(); + + /* Add non-custom currencies; sorted naturally */ + for (uint i = 0; i < CURRENCY_END; items++, i++) { + if (i == CURRENCY_CUSTOM) continue; + *list->Append() = new DropDownListStringItem(*items, i, HasBit(disabled, i)); + } + QSortT(list->Begin(), list->Length(), DropDownListStringItem::NatSortFunc); + + /* Append custom currency at the end */ + *list->Append() = new DropDownListItem(-1, false); // separator line + *list->Append() = new DropDownListStringItem(STR_GAME_OPTIONS_CURRENCY_CUSTOM, CURRENCY_CUSTOM, HasBit(disabled, CURRENCY_CUSTOM)); + break; + } + + case WID_GO_ROADSIDE_DROPDOWN: { // Setup road-side dropdown + list = new DropDownList(); + *selected_index = this->opt->vehicle.road_side; + const StringID *items = _driveside_dropdown; + uint disabled = 0; + + /* You can only change the drive side if you are in the menu or ingame with + * no vehicles present. In a networking game only the server can change it */ + extern bool RoadVehiclesAreBuilt(); + if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server)) { + disabled = ~(1 << this->opt->vehicle.road_side); // disable the other value + } + + for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) { + *list->Append() = new DropDownListStringItem(*items, i, HasBit(disabled, i)); + } + break; + } + + case WID_GO_TOWNNAME_DROPDOWN: { // Setup townname dropdown + list = new DropDownList(); + *selected_index = this->opt->game_creation.town_name; + + int enabled_item = (_game_mode == GM_MENU || Town::GetNumItems() == 0) ? -1 : *selected_index; + + /* Add and sort newgrf townnames generators */ + for (int i = 0; i < _nb_grf_names; i++) { + int result = _nb_orig_names + i; + *list->Append() = new DropDownListStringItem(_grf_names[i], result, enabled_item != result && enabled_item >= 0); + } + QSortT(list->Begin(), list->Length(), DropDownListStringItem::NatSortFunc); + + int newgrf_size = list->Length(); + /* Insert newgrf_names at the top of the list */ + if (newgrf_size > 0) { + *list->Append() = new DropDownListItem(-1, false); // separator line + newgrf_size++; + } + + /* Add and sort original townnames generators */ + for (int i = 0; i < _nb_orig_names; i++) { + *list->Append() = new DropDownListStringItem(STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH + i, i, enabled_item != i && enabled_item >= 0); + } + QSortT(list->Begin() + newgrf_size, list->Length() - newgrf_size, DropDownListStringItem::NatSortFunc); + break; + } + + case WID_GO_AUTOSAVE_DROPDOWN: { // Setup autosave dropdown + list = new DropDownList(); + *selected_index = _settings_client.gui.autosave; + const StringID *items = _autosave_dropdown; + for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) { + *list->Append() = new DropDownListStringItem(*items, i, false); + } + break; + } + + case WID_GO_LANG_DROPDOWN: { // Setup interface language dropdown + list = new DropDownList(); + for (uint i = 0; i < _languages.Length(); i++) { + if (&_languages[i] == _current_language) *selected_index = i; + *list->Append() = new DropDownListStringItem(SPECSTR_LANGUAGE_START + i, i, false); + } + QSortT(list->Begin(), list->Length(), DropDownListStringItem::NatSortFunc); + break; + } + + case WID_GO_RESOLUTION_DROPDOWN: // Setup resolution dropdown + list = new DropDownList(); + *selected_index = GetCurRes(); + for (int i = 0; i < _num_resolutions; i++) { + *list->Append() = new DropDownListStringItem(SPECSTR_RESOLUTION_START + i, i, false); + } + break; + + case WID_GO_SCREENSHOT_DROPDOWN: // Setup screenshot format dropdown + list = new DropDownList(); + *selected_index = _cur_screenshot_format; + for (uint i = 0; i < _num_screenshot_formats; i++) { + if (!GetScreenshotFormatSupports_32bpp(i) && BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 32) continue; + *list->Append() = new DropDownListStringItem(SPECSTR_SCREENSHOT_START + i, i, false); + } + break; + + case WID_GO_BASE_GRF_DROPDOWN: + list = BuiltSetDropDownList(selected_index); + break; + + case WID_GO_BASE_SFX_DROPDOWN: + list = BuiltSetDropDownList(selected_index); + break; + + case WID_GO_BASE_MUSIC_DROPDOWN: + list = BuiltSetDropDownList(selected_index); + break; + + default: + return NULL; + } + + return list; + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_GO_CURRENCY_DROPDOWN: SetDParam(0, _currency_specs[this->opt->locale.currency].name); break; + case WID_GO_ROADSIDE_DROPDOWN: SetDParam(0, STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT + this->opt->vehicle.road_side); break; + case WID_GO_TOWNNAME_DROPDOWN: SetDParam(0, TownName(this->opt->game_creation.town_name)); break; + case WID_GO_AUTOSAVE_DROPDOWN: SetDParam(0, _autosave_dropdown[_settings_client.gui.autosave]); break; + case WID_GO_LANG_DROPDOWN: SetDParamStr(0, _current_language->own_name); break; + case WID_GO_RESOLUTION_DROPDOWN: SetDParam(0, GetCurRes() == _num_resolutions ? STR_GAME_OPTIONS_RESOLUTION_OTHER : SPECSTR_RESOLUTION_START + GetCurRes()); break; + case WID_GO_SCREENSHOT_DROPDOWN: SetDParam(0, SPECSTR_SCREENSHOT_START + _cur_screenshot_format); break; + case WID_GO_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->name); break; + case WID_GO_BASE_GRF_STATUS: SetDParam(0, BaseGraphics::GetUsedSet()->GetNumInvalid()); break; + case WID_GO_BASE_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->name); break; + case WID_GO_BASE_MUSIC_DROPDOWN: SetDParamStr(0, BaseMusic::GetUsedSet()->name); break; + case WID_GO_BASE_MUSIC_STATUS: SetDParam(0, BaseMusic::GetUsedSet()->GetNumInvalid()); break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_GO_BASE_GRF_DESCRIPTION: + SetDParamStr(0, BaseGraphics::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); + DrawString(r.left, r.right, r.top, STR_BLACK_RAW_STRING); + break; + + case WID_GO_BASE_SFX_DESCRIPTION: + SetDParamStr(0, BaseSounds::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); + DrawString(r.left, r.right, r.top, STR_BLACK_RAW_STRING); + break; + + case WID_GO_BASE_MUSIC_DESCRIPTION: + SetDParamStr(0, BaseMusic::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); + DrawString(r.left, r.right, r.top, STR_BLACK_RAW_STRING); + break; + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_GO_BASE_GRF_DESCRIPTION: + /* Find the biggest description for the default size. */ + for (int i = 0; i < BaseGraphics::GetNumSets(); i++) { + SetDParamStr(0, "123"); + size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); + } + break; + + case WID_GO_BASE_GRF_STATUS: + /* Find the biggest description for the default size. */ + for (int i = 0; i < BaseGraphics::GetNumSets(); i++) { + uint invalid_files = BaseGraphics::GetSet(i)->GetNumInvalid(); + if (invalid_files == 0) continue; + + SetDParam(0, invalid_files); + *size = maxdim(*size, GetStringBoundingBox(STR_GAME_OPTIONS_BASE_GRF_STATUS)); + } + break; + + case WID_GO_BASE_SFX_DESCRIPTION: + /* Find the biggest description for the default size. */ + for (int i = 0; i < BaseSounds::GetNumSets(); i++) { + SetDParamStr(0, "123"); + size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); + } + break; + + case WID_GO_BASE_MUSIC_DESCRIPTION: + /* Find the biggest description for the default size. */ + for (int i = 0; i < BaseMusic::GetNumSets(); i++) { + SetDParamStr(0, "123"); + size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); + } + break; + + case WID_GO_BASE_MUSIC_STATUS: + /* Find the biggest description for the default size. */ + for (int i = 0; i < BaseMusic::GetNumSets(); i++) { + uint invalid_files = BaseMusic::GetSet(i)->GetNumInvalid(); + if (invalid_files == 0) continue; + + SetDParam(0, invalid_files); + *size = maxdim(*size, GetStringBoundingBox(STR_GAME_OPTIONS_BASE_MUSIC_STATUS)); + } + break; + + default: { + int selected; + DropDownList *list = this->BuildDropDownList(widget, &selected); + if (list != NULL) { + /* Find the biggest item for the default size. */ + for (const DropDownListItem * const *it = list->Begin(); it != list->End(); it++) { + Dimension string_dim; + int width = (*it)->Width(); + string_dim.width = width + padding.width; + string_dim.height = (*it)->Height(width) + padding.height; + *size = maxdim(*size, string_dim); + } + delete list; + } + } + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + if (widget >= WID_GO_BASE_GRF_TEXTFILE && widget < WID_GO_BASE_GRF_TEXTFILE + TFT_END) { + if (BaseGraphics::GetUsedSet() == NULL) return; + + ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_GRF_TEXTFILE), BaseGraphics::GetUsedSet(), STR_CONTENT_TYPE_BASE_GRAPHICS); + return; + } + if (widget >= WID_GO_BASE_SFX_TEXTFILE && widget < WID_GO_BASE_SFX_TEXTFILE + TFT_END) { + if (BaseSounds::GetUsedSet() == NULL) return; + + ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_SFX_TEXTFILE), BaseSounds::GetUsedSet(), STR_CONTENT_TYPE_BASE_SOUNDS); + return; + } + if (widget >= WID_GO_BASE_MUSIC_TEXTFILE && widget < WID_GO_BASE_MUSIC_TEXTFILE + TFT_END) { + if (BaseMusic::GetUsedSet() == NULL) return; + + ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_MUSIC_TEXTFILE), BaseMusic::GetUsedSet(), STR_CONTENT_TYPE_BASE_MUSIC); + return; + } + switch (widget) { + case WID_GO_FULLSCREEN_BUTTON: // Click fullscreen on/off + /* try to toggle full-screen on/off */ + if (!ToggleFullScreen(!_fullscreen)) { + ShowErrorMessage(STR_ERROR_FULLSCREEN_FAILED, INVALID_STRING_ID, WL_ERROR); + } + this->SetWidgetLoweredState(WID_GO_FULLSCREEN_BUTTON, _fullscreen); + this->SetDirty(); + break; + + default: { + int selected; + DropDownList *list = this->BuildDropDownList(widget, &selected); + if (list != NULL) { + ShowDropDownList(this, list, selected, widget); + } + break; + } + } + } + + /** + * Set the base media set. + * @param index the index of the media set + * @tparam T class of media set + */ + template + void SetMediaSet(int index) + { + if (_game_mode == GM_MENU) { + const char *name = T::GetSet(index)->name; + + free(T::ini_set); + T::ini_set = strdup(name); + + T::SetSet(name); + this->reload = true; + this->InvalidateData(); + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + switch (widget) { + case WID_GO_CURRENCY_DROPDOWN: // Currency + if (index == CURRENCY_CUSTOM) ShowCustCurrency(); + this->opt->locale.currency = index; + ReInitAllWindows(); + break; + + case WID_GO_ROADSIDE_DROPDOWN: // Road side + if (this->opt->vehicle.road_side != index) { // only change if setting changed + uint i; + if (GetSettingFromName("vehicle.road_side", &i) == NULL) NOT_REACHED(); + SetSettingValue(i, index); + MarkWholeScreenDirty(); + } + break; + + case WID_GO_TOWNNAME_DROPDOWN: // Town names + if (_game_mode == GM_MENU || Town::GetNumItems() == 0) { + this->opt->game_creation.town_name = index; + SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_OPTIONS); + } + break; + + case WID_GO_AUTOSAVE_DROPDOWN: // Autosave options + _settings_client.gui.autosave = index; + this->SetDirty(); + break; + + case WID_GO_LANG_DROPDOWN: // Change interface language + ReadLanguagePack(&_languages[index]); + DeleteWindowByClass(WC_QUERY_STRING); + CheckForMissingGlyphs(); + UpdateAllVirtCoords(); + ReInitAllWindows(); + break; + + case WID_GO_RESOLUTION_DROPDOWN: // Change resolution + if (index < _num_resolutions && ChangeResInGame(_resolutions[index].width, _resolutions[index].height)) { + this->SetDirty(); + } + break; + + case WID_GO_SCREENSHOT_DROPDOWN: // Change screenshot format + SetScreenshotFormat(index); + this->SetDirty(); + break; + + case WID_GO_BASE_GRF_DROPDOWN: + this->SetMediaSet(index); + break; + + case WID_GO_BASE_SFX_DROPDOWN: + this->SetMediaSet(index); + break; + + case WID_GO_BASE_MUSIC_DROPDOWN: + this->SetMediaSet(index); + break; + } + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. @see GameOptionsInvalidationData + * @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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + this->SetWidgetLoweredState(WID_GO_FULLSCREEN_BUTTON, _fullscreen); + + bool missing_files = BaseGraphics::GetUsedSet()->GetNumMissing() == 0; + this->GetWidget(WID_GO_BASE_GRF_STATUS)->SetDataTip(missing_files ? STR_EMPTY : STR_GAME_OPTIONS_BASE_GRF_STATUS, STR_NULL); + + for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { + this->SetWidgetDisabledState(WID_GO_BASE_GRF_TEXTFILE + tft, BaseGraphics::GetUsedSet() == NULL || BaseGraphics::GetUsedSet()->GetTextfile(tft) == NULL); + this->SetWidgetDisabledState(WID_GO_BASE_SFX_TEXTFILE + tft, BaseSounds::GetUsedSet() == NULL || BaseSounds::GetUsedSet()->GetTextfile(tft) == NULL); + this->SetWidgetDisabledState(WID_GO_BASE_MUSIC_TEXTFILE + tft, BaseMusic::GetUsedSet() == NULL || BaseMusic::GetUsedSet()->GetTextfile(tft) == NULL); + } + + missing_files = BaseMusic::GetUsedSet()->GetNumInvalid() == 0; + this->GetWidget(WID_GO_BASE_MUSIC_STATUS)->SetDataTip(missing_files ? STR_EMPTY : STR_GAME_OPTIONS_BASE_MUSIC_STATUS, STR_NULL); + } +}; + +static const NWidgetPart _nested_game_options_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_GO_BACKGROUND), SetPIP(6, 6, 10), + NWidget(NWID_HORIZONTAL), SetPIP(10, 10, 10), + NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_CURRENCY_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP), SetFill(1, 0), + EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_ROADSIDE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP), SetFill(1, 0), + EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_AUTOSAVE_FRAME, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_AUTOSAVE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP), SetFill(1, 0), + EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_RESOLUTION, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_RESOLUTION_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_RESOLUTION_TOOLTIP), SetFill(1, 0), SetPadding(0, 0, 3, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_FULLSCREEN, STR_NULL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_FULLSCREEN_BUTTON), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP), + EndContainer(), + EndContainer(), + EndContainer(), + + NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_TOWN_NAMES_FRAME, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_TOWNNAME_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP), SetFill(1, 0), + EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_LANGUAGE, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_LANG_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_LANGUAGE_TOOLTIP), SetFill(1, 0), + EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_SCREENSHOT_FORMAT, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_SCREENSHOT_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_SCREENSHOT_FORMAT_TOOLTIP), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 0), SetFill(0, 1), + EndContainer(), + EndContainer(), + + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_GRF, STR_NULL), SetPadding(0, 10, 0, 10), + NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_GRF_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_GRF_TOOLTIP), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + EndContainer(), + + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_SFX, STR_NULL), SetPadding(0, 10, 0, 10), + NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_SFX_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_SFX_TOOLTIP), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_SFX_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + EndContainer(), + + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_MUSIC, STR_NULL), SetPadding(0, 10, 0, 10), + NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_MUSIC_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + EndContainer(), + EndContainer(), +}; + +static WindowDesc _game_options_desc( + WDP_CENTER, "settings_game", 0, 0, + WC_GAME_OPTIONS, WC_NONE, + 0, + _nested_game_options_widgets, lengthof(_nested_game_options_widgets) +); + +/** Open the game options window. */ +void ShowGameOptions() +{ + DeleteWindowByClass(WC_GAME_OPTIONS); + new GameOptionsWindow(&_game_options_desc); +} + +static int SETTING_HEIGHT = 11; ///< Height of a single setting in the tree view in pixels +static const int LEVEL_WIDTH = 15; ///< Indenting width of a sub-page in pixels + +/** + * Flags for #SettingEntry + * @note The #SEF_BUTTONS_MASK matches expectations of the formal parameter 'state' of #DrawArrowButtons + */ +enum SettingEntryFlags { + SEF_LEFT_DEPRESSED = 0x01, ///< Of a numeric setting entry, the left button is depressed + SEF_RIGHT_DEPRESSED = 0x02, ///< Of a numeric setting entry, the right button is depressed + SEF_BUTTONS_MASK = (SEF_LEFT_DEPRESSED | SEF_RIGHT_DEPRESSED), ///< Bit-mask for button flags + + SEF_LAST_FIELD = 0x04, ///< This entry is the last one in a (sub-)page + SEF_FILTERED = 0x08, ///< Entry is hidden by the string filter + + /* Entry kind */ + SEF_SETTING_KIND = 0x10, ///< Entry kind: Entry is a setting + SEF_SUBTREE_KIND = 0x20, ///< Entry kind: Entry is a sub-tree + SEF_KIND_MASK = (SEF_SETTING_KIND | SEF_SUBTREE_KIND), ///< Bit-mask for fetching entry kind +}; + +struct SettingsPage; // Forward declaration + +/** Data fields for a sub-page (#SEF_SUBTREE_KIND kind)*/ +struct SettingEntrySubtree { + SettingsPage *page; ///< Pointer to the sub-page + bool folded; ///< Sub-page is folded (not visible except for its title) + StringID title; ///< Title of the sub-page +}; + +/** Data fields for a single setting (#SEF_SETTING_KIND kind) */ +struct SettingEntrySetting { + const char *name; ///< Name of the setting + const SettingDesc *setting; ///< Setting description of the setting + uint index; ///< Index of the setting in the settings table +}; + +/** How the list of advanced settings is filtered. */ +enum RestrictionMode { + RM_BASIC, ///< Display settings associated to the "basic" list. + RM_ADVANCED, ///< Display settings associated to the "advanced" list. + RM_ALL, ///< List all settings regardless of the default/newgame/... values. + RM_CHANGED_AGAINST_DEFAULT, ///< Show only settings which are different compared to default values. + RM_CHANGED_AGAINST_NEW, ///< Show only settings which are different compared to the user's new game setting values. + RM_END, ///< End for iteration. +}; +DECLARE_POSTFIX_INCREMENT(RestrictionMode) + +/** Filter for settings list. */ +struct SettingFilter { + StringFilter string; ///< Filter string. + RestrictionMode min_cat; ///< Minimum category needed to display all filtered strings (#RM_BASIC, #RM_ADVANCED, or #RM_ALL). + bool type_hides; ///< Whether the type hides filtered strings. + RestrictionMode mode; ///< Filter based on category. + SettingType type; ///< Filter based on type. +}; + +/** Data structure describing a single setting in a tab */ +struct SettingEntry { + byte flags; ///< Flags of the setting entry. @see SettingEntryFlags + byte level; ///< Nesting level of this setting entry + union { + SettingEntrySetting entry; ///< Data fields if entry is a setting + SettingEntrySubtree sub; ///< Data fields if entry is a sub-page + } d; ///< Data fields for each kind + + SettingEntry(const char *nm); + SettingEntry(SettingsPage *sub, StringID title); + + void Init(byte level); + void FoldAll(); + void UnFoldAll(); + void SetButtons(byte new_val); + + /** + * Set whether this is the last visible entry of the parent node. + * @param last_field Value to set + */ + void SetLastField(bool last_field) { if (last_field) SETBITS(this->flags, SEF_LAST_FIELD); else CLRBITS(this->flags, SEF_LAST_FIELD); } + + uint Length() const; + void GetFoldingState(bool &all_folded, bool &all_unfolded) const; + bool IsVisible(const SettingEntry *item) const; + SettingEntry *FindEntry(uint row, uint *cur_row); + uint GetMaxHelpHeight(int maxw); + + bool IsFiltered() const; + bool UpdateFilterState(SettingFilter &filter, bool force_visible); + + uint Draw(GameSettings *settings_ptr, int base_x, int base_y, int max_x, uint first_row, uint max_row, uint cur_row, uint parent_last, SettingEntry *selected); + + /** + * Get the help text of a single setting. + * @return The requested help text. + */ + inline StringID GetHelpText() + { + assert((this->flags & SEF_KIND_MASK) == SEF_SETTING_KIND); + return this->d.entry.setting->desc.str_help; + } + + void SetValueDParams(uint first_param, int32 value); + +private: + void DrawSetting(GameSettings *settings_ptr, int x, int y, int max_x, int state, bool highlight); + bool IsVisibleByRestrictionMode(RestrictionMode mode) const; +}; + +/** Data structure describing one page of settings in the settings window. */ +struct SettingsPage { + SettingEntry *entries; ///< Array of setting entries of the page. + byte num; ///< Number of entries on the page (statically filled). + + void Init(byte level = 0); + void FoldAll(); + void UnFoldAll(); + + uint Length() const; + void GetFoldingState(bool &all_folded, bool &all_unfolded) const; + bool IsVisible(const SettingEntry *item) const; + SettingEntry *FindEntry(uint row, uint *cur_row) const; + uint GetMaxHelpHeight(int maxw); + + bool UpdateFilterState(SettingFilter &filter, bool force_visible); + + uint Draw(GameSettings *settings_ptr, int base_x, int base_y, int max_x, uint first_row, uint max_row, SettingEntry *selected, uint cur_row = 0, uint parent_last = 0) const; +}; + + +/* == SettingEntry methods == */ + +/** + * Constructor for a single setting in the 'advanced settings' window + * @param nm Name of the setting in the setting table + */ +SettingEntry::SettingEntry(const char *nm) +{ + this->flags = SEF_SETTING_KIND; + this->level = 0; + this->d.entry.name = nm; + this->d.entry.setting = NULL; + this->d.entry.index = 0; +} + +/** + * Constructor for a sub-page in the 'advanced settings' window + * @param sub Sub-page + * @param title Title of the sub-page + */ +SettingEntry::SettingEntry(SettingsPage *sub, StringID title) +{ + this->flags = SEF_SUBTREE_KIND; + this->level = 0; + this->d.sub.page = sub; + this->d.sub.folded = true; + this->d.sub.title = title; +} + +/** + * Initialization of a setting entry + * @param level Page nesting level of this entry + */ +void SettingEntry::Init(byte level) +{ + this->level = level; + + switch (this->flags & SEF_KIND_MASK) { + case SEF_SETTING_KIND: + this->d.entry.setting = GetSettingFromName(this->d.entry.name, &this->d.entry.index); + assert(this->d.entry.setting != NULL); + break; + case SEF_SUBTREE_KIND: + this->d.sub.page->Init(level + 1); + break; + default: NOT_REACHED(); + } +} + +/** Recursively close all (filtered) folds of sub-pages */ +void SettingEntry::FoldAll() +{ + if (this->IsFiltered()) return; + switch (this->flags & SEF_KIND_MASK) { + case SEF_SETTING_KIND: + break; + + case SEF_SUBTREE_KIND: + this->d.sub.folded = true; + this->d.sub.page->FoldAll(); + break; + + default: NOT_REACHED(); + } +} + +/** Recursively open all (filtered) folds of sub-pages */ +void SettingEntry::UnFoldAll() +{ + if (this->IsFiltered()) return; + switch (this->flags & SEF_KIND_MASK) { + case SEF_SETTING_KIND: + break; + + case SEF_SUBTREE_KIND: + this->d.sub.folded = false; + this->d.sub.page->UnFoldAll(); + break; + + default: NOT_REACHED(); + } +} + +/** + * Recursively accumulate the folding state of the (filtered) tree. + * @param[in,out] all_folded Set to false, if one entry is not folded. + * @param[in,out] all_unfolded Set to false, if one entry is folded. + */ +void SettingEntry::GetFoldingState(bool &all_folded, bool &all_unfolded) const +{ + if (this->IsFiltered()) return; + switch (this->flags & SEF_KIND_MASK) { + case SEF_SETTING_KIND: + break; + + case SEF_SUBTREE_KIND: + if (this->d.sub.folded) { + all_unfolded = false; + } else { + all_folded = false; + } + this->d.sub.page->GetFoldingState(all_folded, all_unfolded); + break; + + default: NOT_REACHED(); + } +} + +/** + * Check whether an entry is visible and not folded or filtered away. + * Note: This does not consider the scrolling range; it might still require scrolling to make the setting really visible. + * @param item Entry to search for. + * @return true if entry is visible. + */ +bool SettingEntry::IsVisible(const SettingEntry *item) const +{ + if (this->IsFiltered()) return false; + if (this == item) return true; + + switch (this->flags & SEF_KIND_MASK) { + case SEF_SETTING_KIND: + return false; + + case SEF_SUBTREE_KIND: + return !this->d.sub.folded && this->d.sub.page->IsVisible(item); + + default: NOT_REACHED(); + } +} + +/** + * Set the button-depressed flags (#SEF_LEFT_DEPRESSED and #SEF_RIGHT_DEPRESSED) to a specified value + * @param new_val New value for the button flags + * @see SettingEntryFlags + */ +void SettingEntry::SetButtons(byte new_val) +{ + assert((new_val & ~SEF_BUTTONS_MASK) == 0); // Should not touch any flags outside the buttons + this->flags = (this->flags & ~SEF_BUTTONS_MASK) | new_val; +} + +/** Return numbers of rows needed to display the (filtered) entry */ +uint SettingEntry::Length() const +{ + if (this->IsFiltered()) return 0; + switch (this->flags & SEF_KIND_MASK) { + case SEF_SETTING_KIND: + return 1; + case SEF_SUBTREE_KIND: + if (this->d.sub.folded) return 1; // Only displaying the title + + return 1 + this->d.sub.page->Length(); // 1 extra row for the title + default: NOT_REACHED(); + } +} + +/** + * Find setting entry at row \a row_num + * @param row_num Index of entry to return + * @param cur_row Current row number + * @return The requested setting entry or \c NULL if it not found (folded or filtered) + */ +SettingEntry *SettingEntry::FindEntry(uint row_num, uint *cur_row) +{ + if (this->IsFiltered()) return NULL; + if (row_num == *cur_row) return this; + + switch (this->flags & SEF_KIND_MASK) { + case SEF_SETTING_KIND: + (*cur_row)++; + break; + case SEF_SUBTREE_KIND: + (*cur_row)++; // add one for row containing the title + if (this->d.sub.folded) { + break; + } + + /* sub-page is visible => search it too */ + return this->d.sub.page->FindEntry(row_num, cur_row); + default: NOT_REACHED(); + } + return NULL; +} + +/** + * Get the biggest height of the help text(s), if the width is at least \a maxw. Help text gets wrapped if needed. + * @param maxw Maximal width of a line help text. + * @return Biggest height needed to display any help text of this node (and its descendants). + */ +uint SettingEntry::GetMaxHelpHeight(int maxw) +{ + switch (this->flags & SEF_KIND_MASK) { + case SEF_SETTING_KIND: return GetStringHeight(this->GetHelpText(), maxw); + case SEF_SUBTREE_KIND: return this->d.sub.page->GetMaxHelpHeight(maxw); + default: NOT_REACHED(); + } +} + +/** + * Check whether an entry is hidden due to filters + * @return true if hidden. + */ +bool SettingEntry::IsFiltered() const +{ + return (this->flags & SEF_FILTERED) != 0; +} + +/** + * Checks whether an entry shall be made visible based on the restriction mode. + * @param mode The current status of the restriction drop down box. + * @return true if the entry shall be visible. + */ +bool SettingEntry::IsVisibleByRestrictionMode(RestrictionMode mode) const +{ + /* There shall not be any restriction, i.e. all settings shall be visible. */ + if (mode == RM_ALL) return true; + + GameSettings *settings_ptr = &GetGameSettings(); + assert((this->flags & SEF_KIND_MASK) == SEF_SETTING_KIND); + const SettingDesc *sd = this->d.entry.setting; + + if (mode == RM_BASIC) return (this->d.entry.setting->desc.cat & SC_BASIC_LIST) != 0; + if (mode == RM_ADVANCED) return (this->d.entry.setting->desc.cat & SC_ADVANCED_LIST) != 0; + + /* Read the current value. */ + const void *var = ResolveVariableAddress(settings_ptr, sd); + int64 current_value = ReadValue(var, sd->save.conv); + + int64 filter_value; + + if (mode == RM_CHANGED_AGAINST_DEFAULT) { + /* This entry shall only be visible, if the value deviates from its default value. */ + + /* Read the default value. */ + filter_value = ReadValue(&sd->desc.def, sd->save.conv); + } else { + assert(mode == RM_CHANGED_AGAINST_NEW); + /* This entry shall only be visible, if the value deviates from + * its value is used when starting a new game. */ + + /* Make sure we're not comparing the new game settings against itself. */ + assert(settings_ptr != &_settings_newgame); + + /* Read the new game's value. */ + var = ResolveVariableAddress(&_settings_newgame, sd); + filter_value = ReadValue(var, sd->save.conv); + } + + return current_value != filter_value; +} + +/** + * Update the filter state. + * @param filter Filter + * @param force_visible Whether to force all items visible, no matter what (due to filter text; not affected by restriction drop down box). + * @return true if item remains visible + */ +bool SettingEntry::UpdateFilterState(SettingFilter &filter, bool force_visible) +{ + CLRBITS(this->flags, SEF_FILTERED); + + bool visible = true; + switch (this->flags & SEF_KIND_MASK) { + case SEF_SETTING_KIND: { + const SettingDesc *sd = this->d.entry.setting; + if (!force_visible && !filter.string.IsEmpty()) { + /* Process the search text filter for this item. */ + filter.string.ResetState(); + + const SettingDescBase *sdb = &sd->desc; + + SetDParam(0, STR_EMPTY); + filter.string.AddLine(sdb->str); + filter.string.AddLine(this->GetHelpText()); + + visible = filter.string.GetState(); + } + if (visible) { + if (filter.type != ST_ALL && sd->GetType() != filter.type) { + filter.type_hides = true; + visible = false; + } + if (!this->IsVisibleByRestrictionMode(filter.mode)) { + while (filter.min_cat < RM_ALL && (filter.min_cat == filter.mode || !this->IsVisibleByRestrictionMode(filter.min_cat))) filter.min_cat++; + visible = false; + } + } + break; + } + case SEF_SUBTREE_KIND: { + if (!force_visible && !filter.string.IsEmpty()) { + filter.string.ResetState(); + filter.string.AddLine(this->d.sub.title); + force_visible = filter.string.GetState(); + } + visible = this->d.sub.page->UpdateFilterState(filter, force_visible); + break; + } + default: NOT_REACHED(); + } + + if (!visible) SETBITS(this->flags, SEF_FILTERED); + return visible; +} + + + +/** + * Draw a row in the settings panel. + * + * See SettingsPage::Draw() for an explanation about how drawing is performed. + * + * The \a parent_last parameter ensures that the vertical lines at the left are + * only drawn when another entry follows, that it prevents output like + * \verbatim + * |-- setting + * |-- (-) - Title + * | |-- setting + * | |-- setting + * \endverbatim + * The left-most vertical line is not wanted. It is prevented by setting the + * appropriate bit in the \a parent_last parameter. + * + * @param settings_ptr Pointer to current values of all settings + * @param left Left-most position in window/panel to start drawing \a first_row + * @param right Right-most x position to draw strings at. + * @param base_y Upper-most position in window/panel to start drawing \a first_row + * @param first_row First row number to draw + * @param max_row Row-number to stop drawing (the row-number of the row below the last row to draw) + * @param cur_row Current row number (internal variable) + * @param parent_last Last-field booleans of parent page level (page level \e i sets bit \e i to 1 if it is its last field) + * @param selected Selected entry by the user. + * @return Row number of the next row to draw + */ +uint SettingEntry::Draw(GameSettings *settings_ptr, int left, int right, int base_y, uint first_row, uint max_row, uint cur_row, uint parent_last, SettingEntry *selected) +{ + if (this->IsFiltered()) return cur_row; + if (cur_row >= max_row) return cur_row; + + bool rtl = _current_text_dir == TD_RTL; + int offset = rtl ? -4 : 4; + int level_width = rtl ? -LEVEL_WIDTH : LEVEL_WIDTH; + + int x = rtl ? right : left; + int y = base_y; + if (cur_row >= first_row) { + int colour = _colour_gradient[COLOUR_ORANGE][4]; + y = base_y + (cur_row - first_row) * SETTING_HEIGHT; // Compute correct y start position + + /* Draw vertical for parent nesting levels */ + for (uint lvl = 0; lvl < this->level; lvl++) { + if (!HasBit(parent_last, lvl)) GfxDrawLine(x + offset, y, x + offset, y + SETTING_HEIGHT - 1, colour); + x += level_width; + } + /* draw own |- prefix */ + int halfway_y = y + SETTING_HEIGHT / 2; + int bottom_y = (flags & SEF_LAST_FIELD) ? halfway_y : y + SETTING_HEIGHT - 1; + GfxDrawLine(x + offset, y, x + offset, bottom_y, colour); + /* Small horizontal line from the last vertical line */ + GfxDrawLine(x + offset, halfway_y, x + level_width - offset, halfway_y, colour); + x += level_width; + } + + switch (this->flags & SEF_KIND_MASK) { + case SEF_SETTING_KIND: + if (cur_row >= first_row) { + this->DrawSetting(settings_ptr, rtl ? left : x, rtl ? x : right, y, this->flags & SEF_BUTTONS_MASK, + this == selected); + } + cur_row++; + break; + case SEF_SUBTREE_KIND: + if (cur_row >= first_row) { + DrawSprite((this->d.sub.folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED), PAL_NONE, rtl ? x - 8 : x, y + (SETTING_HEIGHT - 11) / 2); + DrawString(rtl ? left : x + 12, rtl ? x - 12 : right, Center(y, SETTING_HEIGHT), this->d.sub.title); + } + cur_row++; + if (!this->d.sub.folded) { + if (this->flags & SEF_LAST_FIELD) { + assert(this->level < sizeof(parent_last)); + SetBit(parent_last, this->level); // Add own last-field state + } + + cur_row = this->d.sub.page->Draw(settings_ptr, left, right, base_y, first_row, max_row, selected, cur_row, parent_last); + } + break; + default: NOT_REACHED(); + } + return cur_row; +} + +static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const SettingDesc *sd) +{ + if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { + if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) { + return GetVariableAddress(&Company::Get(_local_company)->settings, &sd->save); + } else { + return GetVariableAddress(&_settings_client.company, &sd->save); + } + } else { + return GetVariableAddress(settings_ptr, &sd->save); + } +} + +/** + * Set the DParams for drawing the value of a setting. + * @param first_param First DParam to use + * @param value Setting value to set params for. + */ +void SettingEntry::SetValueDParams(uint first_param, int32 value) +{ + assert((this->flags & SEF_KIND_MASK) == SEF_SETTING_KIND); + const SettingDescBase *sdb = &this->d.entry.setting->desc; + if (sdb->cmd == SDT_BOOLX) { + SetDParam(first_param++, value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); + } else { + if ((sdb->flags & SGF_MULTISTRING) != 0) { + SetDParam(first_param++, sdb->str_val - sdb->min + value); + } else if ((sdb->flags & SGF_DISPLAY_ABS) != 0) { + SetDParam(first_param++, sdb->str_val + ((value >= 0) ? 1 : 0)); + value = abs(value); + } else { + SetDParam(first_param++, sdb->str_val + ((value == 0 && (sdb->flags & SGF_0ISDISABLED) != 0) ? 1 : 0)); + } + SetDParam(first_param++, value); + } +} + +/** + * Private function to draw setting value (button + text + current value) + * @param settings_ptr Pointer to current values of all settings + * @param left Left-most position in window/panel to start drawing + * @param right Right-most position in window/panel to draw + * @param y Upper-most position in window/panel to start drawing + * @param state State of the left + right arrow buttons to draw for the setting + * @param highlight Highlight entry. + */ +void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, int y, int state, bool highlight) +{ + const SettingDesc *sd = this->d.entry.setting; + const SettingDescBase *sdb = &sd->desc; + const void *var = ResolveVariableAddress(settings_ptr, sd); + + bool rtl = _current_text_dir == TD_RTL; + uint buttons_left = rtl ? right + 1 - SETTING_BUTTON_WIDTH : left; + uint text_left = left + (rtl ? 0 : SETTING_BUTTON_WIDTH + 5); + uint text_right = right - (rtl ? SETTING_BUTTON_WIDTH + 5 : 0); + uint button_y = y + (SETTING_HEIGHT - SETTING_BUTTON_HEIGHT) / 2; + + /* We do not allow changes of some items when we are a client in a networkgame */ + bool editable = sd->IsEditable(); + + SetDParam(0, highlight ? STR_ORANGE_STRING1_WHITE : STR_ORANGE_STRING1_LTBLUE); + int32 value = (int32)ReadValue(var, sd->save.conv); + if (sdb->cmd == SDT_BOOLX) { + /* Draw checkbox for boolean-value either on/off */ + DrawBoolButton(buttons_left, button_y, value != 0, editable); + } else if ((sdb->flags & SGF_MULTISTRING) != 0) { + /* Draw [v] button for settings of an enum-type */ + DrawDropDownButton(buttons_left, button_y, COLOUR_YELLOW, state != 0, editable); + } else { + /* Draw [<][>] boxes for settings of an integer-type */ + DrawArrowButtons(buttons_left, button_y, COLOUR_YELLOW, state, + editable && value != (sdb->flags & SGF_0ISDISABLED ? 0 : sdb->min), editable && (uint32)value != sdb->max); + } + this->SetValueDParams(1, value); + DrawString(text_left, text_right, Center(y, SETTING_HEIGHT), sdb->str, highlight ? TC_WHITE : TC_LIGHT_BLUE); +} + + +/* == SettingsPage methods == */ + +/** + * Initialization of an entire setting page + * @param level Nesting level of this page (internal variable, do not provide a value for it when calling) + */ +void SettingsPage::Init(byte level) +{ + for (uint field = 0; field < this->num; field++) { + this->entries[field].Init(level); + } +} + +/** Recursively close all folds of sub-pages */ +void SettingsPage::FoldAll() +{ + for (uint field = 0; field < this->num; field++) { + this->entries[field].FoldAll(); + } +} + +/** Recursively open all folds of sub-pages */ +void SettingsPage::UnFoldAll() +{ + for (uint field = 0; field < this->num; field++) { + this->entries[field].UnFoldAll(); + } +} + +/** + * Recursively accumulate the folding state of the tree. + * @param[in,out] all_folded Set to false, if one entry is not folded. + * @param[in,out] all_unfolded Set to false, if one entry is folded. + */ +void SettingsPage::GetFoldingState(bool &all_folded, bool &all_unfolded) const +{ + for (uint field = 0; field < this->num; field++) { + this->entries[field].GetFoldingState(all_folded, all_unfolded); + } +} + +/** + * Update the filter state. + * @param filter Filter + * @param force_visible Whether to force all items visible, no matter what + * @return true if item remains visible + */ +bool SettingsPage::UpdateFilterState(SettingFilter &filter, bool force_visible) +{ + bool visible = false; + bool first_visible = true; + for (int field = this->num - 1; field >= 0; field--) { + visible |= this->entries[field].UpdateFilterState(filter, force_visible); + this->entries[field].SetLastField(first_visible); + if (visible && first_visible) first_visible = false; + } + return visible; +} + + +/** + * Check whether an entry is visible and not folded or filtered away. + * Note: This does not consider the scrolling range; it might still require scrolling ot make the setting really visible. + * @param item Entry to search for. + * @return true if entry is visible. + */ +bool SettingsPage::IsVisible(const SettingEntry *item) const +{ + for (uint field = 0; field < this->num; field++) { + if (this->entries[field].IsVisible(item)) return true; + } + return false; +} + +/** Return number of rows needed to display the whole page */ +uint SettingsPage::Length() const +{ + uint length = 0; + for (uint field = 0; field < this->num; field++) { + length += this->entries[field].Length(); + } + return length; +} + +/** + * Find the setting entry at row number \a row_num + * @param row_num Index of entry to return + * @param cur_row Variable used for keeping track of the current row number. Should point to memory initialized to \c 0 when first called. + * @return The requested setting entry or \c NULL if it does not exist + */ +SettingEntry *SettingsPage::FindEntry(uint row_num, uint *cur_row) const +{ + SettingEntry *pe = NULL; + + for (uint field = 0; field < this->num; field++) { + pe = this->entries[field].FindEntry(row_num, cur_row); + if (pe != NULL) { + break; + } + } + return pe; +} + +/** + * Get the biggest height of the help texts, if the width is at least \a maxw. Help text gets wrapped if needed. + * @param maxw Maximal width of a line help text. + * @return Biggest height needed to display any help text of this (sub-)tree. + */ +uint SettingsPage::GetMaxHelpHeight(int maxw) +{ + uint biggest = 0; + for (uint field = 0; field < this->num; field++) { + biggest = max(biggest, this->entries[field].GetMaxHelpHeight(maxw)); + } + return biggest; +} + +/** + * Draw a selected part of the settings page. + * + * The scrollbar uses rows of the page, while the page data structure is a tree of #SettingsPage and #SettingEntry objects. + * As a result, the drawing routing traverses the tree from top to bottom, counting rows in \a cur_row until it reaches \a first_row. + * Then it enables drawing rows while traversing until \a max_row is reached, at which point drawing is terminated. + * + * @param settings_ptr Pointer to current values of all settings + * @param left Left-most position in window/panel to start drawing of each setting row + * @param right Right-most position in window/panel to draw at + * @param base_y Upper-most position in window/panel to start drawing of row number \a first_row + * @param first_row Number of first row to draw + * @param max_row Row-number to stop drawing (the row-number of the row below the last row to draw) + * @param cur_row Current row number (internal variable) + * @param parent_last Last-field booleans of parent page level (page level \e i sets bit \e i to 1 if it is its last field) + * @param selected Selected entry by the user. + * @return Row number of the next row to draw + */ +uint SettingsPage::Draw(GameSettings *settings_ptr, int left, int right, int base_y, uint first_row, uint max_row, SettingEntry *selected, uint cur_row, uint parent_last) const +{ + if (cur_row >= max_row) return cur_row; + + for (uint i = 0; i < this->num; i++) { + cur_row = this->entries[i].Draw(settings_ptr, left, right, base_y, first_row, max_row, cur_row, parent_last, selected); + if (cur_row >= max_row) { + break; + } + } + return cur_row; +} + + +static SettingEntry _settings_ui_localisation[] = { + SettingEntry("locale.units_velocity"), + SettingEntry("locale.units_power"), + SettingEntry("locale.units_weight"), + SettingEntry("locale.units_volume"), + SettingEntry("locale.units_force"), + SettingEntry("locale.units_height"), +}; +/** Localisation options sub-page */ +static SettingsPage _settings_ui_localisation_page = {_settings_ui_localisation, lengthof(_settings_ui_localisation)}; + +static SettingEntry _settings_ui_display[] = { + SettingEntry("gui.date_format_in_default_names"), + SettingEntry("gui.population_in_label"), + SettingEntry("gui.measure_tooltip"), + SettingEntry("gui.loading_indicators"), + SettingEntry("gui.liveries"), + SettingEntry("gui.show_track_reservation"), + SettingEntry("gui.expenses_layout"), + SettingEntry("gui.smallmap_land_colour"), + SettingEntry("gui.zoom_min"), + SettingEntry("gui.zoom_max"), + SettingEntry("gui.graph_line_thickness"), +}; +/** Display options sub-page */ +static SettingsPage _settings_ui_display_page = {_settings_ui_display, lengthof(_settings_ui_display)}; + +static SettingEntry _settings_ui_interaction[] = { + SettingEntry("gui.window_snap_radius"), + SettingEntry("gui.window_soft_limit"), + SettingEntry("gui.link_terraform_toolbar"), + SettingEntry("gui.prefer_teamchat"), + SettingEntry("gui.auto_scrolling"), + SettingEntry("gui.reverse_scroll"), + SettingEntry("gui.smooth_scroll"), + SettingEntry("gui.left_mouse_btn_scrolling"), + /* While the horizontal scrollwheel scrolling is written as general code, only + * the cocoa (OSX) driver generates input for it. + * Since it's also able to completely disable the scrollwheel will we display it on all platforms anyway */ + SettingEntry("gui.scrollwheel_scrolling"), + SettingEntry("gui.scrollwheel_multiplier"), + SettingEntry("gui.osk_activation"), +#ifdef __APPLE__ + /* We might need to emulate a right mouse button on mac */ + SettingEntry("gui.right_mouse_btn_emulation"), +#endif +}; +/** Interaction sub-page */ +static SettingsPage _settings_ui_interaction_page = {_settings_ui_interaction, lengthof(_settings_ui_interaction)}; + +static SettingEntry _settings_ui_sound[] = { + SettingEntry("sound.click_beep"), + SettingEntry("sound.confirm"), + SettingEntry("sound.news_ticker"), + SettingEntry("sound.news_full"), + SettingEntry("sound.new_year"), + SettingEntry("sound.disaster"), + SettingEntry("sound.vehicle"), + SettingEntry("sound.ambient"), +}; +/** Sound effects sub-page */ +static SettingsPage _settings_ui_sound_page = {_settings_ui_sound, lengthof(_settings_ui_sound)}; + +static SettingEntry _settings_ui_news[] = { + SettingEntry("news_display.arrival_player"), + SettingEntry("news_display.arrival_other"), + SettingEntry("news_display.accident"), + SettingEntry("news_display.company_info"), + SettingEntry("news_display.open"), + SettingEntry("news_display.close"), + SettingEntry("news_display.economy"), + SettingEntry("news_display.production_player"), + SettingEntry("news_display.production_other"), + SettingEntry("news_display.production_nobody"), + SettingEntry("news_display.advice"), + SettingEntry("news_display.new_vehicles"), + SettingEntry("news_display.acceptance"), + SettingEntry("news_display.subsidies"), + SettingEntry("news_display.general"), + SettingEntry("gui.coloured_news_year"), +}; +/** News sub-page */ +static SettingsPage _settings_ui_news_page = {_settings_ui_news, lengthof(_settings_ui_news)}; + +static SettingEntry _settings_ui[] = { + SettingEntry(&_settings_ui_localisation_page, STR_CONFIG_SETTING_LOCALISATION), + SettingEntry(&_settings_ui_display_page, STR_CONFIG_SETTING_DISPLAY_OPTIONS), + SettingEntry(&_settings_ui_interaction_page, STR_CONFIG_SETTING_INTERACTION), + SettingEntry(&_settings_ui_sound_page, STR_CONFIG_SETTING_SOUND), + SettingEntry(&_settings_ui_news_page, STR_CONFIG_SETTING_NEWS), + SettingEntry("gui.show_finances"), + SettingEntry("gui.errmsg_duration"), + SettingEntry("gui.hover_delay"), + SettingEntry("gui.toolbar_pos"), + SettingEntry("gui.statusbar_pos"), + SettingEntry("gui.newgrf_default_palette"), + SettingEntry("gui.pause_on_newgame"), + SettingEntry("gui.advanced_vehicle_list"), + SettingEntry("gui.timetable_in_ticks"), + SettingEntry("gui.timetable_arrival_departure"), + SettingEntry("gui.quick_goto"), + SettingEntry("gui.default_rail_type"), + SettingEntry("gui.disable_unsuitable_building"), + SettingEntry("gui.persistent_buildingtools"), +}; +/** Interface subpage */ +static SettingsPage _settings_ui_page = {_settings_ui, lengthof(_settings_ui)}; + +static SettingEntry _settings_construction_signals[] = { + SettingEntry("construction.train_signal_side"), + SettingEntry("gui.enable_signal_gui"), + SettingEntry("gui.drag_signals_fixed_distance"), + SettingEntry("gui.semaphore_build_before"), + SettingEntry("gui.default_signal_type"), + SettingEntry("gui.cycle_signal_types"), +}; +/** Signals subpage */ +static SettingsPage _settings_construction_signals_page = {_settings_construction_signals, lengthof(_settings_construction_signals)}; + +static SettingEntry _settings_construction[] = { + SettingEntry(&_settings_construction_signals_page, STR_CONFIG_SETTING_CONSTRUCTION_SIGNALS), + SettingEntry("construction.build_on_slopes"), + SettingEntry("construction.autoslope"), + SettingEntry("construction.extra_dynamite"), + SettingEntry("construction.max_bridge_length"), + SettingEntry("construction.max_tunnel_length"), + SettingEntry("station.never_expire_airports"), + SettingEntry("construction.freeform_edges"), + SettingEntry("construction.extra_tree_placement"), + SettingEntry("construction.command_pause_level"), +}; +/** Construction sub-page */ +static SettingsPage _settings_construction_page = {_settings_construction, lengthof(_settings_construction)}; + +static SettingEntry _settings_stations_cargo[] = { + SettingEntry("order.improved_load"), + SettingEntry("order.gradual_loading"), + SettingEntry("order.selectgoods"), +}; +/** Cargo handling sub-page */ +static SettingsPage _settings_stations_cargo_page = {_settings_stations_cargo, lengthof(_settings_stations_cargo)}; + +static SettingEntry _settings_stations[] = { + SettingEntry(&_settings_stations_cargo_page, STR_CONFIG_SETTING_STATIONS_CARGOHANDLING), + SettingEntry("station.adjacent_stations"), + SettingEntry("station.distant_join_stations"), + SettingEntry("station.station_spread"), + SettingEntry("economy.station_noise_level"), + SettingEntry("station.modified_catchment"), + SettingEntry("construction.road_stop_on_town_road"), + SettingEntry("construction.road_stop_on_competitor_road"), +}; +/** Stations sub-page */ +static SettingsPage _settings_stations_page = {_settings_stations, lengthof(_settings_stations)}; + +static SettingEntry _settings_economy_towns[] = { + SettingEntry("difficulty.town_council_tolerance"), + SettingEntry("economy.bribe"), + SettingEntry("economy.exclusive_rights"), + SettingEntry("economy.fund_roads"), + SettingEntry("economy.fund_buildings"), + SettingEntry("economy.town_layout"), + SettingEntry("economy.allow_town_roads"), + SettingEntry("economy.allow_town_level_crossings"), + SettingEntry("economy.found_town"), + SettingEntry("economy.mod_road_rebuild"), + SettingEntry("economy.town_growth_rate"), + SettingEntry("economy.larger_towns"), + SettingEntry("economy.initial_city_size"), +}; +/** Towns sub-page */ +static SettingsPage _settings_economy_towns_page = {_settings_economy_towns, lengthof(_settings_economy_towns)}; + +static SettingEntry _settings_economy_industries[] = { + SettingEntry("construction.raw_industry_construction"), + SettingEntry("construction.industry_platform"), + SettingEntry("economy.multiple_industry_per_town"), + SettingEntry("game_creation.oil_refinery_limit"), +}; +/** Industries sub-page */ +static SettingsPage _settings_economy_industries_page = {_settings_economy_industries, lengthof(_settings_economy_industries)}; + + +static SettingEntry _settings_economy[] = { + SettingEntry(&_settings_economy_towns_page, STR_CONFIG_SETTING_ECONOMY_TOWNS), + SettingEntry(&_settings_economy_industries_page, STR_CONFIG_SETTING_ECONOMY_INDUSTRIES), + SettingEntry("economy.inflation"), + SettingEntry("difficulty.initial_interest"), + SettingEntry("difficulty.max_loan"), + SettingEntry("difficulty.subsidy_multiplier"), + SettingEntry("difficulty.economy"), + SettingEntry("economy.smooth_economy"), + SettingEntry("economy.feeder_payment_share"), + SettingEntry("economy.infrastructure_maintenance"), + SettingEntry("difficulty.vehicle_costs"), + SettingEntry("difficulty.construction_cost"), + SettingEntry("difficulty.disasters"), +}; +/** Economy sub-page */ +static SettingsPage _settings_economy_page = {_settings_economy, lengthof(_settings_economy)}; + +static SettingEntry _settings_linkgraph[] = { + SettingEntry("linkgraph.recalc_time"), + SettingEntry("linkgraph.recalc_interval"), + SettingEntry("linkgraph.distribution_pax"), + SettingEntry("linkgraph.distribution_mail"), + SettingEntry("linkgraph.distribution_armoured"), + SettingEntry("linkgraph.distribution_default"), + SettingEntry("linkgraph.accuracy"), + SettingEntry("linkgraph.demand_distance"), + SettingEntry("linkgraph.demand_size"), + SettingEntry("linkgraph.short_path_saturation"), +}; +/** Linkgraph sub-page */ +static SettingsPage _settings_linkgraph_page = {_settings_linkgraph, lengthof(_settings_linkgraph)}; + +static SettingEntry _settings_ai_npc[] = { + SettingEntry("script.settings_profile"), + SettingEntry("script.script_max_opcode_till_suspend"), + SettingEntry("difficulty.competitor_speed"), + SettingEntry("ai.ai_in_multiplayer"), + SettingEntry("ai.ai_disable_veh_train"), + SettingEntry("ai.ai_disable_veh_roadveh"), + SettingEntry("ai.ai_disable_veh_aircraft"), + SettingEntry("ai.ai_disable_veh_ship"), +}; +/** Computer players sub-page */ +static SettingsPage _settings_ai_npc_page = {_settings_ai_npc, lengthof(_settings_ai_npc)}; + +static SettingEntry _settings_ai[] = { + SettingEntry(&_settings_ai_npc_page, STR_CONFIG_SETTING_AI_NPC), + SettingEntry("economy.give_money"), + SettingEntry("economy.allow_shares"), +}; +/** AI sub-page */ +static SettingsPage _settings_ai_page = {_settings_ai, lengthof(_settings_ai)}; + +static SettingEntry _settings_vehicles_routing[] = { + SettingEntry("pf.pathfinder_for_trains"), + SettingEntry("pf.forbid_90_deg"), + SettingEntry("pf.pathfinder_for_roadvehs"), + SettingEntry("pf.roadveh_queue"), + SettingEntry("pf.pathfinder_for_ships"), +}; +/** Autorenew sub-page */ +static SettingsPage _settings_vehicles_routing_page = {_settings_vehicles_routing, lengthof(_settings_vehicles_routing)}; + +static SettingEntry _settings_vehicles_autorenew[] = { + SettingEntry("company.engine_renew"), + SettingEntry("company.engine_renew_months"), + SettingEntry("company.engine_renew_money"), +}; +/** Autorenew sub-page */ +static SettingsPage _settings_vehicles_autorenew_page = {_settings_vehicles_autorenew, lengthof(_settings_vehicles_autorenew)}; + +static SettingEntry _settings_vehicles_servicing[] = { + SettingEntry("vehicle.servint_ispercent"), + SettingEntry("vehicle.servint_trains"), + SettingEntry("vehicle.servint_roadveh"), + SettingEntry("vehicle.servint_ships"), + SettingEntry("vehicle.servint_aircraft"), + SettingEntry("difficulty.vehicle_breakdowns"), + SettingEntry("order.no_servicing_if_no_breakdowns"), + SettingEntry("order.serviceathelipad"), +}; +/** Servicing sub-page */ +static SettingsPage _settings_vehicles_servicing_page = {_settings_vehicles_servicing, lengthof(_settings_vehicles_servicing)}; + +static SettingEntry _settings_vehicles_trains[] = { + SettingEntry("difficulty.line_reverse_mode"), + SettingEntry("pf.reverse_at_signals"), + SettingEntry("vehicle.train_acceleration_model"), + SettingEntry("vehicle.train_slope_steepness"), + SettingEntry("vehicle.max_train_length"), + SettingEntry("vehicle.wagon_speed_limits"), + SettingEntry("vehicle.disable_elrails"), + SettingEntry("vehicle.freight_trains"), + SettingEntry("gui.stop_location"), +}; +/** Trains sub-page */ +static SettingsPage _settings_vehicles_trains_page = {_settings_vehicles_trains, lengthof(_settings_vehicles_trains)}; + +static SettingEntry _settings_vehicles[] = { + SettingEntry(&_settings_vehicles_routing_page, STR_CONFIG_SETTING_VEHICLES_ROUTING), + SettingEntry(&_settings_vehicles_autorenew_page, STR_CONFIG_SETTING_VEHICLES_AUTORENEW), + SettingEntry(&_settings_vehicles_servicing_page, STR_CONFIG_SETTING_VEHICLES_SERVICING), + SettingEntry(&_settings_vehicles_trains_page, STR_CONFIG_SETTING_VEHICLES_TRAINS), + SettingEntry("gui.new_nonstop"), + SettingEntry("gui.order_review_system"), + SettingEntry("gui.vehicle_income_warn"), + SettingEntry("gui.lost_vehicle_warn"), + SettingEntry("vehicle.never_expire_vehicles"), + SettingEntry("vehicle.max_trains"), + SettingEntry("vehicle.max_roadveh"), + SettingEntry("vehicle.max_aircraft"), + SettingEntry("vehicle.max_ships"), + SettingEntry("vehicle.plane_speed"), + SettingEntry("vehicle.plane_crashes"), + SettingEntry("vehicle.dynamic_engines"), + SettingEntry("vehicle.roadveh_acceleration_model"), + SettingEntry("vehicle.roadveh_slope_steepness"), + SettingEntry("vehicle.smoke_amount"), +}; +/** Vehicles sub-page */ +static SettingsPage _settings_vehicles_page = {_settings_vehicles, lengthof(_settings_vehicles)}; + +static SettingEntry _settings_main[] = { + SettingEntry(&_settings_ui_page, STR_CONFIG_SETTING_GUI), + SettingEntry(&_settings_construction_page, STR_CONFIG_SETTING_CONSTRUCTION), + SettingEntry(&_settings_vehicles_page, STR_CONFIG_SETTING_VEHICLES), + SettingEntry(&_settings_stations_page, STR_CONFIG_SETTING_STATIONS), + SettingEntry(&_settings_economy_page, STR_CONFIG_SETTING_ECONOMY), + SettingEntry(&_settings_linkgraph_page, STR_CONFIG_SETTING_LINKGRAPH), + SettingEntry(&_settings_ai_page, STR_CONFIG_SETTING_AI), +}; + +/** Main page, holding all advanced settings */ +static SettingsPage _settings_main_page = {_settings_main, lengthof(_settings_main)}; + +static const StringID _game_settings_restrict_dropdown[] = { + STR_CONFIG_SETTING_RESTRICT_BASIC, // RM_BASIC + STR_CONFIG_SETTING_RESTRICT_ADVANCED, // RM_ADVANCED + STR_CONFIG_SETTING_RESTRICT_ALL, // RM_ALL + STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT, // RM_CHANGED_AGAINST_DEFAULT + STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW, // RM_CHANGED_AGAINST_NEW +}; +assert_compile(lengthof(_game_settings_restrict_dropdown) == RM_END); + +/** Warnings about hidden search results. */ +enum WarnHiddenResult { + WHR_NONE, ///< Nothing was filtering matches away. + WHR_CATEGORY, ///< Category setting filtered matches away. + WHR_TYPE, ///< Type setting filtered matches away. + WHR_CATEGORY_TYPE, ///< Both category and type settings filtered matches away. +}; + +/** Window to edit settings of the game. */ +struct GameSettingsWindow : Window { + static const int SETTINGTREE_LEFT_OFFSET = 5; ///< Position of left edge of setting values + static const int SETTINGTREE_RIGHT_OFFSET = 5; ///< Position of right edge of setting values + static const int SETTINGTREE_TOP_OFFSET = 5; ///< Position of top edge of setting values + static const int SETTINGTREE_BOTTOM_OFFSET = 5; ///< Position of bottom edge of setting values + + static GameSettings *settings_ptr; ///< Pointer to the game settings being displayed and modified. + + SettingEntry *valuewindow_entry; ///< If non-NULL, pointer to setting for which a value-entering window has been opened. + SettingEntry *clicked_entry; ///< If non-NULL, pointer to a clicked numeric setting (with a depressed left or right button). + SettingEntry *last_clicked; ///< If non-NULL, pointer to the last clicked setting. + SettingEntry *valuedropdown_entry; ///< If non-NULL, pointer to the value for which a dropdown window is currently opened. + bool closing_dropdown; ///< True, if the dropdown list is currently closing. + + SettingFilter filter; ///< Filter for the list. + QueryString filter_editbox; ///< Filter editbox; + bool manually_changed_folding; ///< Whether the user expanded/collapsed something manually. + WarnHiddenResult warn_missing; ///< Whether and how to warn about missing search results. + int warn_lines; ///< Number of lines used for warning about missing search results. + + Scrollbar *vscroll; + + GameSettingsWindow(WindowDesc *desc) : Window(desc), filter_editbox(50) + { + static bool first_time = true; + + this->warn_missing = WHR_NONE; + this->warn_lines = 0; + this->filter.mode = (RestrictionMode)_settings_client.gui.settings_restriction_mode; + this->filter.min_cat = RM_ALL; + this->filter.type = ST_ALL; + this->filter.type_hides = false; + this->settings_ptr = &GetGameSettings(); + + /* Build up the dynamic settings-array only once per OpenTTD session */ + if (first_time) { + _settings_main_page.Init(); + first_time = false; + } else { + _settings_main_page.FoldAll(); // Close all sub-pages + } + + this->valuewindow_entry = NULL; // No setting entry for which a entry window is opened + this->clicked_entry = NULL; // No numeric setting buttons are depressed + this->last_clicked = NULL; + this->valuedropdown_entry = NULL; + this->closing_dropdown = false; + this->manually_changed_folding = false; + + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_GS_SCROLLBAR); + this->FinishInitNested(WN_GAME_OPTIONS_GAME_SETTINGS); + + this->querystrings[WID_GS_FILTER] = &this->filter_editbox; + this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR; + this->SetFocusedWidget(WID_GS_FILTER); + + this->InvalidateData(); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_GS_OPTIONSPANEL: + resize->height = SETTING_HEIGHT = GetMinSizing(NWST_STEP, max(11, FONT_HEIGHT_NORMAL + 1)); + resize->width = 1; + + size->height = 5 * resize->height + SETTINGTREE_TOP_OFFSET + SETTINGTREE_BOTTOM_OFFSET; + break; + + case WID_GS_HELP_TEXT: { + static const StringID setting_types[] = { + STR_CONFIG_SETTING_TYPE_CLIENT, + STR_CONFIG_SETTING_TYPE_COMPANY_MENU, STR_CONFIG_SETTING_TYPE_COMPANY_INGAME, + STR_CONFIG_SETTING_TYPE_GAME_MENU, STR_CONFIG_SETTING_TYPE_GAME_INGAME, + }; + for (uint i = 0; i < lengthof(setting_types); i++) { + SetDParam(0, setting_types[i]); + size->width = max(size->width, GetStringBoundingBox(STR_CONFIG_SETTING_TYPE).width); + } + size->height = 2 * FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL + + max(size->height, _settings_main_page.GetMaxHelpHeight(size->width)); + break; + } + + case WID_GS_RESTRICT_CATEGORY: + case WID_GS_RESTRICT_TYPE: + size->width = max(GetStringBoundingBox(STR_CONFIG_SETTING_RESTRICT_CATEGORY).width, GetStringBoundingBox(STR_CONFIG_SETTING_RESTRICT_TYPE).width); + break; + + default: + break; + } + } + + virtual void OnPaint() + { + if (this->closing_dropdown) { + this->closing_dropdown = false; + assert(this->valuedropdown_entry != NULL); + this->valuedropdown_entry->SetButtons(0); + this->valuedropdown_entry = NULL; + } + + /* Reserve the correct number of lines for the 'some search results are hidden' notice in the central settings display panel. */ + const NWidgetBase *panel = this->GetWidget(WID_GS_OPTIONSPANEL); + StringID warn_str = STR_CONFIG_SETTING_CATEGORY_HIDES - 1 + this->warn_missing; + int new_warn_lines; + if (this->warn_missing == WHR_NONE) { + new_warn_lines = 0; + } else { + SetDParam(0, _game_settings_restrict_dropdown[this->filter.min_cat]); + new_warn_lines = GetStringLineCount(warn_str, panel->current_x); + } + if (this->warn_lines != new_warn_lines) { + this->vscroll->SetCount(this->vscroll->GetCount() - this->warn_lines + new_warn_lines); + this->warn_lines = new_warn_lines; + } + + this->DrawWidgets(); + + /* Draw the 'some search results are hidden' notice. */ + if (this->warn_missing != WHR_NONE) { + const int left = panel->pos_x; + const int right = left + panel->current_x - 1; + const int top = panel->pos_y; + SetDParam(0, _game_settings_restrict_dropdown[this->filter.min_cat]); + if (this->warn_lines == 1) { + /* If the warning fits at one line, center it. */ + DrawString(left + WD_FRAMETEXT_LEFT, right - WD_FRAMETEXT_RIGHT, top + WD_FRAMETEXT_TOP, warn_str, TC_FROMSTRING, SA_HOR_CENTER); + } else { + DrawStringMultiLine(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top + WD_FRAMERECT_TOP, INT32_MAX, warn_str); + } + } + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_GS_RESTRICT_DROPDOWN: + SetDParam(0, _game_settings_restrict_dropdown[this->filter.mode]); + break; + + case WID_GS_TYPE_DROPDOWN: + switch (this->filter.type) { + case ST_GAME: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME); break; + case ST_COMPANY: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME); break; + case ST_CLIENT: SetDParam(0, STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT); break; + default: SetDParam(0, STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL); break; + } + break; + } + } + + DropDownList *BuildDropDownList(int widget) const + { + DropDownList *list = NULL; + switch (widget) { + case WID_GS_RESTRICT_DROPDOWN: + list = new DropDownList(); + + for (int mode = 0; mode != RM_END; mode++) { + /* If we are in adv. settings screen for the new game's settings, + * we don't want to allow comparing with new game's settings. */ + bool disabled = mode == RM_CHANGED_AGAINST_NEW && settings_ptr == &_settings_newgame; + + *list->Append() = new DropDownListStringItem(_game_settings_restrict_dropdown[mode], mode, disabled); + } + break; + + case WID_GS_TYPE_DROPDOWN: + list = new DropDownList(); + *list->Append() = new DropDownListStringItem(STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL, ST_ALL, false); + *list->Append() = new DropDownListStringItem(_game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME, ST_GAME, false); + *list->Append() = new DropDownListStringItem(_game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME, ST_COMPANY, false); + *list->Append() = new DropDownListStringItem(STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT, ST_CLIENT, false); + break; + } + return list; + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_GS_OPTIONSPANEL: { + int top_pos = r.top + SETTINGTREE_TOP_OFFSET + 1 + this->warn_lines * FONT_HEIGHT_NORMAL; + uint last_row = this->vscroll->GetPosition() + this->vscroll->GetCapacity() - this->warn_lines; + int next_row = _settings_main_page.Draw(settings_ptr, r.left + SETTINGTREE_LEFT_OFFSET, r.right - SETTINGTREE_RIGHT_OFFSET, top_pos, + this->vscroll->GetPosition(), last_row, this->last_clicked); + if (next_row == 0) DrawString(r.left + SETTINGTREE_LEFT_OFFSET, r.right - SETTINGTREE_RIGHT_OFFSET, top_pos, STR_CONFIG_SETTINGS_NONE); + break; + } + + case WID_GS_HELP_TEXT: + if (this->last_clicked != NULL) { + const SettingDesc *sd = this->last_clicked->d.entry.setting; + + int y = r.top; + switch (sd->GetType()) { + case ST_COMPANY: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_COMPANY_INGAME); break; + case ST_CLIENT: SetDParam(0, STR_CONFIG_SETTING_TYPE_CLIENT); break; + case ST_GAME: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_GAME_MENU : STR_CONFIG_SETTING_TYPE_GAME_INGAME); break; + default: NOT_REACHED(); + } + DrawString(r.left, r.right, y, STR_CONFIG_SETTING_TYPE); + y += FONT_HEIGHT_NORMAL; + + int32 default_value = ReadValue(&sd->desc.def, sd->save.conv); + this->last_clicked->SetValueDParams(0, default_value); + DrawString(r.left, r.right, y, STR_CONFIG_SETTING_DEFAULT_VALUE); + y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + + DrawStringMultiLine(r.left, r.right, y, r.bottom, this->last_clicked->GetHelpText(), TC_WHITE); + } + break; + + default: + break; + } + } + + /** + * Set the entry that should have its help text displayed, and mark the window dirty so it gets repainted. + * @param pe Setting to display help text of, use \c NULL to stop displaying help of the currently displayed setting. + */ + void SetDisplayedHelpText(SettingEntry *pe) + { + if (this->last_clicked != pe) this->SetDirty(); + this->last_clicked = pe; + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_GS_EXPAND_ALL: + this->manually_changed_folding = true; + _settings_main_page.UnFoldAll(); + this->InvalidateData(); + break; + + case WID_GS_COLLAPSE_ALL: + this->manually_changed_folding = true; + _settings_main_page.FoldAll(); + this->InvalidateData(); + break; + + case WID_GS_RESTRICT_DROPDOWN: { + DropDownList *list = this->BuildDropDownList(widget); + if (list != NULL) { + ShowDropDownList(this, list, this->filter.mode, widget); + } + break; + } + + case WID_GS_TYPE_DROPDOWN: { + DropDownList *list = this->BuildDropDownList(widget); + if (list != NULL) { + ShowDropDownList(this, list, this->filter.type, widget); + } + break; + } + } + + if (widget != WID_GS_OPTIONSPANEL) return; + + uint btn = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GS_OPTIONSPANEL, SETTINGTREE_TOP_OFFSET); + if (btn == INT_MAX || (int)btn < this->warn_lines) return; + btn -= this->warn_lines; + + uint cur_row = 0; + SettingEntry *pe = _settings_main_page.FindEntry(btn, &cur_row); + + if (pe == NULL) return; // Clicked below the last setting of the page + + int x = (_current_text_dir == TD_RTL ? this->width - 1 - pt.x : pt.x) - SETTINGTREE_LEFT_OFFSET - (pe->level + 1) * LEVEL_WIDTH; // Shift x coordinate + if (x < 0) return; // Clicked left of the entry + + if ((pe->flags & SEF_KIND_MASK) == SEF_SUBTREE_KIND) { + this->SetDisplayedHelpText(NULL); + pe->d.sub.folded = !pe->d.sub.folded; // Flip 'folded'-ness of the sub-page + + this->manually_changed_folding = true; + + this->InvalidateData(); + return; + } + + assert((pe->flags & SEF_KIND_MASK) == SEF_SETTING_KIND); + const SettingDesc *sd = pe->d.entry.setting; + + /* return if action is only active in network, or only settable by server */ + if (!sd->IsEditable()) { + this->SetDisplayedHelpText(pe); + return; + } + + const void *var = ResolveVariableAddress(settings_ptr, sd); + int32 value = (int32)ReadValue(var, sd->save.conv); + + /* clicked on the icon on the left side. Either scroller, bool on/off or dropdown */ + if (x < SETTING_BUTTON_WIDTH && (sd->desc.flags & SGF_MULTISTRING)) { + const SettingDescBase *sdb = &sd->desc; + this->SetDisplayedHelpText(pe); + + if (this->valuedropdown_entry == pe) { + /* unclick the dropdown */ + HideDropDownMenu(this); + this->closing_dropdown = false; + this->valuedropdown_entry->SetButtons(0); + this->valuedropdown_entry = NULL; + } else { + if (this->valuedropdown_entry != NULL) this->valuedropdown_entry->SetButtons(0); + this->closing_dropdown = false; + + const NWidgetBase *wid = this->GetWidget(WID_GS_OPTIONSPANEL); + int rel_y = (pt.y - (int)wid->pos_y - SETTINGTREE_TOP_OFFSET) % wid->resize_y; + + Rect wi_rect; + wi_rect.left = pt.x - (_current_text_dir == TD_RTL ? SETTING_BUTTON_WIDTH - 1 - x : x); + wi_rect.right = wi_rect.left + SETTING_BUTTON_WIDTH - 1; + wi_rect.top = pt.y - rel_y + (SETTING_HEIGHT - SETTING_BUTTON_HEIGHT) / 2; + wi_rect.bottom = wi_rect.top + SETTING_BUTTON_HEIGHT - 1; + + /* For dropdowns we also have to check the y position thoroughly, the mouse may not above the just opening dropdown */ + if (pt.y >= wi_rect.top && pt.y <= wi_rect.bottom) { + this->valuedropdown_entry = pe; + this->valuedropdown_entry->SetButtons(SEF_LEFT_DEPRESSED); + + DropDownList *list = new DropDownList(); + for (int i = sdb->min; i <= (int)sdb->max; i++) { + *list->Append() = new DropDownListStringItem(sdb->str_val + i - sdb->min, i, false); + } + + ShowDropDownListAt(this, list, value, -1, wi_rect, COLOUR_ORANGE, true); + } + } + this->SetDirty(); + } else if (x < SETTING_BUTTON_WIDTH) { + this->SetDisplayedHelpText(pe); + const SettingDescBase *sdb = &sd->desc; + int32 oldvalue = value; + + switch (sdb->cmd) { + case SDT_BOOLX: value ^= 1; break; + case SDT_ONEOFMANY: + case SDT_NUMX: { + /* Add a dynamic step-size to the scroller. In a maximum of + * 50-steps you should be able to get from min to max, + * unless specified otherwise in the 'interval' variable + * of the current setting. */ + uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval; + if (step == 0) step = 1; + + /* don't allow too fast scrolling */ + if ((this->flags & WF_TIMEOUT) && this->timeout_timer > 1) { + _left_button_clicked = false; + return; + } + + /* Increase or decrease the value and clamp it to extremes */ + if (x >= SETTING_BUTTON_WIDTH / 2) { + value += step; + if (sdb->min < 0) { + assert((int32)sdb->max >= 0); + if (value > (int32)sdb->max) value = (int32)sdb->max; + } else { + if ((uint32)value > sdb->max) value = (int32)sdb->max; + } + if (value < sdb->min) value = sdb->min; // skip between "disabled" and minimum + } else { + value -= step; + if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min; + } + + /* Set up scroller timeout for numeric values */ + if (value != oldvalue) { + if (this->clicked_entry != NULL) { // Release previous buttons if any + this->clicked_entry->SetButtons(0); + } + this->clicked_entry = pe; + this->clicked_entry->SetButtons((x >= SETTING_BUTTON_WIDTH / 2) != (_current_text_dir == TD_RTL) ? SEF_RIGHT_DEPRESSED : SEF_LEFT_DEPRESSED); + this->SetTimeout(); + _left_button_clicked = false; + } + break; + } + + default: NOT_REACHED(); + } + + if (value != oldvalue) { + if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { + SetCompanySetting(pe->d.entry.index, value); + } else { + SetSettingValue(pe->d.entry.index, value); + } + this->SetDirty(); + } + } else { + /* Only open editbox if clicked for the second time, and only for types where it is sensible for. */ + if (this->last_clicked == pe && sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) { + /* Show the correct currency-translated value */ + if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate; + + this->valuewindow_entry = pe; + SetDParam(0, value); + ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 10, this, CS_NUMERAL, QSF_ENABLE_DEFAULT); + } + this->SetDisplayedHelpText(pe); + } + } + + virtual void OnTimeout() + { + if (this->clicked_entry != NULL) { // On timeout, release any depressed buttons + this->clicked_entry->SetButtons(0); + this->clicked_entry = NULL; + this->SetDirty(); + } + } + + virtual void OnQueryTextFinished(char *str) + { + /* The user pressed cancel */ + if (str == NULL) return; + + assert(this->valuewindow_entry != NULL); + assert((this->valuewindow_entry->flags & SEF_KIND_MASK) == SEF_SETTING_KIND); + const SettingDesc *sd = this->valuewindow_entry->d.entry.setting; + + int32 value; + if (!StrEmpty(str)) { + value = atoi(str); + + /* Save the correct currency-translated value */ + if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate; + } else { + value = (int32)(size_t)sd->desc.def; + } + + if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { + SetCompanySetting(this->valuewindow_entry->d.entry.index, value); + } else { + SetSettingValue(this->valuewindow_entry->d.entry.index, value); + } + this->SetDirty(); + } + + virtual void OnDropdownSelect(int widget, int index) + { + switch (widget) { + case WID_GS_RESTRICT_DROPDOWN: + this->filter.mode = (RestrictionMode)index; + if (this->filter.mode == RM_CHANGED_AGAINST_DEFAULT || + this->filter.mode == RM_CHANGED_AGAINST_NEW) { + + if (!this->manually_changed_folding) { + /* Expand all when selecting 'changes'. Update the filter state first, in case it becomes less restrictive in some cases. */ + _settings_main_page.UpdateFilterState(this->filter, false); + _settings_main_page.UnFoldAll(); + } + } else { + /* Non-'changes' filter. Save as default. */ + _settings_client.gui.settings_restriction_mode = this->filter.mode; + } + this->InvalidateData(); + break; + + case WID_GS_TYPE_DROPDOWN: + this->filter.type = (SettingType)index; + this->InvalidateData(); + break; + + default: + if (widget < 0) { + /* Deal with drop down boxes on the panel. */ + assert(this->valuedropdown_entry != NULL); + const SettingDesc *sd = this->valuedropdown_entry->d.entry.setting; + assert(sd->desc.flags & SGF_MULTISTRING); + + if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { + SetCompanySetting(this->valuedropdown_entry->d.entry.index, index); + } else { + SetSettingValue(this->valuedropdown_entry->d.entry.index, index); + } + + this->SetDirty(); + } + break; + } + } + + virtual void OnDropdownClose(Point pt, int widget, int index, bool instant_close) + { + if (widget >= 0) { + /* Normally the default implementation of OnDropdownClose() takes care of + * a few things. We want that behaviour here too, but only for + * "normal" dropdown boxes. The special dropdown boxes added for every + * setting that needs one can't have this call. */ + Window::OnDropdownClose(pt, widget, index, instant_close); + } else { + /* We cannot raise the dropdown button just yet. OnClick needs some hint, whether + * the same dropdown button was clicked again, and then not open the dropdown again. + * So, we only remember that it was closed, and process it on the next OnPaint, which is + * after OnClick. */ + assert(this->valuedropdown_entry != NULL); + this->closing_dropdown = true; + this->SetDirty(); + } + } + + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + + /* Update which settings are to be visible. */ + RestrictionMode min_level = (this->filter.mode <= RM_ALL) ? this->filter.mode : RM_BASIC; + this->filter.min_cat = min_level; + this->filter.type_hides = false; + _settings_main_page.UpdateFilterState(this->filter, false); + + if (this->filter.string.IsEmpty()) { + this->warn_missing = WHR_NONE; + } else if (min_level < this->filter.min_cat) { + this->warn_missing = this->filter.type_hides ? WHR_CATEGORY_TYPE : WHR_CATEGORY; + } else { + this->warn_missing = this->filter.type_hides ? WHR_TYPE : WHR_NONE; + } + this->vscroll->SetCount(_settings_main_page.Length() + this->warn_lines); + + if (this->last_clicked != NULL && !_settings_main_page.IsVisible(this->last_clicked)) { + this->SetDisplayedHelpText(NULL); + } + + bool all_folded = true; + bool all_unfolded = true; + _settings_main_page.GetFoldingState(all_folded, all_unfolded); + this->SetWidgetDisabledState(WID_GS_EXPAND_ALL, all_unfolded); + this->SetWidgetDisabledState(WID_GS_COLLAPSE_ALL, all_folded); + } + + virtual void OnEditboxChanged(int wid) + { + if (wid == WID_GS_FILTER) { + this->filter.string.SetFilterTerm(this->filter_editbox.text.buf); + if (!this->filter.string.IsEmpty() && !this->manually_changed_folding) { + /* User never expanded/collapsed single pages and entered a filter term. + * Expand everything, to save weird expand clicks, */ + _settings_main_page.UnFoldAll(); + } + this->InvalidateData(); + } + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_GS_OPTIONSPANEL, SETTINGTREE_TOP_OFFSET + SETTINGTREE_BOTTOM_OFFSET); + } +}; + +GameSettings *GameSettingsWindow::settings_ptr = NULL; + +static const NWidgetPart _nested_settings_selection_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), + NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_CONFIG_SETTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_MAUVE), + NWidget(NWID_VERTICAL), SetPIP(0, WD_PAR_VSEP_NORMAL, 0), SetPadding(WD_TEXTPANEL_TOP, 0, WD_TEXTPANEL_BOTTOM, 0), + NWidget(NWID_HORIZONTAL), SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_RIGHT), + NWidget(WWT_TEXT, COLOUR_MAUVE, WID_GS_RESTRICT_CATEGORY), SetDataTip(STR_CONFIG_SETTING_RESTRICT_CATEGORY, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_MAUVE, WID_GS_RESTRICT_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_BLACK_STRING, STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT), SetFill(1, 0), SetResize(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_RIGHT), + NWidget(WWT_TEXT, COLOUR_MAUVE, WID_GS_RESTRICT_TYPE), SetDataTip(STR_CONFIG_SETTING_RESTRICT_TYPE, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_MAUVE, WID_GS_TYPE_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_BLACK_STRING, STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT), SetFill(1, 0), SetResize(1, 0), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPadding(0, 0, WD_TEXTPANEL_BOTTOM, 0), + SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_RIGHT), + NWidget(WWT_TEXT, COLOUR_MAUVE), SetFill(0, 1), SetDataTip(STR_CONFIG_SETTING_FILTER_TITLE, STR_NULL), + NWidget(WWT_EDITBOX, COLOUR_MAUVE, WID_GS_FILTER), SetFill(1, 0), SetMinimalSize(50, 12), SetResize(1, 0), + SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_MAUVE, WID_GS_OPTIONSPANEL), SetMinimalSize(400, 174), SetScrollbar(WID_GS_SCROLLBAR), EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_GS_SCROLLBAR), + EndContainer(), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_MAUVE), SetMinimalSize(400, 40), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GS_HELP_TEXT), SetMinimalSize(300, 25), SetFill(1, 1), SetResize(1, 0), + SetPadding(WD_FRAMETEXT_TOP, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_BOTTOM, WD_FRAMETEXT_LEFT), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_MAUVE), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_GS_EXPAND_ALL), SetDataTip(STR_CONFIG_SETTING_EXPAND_ALL, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_GS_COLLAPSE_ALL), SetDataTip(STR_CONFIG_SETTING_COLLAPSE_ALL, STR_NULL), + NWidget(NWID_SPACER, INVALID_COLOUR), SetFill(1, 1), SetResize(1, 0), + EndContainer(), + EndContainer(), + NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), + EndContainer(), + EndContainer(), +}; + +static WindowDesc _settings_selection_desc( + WDP_CENTER, "settings", 510, 450, + WC_GAME_OPTIONS, WC_NONE, + 0, + _nested_settings_selection_widgets, lengthof(_nested_settings_selection_widgets) +); + +/** Open advanced settings window. */ +void ShowGameSettings() +{ + DeleteWindowByClass(WC_GAME_OPTIONS); + new GameSettingsWindow(&_settings_selection_desc); +} + + +/** + * Draw [<][>] boxes. + * @param x the x position to draw + * @param y the y position to draw + * @param button_colour the colour of the button + * @param state 0 = none clicked, 1 = first clicked, 2 = second clicked + * @param clickable_left is the left button clickable? + * @param clickable_right is the right button clickable? + */ +void DrawArrowButtons(int x, int y, Colours button_colour, byte state, bool clickable_left, bool clickable_right) +{ + int colour = _colour_gradient[button_colour][2]; + int half_button = SETTING_BUTTON_WIDTH / 2; + + DrawFrameRect(x, y, x + half_button - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, (state == 1) ? FR_LOWERED : FR_NONE); + DrawFrameRect(x + half_button, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, (state == 2) ? FR_LOWERED : FR_NONE); + Dimension d = GetSpriteSize(SPR_ARROW_LEFT); + DrawSprite(SPR_ARROW_LEFT, PAL_NONE, Center(x, half_button, d.width), Center(y, SETTING_BUTTON_HEIGHT, d.height)); + DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, Center(x + half_button, half_button, d.width), Center(y, SETTING_BUTTON_HEIGHT, d.height)); + + /* Grey out the buttons that aren't clickable */ + bool rtl = _current_text_dir == TD_RTL; + if (rtl ? !clickable_right : !clickable_left) { + GfxFillRect(x + 1, y, x + SETTING_BUTTON_WIDTH / 2 - 1, y + SETTING_BUTTON_HEIGHT - 2, colour, FILLRECT_CHECKER); + } + if (rtl ? !clickable_left : !clickable_right) { + GfxFillRect(x + SETTING_BUTTON_WIDTH / 2 + 1, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 2, colour, FILLRECT_CHECKER); + } +} + +/** + * Draw a dropdown button. + * @param x the x position to draw + * @param y the y position to draw + * @param button_colour the colour of the button + * @param state true = lowered + * @param clickable is the button clickable? + */ +void DrawDropDownButton(int x, int y, Colours button_colour, bool state, bool clickable) +{ + static const char *DOWNARROW = "\xEE\x8A\xAA"; + + int colour = _colour_gradient[button_colour][2]; + + DrawFrameRect(x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, state ? FR_LOWERED : FR_NONE); + DrawString(x + (state ? 1 : 0), x + SETTING_BUTTON_WIDTH - (state ? 0 : 1), y + (state ? 2 : 1), DOWNARROW, TC_BLACK, SA_HOR_CENTER); + + if (!clickable) { + GfxFillRect(x + 1, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 2, colour, FILLRECT_CHECKER); + } +} + +/** + * Draw a toggle button. + * @param x the x position to draw + * @param y the y position to draw + * @param state true = lowered + * @param clickable is the button clickable? + */ +void DrawBoolButton(int x, int y, bool state, bool clickable) +{ + static const Colours _bool_ctabs[2][2] = {{COLOUR_CREAM, COLOUR_RED}, {COLOUR_DARK_GREEN, COLOUR_GREEN}}; + DrawFrameRect(x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1, _bool_ctabs[state][clickable], state ? FR_LOWERED : FR_NONE); +} + +struct CustomCurrencyWindow : Window { + int query_widget; + + CustomCurrencyWindow(WindowDesc *desc) : Window(desc) + { + this->InitNested(); + + SetButtonState(); + } + + void SetButtonState() + { + this->SetWidgetDisabledState(WID_CC_RATE_DOWN, _custom_currency.rate == 1); + this->SetWidgetDisabledState(WID_CC_RATE_UP, _custom_currency.rate == UINT16_MAX); + this->SetWidgetDisabledState(WID_CC_YEAR_DOWN, _custom_currency.to_euro == CF_NOEURO); + this->SetWidgetDisabledState(WID_CC_YEAR_UP, _custom_currency.to_euro == MAX_YEAR); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_CC_RATE: SetDParam(0, 1); SetDParam(1, 1); break; + case WID_CC_SEPARATOR: SetDParamStr(0, _custom_currency.separator); break; + case WID_CC_PREFIX: SetDParamStr(0, _custom_currency.prefix); break; + case WID_CC_SUFFIX: SetDParamStr(0, _custom_currency.suffix); break; + case WID_CC_YEAR: + SetDParam(0, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER); + SetDParam(1, _custom_currency.to_euro); + break; + + case WID_CC_PREVIEW: + SetDParam(0, 10000); + break; + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + /* Set the appropriate width for the edit 'buttons' */ + case WID_CC_SEPARATOR_EDIT: + case WID_CC_PREFIX_EDIT: + case WID_CC_SUFFIX_EDIT: + size->width = this->GetWidget(WID_CC_RATE_DOWN)->smallest_x + this->GetWidget(WID_CC_RATE_UP)->smallest_x; + break; + + /* Make sure the window is wide enough for the widest exchange rate */ + case WID_CC_RATE: + SetDParam(0, 1); + SetDParam(1, INT32_MAX); + *size = GetStringBoundingBox(STR_CURRENCY_EXCHANGE_RATE); + break; + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + int line = 0; + int len = 0; + StringID str = 0; + CharSetFilter afilter = CS_ALPHANUMERAL; + + switch (widget) { + case WID_CC_RATE_DOWN: + if (_custom_currency.rate > 1) _custom_currency.rate--; + if (_custom_currency.rate == 1) this->DisableWidget(WID_CC_RATE_DOWN); + this->EnableWidget(WID_CC_RATE_UP); + break; + + case WID_CC_RATE_UP: + if (_custom_currency.rate < UINT16_MAX) _custom_currency.rate++; + if (_custom_currency.rate == UINT16_MAX) this->DisableWidget(WID_CC_RATE_UP); + this->EnableWidget(WID_CC_RATE_DOWN); + break; + + case WID_CC_RATE: + SetDParam(0, _custom_currency.rate); + str = STR_JUST_INT; + len = 5; + line = WID_CC_RATE; + afilter = CS_NUMERAL; + break; + + case WID_CC_SEPARATOR_EDIT: + case WID_CC_SEPARATOR: + SetDParamStr(0, _custom_currency.separator); + str = STR_JUST_RAW_STRING; + len = 1; + line = WID_CC_SEPARATOR; + break; + + case WID_CC_PREFIX_EDIT: + case WID_CC_PREFIX: + SetDParamStr(0, _custom_currency.prefix); + str = STR_JUST_RAW_STRING; + len = 12; + line = WID_CC_PREFIX; + break; + + case WID_CC_SUFFIX_EDIT: + case WID_CC_SUFFIX: + SetDParamStr(0, _custom_currency.suffix); + str = STR_JUST_RAW_STRING; + len = 12; + line = WID_CC_SUFFIX; + break; + + case WID_CC_YEAR_DOWN: + _custom_currency.to_euro = (_custom_currency.to_euro <= 2000) ? CF_NOEURO : _custom_currency.to_euro - 1; + if (_custom_currency.to_euro == CF_NOEURO) this->DisableWidget(WID_CC_YEAR_DOWN); + this->EnableWidget(WID_CC_YEAR_UP); + break; + + case WID_CC_YEAR_UP: + _custom_currency.to_euro = Clamp(_custom_currency.to_euro + 1, 2000, MAX_YEAR); + if (_custom_currency.to_euro == MAX_YEAR) this->DisableWidget(WID_CC_YEAR_UP); + this->EnableWidget(WID_CC_YEAR_DOWN); + break; + + case WID_CC_YEAR: + SetDParam(0, _custom_currency.to_euro); + str = STR_JUST_INT; + len = 7; + line = WID_CC_YEAR; + afilter = CS_NUMERAL; + break; + } + + if (len != 0) { + this->query_widget = line; + ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, this, afilter, QSF_NONE); + } + + this->SetTimeout(); + this->SetDirty(); + } + + virtual void OnQueryTextFinished(char *str) + { + if (str == NULL) return; + + switch (this->query_widget) { + case WID_CC_RATE: + _custom_currency.rate = Clamp(atoi(str), 1, UINT16_MAX); + break; + + case WID_CC_SEPARATOR: // Thousands separator + strecpy(_custom_currency.separator, str, lastof(_custom_currency.separator)); + break; + + case WID_CC_PREFIX: + strecpy(_custom_currency.prefix, str, lastof(_custom_currency.prefix)); + break; + + case WID_CC_SUFFIX: + strecpy(_custom_currency.suffix, str, lastof(_custom_currency.suffix)); + break; + + case WID_CC_YEAR: { // Year to switch to euro + int val = atoi(str); + + _custom_currency.to_euro = (val < 2000 ? CF_NOEURO : min(val, MAX_YEAR)); + break; + } + } + MarkWholeScreenDirty(); + SetButtonState(); + } + + virtual void OnTimeout() + { + this->SetDirty(); + } +}; + +static const NWidgetPart _nested_cust_currency_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CURRENCY_WINDOW, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(7, 3, 0), + NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), + NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_RATE_DOWN), SetDataTip(AWV_DECREASE, STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_RATE_UP), SetDataTip(AWV_INCREASE, STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP), + NWidget(NWID_SPACER), SetMinimalSize(5, 0), + NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_RATE), SetDataTip(STR_CURRENCY_EXCHANGE_RATE, STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), + NWidget(WWT_PUSHBTN, COLOUR_DARK_BLUE, WID_CC_SEPARATOR_EDIT), SetDataTip(0x0, STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP), SetFill(0, 1), + NWidget(NWID_SPACER), SetMinimalSize(5, 0), + NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_SEPARATOR), SetDataTip(STR_CURRENCY_SEPARATOR, STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), + NWidget(WWT_PUSHBTN, COLOUR_DARK_BLUE, WID_CC_PREFIX_EDIT), SetDataTip(0x0, STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP), SetFill(0, 1), + NWidget(NWID_SPACER), SetMinimalSize(5, 0), + NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_PREFIX), SetDataTip(STR_CURRENCY_PREFIX, STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), + NWidget(WWT_PUSHBTN, COLOUR_DARK_BLUE, WID_CC_SUFFIX_EDIT), SetDataTip(0x0, STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP), SetFill(0, 1), + NWidget(NWID_SPACER), SetMinimalSize(5, 0), + NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_SUFFIX), SetDataTip(STR_CURRENCY_SUFFIX, STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), + NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_YEAR_DOWN), SetDataTip(AWV_DECREASE, STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_YEAR_UP), SetDataTip(AWV_INCREASE, STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP), + NWidget(NWID_SPACER), SetMinimalSize(5, 0), + NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_YEAR), SetDataTip(STR_JUST_STRING, STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP), SetFill(1, 0), + EndContainer(), + EndContainer(), + NWidget(WWT_LABEL, COLOUR_BLUE, WID_CC_PREVIEW), + SetDataTip(STR_CURRENCY_PREVIEW, STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP), SetPadding(15, 1, 18, 2), + EndContainer(), +}; + +static WindowDesc _cust_currency_desc( + WDP_CENTER, NULL, 0, 0, + WC_CUSTOM_CURRENCY, WC_NONE, + 0, + _nested_cust_currency_widgets, lengthof(_nested_cust_currency_widgets) +); + +/** Open custom currency window. */ +static void ShowCustCurrency() +{ + DeleteWindowById(WC_CUSTOM_CURRENCY, 0); + new CustomCurrencyWindow(&_cust_currency_desc); +} diff --git a/src/smallmap_gui.cpp.orig b/src/smallmap_gui.cpp.orig new file mode 100644 index 0000000000..b4137038fc --- /dev/null +++ b/src/smallmap_gui.cpp.orig @@ -0,0 +1,1827 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file smallmap_gui.cpp GUI that shows a small map of the world with metadata like owner or height. */ + +#include "stdafx.h" +#include "clear_map.h" +#include "industry.h" +#include "station_map.h" +#include "landscape.h" +#include "tree_map.h" +#include "viewport_func.h" +#include "town.h" +#include "tunnelbridge_map.h" +#include "core/endian_func.hpp" +#include "vehicle_base.h" +#include "sound_func.h" +#include "window_func.h" +#include "company_base.h" + +#include "smallmap_gui.h" + +#include "table/strings.h" + +static int _smallmap_industry_count; ///< Number of used industries +static int _smallmap_company_count; ///< Number of entries in the owner legend. +static int _smallmap_cargo_count; ///< Number of cargos in the link stats legend. + +/** Link stat colours shown in legenda. */ +static uint8 _linkstat_colours_in_legenda[] = {0, 1, 3, 5, 7, 9, 11}; + +static const int NUM_NO_COMPANY_ENTRIES = 4; ///< Number of entries in the owner legend that are not companies. + +static const uint8 PC_ROUGH_LAND = 0x52; ///< Dark green palette colour for rough land. +static const uint8 PC_GRASS_LAND = 0x54; ///< Dark green palette colour for grass land. +static const uint8 PC_BARE_LAND = 0x37; ///< Brown palette colour for bare land. +static const uint8 PC_FIELDS = 0x25; ///< Light brown palette colour for fields. +static const uint8 PC_TREES = 0x57; ///< Green palette colour for trees. +static const uint8 PC_WATER = 0xCA; ///< Dark blue palette colour for water. + +/** Macro for ordinary entry of LegendAndColour */ +#define MK(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false} + +/** Macro for a height legend entry with configurable colour. */ +#define MC(height) {0, STR_TINY_BLACK_HEIGHT, INVALID_INDUSTRYTYPE, height, INVALID_COMPANY, true, false, false} + +/** Macro for non-company owned property entry of LegendAndColour */ +#define MO(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false} + +/** Macro used for forcing a rebuild of the owner legend the first time it is used. */ +#define MOEND() {0, 0, INVALID_INDUSTRYTYPE, 0, OWNER_NONE, true, true, false} + +/** Macro for end of list marker in arrays of LegendAndColour */ +#define MKEND() {0, STR_NULL, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, true, false} + +/** + * Macro for break marker in arrays of LegendAndColour. + * It will have valid data, though + */ +#define MS(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, true} + +/** Legend text giving the colours to look for on the minimap */ +static LegendAndColour _legend_land_contours[] = { + /* The colours for the following values are set at BuildLandLegend() based on each colour scheme. */ + MC(0), + MC(4), + MC(8), + MC(12), + MC(14), + + MS(PC_BLACK, STR_SMALLMAP_LEGENDA_ROADS), + MK(PC_GREY, STR_SMALLMAP_LEGENDA_RAILROADS), + MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS), + MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES), + MK(PC_WHITE, STR_SMALLMAP_LEGENDA_VEHICLES), + MKEND() +}; + +static const LegendAndColour _legend_vehicles[] = { + MK(PC_RED, STR_SMALLMAP_LEGENDA_TRAINS), + MK(PC_YELLOW, STR_SMALLMAP_LEGENDA_ROAD_VEHICLES), + MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_SHIPS), + MK(PC_WHITE, STR_SMALLMAP_LEGENDA_AIRCRAFT), + + MS(PC_BLACK, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES), + MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES), + MKEND() +}; + +static const LegendAndColour _legend_routes[] = { + MK(PC_BLACK, STR_SMALLMAP_LEGENDA_ROADS), + MK(PC_GREY, STR_SMALLMAP_LEGENDA_RAILROADS), + MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES), + + MS(PC_VERY_DARK_BROWN, STR_SMALLMAP_LEGENDA_RAILROAD_STATION), + MK(PC_ORANGE, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY), + MK(PC_YELLOW, STR_SMALLMAP_LEGENDA_BUS_STATION), + MK(PC_RED, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT), + MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_DOCK), + MKEND() +}; + +static const LegendAndColour _legend_vegetation[] = { + MK(PC_ROUGH_LAND, STR_SMALLMAP_LEGENDA_ROUGH_LAND), + MK(PC_GRASS_LAND, STR_SMALLMAP_LEGENDA_GRASS_LAND), + MK(PC_BARE_LAND, STR_SMALLMAP_LEGENDA_BARE_LAND), + MK(PC_FIELDS, STR_SMALLMAP_LEGENDA_FIELDS), + MK(PC_TREES, STR_SMALLMAP_LEGENDA_TREES), + MK(PC_GREEN, STR_SMALLMAP_LEGENDA_FOREST), + + MS(PC_GREY, STR_SMALLMAP_LEGENDA_ROCKS), + MK(PC_ORANGE, STR_SMALLMAP_LEGENDA_DESERT), + MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_SNOW), + MK(PC_BLACK, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES), + MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES), + MKEND() +}; + +static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = { + MO(PC_WATER, STR_SMALLMAP_LEGENDA_WATER), + MO(0x00, STR_SMALLMAP_LEGENDA_NO_OWNER), // This colour will vary depending on settings. + MO(PC_DARK_RED, STR_SMALLMAP_LEGENDA_TOWNS), + MO(PC_DARK_GREY, STR_SMALLMAP_LEGENDA_INDUSTRIES), + /* The legend will be terminated the first time it is used. */ + MOEND(), +}; + +#undef MK +#undef MC +#undef MS +#undef MO +#undef MOEND +#undef MKEND + +/** Legend entries for the link stats view. */ +static LegendAndColour _legend_linkstats[NUM_CARGO + lengthof(_linkstat_colours_in_legenda) + 1]; +/** + * Allow room for all industries, plus a terminator entry + * This is required in order to have the industry slots all filled up + */ +static LegendAndColour _legend_from_industries[NUM_INDUSTRYTYPES + 1]; +/** For connecting industry type to position in industries list(small map legend) */ +static uint _industry_to_list_pos[NUM_INDUSTRYTYPES]; +/** Show heightmap in industry and owner mode of smallmap window. */ +static bool _smallmap_show_heightmap = false; +/** Highlight a specific industry type */ +static IndustryType _smallmap_industry_highlight = INVALID_INDUSTRYTYPE; +/** State of highlight blinking */ +static bool _smallmap_industry_highlight_state; +/** For connecting company ID to position in owner list (small map legend) */ +static uint _company_to_list_pos[MAX_COMPANIES]; + +/** + * Fills an array for the industries legends. + */ +void BuildIndustriesLegend() +{ + uint j = 0; + + /* Add each name */ + for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) { + IndustryType ind = _sorted_industry_types[i]; + const IndustrySpec *indsp = GetIndustrySpec(ind); + if (indsp->enabled) { + _legend_from_industries[j].legend = indsp->name; + _legend_from_industries[j].colour = indsp->map_colour; + _legend_from_industries[j].type = ind; + _legend_from_industries[j].show_on_map = true; + _legend_from_industries[j].col_break = false; + _legend_from_industries[j].end = false; + + /* Store widget number for this industry type. */ + _industry_to_list_pos[ind] = j; + j++; + } + } + /* Terminate the list */ + _legend_from_industries[j].end = true; + + /* Store number of enabled industries */ + _smallmap_industry_count = j; +} + +/** + * Populate legend table for the link stat view. + */ +void BuildLinkStatsLegend() +{ + /* Clear the legend */ + memset(_legend_linkstats, 0, sizeof(_legend_linkstats)); + + uint i = 0; + for (; i < _sorted_cargo_specs_size; ++i) { + const CargoSpec *cs = _sorted_cargo_specs[i]; + + _legend_linkstats[i].legend = cs->name; + _legend_linkstats[i].colour = cs->legend_colour; + _legend_linkstats[i].type = cs->Index(); + _legend_linkstats[i].show_on_map = true; + } + + _legend_linkstats[i].col_break = true; + _smallmap_cargo_count = i; + + for (; i < _smallmap_cargo_count + lengthof(_linkstat_colours_in_legenda); ++i) { + _legend_linkstats[i].legend = STR_EMPTY; + _legend_linkstats[i].colour = LinkGraphOverlay::LINK_COLOURS[_linkstat_colours_in_legenda[i - _smallmap_cargo_count]]; + _legend_linkstats[i].show_on_map = true; + } + + _legend_linkstats[_smallmap_cargo_count].legend = STR_LINKGRAPH_LEGEND_UNUSED; + _legend_linkstats[i - 1].legend = STR_LINKGRAPH_LEGEND_OVERLOADED; + _legend_linkstats[(_smallmap_cargo_count + i - 1) / 2].legend = STR_LINKGRAPH_LEGEND_SATURATED; + _legend_linkstats[i].end = true; +} + +static const LegendAndColour * const _legend_table[] = { + _legend_land_contours, + _legend_vehicles, + _legend_from_industries, + _legend_linkstats, + _legend_routes, + _legend_vegetation, + _legend_land_owners, +}; + +#define MKCOLOUR(x) TO_LE32X(x) + +#define MKCOLOUR_XXXX(x) (MKCOLOUR(0x01010101) * (uint)(x)) +#define MKCOLOUR_X0X0(x) (MKCOLOUR(0x01000100) * (uint)(x)) +#define MKCOLOUR_0X0X(x) (MKCOLOUR(0x00010001) * (uint)(x)) +#define MKCOLOUR_0XX0(x) (MKCOLOUR(0x00010100) * (uint)(x)) +#define MKCOLOUR_X00X(x) (MKCOLOUR(0x01000001) * (uint)(x)) + +#define MKCOLOUR_XYXY(x, y) (MKCOLOUR_X0X0(x) | MKCOLOUR_0X0X(y)) +#define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y)) + +#define MKCOLOUR_0000 MKCOLOUR_XXXX(0x00) +#define MKCOLOUR_0FF0 MKCOLOUR_0XX0(0xFF) +#define MKCOLOUR_F00F MKCOLOUR_X00X(0xFF) +#define MKCOLOUR_FFFF MKCOLOUR_XXXX(0xFF) + +/** Height map colours for the green colour scheme, ordered by height. */ +static const uint32 _green_map_heights[] = { + MKCOLOUR_XXXX(0x5A), + MKCOLOUR_XYXY(0x5A, 0x5B), + MKCOLOUR_XXXX(0x5B), + MKCOLOUR_XYXY(0x5B, 0x5C), + MKCOLOUR_XXXX(0x5C), + MKCOLOUR_XYXY(0x5C, 0x5D), + MKCOLOUR_XXXX(0x5D), + MKCOLOUR_XYXY(0x5D, 0x5E), + MKCOLOUR_XXXX(0x5E), + MKCOLOUR_XYXY(0x5E, 0x5F), + MKCOLOUR_XXXX(0x5F), + MKCOLOUR_XYXY(0x5F, 0x1F), + MKCOLOUR_XXXX(0x1F), + MKCOLOUR_XYXY(0x1F, 0x27), + MKCOLOUR_XXXX(0x27), + MKCOLOUR_XXXX(0x27), +}; +assert_compile(lengthof(_green_map_heights) == MAX_TILE_HEIGHT + 1); + +/** Height map colours for the dark green colour scheme, ordered by height. */ +static const uint32 _dark_green_map_heights[] = { + MKCOLOUR_XXXX(0x60), + MKCOLOUR_XYXY(0x60, 0x61), + MKCOLOUR_XXXX(0x61), + MKCOLOUR_XYXY(0x61, 0x62), + MKCOLOUR_XXXX(0x62), + MKCOLOUR_XYXY(0x62, 0x63), + MKCOLOUR_XXXX(0x63), + MKCOLOUR_XYXY(0x63, 0x64), + MKCOLOUR_XXXX(0x64), + MKCOLOUR_XYXY(0x64, 0x65), + MKCOLOUR_XXXX(0x65), + MKCOLOUR_XYXY(0x65, 0x66), + MKCOLOUR_XXXX(0x66), + MKCOLOUR_XYXY(0x66, 0x67), + MKCOLOUR_XXXX(0x67), + MKCOLOUR_XXXX(0x67), +}; +assert_compile(lengthof(_dark_green_map_heights) == MAX_TILE_HEIGHT + 1); + +/** Height map colours for the violet colour scheme, ordered by height. */ +static const uint32 _violet_map_heights[] = { + MKCOLOUR_XXXX(0x80), + MKCOLOUR_XYXY(0x80, 0x81), + MKCOLOUR_XXXX(0x81), + MKCOLOUR_XYXY(0x81, 0x82), + MKCOLOUR_XXXX(0x82), + MKCOLOUR_XYXY(0x82, 0x83), + MKCOLOUR_XXXX(0x83), + MKCOLOUR_XYXY(0x83, 0x84), + MKCOLOUR_XXXX(0x84), + MKCOLOUR_XYXY(0x84, 0x85), + MKCOLOUR_XXXX(0x85), + MKCOLOUR_XYXY(0x85, 0x86), + MKCOLOUR_XXXX(0x86), + MKCOLOUR_XYXY(0x86, 0x87), + MKCOLOUR_XXXX(0x87), + MKCOLOUR_XXXX(0x87), +}; +assert_compile(lengthof(_violet_map_heights) == MAX_TILE_HEIGHT + 1); + +/** Colour scheme of the smallmap. */ +struct SmallMapColourScheme { + const uint32 *height_colours; ///< Colour of each level in a heightmap. + uint32 default_colour; ///< Default colour of the land. +}; + +/** Available colour schemes for height maps. */ +static const SmallMapColourScheme _heightmap_schemes[] = { + {_green_map_heights, MKCOLOUR_XXXX(0x54)}, ///< Green colour scheme. + {_dark_green_map_heights, MKCOLOUR_XXXX(0x62)}, ///< Dark green colour scheme. + {_violet_map_heights, MKCOLOUR_XXXX(0x82)}, ///< Violet colour scheme. +}; + +/** + * (Re)build the colour tables for the legends. + */ +void BuildLandLegend() +{ + for (LegendAndColour *lc = _legend_land_contours; lc->legend == STR_TINY_BLACK_HEIGHT; lc++) { + lc->colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[lc->height]; + } +} + +/** + * Completes the array for the owned property legend. + */ +void BuildOwnerLegend() +{ + _legend_land_owners[1].colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour; + + int i = NUM_NO_COMPANY_ENTRIES; + const Company *c; + FOR_ALL_COMPANIES(c) { + _legend_land_owners[i].colour = _colour_gradient[c->colour][5]; + _legend_land_owners[i].company = c->index; + _legend_land_owners[i].show_on_map = true; + _legend_land_owners[i].col_break = false; + _legend_land_owners[i].end = false; + _company_to_list_pos[c->index] = i; + i++; + } + + /* Terminate the list */ + _legend_land_owners[i].end = true; + + /* Store maximum amount of owner legend entries. */ + _smallmap_company_count = i; +} + +struct AndOr { + uint32 mor; + uint32 mand; +}; + +static inline uint32 ApplyMask(uint32 colour, const AndOr *mask) +{ + return (colour & mask->mand) | mask->mor; +} + + +/** Colour masks for "Contour" and "Routes" modes. */ +static const AndOr _smallmap_contours_andor[] = { + {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_CLEAR + {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F}, // MP_RAILWAY + {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_ROAD + {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_HOUSE + {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TREES + {MKCOLOUR_XXXX(PC_LIGHT_BLUE), MKCOLOUR_0000}, // MP_STATION + {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000}, // MP_WATER + {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_VOID + {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000}, // MP_INDUSTRY + {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE + {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_OBJECT + {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F}, +}; + +/** Colour masks for "Vehicles", "Industry", and "Vegetation" modes. */ +static const AndOr _smallmap_vehicles_andor[] = { + {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_CLEAR + {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_RAILWAY + {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_ROAD + {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_HOUSE + {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TREES + {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_STATION + {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000}, // MP_WATER + {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_VOID + {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000}, // MP_INDUSTRY + {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE + {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_OBJECT + {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, +}; + +/** Mapping of tile type to importance of the tile (higher number means more interesting to show). */ +static const byte _tiletype_importance[] = { + 2, // MP_CLEAR + 8, // MP_RAILWAY + 7, // MP_ROAD + 5, // MP_HOUSE + 2, // MP_TREES + 9, // MP_STATION + 2, // MP_WATER + 1, // MP_VOID + 6, // MP_INDUSTRY + 8, // MP_TUNNELBRIDGE + 2, // MP_OBJECT + 0, +}; + + +static inline TileType GetEffectiveTileType(TileIndex tile) +{ + TileType t = GetTileType(tile); + + if (t == MP_TUNNELBRIDGE) { + TransportType tt = GetTunnelBridgeTransportType(tile); + + switch (tt) { + case TRANSPORT_RAIL: t = MP_RAILWAY; break; + case TRANSPORT_ROAD: t = MP_ROAD; break; + default: t = MP_WATER; break; + } + } + return t; +} + +/** + * Return the colour a tile would be displayed with in the small map in mode "Contour". + * @param tile The tile of which we would like to get the colour. + * @param t Effective tile type of the tile (see #GetEffectiveTileType). + * @return The colour of tile in the small map in mode "Contour" + */ +static inline uint32 GetSmallMapContoursPixels(TileIndex tile, TileType t) +{ + const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; + return ApplyMask(cs->height_colours[TileHeight(tile)], &_smallmap_contours_andor[t]); +} + +/** + * Return the colour a tile would be displayed with in the small map in mode "Vehicles". + * + * @param tile The tile of which we would like to get the colour. + * @param t Effective tile type of the tile (see #GetEffectiveTileType). + * @return The colour of tile in the small map in mode "Vehicles" + */ +static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile, TileType t) +{ + const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; + return ApplyMask(cs->default_colour, &_smallmap_vehicles_andor[t]); +} + +/** + * Return the colour a tile would be displayed with in the small map in mode "Industries". + * + * @param tile The tile of which we would like to get the colour. + * @param t Effective tile type of the tile (see #GetEffectiveTileType). + * @return The colour of tile in the small map in mode "Industries" + */ +static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile, TileType t) +{ + if (t == MP_INDUSTRY) { + /* If industry is allowed to be seen, use its colour on the map */ + IndustryType type = Industry::GetByTile(tile)->type; + if (_legend_from_industries[_industry_to_list_pos[type]].show_on_map && + (_smallmap_industry_highlight_state || type != _smallmap_industry_highlight)) { + return (type == _smallmap_industry_highlight ? PC_WHITE : GetIndustrySpec(Industry::GetByTile(tile)->type)->map_colour) * 0x01010101; + } else { + /* Otherwise, return the colour which will make it disappear */ + t = (IsTileOnWater(tile) ? MP_WATER : MP_CLEAR); + } + } + + const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; + return ApplyMask(_smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour, &_smallmap_vehicles_andor[t]); +} + +/** + * Return the colour a tile would be displayed with in the small map in mode "Routes". + * + * @param tile The tile of which we would like to get the colour. + * @param t Effective tile type of the tile (see #GetEffectiveTileType). + * @return The colour of tile in the small map in mode "Routes" + */ +static inline uint32 GetSmallMapRoutesPixels(TileIndex tile, TileType t) +{ + if (t == MP_STATION) { + switch (GetStationType(tile)) { + case STATION_RAIL: return MKCOLOUR_XXXX(PC_VERY_DARK_BROWN); + case STATION_AIRPORT: return MKCOLOUR_XXXX(PC_RED); + case STATION_TRUCK: return MKCOLOUR_XXXX(PC_ORANGE); + case STATION_BUS: return MKCOLOUR_XXXX(PC_YELLOW); + case STATION_DOCK: return MKCOLOUR_XXXX(PC_LIGHT_BLUE); + default: return MKCOLOUR_FFFF; + } + } else if (t == MP_RAILWAY) { + AndOr andor = { + MKCOLOUR_0XX0(GetRailTypeInfo(GetRailType(tile))->map_colour), + _smallmap_contours_andor[t].mand + }; + + const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; + return ApplyMask(cs->default_colour, &andor); + } + + /* Ground colour */ + const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; + return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]); +} + +/** + * Return the colour a tile would be displayed with in the small map in mode "link stats". + * + * @param tile The tile of which we would like to get the colour. + * @param t Effective tile type of the tile (see #GetEffectiveTileType). + * @return The colour of tile in the small map in mode "link stats" + */ +static inline uint32 GetSmallMapLinkStatsPixels(TileIndex tile, TileType t) +{ + return _smallmap_show_heightmap ? GetSmallMapContoursPixels(tile, t) : GetSmallMapRoutesPixels(tile, t); +} + +static const uint32 _vegetation_clear_bits[] = { + MKCOLOUR_XXXX(PC_GRASS_LAND), ///< full grass + MKCOLOUR_XXXX(PC_ROUGH_LAND), ///< rough land + MKCOLOUR_XXXX(PC_GREY), ///< rocks + MKCOLOUR_XXXX(PC_FIELDS), ///< fields + MKCOLOUR_XXXX(PC_LIGHT_BLUE), ///< snow + MKCOLOUR_XXXX(PC_ORANGE), ///< desert + MKCOLOUR_XXXX(PC_GRASS_LAND), ///< unused + MKCOLOUR_XXXX(PC_GRASS_LAND), ///< unused +}; + +/** + * Return the colour a tile would be displayed with in the smallmap in mode "Vegetation". + * + * @param tile The tile of which we would like to get the colour. + * @param t Effective tile type of the tile (see #GetEffectiveTileType). + * @return The colour of tile in the smallmap in mode "Vegetation" + */ +static inline uint32 GetSmallMapVegetationPixels(TileIndex tile, TileType t) +{ + switch (t) { + case MP_CLEAR: + return (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) ? MKCOLOUR_XXXX(PC_BARE_LAND) : _vegetation_clear_bits[GetClearGround(tile)]; + + case MP_INDUSTRY: + return IsTileForestIndustry(tile) ? MKCOLOUR_XXXX(PC_GREEN) : MKCOLOUR_XXXX(PC_DARK_RED); + + case MP_TREES: + if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(tile) == TREE_GROUND_ROUGH_SNOW) { + return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR_XYYX(PC_LIGHT_BLUE, PC_TREES) : MKCOLOUR_XYYX(PC_ORANGE, PC_TREES); + } + return MKCOLOUR_XYYX(PC_GRASS_LAND, PC_TREES); + + default: + return ApplyMask(MKCOLOUR_XXXX(PC_GRASS_LAND), &_smallmap_vehicles_andor[t]); + } +} + +/** + * Return the colour a tile would be displayed with in the small map in mode "Owner". + * + * @param tile The tile of which we would like to get the colour. + * @param t Effective tile type of the tile (see #GetEffectiveTileType). + * @return The colour of tile in the small map in mode "Owner" + */ +static inline uint32 GetSmallMapOwnerPixels(TileIndex tile, TileType t) +{ + Owner o; + + switch (t) { + case MP_INDUSTRY: return MKCOLOUR_XXXX(PC_DARK_GREY); + case MP_HOUSE: return MKCOLOUR_XXXX(PC_DARK_RED); + default: o = GetTileOwner(tile); break; + /* FIXME: For MP_ROAD there are multiple owners. + * GetTileOwner returns the rail owner (level crossing) resp. the owner of ROADTYPE_ROAD (normal road), + * even if there are no ROADTYPE_ROAD bits on the tile. + */ + } + + if ((o < MAX_COMPANIES && !_legend_land_owners[_company_to_list_pos[o]].show_on_map) || o == OWNER_NONE || o == OWNER_WATER) { + if (t == MP_WATER) return MKCOLOUR_XXXX(PC_WATER); + const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; + return _smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour; + } else if (o == OWNER_TOWN) { + return MKCOLOUR_XXXX(PC_DARK_RED); + } + + return MKCOLOUR_XXXX(_legend_land_owners[_company_to_list_pos[o]].colour); +} + +/** Vehicle colours in #SMT_VEHICLES mode. Indexed by #VehicleTypeByte. */ +static const byte _vehicle_type_colours[6] = { + PC_RED, PC_YELLOW, PC_LIGHT_BLUE, PC_WHITE, PC_BLACK, PC_RED +}; + + +inline Point SmallMapWindow::SmallmapRemapCoords(int x, int y) const +{ + Point pt; + pt.x = (y - x) * 2; + pt.y = y + x; + return pt; +} + +/** + * Remap tile to location on this smallmap. + * @param tile_x X coordinate of the tile. + * @param tile_y Y coordinate of the tile. + * @return Position to draw on. + */ +inline Point SmallMapWindow::RemapTile(int tile_x, int tile_y) const +{ + int x_offset = tile_x - this->scroll_x / (int)TILE_SIZE; + int y_offset = tile_y - this->scroll_y / (int)TILE_SIZE; + + if (this->zoom == 1) return SmallmapRemapCoords(x_offset, y_offset); + + /* For negative offsets, round towards -inf. */ + if (x_offset < 0) x_offset -= this->zoom - 1; + if (y_offset < 0) y_offset -= this->zoom - 1; + + return SmallmapRemapCoords(x_offset / this->zoom, y_offset / this->zoom); +} + +/** + * Determine the tile relative to the base tile of the smallmap, and the pixel position at + * that tile for a point in the smallmap. + * @param px Horizontal coordinate of the pixel. + * @param py Vertical coordinate of the pixel. + * @param sub[out] Pixel position at the tile (0..3). + * @param add_sub Add current #subscroll to the position. + * @return Tile being displayed at the given position relative to #scroll_x and #scroll_y. + * @note The #subscroll offset is already accounted for. + */ +inline Point SmallMapWindow::PixelToTile(int px, int py, int *sub, bool add_sub) const +{ + if (add_sub) px += this->subscroll; // Total horizontal offset. + + /* For each two rows down, add a x and a y tile, and + * For each four pixels to the right, move a tile to the right. */ + Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom}; + px &= 3; + + if (py & 1) { // Odd number of rows, handle the 2 pixel shift. + if (px < 2) { + pt.x += this->zoom; + px += 2; + } else { + pt.y += this->zoom; + px -= 2; + } + } + + *sub = px; + return pt; +} + +/** + * Compute base parameters of the smallmap such that tile (\a tx, \a ty) starts at pixel (\a x, \a y). + * @param tx Tile x coordinate. + * @param ty Tile y coordinate. + * @param x Non-negative horizontal position in the display where the tile starts. + * @param y Non-negative vertical position in the display where the tile starts. + * @param sub [out] Value of #subscroll needed. + * @return #scroll_x, #scroll_y values. + */ +Point SmallMapWindow::ComputeScroll(int tx, int ty, int x, int y, int *sub) +{ + assert(x >= 0 && y >= 0); + + int new_sub; + Point tile_xy = PixelToTile(x, y, &new_sub, false); + tx -= tile_xy.x; + ty -= tile_xy.y; + + Point scroll; + if (new_sub == 0) { + *sub = 0; + scroll.x = (tx + this->zoom) * TILE_SIZE; + scroll.y = (ty - this->zoom) * TILE_SIZE; + } else { + *sub = 4 - new_sub; + scroll.x = (tx + 2 * this->zoom) * TILE_SIZE; + scroll.y = (ty - 2 * this->zoom) * TILE_SIZE; + } + return scroll; +} + +/** + * Initialize or change the zoom level. + * @param change Way to change the zoom level. + * @param zoom_pt Position to keep fixed while zooming. + * @pre \c *zoom_pt should contain a point in the smallmap display when zooming in or out. + */ +void SmallMapWindow::SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt) +{ + static const int zoomlevels[] = {1, 2, 4, 6, 8}; // Available zoom levels. Bigger number means more zoom-out (further away). + static const int MIN_ZOOM_INDEX = 0; + static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1; + + int new_index, cur_index, sub; + Point tile; + switch (change) { + case ZLC_INITIALIZE: + cur_index = - 1; // Definitely different from new_index. + new_index = MIN_ZOOM_INDEX; + tile.x = tile.y = 0; + break; + + case ZLC_ZOOM_IN: + case ZLC_ZOOM_OUT: + for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) { + if (this->zoom == zoomlevels[cur_index]) break; + } + assert(cur_index <= MAX_ZOOM_INDEX); + + tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub); + new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX); + break; + + default: NOT_REACHED(); + } + + if (new_index != cur_index) { + this->zoom = zoomlevels[new_index]; + if (cur_index >= 0) { + Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub); + this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE, + this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub); + } else if (this->map_type == SMT_LINKSTATS) { + this->overlay->RebuildCache(); + } + this->SetWidgetDisabledState(WID_SM_ZOOM_IN, this->zoom == zoomlevels[MIN_ZOOM_INDEX]); + this->SetWidgetDisabledState(WID_SM_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]); + this->SetDirty(); + } +} + +/** + * Decide which colours to show to the user for a group of tiles. + * @param ta Tile area to investigate. + * @return Colours to display. + */ +inline uint32 SmallMapWindow::GetTileColours(const TileArea &ta) const +{ + int importance = 0; + TileIndex tile = INVALID_TILE; // Position of the most important tile. + TileType et = MP_VOID; // Effective tile type at that position. + + TILE_AREA_LOOP(ti, ta) { + TileType ttype = GetEffectiveTileType(ti); + if (_tiletype_importance[ttype] > importance) { + importance = _tiletype_importance[ttype]; + tile = ti; + et = ttype; + } + } + + switch (this->map_type) { + case SMT_CONTOUR: + return GetSmallMapContoursPixels(tile, et); + + case SMT_VEHICLES: + return GetSmallMapVehiclesPixels(tile, et); + + case SMT_INDUSTRY: + return GetSmallMapIndustriesPixels(tile, et); + + case SMT_LINKSTATS: + return GetSmallMapLinkStatsPixels(tile, et); + + case SMT_ROUTES: + return GetSmallMapRoutesPixels(tile, et); + + case SMT_VEGETATION: + return GetSmallMapVegetationPixels(tile, et); + + case SMT_OWNER: + return GetSmallMapOwnerPixels(tile, et); + + default: NOT_REACHED(); + } +} + +/** + * Draws one column of tiles of the small map in a certain mode onto the screen buffer, skipping the shifted rows in between. + * + * @param dst Pointer to a part of the screen buffer to write to. + * @param xc The X coordinate of the first tile in the column. + * @param yc The Y coordinate of the first tile in the column + * @param pitch Number of pixels to advance in the screen buffer each time a pixel is written. + * @param reps Number of lines to draw + * @param start_pos Position of first pixel to draw. + * @param end_pos Position of last pixel to draw (exclusive). + * @param blitter current blitter + * @note If pixel position is below \c 0, skip drawing. + */ +void SmallMapWindow::DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const +{ + void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height); + uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0; + + do { + /* Check if the tile (xc,yc) is within the map range */ + if (xc >= MapMaxX() || yc >= MapMaxY()) continue; + + /* Check if the dst pointer points to a pixel inside the screen buffer */ + if (dst < _screen.dst_ptr) continue; + if (dst >= dst_ptr_abs_end) continue; + + /* Construct tilearea covered by (xc, yc, xc + this->zoom, yc + this->zoom) such that it is within min_xy limits. */ + TileArea ta; + if (min_xy == 1 && (xc == 0 || yc == 0)) { + if (this->zoom == 1) continue; // The tile area is empty, don't draw anything. + + ta = TileArea(TileXY(max(min_xy, xc), max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0)); + } else { + ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom); + } + ta.ClampToMap(); // Clamp to map boundaries (may contain MP_VOID tiles!). + + uint32 val = this->GetTileColours(ta); + uint8 *val8 = (uint8 *)&val; + int idx = max(0, -start_pos); + for (int pos = max(0, start_pos); pos < end_pos; pos++) { + blitter->SetPixel(dst, idx, 0, val8[idx]); + idx++; + } + /* Switch to next tile in the column */ + } while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0); +} + +/** + * Adds vehicles to the smallmap. + * @param dpi the part of the smallmap to be drawn into + * @param blitter current blitter + */ +void SmallMapWindow::DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const +{ + const Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_EFFECT) continue; + if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue; + + /* Remap into flat coordinates. */ + Point pt = this->RemapTile(v->x_pos / TILE_SIZE, v->y_pos / TILE_SIZE); + + int y = pt.y - dpi->top; + if (!IsInsideMM(y, 0, dpi->height)) continue; // y is out of bounds. + + bool skip = false; // Default is to draw both pixels. + int x = pt.x - this->subscroll - 3 - dpi->left; // Offset X coordinate. + if (x < 0) { + /* if x+1 is 0, that means we're on the very left edge, + * and should thus only draw a single pixel */ + if (++x != 0) continue; + skip = true; + } else if (x >= dpi->width - 1) { + /* Check if we're at the very right edge, and if so draw only a single pixel */ + if (x != dpi->width - 1) continue; + skip = true; + } + + /* Calculate pointer to pixel and the colour */ + byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE; + + /* And draw either one or two pixels depending on clipping */ + blitter->SetPixel(dpi->dst_ptr, x, y, colour); + if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour); + } +} + +/** + * Adds town names to the smallmap. + * @param dpi the part of the smallmap to be drawn into + */ +void SmallMapWindow::DrawTowns(const DrawPixelInfo *dpi) const +{ + const Town *t; + FOR_ALL_TOWNS(t) { + /* Remap the town coordinate */ + Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy)); + int x = pt.x - this->subscroll - (t->cache.sign.width_small >> 1); + int y = pt.y; + + /* Check if the town sign is within bounds */ + if (x + t->cache.sign.width_small > dpi->left && + x < dpi->left + dpi->width && + y + FONT_HEIGHT_SMALL > dpi->top && + y < dpi->top + dpi->height) { + /* And draw it. */ + SetDParam(0, t->index); + DrawString(x, x + t->cache.sign.width_small, y, STR_SMALLMAP_TOWN); + } + } +} + +/** + * Adds map indicators to the smallmap. + */ +void SmallMapWindow::DrawMapIndicators() const +{ + /* Find main viewport. */ + const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; + + Point tile = InverseRemapCoords(vp->virtual_left, vp->virtual_top); + Point tl = this->RemapTile(tile.x >> 4, tile.y >> 4); + tl.x -= this->subscroll; + + tile = InverseRemapCoords(vp->virtual_left + vp->virtual_width, vp->virtual_top + vp->virtual_height); + Point br = this->RemapTile(tile.x >> 4, tile.y >> 4); + br.x -= this->subscroll; + + SmallMapWindow::DrawVertMapIndicator(tl.x, tl.y, br.y); + SmallMapWindow::DrawVertMapIndicator(br.x, tl.y, br.y); + + SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, tl.y); + SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, br.y); +} + +/** + * Draws the small map. + * + * Basically, the small map is draw column of pixels by column of pixels. The pixels + * are drawn directly into the screen buffer. The final map is drawn in multiple passes. + * The passes are: + *
  1. The colours of tiles in the different modes.
  2. + *
  3. Town names (optional)
+ * + * @param dpi pointer to pixel to write onto + */ +void SmallMapWindow::DrawSmallMap(DrawPixelInfo *dpi) const +{ + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + DrawPixelInfo *old_dpi; + + old_dpi = _cur_dpi; + _cur_dpi = dpi; + + /* Clear it */ + GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, PC_BLACK); + + /* Which tile is displayed at (dpi->left, dpi->top)? */ + int dx; + Point tile = this->PixelToTile(dpi->left, dpi->top, &dx); + int tile_x = this->scroll_x / (int)TILE_SIZE + tile.x; + int tile_y = this->scroll_y / (int)TILE_SIZE + tile.y; + + void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0); + int x = - dx - 4; + int y = 0; + + for (;;) { + /* Distance from left edge */ + if (x >= -3) { + if (x >= dpi->width) break; // Exit the loop. + + int end_pos = min(dpi->width, x + 4); + int reps = (dpi->height - y + 1) / 2; // Number of lines. + if (reps > 0) { + this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter); + } + } + + if (y == 0) { + tile_y += this->zoom; + y++; + ptr = blitter->MoveTo(ptr, 0, 1); + } else { + tile_x -= this->zoom; + y--; + ptr = blitter->MoveTo(ptr, 0, -1); + } + ptr = blitter->MoveTo(ptr, 2, 0); + x += 2; + } + + /* Draw vehicles */ + if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter); + + /* Draw link stat overlay */ + if (this->map_type == SMT_LINKSTATS) this->overlay->Draw(dpi); + + /* Draw town names */ + if (this->show_towns) this->DrawTowns(dpi); + + /* Draw map indicators */ + this->DrawMapIndicators(); + + _cur_dpi = old_dpi; +} + +/** + * Function to set up widgets depending on the information being shown on the smallmap. + */ +void SmallMapWindow::SetupWidgetData() +{ + StringID legend_tooltip; + StringID enable_all_tooltip; + StringID disable_all_tooltip; + int plane; + switch (this->map_type) { + case SMT_INDUSTRY: + legend_tooltip = STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION; + enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES; + disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES; + plane = 0; + break; + + case SMT_OWNER: + legend_tooltip = STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION; + enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES; + disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES; + plane = 0; + break; + + case SMT_LINKSTATS: + legend_tooltip = STR_SMALLMAP_TOOLTIP_CARGO_SELECTION; + enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS; + disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS; + plane = 0; + break; + + default: + legend_tooltip = STR_NULL; + enable_all_tooltip = STR_NULL; + disable_all_tooltip = STR_NULL; + plane = 1; + break; + } + + this->GetWidget(WID_SM_LEGEND)->SetDataTip(STR_NULL, legend_tooltip); + this->GetWidget(WID_SM_ENABLE_ALL)->SetDataTip(STR_SMALLMAP_ENABLE_ALL, enable_all_tooltip); + this->GetWidget(WID_SM_DISABLE_ALL)->SetDataTip(STR_SMALLMAP_DISABLE_ALL, disable_all_tooltip); + this->GetWidget(WID_SM_SELECT_BUTTONS)->SetDisplayedPlane(plane); +} + +SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : Window(desc), refresh(FORCE_REFRESH_PERIOD) +{ + _smallmap_industry_highlight = INVALID_INDUSTRYTYPE; + this->overlay = new LinkGraphOverlay(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1); + this->InitNested(window_number); + this->LowerWidget(this->map_type + WID_SM_CONTOUR); + + BuildLandLegend(); + this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap); + + this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns); + + this->SetupWidgetData(); + + this->SetZoomLevel(ZLC_INITIALIZE, NULL); + this->SmallMapCenterOnCurrentPos(); + this->SetOverlayCargoMask(); +} + +/* virtual */ void SmallMapWindow::SetStringParameters(int widget) const +{ + switch (widget) { + case WID_SM_CAPTION: + SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type); + break; + } +} + +/* virtual */ void SmallMapWindow::OnInit() +{ + uint min_width = 0; + this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS; + this->min_number_of_fixed_rows = lengthof(_linkstat_colours_in_legenda); + for (uint i = 0; i < lengthof(_legend_table); i++) { + uint height = 0; + uint num_columns = 1; + for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) { + StringID str; + if (i == SMT_INDUSTRY) { + SetDParam(0, tbl->legend); + SetDParam(1, IndustryPool::MAX_SIZE); + str = STR_SMALLMAP_INDUSTRY; + } else if (i == SMT_LINKSTATS) { + SetDParam(0, tbl->legend); + str = STR_SMALLMAP_LINKSTATS; + } else if (i == SMT_OWNER) { + if (tbl->company != INVALID_COMPANY) { + if (!Company::IsValidID(tbl->company)) { + /* Rebuild the owner legend. */ + BuildOwnerLegend(); + this->OnInit(); + return; + } + /* Non-fixed legend entries for the owner view. */ + SetDParam(0, tbl->company); + str = STR_SMALLMAP_COMPANY; + } else { + str = tbl->legend; + } + } else { + if (tbl->col_break) { + this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height); + height = 0; + num_columns++; + } + height++; + str = tbl->legend; + } + min_width = max(GetStringBoundingBox(str).width, min_width); + } + this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height); + this->min_number_of_columns = max(this->min_number_of_columns, num_columns); + } + + /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */ + this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; +} + +/* virtual */ void SmallMapWindow::OnPaint() +{ + if (this->map_type == SMT_OWNER) { + for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) { + if (tbl->company != INVALID_COMPANY && !Company::IsValidID(tbl->company)) { + /* Rebuild the owner legend. */ + BuildOwnerLegend(); + this->InvalidateData(1); + break; + } + } + } + + this->DrawWidgets(); +} + +/* virtual */ void SmallMapWindow::DrawWidget(const Rect &r, int widget) const +{ + switch (widget) { + case WID_SM_MAP: { + DrawPixelInfo new_dpi; + if (!FillDrawPixelInfo(&new_dpi, r.left + 1, r.top + 1, r.right - r.left - 1, r.bottom - r.top - 1)) return; + this->DrawSmallMap(&new_dpi); + break; + } + + case WID_SM_LEGEND: { + uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1); + uint number_of_rows = this->GetNumberRowsLegend(columns); + bool rtl = _current_text_dir == TD_RTL; + uint y_org = r.top + WD_FRAMERECT_TOP; + uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT; + uint y = y_org; + uint i = 0; // Row counter for industry legend. + uint row_height = FONT_HEIGHT_SMALL; + + uint text_left = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT; + uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0); + uint blob_left = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0; + uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH; + + StringID string = STR_NULL; + switch (this->map_type) { + case SMT_INDUSTRY: + string = STR_SMALLMAP_INDUSTRY; + break; + case SMT_LINKSTATS: + string = STR_SMALLMAP_LINKSTATS; + break; + case SMT_OWNER: + string = STR_SMALLMAP_COMPANY; + break; + default: + break; + } + + for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) { + if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER || this->map_type == SMT_LINKSTATS) && i++ >= number_of_rows)) { + /* Column break needed, continue at top, COLUMN_WIDTH pixels + * (one "row") to the right. */ + x += rtl ? -(int)this->column_width : this->column_width; + y = y_org; + i = 1; + } + + uint8 legend_colour = tbl->colour; + + switch (this->map_type) { + case SMT_INDUSTRY: + /* Industry name must be formatted, since it's not in tiny font in the specs. + * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font */ + SetDParam(0, tbl->legend); + SetDParam(1, Industry::GetIndustryTypeCount(tbl->type)); + if (tbl->show_on_map && tbl->type == _smallmap_industry_highlight) { + legend_colour = _smallmap_industry_highlight_state ? PC_WHITE : PC_BLACK; + } + /* FALL THROUGH */ + case SMT_LINKSTATS: + SetDParam(0, tbl->legend); + /* FALL_THROUGH */ + case SMT_OWNER: + if (this->map_type != SMT_OWNER || tbl->company != INVALID_COMPANY) { + if (this->map_type == SMT_OWNER) SetDParam(0, tbl->company); + if (!tbl->show_on_map) { + /* Simply draw the string, not the black border of the legend colour. + * This will enforce the idea of the disabled item */ + DrawString(x + text_left, x + text_right, y, string, TC_GREY); + } else { + DrawString(x + text_left, x + text_right, y, string, TC_BLACK); + GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK); // Outer border of the legend colour + } + break; + } + /* FALL_THROUGH */ + default: + if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP); + /* Anything that is not an industry or a company is using normal process */ + GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK); + DrawString(x + text_left, x + text_right, y, tbl->legend); + break; + } + GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, legend_colour); // Legend colour + + y += row_height; + } + } + } +} + +/** + * Select a new map type. + * @param map_type New map type. + */ +void SmallMapWindow::SwitchMapType(SmallMapType map_type) +{ + this->RaiseWidget(this->map_type + WID_SM_CONTOUR); + this->map_type = map_type; + this->LowerWidget(this->map_type + WID_SM_CONTOUR); + + this->SetupWidgetData(); + + if (map_type == SMT_LINKSTATS) this->overlay->RebuildCache(); + this->SetDirty(); +} + +/** + * Get the number of rows in the legend from the number of columns. Those + * are at least min_number_of_fixed_rows and possibly more if there are so + * many cargoes, industry types or companies that they won't fit in the + * available space. + * @param columns Number of columns in the legend. + * @return Number of rows needed for everything to fit in. + */ +inline uint SmallMapWindow::GetNumberRowsLegend(uint columns) const +{ + /* Reserve one column for link colours */ + uint num_rows_linkstats = CeilDiv(_smallmap_cargo_count, columns - 1); + uint num_rows_others = CeilDiv(max(_smallmap_industry_count, _smallmap_company_count), columns); + return max(this->min_number_of_fixed_rows, max(num_rows_linkstats, num_rows_others)); +} + +/** + * Select and toggle a legend item. When CTRL is pressed, disable all other + * items in the group defined by begin_legend_item and end_legend_item and + * keep the clicked one enabled even if it was already enabled before. If + * the other items in the group are all disabled already and CTRL is pressed + * enable them instead. + * @param click_pos the index of the item being selected + * @param legend the legend from which we select + * @param end_legend_item index one past the last item in the group to be inverted + * @param begin_legend_item index of the first item in the group to be inverted + */ +void SmallMapWindow::SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item) +{ + if (_ctrl_pressed) { + /* Disable all, except the clicked one */ + bool changes = false; + for (int i = begin_legend_item; i != end_legend_item; i++) { + bool new_state = (i == click_pos); + if (legend[i].show_on_map != new_state) { + changes = true; + legend[i].show_on_map = new_state; + } + } + if (!changes) { + /* Nothing changed? Then show all (again). */ + for (int i = begin_legend_item; i != end_legend_item; i++) { + legend[i].show_on_map = true; + } + } + } else { + legend[click_pos].show_on_map = !legend[click_pos].show_on_map; + } +} + +/** + * Set the link graph overlay cargo mask from the legend. + */ +void SmallMapWindow::SetOverlayCargoMask() +{ + uint32 cargo_mask = 0; + for (int i = 0; i != _smallmap_cargo_count; ++i) { + if (_legend_linkstats[i].show_on_map) SetBit(cargo_mask, _legend_linkstats[i].type); + } + this->overlay->SetCargoMask(cargo_mask); +} + +/** + * Determines the mouse position on the legend. + * @param pt Mouse position. + * @return Legend item under the mouse. + */ +int SmallMapWindow::GetPositionOnLegend(Point pt) +{ + const NWidgetBase *wi = this->GetWidget(WID_SM_LEGEND); + uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL; + uint columns = this->GetNumberColumnsLegend(wi->current_x); + uint number_of_rows = this->GetNumberRowsLegend(columns); + if (line >= number_of_rows) return -1; + + bool rtl = _current_text_dir == TD_RTL; + int x = pt.x - wi->pos_x; + if (rtl) x = wi->current_x - x; + uint column = (x - WD_FRAMERECT_LEFT) / this->column_width; + + return (column * number_of_rows) + line; +} + +/* virtual */ void SmallMapWindow::OnMouseOver(Point pt, int widget) +{ + IndustryType new_highlight = INVALID_INDUSTRYTYPE; + if (widget == WID_SM_LEGEND && this->map_type == SMT_INDUSTRY) { + int industry_pos = GetPositionOnLegend(pt); + if (industry_pos >= 0 && industry_pos < _smallmap_industry_count) { + new_highlight = _legend_from_industries[industry_pos].type; + } + } + if (new_highlight != _smallmap_industry_highlight) { + _smallmap_industry_highlight = new_highlight; + this->refresh = _smallmap_industry_highlight != INVALID_INDUSTRYTYPE ? BLINK_PERIOD : FORCE_REFRESH_PERIOD; + _smallmap_industry_highlight_state = true; + this->SetDirty(); + } +} + +/* virtual */ void SmallMapWindow::OnClick(Point pt, int widget, int click_count) +{ + /* User clicked something, notify the industry chain window to stop sending newly selected industries. */ + InvalidateWindowClassesData(WC_INDUSTRY_CARGOES, NUM_INDUSTRYTYPES); + + switch (widget) { + case WID_SM_MAP: { // Map window + /* + * XXX: scrolling with the left mouse button is done by subsequently + * clicking with the left mouse button; clicking once centers the + * large map at the selected point. So by unclicking the left mouse + * button here, it gets reclicked during the next inputloop, which + * would make it look like the mouse is being dragged, while it is + * actually being (virtually) clicked every inputloop. + */ + _left_button_clicked = false; + + const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); + Window *w = FindWindowById(WC_MAIN_WINDOW, 0); + int sub; + pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub); + pt = RemapCoords(this->scroll_x + pt.x * TILE_SIZE + this->zoom * (TILE_SIZE - sub * TILE_SIZE / 4), + this->scroll_y + pt.y * TILE_SIZE + sub * this->zoom * TILE_SIZE / 4, 0); + + w->viewport->follow_vehicle = INVALID_VEHICLE; + w->viewport->dest_scrollpos_x = pt.x - (w->viewport->virtual_width >> 1); + w->viewport->dest_scrollpos_y = pt.y - (w->viewport->virtual_height >> 1); + + this->SetDirty(); + break; + } + + case WID_SM_ZOOM_IN: + case WID_SM_ZOOM_OUT: { + const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); + Point pt = {wid->current_x / 2, wid->current_y / 2}; + this->SetZoomLevel((widget == WID_SM_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + break; + } + + case WID_SM_CONTOUR: // Show land contours + case WID_SM_VEHICLES: // Show vehicles + case WID_SM_INDUSTRIES: // Show industries + case WID_SM_LINKSTATS: // Show route map + case WID_SM_ROUTES: // Show transport routes + case WID_SM_VEGETATION: // Show vegetation + case WID_SM_OWNERS: // Show land owners + this->SwitchMapType((SmallMapType)(widget - WID_SM_CONTOUR)); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + break; + + case WID_SM_CENTERMAP: // Center the smallmap again + this->SmallMapCenterOnCurrentPos(); + this->HandleButtonClick(WID_SM_CENTERMAP); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + break; + + case WID_SM_TOGGLETOWNNAME: // Toggle town names + this->show_towns = !this->show_towns; + this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns); + + this->SetDirty(); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + break; + + case WID_SM_LEGEND: // Legend + if (this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER) { + int click_pos = this->GetPositionOnLegend(pt); + if (click_pos < 0) break; + + /* If industry type small map*/ + if (this->map_type == SMT_INDUSTRY) { + /* If click on industries label, find right industry type and enable/disable it. */ + if (click_pos < _smallmap_industry_count) { + this->SelectLegendItem(click_pos, _legend_from_industries, _smallmap_industry_count); + } + } else if (this->map_type == SMT_LINKSTATS) { + if (click_pos < _smallmap_cargo_count) { + this->SelectLegendItem(click_pos, _legend_linkstats, _smallmap_cargo_count); + this->SetOverlayCargoMask(); + } + } else if (this->map_type == SMT_OWNER) { + if (click_pos < _smallmap_company_count) { + this->SelectLegendItem(click_pos, _legend_land_owners, _smallmap_company_count, NUM_NO_COMPANY_ENTRIES); + } + } + this->SetDirty(); + } + break; + + case WID_SM_ENABLE_ALL: + /* FALL THROUGH */ + case WID_SM_DISABLE_ALL: { + LegendAndColour *tbl = NULL; + switch (this->map_type) { + case SMT_INDUSTRY: + tbl = _legend_from_industries; + break; + case SMT_OWNER: + tbl = &(_legend_land_owners[NUM_NO_COMPANY_ENTRIES]); + break; + case SMT_LINKSTATS: + tbl = _legend_linkstats; + break; + default: + NOT_REACHED(); + } + for (;!tbl->end && tbl->legend != STR_LINKGRAPH_LEGEND_UNUSED; ++tbl) { + tbl->show_on_map = (widget == WID_SM_ENABLE_ALL); + } + if (this->map_type == SMT_LINKSTATS) this->SetOverlayCargoMask(); + this->SetDirty(); + break; + } + + case WID_SM_SHOW_HEIGHT: // Enable/disable showing of heightmap. + _smallmap_show_heightmap = !_smallmap_show_heightmap; + this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap); + this->SetDirty(); + break; + } +} + +/** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * - data = 0: Displayed industries at the industry chain window have changed. + * - data = 1: Companies have changed. + * @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. + */ +/* virtual */ void SmallMapWindow::OnInvalidateData(int data, bool gui_scope) +{ + if (!gui_scope) return; + switch (data) { + case 1: + /* The owner legend has already been rebuilt. */ + this->ReInit(); + break; + + case 0: { + extern uint64 _displayed_industries; + if (this->map_type != SMT_INDUSTRY) this->SwitchMapType(SMT_INDUSTRY); + + for (int i = 0; i != _smallmap_industry_count; i++) { + _legend_from_industries[i].show_on_map = HasBit(_displayed_industries, _legend_from_industries[i].type); + } + break; + } + + default: NOT_REACHED(); + } + this->SetDirty(); +} + +/* virtual */ bool SmallMapWindow::OnRightClick(Point pt, int widget) +{ + if (widget != WID_SM_MAP || _scrolling_viewport) return false; + + _scrolling_viewport = true; + return true; +} + +/* virtual */ void SmallMapWindow::OnMouseWheel(int wheel) +{ + if (_settings_client.gui.scrollwheel_scrolling == 0) { + const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); + int cursor_x = _cursor.pos.x - this->left - wid->pos_x; + int cursor_y = _cursor.pos.y - this->top - wid->pos_y; + if (IsInsideMM(cursor_x, 0, wid->current_x) && IsInsideMM(cursor_y, 0, wid->current_y)) { + Point pt = {cursor_x, cursor_y}; + this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt); + } + } +} + +/* virtual */ void SmallMapWindow::OnTick() +{ + /* Update the window every now and then */ + if (--this->refresh != 0) return; + + if (this->map_type == SMT_LINKSTATS) { + uint32 company_mask = this->GetOverlayCompanyMask(); + if (this->overlay->GetCompanyMask() != company_mask) { + this->overlay->SetCompanyMask(company_mask); + } else { + this->overlay->RebuildCache(); + } + } + _smallmap_industry_highlight_state = !_smallmap_industry_highlight_state; + + this->refresh = _smallmap_industry_highlight != INVALID_INDUSTRYTYPE ? BLINK_PERIOD : FORCE_REFRESH_PERIOD; + this->SetDirty(); +} + +/** + * Set new #scroll_x, #scroll_y, and #subscroll values after limiting them such that the center + * of the smallmap always contains a part of the map. + * @param sx Proposed new #scroll_x + * @param sy Proposed new #scroll_y + * @param sub Proposed new #subscroll + */ +void SmallMapWindow::SetNewScroll(int sx, int sy, int sub) +{ + const NWidgetBase *wi = this->GetWidget(WID_SM_MAP); + Point hv = InverseRemapCoords(wi->current_x * ZOOM_LVL_BASE * TILE_SIZE / 2, wi->current_y * ZOOM_LVL_BASE * TILE_SIZE / 2); + hv.x *= this->zoom; + hv.y *= this->zoom; + + if (sx < -hv.x) { + sx = -hv.x; + sub = 0; + } + if (sx > (int)(MapMaxX() * TILE_SIZE) - hv.x) { + sx = MapMaxX() * TILE_SIZE - hv.x; + sub = 0; + } + if (sy < -hv.y) { + sy = -hv.y; + sub = 0; + } + if (sy > (int)(MapMaxY() * TILE_SIZE) - hv.y) { + sy = MapMaxY() * TILE_SIZE - hv.y; + sub = 0; + } + + this->scroll_x = sx; + this->scroll_y = sy; + this->subscroll = sub; + if (this->map_type == SMT_LINKSTATS) this->overlay->RebuildCache(); +} + +/* virtual */ void SmallMapWindow::OnScroll(Point delta) +{ + _cursor.fix_at = true; + + /* While tile is at (delta.x, delta.y)? */ + int sub; + Point pt = this->PixelToTile(delta.x, delta.y, &sub); + this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub); + + this->SetDirty(); +} + +void SmallMapWindow::SmallMapCenterOnCurrentPos() +{ + const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; + Point pt = InverseRemapCoords(vp->virtual_left + vp->virtual_width / 2, vp->virtual_top + vp->virtual_height / 2); + + int sub; + const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); + Point sxy = this->ComputeScroll(pt.x / TILE_SIZE, pt.y / TILE_SIZE, max(0, (int)wid->current_x / 2 - 2), wid->current_y / 2, &sub); + this->SetNewScroll(sxy.x, sxy.y, sub); + this->SetDirty(); +} + +/** + * Get the center of the given station as point on the screen in the smallmap window. + * @param st Station to find in the smallmap. + * @return Point with coordinates of the station. + */ +Point SmallMapWindow::GetStationMiddle(const Station *st) const +{ + int x = (st->rect.right + st->rect.left + 1) / 2; + int y = (st->rect.bottom + st->rect.top + 1) / 2; + Point ret = this->RemapTile(x, y); + + /* Same magic 3 as in DrawVehicles; that's where I got it from. + * No idea what it is, but without it the result looks bad. + */ + ret.x -= 3 + this->subscroll; + return ret; +} + +SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR; +bool SmallMapWindow::show_towns = true; + +/** + * Custom container class for displaying smallmap with a vertically resizing legend panel. + * The legend panel has a smallest height that depends on its width. Standard containers cannot handle this case. + * + * @note The container assumes it has two children, the first is the display, the second is the bar with legends and selection image buttons. + * Both children should be both horizontally and vertically resizable and horizontally fillable. + * The bar should have a minimal size with a zero-size legends display. Child padding is not supported. + */ +class NWidgetSmallmapDisplay : public NWidgetContainer { + const SmallMapWindow *smallmap_window; ///< Window manager instance. +public: + NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL) + { + this->smallmap_window = NULL; + } + + virtual void SetupSmallestSize(Window *w, bool init_array) + { + NWidgetBase *display = this->head; + NWidgetBase *bar = display->next; + + display->SetupSmallestSize(w, init_array); + bar->SetupSmallestSize(w, init_array); + + this->smallmap_window = dynamic_cast(w); + assert(this->smallmap_window != NULL); + this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth()); + this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetLegendHeight(smallmap_window->min_number_of_columns)); + this->fill_x = max(display->fill_x, bar->fill_x); + this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y); + this->resize_x = max(display->resize_x, bar->resize_x); + this->resize_y = min(display->resize_y, bar->resize_y); + } + + virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) + { + this->pos_x = x; + this->pos_y = y; + this->current_x = given_width; + this->current_y = given_height; + + NWidgetBase *display = this->head; + NWidgetBase *bar = display->next; + + if (sizing == ST_SMALLEST) { + this->smallest_x = given_width; + this->smallest_y = given_height; + /* Make display and bar exactly equal to their minimal size. */ + display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl); + bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl); + } + + uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(this->smallmap_window->GetNumberColumnsLegend(given_width - bar->smallest_x))); + uint display_height = given_height - bar_height; + display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl); + bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl); + } + + virtual NWidgetCore *GetWidgetFromPos(int x, int y) + { + if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y); + if (widget != NULL) return widget; + } + return NULL; + } + + virtual void Draw(const Window *w) + { + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w); + } +}; + +/** Widget parts of the smallmap display. */ +static const NWidgetPart _nested_smallmap_display[] = { + NWidget(WWT_PANEL, COLOUR_BROWN, WID_SM_MAP_BORDER), + NWidget(WWT_INSET, COLOUR_BROWN, WID_SM_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(), + EndContainer(), +}; + +/** Widget parts of the smallmap legend bar + image buttons. */ +static const NWidgetPart _nested_smallmap_bar[] = { + NWidget(WWT_PANEL, COLOUR_BROWN), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SM_LEGEND), SetResize(1, 1), + NWidget(NWID_VERTICAL), + /* Top button row. */ + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_IN), + SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetFill(1, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_CENTERMAP), + SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_BLANK), + SetDataTip(SPR_DOT_SMALL, STR_NULL), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_CONTOUR), + SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_VEHICLES), + SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_INDUSTRIES), + SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), SetFill(1, 1), + EndContainer(), + /* Bottom button row. */ + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_OUT), + SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_TOGGLETOWNNAME), + SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_LINKSTATS), + SetDataTip(SPR_IMG_CARGOFLOW, STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_ROUTES), + SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_VEGETATION), + SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_OWNERS), + SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP), SetFill(1, 1), + EndContainer(), + NWidget(NWID_SPACER), SetResize(0, 1), + EndContainer(), + EndContainer(), + EndContainer(), +}; + +static NWidgetBase *SmallMapDisplay(int *biggest_index) +{ + NWidgetContainer *map_display = new NWidgetSmallmapDisplay; + + MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display); + MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display); + return map_display; +} + + +static const NWidgetPart _nested_smallmap_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_BROWN), + NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SM_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_BROWN), + NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), + NWidget(WWT_STICKYBOX, COLOUR_BROWN), + EndContainer(), + NWidgetFunction(SmallMapDisplay), // Smallmap display and legend bar + image buttons. + /* Bottom button row and resize box. */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_BROWN), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SM_SELECT_BUTTONS), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SM_ENABLE_ALL), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SM_DISABLE_ALL), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_NULL), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SM_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT), + EndContainer(), + NWidget(NWID_SPACER), SetFill(1, 1), + EndContainer(), + NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0), + EndContainer(), + EndContainer(), + NWidget(WWT_RESIZEBOX, COLOUR_BROWN), + EndContainer(), +}; + +static WindowDesc _smallmap_desc( + WDP_AUTO, "smallmap", 484, 314, + WC_SMALLMAP, WC_NONE, + 0, + _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets) +); + +/** + * Show the smallmap window. + */ +void ShowSmallMap() +{ + AllocateWindowDescFront(&_smallmap_desc, 0); +} + +/** + * Scrolls the main window to given coordinates. + * @param x x coordinate + * @param y y coordinate + * @param z z coordinate; -1 to scroll to terrain height + * @param instant scroll instantly (meaningful only when smooth_scrolling is active) + * @return did the viewport position change? + */ +bool ScrollMainWindowTo(int x, int y, int z, bool instant) +{ + bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant); + + /* If a user scrolls to a tile (via what way what so ever) and already is on + * that tile (e.g.: pressed twice), move the smallmap to that location, + * so you directly see where you are on the smallmap. */ + + if (res) return res; + + SmallMapWindow *w = dynamic_cast(FindWindowById(WC_SMALLMAP, 0)); + if (w != NULL) w->SmallMapCenterOnCurrentPos(); + + return res; +} diff --git a/src/smallmap_gui.h.orig b/src/smallmap_gui.h.orig new file mode 100644 index 0000000000..6652f83d8c --- /dev/null +++ b/src/smallmap_gui.h.orig @@ -0,0 +1,192 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file smallmap_gui.h Smallmap GUI functions. */ + +#ifndef SMALLMAP_GUI_H +#define SMALLMAP_GUI_H + +#include "industry_type.h" +#include "company_base.h" +#include "window_gui.h" +#include "strings_func.h" +#include "blitter/factory.hpp" +#include "linkgraph/linkgraph_gui.h" +#include "widgets/smallmap_widget.h" + +/* set up the cargos to be displayed in the smallmap's route legend */ +void BuildLinkStatsLegend(); + +void BuildIndustriesLegend(); +void ShowSmallMap(); +void BuildLandLegend(); +void BuildOwnerLegend(); + +/** Structure for holding relevant data for legends in small map */ +struct LegendAndColour { + uint8 colour; ///< Colour of the item on the map. + StringID legend; ///< String corresponding to the coloured item. + IndustryType type; ///< Type of industry. Only valid for industry entries. + uint8 height; ///< Height in tiles. Only valid for height legend entries. + CompanyID company; ///< Company to display. Only valid for company entries of the owner legend. + bool show_on_map; ///< For filtering industries, if \c true, industry is shown on the map in colour. + bool end; ///< This is the end of the list. + bool col_break; ///< Perform a column break and go further at the next column. +}; + +/** Class managing the smallmap window. */ +class SmallMapWindow : public Window { +protected: + /** Types of legends in the #WID_SM_LEGEND widget. */ + enum SmallMapType { + SMT_CONTOUR, + SMT_VEHICLES, + SMT_INDUSTRY, + SMT_LINKSTATS, + SMT_ROUTES, + SMT_VEGETATION, + SMT_OWNER, + }; + + /** Available kinds of zoomlevel changes. */ + enum ZoomLevelChange { + ZLC_INITIALIZE, ///< Initialize zoom level. + ZLC_ZOOM_OUT, ///< Zoom out. + ZLC_ZOOM_IN, ///< Zoom in. + }; + + static SmallMapType map_type; ///< Currently displayed legends. + static bool show_towns; ///< Display town names in the smallmap. + + static const uint LEGEND_BLOB_WIDTH = 8; ///< Width of the coloured blob in front of a line text in the #WID_SM_LEGEND widget. + static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2; ///< Minimal number of columns in the #WID_SM_LEGEND widget for the #SMT_INDUSTRY legend. + static const uint FORCE_REFRESH_PERIOD = 0x1F; ///< map is redrawn after that many ticks + static const uint BLINK_PERIOD = 0x0F; ///< highlight blinking interval + + uint min_number_of_columns; ///< Minimal number of columns in legends. + uint min_number_of_fixed_rows; ///< Minimal number of rows in the legends for the fixed layouts only (all except #SMT_INDUSTRY). + uint column_width; ///< Width of a column in the #WID_SM_LEGEND widget. + + int32 scroll_x; ///< Horizontal world coordinate of the base tile left of the top-left corner of the smallmap display. + int32 scroll_y; ///< Vertical world coordinate of the base tile left of the top-left corner of the smallmap display. + int32 subscroll; ///< Number of pixels (0..3) between the right end of the base tile and the pixel at the top-left corner of the smallmap display. + int zoom; ///< Zoom level. Bigger number means more zoom-out (further away). + + uint8 refresh; ///< Refresh counter, zeroed every FORCE_REFRESH_PERIOD ticks. + LinkGraphOverlay *overlay; + + Point SmallmapRemapCoords(int x, int y) const; + + /** + * Draws vertical part of map indicator + * @param x X coord of left/right border of main viewport + * @param y Y coord of top border of main viewport + * @param y2 Y coord of bottom border of main viewport + */ + static inline void DrawVertMapIndicator(int x, int y, int y2) + { + GfxFillRect(x, y, x, y + 3, PC_VERY_LIGHT_YELLOW); + GfxFillRect(x, y2 - 3, x, y2, PC_VERY_LIGHT_YELLOW); + } + + /** + * Draws horizontal part of map indicator + * @param x X coord of left border of main viewport + * @param x2 X coord of right border of main viewport + * @param y Y coord of top/bottom border of main viewport + */ + static inline void DrawHorizMapIndicator(int x, int x2, int y) + { + GfxFillRect(x, y, x + 3, y, PC_VERY_LIGHT_YELLOW); + GfxFillRect(x2 - 3, y, x2, y, PC_VERY_LIGHT_YELLOW); + } + + /** + * Compute minimal required width of the legends. + * @return Minimally needed width for displaying the smallmap legends in pixels. + */ + inline uint GetMinLegendWidth() const + { + return WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width; + } + + /** + * Return number of columns that can be displayed in \a width pixels. + * @return Number of columns to display. + */ + inline uint GetNumberColumnsLegend(uint width) const + { + return width / this->column_width; + } + + /** + * Compute height given a number of columns. + * @param num_columns Number of columns. + * @return Needed height for displaying the smallmap legends in pixels. + */ + inline uint GetLegendHeight(uint num_columns) const + { + return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + + this->GetNumberRowsLegend(num_columns) * FONT_HEIGHT_SMALL; + } + + /** + * Get a bitmask for company links to be displayed. Usually this will be + * the _local_company. Spectators get to see all companies' links. + * @return Company mask. + */ + inline uint32 GetOverlayCompanyMask() const + { + return Company::IsValidID(_local_company) ? 1U << _local_company : 0xffffffff; + } + + uint GetNumberRowsLegend(uint columns) const; + void SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item = 0); + void SwitchMapType(SmallMapType map_type); + void SetNewScroll(int sx, int sy, int sub); + + void DrawMapIndicators() const; + void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const; + void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const; + void DrawTowns(const DrawPixelInfo *dpi) const; + void DrawSmallMap(DrawPixelInfo *dpi) const; + + Point RemapTile(int tile_x, int tile_y) const; + Point PixelToTile(int px, int py, int *sub, bool add_sub = true) const; + Point ComputeScroll(int tx, int ty, int x, int y, int *sub); + void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt); + void SetOverlayCargoMask(); + void SetupWidgetData(); + uint32 GetTileColours(const TileArea &ta) const; + + int GetPositionOnLegend(Point pt); + +public: + friend class NWidgetSmallmapDisplay; + + SmallMapWindow(WindowDesc *desc, int window_number); + virtual ~SmallMapWindow() { delete this->overlay; } + + void SmallMapCenterOnCurrentPos(); + Point GetStationMiddle(const Station *st) const; + + virtual void SetStringParameters(int widget) const; + virtual void OnInit(); + virtual void OnPaint(); + virtual void DrawWidget(const Rect &r, int widget) const; + virtual void OnClick(Point pt, int widget, int click_count); + virtual void OnInvalidateData(int data = 0, bool gui_scope = true); + virtual bool OnRightClick(Point pt, int widget); + virtual void OnMouseWheel(int wheel); + virtual void OnTick(); + virtual void OnScroll(Point delta); + virtual void OnMouseOver(Point pt, int widget); +}; + +#endif /* SMALLMAP_GUI_H */ diff --git a/src/station_base.h.orig b/src/station_base.h.orig new file mode 100644 index 0000000000..a4ad69547e --- /dev/null +++ b/src/station_base.h.orig @@ -0,0 +1,534 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file station_base.h Base classes/functions for stations. */ + +#ifndef STATION_BASE_H +#define STATION_BASE_H + +#include "core/random_func.hpp" +#include "base_station_base.h" +#include "newgrf_airport.h" +#include "cargopacket.h" +#include "industry_type.h" +#include "linkgraph/linkgraph_type.h" +#include "newgrf_storage.h" +#include + +typedef Pool StationPool; +extern StationPool _station_pool; + +static const byte INITIAL_STATION_RATING = 175; + +/** + * Flow statistics telling how much flow should be sent along a link. This is + * done by creating "flow shares" and using std::map's upper_bound() method to + * look them up with a random number. A flow share is the difference between a + * key in a map and the previous key. So one key in the map doesn't actually + * mean anything by itself. + */ +class FlowStat { +public: + typedef std::map SharesMap; + + /** + * Invalid constructor. This can't be called as a FlowStat must not be + * empty. However, the constructor must be defined and reachable for + * FlwoStat to be used in a std::map. + */ + inline FlowStat() {NOT_REACHED();} + + /** + * Create a FlowStat with an initial entry. + * @param st Station the initial entry refers to. + * @param flow Amount of flow for the initial entry. + */ + inline FlowStat(StationID st, uint flow) + { + assert(flow > 0); + this->shares[flow] = st; + this->unrestricted = flow; + } + + /** + * Add some flow to the end of the shares map. Only do that if you know + * that the station isn't in the map yet. Anything else may lead to + * inconsistencies. + * @param st Remote station. + * @param flow Amount of flow to be added. + * @param restricted If the flow to be added is restricted. + */ + inline void AppendShare(StationID st, uint flow, bool restricted = false) + { + assert(flow > 0); + this->shares[(--this->shares.end())->first + flow] = st; + if (!restricted) this->unrestricted += flow; + } + + uint GetShare(StationID st) const; + + void ChangeShare(StationID st, int flow); + + void RestrictShare(StationID st); + + void ReleaseShare(StationID st); + + void ScaleToMonthly(uint runtime); + + /** + * Get the actual shares as a const pointer so that they can be iterated + * over. + * @return Actual shares. + */ + inline const SharesMap *GetShares() const { return &this->shares; } + + /** + * Return total amount of unrestricted shares. + * @return Amount of unrestricted shares. + */ + inline uint GetUnrestricted() const { return this->unrestricted; } + + /** + * Swap the shares maps, and thus the content of this FlowStat with the + * other one. + * @param other FlowStat to swap with. + */ + inline void SwapShares(FlowStat &other) + { + this->shares.swap(other.shares); + Swap(this->unrestricted, other.unrestricted); + } + + /** + * Get a station a package can be routed to. This done by drawing a + * random number between 0 and sum_shares and then looking that up in + * the map with lower_bound. So each share gets selected with a + * probability dependent on its flow. Do include restricted flows here. + * @param is_restricted Output if a restricted flow was chosen. + * @return A station ID from the shares map. + */ + inline StationID GetViaWithRestricted(bool &is_restricted) const + { + assert(!this->shares.empty()); + uint rand = RandomRange((--this->shares.end())->first); + is_restricted = rand >= this->unrestricted; + return this->shares.upper_bound(rand)->second; + } + + /** + * Get a station a package can be routed to. This done by drawing a + * random number between 0 and sum_shares and then looking that up in + * the map with lower_bound. So each share gets selected with a + * probability dependent on its flow. Don't include restricted flows. + * @return A station ID from the shares map. + */ + inline StationID GetVia() const + { + assert(!this->shares.empty()); + return this->unrestricted > 0 ? + this->shares.upper_bound(RandomRange(this->unrestricted))->second : + INVALID_STATION; + } + + StationID GetVia(StationID excluded, StationID excluded2 = INVALID_STATION) const; + + void Invalidate(); + +private: + SharesMap shares; ///< Shares of flow to be sent via specified station (or consumed locally). + uint unrestricted; ///< Limit for unrestricted shares. +}; + +/** Flow descriptions by origin stations. */ +class FlowStatMap : public std::map { +public: + void AddFlow(StationID origin, StationID via, uint amount); + void PassOnFlow(StationID origin, StationID via, uint amount); + StationIDStack DeleteFlows(StationID via); + void RestrictFlows(StationID via); + void ReleaseFlows(StationID via); + void FinalizeLocalConsumption(StationID self); +}; + +/** + * Stores station stats for a single cargo. + */ +struct GoodsEntry { + /** Status of this cargo for the station. */ + enum GoodsEntryStatus { + /** + * Set when the station accepts the cargo currently for final deliveries. + * It is updated every STATION_ACCEPTANCE_TICKS ticks by checking surrounding tiles for acceptance >= 8/8. + */ + GES_ACCEPTANCE, + + /** + * Set when the cargo was ever waiting at the station. + * It is set when cargo supplied by surrounding tiles is moved to the station, or when + * arriving vehicles unload/transfer cargo without it being a final delivery. + * This also indicates, whether a cargo has a rating at the station. + * This flag is never cleared. + */ + GES_PICKUP, + + /** + * Set when a vehicle ever delivered cargo to the station for final delivery. + * This flag is never cleared. + */ + GES_EVER_ACCEPTED, + + /** + * Set when cargo was delivered for final delivery last month. + * This flag is set to the value of GES_CURRENT_MONTH at the start of each month. + */ + GES_LAST_MONTH, + + /** + * Set when cargo was delivered for final delivery this month. + * This flag is reset on the beginning of every month. + */ + GES_CURRENT_MONTH, + + /** + * Set when cargo was delivered for final delivery during the current STATION_ACCEPTANCE_TICKS interval. + * This flag is reset every STATION_ACCEPTANCE_TICKS ticks. + */ + GES_ACCEPTED_BIGTICK, + }; + + GoodsEntry() : + acceptance_pickup(0), + time_since_pickup(255), + rating(INITIAL_STATION_RATING), + last_speed(0), + last_age(255), + amount_fract(0), + link_graph(INVALID_LINK_GRAPH), + node(INVALID_NODE), + max_waiting_cargo(0) + {} + + byte acceptance_pickup; ///< Status of this cargo, see #GoodsEntryStatus. + + /** + * Number of rating-intervals (up to 255) since the last vehicle tried to load this cargo. + * The unit used is STATION_RATING_TICKS. + * This does not imply there was any cargo to load. + */ + byte time_since_pickup; + + byte rating; ///< %Station rating for this cargo. + + /** + * Maximum speed (up to 255) of the last vehicle that tried to load this cargo. + * This does not imply there was any cargo to load. + * The unit used is a special vehicle-specific speed unit for station ratings. + * - Trains: km-ish/h + * - RV: km-ish/h + * - Ships: 0.5 * km-ish/h + * - Aircraft: 8 * mph + */ + byte last_speed; + + /** + * Age in years (up to 255) of the last vehicle that tried to load this cargo. + * This does not imply there was any cargo to load. + */ + byte last_age; + + byte amount_fract; ///< Fractional part of the amount in the cargo list + StationCargoList cargo; ///< The cargo packets of cargo waiting in this station + + LinkGraphID link_graph; ///< Link graph this station belongs to. + NodeID node; ///< ID of node in link graph referring to this goods entry. + FlowStatMap flows; ///< Planned flows through this station. + uint max_waiting_cargo; ///< Max cargo from this station waiting at any station. + + /** + * Reports whether a vehicle has ever tried to load the cargo at this station. + * This does not imply that there was cargo available for loading. Refer to GES_PICKUP for that. + * @return true if vehicle tried to load. + */ + bool HasVehicleEverTriedLoading() const { return this->last_speed != 0; } + + /** + * Does this cargo have a rating at this station? + * @return true if the cargo has a rating, i.e. pickup has been attempted. + */ + inline bool HasRating() const + { + return HasBit(this->acceptance_pickup, GES_PICKUP); + } + + uint GetSumFlowVia(StationID via) const; + + /** + * Get the best next hop for a cargo packet from station source. + * @param source Source of the packet. + * @return The chosen next hop or INVALID_STATION if none was found. + */ + inline StationID GetVia(StationID source) const + { + FlowStatMap::const_iterator flow_it(this->flows.find(source)); + return flow_it != this->flows.end() ? flow_it->second.GetVia() : INVALID_STATION; + } + + /** + * Get the best next hop for a cargo packet from station source, optionally + * excluding one or two stations. + * @param source Source of the packet. + * @param excluded If this station would be chosen choose the second best one instead. + * @param excluded2 Second station to be excluded, if != INVALID_STATION. + * @return The chosen next hop or INVALID_STATION if none was found. + */ + inline StationID GetVia(StationID source, StationID excluded, StationID excluded2 = INVALID_STATION) const + { + FlowStatMap::const_iterator flow_it(this->flows.find(source)); + return flow_it != this->flows.end() ? flow_it->second.GetVia(excluded, excluded2) : INVALID_STATION; + } +}; + +/** All airport-related information. Only valid if tile != INVALID_TILE. */ +struct Airport : public TileArea { + Airport() : TileArea(INVALID_TILE, 0, 0) {} + + uint64 flags; ///< stores which blocks on the airport are taken. was 16 bit earlier on, then 32 + byte type; ///< Type of this airport, @see AirportTypes + byte layout; ///< Airport layout number. + Direction rotation; ///< How this airport is rotated. + + PersistentStorage *psa; ///< Persistent storage for NewGRF airports. + + /** + * Get the AirportSpec that from the airport type of this airport. If there + * is no airport (\c tile == INVALID_TILE) then return the dummy AirportSpec. + * @return The AirportSpec for this airport. + */ + const AirportSpec *GetSpec() const + { + if (this->tile == INVALID_TILE) return &AirportSpec::dummy; + return AirportSpec::Get(this->type); + } + + /** + * Get the finite-state machine for this airport or the finite-state machine + * for the dummy airport in case this isn't an airport. + * @pre this->type < NEW_AIRPORT_OFFSET. + * @return The state machine for this airport. + */ + const AirportFTAClass *GetFTA() const + { + return this->GetSpec()->fsm; + } + + /** Check if this airport has at least one hangar. */ + inline bool HasHangar() const + { + return this->GetSpec()->nof_depots > 0; + } + + /** + * Add the tileoffset to the base tile of this airport but rotate it first. + * The base tile is the northernmost tile of this airport. This function + * helps to make sure that getting the tile of a hangar works even for + * rotated airport layouts without requiring a rotated array of hangar tiles. + * @param tidc The tilediff to add to the airport tile. + * @return The tile of this airport plus the rotated offset. + */ + inline TileIndex GetRotatedTileFromOffset(TileIndexDiffC tidc) const + { + const AirportSpec *as = this->GetSpec(); + switch (this->rotation) { + case DIR_N: return this->tile + ToTileIndexDiff(tidc); + + case DIR_E: return this->tile + TileDiffXY(tidc.y, as->size_x - 1 - tidc.x); + + case DIR_S: return this->tile + TileDiffXY(as->size_x - 1 - tidc.x, as->size_y - 1 - tidc.y); + + case DIR_W: return this->tile + TileDiffXY(as->size_y - 1 - tidc.y, tidc.x); + + default: NOT_REACHED(); + } + } + + /** + * Get the first tile of the given hangar. + * @param hangar_num The hangar to get the location of. + * @pre hangar_num < GetNumHangars(). + * @return A tile with the given hangar. + */ + inline TileIndex GetHangarTile(uint hangar_num) const + { + const AirportSpec *as = this->GetSpec(); + for (uint i = 0; i < as->nof_depots; i++) { + if (as->depot_table[i].hangar_num == hangar_num) { + return this->GetRotatedTileFromOffset(as->depot_table[i].ti); + } + } + NOT_REACHED(); + } + + /** + * Get the exit direction of the hangar at a specific tile. + * @param tile The tile to query. + * @pre IsHangarTile(tile). + * @return The exit direction of the hangar, taking airport rotation into account. + */ + inline Direction GetHangarExitDirection(TileIndex tile) const + { + const AirportSpec *as = this->GetSpec(); + const HangarTileTable *htt = GetHangarDataByTile(tile); + return ChangeDir(htt->dir, DirDifference(this->rotation, as->rotation[0])); + } + + /** + * Get the hangar number of the hangar at a specific tile. + * @param tile The tile to query. + * @pre IsHangarTile(tile). + * @return The hangar number of the hangar at the given tile. + */ + inline uint GetHangarNum(TileIndex tile) const + { + const HangarTileTable *htt = GetHangarDataByTile(tile); + return htt->hangar_num; + } + + /** Get the number of hangars on this airport. */ + inline uint GetNumHangars() const + { + uint num = 0; + uint counted = 0; + const AirportSpec *as = this->GetSpec(); + for (uint i = 0; i < as->nof_depots; i++) { + if (!HasBit(counted, as->depot_table[i].hangar_num)) { + num++; + SetBit(counted, as->depot_table[i].hangar_num); + } + } + return num; + } + +private: + /** + * Retrieve hangar information of a hangar at a given tile. + * @param tile %Tile containing the hangar. + * @return The requested hangar information. + * @pre The \a tile must be at a hangar tile at an airport. + */ + inline const HangarTileTable *GetHangarDataByTile(TileIndex tile) const + { + const AirportSpec *as = this->GetSpec(); + for (uint i = 0; i < as->nof_depots; i++) { + if (this->GetRotatedTileFromOffset(as->depot_table[i].ti) == tile) { + return as->depot_table + i; + } + } + NOT_REACHED(); + } +}; + +typedef SmallVector IndustryVector; + +/** Station data structure */ +struct Station FINAL : SpecializedStation { +public: + RoadStop *GetPrimaryRoadStop(RoadStopType type) const + { + return type == ROADSTOP_BUS ? bus_stops : truck_stops; + } + + RoadStop *GetPrimaryRoadStop(const struct RoadVehicle *v) const; + + RoadStop *bus_stops; ///< All the road stops + TileArea bus_station; ///< Tile area the bus 'station' part covers + RoadStop *truck_stops; ///< All the truck stops + TileArea truck_station; ///< Tile area the truck 'station' part covers + + Airport airport; ///< Tile area the airport covers + TileIndex dock_tile; ///< The location of the dock + + IndustryType indtype; ///< Industry type to get the name from + + StationHadVehicleOfTypeByte had_vehicle_of_type; + + byte time_since_load; + byte time_since_unload; + + byte last_vehicle_type; + std::list loading_vehicles; + GoodsEntry goods[NUM_CARGO]; ///< Goods at this station + uint32 always_accepted; ///< Bitmask of always accepted cargo types (by houses, HQs, industry tiles when industry doesn't accept cargo) + + IndustryVector industries_near; ///< Cached list of industries near the station that can accept cargo, @see DeliverGoodsToIndustry() + + Station(TileIndex tile = INVALID_TILE); + ~Station(); + + void AddFacility(StationFacility new_facility_bit, TileIndex facil_xy); + + void MarkTilesDirty(bool cargo_change) const; + + void UpdateVirtCoord(); + + /* virtual */ uint GetPlatformLength(TileIndex tile, DiagDirection dir) const; + /* virtual */ uint GetPlatformLength(TileIndex tile) const; + void RecomputeIndustriesNear(); + static void RecomputeIndustriesNearForAll(); + + uint GetCatchmentRadius() const; + Rect GetCatchmentRect() const; + + /* virtual */ inline bool TileBelongsToRailStation(TileIndex tile) const + { + return IsRailStationTile(tile) && GetStationIndex(tile) == this->index; + } + + inline bool TileBelongsToAirport(TileIndex tile) const + { + return IsAirportTile(tile) && GetStationIndex(tile) == this->index; + } + + /* virtual */ uint32 GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const; + + /* virtual */ void GetTileArea(TileArea *ta, StationType type) const; +}; + +#define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var) + +/** Iterator to iterate over all tiles belonging to an airport. */ +class AirportTileIterator : public OrthogonalTileIterator { +private: + const Station *st; ///< The station the airport is a part of. + +public: + /** + * Construct the iterator. + * @param ta Area, i.e. begin point and width/height of to-be-iterated area. + */ + AirportTileIterator(const Station *st) : OrthogonalTileIterator(st->airport), st(st) + { + if (!st->TileBelongsToAirport(this->tile)) ++(*this); + } + + inline TileIterator& operator ++() + { + (*this).OrthogonalTileIterator::operator++(); + while (this->tile != INVALID_TILE && !st->TileBelongsToAirport(this->tile)) { + (*this).OrthogonalTileIterator::operator++(); + } + return *this; + } + + virtual TileIterator *Clone() const + { + return new AirportTileIterator(*this); + } +}; + +#endif /* STATION_BASE_H */ diff --git a/src/station_gui.cpp.orig b/src/station_gui.cpp.orig new file mode 100644 index 0000000000..e57be72c86 --- /dev/null +++ b/src/station_gui.cpp.orig @@ -0,0 +1,2450 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file station_gui.cpp The GUI for stations. */ + +#include "stdafx.h" +#include "debug.h" +#include "gui.h" +#include "textbuf_gui.h" +#include "company_func.h" +#include "command_func.h" +#include "vehicle_gui.h" +#include "cargotype.h" +#include "station_gui.h" +#include "strings_func.h" +#include "window_func.h" +#include "viewport_func.h" +#include "widgets/dropdown_func.h" +#include "station_base.h" +#include "waypoint_base.h" +#include "tilehighlight_func.h" +#include "company_base.h" +#include "sortlist_type.h" +#include "core/geometry_func.hpp" +#include "vehiclelist.h" +#include "town.h" +#include "linkgraph/linkgraph.h" + +#include "widgets/station_widget.h" + +#include "table/strings.h" + +#include +#include + +/** + * Calculates and draws the accepted or supplied cargo around the selected tile(s) + * @param left x position where the string is to be drawn + * @param right the right most position to draw on + * @param top y position where the string is to be drawn + * @param sct which type of cargo is to be displayed (passengers/non-passengers) + * @param rad radius around selected tile(s) to be searched + * @param supplies if supplied cargoes should be drawn, else accepted cargoes + * @return Returns the y value below the string that was drawn + */ +int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageType sct, int rad, bool supplies) +{ + TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y); + uint32 cargo_mask = 0; + if (_thd.drawstyle == HT_RECT && tile < MapSize()) { + CargoArray cargoes; + if (supplies) { + cargoes = GetProductionAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad); + } else { + cargoes = GetAcceptanceAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad); + } + + /* Convert cargo counts to a set of cargo bits, and draw the result. */ + for (CargoID i = 0; i < NUM_CARGO; i++) { + switch (sct) { + case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(i, CC_PASSENGERS)) continue; break; + case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(i, CC_PASSENGERS)) continue; break; + case SCT_ALL: break; + default: NOT_REACHED(); + } + if (cargoes[i] >= (supplies ? 1U : 8U)) SetBit(cargo_mask, i); + } + } + SetDParam(0, cargo_mask); + return DrawStringMultiLine(left, right, top, INT32_MAX, supplies ? STR_STATION_BUILD_SUPPLIES_CARGO : STR_STATION_BUILD_ACCEPTS_CARGO); +} + +/** + * Check whether we need to redraw the station coverage text. + * If it is needed actually make the window for redrawing. + * @param w the window to check. + */ +void CheckRedrawStationCoverage(const Window *w) +{ + if (_thd.dirty & 1) { + _thd.dirty &= ~1; + w->SetDirty(); + } +} + +/** + * Draw small boxes of cargo amount and ratings data at the given + * coordinates. If amount exceeds 576 units, it is shown 'full', same + * goes for the rating: at above 90% orso (224) it is also 'full' + * + * @param left left most coordinate to draw the box at + * @param right right most coordinate to draw the box at + * @param y coordinate to draw the box at + * @param type Cargo type + * @param amount Cargo amount + * @param rating ratings data for that particular cargo + */ +static void StationsWndShowStationRating(int left, int right, int y, CargoID type, uint amount, byte rating) +{ + static const uint units_full = 1 << 9; ///< Number of units to show station as full. + static const uint rating_full = 224; ///< Rating needed so it is shown as full. + + const CargoSpec *cs = CargoSpec::Get(type); + if (!cs->IsValid()) return; + + y++; ///< Make boxes 1 pixel shorter. + int left_start = left; + int right_start = right; + int height = GetCharacterHeight(FS_SMALL) - 2; + int colour = cs->rating_colour; + + /* Get width of the box to draw. */ + uint width = minu(amount, units_full) * (right - left) / units_full; + + /* Update the end margin, adding the width of the box not to be drawn... */ + if (width != 0) UpdateMarginsWidth(right - left - width, left_start, right_start, true); + /* ... or prepare margins in case width == 0 and amount > 0 (just one pixel bar). */ + else left_start = right_start = _current_text_dir ? right : left; + + /* Draw total cargo (limited) on station */ + if (amount > 0) GfxFillRect(left_start, y, right_start, y + height, colour); + + DrawString(left, right, y, cs->abbrev, GetContrastColour(colour), SA_CENTER); + + /* Draw green/red ratings bar*/ + y += height + 2; + left_start = left + 1; + right_start = right - 1; + if (rating != 0) { + GfxFillRect(left_start, y, right_start, y, PC_GREEN); + width = minu(rating, rating_full) * (right_start - left_start) / rating_full; + UpdateMarginsWidth(width, left_start, right_start, false); + } + GfxFillRect(left_start, y, right_start, y, PC_RED); +} + +/** + * Draw small boxes of cargo accepted. + * @param left Left most coordinate to draw the box at. + * @param right Right most coordinate to draw the box at. + * @param y Coordinate to draw the box at. + * @param type Cargo type. + * @param acceptance_pickup_byte Acceptance byte. + */ +static void StationsWndShowAcceptance(int left, int right, int y, CargoID type) +{ + const CargoSpec *cs = CargoSpec::Get(type); + if (!cs->IsValid()) return; + y++; + GfxFillRect(left, y, right, y + GetCharacterHeight(FS_SMALL), cs->rating_colour, FILLRECT_CHECKER); + DrawString(left, right, y, cs->abbrev, TC_BLACK, SA_CENTER); +} + +/** + * Draw small boxes showing cargo waiting, ratings... for a given station. + * @param st Station to draw statistics of. + * @param x Position to start drawing at. + * @param width Width for each box. + * @param y Height position to draw the box at. + */ +void StationsWndShowStationRating(const Station *st, int left, int right, int x, int width, int y) +{ + bool rtl = _current_text_dir == TD_RTL; + AddSpace(5, x, false); + + /* For RTL we work in exactly the opposite direction. So + * decrement the space needed first, then draw to the left + * instead of drawing to the left and then incrementing + * the space. */ + if (rtl) x -= width + 4; + for (uint j = 0; j < _sorted_standard_cargo_specs_size && ( x > left && x + width < right ); j++) { + CargoID cid = _sorted_cargo_specs[j]->Index(); + if (st->goods[cid].IsSourceStationForCargo()) { + StationsWndShowStationRating(x, x + width, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating); + AddSpace(width + 4, x, false); + } else if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_EVER_ACCEPTED)) { + StationsWndShowAcceptance(x, x + width, y, cid); + AddSpace(width + 4, x, false); + } + } +} + +typedef GUIList GUIStationList; + +/** + * The list of stations per company. + */ +class CompanyStationsWindow : public Window +{ +protected: + /* Runtime saved values */ + static Listing last_sorting; + static byte facilities; // types of stations of interest + static bool include_empty; // whether we should include stations without waiting cargo + static const uint32 cargo_filter_max; + static uint32 cargo_filter; // bitmap of cargo types to include + static const Station *last_station; + + /* Constants for sorting stations */ + static const StringID sorter_names[]; + static GUIStationList::SortFunction * const sorter_funcs[]; + + GUIStationList stations; + Scrollbar *vscroll; + + /** + * (Re)Build station list + * + * @param owner company whose stations are to be in list + */ + void BuildStationsList(const Owner owner) + { + if (!this->stations.NeedRebuild()) return; + + DEBUG(misc, 3, "Building station list for company %d", owner); + + this->stations.Clear(); + + const Station *st; + FOR_ALL_STATIONS(st) { + if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) { + if (this->facilities & st->facilities) { // only stations with selected facilities + int num_waiting_cargo = 0; + for (CargoID j = 0; j < NUM_CARGO; j++) { + if (st->goods[j].HasRating()) { + num_waiting_cargo++; // count number of waiting cargo + if (HasBit(this->cargo_filter, j)) { + *this->stations.Append() = st; + break; + } + } + } + /* stations without waiting cargo */ + if (num_waiting_cargo == 0 && this->include_empty) { + *this->stations.Append() = st; + } + } + } + } + + this->stations.Compact(); + this->stations.RebuildDone(); + + this->vscroll->SetCount(this->stations.Length()); // Update the scrollbar + } + + /** Sort stations by their name */ + static int CDECL StationNameSorter(const Station * const *a, const Station * const *b) + { + static char buf_cache[64]; + char buf[64]; + + SetDParam(0, (*a)->index); + GetString(buf, STR_STATION_NAME, lastof(buf)); + + if (*b != last_station) { + last_station = *b; + SetDParam(0, (*b)->index); + GetString(buf_cache, STR_STATION_NAME, lastof(buf_cache)); + } + + return strcmp(buf, buf_cache); + } + + /** Sort stations by their type */ + static int CDECL StationTypeSorter(const Station * const *a, const Station * const *b) + { + return (*a)->facilities - (*b)->facilities; + } + + /** Sort stations by their waiting cargo */ + static int CDECL StationWaitingTotalSorter(const Station * const *a, const Station * const *b) + { + int diff = 0; + + CargoID j; + FOR_EACH_SET_CARGO_ID(j, cargo_filter) { + diff += (*a)->goods[j].cargo.TotalCount() - (*b)->goods[j].cargo.TotalCount(); + } + + return diff; + } + + /** Sort stations by their available waiting cargo */ + static int CDECL StationWaitingAvailableSorter(const Station * const *a, const Station * const *b) + { + int diff = 0; + + CargoID j; + FOR_EACH_SET_CARGO_ID(j, cargo_filter) { + diff += (*a)->goods[j].cargo.AvailableCount() - (*b)->goods[j].cargo.AvailableCount(); + } + + return diff; + } + + /** Sort stations by their rating */ + static int CDECL StationRatingMaxSorter(const Station * const *a, const Station * const *b) + { + byte maxr1 = 0; + byte maxr2 = 0; + + CargoID j; + FOR_EACH_SET_CARGO_ID(j, cargo_filter) { + if ((*a)->goods[j].HasRating()) maxr1 = max(maxr1, (*a)->goods[j].rating); + if ((*b)->goods[j].HasRating()) maxr2 = max(maxr2, (*b)->goods[j].rating); + } + + return maxr1 - maxr2; + } + + /** Sort stations by their rating */ + static int CDECL StationRatingMinSorter(const Station * const *a, const Station * const *b) + { + byte minr1 = 255; + byte minr2 = 255; + + for (CargoID j = 0; j < NUM_CARGO; j++) { + if (!HasBit(cargo_filter, j)) continue; + if ((*a)->goods[j].HasRating()) minr1 = min(minr1, (*a)->goods[j].rating); + if ((*b)->goods[j].HasRating()) minr2 = min(minr2, (*b)->goods[j].rating); + } + + return -(minr1 - minr2); + } + + /** Sort the stations list */ + void SortStationsList() + { + if (!this->stations.Sort()) return; + + /* Reset name sorter sort cache */ + this->last_station = NULL; + + /* Set the modified widget dirty */ + this->SetWidgetDirty(WID_STL_LIST); + } + +public: + CompanyStationsWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->stations.SetListing(this->last_sorting); + this->stations.SetSortFuncs(this->sorter_funcs); + this->stations.ForceRebuild(); + this->stations.NeedResort(); + this->SortStationsList(); + + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_STL_SCROLLBAR); + this->FinishInitNested(window_number); + this->owner = (Owner)this->window_number; + + const CargoSpec *cs; + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + if (!HasBit(this->cargo_filter, cs->Index())) continue; + this->LowerWidget(WID_STL_CARGOSTART + index); + } + + if (this->cargo_filter == this->cargo_filter_max) this->cargo_filter = _cargo_mask; + + for (uint i = 0; i < 5; i++) { + if (HasBit(this->facilities, i)) this->LowerWidget(i + WID_STL_TRAIN); + } + this->SetWidgetLoweredState(WID_STL_NOCARGOWAITING, this->include_empty); + + this->GetWidget(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()]; + } + + ~CompanyStationsWindow() + { + this->last_sorting = this->stations.GetListing(); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_STL_SORTBY: { + Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); + d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_STL_SORTDROPBTN: { + Dimension d = {0, 0}; + for (int i = 0; this->sorter_names[i] != INVALID_STRING_ID; i++) { + d = maxdim(d, GetStringBoundingBox(this->sorter_names[i])); + } + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_STL_LIST: + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; + break; + + case WID_STL_TRAIN: + case WID_STL_TRUCK: + case WID_STL_BUS: + case WID_STL_AIRPLANE: + case WID_STL_SHIP: + size->height = max(FONT_HEIGHT_SMALL, 10) + padding.height; + break; + + case WID_STL_CARGOALL: + case WID_STL_FACILALL: + case WID_STL_NOCARGOWAITING: { + Dimension d = GetStringBoundingBox(widget == WID_STL_NOCARGOWAITING ? STR_ABBREV_NONE : STR_ABBREV_ALL); + d.width += padding.width + 2; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + default: + if (widget >= WID_STL_CARGOSTART) { + Dimension d = GetStringBoundingBox(_sorted_cargo_specs[widget - WID_STL_CARGOSTART]->abbrev); + d.width += padding.width + 2; + d.height += padding.height; + *size = maxdim(*size, d); + } + break; + } + } + + virtual void OnPaint() + { + this->BuildStationsList((Owner)this->window_number); + this->SortStationsList(); + + this->DrawWidgets(); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_STL_SORTBY: + /* draw arrow pointing up/down for ascending/descending sorting */ + this->DrawSortButtonState(WID_STL_SORTBY, this->stations.IsDescSortOrder() ? SBS_DOWN : SBS_UP); + break; + + case WID_STL_LIST: { + int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.Length()); + uint line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + int y = Center(r.top + WD_FRAMERECT_TOP, line_height); + for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner + const Station *st = this->stations[i]; + assert(st->xy != INVALID_TILE); + + /* Do not do the complex check HasStationInUse here, it may be even false + * when the order had been removed and the station list hasn't been removed yet */ + assert(st->owner == owner || st->owner == OWNER_NONE); + + SetDParam(0, st->index); + SetDParam(1, st->facilities); + int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION); + + StationsWndShowStationRating(st, r.left, r.right, x, line_height + 2, y); + + y += line_height; + } + + if (this->vscroll->GetCount() == 0) { // company has no stations + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_NONE); + return; + } + break; + } + + case WID_STL_NOCARGOWAITING: { + int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1; + DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_NONE, TC_BLACK, SA_HOR_CENTER); + break; + } + + case WID_STL_CARGOALL: { + int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1; + DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER); + break; + } + + case WID_STL_FACILALL: { + int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1; + DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER); + break; + } + + default: + if (widget >= WID_STL_CARGOSTART) { + const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART]; + int cg_ofst = HasBit(this->cargo_filter, cs->Index()) ? 2 : 1; + GfxFillRect(r.left + cg_ofst, r.top + cg_ofst, r.right - 2 + cg_ofst, r.bottom - 2 + cg_ofst, cs->rating_colour); + TextColour tc = GetContrastColour(cs->rating_colour); + DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, cs->abbrev, tc, SA_HOR_CENTER); + } + break; + } + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_STL_CAPTION) { + SetDParam(0, this->window_number); + SetDParam(1, this->vscroll->GetCount()); + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_STL_LIST: { + uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, this->resize.step_height); + if (id_v >= this->stations.Length()) return; // click out of list bound + + const Station *st = this->stations[id_v]; + /* do not check HasStationInUse - it is slow and may be invalid */ + assert(st->owner == (Owner)this->window_number || st->owner == OWNER_NONE); + + if (_ctrl_pressed) { + ShowExtraViewPortWindow(st->xy); + } else { + ScrollMainWindowToTile(st->xy); + } + break; + } + + case WID_STL_TRAIN: + case WID_STL_TRUCK: + case WID_STL_BUS: + case WID_STL_AIRPLANE: + case WID_STL_SHIP: + if (_ctrl_pressed) { + ToggleBit(this->facilities, widget - WID_STL_TRAIN); + this->ToggleWidgetLoweredState(widget); + } else { + uint i; + FOR_EACH_SET_BIT(i, this->facilities) { + this->RaiseWidget(i + WID_STL_TRAIN); + } + this->facilities = 1 << (widget - WID_STL_TRAIN); + this->LowerWidget(widget); + } + this->stations.ForceRebuild(); + this->SetDirty(); + break; + + case WID_STL_FACILALL: + for (uint i = WID_STL_TRAIN; i <= WID_STL_SHIP; i++) { + this->LowerWidget(i); + } + + this->facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK; + this->stations.ForceRebuild(); + this->SetDirty(); + break; + + case WID_STL_CARGOALL: { + for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { + this->LowerWidget(WID_STL_CARGOSTART + i); + } + this->LowerWidget(WID_STL_NOCARGOWAITING); + + this->cargo_filter = _cargo_mask; + this->include_empty = true; + this->stations.ForceRebuild(); + this->SetDirty(); + break; + } + + case WID_STL_SORTBY: // flip sorting method asc/desc + this->stations.ToggleSortOrder(); + this->SetDirty(); + break; + + case WID_STL_SORTDROPBTN: // select sorting criteria dropdown menu + ShowDropDownMenu(this, this->sorter_names, this->stations.SortType(), WID_STL_SORTDROPBTN, 0, 0); + break; + + case WID_STL_NOCARGOWAITING: + if (_ctrl_pressed) { + this->include_empty = !this->include_empty; + this->ToggleWidgetLoweredState(WID_STL_NOCARGOWAITING); + } else { + for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { + this->RaiseWidget(WID_STL_CARGOSTART + i); + } + + this->cargo_filter = 0; + this->include_empty = true; + + this->LowerWidget(WID_STL_NOCARGOWAITING); + } + this->stations.ForceRebuild(); + this->SetDirty(); + break; + + default: + if (widget >= WID_STL_CARGOSTART) { // change cargo_filter + /* Determine the selected cargo type */ + const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART]; + + if (_ctrl_pressed) { + ToggleBit(this->cargo_filter, cs->Index()); + this->ToggleWidgetLoweredState(widget); + } else { + for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { + this->RaiseWidget(WID_STL_CARGOSTART + i); + } + this->RaiseWidget(WID_STL_NOCARGOWAITING); + + this->cargo_filter = 0; + this->include_empty = false; + + SetBit(this->cargo_filter, cs->Index()); + this->LowerWidget(widget); + } + this->stations.ForceRebuild(); + this->SetDirty(); + } + break; + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + if (this->stations.SortType() != index) { + this->stations.SetSortType(index); + + /* Display the current sort variant */ + this->GetWidget(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()]; + + this->SetDirty(); + } + } + + virtual void OnTick() + { + if (_pause_mode != PM_UNPAUSED) return; + if (this->stations.NeedResort()) { + DEBUG(misc, 3, "Periodic rebuild station list company %d", this->window_number); + this->SetDirty(); + } + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_STL_LIST, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (data == 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ + this->stations.ForceRebuild(); + } else { + this->stations.ForceResort(); + } + } +}; + +Listing CompanyStationsWindow::last_sorting = {false, 0}; +byte CompanyStationsWindow::facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK; +bool CompanyStationsWindow::include_empty = true; +const uint32 CompanyStationsWindow::cargo_filter_max = UINT32_MAX; +uint32 CompanyStationsWindow::cargo_filter = UINT32_MAX; +const Station *CompanyStationsWindow::last_station = NULL; + +/* Availible station sorting functions */ +GUIStationList::SortFunction * const CompanyStationsWindow::sorter_funcs[] = { + &StationNameSorter, + &StationTypeSorter, + &StationWaitingTotalSorter, + &StationWaitingAvailableSorter, + &StationRatingMaxSorter, + &StationRatingMinSorter +}; + +/* Names of the sorting functions */ +const StringID CompanyStationsWindow::sorter_names[] = { + STR_SORT_BY_NAME, + STR_SORT_BY_FACILITY, + STR_SORT_BY_WAITING_TOTAL, + STR_SORT_BY_WAITING_AVAILABLE, + STR_SORT_BY_RATING_MAX, + STR_SORT_BY_RATING_MIN, + INVALID_STRING_ID +}; + +/** + * Make a horizontal row of cargo buttons, starting at widget #WID_STL_CARGOSTART. + * @param biggest_index Pointer to store biggest used widget number of the buttons. + * @return Horizontal row. + */ +static NWidgetBase *CargoWidgets(int *biggest_index) +{ + NWidgetHorizontal *container = new NWidgetHorizontal(); + + for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { + NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_STL_CARGOSTART + i); + panel->SetMinimalSize(14, 11); + panel->SetResize(0, 0); + panel->SetFill(0, 1); + panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE); + container->Add(panel); + } + *biggest_index = WID_STL_CARGOSTART + _sorted_standard_cargo_specs_size; + return container; +} + +static const NWidgetPart _nested_company_stations_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_STL_CAPTION), SetDataTip(STR_STATION_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRAIN), SetMinimalSize(14, 11), SetDataTip(STR_TRAIN, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRUCK), SetMinimalSize(14, 11), SetDataTip(STR_LORRY, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_BUS), SetMinimalSize(14, 11), SetDataTip(STR_BUS, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_SHIP), SetMinimalSize(14, 11), SetDataTip(STR_SHIP, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetMinimalSize(14, 11), SetDataTip(STR_PLANE, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), + NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetFill(0, 1), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 11), SetFill(0, 1), EndContainer(), + NWidgetFunction(CargoWidgets), + NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_NOCARGOWAITING), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), SetFill(0, 1), EndContainer(), + NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_CARGOALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_TYPES), SetFill(0, 1), + NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetSizingType(NWST_STEP), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_SORTDROPBTN), SetMinimalSize(163, 12), SetDataTip(STR_SORT_BY_NAME, STR_TOOLTIP_SORT_CRITERIA), // widget_data gets overwritten. + NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_LIST), SetMinimalSize(346, 125), SetResize(1, 10), SetDataTip(0x0, STR_STATION_LIST_TOOLTIP), SetScrollbar(WID_STL_SCROLLBAR), EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_STL_SCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), + EndContainer(), +}; + +static WindowDesc _company_stations_desc( + WDP_AUTO, "list_stations", 358, 162, + WC_STATION_LIST, WC_NONE, + 0, + _nested_company_stations_widgets, lengthof(_nested_company_stations_widgets) +); + +/** + * Opens window with list of company's stations + * + * @param company whose stations' list show + */ +void ShowCompanyStations(CompanyID company) +{ + if (!Company::IsValidID(company)) return; + + AllocateWindowDescFront(&_company_stations_desc, company); +} + +static const NWidgetPart _nested_station_view_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_SV_CAPTION), SetDataTip(STR_STATION_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(1, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_GROUP), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_STATION_VIEW_GROUP, 0x0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_GROUP_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(1, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_GREY, WID_SV_WAITING), SetMinimalSize(237, 44), SetResize(1, 10), SetScrollbar(WID_SV_SCROLLBAR), EndContainer(), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SV_SCROLLBAR), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_SV_ACCEPT_RATING_LIST), SetMinimalSize(249, 23), SetResize(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_LOCATION), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1), + SetDataTip(STR_BUTTON_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ACCEPTS_RATINGS), SetMinimalSize(46, 12), SetResize(1, 0), SetFill(1, 1), + SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_RENAME), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1), + SetDataTip(STR_BUTTON_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP), + EndContainer(), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1), + SetDataTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_TRAINS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ROADVEHS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SHIPS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_PLANES), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_PLANE, STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +/** + * Draws icons of waiting cargo in the StationView window + * + * @param i type of cargo + * @param waiting number of waiting units + * @param left left most coordinate to draw on + * @param right right most coordinate to draw on + * @param y y coordinate + * @param width the width of the view + */ +static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int y) +{ + uint num = min((waiting + 5) / 10, (right - left) / 10); // maximum is width / 10 icons so it won't overflow + if (num == 0) return; + + SpriteID sprite = CargoSpec::Get(i)->GetCargoIcon(); + + int x = _current_text_dir == TD_RTL ? left : right - num * 10; + do { + DrawSprite(sprite, PAL_NONE, x, y); + x += 10; + } while (--num); +} + +enum SortOrder { + SO_DESCENDING, + SO_ASCENDING +}; + +class CargoDataEntry; + +enum CargoSortType { + ST_AS_GROUPING, ///< by the same principle the entries are being grouped + ST_COUNT, ///< by amount of cargo + ST_STATION_STRING, ///< by station name + ST_STATION_ID, ///< by station id + ST_CARGO_ID, ///< by cargo id +}; + +class CargoSorter { +public: + CargoSorter(CargoSortType t = ST_STATION_ID, SortOrder o = SO_ASCENDING) : type(t), order(o) {} + CargoSortType GetSortType() {return this->type;} + bool operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const; + +private: + CargoSortType type; + SortOrder order; + + template + bool SortId(Tid st1, Tid st2) const; + bool SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const; + bool SortStation (StationID st1, StationID st2) const; +}; + +typedef std::set CargoDataSet; + +/** + * A cargo data entry representing one possible row in the station view window's + * top part. Cargo data entries form a tree where each entry can have several + * children. Parents keep track of the sums of their childrens' cargo counts. + */ +class CargoDataEntry { +public: + CargoDataEntry(); + ~CargoDataEntry(); + + /** + * Insert a new child or retrieve an existing child using a station ID as ID. + * @param station ID of the station for which an entry shall be created or retrieved + * @return a child entry associated with the given station. + */ + CargoDataEntry *InsertOrRetrieve(StationID station) + { + return this->InsertOrRetrieve(station); + } + + /** + * Insert a new child or retrieve an existing child using a cargo ID as ID. + * @param cargo ID of the cargo for which an entry shall be created or retrieved + * @return a child entry associated with the given cargo. + */ + CargoDataEntry *InsertOrRetrieve(CargoID cargo) + { + return this->InsertOrRetrieve(cargo); + } + + void Update(uint count); + + /** + * Remove a child associated with the given station. + * @param station ID of the station for which the child should be removed. + */ + void Remove(StationID station) + { + CargoDataEntry t(station); + this->Remove(&t); + } + + /** + * Remove a child associated with the given cargo. + * @param cargo ID of the cargo for which the child should be removed. + */ + void Remove(CargoID cargo) + { + CargoDataEntry t(cargo); + this->Remove(&t); + } + + /** + * Retrieve a child for the given station. Return NULL if it doesn't exist. + * @param station ID of the station the child we're looking for is associated with. + * @return a child entry for the given station or NULL. + */ + CargoDataEntry *Retrieve(StationID station) const + { + CargoDataEntry t(station); + return this->Retrieve(this->children->find(&t)); + } + + /** + * Retrieve a child for the given cargo. Return NULL if it doesn't exist. + * @param cargo ID of the cargo the child we're looking for is associated with. + * @return a child entry for the given cargo or NULL. + */ + CargoDataEntry *Retrieve(CargoID cargo) const + { + CargoDataEntry t(cargo); + return this->Retrieve(this->children->find(&t)); + } + + void Resort(CargoSortType type, SortOrder order); + + /** + * Get the station ID for this entry. + */ + StationID GetStation() const { return this->station; } + + /** + * Get the cargo ID for this entry. + */ + CargoID GetCargo() const { return this->cargo; } + + /** + * Get the cargo count for this entry. + */ + uint GetCount() const { return this->count; } + + /** + * Get the parent entry for this entry. + */ + CargoDataEntry *GetParent() const { return this->parent; } + + /** + * Get the number of children for this entry. + */ + uint GetNumChildren() const { return this->num_children; } + + /** + * Get an iterator pointing to the begin of the set of children. + */ + CargoDataSet::iterator Begin() const { return this->children->begin(); } + + /** + * Get an iterator pointing to the end of the set of children. + */ + CargoDataSet::iterator End() const { return this->children->end(); } + + /** + * Has this entry transfers. + */ + bool HasTransfers() const { return this->transfers; } + + /** + * Set the transfers state. + */ + void SetTransfers(bool value) { this->transfers = value; } + + void Clear(); +private: + + CargoDataEntry(StationID st, uint c, CargoDataEntry *p); + CargoDataEntry(CargoID car, uint c, CargoDataEntry *p); + CargoDataEntry(StationID st); + CargoDataEntry(CargoID car); + + CargoDataEntry *Retrieve(CargoDataSet::iterator i) const; + + template + CargoDataEntry *InsertOrRetrieve(Tid s); + + void Remove(CargoDataEntry *comp); + void IncrementSize(); + + CargoDataEntry *parent; ///< the parent of this entry. + const union { + StationID station; ///< ID of the station this entry is associated with. + struct { + CargoID cargo; ///< ID of the cargo this entry is associated with. + bool transfers; ///< If there are transfers for this cargo. + }; + }; + uint num_children; ///< the number of subentries belonging to this entry. + uint count; ///< sum of counts of all children or amount of cargo for this entry. + CargoDataSet *children; ///< the children of this entry. +}; + +CargoDataEntry::CargoDataEntry() : + parent(NULL), + station(INVALID_STATION), + num_children(0), + count(0), + children(new CargoDataSet(CargoSorter(ST_CARGO_ID))) +{} + +CargoDataEntry::CargoDataEntry(CargoID cargo, uint count, CargoDataEntry *parent) : + parent(parent), + cargo(cargo), + num_children(0), + count(count), + children(new CargoDataSet) +{} + +CargoDataEntry::CargoDataEntry(StationID station, uint count, CargoDataEntry *parent) : + parent(parent), + station(station), + num_children(0), + count(count), + children(new CargoDataSet) +{} + +CargoDataEntry::CargoDataEntry(StationID station) : + parent(NULL), + station(station), + num_children(0), + count(0), + children(NULL) +{} + +CargoDataEntry::CargoDataEntry(CargoID cargo) : + parent(NULL), + cargo(cargo), + num_children(0), + count(0), + children(NULL) +{} + +CargoDataEntry::~CargoDataEntry() +{ + this->Clear(); + delete this->children; +} + +/** + * Delete all subentries, reset count and num_children and adapt parent's count. + */ +void CargoDataEntry::Clear() +{ + if (this->children != NULL) { + for (CargoDataSet::iterator i = this->children->begin(); i != this->children->end(); ++i) { + assert(*i != this); + delete *i; + } + this->children->clear(); + } + if (this->parent != NULL) this->parent->count -= this->count; + this->count = 0; + this->num_children = 0; +} + +/** + * Remove a subentry from this one and delete it. + * @param child the entry to be removed. This may also be a synthetic entry + * which only contains the ID of the entry to be removed. In this case child is + * not deleted. + */ +void CargoDataEntry::Remove(CargoDataEntry *child) +{ + CargoDataSet::iterator i = this->children->find(child); + if (i != this->children->end()) { + delete *i; + this->children->erase(i); + } +} + +/** + * Retrieve a subentry or insert it if it doesn't exist, yet. + * @tparam ID type of ID: either StationID or CargoID + * @param child_id ID of the child to be inserted or retrieved. + * @return the new or retrieved subentry + */ +template +CargoDataEntry *CargoDataEntry::InsertOrRetrieve(Tid child_id) +{ + CargoDataEntry tmp(child_id); + CargoDataSet::iterator i = this->children->find(&tmp); + if (i == this->children->end()) { + IncrementSize(); + return *(this->children->insert(new CargoDataEntry(child_id, 0, this)).first); + } else { + CargoDataEntry *ret = *i; + assert(this->children->value_comp().GetSortType() != ST_COUNT); + return ret; + } +} + +/** + * Update the count for this entry and propagate the change to the parent entry + * if there is one. + * @param count the amount to be added to this entry + */ +void CargoDataEntry::Update(uint count) +{ + this->count += count; + if (this->parent != NULL) this->parent->Update(count); +} + +/** + * Increment + */ +void CargoDataEntry::IncrementSize() +{ + ++this->num_children; + if (this->parent != NULL) this->parent->IncrementSize(); +} + +void CargoDataEntry::Resort(CargoSortType type, SortOrder order) +{ + CargoDataSet *new_subs = new CargoDataSet(this->children->begin(), this->children->end(), CargoSorter(type, order)); + delete this->children; + this->children = new_subs; +} + +CargoDataEntry *CargoDataEntry::Retrieve(CargoDataSet::iterator i) const +{ + if (i == this->children->end()) { + return NULL; + } else { + assert(this->children->value_comp().GetSortType() != ST_COUNT); + return *i; + } +} + +bool CargoSorter::operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const +{ + switch (this->type) { + case ST_STATION_ID: + return this->SortId(cd1->GetStation(), cd2->GetStation()); + case ST_CARGO_ID: + return this->SortId(cd1->GetCargo(), cd2->GetCargo()); + case ST_COUNT: + return this->SortCount(cd1, cd2); + case ST_STATION_STRING: + return this->SortStation(cd1->GetStation(), cd2->GetStation()); + default: + NOT_REACHED(); + } +} + +template +bool CargoSorter::SortId(Tid st1, Tid st2) const +{ + return (this->order == SO_ASCENDING) ? st1 < st2 : st2 < st1; +} + +bool CargoSorter::SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const +{ + uint c1 = cd1->GetCount(); + uint c2 = cd2->GetCount(); + if (c1 == c2) { + return this->SortStation(cd1->GetStation(), cd2->GetStation()); + } else if (this->order == SO_ASCENDING) { + return c1 < c2; + } else { + return c2 < c1; + } +} + +bool CargoSorter::SortStation(StationID st1, StationID st2) const +{ + static char buf1[MAX_LENGTH_STATION_NAME_CHARS]; + static char buf2[MAX_LENGTH_STATION_NAME_CHARS]; + + if (!Station::IsValidID(st1)) { + return Station::IsValidID(st2) ? this->order == SO_ASCENDING : this->SortId(st1, st2); + } else if (!Station::IsValidID(st2)) { + return order == SO_DESCENDING; + } + + SetDParam(0, st1); + GetString(buf1, STR_STATION_NAME, lastof(buf1)); + SetDParam(0, st2); + GetString(buf2, STR_STATION_NAME, lastof(buf2)); + + int res = strcmp(buf1, buf2); + if (res == 0) { + return this->SortId(st1, st2); + } else { + return (this->order == SO_ASCENDING) ? res < 0 : res > 0; + } +} + +/** + * The StationView window + */ +struct StationViewWindow : public Window { + /** + * A row being displayed in the cargo view (as opposed to being "hidden" behind a plus sign). + */ + struct RowDisplay { + RowDisplay(CargoDataEntry *f, StationID n) : filter(f), next_station(n) {} + RowDisplay(CargoDataEntry *f, CargoID n) : filter(f), next_cargo(n) {} + + /** + * Parent of the cargo entry belonging to the row. + */ + CargoDataEntry *filter; + union { + /** + * ID of the station belonging to the entry actually displayed if it's to/from/via. + */ + StationID next_station; + + /** + * ID of the cargo belonging to the entry actually displayed if it's cargo. + */ + CargoID next_cargo; + }; + }; + + typedef std::vector CargoDataVector; + + static const int NUM_COLUMNS = 4; ///< Number of "columns" in the cargo view: cargo, from, via, to + + /** + * Type of data invalidation. + */ + enum Invalidation { + INV_FLOWS = 0x100, ///< The planned flows have been recalculated and everything has to be updated. + INV_CARGO = 0x200 ///< Some cargo has been added or removed. + }; + + /** + * Type of grouping used in each of the "columns". + */ + enum Grouping { + GR_SOURCE, ///< Group by source of cargo ("from"). + GR_NEXT, ///< Group by next station ("via"). + GR_DESTINATION, ///< Group by estimated final destination ("to"). + GR_CARGO, ///< Group by cargo type. + }; + + /** + * Display mode of the cargo view. + */ + enum Mode { + MODE_WAITING, ///< Show cargo waiting at the station. + MODE_PLANNED ///< Show cargo planned to pass through the station. + }; + + uint expand_shrink_width; ///< The width allocated to the expand/shrink 'button' + int rating_lines; ///< Number of lines in the cargo ratings view. + int accepts_lines; ///< Number of lines in the accepted cargo view. + Scrollbar *vscroll; + + /** Height of the #WID_SV_ACCEPT_RATING_LIST widget for different views. */ + enum AcceptListHeight { + ALH_RATING = 13, ///< Height of the cargo ratings view. + ALH_ACCEPTS = 3, ///< Height of the accepted cargo view. + }; + + static const StringID _sort_names[]; ///< Names of the sorting options in the dropdown. + static const StringID _group_names[]; ///< Names of the grouping options in the dropdown. + + /** + * Sort types of the different 'columns'. + * In fact only ST_COUNT and ST_AS_GROUPING are active and you can only + * sort all the columns in the same way. The other options haven't been + * included in the GUI due to lack of space. + */ + CargoSortType sortings[NUM_COLUMNS]; + + /** Sort order (ascending/descending) for the 'columns'. */ + SortOrder sort_orders[NUM_COLUMNS]; + + int scroll_to_row; ///< If set, scroll the main viewport to the station pointed to by this row. + int grouping_index; ///< Currently selected entry in the grouping drop down. + Mode current_mode; ///< Currently selected display mode of cargo view. + Grouping groupings[NUM_COLUMNS]; ///< Grouping modes for the different columns. + + CargoDataEntry expanded_rows; ///< Parent entry of currently expanded rows. + CargoDataEntry cached_destinations; ///< Cache for the flows passing through this station. + CargoDataVector displayed_rows; ///< Parent entry of currently displayed rows (including collapsed ones). + + StationViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), + scroll_to_row(INT_MAX), grouping_index(0) + { + this->rating_lines = ALH_RATING; + this->accepts_lines = ALH_ACCEPTS; + + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_SV_SCROLLBAR); + /* Nested widget tree creation is done in two steps to ensure that this->GetWidget(WID_SV_ACCEPTS_RATINGS) exists in UpdateWidgetSize(). */ + this->FinishInitNested(window_number); + + this->groupings[0] = GR_CARGO; + this->sortings[0] = ST_AS_GROUPING; + this->SelectGroupBy(_settings_client.gui.station_gui_group_order); + this->SelectSortBy(_settings_client.gui.station_gui_sort_by); + this->sort_orders[0] = SO_ASCENDING; + this->SelectSortOrder((SortOrder)_settings_client.gui.station_gui_sort_order); + Owner owner = Station::Get(window_number)->owner; + if (owner != OWNER_NONE) this->owner = owner; + } + + ~StationViewWindow() + { + Owner owner = Station::Get(this->window_number)->owner; + DeleteWindowById(WC_TRAINS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_TRAIN, owner, this->window_number).Pack(), false); + DeleteWindowById(WC_ROADVEH_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_ROAD, owner, this->window_number).Pack(), false); + DeleteWindowById(WC_SHIPS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_SHIP, owner, this->window_number).Pack(), false); + DeleteWindowById(WC_AIRCRAFT_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_AIRCRAFT, owner, this->window_number).Pack(), false); + } + + /** + * Show a certain cargo entry characterized by source/next/dest station, cargo ID and amount of cargo at the + * right place in the cargo view. I.e. update as many rows as are expanded following that characterization. + * @param data Root entry of the tree. + * @param cargo Cargo ID of the entry to be shown. + * @param source Source station of the entry to be shown. + * @param next Next station the cargo to be shown will visit. + * @param dest Final destination of the cargo to be shown. + * @param count Amount of cargo to be shown. + */ + void ShowCargo(CargoDataEntry *data, CargoID cargo, StationID source, StationID next, StationID dest, uint count) + { + if (count == 0) return; + bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL; + const CargoDataEntry *expand = &this->expanded_rows; + for (int i = 0; i < NUM_COLUMNS && expand != NULL; ++i) { + switch (groupings[i]) { + case GR_CARGO: + assert(i == 0); + data = data->InsertOrRetrieve(cargo); + data->SetTransfers(source != this->window_number); + expand = expand->Retrieve(cargo); + break; + case GR_SOURCE: + if (auto_distributed || source != this->window_number) { + data = data->InsertOrRetrieve(source); + expand = expand->Retrieve(source); + } + break; + case GR_NEXT: + if (auto_distributed) { + data = data->InsertOrRetrieve(next); + expand = expand->Retrieve(next); + } + break; + case GR_DESTINATION: + if (auto_distributed) { + data = data->InsertOrRetrieve(dest); + expand = expand->Retrieve(dest); + } + break; + } + } + data->Update(count); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_SV_WAITING: + resize->height = FONT_HEIGHT_NORMAL; + size->height = WD_FRAMERECT_TOP + 4 * resize->height + WD_FRAMERECT_BOTTOM; + this->expand_shrink_width = max(GetStringBoundingBox("-").width, GetStringBoundingBox("+").width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + break; + + case WID_SV_ACCEPT_RATING_LIST: + size->height = WD_FRAMERECT_TOP + ((this->GetWidget(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) ? this->accepts_lines : this->rating_lines) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; + break; + + case WID_SV_CLOSE_AIRPORT: + if (!(Station::Get(this->window_number)->facilities & FACIL_AIRPORT)) { + /* Hide 'Close Airport' button if no airport present. */ + size->width = 0; + resize->width = 0; + fill->width = 0; + } + break; + + case WID_SV_SORT_ORDER: + case WID_SV_GROUP: + *size = maxdim(GetStringBoundingBox(STR_BUTTON_SORT_BY), GetStringBoundingBox(STR_STATION_VIEW_GROUP)); + size->width += padding.width; + break; + } + } + + virtual void OnPaint() + { + const Station *st = Station::Get(this->window_number); + CargoDataEntry cargo; + BuildCargoList(&cargo, st); + + this->vscroll->SetCount(cargo.GetNumChildren()); // update scrollbar + + /* disable some buttons */ + this->SetWidgetDisabledState(WID_SV_RENAME, st->owner != _local_company); + this->SetWidgetDisabledState(WID_SV_TRAINS, !(st->facilities & FACIL_TRAIN)); + this->SetWidgetDisabledState(WID_SV_ROADVEHS, !(st->facilities & FACIL_TRUCK_STOP) && !(st->facilities & FACIL_BUS_STOP)); + this->SetWidgetDisabledState(WID_SV_SHIPS, !(st->facilities & FACIL_DOCK)); + this->SetWidgetDisabledState(WID_SV_PLANES, !(st->facilities & FACIL_AIRPORT)); + this->SetWidgetDisabledState(WID_SV_CLOSE_AIRPORT, !(st->facilities & FACIL_AIRPORT) || st->owner != _local_company || st->owner == OWNER_NONE); // Also consider SE, where _local_company == OWNER_NONE + this->SetWidgetLoweredState(WID_SV_CLOSE_AIRPORT, (st->facilities & FACIL_AIRPORT) && (st->airport.flags & AIRPORT_CLOSED_block) != 0); + + this->DrawWidgets(); + + if (!this->IsShaded()) { + /* Draw 'accepted cargo' or 'cargo ratings'. */ + const NWidgetBase *wid = this->GetWidget(WID_SV_ACCEPT_RATING_LIST); + const Rect r = {wid->pos_x, wid->pos_y, wid->pos_x + wid->current_x - 1, wid->pos_y + wid->current_y - 1}; + if (this->GetWidget(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) { + int lines = this->DrawAcceptedCargo(r); + if (lines > this->accepts_lines) { // Resize the widget, and perform re-initialization of the window. + this->accepts_lines = lines; + this->ReInit(); + return; + } + } else { + int lines = this->DrawCargoRatings(r); + if (lines > this->rating_lines) { // Resize the widget, and perform re-initialization of the window. + this->rating_lines = lines; + this->ReInit(); + return; + } + } + + /* Draw arrow pointing up/down for ascending/descending sorting */ + this->DrawSortButtonState(WID_SV_SORT_ORDER, sort_orders[1] == SO_ASCENDING ? SBS_UP : SBS_DOWN); + + int pos = this->vscroll->GetPosition(); + + int maxrows = this->vscroll->GetCapacity(); + + displayed_rows.clear(); + + /* Draw waiting cargo. */ + NWidgetBase *nwi = this->GetWidget(WID_SV_WAITING); + Rect waiting_rect = {nwi->pos_x, nwi->pos_y, nwi->pos_x + nwi->current_x - 1, nwi->pos_y + nwi->current_y - 1}; + this->DrawEntries(&cargo, waiting_rect, pos, maxrows, 0); + scroll_to_row = INT_MAX; + } + } + + virtual void SetStringParameters(int widget) const + { + const Station *st = Station::Get(this->window_number); + SetDParam(0, st->index); + SetDParam(1, st->facilities); + } + + /** + * Rebuild the cache for estimated destinations which is used to quickly show the "destination" entries + * even if we actually don't know the destination of a certain packet from just looking at it. + * @param i Cargo to recalculate the cache for. + */ + void RecalcDestinations(CargoID i) + { + const Station *st = Station::Get(this->window_number); + CargoDataEntry *cargo_entry = cached_destinations.InsertOrRetrieve(i); + cargo_entry->Clear(); + + const FlowStatMap &flows = st->goods[i].flows; + for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) { + StationID from = it->first; + CargoDataEntry *source_entry = cargo_entry->InsertOrRetrieve(from); + const FlowStat::SharesMap *shares = it->second.GetShares(); + uint32 prev_count = 0; + for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) { + StationID via = flow_it->second; + CargoDataEntry *via_entry = source_entry->InsertOrRetrieve(via); + if (via == this->window_number) { + via_entry->InsertOrRetrieve(via)->Update(flow_it->first - prev_count); + } else { + EstimateDestinations(i, from, via, flow_it->first - prev_count, via_entry); + } + prev_count = flow_it->first; + } + } + } + + /** + * Estimate the amounts of cargo per final destination for a given cargo, source station and next hop and + * save the result as children of the given CargoDataEntry. + * @param cargo ID of the cargo to estimate destinations for. + * @param source Source station of the given batch of cargo. + * @param next Intermediate hop to start the calculation at ("next hop"). + * @param count Size of the batch of cargo. + * @param dest CargoDataEntry to save the results in. + */ + void EstimateDestinations(CargoID cargo, StationID source, StationID next, uint count, CargoDataEntry *dest) + { + if (Station::IsValidID(next) && Station::IsValidID(source)) { + CargoDataEntry tmp; + const FlowStatMap &flowmap = Station::Get(next)->goods[cargo].flows; + FlowStatMap::const_iterator map_it = flowmap.find(source); + if (map_it != flowmap.end()) { + const FlowStat::SharesMap *shares = map_it->second.GetShares(); + uint32 prev_count = 0; + for (FlowStat::SharesMap::const_iterator i = shares->begin(); i != shares->end(); ++i) { + tmp.InsertOrRetrieve(i->second)->Update(i->first - prev_count); + prev_count = i->first; + } + } + + if (tmp.GetCount() == 0) { + dest->InsertOrRetrieve(INVALID_STATION)->Update(count); + } else { + uint sum_estimated = 0; + while (sum_estimated < count) { + for (CargoDataSet::iterator i = tmp.Begin(); i != tmp.End() && sum_estimated < count; ++i) { + CargoDataEntry *child = *i; + uint estimate = DivideApprox(child->GetCount() * count, tmp.GetCount()); + if (estimate == 0) estimate = 1; + + sum_estimated += estimate; + if (sum_estimated > count) { + estimate -= sum_estimated - count; + sum_estimated = count; + } + + if (estimate > 0) { + if (child->GetStation() == next) { + dest->InsertOrRetrieve(next)->Update(estimate); + } else { + EstimateDestinations(cargo, source, child->GetStation(), estimate, dest); + } + } + } + + } + } + } else { + dest->InsertOrRetrieve(INVALID_STATION)->Update(count); + } + } + + /** + * Build up the cargo view for PLANNED mode and a specific cargo. + * @param i Cargo to show. + * @param flows The current station's flows for that cargo. + * @param cargo The CargoDataEntry to save the results in. + */ + void BuildFlowList(CargoID i, const FlowStatMap &flows, CargoDataEntry *cargo) + { + const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i); + for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) { + StationID from = it->first; + const CargoDataEntry *source_entry = source_dest->Retrieve(from); + const FlowStat::SharesMap *shares = it->second.GetShares(); + for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) { + const CargoDataEntry *via_entry = source_entry->Retrieve(flow_it->second); + for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) { + CargoDataEntry *dest_entry = *dest_it; + ShowCargo(cargo, i, from, flow_it->second, dest_entry->GetStation(), dest_entry->GetCount()); + } + } + } + } + + /** + * Build up the cargo view for WAITING mode and a specific cargo. + * @param i Cargo to show. + * @param packets The current station's cargo list for that cargo. + * @param cargo The CargoDataEntry to save the result in. + */ + void BuildCargoList(CargoID i, const StationCargoList &packets, CargoDataEntry *cargo) + { + const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i); + for (StationCargoList::ConstIterator it = packets.Packets()->begin(); it != packets.Packets()->end(); it++) { + const CargoPacket *cp = *it; + StationID next = it.GetKey(); + + const CargoDataEntry *source_entry = source_dest->Retrieve(cp->SourceStation()); + if (source_entry == NULL) { + this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count()); + continue; + } + + const CargoDataEntry *via_entry = source_entry->Retrieve(next); + if (via_entry == NULL) { + this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count()); + continue; + } + + for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) { + CargoDataEntry *dest_entry = *dest_it; + uint val = DivideApprox(cp->Count() * dest_entry->GetCount(), via_entry->GetCount()); + this->ShowCargo(cargo, i, cp->SourceStation(), next, dest_entry->GetStation(), val); + } + } + this->ShowCargo(cargo, i, NEW_STATION, NEW_STATION, NEW_STATION, packets.ReservedCount()); + } + + /** + * Build up the cargo view for all cargoes. + * @param cargo The root cargo entry to save all results in. + * @param st The station to calculate the cargo view from. + */ + void BuildCargoList(CargoDataEntry *cargo, const Station *st) + { + for (CargoID i = 0; i < NUM_CARGO; i++) { + + if (this->cached_destinations.Retrieve(i) == NULL) { + this->RecalcDestinations(i); + } + + if (this->current_mode == MODE_WAITING) { + this->BuildCargoList(i, st->goods[i].cargo, cargo); + } else { + this->BuildFlowList(i, st->goods[i].flows, cargo); + } + } + } + + /** + * Mark a specific row, characterized by its CargoDataEntry, as expanded. + * @param data The row to be marked as expanded. + */ + void SetDisplayedRow(const CargoDataEntry *data) + { + std::list stations; + const CargoDataEntry *parent = data->GetParent(); + if (parent->GetParent() == NULL) { + this->displayed_rows.push_back(RowDisplay(&this->expanded_rows, data->GetCargo())); + return; + } + + StationID next = data->GetStation(); + while (parent->GetParent()->GetParent() != NULL) { + stations.push_back(parent->GetStation()); + parent = parent->GetParent(); + } + + CargoID cargo = parent->GetCargo(); + CargoDataEntry *filter = this->expanded_rows.Retrieve(cargo); + while (!stations.empty()) { + filter = filter->Retrieve(stations.back()); + stations.pop_back(); + } + + this->displayed_rows.push_back(RowDisplay(filter, next)); + } + + /** + * Select the correct string for an entry referring to the specified station. + * @param station Station the entry is showing cargo for. + * @param here String to be shown if the entry refers to the same station as this station GUI belongs to. + * @param other_station String to be shown if the entry refers to a specific other station. + * @param any String to be shown if the entry refers to "any station". + * @return One of the three given strings or STR_STATION_VIEW_RESERVED, depending on what station the entry refers to. + */ + StringID GetEntryString(StationID station, StringID here, StringID other_station, StringID any) + { + if (station == this->window_number) { + return here; + } else if (station == INVALID_STATION) { + return any; + } else if (station == NEW_STATION) { + return STR_STATION_VIEW_RESERVED; + } else { + SetDParam(2, station); + return other_station; + } + } + + /** + * Determine if we need to show the special "non-stop" string. + * @param cd Entry we are going to show. + * @param station Station the entry refers to. + * @param column The "column" the entry will be shown in. + * @return either STR_STATION_VIEW_VIA or STR_STATION_VIEW_NONSTOP. + */ + StringID SearchNonStop(CargoDataEntry *cd, StationID station, int column) + { + CargoDataEntry *parent = cd->GetParent(); + for (int i = column - 1; i > 0; --i) { + if (this->groupings[i] == GR_DESTINATION) { + if (parent->GetStation() == station) { + return STR_STATION_VIEW_NONSTOP; + } else { + return STR_STATION_VIEW_VIA; + } + } + parent = parent->GetParent(); + } + + if (this->groupings[column + 1] == GR_DESTINATION) { + CargoDataSet::iterator begin = cd->Begin(); + CargoDataSet::iterator end = cd->End(); + if (begin != end && ++(cd->Begin()) == end && (*(begin))->GetStation() == station) { + return STR_STATION_VIEW_NONSTOP; + } else { + return STR_STATION_VIEW_VIA; + } + } + + return STR_STATION_VIEW_VIA; + } + + /** + * Draw the given cargo entries in the station GUI. + * @param entry Root entry for all cargo to be drawn. + * @param r Screen rectangle to draw into. + * @param pos Current row to be drawn to (counted down from 0 to -maxrows, same as vscroll->GetPosition()). + * @param maxrows Maximum row to be drawn. + * @param column Current "column" being drawn. + * @param cargo Current cargo being drawn (if cargo column has been passed). + * @return row (in "pos" counting) after the one we have last drawn to. + */ + int DrawEntries(CargoDataEntry *entry, Rect &r, int pos, int maxrows, int column, CargoID cargo = CT_INVALID) + { + if (this->sortings[column] == ST_AS_GROUPING) { + if (this->groupings[column] != GR_CARGO) { + entry->Resort(ST_STATION_STRING, this->sort_orders[column]); + } + } else { + entry->Resort(ST_COUNT, this->sort_orders[column]); + } + for (CargoDataSet::iterator i = entry->Begin(); i != entry->End(); ++i) { + CargoDataEntry *cd = *i; + + Grouping grouping = this->groupings[column]; + if (grouping == GR_CARGO) cargo = cd->GetCargo(); + bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL; + + if (pos > -maxrows && pos <= 0) { + StringID str = STR_EMPTY; + int y = r.top + WD_FRAMERECT_TOP - pos * FONT_HEIGHT_NORMAL; + SetDParam(0, cargo); + SetDParam(1, cd->GetCount()); + + if (this->groupings[column] == GR_CARGO) { + str = STR_STATION_VIEW_WAITING_CARGO; + DrawCargoIcons(cd->GetCargo(), cd->GetCount(), r.left + WD_FRAMERECT_LEFT + this->expand_shrink_width, r.right - WD_FRAMERECT_RIGHT - this->expand_shrink_width, y); + } else { + if (!auto_distributed) grouping = GR_SOURCE; + StationID station = cd->GetStation(); + + switch (grouping) { + case GR_SOURCE: + str = this->GetEntryString(station, STR_STATION_VIEW_FROM_HERE, STR_STATION_VIEW_FROM, STR_STATION_VIEW_FROM_ANY); + break; + case GR_NEXT: + str = this->GetEntryString(station, STR_STATION_VIEW_VIA_HERE, STR_STATION_VIEW_VIA, STR_STATION_VIEW_VIA_ANY); + if (str == STR_STATION_VIEW_VIA) str = this->SearchNonStop(cd, station, column); + break; + case GR_DESTINATION: + str = this->GetEntryString(station, STR_STATION_VIEW_TO_HERE, STR_STATION_VIEW_TO, STR_STATION_VIEW_TO_ANY); + break; + default: + NOT_REACHED(); + } + if (pos == -this->scroll_to_row && Station::IsValidID(station)) { + ScrollMainWindowToTile(Station::Get(station)->xy); + } + } + + bool rtl = _current_text_dir == TD_RTL; + int text_left = rtl ? r.left + this->expand_shrink_width : r.left + WD_FRAMERECT_LEFT + column * this->expand_shrink_width; + int text_right = rtl ? r.right - WD_FRAMERECT_LEFT - column * this->expand_shrink_width : r.right - this->expand_shrink_width; + int shrink_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - this->expand_shrink_width + WD_FRAMERECT_LEFT; + int shrink_right = rtl ? r.left + this->expand_shrink_width - WD_FRAMERECT_RIGHT : r.right - WD_FRAMERECT_RIGHT; + + DrawString(text_left, text_right, y, str); + + if (column < NUM_COLUMNS - 1) { + const char *sym = NULL; + if (cd->GetNumChildren() > 0) { + sym = "-"; + } else if (auto_distributed && str != STR_STATION_VIEW_RESERVED) { + sym = "+"; + } else { + /* Only draw '+' if there is something to be shown. */ + const StationCargoList &list = Station::Get(this->window_number)->goods[cargo].cargo; + if (grouping == GR_CARGO && (list.ReservedCount() > 0 || cd->HasTransfers())) { + sym = "+"; + } + } + if (sym) DrawString(shrink_left, shrink_right, y, sym, TC_YELLOW); + } + this->SetDisplayedRow(cd); + } + --pos; + if (auto_distributed || column == 0) { + pos = this->DrawEntries(cd, r, pos, maxrows, column + 1, cargo); + } + } + return pos; + } + + /** + * Draw accepted cargo in the #WID_SV_ACCEPT_RATING_LIST widget. + * @param r Rectangle of the widget. + * @return Number of lines needed for drawing the accepted cargo. + */ + int DrawAcceptedCargo(const Rect &r) const + { + const Station *st = Station::Get(this->window_number); + + uint32 cargo_mask = 0; + for (CargoID i = 0; i < NUM_CARGO; i++) { + if (HasBit(st->goods[i].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE)) SetBit(cargo_mask, i); + } + SetDParam(0, cargo_mask); + int bottom = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INT32_MAX, STR_STATION_VIEW_ACCEPTS_CARGO); + return CeilDiv(bottom - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL); + } + + /** + * Draw cargo ratings in the #WID_SV_ACCEPT_RATING_LIST widget. + * @param r Rectangle of the widget. + * @return Number of lines needed for drawing the cargo ratings. + */ + int DrawCargoRatings(const Rect &r) const + { + const Station *st = Station::Get(this->window_number); + int y = r.top + WD_FRAMERECT_TOP; + + if (st->town->exclusive_counter > 0) { + SetDParam(0, st->town->exclusivity); + y = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, r.bottom, st->town->exclusivity == st->owner ? STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF : STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY); + y += WD_PAR_VSEP_WIDE; + } + + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_VIEW_SUPPLY_RATINGS_TITLE); + y += FONT_HEIGHT_NORMAL; + + const CargoSpec *cs; + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + const GoodsEntry *ge = &st->goods[cs->Index()]; + if (!ge->HasRating()) continue; + + const LinkGraph *lg = LinkGraph::GetIfValid(ge->link_graph); + SetDParam(0, cs->name); + SetDParam(1, lg != NULL ? lg->Monthly((*lg)[ge->node].Supply()) : 0); + SetDParam(2, STR_CARGO_RATING_APPALLING + (ge->rating >> 5)); + SetDParam(3, ToPercent8(ge->rating)); + DrawString(r.left + WD_FRAMERECT_LEFT + 6, r.right - WD_FRAMERECT_RIGHT - 6, y, STR_STATION_VIEW_CARGO_SUPPLY_RATING); + y += FONT_HEIGHT_NORMAL; + } + return CeilDiv(y - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL); + } + + /** + * Expand or collapse a specific row. + * @param filter Parent of the row. + * @param next ID pointing to the row. + */ + template + void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next) + { + if (filter->Retrieve(next) != NULL) { + filter->Remove(next); + } else { + filter->InsertOrRetrieve(next); + } + } + + /** + * Handle a click on a specific row in the cargo view. + * @param row Row being clicked. + */ + void HandleCargoWaitingClick(int row) + { + if (row < 0 || (uint)row >= this->displayed_rows.size()) return; + if (_ctrl_pressed) { + this->scroll_to_row = row; + } else { + RowDisplay &display = this->displayed_rows[row]; + if (display.filter == &this->expanded_rows) { + this->HandleCargoWaitingClick(display.filter, display.next_cargo); + } else { + this->HandleCargoWaitingClick(display.filter, display.next_station); + } + } + this->SetWidgetDirty(WID_SV_WAITING); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_SV_WAITING: + this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL) - this->vscroll->GetPosition()); + break; + + case WID_SV_LOCATION: + if (_ctrl_pressed) { + ShowExtraViewPortWindow(Station::Get(this->window_number)->xy); + } else { + ScrollMainWindowToTile(Station::Get(this->window_number)->xy); + } + break; + + case WID_SV_ACCEPTS_RATINGS: { + /* Swap between 'accepts' and 'ratings' view. */ + int height_change; + NWidgetCore *nwi = this->GetWidget(WID_SV_ACCEPTS_RATINGS); + if (this->GetWidget(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) { + nwi->SetDataTip(STR_STATION_VIEW_ACCEPTS_BUTTON, STR_STATION_VIEW_ACCEPTS_TOOLTIP); // Switch to accepts view. + height_change = this->rating_lines - this->accepts_lines; + } else { + nwi->SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP); // Switch to ratings view. + height_change = this->accepts_lines - this->rating_lines; + } + this->ReInit(0, height_change * FONT_HEIGHT_NORMAL); + break; + } + + case WID_SV_RENAME: + SetDParam(0, this->window_number); + ShowQueryString(STR_STATION_NAME, STR_STATION_VIEW_RENAME_STATION_CAPTION, MAX_LENGTH_STATION_NAME_CHARS, + this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); + break; + + case WID_SV_CLOSE_AIRPORT: + DoCommandP(0, this->window_number, 0, CMD_OPEN_CLOSE_AIRPORT); + break; + + case WID_SV_TRAINS: // Show list of scheduled trains to this station + case WID_SV_ROADVEHS: // Show list of scheduled road-vehicles to this station + case WID_SV_SHIPS: // Show list of scheduled ships to this station + case WID_SV_PLANES: { // Show list of scheduled aircraft to this station + Owner owner = Station::Get(this->window_number)->owner; + ShowVehicleListWindow(owner, (VehicleType)(widget - WID_SV_TRAINS), (StationID)this->window_number); + break; + } + + case WID_SV_SORT_BY: { + /* The initial selection is composed of current mode and + * sorting criteria for columns 1, 2, and 3. Column 0 is always + * sorted by cargo ID. The others can theoretically be sorted + * by different things but there is no UI for that. */ + ShowDropDownMenu(this, _sort_names, + this->current_mode * 2 + (this->sortings[1] == ST_COUNT ? 1 : 0), + WID_SV_SORT_BY, 0, 0); + break; + } + + case WID_SV_GROUP_BY: { + ShowDropDownMenu(this, _group_names, this->grouping_index, WID_SV_GROUP_BY, 0, 0); + break; + } + + case WID_SV_SORT_ORDER: { // flip sorting method asc/desc + this->SelectSortOrder(this->sort_orders[1] == SO_ASCENDING ? SO_DESCENDING : SO_ASCENDING); + this->SetTimeout(); + this->LowerWidget(WID_SV_SORT_ORDER); + break; + } + } + } + + /** + * Select a new sort order for the cargo view. + * @param order New sort order. + */ + void SelectSortOrder(SortOrder order) + { + this->sort_orders[1] = this->sort_orders[2] = this->sort_orders[3] = order; + _settings_client.gui.station_gui_sort_order = this->sort_orders[1]; + this->SetDirty(); + } + + /** + * Select a new sort criterium for the cargo view. + * @param index Row being selected in the sort criteria drop down. + */ + void SelectSortBy(int index) + { + _settings_client.gui.station_gui_sort_by = index; + switch (_sort_names[index]) { + case STR_STATION_VIEW_WAITING_STATION: + this->current_mode = MODE_WAITING; + this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING; + break; + case STR_STATION_VIEW_WAITING_AMOUNT: + this->current_mode = MODE_WAITING; + this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT; + break; + case STR_STATION_VIEW_PLANNED_STATION: + this->current_mode = MODE_PLANNED; + this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING; + break; + case STR_STATION_VIEW_PLANNED_AMOUNT: + this->current_mode = MODE_PLANNED; + this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT; + break; + default: + NOT_REACHED(); + } + /* Display the current sort variant */ + this->GetWidget(WID_SV_SORT_BY)->widget_data = _sort_names[index]; + this->SetDirty(); + } + + /** + * Select a new grouping mode for the cargo view. + * @param index Row being selected in the grouping drop down. + */ + void SelectGroupBy(int index) + { + this->grouping_index = index; + _settings_client.gui.station_gui_group_order = index; + this->GetWidget(WID_SV_GROUP_BY)->widget_data = _group_names[index]; + switch (_group_names[index]) { + case STR_STATION_VIEW_GROUP_S_V_D: + this->groupings[1] = GR_SOURCE; + this->groupings[2] = GR_NEXT; + this->groupings[3] = GR_DESTINATION; + break; + case STR_STATION_VIEW_GROUP_S_D_V: + this->groupings[1] = GR_SOURCE; + this->groupings[2] = GR_DESTINATION; + this->groupings[3] = GR_NEXT; + break; + case STR_STATION_VIEW_GROUP_V_S_D: + this->groupings[1] = GR_NEXT; + this->groupings[2] = GR_SOURCE; + this->groupings[3] = GR_DESTINATION; + break; + case STR_STATION_VIEW_GROUP_V_D_S: + this->groupings[1] = GR_NEXT; + this->groupings[2] = GR_DESTINATION; + this->groupings[3] = GR_SOURCE; + break; + case STR_STATION_VIEW_GROUP_D_S_V: + this->groupings[1] = GR_DESTINATION; + this->groupings[2] = GR_SOURCE; + this->groupings[3] = GR_NEXT; + break; + case STR_STATION_VIEW_GROUP_D_V_S: + this->groupings[1] = GR_DESTINATION; + this->groupings[2] = GR_NEXT; + this->groupings[3] = GR_SOURCE; + break; + } + this->SetDirty(); + } + + virtual void OnDropdownSelect(int widget, int index) + { + if (widget == WID_SV_SORT_BY) { + this->SelectSortBy(index); + } else { + this->SelectGroupBy(index); + } + } + + virtual void OnQueryTextFinished(char *str) + { + if (str == NULL) return; + + DoCommandP(0, this->window_number, 0, CMD_RENAME_STATION | CMD_MSG(STR_ERROR_CAN_T_RENAME_STATION), NULL, str); + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_SV_WAITING, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); + } + + /** + * Some data on this window has become invalid. Invalidate the cache for the given cargo if necessary. + * @param data Information about the changed data. If it's a valid cargo ID, invalidate the cargo 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (gui_scope) { + if (data >= 0 && data < NUM_CARGO) { + this->cached_destinations.Remove((CargoID)data); + } else { + this->ReInit(); + } + } + } +}; + +const StringID StationViewWindow::_sort_names[] = { + STR_STATION_VIEW_WAITING_STATION, + STR_STATION_VIEW_WAITING_AMOUNT, + STR_STATION_VIEW_PLANNED_STATION, + STR_STATION_VIEW_PLANNED_AMOUNT, + INVALID_STRING_ID +}; + +const StringID StationViewWindow::_group_names[] = { + STR_STATION_VIEW_GROUP_S_V_D, + STR_STATION_VIEW_GROUP_S_D_V, + STR_STATION_VIEW_GROUP_V_S_D, + STR_STATION_VIEW_GROUP_V_D_S, + STR_STATION_VIEW_GROUP_D_S_V, + STR_STATION_VIEW_GROUP_D_V_S, + INVALID_STRING_ID +}; + +static WindowDesc _station_view_desc( + WDP_AUTO, "view_station", 249, 117, + WC_STATION_VIEW, WC_NONE, + 0, + _nested_station_view_widgets, lengthof(_nested_station_view_widgets) +); + +/** + * Opens StationViewWindow for given station + * + * @param station station which window should be opened + */ +void ShowStationViewWindow(StationID station) +{ + AllocateWindowDescFront(&_station_view_desc, station); +} + +/** Struct containing TileIndex and StationID */ +struct TileAndStation { + TileIndex tile; ///< TileIndex + StationID station; ///< StationID +}; + +static SmallVector _deleted_stations_nearby; +static SmallVector _stations_nearby_list; + +/** + * Add station on this tile to _stations_nearby_list if it's fully within the + * station spread. + * @param tile Tile just being checked + * @param user_data Pointer to TileArea context + * @tparam T the type of station to look for + */ +template +static bool AddNearbyStation(TileIndex tile, void *user_data) +{ + TileArea *ctx = (TileArea *)user_data; + + /* First check if there were deleted stations here */ + for (uint i = 0; i < _deleted_stations_nearby.Length(); i++) { + TileAndStation *ts = _deleted_stations_nearby.Get(i); + if (ts->tile == tile) { + *_stations_nearby_list.Append() = _deleted_stations_nearby[i].station; + _deleted_stations_nearby.Erase(ts); + i--; + } + } + + /* Check if own station and if we stay within station spread */ + if (!IsTileType(tile, MP_STATION)) return false; + + StationID sid = GetStationIndex(tile); + + /* This station is (likely) a waypoint */ + if (!T::IsValidID(sid)) return false; + + T *st = T::Get(sid); + if (st->owner != _local_company || _stations_nearby_list.Contains(sid)) return false; + + if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) { + *_stations_nearby_list.Append() = sid; + } + + return false; // We want to include *all* nearby stations +} + +/** + * Circulate around the to-be-built station to find stations we could join. + * Make sure that only stations are returned where joining wouldn't exceed + * station spread and are our own station. + * @param ta Base tile area of the to-be-built station + * @param distant_join Search for adjacent stations (false) or stations fully + * within station spread + * @tparam T the type of station to look for + */ +template +static const T *FindStationsNearby(TileArea ta, bool distant_join) +{ + TileArea ctx = ta; + + _stations_nearby_list.Clear(); + _deleted_stations_nearby.Clear(); + + /* Check the inside, to return, if we sit on another station */ + TILE_AREA_LOOP(t, ta) { + if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t); + } + + /* Look for deleted stations */ + const BaseStation *st; + FOR_ALL_BASE_STATIONS(st) { + if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) { + /* Include only within station spread (yes, it is strictly less than) */ + if (max(DistanceMax(ta.tile, st->xy), DistanceMax(TILE_ADDXY(ta.tile, ta.w - 1, ta.h - 1), st->xy)) < _settings_game.station.station_spread) { + TileAndStation *ts = _deleted_stations_nearby.Append(); + ts->tile = st->xy; + ts->station = st->index; + + /* Add the station when it's within where we're going to build */ + if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) && + IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) { + AddNearbyStation(st->xy, &ctx); + } + } + } + } + + /* Only search tiles where we have a chance to stay within the station spread. + * The complete check needs to be done in the callback as we don't know the + * extent of the found station, yet. */ + if (distant_join && min(ta.w, ta.h) >= _settings_game.station.station_spread) return NULL; + uint max_dist = distant_join ? _settings_game.station.station_spread - min(ta.w, ta.h) : 1; + + TileIndex tile = TILE_ADD(ctx.tile, TileOffsByDir(DIR_N)); + CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation, &ctx); + + return NULL; +} + +static const NWidgetPart _nested_select_station_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_JS_CAPTION), SetDataTip(STR_JOIN_STATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_JS_PANEL), SetResize(1, 0), SetScrollbar(WID_JS_SCROLLBAR), EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_JS_SCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), + EndContainer(), + EndContainer(), +}; + +/** + * Window for selecting stations/waypoints to (distant) join to. + * @tparam T The type of station to join with + */ +template +struct SelectStationWindow : Window { + CommandContainer select_station_cmd; ///< Command to build new station + TileArea area; ///< Location of new station + Scrollbar *vscroll; + + SelectStationWindow(WindowDesc *desc, const CommandContainer &cmd, TileArea ta) : + Window(desc), + select_station_cmd(cmd), + area(ta) + { + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_JS_SCROLLBAR); + this->GetWidget(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION; + this->FinishInitNested(0); + this->OnInvalidateData(0); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget != WID_JS_PANEL) return; + + /* Determine the widest string */ + Dimension d = GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); + for (uint i = 0; i < _stations_nearby_list.Length(); i++) { + const T *st = T::Get(_stations_nearby_list[i]); + SetDParam(0, st->index); + SetDParam(1, st->facilities); + d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION)); + } + + resize->height = GetMinSizing(NWST_STEP, d.height); + d.height = 5 * resize->height; + d.width += WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT; + d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + *size = d; + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_JS_PANEL) return; + + uint y = Center(r.top, this->resize.step_height); + if (this->vscroll->GetPosition() == 0) { + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); + y += this->resize.step_height; + } + + for (uint i = max(1, this->vscroll->GetPosition()); i <= _stations_nearby_list.Length(); ++i, y += this->resize.step_height) { + /* Don't draw anything if it extends past the end of the window. */ + if (i - this->vscroll->GetPosition() >= this->vscroll->GetCapacity()) break; + + const T *st = T::Get(_stations_nearby_list[i - 1]); + SetDParam(0, st->index); + SetDParam(1, st->facilities); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION); + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + if (widget != WID_JS_PANEL) return; + + uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WD_FRAMERECT_TOP); + bool distant_join = (st_index > 0); + if (distant_join) st_index--; + + if (distant_join && st_index >= _stations_nearby_list.Length()) return; + + /* Insert station to be joined into stored command */ + SB(this->select_station_cmd.p2, 16, 16, + (distant_join ? _stations_nearby_list[st_index] : NEW_STATION)); + + /* Execute stored Command */ + DoCommandP(&this->select_station_cmd); + + /* Close Window; this might cause double frees! */ + DeleteWindowById(WC_SELECT_STATION, 0); + } + + virtual void OnTick() + { + if (_thd.dirty & 2) { + _thd.dirty &= ~2; + this->SetDirty(); + } + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_JS_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + FindStationsNearby(this->area, true); + this->vscroll->SetCount(_stations_nearby_list.Length() + 1); + this->SetDirty(); + } +}; + +static WindowDesc _select_station_desc( + WDP_AUTO, "build_station_join", 200, 180, + WC_SELECT_STATION, WC_NONE, + WDF_CONSTRUCTION, + _nested_select_station_widgets, lengthof(_nested_select_station_widgets) +); + + +/** + * Check whether we need to show the station selection window. + * @param cmd Command to build the station. + * @param ta Tile area of the to-be-built station + * @tparam T the type of station + * @return whether we need to show the station selection window. + */ +template +static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta) +{ + /* Only show selection if distant join is enabled in the settings */ + if (!_settings_game.station.distant_join_stations) return false; + + /* If a window is already opened and we didn't ctrl-click, + * return true (i.e. just flash the old window) */ + Window *selection_window = FindWindowById(WC_SELECT_STATION, 0); + if (selection_window != NULL) { + /* Abort current distant-join and start new one */ + delete selection_window; + UpdateTileSelection(); + } + + /* only show the popup, if we press ctrl */ + if (!_ctrl_pressed) return false; + + /* Now check if we could build there */ + if (DoCommand(&cmd, CommandFlagsToDCFlags(GetCommandFlags(cmd.cmd))).Failed()) return false; + + /* Test for adjacent station or station below selection. + * If adjacent-stations is disabled and we are building next to a station, do not show the selection window. + * but join the other station immediately. */ + const T *st = FindStationsNearby(ta, false); + return st == NULL && (_settings_game.station.adjacent_stations || _stations_nearby_list.Length() == 0); +} + +/** + * Show the station selection window when needed. If not, build the station. + * @param cmd Command to build the station. + * @param ta Area to build the station in + * @tparam the class to find stations for + */ +template +void ShowSelectBaseStationIfNeeded(const CommandContainer &cmd, TileArea ta) +{ + if (StationJoinerNeeded(cmd, ta)) { + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + new SelectStationWindow(&_select_station_desc, cmd, ta); + } else { + DoCommandP(&cmd); + } +} + +/** + * Show the station selection window when needed. If not, build the station. + * @param cmd Command to build the station. + * @param ta Area to build the station in + */ +void ShowSelectStationIfNeeded(const CommandContainer &cmd, TileArea ta) +{ + ShowSelectBaseStationIfNeeded(cmd, ta); +} + +/** + * Show the waypoint selection window when needed. If not, build the waypoint. + * @param cmd Command to build the waypoint. + * @param ta Area to build the waypoint in + */ +void ShowSelectWaypointIfNeeded(const CommandContainer &cmd, TileArea ta) +{ + ShowSelectBaseStationIfNeeded(cmd, ta); +} diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index d1815ca9b2..be85e8a0b1 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -259,13 +259,6 @@ struct TerraformToolbarWindow : Window { VpSelectTilesWithMethod(pt.x, pt.y, select_method); } - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) - { - Point pt = GetToolbarAlignedWindowPosition(sm_width); - pt.y += sm_height; - return pt; - } - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) { if (pt.x != -1) { @@ -348,7 +341,7 @@ static const NWidgetPart _nested_terraform_widgets[] = { }; static WindowDesc _terraform_desc( - WDP_MANUAL, "toolbar_landscape", 0, 0, + WDP_ALIGN_TOOLBAR, "toolbar_landscape", 0, 0, WC_SCEN_LAND_GEN, WC_NONE, WDF_CONSTRUCTION, _nested_terraform_widgets, lengthof(_nested_terraform_widgets), @@ -374,7 +367,6 @@ Window *ShowTerraformToolbar(Window *link) DeleteWindowById(WC_SCEN_LAND_GEN, 0, true); w = AllocateWindowDescFront(&_terraform_desc, 0); /* Align the terraform toolbar under the main toolbar. */ - w->top -= w->height; w->SetDirty(); /* Put the linked toolbar to the left / right of it. */ link->left = w->left + (_current_text_dir == TD_RTL ? w->width : -link->width); diff --git a/src/terraform_gui.cpp.orig b/src/terraform_gui.cpp.orig new file mode 100644 index 0000000000..d1815ca9b2 --- /dev/null +++ b/src/terraform_gui.cpp.orig @@ -0,0 +1,760 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file terraform_gui.cpp GUI related to terraforming the map. */ + +#include "stdafx.h" +#include "clear_map.h" +#include "company_func.h" +#include "company_base.h" +#include "gui.h" +#include "window_gui.h" +#include "window_func.h" +#include "viewport_func.h" +#include "command_func.h" +#include "signs_func.h" +#include "sound_func.h" +#include "base_station_base.h" +#include "textbuf_gui.h" +#include "genworld.h" +#include "tree_map.h" +#include "landscape_type.h" +#include "tilehighlight_func.h" +#include "strings_func.h" +#include "newgrf_object.h" +#include "object.h" +#include "hotkeys.h" +#include "engine_base.h" +#include "terraform_gui.h" + +#include "widgets/terraform_widget.h" + +#include "table/strings.h" + +void CcTerraform(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Succeeded()) { + if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); + } else { + extern TileIndex _terraform_err_tile; + SetRedErrorSquare(_terraform_err_tile); + } +} + + +/** Scenario editor command that generates desert areas */ +static void GenerateDesertArea(TileIndex end, TileIndex start) +{ + if (_game_mode != GM_EDITOR) return; + + _generating_world = true; + + TileArea ta(start, end); + TILE_AREA_LOOP(tile, ta) { + SetTropicZone(tile, (_ctrl_pressed) ? TROPICZONE_NORMAL : TROPICZONE_DESERT); + DoCommandP(tile, 0, 0, CMD_LANDSCAPE_CLEAR); + MarkTileDirtyByTile(tile); + } + _generating_world = false; + InvalidateWindowClassesData(WC_TOWN_VIEW, 0); +} + +/** Scenario editor command that generates rocky areas */ +static void GenerateRockyArea(TileIndex end, TileIndex start) +{ + if (_game_mode != GM_EDITOR) return; + + bool success = false; + TileArea ta(start, end); + + TILE_AREA_LOOP(tile, ta) { + switch (GetTileType(tile)) { + case MP_TREES: + if (GetTreeGround(tile) == TREE_GROUND_SHORE) continue; + /* FALL THROUGH */ + case MP_CLEAR: + MakeClear(tile, CLEAR_ROCKS, 3); + break; + + default: continue; + } + MarkTileDirtyByTile(tile); + success = true; + } + + if (success && _settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, end); +} + +/** + * A central place to handle all X_AND_Y dragged GUI functions. + * @param proc Procedure related to the dragging + * @param start_tile Begin of the dragging + * @param end_tile End of the dragging + * @return Returns true if the action was found and handled, and false otherwise. This + * allows for additional implements that are more local. For example X_Y drag + * of convertrail which belongs in rail_gui.cpp and not terraform_gui.cpp + */ +bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile) +{ + if (!_settings_game.construction.freeform_edges) { + /* When end_tile is MP_VOID, the error tile will not be visible to the + * user. This happens when terraforming at the southern border. */ + if (TileX(end_tile) == MapMaxX()) end_tile += TileDiffXY(-1, 0); + if (TileY(end_tile) == MapMaxY()) end_tile += TileDiffXY(0, -1); + } + + switch (proc) { + case DDSP_DEMOLISH_AREA: + DoCommandP(end_tile, start_tile, _ctrl_pressed ? 1 : 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound10); + break; + case DDSP_RAISE_AND_LEVEL_AREA: + DoCommandP(end_tile, start_tile, LM_RAISE << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_RAISE_LAND_HERE), CcTerraform); + break; + case DDSP_LOWER_AND_LEVEL_AREA: + DoCommandP(end_tile, start_tile, LM_LOWER << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LOWER_LAND_HERE), CcTerraform); + break; + case DDSP_LEVEL_AREA: + DoCommandP(end_tile, start_tile, LM_LEVEL << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LEVEL_LAND_HERE), CcTerraform); + break; + case DDSP_CREATE_ROCKS: + GenerateRockyArea(end_tile, start_tile); + break; + case DDSP_CREATE_DESERT: + GenerateDesertArea(end_tile, start_tile); + break; + default: + return false; + } + + return true; +} + +/** + * Start a drag for demolishing an area. + * @param tile Position of one corner. + */ +void PlaceProc_DemolishArea(TileIndex tile) +{ + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_DEMOLISH_AREA); +} + +/** Terra form toolbar managing class. */ +struct TerraformToolbarWindow : Window { + int last_user_action; ///< Last started user action. + + TerraformToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + /* This is needed as we like to have the tree available on OnInit. */ + this->CreateNestedTree(); + this->FinishInitNested(window_number); + this->last_user_action = WIDGET_LIST_END; + } + + ~TerraformToolbarWindow() + { + } + + virtual void OnInit() + { + /* Don't show the place object button when there are no objects to place. */ + NWidgetStacked *show_object = this->GetWidget(WID_TT_SHOW_PLACE_OBJECT); + show_object->SetDisplayedPlane(ObjectClass::GetUIClassCount() != 0 ? 0 : SZSP_NONE); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + if (widget < WID_TT_BUTTONS_START) return; + + switch (widget) { + case WID_TT_LOWER_LAND: // Lower land button + HandlePlacePushButton(this, WID_TT_LOWER_LAND, ANIMCURSOR_LOWERLAND, HT_POINT | HT_DIAGONAL); + this->last_user_action = widget; + break; + + case WID_TT_RAISE_LAND: // Raise land button + HandlePlacePushButton(this, WID_TT_RAISE_LAND, ANIMCURSOR_RAISELAND, HT_POINT | HT_DIAGONAL); + this->last_user_action = widget; + break; + + case WID_TT_LEVEL_LAND: // Level land button + HandlePlacePushButton(this, WID_TT_LEVEL_LAND, SPR_CURSOR_LEVEL_LAND, HT_POINT | HT_DIAGONAL); + this->last_user_action = widget; + break; + + case WID_TT_DEMOLISH: // Demolish aka dynamite button + HandlePlacePushButton(this, WID_TT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); + this->last_user_action = widget; + break; + + case WID_TT_BUY_LAND: // Buy land button + HandlePlacePushButton(this, WID_TT_BUY_LAND, SPR_CURSOR_BUY_LAND, HT_RECT); + this->last_user_action = widget; + break; + + case WID_TT_PLANT_TREES: // Plant trees button + ShowBuildTreesToolbar(); + break; + + case WID_TT_PLACE_SIGN: // Place sign button + HandlePlacePushButton(this, WID_TT_PLACE_SIGN, SPR_CURSOR_SIGN, HT_RECT); + this->last_user_action = widget; + break; + + case WID_TT_PLACE_OBJECT: // Place object button + /* Don't show the place object button when there are no objects to place. */ + if (ObjectClass::GetUIClassCount() == 0) return; + if (HandlePlacePushButton(this, WID_TT_PLACE_OBJECT, SPR_CURSOR_TRANSMITTER, HT_RECT)) { + ShowBuildObjectPicker(this); + this->last_user_action = widget; + } + break; + + default: NOT_REACHED(); + } + } + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + switch (this->last_user_action) { + case WID_TT_LOWER_LAND: // Lower land button + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LOWER_AND_LEVEL_AREA); + break; + + case WID_TT_RAISE_LAND: // Raise land button + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_RAISE_AND_LEVEL_AREA); + break; + + case WID_TT_LEVEL_LAND: // Level land button + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LEVEL_AREA); + break; + + case WID_TT_DEMOLISH: // Demolish aka dynamite button + PlaceProc_DemolishArea(tile); + break; + + case WID_TT_BUY_LAND: // Buy land button + DoCommandP(tile, OBJECT_OWNED_LAND, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_PURCHASE_THIS_LAND), CcPlaySound1E); + break; + + case WID_TT_PLACE_SIGN: // Place sign button + PlaceProc_Sign(tile); + break; + + case WID_TT_PLACE_OBJECT: // Place object button + PlaceProc_Object(tile); + break; + + default: NOT_REACHED(); + } + } + + virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + { + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + } + + virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + { + Point pt = GetToolbarAlignedWindowPosition(sm_width); + pt.y += sm_height; + return pt; + } + + virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + { + if (pt.x != -1) { + switch (select_proc) { + default: NOT_REACHED(); + case DDSP_DEMOLISH_AREA: + case DDSP_RAISE_AND_LEVEL_AREA: + case DDSP_LOWER_AND_LEVEL_AREA: + case DDSP_LEVEL_AREA: + GUIPlaceProcDragXY(select_proc, start_tile, end_tile); + break; + } + } + } + + virtual void OnPlaceObjectAbort() + { + DeleteWindowById(WC_BUILD_OBJECT, 0); + this->RaiseButtons(); + } + + static HotkeyList hotkeys; +}; + +/** + * Handler for global hotkeys of the TerraformToolbarWindow. + * @param hotkey Hotkey + * @return ES_HANDLED if hotkey was accepted. + */ +static EventState TerraformToolbarGlobalHotkeys(int hotkey) +{ + if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED; + Window *w = ShowTerraformToolbar(NULL); + if (w == NULL) return ES_NOT_HANDLED; + return w->OnHotkey(hotkey); +} + +static Hotkey terraform_hotkeys[] = { + Hotkey('Q' | WKC_GLOBAL_HOTKEY, "lower", WID_TT_LOWER_LAND), + Hotkey('W' | WKC_GLOBAL_HOTKEY, "raise", WID_TT_RAISE_LAND), + Hotkey('E' | WKC_GLOBAL_HOTKEY, "level", WID_TT_LEVEL_LAND), + Hotkey('D' | WKC_GLOBAL_HOTKEY, "dynamite", WID_TT_DEMOLISH), + Hotkey('U', "buyland", WID_TT_BUY_LAND), + Hotkey('I', "trees", WID_TT_PLANT_TREES), + Hotkey('O', "placesign", WID_TT_PLACE_SIGN), + Hotkey('P', "placeobject", WID_TT_PLACE_OBJECT), + HOTKEY_LIST_END +}; +HotkeyList TerraformToolbarWindow::hotkeys("terraform", terraform_hotkeys, TerraformToolbarGlobalHotkeys); + +static const NWidgetPart _nested_terraform_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_LANDSCAPING_TOOLBAR, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_LOWER_LAND), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_TERRAFORM_DOWN, STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_RAISE_LAND), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_TERRAFORM_UP, STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_LEVEL_LAND), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_LEVEL_LAND, STR_LANDSCAPING_LEVEL_LAND_TOOLTIP), + + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), EndContainer(), + + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_DEMOLISH), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_BUY_LAND), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_BUY_LAND, STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND), + NWidget(WWT_PUSHIMGBTN, COLOUR_DARK_GREEN, WID_TT_PLANT_TREES), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_PLACE_SIGN), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_TT_SHOW_PLACE_OBJECT), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_PLACE_OBJECT), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_TRANSMITTER, STR_SCENEDIT_TOOLBAR_PLACE_OBJECT), + EndContainer(), + EndContainer(), +}; + +static WindowDesc _terraform_desc( + WDP_MANUAL, "toolbar_landscape", 0, 0, + WC_SCEN_LAND_GEN, WC_NONE, + WDF_CONSTRUCTION, + _nested_terraform_widgets, lengthof(_nested_terraform_widgets), + &TerraformToolbarWindow::hotkeys +); + +/** + * Show the toolbar for terraforming in the game. + * @param link The toolbar we might want to link to. + * @return The allocated toolbar. + */ +Window *ShowTerraformToolbar(Window *link) +{ + if (!Company::IsValidID(_local_company)) return NULL; + + Window *w; + if (link == NULL) { + w = AllocateWindowDescFront(&_terraform_desc, 0); + return w; + } + + /* Delete the terraform toolbar to place it again. */ + DeleteWindowById(WC_SCEN_LAND_GEN, 0, true); + w = AllocateWindowDescFront(&_terraform_desc, 0); + /* Align the terraform toolbar under the main toolbar. */ + w->top -= w->height; + w->SetDirty(); + /* Put the linked toolbar to the left / right of it. */ + link->left = w->left + (_current_text_dir == TD_RTL ? w->width : -link->width); + link->top = w->top; + link->SetDirty(); + + return w; +} + +static byte _terraform_size = 1; + +/** + * Raise/Lower a bigger chunk of land at the same time in the editor. When + * raising get the lowest point, when lowering the highest point, and set all + * tiles in the selection to that height. + * @todo : Incorporate into game itself to allow for ingame raising/lowering of + * larger chunks at the same time OR remove altogether, as we have 'level land' ? + * @param tile The top-left tile where the terraforming will start + * @param mode 1 for raising, 0 for lowering land + */ +static void CommonRaiseLowerBigLand(TileIndex tile, int mode) +{ + if (_terraform_size == 1) { + StringID msg = + mode ? STR_ERROR_CAN_T_RAISE_LAND_HERE : STR_ERROR_CAN_T_LOWER_LAND_HERE; + + DoCommandP(tile, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND | CMD_MSG(msg), CcTerraform); + } else { + assert(_terraform_size != 0); + TileArea ta(tile, _terraform_size, _terraform_size); + ta.ClampToMap(); + + if (ta.w == 0 || ta.h == 0) return; + + if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); + + uint h; + if (mode != 0) { + /* Raise land */ + h = MAX_TILE_HEIGHT; + TILE_AREA_LOOP(tile2, ta) { + h = min(h, TileHeight(tile2)); + } + } else { + /* Lower land */ + h = 0; + TILE_AREA_LOOP(tile2, ta) { + h = max(h, TileHeight(tile2)); + } + } + + TILE_AREA_LOOP(tile2, ta) { + if (TileHeight(tile2) == h) { + DoCommandP(tile2, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND); + } + } + } +} + +static const int8 _multi_terraform_coords[][2] = { + { 0, -2}, + { 4, 0}, { -4, 0}, { 0, 2}, + { -8, 2}, { -4, 4}, { 0, 6}, { 4, 4}, { 8, 2}, + {-12, 0}, { -8, -2}, { -4, -4}, { 0, -6}, { 4, -4}, { 8, -2}, { 12, 0}, + {-16, 2}, {-12, 4}, { -8, 6}, { -4, 8}, { 0, 10}, { 4, 8}, { 8, 6}, { 12, 4}, { 16, 2}, + {-20, 0}, {-16, -2}, {-12, -4}, { -8, -6}, { -4, -8}, { 0,-10}, { 4, -8}, { 8, -6}, { 12, -4}, { 16, -2}, { 20, 0}, + {-24, 2}, {-20, 4}, {-16, 6}, {-12, 8}, { -8, 10}, { -4, 12}, { 0, 14}, { 4, 12}, { 8, 10}, { 12, 8}, { 16, 6}, { 20, 4}, { 24, 2}, + {-28, 0}, {-24, -2}, {-20, -4}, {-16, -6}, {-12, -8}, { -8,-10}, { -4,-12}, { 0,-14}, { 4,-12}, { 8,-10}, { 12, -8}, { 16, -6}, { 20, -4}, { 24, -2}, { 28, 0}, +}; + +static const NWidgetPart _nested_scen_edit_land_gen_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), + NWidget(NWID_HORIZONTAL), SetPadding(2, 2, 7, 2), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_DEMOLISH), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_LOWER_LAND), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_TERRAFORM_DOWN, STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_RAISE_LAND), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_TERRAFORM_UP, STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_LEVEL_LAND), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_LEVEL_LAND, STR_LANDSCAPING_LEVEL_LAND_TOOLTIP), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_PLACE_ROCKS), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_ROCKS, STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_ETT_SHOW_PLACE_DESERT), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_PLACE_DESERT), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_DESERT, STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA), + EndContainer(), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_PLACE_OBJECT), SetMinimalSize(23, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_TRANSMITTER, STR_SCENEDIT_TOOLBAR_PLACE_OBJECT), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_ETT_DOTS), SetMinimalSize(59, 31), SetDataTip(STR_EMPTY, STR_NULL), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetFill(0, 1), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_INCREASE_SIZE), SetMinimalSize(12, 12), SetDataTip(SPR_ARROW_UP, STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA), + NWidget(NWID_SPACER), SetMinimalSize(0, 1), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_DECREASE_SIZE), SetMinimalSize(12, 12), SetDataTip(SPR_ARROW_DOWN, STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA), + NWidget(NWID_SPACER), SetFill(0, 1), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 6), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_ETT_NEW_SCENARIO), SetMinimalSize(160, 12), + SetFill(1, 0), SetDataTip(STR_TERRAFORM_SE_NEW_WORLD, STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND), SetPadding(0, 2, 0, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_ETT_RESET_LANDSCAPE), SetMinimalSize(160, 12), + SetFill(1, 0), SetDataTip(STR_TERRAFORM_RESET_LANDSCAPE, STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP), SetPadding(1, 2, 2, 2), + EndContainer(), +}; + +/** + * Callback function for the scenario editor 'reset landscape' confirmation window + * @param w Window unused + * @param confirmed boolean value, true when yes was clicked, false otherwise + */ +static void ResetLandscapeConfirmationCallback(Window *w, bool confirmed) +{ + if (confirmed) { + /* Set generating_world to true to get instant-green grass after removing + * company property. */ + _generating_world = true; + + /* Delete all companies */ + Company *c; + FOR_ALL_COMPANIES(c) { + ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER); + delete c; + } + + _generating_world = false; + + /* Delete all station signs */ + BaseStation *st; + FOR_ALL_BASE_STATIONS(st) { + /* There can be buoys, remove them */ + if (IsBuoyTile(st->xy)) DoCommand(st->xy, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); + if (!st->IsInUse()) delete st; + } + + /* Now that all vehicles are gone, we can reset the engine pool. Maybe it reduces some NewGRF changing-mess */ + EngineOverrideManager::ResetToCurrentNewGRFConfig(); + + MarkWholeScreenDirty(); + } +} + +/** Landscape generation window handler in the scenario editor. */ +struct ScenarioEditorLandscapeGenerationWindow : Window { + int last_user_action; ///< Last started user action. + + ScenarioEditorLandscapeGenerationWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->CreateNestedTree(); + NWidgetStacked *show_desert = this->GetWidget(WID_ETT_SHOW_PLACE_DESERT); + show_desert->SetDisplayedPlane(_settings_game.game_creation.landscape == LT_TROPIC ? 0 : SZSP_NONE); + this->FinishInitNested(window_number); + this->last_user_action = WIDGET_LIST_END; + } + + virtual void OnPaint() + { + this->DrawWidgets(); + + if (this->IsWidgetLowered(WID_ETT_LOWER_LAND) || this->IsWidgetLowered(WID_ETT_RAISE_LAND)) { // change area-size if raise/lower corner is selected + SetTileSelectSize(_terraform_size, _terraform_size); + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_ETT_DOTS) return; + + int center_x = RoundDivSU(r.left + r.right, 2); + int center_y = RoundDivSU(r.top + r.bottom, 2); + + int n = _terraform_size * _terraform_size; + const int8 *coords = &_multi_terraform_coords[0][0]; + + assert(n != 0); + do { + DrawSprite(SPR_WHITE_POINT, PAL_NONE, center_x + coords[0], center_y + coords[1]); + coords += 2; + } while (--n); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + if (widget < WID_ETT_BUTTONS_START) return; + + switch (widget) { + case WID_ETT_DEMOLISH: // Demolish aka dynamite button + HandlePlacePushButton(this, WID_ETT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); + this->last_user_action = widget; + break; + + case WID_ETT_LOWER_LAND: // Lower land button + HandlePlacePushButton(this, WID_ETT_LOWER_LAND, ANIMCURSOR_LOWERLAND, HT_POINT); + this->last_user_action = widget; + break; + + case WID_ETT_RAISE_LAND: // Raise land button + HandlePlacePushButton(this, WID_ETT_RAISE_LAND, ANIMCURSOR_RAISELAND, HT_POINT); + this->last_user_action = widget; + break; + + case WID_ETT_LEVEL_LAND: // Level land button + HandlePlacePushButton(this, WID_ETT_LEVEL_LAND, SPR_CURSOR_LEVEL_LAND, HT_POINT | HT_DIAGONAL); + this->last_user_action = widget; + break; + + case WID_ETT_PLACE_ROCKS: // Place rocks button + HandlePlacePushButton(this, WID_ETT_PLACE_ROCKS, SPR_CURSOR_ROCKY_AREA, HT_RECT); + this->last_user_action = widget; + break; + + case WID_ETT_PLACE_DESERT: // Place desert button (in tropical climate) + HandlePlacePushButton(this, WID_ETT_PLACE_DESERT, SPR_CURSOR_DESERT, HT_RECT); + this->last_user_action = widget; + break; + + case WID_ETT_PLACE_OBJECT: // Place transmitter button + if (HandlePlacePushButton(this, WID_ETT_PLACE_OBJECT, SPR_CURSOR_TRANSMITTER, HT_RECT)) { + ShowBuildObjectPicker(this); + this->last_user_action = widget; + } + break; + + case WID_ETT_INCREASE_SIZE: + case WID_ETT_DECREASE_SIZE: { // Increase/Decrease terraform size + int size = (widget == WID_ETT_INCREASE_SIZE) ? 1 : -1; + this->HandleButtonClick(widget); + size += _terraform_size; + + if (!IsInsideMM(size, 1, 8 + 1)) return; + _terraform_size = size; + + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->SetDirty(); + break; + } + + case WID_ETT_NEW_SCENARIO: // gen random land + this->HandleButtonClick(widget); + ShowCreateScenario(); + break; + + case WID_ETT_RESET_LANDSCAPE: // Reset landscape + ShowQuery(STR_QUERY_RESET_LANDSCAPE_CAPTION, STR_RESET_LANDSCAPE_CONFIRMATION_TEXT, NULL, ResetLandscapeConfirmationCallback); + break; + + default: NOT_REACHED(); + } + } + + virtual void OnTimeout() + { + for (uint i = WID_ETT_START; i < this->nested_array_size; i++) { + if (i == WID_ETT_BUTTONS_START) i = WID_ETT_BUTTONS_END; // skip the buttons + if (this->IsWidgetLowered(i)) { + this->RaiseWidget(i); + this->SetWidgetDirty(i); + } + } + } + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + switch (this->last_user_action) { + case WID_ETT_DEMOLISH: // Demolish aka dynamite button + PlaceProc_DemolishArea(tile); + break; + + case WID_ETT_LOWER_LAND: // Lower land button + CommonRaiseLowerBigLand(tile, 0); + break; + + case WID_ETT_RAISE_LAND: // Raise land button + CommonRaiseLowerBigLand(tile, 1); + break; + + case WID_ETT_LEVEL_LAND: // Level land button + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LEVEL_AREA); + break; + + case WID_ETT_PLACE_ROCKS: // Place rocks button + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_ROCKS); + break; + + case WID_ETT_PLACE_DESERT: // Place desert button (in tropical climate) + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_DESERT); + break; + + case WID_ETT_PLACE_OBJECT: // Place transmitter button + PlaceProc_Object(tile); + break; + + default: NOT_REACHED(); + } + } + + virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + { + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + } + + virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + { + if (pt.x != -1) { + switch (select_proc) { + default: NOT_REACHED(); + case DDSP_CREATE_ROCKS: + case DDSP_CREATE_DESERT: + case DDSP_RAISE_AND_LEVEL_AREA: + case DDSP_LOWER_AND_LEVEL_AREA: + case DDSP_LEVEL_AREA: + case DDSP_DEMOLISH_AREA: + GUIPlaceProcDragXY(select_proc, start_tile, end_tile); + break; + } + } + } + + virtual void OnPlaceObjectAbort() + { + this->RaiseButtons(); + this->SetDirty(); + DeleteWindowById(WC_BUILD_OBJECT, 0); + } + + static HotkeyList hotkeys; +}; + +/** + * Handler for global hotkeys of the ScenarioEditorLandscapeGenerationWindow. + * @param hotkey Hotkey + * @return ES_HANDLED if hotkey was accepted. + */ +static EventState TerraformToolbarEditorGlobalHotkeys(int hotkey) +{ + if (_game_mode != GM_EDITOR) return ES_NOT_HANDLED; + Window *w = ShowEditorTerraformToolbar(); + if (w == NULL) return ES_NOT_HANDLED; + return w->OnHotkey(hotkey); +} + +static Hotkey terraform_editor_hotkeys[] = { + Hotkey('D' | WKC_GLOBAL_HOTKEY, "dynamite", WID_ETT_DEMOLISH), + Hotkey('Q' | WKC_GLOBAL_HOTKEY, "lower", WID_ETT_LOWER_LAND), + Hotkey('W' | WKC_GLOBAL_HOTKEY, "raise", WID_ETT_RAISE_LAND), + Hotkey('E' | WKC_GLOBAL_HOTKEY, "level", WID_ETT_LEVEL_LAND), + Hotkey('R', "rocky", WID_ETT_PLACE_ROCKS), + Hotkey('T', "desert", WID_ETT_PLACE_DESERT), + Hotkey('O', "object", WID_ETT_PLACE_OBJECT), + HOTKEY_LIST_END +}; + +HotkeyList ScenarioEditorLandscapeGenerationWindow::hotkeys("terraform_editor", terraform_editor_hotkeys, TerraformToolbarEditorGlobalHotkeys); + +static WindowDesc _scen_edit_land_gen_desc( + WDP_AUTO, "toolbar_landscape_scen", 0, 0, + WC_SCEN_LAND_GEN, WC_NONE, + WDF_CONSTRUCTION, + _nested_scen_edit_land_gen_widgets, lengthof(_nested_scen_edit_land_gen_widgets), + &ScenarioEditorLandscapeGenerationWindow::hotkeys +); + +/** + * Show the toolbar for terraforming in the scenario editor. + * @return The allocated toolbar. + */ +Window *ShowEditorTerraformToolbar() +{ + return AllocateWindowDescFront(&_scen_edit_land_gen_desc, 0); +} diff --git a/src/toolbar_gui.cpp.orig b/src/toolbar_gui.cpp.orig new file mode 100644 index 0000000000..9bac4f406d --- /dev/null +++ b/src/toolbar_gui.cpp.orig @@ -0,0 +1,2228 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file toolbar_gui.cpp Code related to the (main) toolbar. */ + +#include "stdafx.h" +#include "gui.h" +#include "window_gui.h" +#include "window_func.h" +#include "viewport_func.h" +#include "command_func.h" +#include "vehicle_gui.h" +#include "rail_gui.h" +#include "road_gui.h" +#include "date_func.h" +#include "vehicle_func.h" +#include "sound_func.h" +#include "terraform_gui.h" +#include "strings_func.h" +#include "company_func.h" +#include "company_gui.h" +#include "vehicle_base.h" +#include "cheat_func.h" +#include "transparency_gui.h" +#include "screenshot.h" +#include "signs_func.h" +#include "fios.h" +#include "console_gui.h" +#include "news_gui.h" +#include "ai/ai_gui.hpp" +#include "tilehighlight_func.h" +#include "smallmap_gui.h" +#include "graph_gui.h" +#include "textbuf_gui.h" +#include "linkgraph/linkgraph_gui.h" +#include "newgrf_debug.h" +#include "hotkeys.h" +#include "engine_base.h" +#include "highscore.h" +#include "game/game.hpp" +#include "goal_base.h" +#include "story_base.h" + +#include "widgets/toolbar_widget.h" + +#include "network/network.h" +#include "network/network_gui.h" +#include "network/network_func.h" + + +RailType _last_built_railtype; +RoadType _last_built_roadtype; + +static ScreenshotType _confirmed_screenshot_type; ///< Screenshot type the current query is about to confirm. + +/** Toobar modes */ +enum ToolbarMode { + TB_NORMAL, + TB_UPPER, + TB_LOWER +}; + +/** Callback functions. */ +enum CallBackFunction { + CBF_NONE, + CBF_PLACE_SIGN, + CBF_PLACE_LANDINFO, +}; + +/** + * Drop down list entry for showing a checked/unchecked toggle item. + */ +class DropDownListCheckedItem : public DropDownListStringItem { + uint checkmark_width; +public: + bool checked; + + DropDownListCheckedItem(StringID string, int result, bool masked, bool checked) : DropDownListStringItem(string, result, masked), checked(checked) + { + this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3; + } + + virtual ~DropDownListCheckedItem() {} + + uint Width() const + { + return DropDownListStringItem::Width() + this->checkmark_width; + } + + void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const + { + bool rtl = _current_text_dir == TD_RTL; + if (this->checked) { + DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK); + } + DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : this->checkmark_width), right - WD_FRAMERECT_RIGHT - (rtl ? this->checkmark_width : 0), top, this->String(), sel ? TC_WHITE : TC_BLACK); + } +}; + +/** + * Drop down list entry for showing a company entry, with companies 'blob'. + */ +class DropDownListCompanyItem : public DropDownListItem { + Dimension icon_size; +public: + bool greyed; + + DropDownListCompanyItem(int result, bool masked, bool greyed) : DropDownListItem(result, masked), greyed(greyed) + { + this->icon_size = GetSpriteSize(SPR_COMPANY_ICON); + } + + virtual ~DropDownListCompanyItem() {} + + bool Selectable() const + { + return true; + } + + uint Width() const + { + CompanyID company = (CompanyID)this->result; + SetDParam(0, company); + SetDParam(1, company); + return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + 3; + } + + uint Height(uint width) const + { + return GetMinSizing(NWST_STEP, max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL)); + } + + void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const + { + CompanyID company = (CompanyID)this->result; + bool rtl = _current_text_dir == TD_RTL; + + /* It's possible the company is deleted while the dropdown is open */ + if (!Company::IsValidID(company)) return; + + int icon_offset = (bottom - top - icon_size.height) / 2; + int text_offset = (bottom - top - FONT_HEIGHT_NORMAL) / 2; + + DrawCompanyIcon(company, rtl ? right - this->icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + icon_offset); + + SetDParam(0, company); + SetDParam(1, company); + TextColour col; + if (this->greyed) { + col = (sel ? TC_SILVER : TC_GREY) | TC_NO_SHADE; + } else { + col = sel ? TC_WHITE : TC_BLACK; + } + DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : 3 + this->icon_size.width), right - WD_FRAMERECT_RIGHT - (rtl ? 3 + this->icon_size.width : 0), top + text_offset, STR_COMPANY_NAME_COMPANY_NUM, col); + } +}; + +/** + * Pop up a generic text only menu. + * @param w Toolbar + * @param widget Toolbar button + * @param list List of items + * @param def Default item + */ +static void PopupMainToolbMenu(Window *w, int widget, DropDownList *list, int def) +{ + ShowDropDownList(w, list, def, widget, 0, true, true); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); +} + +/** + * Pop up a generic text only menu. + * @param w Toolbar + * @param widget Toolbar button + * @param string String for the first item in the menu + * @param count Number of items in the menu + */ +static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count) +{ + DropDownList *list = new DropDownList(); + for (int i = 0; i < count; i++) { + *list->Append() = new DropDownListStringItem(string + i, i, false); + } + PopupMainToolbMenu(w, widget, list, 0); +} + +/** Enum for the Company Toolbar's network related buttons */ +static const int CTMN_CLIENT_LIST = -1; ///< Show the client list +static const int CTMN_NEW_COMPANY = -2; ///< Create a new company +static const int CTMN_SPECTATE = -3; ///< Become spectator +static const int CTMN_SPECTATOR = -4; ///< Show a company window as spectator + +/** + * Pop up a generic company list menu. + * @param w The toolbar window. + * @param widget The button widget id. + * @param grey A bitbask of which items to mark as disabled. + * @param include_spectator If true, a spectator option is included in the list. + */ +static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0, bool include_spectator = false) +{ + DropDownList *list = new DropDownList(); + +#ifdef ENABLE_NETWORK + if (_networking) { + if (widget == WID_TN_COMPANIES) { + /* Add the client list button for the companies menu */ + *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false); + } + + if (include_spectator) { + if (widget == WID_TN_COMPANIES) { + if (_local_company == COMPANY_SPECTATOR) { + *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, NetworkMaxCompaniesReached()); + } else { + *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, NetworkMaxSpectatorsReached()); + } + } else { + *list->Append() = new DropDownListStringItem(STR_NETWORK_TOOLBAR_LIST_SPECTATOR, CTMN_SPECTATOR, false); + } + } + } +#endif /* ENABLE_NETWORK */ + + for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { + if (!Company::IsValidID(c)) continue; + *list->Append() = new DropDownListCompanyItem(c, false, HasBit(grey, c)); + } + + PopupMainToolbMenu(w, widget, list, _local_company == COMPANY_SPECTATOR ? CTMN_CLIENT_LIST : (int)_local_company); +} + + +static ToolbarMode _toolbar_mode; + +static CallBackFunction SelectSignTool() +{ + if (_cursor.sprite == SPR_CURSOR_SIGN) { + ResetObjectToPlace(); + return CBF_NONE; + } else { + SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0); + return CBF_PLACE_SIGN; + } +} + +/* --- Pausing --- */ + +static CallBackFunction ToolbarPauseClick(Window *w) +{ + if (_networking && !_network_server) return CBF_NONE; // only server can pause the game + + if (DoCommandP(0, PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED, CMD_PAUSE)) { + if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP); + } + return CBF_NONE; +} + +/** + * Toggle fast forward mode. + * + * @param w Unused. + * @return #CBF_NONE + */ +static CallBackFunction ToolbarFastForwardClick(Window *w) +{ + _fast_forward ^= true; + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + return CBF_NONE; +} + +/** + * Game Option button menu entries. + */ +enum OptionMenuEntries { + OME_GAMEOPTIONS, + OME_SETTINGS, + OME_SCRIPT_SETTINGS, + OME_NEWGRFSETTINGS, + OME_TRANSPARENCIES, + OME_SHOW_TOWNNAMES, + OME_SHOW_STATIONNAMES, + OME_SHOW_WAYPOINTNAMES, + OME_SHOW_SIGNS, + OME_SHOW_COMPETITOR_SIGNS, + OME_FULL_ANIMATION, + OME_FULL_DETAILS, + OME_TRANSPARENTBUILDINGS, + OME_SHOW_STATIONSIGNS, +}; + +/** + * Handle click on Options button in toolbar. + * + * @param w parent window the shown Drop down list is attached to. + * @return #CBF_NONE + */ +static CallBackFunction ToolbarOptionsClick(Window *w) +{ + DropDownList *list = new DropDownList(); + *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS, OME_GAMEOPTIONS, false); + *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS, OME_SETTINGS, false); + /* Changes to the per-AI settings don't get send from the server to the clients. Clients get + * the settings once they join but never update it. As such don't show the window at all + * to network clients. */ + if (!_networking || _network_server) *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false); + *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS, OME_NEWGRFSETTINGS, false); + *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS, OME_TRANSPARENCIES, false); + *list->Append() = new DropDownListItem(-1, false); + *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES)); + *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES, false, HasBit(_display_opt, DO_SHOW_STATION_NAMES)); + *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED, OME_SHOW_WAYPOINTNAMES, false, HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)); + *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SIGNS_DISPLAYED, OME_SHOW_SIGNS, false, HasBit(_display_opt, DO_SHOW_SIGNS)); + *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS, OME_SHOW_COMPETITOR_SIGNS, false, HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS)); + *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_ANIMATION, OME_FULL_ANIMATION, false, HasBit(_display_opt, DO_FULL_ANIMATION)); + *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_DETAIL, OME_FULL_DETAILS, false, HasBit(_display_opt, DO_FULL_DETAIL)); + *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS, OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES)); + *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS)); + + ShowDropDownList(w, list, 0, WID_TN_SETTINGS, 140, true, true); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + return CBF_NONE; +} + +/** + * Handle click on one of the entries in the Options button menu. + * + * @param index Index being clicked. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickSettings(int index) +{ + switch (index) { + case OME_GAMEOPTIONS: ShowGameOptions(); return CBF_NONE; + case OME_SETTINGS: ShowGameSettings(); return CBF_NONE; + case OME_SCRIPT_SETTINGS: ShowAIConfigWindow(); return CBF_NONE; + case OME_NEWGRFSETTINGS: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); return CBF_NONE; + case OME_TRANSPARENCIES: ShowTransparencyToolbar(); break; + + case OME_SHOW_TOWNNAMES: ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES); break; + case OME_SHOW_STATIONNAMES: ToggleBit(_display_opt, DO_SHOW_STATION_NAMES); break; + case OME_SHOW_WAYPOINTNAMES: ToggleBit(_display_opt, DO_SHOW_WAYPOINT_NAMES); break; + case OME_SHOW_SIGNS: ToggleBit(_display_opt, DO_SHOW_SIGNS); break; + case OME_SHOW_COMPETITOR_SIGNS: + ToggleBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS); + InvalidateWindowClassesData(WC_SIGN_LIST, -1); + break; + case OME_FULL_ANIMATION: ToggleBit(_display_opt, DO_FULL_ANIMATION); CheckBlitter(); break; + case OME_FULL_DETAILS: ToggleBit(_display_opt, DO_FULL_DETAIL); break; + case OME_TRANSPARENTBUILDINGS: ToggleTransparency(TO_HOUSES); break; + case OME_SHOW_STATIONSIGNS: ToggleTransparency(TO_SIGNS); break; + } + MarkWholeScreenDirty(); + return CBF_NONE; +} + +/** + * SaveLoad entries in scenario editor mode. + */ +enum SaveLoadEditorMenuEntries { + SLEME_SAVE_SCENARIO = 0, + SLEME_LOAD_SCENARIO, + SLEME_SAVE_HEIGHTMAP, + SLEME_LOAD_HEIGHTMAP, + SLEME_EXIT_TOINTRO, + SLEME_EXIT_GAME = 6, + SLEME_MENUCOUNT, +}; + +/** + * SaveLoad entries in normal game mode. + */ +enum SaveLoadNormalMenuEntries { + SLNME_SAVE_GAME = 0, + SLNME_LOAD_GAME, + SLNME_EXIT_TOINTRO, + SLNME_EXIT_GAME = 4, + SLNME_MENUCOUNT, +}; + +/** + * Handle click on Save button in toolbar in normal game mode. + * + * @param w parent window the shown save dialogue is attached to. + * @return #CBF_NONE + */ +static CallBackFunction ToolbarSaveClick(Window *w) +{ + PopupMainToolbMenu(w, WID_TN_SAVE, STR_FILE_MENU_SAVE_GAME, SLNME_MENUCOUNT); + return CBF_NONE; +} + +/** + * Handle click on SaveLoad button in toolbar in the scenario editor. + * + * @param w parent window the shown save dialogue is attached to. + * @return #CBF_NONE + */ +static CallBackFunction ToolbarScenSaveOrLoad(Window *w) +{ + PopupMainToolbMenu(w, WID_TE_SAVE, STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO, SLEME_MENUCOUNT); + return CBF_NONE; +} + +/** + * Handle click on one of the entries in the SaveLoad menu. + * + * @param index Index being clicked. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickSaveLoad(int index = 0) +{ + if (_game_mode == GM_EDITOR) { + switch (index) { + case SLEME_SAVE_SCENARIO: ShowSaveLoadDialog(SLD_SAVE_SCENARIO); break; + case SLEME_LOAD_SCENARIO: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break; + case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(SLD_SAVE_HEIGHTMAP); break; + case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break; + case SLEME_EXIT_TOINTRO: AskExitToGameMenu(); break; + case SLEME_EXIT_GAME: HandleExitGameRequest(); break; + } + } else { + switch (index) { + case SLNME_SAVE_GAME: ShowSaveLoadDialog(SLD_SAVE_GAME); break; + case SLNME_LOAD_GAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break; + case SLNME_EXIT_TOINTRO: AskExitToGameMenu(); break; + case SLNME_EXIT_GAME: HandleExitGameRequest(); break; + } + } + return CBF_NONE; +} + +/* --- Map button menu --- */ + +enum MapMenuEntries { + MME_SHOW_SMALLMAP = 0, + MME_SHOW_EXTRAVIEWPORTS, + MME_SHOW_LINKGRAPH, + MME_SHOW_SIGNLISTS, + MME_SHOW_TOWNDIRECTORY, + MME_SHOW_INDUSTRYDIRECTORY, +}; + +static CallBackFunction ToolbarMapClick(Window *w) +{ + DropDownList *list = new DropDownList(); + *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false); + *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false); + *list->Append() = new DropDownListStringItem(STR_MAP_MENU_LINGRAPH_LEGEND, MME_SHOW_LINKGRAPH, false); + *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false); + PopupMainToolbMenu(w, WID_TN_SMALL_MAP, list, 0); + return CBF_NONE; +} + +static CallBackFunction ToolbarScenMapTownDir(Window *w) +{ + DropDownList *list = new DropDownList(); + *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false); + *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false); + *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false); + *list->Append() = new DropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, MME_SHOW_TOWNDIRECTORY, false); + *list->Append() = new DropDownListStringItem(STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, MME_SHOW_INDUSTRYDIRECTORY, false); + PopupMainToolbMenu(w, WID_TE_SMALL_MAP, list, 0); + return CBF_NONE; +} + +/** + * Handle click on one of the entries in the Map menu. + * + * @param index Index being clicked. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickMap(int index) +{ + switch (index) { + case MME_SHOW_SMALLMAP: ShowSmallMap(); break; + case MME_SHOW_EXTRAVIEWPORTS: ShowExtraViewPortWindow(); break; + case MME_SHOW_LINKGRAPH: ShowLinkGraphLegend(); break; + case MME_SHOW_SIGNLISTS: ShowSignList(); break; + case MME_SHOW_TOWNDIRECTORY: ShowTownDirectory(); break; + case MME_SHOW_INDUSTRYDIRECTORY: ShowIndustryDirectory(); break; + } + return CBF_NONE; +} + +/* --- Town button menu --- */ + +static CallBackFunction ToolbarTownClick(Window *w) +{ + PopupMainToolbMenu(w, WID_TN_TOWNS, STR_TOWN_MENU_TOWN_DIRECTORY, (_settings_game.economy.found_town == TF_FORBIDDEN) ? 1 : 2); + return CBF_NONE; +} + +/** + * Handle click on one of the entries in the Town menu. + * + * @param index Index being clicked. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickTown(int index) +{ + switch (index) { + case 0: ShowTownDirectory(); break; + case 1: // setting could be changed when the dropdown was open + if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow(); + break; + } + return CBF_NONE; +} + +/* --- Subidies button menu --- */ + +static CallBackFunction ToolbarSubsidiesClick(Window *w) +{ + PopupMainToolbMenu(w, WID_TN_SUBSIDIES, STR_SUBSIDIES_MENU_SUBSIDIES, 1); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Subsidies menu. + * + * @param index Unused. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickSubsidies(int index) +{ + switch (index) { + case 0: ShowSubsidiesList(); break; + } + return CBF_NONE; +} + +/* --- Stations button menu --- */ + +static CallBackFunction ToolbarStationsClick(Window *w) +{ + PopupMainCompanyToolbMenu(w, WID_TN_STATIONS); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Stations menu + * + * @param index CompanyID to show station list for + * @return #CBF_NONE + */ +static CallBackFunction MenuClickStations(int index) +{ + ShowCompanyStations((CompanyID)index); + return CBF_NONE; +} + +/* --- Finances button menu --- */ + +static CallBackFunction ToolbarFinancesClick(Window *w) +{ + PopupMainCompanyToolbMenu(w, WID_TN_FINANCES); + return CBF_NONE; +} + +/** + * Handle click on the entry in the finances overview menu. + * + * @param index CompanyID to show finances for. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickFinances(int index) +{ + ShowCompanyFinances((CompanyID)index); + return CBF_NONE; +} + +/* --- Company's button menu --- */ + +static CallBackFunction ToolbarCompaniesClick(Window *w) +{ + PopupMainCompanyToolbMenu(w, WID_TN_COMPANIES, 0, true); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Company menu. + * + * @param index Menu entry to handle. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickCompany(int index) +{ +#ifdef ENABLE_NETWORK + if (_networking) { + switch (index) { + case CTMN_CLIENT_LIST: + ShowClientList(); + return CBF_NONE; + + case CTMN_NEW_COMPANY: + if (_network_server) { + DoCommandP(0, 0, _network_own_client_id, CMD_COMPANY_CTRL); + } else { + NetworkSendCommand(0, 0, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company); + } + return CBF_NONE; + + case CTMN_SPECTATE: + if (_network_server) { + NetworkServerDoMove(CLIENT_ID_SERVER, COMPANY_SPECTATOR); + MarkWholeScreenDirty(); + } else { + NetworkClientRequestMove(COMPANY_SPECTATOR); + } + return CBF_NONE; + } + } +#endif /* ENABLE_NETWORK */ + ShowCompany((CompanyID)index); + return CBF_NONE; +} + +/* --- Story button menu --- */ + +static CallBackFunction ToolbarStoryClick(Window *w) +{ + PopupMainCompanyToolbMenu(w, WID_TN_STORY, 0, true); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Story menu + * + * @param index CompanyID to show story book for + * @return #CBF_NONE + */ +static CallBackFunction MenuClickStory(int index) +{ + ShowStoryBook(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index); + return CBF_NONE; +} + +/* --- Goal button menu --- */ + +static CallBackFunction ToolbarGoalClick(Window *w) +{ + PopupMainCompanyToolbMenu(w, WID_TN_GOAL, 0, true); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Goal menu + * + * @param index CompanyID to show story book for + * @return #CBF_NONE + */ +static CallBackFunction MenuClickGoal(int index) +{ + ShowGoalsList(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index); + return CBF_NONE; +} + +/* --- Graphs button menu --- */ + +static CallBackFunction ToolbarGraphsClick(Window *w) +{ + PopupMainToolbMenu(w, WID_TN_GRAPHS, STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH, (_toolbar_mode == TB_NORMAL) ? 6 : 8); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Graphs menu. + * + * @param index Graph to show. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickGraphs(int index) +{ + switch (index) { + case 0: ShowOperatingProfitGraph(); break; + case 1: ShowIncomeGraph(); break; + case 2: ShowDeliveredCargoGraph(); break; + case 3: ShowPerformanceHistoryGraph(); break; + case 4: ShowCompanyValueGraph(); break; + case 5: ShowCargoPaymentRates(); break; + /* functions for combined graphs/league button */ + case 6: ShowCompanyLeagueTable(); break; + case 7: ShowPerformanceRatingDetail(); break; + } + return CBF_NONE; +} + +/* --- League button menu --- */ + +static CallBackFunction ToolbarLeagueClick(Window *w) +{ + PopupMainToolbMenu(w, WID_TN_LEAGUE, STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, _networking ? 2 : 3); + return CBF_NONE; +} + +/** + * Handle click on the entry in the CompanyLeague menu. + * + * @param index Menu entry number. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickLeague(int index) +{ + switch (index) { + case 0: ShowCompanyLeagueTable(); break; + case 1: ShowPerformanceRatingDetail(); break; + case 2: ShowHighscoreTable(); break; + } + return CBF_NONE; +} + +/* --- Industries button menu --- */ + +static CallBackFunction ToolbarIndustryClick(Window *w) +{ + /* Disable build-industry menu if we are a spectator */ + PopupMainToolbMenu(w, WID_TN_INDUSTRIES, STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, (_local_company == COMPANY_SPECTATOR) ? 2 : 3); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Industry menu. + * + * @param index Menu entry number. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickIndustry(int index) +{ + switch (index) { + case 0: ShowIndustryDirectory(); break; + case 1: ShowIndustryCargoesWindow(); break; + case 2: ShowBuildIndustryWindow(); break; + } + return CBF_NONE; +} + +/* --- Trains button menu + 1 helper function for all vehicles. --- */ + +static void ToolbarVehicleClick(Window *w, VehicleType veh) +{ + const Vehicle *v; + int dis = ~0; + + FOR_ALL_VEHICLES(v) { + if (v->type == veh && v->IsPrimaryVehicle()) ClrBit(dis, v->owner); + } + PopupMainCompanyToolbMenu(w, WID_TN_VEHICLE_START + veh, dis); +} + + +static CallBackFunction ToolbarTrainClick(Window *w) +{ + ToolbarVehicleClick(w, VEH_TRAIN); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Train menu. + * + * @param index CompanyID to show train list for. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickShowTrains(int index) +{ + ShowVehicleListWindow((CompanyID)index, VEH_TRAIN); + return CBF_NONE; +} + +/* --- Road vehicle button menu --- */ + +static CallBackFunction ToolbarRoadClick(Window *w) +{ + ToolbarVehicleClick(w, VEH_ROAD); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Road Vehicles menu. + * + * @param index CompanyID to show road vehicles list for. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickShowRoad(int index) +{ + ShowVehicleListWindow((CompanyID)index, VEH_ROAD); + return CBF_NONE; +} + +/* --- Ship button menu --- */ + +static CallBackFunction ToolbarShipClick(Window *w) +{ + ToolbarVehicleClick(w, VEH_SHIP); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Ships menu. + * + * @param index CompanyID to show ship list for. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickShowShips(int index) +{ + ShowVehicleListWindow((CompanyID)index, VEH_SHIP); + return CBF_NONE; +} + +/* --- Aircraft button menu --- */ + +static CallBackFunction ToolbarAirClick(Window *w) +{ + ToolbarVehicleClick(w, VEH_AIRCRAFT); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Aircraft menu. + * + * @param index CompanyID to show aircraft list for. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickShowAir(int index) +{ + ShowVehicleListWindow((CompanyID)index, VEH_AIRCRAFT); + return CBF_NONE; +} + +/* --- Zoom in button --- */ + +static CallBackFunction ToolbarZoomInClick(Window *w) +{ + if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) { + w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_IN : (byte)WID_TN_ZOOM_IN); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + } + return CBF_NONE; +} + +/* --- Zoom out button --- */ + +static CallBackFunction ToolbarZoomOutClick(Window *w) +{ + if (DoZoomInOutWindow(ZOOM_OUT, FindWindowById(WC_MAIN_WINDOW, 0))) { + w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_OUT : (byte)WID_TN_ZOOM_OUT); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + } + return CBF_NONE; +} + +/* --- Rail button menu --- */ + +static CallBackFunction ToolbarBuildRailClick(Window *w) +{ + ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true, true); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Build Rail menu. + * + * @param index RailType to show the build toolbar for. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickBuildRail(int index) +{ + _last_built_railtype = (RailType)index; + ShowBuildRailToolbar(_last_built_railtype); + return CBF_NONE; +} + +/* --- Road button menu --- */ + +static CallBackFunction ToolbarBuildRoadClick(Window *w) +{ + const Company *c = Company::Get(_local_company); + DropDownList *list = new DropDownList(); + + /* Road is always visible and available. */ + *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_ROAD_CONSTRUCTION, ROADTYPE_ROAD, false); + + /* Tram is only visible when there will be a tram, and available when that has been introduced. */ + Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { + if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; + if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue; + + *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_TRAM_CONSTRUCTION, ROADTYPE_TRAM, !HasBit(c->avail_roadtypes, ROADTYPE_TRAM)); + break; + } + ShowDropDownList(w, list, _last_built_roadtype, WID_TN_ROADS, 140, true, true); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Build Road menu. + * + * @param index RoadType to show the build toolbar for. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickBuildRoad(int index) +{ + _last_built_roadtype = (RoadType)index; + ShowBuildRoadToolbar(_last_built_roadtype); + return CBF_NONE; +} + +/* --- Water button menu --- */ + +static CallBackFunction ToolbarBuildWaterClick(Window *w) +{ + PopupMainToolbMenu(w, WID_TN_WATER, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 1); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Build Waterways menu. + * + * @param index Unused. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickBuildWater(int index) +{ + ShowBuildDocksToolbar(); + return CBF_NONE; +} + +/* --- Airport button menu --- */ + +static CallBackFunction ToolbarBuildAirClick(Window *w) +{ + PopupMainToolbMenu(w, WID_TN_AIR, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 1); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Build Air menu. + * + * @param index Unused. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickBuildAir(int index) +{ + ShowBuildAirToolbar(); + return CBF_NONE; +} + +/* --- Forest button menu --- */ + +static CallBackFunction ToolbarForestClick(Window *w) +{ + PopupMainToolbMenu(w, WID_TN_LANDSCAPE, STR_LANDSCAPING_MENU_LANDSCAPING, 1); + return CBF_NONE; +} + +/** + * Handle click on the entry in the landscaping menu. + * + * @param index Menu entry clicked. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickForest(int index) +{ + switch (index) { + case 0: ShowTerraformToolbar(); break; + } + return CBF_NONE; +} + +/* --- Music button menu --- */ + +static CallBackFunction ToolbarMusicClick(Window *w) +{ + PopupMainToolbMenu(w, WID_TN_MUSIC_SOUND, STR_TOOLBAR_SOUND_MUSIC, 1); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Music menu. + * + * @param index Unused. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickMusicWindow(int index) +{ + ShowMusicWindow(); + return CBF_NONE; +} + +/* --- Newspaper button menu --- */ + +static CallBackFunction ToolbarNewspaperClick(Window *w) +{ + PopupMainToolbMenu(w, WID_TN_MESSAGES, STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT, 2); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Newspaper menu. + * + * @param index Menu entry clicked. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickNewspaper(int index) +{ + switch (index) { + case 0: ShowLastNewsMessage(); break; + case 1: ShowMessageHistory(); break; + } + return CBF_NONE; +} + +/* --- Help button menu --- */ + +static CallBackFunction PlaceLandBlockInfo() +{ + if (_cursor.sprite == SPR_CURSOR_QUERY) { + ResetObjectToPlace(); + return CBF_NONE; + } else { + SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0); + return CBF_PLACE_LANDINFO; + } +} + +static CallBackFunction ToolbarHelpClick(Window *w) +{ + PopupMainToolbMenu(w, WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 12 : 9); + return CBF_NONE; +} + +static void MenuClickSmallScreenshot() +{ + MakeScreenshot(SC_VIEWPORT, NULL); +} + +/** + * Callback on the confirmation window for huge screenshots. + * @param w Window with viewport + * @param confirmed true on confirmation + */ +static void ScreenshotConfirmCallback(Window *w, bool confirmed) +{ + if (confirmed) MakeScreenshot(_confirmed_screenshot_type, NULL); +} + +/** + * Make a screenshot of the world. + * Ask for confirmation if the screenshot will be huge. + * @param t Screenshot type: World or viewport screenshot + */ +static void MenuClickLargeWorldScreenshot(ScreenshotType t) +{ + ViewPort vp; + SetupScreenshotViewport(t, &vp); + if ((uint64)vp.width * (uint64)vp.height > 8192 * 8192) { + /* Ask for confirmation */ + SetDParam(0, vp.width); + SetDParam(1, vp.height); + _confirmed_screenshot_type = t; + ShowQuery(STR_WARNING_SCREENSHOT_SIZE_CAPTION, STR_WARNING_SCREENSHOT_SIZE_MESSAGE, NULL, ScreenshotConfirmCallback); + } else { + /* Less than 64M pixels, just do it */ + MakeScreenshot(t, NULL); + } +} + +/** + * Toggle drawing of sprites' bounding boxes. + * @note has only an effect when newgrf_developer_tools are active. + * + * Function is found here and not in viewport.cpp in order to avoid + * importing the settings structs to there. + */ +void ToggleBoundingBoxes() +{ + extern bool _draw_bounding_boxes; + /* Always allow to toggle them off */ + if (_settings_client.gui.newgrf_developer_tools || _draw_bounding_boxes) { + _draw_bounding_boxes = !_draw_bounding_boxes; + MarkWholeScreenDirty(); + } +} + +/** + * Toggle drawing of the dirty blocks. + * @note has only an effect when newgrf_developer_tools are active. + * + * Function is found here and not in viewport.cpp in order to avoid + * importing the settings structs to there. + */ +void ToggleDirtyBlocks() +{ + extern bool _draw_dirty_blocks; + /* Always allow to toggle them off */ + if (_settings_client.gui.newgrf_developer_tools || _draw_dirty_blocks) { + _draw_dirty_blocks = !_draw_dirty_blocks; + MarkWholeScreenDirty(); + } +} + +/** + * Set the starting year for a scenario. + * @param year New starting year. + */ +void SetStartingYear(Year year) +{ + _settings_game.game_creation.starting_year = Clamp(year, MIN_YEAR, MAX_YEAR); + Date new_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1); + /* If you open a savegame as scenario there may already be link graphs.*/ + LinkGraphSchedule::Instance()->ShiftDates(new_date - _date); + SetDate(new_date, 0); +} + +/** + * Choose the proper callback function for the main toolbar's help menu. + * @param index The menu index which was selected. + * @return CBF_NONE + */ +static CallBackFunction MenuClickHelp(int index) +{ + switch (index) { + case 0: return PlaceLandBlockInfo(); + case 2: IConsoleSwitch(); break; + case 3: ShowAIDebugWindow(); break; + case 4: MenuClickSmallScreenshot(); break; + case 5: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break; + case 6: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break; + case 7: MenuClickLargeWorldScreenshot(SC_WORLD); break; + case 8: ShowAboutWindow(); break; + case 9: ShowSpriteAlignerWindow(); break; + case 10: ToggleBoundingBoxes(); break; + case 11: ToggleDirtyBlocks(); break; + } + return CBF_NONE; +} + +/* --- Switch toolbar button --- */ + +static CallBackFunction ToolbarSwitchClick(Window *w) +{ + if (_toolbar_mode != TB_LOWER) { + _toolbar_mode = TB_LOWER; + } else { + _toolbar_mode = TB_UPPER; + } + + w->ReInit(); + w->SetWidgetLoweredState(WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + return CBF_NONE; +} + +/* --- Scenario editor specific handlers. */ + +/** + * Called when clicking at the date panel of the scenario editor toolbar. + */ +static CallBackFunction ToolbarScenDatePanel(Window *w) +{ + SetDParam(0, _settings_game.game_creation.starting_year); + ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, w, CS_NUMERAL, QSF_ENABLE_DEFAULT); + _left_button_clicked = false; + return CBF_NONE; +} + +static CallBackFunction ToolbarScenDateBackward(Window *w) +{ + /* don't allow too fast scrolling */ + if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) { + w->HandleButtonClick(WID_TE_DATE_BACKWARD); + w->SetDirty(); + + SetStartingYear(_settings_game.game_creation.starting_year - 1); + } + _left_button_clicked = false; + return CBF_NONE; +} + +static CallBackFunction ToolbarScenDateForward(Window *w) +{ + /* don't allow too fast scrolling */ + if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) { + w->HandleButtonClick(WID_TE_DATE_FORWARD); + w->SetDirty(); + + SetStartingYear(_settings_game.game_creation.starting_year + 1); + } + _left_button_clicked = false; + return CBF_NONE; +} + +static CallBackFunction ToolbarScenGenLand(Window *w) +{ + w->HandleButtonClick(WID_TE_LAND_GENERATE); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + + ShowEditorTerraformToolbar(); + return CBF_NONE; +} + + +static CallBackFunction ToolbarScenGenTown(Window *w) +{ + w->HandleButtonClick(WID_TE_TOWN_GENERATE); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + ShowFoundTownWindow(); + return CBF_NONE; +} + +static CallBackFunction ToolbarScenGenIndustry(Window *w) +{ + w->HandleButtonClick(WID_TE_INDUSTRY); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + ShowBuildIndustryWindow(); + return CBF_NONE; +} + +static CallBackFunction ToolbarScenBuildRoad(Window *w) +{ + w->HandleButtonClick(WID_TE_ROADS); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + ShowBuildRoadScenToolbar(); + return CBF_NONE; +} + +static CallBackFunction ToolbarScenBuildDocks(Window *w) +{ + w->HandleButtonClick(WID_TE_WATER); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + ShowBuildDocksScenToolbar(); + return CBF_NONE; +} + +static CallBackFunction ToolbarScenPlantTrees(Window *w) +{ + w->HandleButtonClick(WID_TE_TREES); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + ShowBuildTreesToolbar(); + return CBF_NONE; +} + +static CallBackFunction ToolbarScenPlaceSign(Window *w) +{ + w->HandleButtonClick(WID_TE_SIGNS); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + return SelectSignTool(); +} + +static CallBackFunction ToolbarBtn_NULL(Window *w) +{ + return CBF_NONE; +} + +typedef CallBackFunction MenuClickedProc(int index); + +static MenuClickedProc * const _menu_clicked_procs[] = { + NULL, // 0 + NULL, // 1 + MenuClickSettings, // 2 + MenuClickSaveLoad, // 3 + MenuClickMap, // 4 + MenuClickTown, // 5 + MenuClickSubsidies, // 6 + MenuClickStations, // 7 + MenuClickFinances, // 8 + MenuClickCompany, // 9 + MenuClickStory, // 10 + MenuClickGoal, // 11 + MenuClickGraphs, // 12 + MenuClickLeague, // 13 + MenuClickIndustry, // 14 + MenuClickShowTrains, // 15 + MenuClickShowRoad, // 16 + MenuClickShowShips, // 17 + MenuClickShowAir, // 18 + MenuClickMap, // 19 + NULL, // 20 + MenuClickBuildRail, // 21 + MenuClickBuildRoad, // 22 + MenuClickBuildWater, // 23 + MenuClickBuildAir, // 24 + MenuClickForest, // 25 + MenuClickMusicWindow, // 26 + MenuClickNewspaper, // 27 + MenuClickHelp, // 28 +}; + +/** Full blown container to make it behave exactly as we want :) */ +class NWidgetToolbarContainer : public NWidgetContainer { + bool visible[WID_TN_END]; ///< The visible headers +protected: + uint spacers; ///< Number of spacer widgets in this toolbar + +public: + NWidgetToolbarContainer() : NWidgetContainer(NWID_HORIZONTAL) + { + } + + /** + * Check whether the given widget type is a button for us. + * @param type the widget type to check. + * @return true if it is a button for us. + */ + bool IsButton(WidgetType type) const + { + return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN; + } + + void SetupSmallestSize(Window *w, bool init_array) + { + this->smallest_x = 0; // Biggest child + this->smallest_y = 0; // Biggest child + this->fill_x = 1; + this->fill_y = 0; + this->resize_x = 1; // We only resize in this direction + this->resize_y = 0; // We never resize in this direction + this->spacers = 0; + + uint nbuttons = 0; + /* First initialise some variables... */ + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + child_wid->SetupSmallestSize(w, init_array); + this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); + if (this->IsButton(child_wid->type)) { + nbuttons++; + this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); + } else if (child_wid->type == NWID_SPACER) { + this->spacers++; + } + } + + /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */ + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + child_wid->current_y = this->smallest_y; + if (!this->IsButton(child_wid->type)) { + child_wid->current_x = child_wid->smallest_x; + } + } + w->window_desc->default_width = nbuttons * this->smallest_x; + } + + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) + { + assert(given_width >= this->smallest_x && given_height >= this->smallest_y); + + this->pos_x = x; + this->pos_y = y; + this->current_x = given_width; + this->current_y = given_height; + + /* Figure out what are the visible buttons */ + memset(this->visible, 0, sizeof(this->visible)); + uint arrangable_count, button_count, spacer_count; + const byte *arrangement = GetButtonArrangement(given_width, arrangable_count, button_count, spacer_count); + for (uint i = 0; i < arrangable_count; i++) { + this->visible[arrangement[i]] = true; + } + + /* Create us ourselves a quick lookup table */ + NWidgetBase *widgets[WID_TN_END]; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + if (child_wid->type == NWID_SPACER) continue; + widgets[((NWidgetCore*)child_wid)->index] = child_wid; + } + + /* Now assign the widgets to their rightful place */ + uint position = 0; // Place to put next child relative to origin of the container. + uint spacer_space = max(0, (int)given_width - (int)(button_count * this->smallest_x)); // Remaining spacing for 'spacer' widgets + uint button_space = given_width - spacer_space; // Remaining spacing for the buttons + uint spacer_i = 0; + uint button_i = 0; + + /* Index into the arrangement indices. The macro lastof cannot be used here! */ + const byte *cur_wid = rtl ? &arrangement[arrangable_count - 1] : arrangement; + for (uint i = 0; i < arrangable_count; i++) { + NWidgetBase *child_wid = widgets[*cur_wid]; + /* If we have to give space to the spacers, do that */ + if (spacer_space != 0) { + NWidgetBase *possible_spacer = rtl ? child_wid->next : child_wid->prev; + if (possible_spacer != NULL && possible_spacer->type == NWID_SPACER) { + uint add = spacer_space / (spacer_count - spacer_i); + position += add; + spacer_space -= add; + spacer_i++; + } + } + + /* Buttons can be scaled, the others not. */ + if (this->IsButton(child_wid->type)) { + child_wid->current_x = button_space / (button_count - button_i); + button_space -= child_wid->current_x; + button_i++; + } + child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl); + position += child_wid->current_x; + + if (rtl) { + cur_wid--; + } else { + cur_wid++; + } + } + } + + /* virtual */ void Draw(const Window *w) + { + /* Draw brown-red toolbar bg. */ + GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, PC_VERY_DARK_RED); + GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, PC_DARK_RED, FILLRECT_CHECKER); + + bool rtl = _current_text_dir == TD_RTL; + for (NWidgetBase *child_wid = rtl ? this->tail : this->head; child_wid != NULL; child_wid = rtl ? child_wid->prev : child_wid->next) { + if (child_wid->type == NWID_SPACER) continue; + if (!this->visible[((NWidgetCore*)child_wid)->index]) continue; + + child_wid->Draw(w); + } + } + + /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y) + { + if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; + + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + if (child_wid->type == NWID_SPACER) continue; + if (!this->visible[((NWidgetCore*)child_wid)->index]) continue; + + NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y); + if (nwid != NULL) return nwid; + } + return NULL; + } + + /** + * Get the arrangement of the buttons for the toolbar. + * @param width the new width of the toolbar. + * @param arrangable_count output of the number of visible items. + * @param button_count output of the number of visible buttons. + * @param spacer_count output of the number of spacers. + * @return the button configuration. + */ + virtual const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const = 0; +}; + +/** Container for the 'normal' main toolbar */ +class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { + /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const + { + static const uint SMALLEST_ARRANGEMENT = 14; + static const uint BIGGEST_ARRANGEMENT = 20; + static const byte arrange14[] = { + 0, 1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 29, + 2, 3, 4, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29, + }; + static const byte arrange15[] = { + 0, 1, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, + 0, 2, 4, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29, + }; + static const byte arrange16[] = { + 0, 1, 2, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, + 0, 1, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29, + }; + static const byte arrange17[] = { + 0, 1, 2, 4, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, + 0, 1, 3, 4, 6, 5, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29, + }; + static const byte arrange18[] = { + 0, 1, 2, 4, 5, 6, 7, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29, + 0, 1, 3, 4, 5, 6, 7, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29, + }; + static const byte arrange19[] = { + 0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 19, 20, 29, + 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 28, 19, 20, 29, + }; + static const byte arrange20[] = { + 0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 11, 19, 20, 29, + 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29, + }; + static const byte arrange_all[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 + }; + + /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */ + uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT); + if (full_buttons > BIGGEST_ARRANGEMENT) { + button_count = arrangable_count = lengthof(arrange_all); + spacer_count = this->spacers; + return arrange_all; + } + + /* Introduce the split toolbar */ + static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 }; + + button_count = arrangable_count = full_buttons; + spacer_count = this->spacers; + return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0); + } +}; + +/** Container for the scenario editor's toolbar */ +class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { + uint panel_widths[2]; ///< The width of the two panels (the text panel and date panel) + + void SetupSmallestSize(Window *w, bool init_array) + { + this->NWidgetToolbarContainer::SetupSmallestSize(w, init_array); + + /* Find the size of panel_widths */ + uint i = 0; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue; + + assert(i < lengthof(this->panel_widths)); + this->panel_widths[i++] = child_wid->current_x; + w->window_desc->default_width += child_wid->current_x; + } + } + + /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const + { + static const byte arrange_all[] = { + 0, 1, 2, 3, 4, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28, + }; + static const byte arrange_nopanel[] = { + 0, 1, 2, 3, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28, + }; + static const byte arrange_switch[] = { + 18, 8, 11, 12, 13, 14, 15, 16, 17, 29, + 0, 1, 2, 3, 18, 9, 10, 26, 28, 29, + }; + + /* If we can place all buttons *and* the panels, show them. */ + uint min_full_width = (lengthof(arrange_all) - lengthof(this->panel_widths)) * this->smallest_x + this->panel_widths[0] + this->panel_widths[1]; + if (width >= min_full_width) { + width -= this->panel_widths[0] + this->panel_widths[1]; + arrangable_count = lengthof(arrange_all); + button_count = arrangable_count - 2; + spacer_count = this->spacers; + return arrange_all; + } + + /* Otherwise don't show the date panel and if we can't fit half the buttons and the panels anymore, split the toolbar in two */ + uint min_small_width = (lengthof(arrange_switch) - lengthof(this->panel_widths)) * this->smallest_x / 2 + this->panel_widths[1]; + if (width > min_small_width) { + width -= this->panel_widths[1]; + arrangable_count = lengthof(arrange_nopanel); + button_count = arrangable_count - 1; + spacer_count = this->spacers - 1; + return arrange_nopanel; + } + + /* Split toolbar */ + width -= this->panel_widths[1]; + arrangable_count = lengthof(arrange_switch) / 2; + button_count = arrangable_count - 1; + spacer_count = 0; + return arrange_switch + ((_toolbar_mode == TB_LOWER) ? arrangable_count : 0); + } +}; + +/* --- Toolbar handling for the 'normal' case */ + +typedef CallBackFunction ToolbarButtonProc(Window *w); + +static ToolbarButtonProc * const _toolbar_button_procs[] = { + ToolbarPauseClick, + ToolbarFastForwardClick, + ToolbarOptionsClick, + ToolbarSaveClick, + ToolbarMapClick, + ToolbarTownClick, + ToolbarSubsidiesClick, + ToolbarStationsClick, + ToolbarFinancesClick, + ToolbarCompaniesClick, + ToolbarStoryClick, + ToolbarGoalClick, + ToolbarGraphsClick, + ToolbarLeagueClick, + ToolbarIndustryClick, + ToolbarTrainClick, + ToolbarRoadClick, + ToolbarShipClick, + ToolbarAirClick, + ToolbarZoomInClick, + ToolbarZoomOutClick, + ToolbarBuildRailClick, + ToolbarBuildRoadClick, + ToolbarBuildWaterClick, + ToolbarBuildAirClick, + ToolbarForestClick, + ToolbarMusicClick, + ToolbarNewspaperClick, + ToolbarHelpClick, + ToolbarSwitchClick, +}; + +enum MainToolbarHotkeys { + MTHK_PAUSE, + MTHK_FASTFORWARD, + MTHK_SETTINGS, + MTHK_SAVEGAME, + MTHK_LOADGAME, + MTHK_SMALLMAP, + MTHK_TOWNDIRECTORY, + MTHK_SUBSIDIES, + MTHK_STATIONS, + MTHK_FINANCES, + MTHK_COMPANIES, + MTHK_STORY, + MTHK_GOAL, + MTHK_GRAPHS, + MTHK_LEAGUE, + MTHK_INDUSTRIES, + MTHK_TRAIN_LIST, + MTHK_ROADVEH_LIST, + MTHK_SHIP_LIST, + MTHK_AIRCRAFT_LIST, + MTHK_ZOOM_IN, + MTHK_ZOOM_OUT, + MTHK_BUILD_RAIL, + MTHK_BUILD_ROAD, + MTHK_BUILD_DOCKS, + MTHK_BUILD_AIRPORT, + MTHK_BUILD_TREES, + MTHK_MUSIC, + MTHK_AI_DEBUG, + MTHK_SMALL_SCREENSHOT, + MTHK_ZOOMEDIN_SCREENSHOT, + MTHK_DEFAULTZOOM_SCREENSHOT, + MTHK_GIANT_SCREENSHOT, + MTHK_CHEATS, + MTHK_TERRAFORM, + MTHK_EXTRA_VIEWPORT, + MTHK_CLIENT_LIST, + MTHK_SIGN_LIST, +}; + +/** Main toolbar. */ +struct MainToolbarWindow : Window { + CallBackFunction last_started_action; ///< Last started user action. + + MainToolbarWindow(WindowDesc *desc) : Window(desc) + { + this->InitNested(0); + + this->last_started_action = CBF_NONE; + CLRBITS(this->flags, WF_WHITE_BORDER); + this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !_network_server); // if not server, disable pause button + this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button + PositionMainToolbar(this); + DoZoomInOutWindow(ZOOM_NONE, this); + } + + virtual void OnPaint() + { + /* If spectator, disable all construction buttons + * ie : Build road, rail, ships, airports and landscaping + * Since enabled state is the default, just disable when needed */ + this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END); + /* disable company list drop downs, if there are no companies */ + this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFTS, WIDGET_LIST_END); + + this->SetWidgetDisabledState(WID_TN_GOAL, Goal::GetNumItems() == 0); + this->SetWidgetDisabledState(WID_TN_STORY, StoryPage::GetNumItems() == 0); + + this->SetWidgetDisabledState(WID_TN_RAILS, !CanBuildVehicleInfrastructure(VEH_TRAIN)); + this->SetWidgetDisabledState(WID_TN_AIR, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT)); + + this->DrawWidgets(); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this); + } + + virtual void OnDropdownSelect(int widget, int index) + { + CallBackFunction cbf = _menu_clicked_procs[widget](index); + if (cbf != CBF_NONE) this->last_started_action = cbf; + } + + virtual EventState OnHotkey(int hotkey) + { + switch (hotkey) { + case MTHK_PAUSE: ToolbarPauseClick(this); break; + case MTHK_FASTFORWARD: ToolbarFastForwardClick(this); break; + case MTHK_SETTINGS: ShowGameOptions(); break; + case MTHK_SAVEGAME: MenuClickSaveLoad(); break; + case MTHK_LOADGAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break; + case MTHK_SMALLMAP: ShowSmallMap(); break; + case MTHK_TOWNDIRECTORY: ShowTownDirectory(); break; + case MTHK_SUBSIDIES: ShowSubsidiesList(); break; + case MTHK_STATIONS: ShowCompanyStations(_local_company); break; + case MTHK_FINANCES: ShowCompanyFinances(_local_company); break; + case MTHK_COMPANIES: ShowCompany(_local_company); break; + case MTHK_STORY: ShowStoryBook(_local_company); break; + case MTHK_GOAL: ShowGoalsList(_local_company); break; + case MTHK_GRAPHS: ShowOperatingProfitGraph(); break; + case MTHK_LEAGUE: ShowCompanyLeagueTable(); break; + case MTHK_INDUSTRIES: ShowBuildIndustryWindow(); break; + case MTHK_TRAIN_LIST: ShowVehicleListWindow(_local_company, VEH_TRAIN); break; + case MTHK_ROADVEH_LIST: ShowVehicleListWindow(_local_company, VEH_ROAD); break; + case MTHK_SHIP_LIST: ShowVehicleListWindow(_local_company, VEH_SHIP); break; + case MTHK_AIRCRAFT_LIST: ShowVehicleListWindow(_local_company, VEH_AIRCRAFT); break; + case MTHK_ZOOM_IN: ToolbarZoomInClick(this); break; + case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break; + case MTHK_BUILD_RAIL: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype); break; + case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break; + case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break; + case MTHK_BUILD_AIRPORT: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break; + case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break; + case MTHK_MUSIC: ShowMusicWindow(); break; + case MTHK_AI_DEBUG: ShowAIDebugWindow(); break; + case MTHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break; + case MTHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break; + case MTHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break; + case MTHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break; + case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break; + case MTHK_TERRAFORM: ShowTerraformToolbar(); break; + case MTHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break; +#ifdef ENABLE_NETWORK + case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break; +#endif + case MTHK_SIGN_LIST: ShowSignList(); break; + default: return ES_NOT_HANDLED; + } + return ES_HANDLED; + } + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + switch (this->last_started_action) { + case CBF_PLACE_SIGN: + PlaceProc_Sign(tile); + break; + + case CBF_PLACE_LANDINFO: + ShowLandInfo(tile); + break; + + default: NOT_REACHED(); + } + } + + virtual void OnTick() + { + if (this->IsWidgetLowered(WID_TN_PAUSE) != !!_pause_mode) { + this->ToggleWidgetLoweredState(WID_TN_PAUSE); + this->SetWidgetDirty(WID_TN_PAUSE); + } + + if (this->IsWidgetLowered(WID_TN_FAST_FORWARD) != !!_fast_forward) { + this->ToggleWidgetLoweredState(WID_TN_FAST_FORWARD); + this->SetWidgetDirty(WID_TN_FAST_FORWARD); + } + } + + virtual void OnTimeout() + { + /* We do not want to automatically raise the pause, fast forward and + * switchbar buttons; they have to stay down when pressed etc. */ + for (uint i = WID_TN_SETTINGS; i < WID_TN_SWITCH_BAR; i++) { + if (this->IsWidgetLowered(i)) { + this->RaiseWidget(i); + this->SetWidgetDirty(i); + } + } + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT); + } + + static HotkeyList hotkeys; +}; + +const uint16 _maintoolbar_pause_keys[] = {WKC_F1, WKC_PAUSE, 0}; +const uint16 _maintoolbar_zoomin_keys[] = {WKC_NUM_PLUS, WKC_EQUALS, WKC_SHIFT | WKC_EQUALS, WKC_SHIFT | WKC_F5, 0}; +const uint16 _maintoolbar_zoomout_keys[] = {WKC_NUM_MINUS, WKC_MINUS, WKC_SHIFT | WKC_MINUS, WKC_SHIFT | WKC_F6, 0}; +const uint16 _maintoolbar_smallmap_keys[] = {WKC_F4, 'M', 0}; + +static Hotkey maintoolbar_hotkeys[] = { + Hotkey(_maintoolbar_pause_keys, "pause", MTHK_PAUSE), + Hotkey((uint16)0, "fastforward", MTHK_FASTFORWARD), + Hotkey(WKC_F2, "settings", MTHK_SETTINGS), + Hotkey(WKC_F3, "saveload", MTHK_SAVEGAME), + Hotkey((uint16)0, "load_game", MTHK_LOADGAME), + Hotkey(_maintoolbar_smallmap_keys, "smallmap", MTHK_SMALLMAP), + Hotkey(WKC_F5, "town_list", MTHK_TOWNDIRECTORY), + Hotkey(WKC_F6, "subsidies", MTHK_SUBSIDIES), + Hotkey(WKC_F7, "station_list", MTHK_STATIONS), + Hotkey(WKC_F8, "finances", MTHK_FINANCES), + Hotkey(WKC_F9, "companies", MTHK_COMPANIES), + Hotkey((uint16)0, "story_book", MTHK_STORY), + Hotkey((uint16)0, "goal_list", MTHK_GOAL), + Hotkey(WKC_F10, "graphs", MTHK_GRAPHS), + Hotkey(WKC_F11, "league", MTHK_LEAGUE), + Hotkey(WKC_F12, "industry_list", MTHK_INDUSTRIES), + Hotkey(WKC_SHIFT | WKC_F1, "train_list", MTHK_TRAIN_LIST), + Hotkey(WKC_SHIFT | WKC_F2, "roadveh_list", MTHK_ROADVEH_LIST), + Hotkey(WKC_SHIFT | WKC_F3, "ship_list", MTHK_SHIP_LIST), + Hotkey(WKC_SHIFT | WKC_F4, "aircraft_list", MTHK_AIRCRAFT_LIST), + Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTHK_ZOOM_IN), + Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTHK_ZOOM_OUT), + Hotkey(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL), + Hotkey(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD), + Hotkey(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS), + Hotkey(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT), + Hotkey(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES), + Hotkey(WKC_SHIFT | WKC_F12, "music", MTHK_MUSIC), + Hotkey((uint16)0, "ai_debug", MTHK_AI_DEBUG), + Hotkey(WKC_CTRL | 'S', "small_screenshot", MTHK_SMALL_SCREENSHOT), + Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTHK_ZOOMEDIN_SCREENSHOT), + Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTHK_DEFAULTZOOM_SCREENSHOT), + Hotkey((uint16)0, "giant_screenshot", MTHK_GIANT_SCREENSHOT), + Hotkey(WKC_CTRL | WKC_ALT | 'C', "cheats", MTHK_CHEATS), + Hotkey('L', "terraform", MTHK_TERRAFORM), + Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT), +#ifdef ENABLE_NETWORK + Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST), +#endif + Hotkey((uint16)0, "sign_list", MTHK_SIGN_LIST), + HOTKEY_LIST_END +}; +HotkeyList MainToolbarWindow::hotkeys("maintoolbar", maintoolbar_hotkeys); + +static NWidgetBase *MakeMainToolbar(int *biggest_index) +{ + /** Sprites to use for the different toolbar buttons */ + static const SpriteID toolbar_button_sprites[] = { + SPR_IMG_PAUSE, // WID_TN_PAUSE + SPR_IMG_FASTFORWARD, // WID_TN_FAST_FORWARD + SPR_IMG_SETTINGS, // WID_TN_SETTINGS + SPR_IMG_SAVE, // WID_TN_SAVE + SPR_IMG_SMALLMAP, // WID_TN_SMALL_MAP + SPR_IMG_TOWN, // WID_TN_TOWNS + SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES + SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS + SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES + SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES + SPR_IMG_STORY_BOOK, // WID_TN_STORY + SPR_IMG_GOAL, // WID_TN_GOAL + SPR_IMG_GRAPHS, // WID_TN_GRAPHS + SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE + SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES + SPR_IMG_TRAINLIST, // WID_TN_TRAINS + SPR_IMG_TRUCKLIST, // WID_TN_ROADVEHS + SPR_IMG_SHIPLIST, // WID_TN_SHIPS + SPR_IMG_AIRPLANESLIST, // WID_TN_AIRCRAFT + SPR_IMG_ZOOMIN, // WID_TN_ZOOMIN + SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT + SPR_IMG_BUILDRAIL, // WID_TN_RAILS + SPR_IMG_BUILDROAD, // WID_TN_ROADS + SPR_IMG_BUILDWATER, // WID_TN_WATER + SPR_IMG_BUILDAIR, // WID_TN_AIR + SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE + SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND + SPR_IMG_MESSAGES, // WID_TN_MESSAGES + SPR_IMG_QUERY, // WID_TN_HELP + SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR + }; + + NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer(); + for (uint i = 0; i < WID_TN_END; i++) { + switch (i) { + case 4: case 8: case 15: case 19: case 21: case 26: hor->Add(new NWidgetSpacer(0, 0)); break; + } + hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); + } + + *biggest_index = max(*biggest_index, WID_TN_SWITCH_BAR); + return hor; +} + +static const NWidgetPart _nested_toolbar_normal_widgets[] = { + NWidgetFunction(MakeMainToolbar), +}; + +static WindowDesc _toolb_normal_desc( + WDP_MANUAL, NULL, 640, 22, + WC_MAIN_TOOLBAR, WC_NONE, + WDF_NO_FOCUS, + _nested_toolbar_normal_widgets, lengthof(_nested_toolbar_normal_widgets), + &MainToolbarWindow::hotkeys +); + + +/* --- Toolbar handling for the scenario editor */ + +static ToolbarButtonProc * const _scen_toolbar_button_procs[] = { + ToolbarPauseClick, + ToolbarFastForwardClick, + ToolbarOptionsClick, + ToolbarScenSaveOrLoad, + ToolbarBtn_NULL, + ToolbarScenDatePanel, + ToolbarScenDateBackward, + ToolbarScenDateForward, + ToolbarScenMapTownDir, + ToolbarZoomInClick, + ToolbarZoomOutClick, + ToolbarScenGenLand, + ToolbarScenGenTown, + ToolbarScenGenIndustry, + ToolbarScenBuildRoad, + ToolbarScenBuildDocks, + ToolbarScenPlantTrees, + ToolbarScenPlaceSign, + ToolbarBtn_NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ToolbarMusicClick, + NULL, + ToolbarHelpClick, + ToolbarSwitchClick, +}; + +enum MainToolbarEditorHotkeys { + MTEHK_PAUSE, + MTEHK_FASTFORWARD, + MTEHK_SETTINGS, + MTEHK_SAVEGAME, + MTEHK_GENLAND, + MTEHK_GENTOWN, + MTEHK_GENINDUSTRY, + MTEHK_BUILD_ROAD, + MTEHK_BUILD_DOCKS, + MTEHK_BUILD_TREES, + MTEHK_SIGN, + MTEHK_MUSIC, + MTEHK_LANDINFO, + MTEHK_SMALL_SCREENSHOT, + MTEHK_ZOOMEDIN_SCREENSHOT, + MTEHK_DEFAULTZOOM_SCREENSHOT, + MTEHK_GIANT_SCREENSHOT, + MTEHK_ZOOM_IN, + MTEHK_ZOOM_OUT, + MTEHK_TERRAFORM, + MTEHK_SMALLMAP, + MTEHK_EXTRA_VIEWPORT, +}; + +struct ScenarioEditorToolbarWindow : Window { + CallBackFunction last_started_action; ///< Last started user action. + + ScenarioEditorToolbarWindow(WindowDesc *desc) : Window(desc) + { + this->InitNested(0); + + this->last_started_action = CBF_NONE; + CLRBITS(this->flags, WF_WHITE_BORDER); + PositionMainToolbar(this); + DoZoomInOutWindow(ZOOM_NONE, this); + } + + virtual void OnPaint() + { + this->SetWidgetDisabledState(WID_TE_DATE_BACKWARD, _settings_game.game_creation.starting_year <= MIN_YEAR); + this->SetWidgetDisabledState(WID_TE_DATE_FORWARD, _settings_game.game_creation.starting_year >= MAX_YEAR); + + this->DrawWidgets(); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_TE_DATE: + SetDParam(0, ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1)); + DrawString(r.left, r.right, (this->height - FONT_HEIGHT_NORMAL) / 2, STR_WHITE_DATE_LONG, TC_FROMSTRING, SA_HOR_CENTER); + break; + + case WID_TE_SPACER: { + int height = r.bottom - r.top; + if (height > 2 * FONT_HEIGHT_NORMAL) { + DrawString(r.left, r.right, (height + 1) / 2 - FONT_HEIGHT_NORMAL, STR_SCENEDIT_TOOLBAR_OPENTTD, TC_FROMSTRING, SA_HOR_CENTER); + DrawString(r.left, r.right, (height + 1) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER); + } else { + DrawString(r.left, r.right, (height - FONT_HEIGHT_NORMAL) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER); + } + break; + } + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_TE_SPACER: + size->width = max(GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_OPENTTD).width, GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + break; + + case WID_TE_DATE: + SetDParam(0, ConvertYMDToDate(MAX_YEAR, 0, 1)); + *size = GetStringBoundingBox(STR_WHITE_DATE_LONG); + size->height = max(size->height, GetSpriteSize(SPR_IMG_SAVE).height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM); + break; + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + if (_game_mode == GM_MENU) return; + CallBackFunction cbf = _scen_toolbar_button_procs[widget](this); + if (cbf != CBF_NONE) this->last_started_action = cbf; + } + + virtual void OnDropdownSelect(int widget, int index) + { + /* The map button is in a different location on the scenario + * editor toolbar, so we need to adjust for it. */ + if (widget == WID_TE_SMALL_MAP) widget = WID_TN_SMALL_MAP; + CallBackFunction cbf = _menu_clicked_procs[widget](index); + if (cbf != CBF_NONE) this->last_started_action = cbf; + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + } + + virtual EventState OnHotkey(int hotkey) + { + CallBackFunction cbf = CBF_NONE; + switch (hotkey) { + case MTEHK_PAUSE: ToolbarPauseClick(this); break; + case MTEHK_FASTFORWARD: ToolbarFastForwardClick(this); break; + case MTEHK_SETTINGS: ShowGameOptions(); break; + case MTEHK_SAVEGAME: MenuClickSaveLoad(); break; + case MTEHK_GENLAND: ToolbarScenGenLand(this); break; + case MTEHK_GENTOWN: ToolbarScenGenTown(this); break; + case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break; + case MTEHK_BUILD_ROAD: ToolbarScenBuildRoad(this); break; + case MTEHK_BUILD_DOCKS: ToolbarScenBuildDocks(this); break; + case MTEHK_BUILD_TREES: ToolbarScenPlantTrees(this); break; + case MTEHK_SIGN: cbf = ToolbarScenPlaceSign(this); break; + case MTEHK_MUSIC: ShowMusicWindow(); break; + case MTEHK_LANDINFO: cbf = PlaceLandBlockInfo(); break; + case MTEHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break; + case MTEHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break; + case MTEHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break; + case MTEHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break; + case MTEHK_ZOOM_IN: ToolbarZoomInClick(this); break; + case MTEHK_ZOOM_OUT: ToolbarZoomOutClick(this); break; + case MTEHK_TERRAFORM: ShowEditorTerraformToolbar(); break; + case MTEHK_SMALLMAP: ShowSmallMap(); break; + case MTEHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break; + default: return ES_NOT_HANDLED; + } + if (cbf != CBF_NONE) this->last_started_action = cbf; + return ES_HANDLED; + } + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + switch (this->last_started_action) { + case CBF_PLACE_SIGN: + PlaceProc_Sign(tile); + break; + + case CBF_PLACE_LANDINFO: + ShowLandInfo(tile); + break; + + default: NOT_REACHED(); + } + } + + virtual void OnTimeout() + { + this->SetWidgetsLoweredState(false, WID_TE_DATE_BACKWARD, WID_TE_DATE_FORWARD, WIDGET_LIST_END); + this->SetWidgetDirty(WID_TE_DATE_BACKWARD); + this->SetWidgetDirty(WID_TE_DATE_FORWARD); + } + + virtual void OnTick() + { + if (this->IsWidgetLowered(WID_TE_PAUSE) != !!_pause_mode) { + this->ToggleWidgetLoweredState(WID_TE_PAUSE); + this->SetDirty(); + } + + if (this->IsWidgetLowered(WID_TE_FAST_FORWARD) != !!_fast_forward) { + this->ToggleWidgetLoweredState(WID_TE_FAST_FORWARD); + this->SetDirty(); + } + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT); + } + + virtual void OnQueryTextFinished(char *str) + { + /* Was 'cancel' pressed? */ + if (str == NULL) return; + + int32 value; + if (!StrEmpty(str)) { + value = atoi(str); + } else { + /* An empty string means revert to the default */ + value = DEF_START_YEAR; + } + SetStartingYear(value); + + this->SetDirty(); + } + + static HotkeyList hotkeys; +}; + +static Hotkey scenedit_maintoolbar_hotkeys[] = { + Hotkey(_maintoolbar_pause_keys, "pause", MTEHK_PAUSE), + Hotkey((uint16)0, "fastforward", MTEHK_FASTFORWARD), + Hotkey(WKC_F2, "settings", MTEHK_SETTINGS), + Hotkey(WKC_F3, "saveload", MTEHK_SAVEGAME), + Hotkey(WKC_F4, "gen_land", MTEHK_GENLAND), + Hotkey(WKC_F5, "gen_town", MTEHK_GENTOWN), + Hotkey(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY), + Hotkey(WKC_F7, "build_road", MTEHK_BUILD_ROAD), + Hotkey(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS), + Hotkey(WKC_F9, "build_trees", MTEHK_BUILD_TREES), + Hotkey(WKC_F10, "build_sign", MTEHK_SIGN), + Hotkey(WKC_F11, "music", MTEHK_MUSIC), + Hotkey(WKC_F12, "land_info", MTEHK_LANDINFO), + Hotkey(WKC_CTRL | 'S', "small_screenshot", MTEHK_SMALL_SCREENSHOT), + Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTEHK_ZOOMEDIN_SCREENSHOT), + Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTEHK_DEFAULTZOOM_SCREENSHOT), + Hotkey((uint16)0, "giant_screenshot", MTEHK_GIANT_SCREENSHOT), + Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTEHK_ZOOM_IN), + Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTEHK_ZOOM_OUT), + Hotkey('L', "terraform", MTEHK_TERRAFORM), + Hotkey('M', "smallmap", MTEHK_SMALLMAP), + Hotkey('V', "extra_viewport", MTEHK_EXTRA_VIEWPORT), + HOTKEY_LIST_END +}; +HotkeyList ScenarioEditorToolbarWindow::hotkeys("scenedit_maintoolbar", scenedit_maintoolbar_hotkeys); + +static const NWidgetPart _nested_toolb_scen_inner_widgets[] = { + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS), + NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO), + NWidget(NWID_SPACER), + NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(), + NWidget(NWID_SPACER), + NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL), + NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD), + EndContainer(), + EndContainer(), + NWidget(NWID_SPACER), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY), + NWidget(NWID_SPACER), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), + NWidget(NWID_SPACER), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), + NWidget(NWID_SPACER), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR), +}; + +static NWidgetBase *MakeScenarioToolbar(int *biggest_index) +{ + return MakeNWidgets(_nested_toolb_scen_inner_widgets, lengthof(_nested_toolb_scen_inner_widgets), biggest_index, new NWidgetScenarioToolbarContainer()); +} + +static const NWidgetPart _nested_toolb_scen_widgets[] = { + NWidgetFunction(MakeScenarioToolbar), +}; + +static WindowDesc _toolb_scen_desc( + WDP_MANUAL, NULL, 640, 22, + WC_MAIN_TOOLBAR, WC_NONE, + WDF_NO_FOCUS, + _nested_toolb_scen_widgets, lengthof(_nested_toolb_scen_widgets), + &ScenarioEditorToolbarWindow::hotkeys +); + +/** Allocate the toolbar. */ +void AllocateToolbar() +{ + /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */ + _last_built_roadtype = ROADTYPE_ROAD; + + if (_game_mode == GM_EDITOR) { + new ScenarioEditorToolbarWindow(&_toolb_scen_desc); + } else { + new MainToolbarWindow(&_toolb_normal_desc); + } +} diff --git a/src/toolbar_type.h b/src/toolbar_type.h new file mode 100644 index 0000000000..cfde179dcc --- /dev/null +++ b/src/toolbar_type.h @@ -0,0 +1,23 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file toolbar_type.h Types related to toolbars. */ + +#ifndef TOOLBAR_TYPE_H +#define TOOLBAR_TYPE_H + +/** Types of touchscreen modes. */ +enum TouchscreenMode { + TSC_NONE = 0, + TSC_SIMPLE, +}; +DECLARE_CYCLE(TouchscreenMode, TSC_NONE, TSC_SIMPLE) +typedef SimpleTinyEnumT TouchscreenModeByte; + +#endif /* TOOLBAR_TYPE_H */ diff --git a/src/town_gui.cpp.orig b/src/town_gui.cpp.orig new file mode 100644 index 0000000000..e6ad46e33b --- /dev/null +++ b/src/town_gui.cpp.orig @@ -0,0 +1,1199 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file town_gui.cpp GUI for towns. */ + +#include "stdafx.h" +#include "town.h" +#include "viewport_func.h" +#include "error.h" +#include "gui.h" +#include "command_func.h" +#include "company_func.h" +#include "company_base.h" +#include "company_gui.h" +#include "network/network.h" +#include "string_func.h" +#include "strings_func.h" +#include "sound_func.h" +#include "tilehighlight_func.h" +#include "sortlist_type.h" +#include "road_cmd.h" +#include "landscape.h" +#include "querystring_gui.h" +#include "window_func.h" +#include "townname_func.h" +#include "core/geometry_func.hpp" +#include "genworld.h" +#include "widgets/dropdown_func.h" + +#include "widgets/town_widget.h" + +#include "table/strings.h" + +typedef GUIList GUITownList; + +static const NWidgetPart _nested_town_authority_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_BROWN), + NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TA_CAPTION), SetDataTip(STR_LOCAL_AUTHORITY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_BROWN), + NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), + NWidget(WWT_STICKYBOX, COLOUR_BROWN), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), SetFill(1, 1), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_COMMAND_LIST), SetMinimalSize(305, 52), SetResize(1, 0), SetDataTip(0x0, STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), SetScrollbar(WID_TA_SCROLLBAR), EndContainer(), + NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_TA_SCROLLBAR), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 1), SetFill(1, 1), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TA_EXECUTE), SetMinimalSize(317, 12), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_LOCAL_AUTHORITY_DO_IT_BUTTON, STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP), + NWidget(WWT_RESIZEBOX, COLOUR_BROWN), + EndContainer() +}; + +/** Town authority window. */ +struct TownAuthorityWindow : Window { +private: + Town *town; ///< Town being displayed. + int sel_index; ///< Currently selected town action, \c 0 to \c TACT_COUNT-1, \c -1 means no action selected. + Scrollbar *vscroll; + uint actions_step; + uint displayed_actions_on_previous_painting; ///< Actions that were available on the previous call to OnPaint() + + /** + * Get the position of the Nth set bit. + * + * If there is no Nth bit set return -1 + * + * @param bits The value to search in + * @param n The Nth set bit from which we want to know the position + * @return The position of the Nth set bit + */ + static int GetNthSetBit(uint32 bits, int n) + { + if (n >= 0) { + uint i; + FOR_EACH_SET_BIT(i, bits) { + n--; + if (n < 0) return i; + } + } + return -1; + } + +public: + TownAuthorityWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), sel_index(-1), displayed_actions_on_previous_painting(0) + { + this->town = Town::Get(window_number); + this->InitNested(window_number); + this->vscroll = this->GetScrollbar(WID_TA_SCROLLBAR); + this->actions_step = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + this->vscroll->SetCapacity((this->GetWidget(WID_TA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / this->actions_step); + } + + virtual void OnPaint() + { + int numact; + uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); + if (buttons != displayed_actions_on_previous_painting) this->SetDirty(); + displayed_actions_on_previous_painting = buttons; + + this->vscroll->SetCount(numact + 1); + + if (this->sel_index != -1 && !HasBit(buttons, this->sel_index)) { + this->sel_index = -1; + } + + this->SetWidgetDisabledState(WID_TA_EXECUTE, this->sel_index == -1); + + this->DrawWidgets(); + if (!this->IsShaded()) this->DrawRatings(); + } + + /** Draw the contents of the ratings panel. May request a resize of the window if the contents does not fit. */ + void DrawRatings() + { + NWidgetBase *nwid = this->GetWidget(WID_TA_RATING_INFO); + uint left = nwid->pos_x + WD_FRAMERECT_LEFT; + uint right = nwid->pos_x + nwid->current_x - 1 - WD_FRAMERECT_RIGHT; + + uint y = nwid->pos_y + WD_FRAMERECT_TOP; + + DrawString(left, right, y, STR_LOCAL_AUTHORITY_COMPANY_RATINGS); + y += FONT_HEIGHT_NORMAL; + + Dimension icon_size = GetSpriteSize(SPR_COMPANY_ICON); + int icon_width = icon_size.width; + int icon_y_offset = (FONT_HEIGHT_NORMAL - icon_size.height) / 2; + + Dimension exclusive_size = GetSpriteSize(SPR_EXCLUSIVE_TRANSPORT); + int exclusive_width = exclusive_size.width; + int exclusive_y_offset = (FONT_HEIGHT_NORMAL - exclusive_size.height) / 2; + + bool rtl = _current_text_dir == TD_RTL; + uint text_left = left + (rtl ? 0 : icon_width + exclusive_width + 4); + uint text_right = right - (rtl ? icon_width + exclusive_width + 4 : 0); + uint icon_left = rtl ? right - icon_width : left; + uint exclusive_left = rtl ? right - icon_width - exclusive_width - 2 : left + icon_width + 2; + + /* Draw list of companies */ + const Company *c; + FOR_ALL_COMPANIES(c) { + if ((HasBit(this->town->have_ratings, c->index) || this->town->exclusivity == c->index)) { + DrawCompanyIcon(c->index, icon_left, y + icon_y_offset); + + SetDParam(0, c->index); + SetDParam(1, c->index); + + int r = this->town->ratings[c->index]; + StringID str; + (str = STR_CARGO_RATING_APPALLING, r <= RATING_APPALLING) || // Apalling + (str++, r <= RATING_VERYPOOR) || // Very Poor + (str++, r <= RATING_POOR) || // Poor + (str++, r <= RATING_MEDIOCRE) || // Mediocore + (str++, r <= RATING_GOOD) || // Good + (str++, r <= RATING_VERYGOOD) || // Very Good + (str++, r <= RATING_EXCELLENT) || // Excellent + (str++, true); // Outstanding + + SetDParam(2, str); + if (this->town->exclusivity == c->index) { + DrawSprite(SPR_EXCLUSIVE_TRANSPORT, COMPANY_SPRITE_COLOUR(c->index), exclusive_left, y + exclusive_y_offset); + } + + DrawString(text_left, text_right, y, STR_LOCAL_AUTHORITY_COMPANY_RATING); + y += FONT_HEIGHT_NORMAL; + } + } + + y = y + WD_FRAMERECT_BOTTOM - nwid->pos_y; // Compute needed size of the widget. + if (y > nwid->current_y) { + /* If the company list is too big to fit, mark ourself dirty and draw again. */ + ResizeWindow(this, 0, y - nwid->current_y); + } + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_TA_CAPTION) SetDParam(0, this->window_number); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_TA_ACTION_INFO: + if (this->sel_index != -1) { + SetDParam(0, _price[PR_TOWN_ACTION] * _town_action_costs[this->sel_index] >> 8); + DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, + STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING + this->sel_index); + } + break; + case WID_TA_COMMAND_LIST: { + int numact; + uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); + int y = Center(r.top, this->actions_step); + int pos = this->vscroll->GetPosition(); + + if (--pos < 0) { + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTIONS_TITLE); + y += this->actions_step; + } + + for (int i = 0; buttons; i++, buttons >>= 1) { + if (pos <= -5) break; ///< Draw only the 5 fitting lines + + if ((buttons & 1) && --pos < 0) { + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, + STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i, this->sel_index == i ? TC_WHITE : TC_ORANGE); + y += this->actions_step; + } + } + break; + } + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_TA_ACTION_INFO: { + assert(size->width > padding.width && size->height > padding.height); + size->width -= WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + size->height -= WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + Dimension d = {0, 0}; + for (int i = 0; i < TACT_COUNT; i++) { + SetDParam(0, _price[PR_TOWN_ACTION] * _town_action_costs[i] >> 8); + d = maxdim(d, GetStringMultiLineBoundingBox(STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING + i, *size)); + } + *size = maxdim(*size, d); + size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + break; + } + + case WID_TA_COMMAND_LIST: + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; + size->width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width; + for (uint i = 0; i < TACT_COUNT; i++ ) { + size->width = max(size->width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i).width); + } + size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + break; + + case WID_TA_RATING_INFO: + resize->height = FONT_HEIGHT_NORMAL; + size->height = WD_FRAMERECT_TOP + 9 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; + break; + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_TA_COMMAND_LIST: { + int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, this->actions_step); + if (!IsInsideMM(y, 0, 5)) return; + + y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_company, this->town), y + this->vscroll->GetPosition() - 1); + if (y >= 0) { + this->sel_index = y; + this->SetDirty(); + } + /* FALL THROUGH, when double-clicking. */ + if (click_count == 1 || y < 0) break; + } + + case WID_TA_EXECUTE: + DoCommandP(this->town->xy, this->window_number, this->sel_index, CMD_DO_TOWN_ACTION | CMD_MSG(STR_ERROR_CAN_T_DO_THIS)); + break; + } + } + + virtual void OnHundredthTick() + { + this->SetDirty(); + } +}; + +static WindowDesc _town_authority_desc( + WDP_AUTO, "view_town_authority", 317, 222, + WC_TOWN_AUTHORITY, WC_NONE, + 0, + _nested_town_authority_widgets, lengthof(_nested_town_authority_widgets) +); + +static void ShowTownAuthorityWindow(uint town) +{ + AllocateWindowDescFront(&_town_authority_desc, town); +} + + +/* Town view window. */ +struct TownViewWindow : Window { +private: + Town *town; ///< Town displayed by the window. + +public: + static const int WID_TV_HEIGHT_NORMAL = 150; + + TownViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->CreateNestedTree(); + + this->town = Town::Get(window_number); + if (this->town->larger_town) this->GetWidget(WID_TV_CAPTION)->widget_data = STR_TOWN_VIEW_CITY_CAPTION; + + this->FinishInitNested(window_number); + + this->flags |= WF_DISABLE_VP_SCROLL; + NWidgetViewport *nvp = this->GetWidget(WID_TV_VIEWPORT); + nvp->InitializeViewport(this, this->town->xy, ZOOM_LVL_NEWS); + + /* disable renaming town in network games if you are not the server */ + this->SetWidgetDisabledState(WID_TV_CHANGE_NAME, _networking && !_network_server); + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_TV_CAPTION) SetDParam(0, this->town->index); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_TV_INFO) return; + + uint y = r.top + WD_FRAMERECT_TOP; + + SetDParam(0, this->town->cache.population); + SetDParam(1, this->town->cache.num_houses); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, STR_TOWN_VIEW_POPULATION_HOUSES); + + SetDParam(0, this->town->supplied[CT_PASSENGERS].old_act); + SetDParam(1, this->town->supplied[CT_PASSENGERS].old_max); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX); + + SetDParam(0, this->town->supplied[CT_MAIL].old_act); + SetDParam(1, this->town->supplied[CT_MAIL].old_max); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX); + + bool first = true; + for (int i = TE_BEGIN; i < TE_END; i++) { + if (this->town->goal[i] == 0) continue; + if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue; + if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue; + + if (first) { + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH); + first = false; + } + + bool rtl = _current_text_dir == TD_RTL; + uint cargo_text_left = r.left + WD_FRAMERECT_LEFT + (rtl ? 0 : 20); + uint cargo_text_right = r.right - WD_FRAMERECT_RIGHT - (rtl ? 20 : 0); + + const CargoSpec *cargo = FindFirstCargoWithTownEffect((TownEffect)i); + assert(cargo != NULL); + + StringID string; + + if (this->town->goal[i] == TOWN_GROWTH_DESERT || this->town->goal[i] == TOWN_GROWTH_WINTER) { + /* For 'original' gameplay, don't show the amount required (you need 1 or more ..) */ + string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL; + if (this->town->received[i].old_act == 0) { + string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL; + + if (this->town->goal[i] == TOWN_GROWTH_WINTER && TileHeight(this->town->xy) < GetSnowLine()) { + string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER; + } + } + + SetDParam(0, cargo->name); + } else { + string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED; + if (this->town->received[i].old_act < this->town->goal[i]) { + string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED; + } + + SetDParam(0, cargo->Index()); + SetDParam(1, this->town->received[i].old_act); + SetDParam(2, cargo->Index()); + SetDParam(3, this->town->goal[i]); + } + DrawString(cargo_text_left, cargo_text_right, y += FONT_HEIGHT_NORMAL, string); + } + + if (HasBit(this->town->flags, TOWN_IS_GROWING)) { + SetDParam(0, ((this->town->growth_rate & (~TOWN_GROW_RATE_CUSTOM)) * TOWN_GROWTH_TICKS + DAY_TICKS) / DAY_TICKS); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, this->town->fund_buildings_months == 0 ? STR_TOWN_VIEW_TOWN_GROWS_EVERY : STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED); + } else { + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_TOWN_GROW_STOPPED); + } + + /* only show the town noise, if the noise option is activated. */ + if (_settings_game.economy.station_noise_level) { + SetDParam(0, this->town->noise_reached); + SetDParam(1, this->town->MaxTownNoise()); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_NOISE_IN_TOWN); + } + + if (this->town->text != NULL) { + SetDParamStr(0, this->town->text); + DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK); + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_TV_CENTER_VIEW: // scroll to location + if (_ctrl_pressed) { + ShowExtraViewPortWindow(this->town->xy); + } else { + ScrollMainWindowToTile(this->town->xy); + } + break; + + case WID_TV_SHOW_AUTHORITY: // town authority + ShowTownAuthorityWindow(this->window_number); + break; + + case WID_TV_CHANGE_NAME: // rename + SetDParam(0, this->window_number); + ShowQueryString(STR_TOWN_NAME, STR_TOWN_VIEW_RENAME_TOWN_BUTTON, MAX_LENGTH_TOWN_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); + break; + + case WID_TV_EXPAND: { // expand town - only available on Scenario editor + /* Warn the user if towns are not allowed to build roads, but do this only once per OpenTTD run. */ + static bool _warn_town_no_roads = false; + + if (!_settings_game.economy.allow_town_roads && !_warn_town_no_roads) { + ShowErrorMessage(STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS, INVALID_STRING_ID, WL_WARNING); + _warn_town_no_roads = true; + } + + DoCommandP(0, this->window_number, 0, CMD_EXPAND_TOWN | CMD_MSG(STR_ERROR_CAN_T_EXPAND_TOWN)); + break; + } + + case WID_TV_DELETE: // delete town - only available on Scenario editor + DoCommandP(0, this->window_number, 0, CMD_DELETE_TOWN | CMD_MSG(STR_ERROR_TOWN_CAN_T_DELETE)); + break; + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_TV_INFO: + size->height = GetDesiredInfoHeight(size->width); + break; + } + } + + /** + * Gets the desired height for the information panel. + * @return the desired height in pixels. + */ + uint GetDesiredInfoHeight(int width) const + { + uint aimed_height = 3 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + + bool first = true; + for (int i = TE_BEGIN; i < TE_END; i++) { + if (this->town->goal[i] == 0) continue; + if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue; + if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue; + + if (first) { + aimed_height += FONT_HEIGHT_NORMAL; + first = false; + } + aimed_height += FONT_HEIGHT_NORMAL; + } + aimed_height += FONT_HEIGHT_NORMAL; + + if (_settings_game.economy.station_noise_level) aimed_height += FONT_HEIGHT_NORMAL; + + if (this->town->text != NULL) { + SetDParamStr(0, this->town->text); + aimed_height += GetStringHeight(STR_JUST_RAW_STRING, width); + } + + return aimed_height; + } + + void ResizeWindowAsNeeded() + { + const NWidgetBase *nwid_info = this->GetWidget(WID_TV_INFO); + uint aimed_height = GetDesiredInfoHeight(nwid_info->current_x); + if (aimed_height > nwid_info->current_y || (aimed_height < nwid_info->current_y && nwid_info->current_y > nwid_info->smallest_y)) { + this->ReInit(); + } + } + + virtual void OnResize() + { + if (this->viewport != NULL) { + NWidgetViewport *nvp = this->GetWidget(WID_TV_VIEWPORT); + nvp->UpdateViewportCoordinates(this); + + ScrollWindowToTile(this->town->xy, this, true); // Re-center viewport. + } + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + /* Called when setting station noise or required cargoes have changed, in order to resize the window */ + this->SetDirty(); // refresh display for current size. This will allow to avoid glitches when downgrading + this->ResizeWindowAsNeeded(); + } + + virtual void OnQueryTextFinished(char *str) + { + if (str == NULL) return; + + DoCommandP(0, this->window_number, 0, CMD_RENAME_TOWN | CMD_MSG(STR_ERROR_CAN_T_RENAME_TOWN), NULL, str); + } +}; + +static const NWidgetPart _nested_town_game_view_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_BROWN), + NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_BROWN), + NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), + NWidget(WWT_STICKYBOX, COLOUR_BROWN), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN), + NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2), + NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 0), SetResize(1, 1), SetPadding(1, 1, 1, 1), + EndContainer(), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_SHOW_AUTHORITY), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON, STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP), + EndContainer(), + NWidget(WWT_RESIZEBOX, COLOUR_BROWN), + EndContainer(), +}; + +static WindowDesc _town_game_view_desc( + WDP_AUTO, "view_town", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL, + WC_TOWN_VIEW, WC_NONE, + 0, + _nested_town_game_view_widgets, lengthof(_nested_town_game_view_widgets) +); + +static const NWidgetPart _nested_town_editor_view_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_BROWN), + NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetMinimalSize(76, 14), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP), + NWidget(WWT_SHADEBOX, COLOUR_BROWN), + NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), + NWidget(WWT_STICKYBOX, COLOUR_BROWN), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN), + NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2), + NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 1), SetResize(1, 1), SetPadding(1, 1, 1, 1), + EndContainer(), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_EXPAND_BUTTON, STR_TOWN_VIEW_EXPAND_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_DELETE), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_TOWN_VIEW_DELETE_TOOLTIP), + EndContainer(), + NWidget(WWT_RESIZEBOX, COLOUR_BROWN), + EndContainer(), +}; + +static WindowDesc _town_editor_view_desc( + WDP_AUTO, "view_town_scen", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL, + WC_TOWN_VIEW, WC_NONE, + 0, + _nested_town_editor_view_widgets, lengthof(_nested_town_editor_view_widgets) +); + +void ShowTownViewWindow(TownID town) +{ + if (_game_mode == GM_EDITOR) { + AllocateWindowDescFront(&_town_editor_view_desc, town); + } else { + AllocateWindowDescFront(&_town_game_view_desc, town); + } +} + +static const NWidgetPart _nested_town_directory_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_BROWN), + NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_TOWN_DIRECTORY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_BROWN), + NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), + NWidget(WWT_STICKYBOX, COLOUR_BROWN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TD_SORT_ORDER), SetSizingType(NWST_STEP), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_TD_SORT_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TD_LIST), SetMinimalSize(196, 0), SetDataTip(0x0, STR_TOWN_DIRECTORY_LIST_TOOLTIP), + SetFill(1, 0), SetResize(0, 10), SetScrollbar(WID_TD_SCROLLBAR), EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN), + NWidget(WWT_TEXT, COLOUR_BROWN, WID_TD_WORLD_POPULATION), SetPadding(2, 0, 0, 2), SetMinimalSize(196, 12), SetFill(1, 0), SetDataTip(STR_TOWN_POPULATION, STR_NULL), + EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_TD_SCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_BROWN), + EndContainer(), + EndContainer(), +}; + +/** Town directory window class. */ +struct TownDirectoryWindow : public Window { +private: + /* Runtime saved values */ + static Listing last_sorting; + static const Town *last_town; + + /* Constants for sorting towns */ + static const StringID sorter_names[]; + static GUITownList::SortFunction * const sorter_funcs[]; + + GUITownList towns; + + Scrollbar *vscroll; + + void BuildSortTownList() + { + if (this->towns.NeedRebuild()) { + this->towns.Clear(); + + const Town *t; + FOR_ALL_TOWNS(t) { + *this->towns.Append() = t; + } + + this->towns.Compact(); + this->towns.RebuildDone(); + this->vscroll->SetCount(this->towns.Length()); // Update scrollbar as well. + } + /* Always sort the towns. */ + this->last_town = NULL; + this->towns.Sort(); + this->SetWidgetDirty(WID_TD_LIST); // Force repaint of the displayed towns. + } + + /** Sort by town name */ + static int CDECL TownNameSorter(const Town * const *a, const Town * const *b) + { + static char buf_cache[64]; + const Town *ta = *a; + const Town *tb = *b; + char buf[64]; + + SetDParam(0, ta->index); + GetString(buf, STR_TOWN_NAME, lastof(buf)); + + /* If 'b' is the same town as in the last round, use the cached value + * We do this to speed stuff up ('b' is called with the same value a lot of + * times after each other) */ + if (tb != last_town) { + last_town = tb; + SetDParam(0, tb->index); + GetString(buf_cache, STR_TOWN_NAME, lastof(buf_cache)); + } + + return strnatcmp(buf, buf_cache); // Sort by name (natural sorting). + } + + /** Sort by population (default descending, as big towns are of the most interest). */ + static int CDECL TownPopulationSorter(const Town * const *a, const Town * const *b) + { + uint32 a_population = (*a)->cache.population; + uint32 b_population = (*b)->cache.population; + if (a_population == b_population) return TownDirectoryWindow::TownNameSorter(a, b); + return (a_population < b_population) ? -1 : 1; + } + + /** Sort by town rating */ + static int CDECL TownRatingSorter(const Town * const *a, const Town * const *b) + { + int before = TownDirectoryWindow::last_sorting.order ? 1 : -1; // Value to get 'a' before 'b'. + + /* Towns without rating are always after towns with rating. */ + if (HasBit((*a)->have_ratings, _local_company)) { + if (HasBit((*b)->have_ratings, _local_company)) { + int16 a_rating = (*a)->ratings[_local_company]; + int16 b_rating = (*b)->ratings[_local_company]; + if (a_rating == b_rating) return TownDirectoryWindow::TownNameSorter(a, b); + return (a_rating < b_rating) ? -1 : 1; + } + return before; + } + if (HasBit((*b)->have_ratings, _local_company)) return -before; + return -before * TownDirectoryWindow::TownNameSorter(a, b); // Sort unrated towns always on ascending town name. + } + +public: + TownDirectoryWindow(WindowDesc *desc) : Window(desc) + { + this->CreateNestedTree(); + + this->vscroll = this->GetScrollbar(WID_TD_SCROLLBAR); + + this->towns.SetListing(this->last_sorting); + this->towns.SetSortFuncs(TownDirectoryWindow::sorter_funcs); + this->towns.ForceRebuild(); + this->BuildSortTownList(); + + this->FinishInitNested(0); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_TD_WORLD_POPULATION: + SetDParam(0, GetWorldPopulation()); + break; + + case WID_TD_SORT_CRITERIA: + SetDParam(0, TownDirectoryWindow::sorter_names[this->towns.SortType()]); + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_TD_SORT_ORDER: + this->DrawSortButtonState(widget, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP); + break; + + case WID_TD_LIST: { + int n = 0; + int y = r.top + WD_FRAMERECT_TOP; + if (this->towns.Length() == 0) { // No towns available. + DrawString(r.left + WD_FRAMERECT_LEFT, r.right, y, STR_TOWN_DIRECTORY_NONE); + break; + } + + /* At least one town available. */ + bool rtl = _current_text_dir == TD_RTL; + Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD); + int text_left = r.left + WD_FRAMERECT_LEFT + (rtl ? 0 : icon_size.width + 2); + int text_right = r.right - WD_FRAMERECT_RIGHT - (rtl ? icon_size.width + 2 : 0); + int icon_x = rtl ? r.right - WD_FRAMERECT_RIGHT - icon_size.width : r.left + WD_FRAMERECT_LEFT; + + for (uint i = this->vscroll->GetPosition(); i < this->towns.Length(); i++) { + const Town *t = this->towns[i]; + assert(t->xy != INVALID_TILE); + + /* Draw rating icon. */ + if (_game_mode == GM_EDITOR || !HasBit(t->have_ratings, _local_company)) { + DrawSprite(SPR_TOWN_RATING_NA, PAL_NONE, icon_x, y + (this->resize.step_height - icon_size.height) / 2); + } else { + SpriteID icon = SPR_TOWN_RATING_APALLING; + if (t->ratings[_local_company] > RATING_VERYPOOR) icon = SPR_TOWN_RATING_MEDIOCRE; + if (t->ratings[_local_company] > RATING_GOOD) icon = SPR_TOWN_RATING_GOOD; + DrawSprite(icon, PAL_NONE, icon_x, y + (this->resize.step_height - icon_size.height) / 2); + } + + SetDParam(0, t->index); + SetDParam(1, t->cache.population); + DrawString(text_left, text_right, y + (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2, STR_TOWN_DIRECTORY_TOWN); + + y += this->resize.step_height; + if (++n == this->vscroll->GetCapacity()) break; // max number of towns in 1 window + } + break; + } + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_TD_SORT_ORDER: { + Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); + d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + case WID_TD_SORT_CRITERIA: { + Dimension d = {0, 0}; + for (uint i = 0; TownDirectoryWindow::sorter_names[i] != INVALID_STRING_ID; i++) { + d = maxdim(d, GetStringBoundingBox(TownDirectoryWindow::sorter_names[i])); + } + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + case WID_TD_LIST: { + Dimension d = GetStringBoundingBox(STR_TOWN_DIRECTORY_NONE); + for (uint i = 0; i < this->towns.Length(); i++) { + const Town *t = this->towns[i]; + + assert(t != NULL); + + SetDParam(0, t->index); + SetDParamMaxDigits(1, 8); + d = maxdim(d, GetStringBoundingBox(STR_TOWN_DIRECTORY_TOWN)); + } + Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD); + d.width += icon_size.width + 2; + d.height = GetMinSizing(NWST_STEP, max(d.height, icon_size.height)); + resize->height = d.height; + d.height *= 5; + d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + *size = maxdim(*size, d); + break; + } + case WID_TD_WORLD_POPULATION: { + SetDParamMaxDigits(0, 10); + Dimension d = GetStringBoundingBox(STR_TOWN_POPULATION); + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_TD_SORT_ORDER: // Click on sort order button + if (this->towns.SortType() != 2) { // A different sort than by rating. + this->towns.ToggleSortOrder(); + this->last_sorting = this->towns.GetListing(); // Store new sorting order. + } else { + /* Some parts are always sorted ascending on name. */ + this->last_sorting.order = !this->last_sorting.order; + this->towns.SetListing(this->last_sorting); + this->towns.ForceResort(); + this->towns.Sort(); + } + this->SetDirty(); + break; + + case WID_TD_SORT_CRITERIA: // Click on sort criteria dropdown + ShowDropDownMenu(this, TownDirectoryWindow::sorter_names, this->towns.SortType(), WID_TD_SORT_CRITERIA, 0, 0); + break; + + case WID_TD_LIST: { // Click on Town Matrix + uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_TD_LIST, WD_FRAMERECT_TOP); + if (id_v >= this->towns.Length()) return; // click out of town bounds + + const Town *t = this->towns[id_v]; + assert(t != NULL); + if (_ctrl_pressed) { + ShowExtraViewPortWindow(t->xy); + } else { + ScrollMainWindowToTile(t->xy); + } + break; + } + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + if (widget != WID_TD_SORT_CRITERIA) return; + + if (this->towns.SortType() != index) { + this->towns.SetSortType(index); + this->last_sorting = this->towns.GetListing(); // Store new sorting order. + this->BuildSortTownList(); + } + } + + virtual void OnPaint() + { + if (this->towns.NeedRebuild()) this->BuildSortTownList(); + this->DrawWidgets(); + } + + virtual void OnHundredthTick() + { + this->BuildSortTownList(); + this->SetDirty(); + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_TD_LIST); + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (data == 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ + this->towns.ForceRebuild(); + } else { + this->towns.ForceResort(); + } + } +}; + +Listing TownDirectoryWindow::last_sorting = {false, 0}; +const Town *TownDirectoryWindow::last_town = NULL; + +/** Names of the sorting functions. */ +const StringID TownDirectoryWindow::sorter_names[] = { + STR_SORT_BY_NAME, + STR_SORT_BY_POPULATION, + STR_SORT_BY_RATING, + INVALID_STRING_ID +}; + +/** Available town directory sorting functions. */ +GUITownList::SortFunction * const TownDirectoryWindow::sorter_funcs[] = { + &TownNameSorter, + &TownPopulationSorter, + &TownRatingSorter, +}; + +static WindowDesc _town_directory_desc( + WDP_AUTO, "list_towns", 208, 202, + WC_TOWN_DIRECTORY, WC_NONE, + 0, + _nested_town_directory_widgets, lengthof(_nested_town_directory_widgets) +); + +void ShowTownDirectory() +{ + if (BringWindowToFrontById(WC_TOWN_DIRECTORY, 0)) return; + new TownDirectoryWindow(&_town_directory_desc); +} + +void CcFoundTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + + if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); +} + +void CcFoundRandomTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Succeeded()) ScrollMainWindowToTile(Town::Get(_new_town_id)->xy); +} + +static const NWidgetPart _nested_found_town_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_FOUND_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + /* Construct new town(s) buttons. */ + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_NEW_TOWN), SetMinimalSize(156, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_NEW_TOWN_BUTTON, STR_FOUND_TOWN_NEW_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_RANDOM_TOWN), SetMinimalSize(156, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_RANDOM_TOWN_BUTTON, STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_MANY_RANDOM_TOWNS), SetMinimalSize(156, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetPadding(0, 2, 0, 2), + /* Town name selection. */ + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(156, 14), SetPadding(0, 2, 0, 2), SetDataTip(STR_FOUND_TOWN_NAME_TITLE, STR_NULL), + NWidget(WWT_EDITBOX, COLOUR_GREY, WID_TF_TOWN_NAME_EDITBOX), SetMinimalSize(156, 12), SetPadding(0, 2, 3, 2), + SetDataTip(STR_FOUND_TOWN_NAME_EDITOR_TITLE, STR_FOUND_TOWN_NAME_EDITOR_HELP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_TOWN_NAME_RANDOM), SetMinimalSize(78, 12), SetPadding(0, 2, 0, 2), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_NAME_RANDOM_BUTTON, STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP), + /* Town size selection. */ + NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_TITLE, STR_NULL), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_SMALL), SetMinimalSize(78, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_MEDIUM), SetMinimalSize(78, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 1), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_LARGE), SetMinimalSize(78, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_RANDOM), SetMinimalSize(78, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_SIZE_RANDOM, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 3), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_CITY), SetPadding(0, 2, 0, 2), SetMinimalSize(156, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_CITY, STR_FOUND_TOWN_CITY_TOOLTIP), SetFill(1, 0), + /* Town roads selection. */ + NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_ROAD_LAYOUT, STR_NULL), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_ORIGINAL), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_BETTER), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 1), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID2), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID3), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_RANDOM), SetPadding(0, 2, 0, 2), SetMinimalSize(0, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), SetFill(1, 0), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + EndContainer(), +}; + +/** Found a town window class. */ +struct FoundTownWindow : Window { +private: + TownSize town_size; ///< Selected town size + TownLayout town_layout; ///< Selected town layout + bool city; ///< Are we building a city? + QueryString townname_editbox; ///< Townname editbox + bool townnamevalid; ///< Is generated town name valid? + uint32 townnameparts; ///< Generated town name + TownNameParams params; ///< Town name parameters + +public: + FoundTownWindow(WindowDesc *desc, WindowNumber window_number) : + Window(desc), + town_size(TSZ_MEDIUM), + town_layout(_settings_game.economy.town_layout), + townname_editbox(MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_TOWN_NAME_CHARS), + params(_settings_game.game_creation.town_name) + { + this->InitNested(window_number); + this->querystrings[WID_TF_TOWN_NAME_EDITBOX] = &this->townname_editbox; + this->RandomTownName(); + this->UpdateButtons(true); + } + + void RandomTownName() + { + this->townnamevalid = GenerateTownName(&this->townnameparts); + + if (!this->townnamevalid) { + this->townname_editbox.text.DeleteAll(); + } else { + GetTownName(this->townname_editbox.text.buf, &this->params, this->townnameparts, &this->townname_editbox.text.buf[this->townname_editbox.text.max_bytes - 1]); + this->townname_editbox.text.UpdateSize(); + } + UpdateOSKOriginalText(this, WID_TF_TOWN_NAME_EDITBOX); + + this->SetWidgetDirty(WID_TF_TOWN_NAME_EDITBOX); + } + + void UpdateButtons(bool check_availability) + { + if (check_availability && _game_mode != GM_EDITOR) { + this->SetWidgetsDisabledState(true, WID_TF_RANDOM_TOWN, WID_TF_MANY_RANDOM_TOWNS, WID_TF_SIZE_LARGE, WIDGET_LIST_END); + this->SetWidgetsDisabledState(_settings_game.economy.found_town != TF_CUSTOM_LAYOUT, + WID_TF_LAYOUT_ORIGINAL, WID_TF_LAYOUT_BETTER, WID_TF_LAYOUT_GRID2, WID_TF_LAYOUT_GRID3, WID_TF_LAYOUT_RANDOM, WIDGET_LIST_END); + if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT) town_layout = _settings_game.economy.town_layout; + } + + for (int i = WID_TF_SIZE_SMALL; i <= WID_TF_SIZE_RANDOM; i++) { + this->SetWidgetLoweredState(i, i == WID_TF_SIZE_SMALL + this->town_size); + } + + this->SetWidgetLoweredState(WID_TF_CITY, this->city); + + for (int i = WID_TF_LAYOUT_ORIGINAL; i <= WID_TF_LAYOUT_RANDOM; i++) { + this->SetWidgetLoweredState(i, i == WID_TF_LAYOUT_ORIGINAL + this->town_layout); + } + + this->SetDirty(); + } + + void ExecuteFoundTownCommand(TileIndex tile, bool random, StringID errstr, CommandCallback cc) + { + const char *name = NULL; + + if (!this->townnamevalid) { + name = this->townname_editbox.text.buf; + } else { + /* If user changed the name, send it */ + char buf[MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH]; + GetTownName(buf, &this->params, this->townnameparts, lastof(buf)); + if (strcmp(buf, this->townname_editbox.text.buf) != 0) name = this->townname_editbox.text.buf; + } + + bool success = DoCommandP(tile, this->town_size | this->city << 2 | this->town_layout << 3 | random << 6, + townnameparts, CMD_FOUND_TOWN | CMD_MSG(errstr), cc, name); + + if (success) this->RandomTownName(); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_TF_NEW_TOWN: + HandlePlacePushButton(this, WID_TF_NEW_TOWN, SPR_CURSOR_TOWN, HT_RECT); + break; + + case WID_TF_RANDOM_TOWN: + this->ExecuteFoundTownCommand(0, true, STR_ERROR_CAN_T_GENERATE_TOWN, CcFoundRandomTown); + break; + + case WID_TF_TOWN_NAME_RANDOM: + this->RandomTownName(); + this->SetFocusedWidget(WID_TF_TOWN_NAME_EDITBOX); + break; + + case WID_TF_MANY_RANDOM_TOWNS: + _generating_world = true; + UpdateNearestTownForRoadTiles(true); + if (!GenerateTowns(this->town_layout)) { + ShowErrorMessage(STR_ERROR_CAN_T_GENERATE_TOWN, STR_ERROR_NO_SPACE_FOR_TOWN, WL_INFO); + } + UpdateNearestTownForRoadTiles(false); + _generating_world = false; + break; + + case WID_TF_SIZE_SMALL: case WID_TF_SIZE_MEDIUM: case WID_TF_SIZE_LARGE: case WID_TF_SIZE_RANDOM: + this->town_size = (TownSize)(widget - WID_TF_SIZE_SMALL); + this->UpdateButtons(false); + break; + + case WID_TF_CITY: + this->city ^= true; + this->SetWidgetLoweredState(WID_TF_CITY, this->city); + this->SetDirty(); + break; + + case WID_TF_LAYOUT_ORIGINAL: case WID_TF_LAYOUT_BETTER: case WID_TF_LAYOUT_GRID2: + case WID_TF_LAYOUT_GRID3: case WID_TF_LAYOUT_RANDOM: + this->town_layout = (TownLayout)(widget - WID_TF_LAYOUT_ORIGINAL); + this->UpdateButtons(false); + break; + } + } + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown); + } + + virtual void OnPlaceObjectAbort() + { + this->RaiseButtons(); + this->UpdateButtons(false); + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + this->UpdateButtons(true); + } +}; + +static WindowDesc _found_town_desc( + WDP_AUTO, "build_town", 160, 162, + WC_FOUND_TOWN, WC_NONE, + WDF_CONSTRUCTION, + _nested_found_town_widgets, lengthof(_nested_found_town_widgets) +); + +void ShowFoundTownWindow() +{ + if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return; + AllocateWindowDescFront(&_found_town_desc, 0); +} diff --git a/src/vehicle_gui.cpp.orig b/src/vehicle_gui.cpp.orig new file mode 100644 index 0000000000..79e9e9216b --- /dev/null +++ b/src/vehicle_gui.cpp.orig @@ -0,0 +1,2841 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file vehicle_gui.cpp The base GUI for all vehicles. */ + +#include "stdafx.h" +#include "debug.h" +#include "company_func.h" +#include "gui.h" +#include "textbuf_gui.h" +#include "command_func.h" +#include "vehicle_gui_base.h" +#include "viewport_func.h" +#include "newgrf_text.h" +#include "newgrf_debug.h" +#include "roadveh.h" +#include "train.h" +#include "aircraft.h" +#include "depot_map.h" +#include "group_gui.h" +#include "strings_func.h" +#include "vehicle_func.h" +#include "autoreplace_gui.h" +#include "string_func.h" +#include "widgets/dropdown_func.h" +#include "timetable.h" +#include "articulated_vehicles.h" +#include "spritecache.h" +#include "core/geometry_func.hpp" +#include "company_base.h" +#include "engine_func.h" +#include "station_base.h" +#include "tilehighlight_func.h" +#include "zoom_func.h" + + +Sorting _sorting; + +static GUIVehicleList::SortFunction VehicleNumberSorter; +static GUIVehicleList::SortFunction VehicleNameSorter; +static GUIVehicleList::SortFunction VehicleAgeSorter; +static GUIVehicleList::SortFunction VehicleProfitThisYearSorter; +static GUIVehicleList::SortFunction VehicleProfitLastYearSorter; +static GUIVehicleList::SortFunction VehicleCargoSorter; +static GUIVehicleList::SortFunction VehicleReliabilitySorter; +static GUIVehicleList::SortFunction VehicleMaxSpeedSorter; +static GUIVehicleList::SortFunction VehicleModelSorter; +static GUIVehicleList::SortFunction VehicleValueSorter; +static GUIVehicleList::SortFunction VehicleLengthSorter; +static GUIVehicleList::SortFunction VehicleTimeToLiveSorter; +static GUIVehicleList::SortFunction VehicleTimetableDelaySorter; + +GUIVehicleList::SortFunction * const BaseVehicleListWindow::vehicle_sorter_funcs[] = { + &VehicleNumberSorter, + &VehicleNameSorter, + &VehicleAgeSorter, + &VehicleProfitThisYearSorter, + &VehicleProfitLastYearSorter, + &VehicleCargoSorter, + &VehicleReliabilitySorter, + &VehicleMaxSpeedSorter, + &VehicleModelSorter, + &VehicleValueSorter, + &VehicleLengthSorter, + &VehicleTimeToLiveSorter, + &VehicleTimetableDelaySorter, +}; + +const StringID BaseVehicleListWindow::vehicle_sorter_names[] = { + STR_SORT_BY_NUMBER, + STR_SORT_BY_NAME, + STR_SORT_BY_AGE, + STR_SORT_BY_PROFIT_THIS_YEAR, + STR_SORT_BY_PROFIT_LAST_YEAR, + STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE, + STR_SORT_BY_RELIABILITY, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_MODEL, + STR_SORT_BY_VALUE, + STR_SORT_BY_LENGTH, + STR_SORT_BY_LIFE_TIME, + STR_SORT_BY_TIMETABLE_DELAY, + INVALID_STRING_ID +}; + +const StringID BaseVehicleListWindow::vehicle_depot_name[] = { + STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT, + STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT, + STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT, + STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR +}; + +void BaseVehicleListWindow::BuildVehicleList() +{ + if (!this->vehicles.NeedRebuild()) return; + + DEBUG(misc, 3, "Building vehicle list type %d for company %d given index %d", this->vli.type, this->vli.company, this->vli.index); + + GenerateVehicleSortList(&this->vehicles, this->vli); + + uint unitnumber = 0; + for (const Vehicle **v = this->vehicles.Begin(); v != this->vehicles.End(); v++) { + unitnumber = max(unitnumber, (*v)->unitnumber); + } + + /* Because 111 is much less wide than e.g. 999 we use the + * wider numbers to determine the width instead of just + * the random number that it seems to be. */ + if (unitnumber >= 1000) { + this->unitnumber_digits = 4; + } else if (unitnumber >= 100) { + this->unitnumber_digits = 3; + } else { + this->unitnumber_digits = 2; + } + + this->vehicles.RebuildDone(); + this->vscroll->SetCount(this->vehicles.Length()); +} + +/** + * Compute the size for the Action dropdown. + * @param show_autoreplace If true include the autoreplace item. + * @param show_group If true include group-related stuff. + * @return Required size. + */ +Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bool show_group) +{ + Dimension d = {0, 0}; + + if (show_autoreplace) d = maxdim(d, GetStringBoundingBox(STR_VEHICLE_LIST_REPLACE_VEHICLES)); + d = maxdim(d, GetStringBoundingBox(STR_VEHICLE_LIST_SEND_FOR_SERVICING)); + d = maxdim(d, GetStringBoundingBox(this->vehicle_depot_name[this->vli.vtype])); + + if (show_group) { + d = maxdim(d, GetStringBoundingBox(STR_GROUP_ADD_SHARED_VEHICLE)); + d = maxdim(d, GetStringBoundingBox(STR_GROUP_REMOVE_ALL_VEHICLES)); + } + + return d; +} + +/** + * Display the Action dropdown window. + * @param show_autoreplace If true include the autoreplace item. + * @param show_group If true include group-related stuff. + * @return Itemlist for dropdown + */ +DropDownList *BaseVehicleListWindow::BuildActionDropdownList(bool show_autoreplace, bool show_group) +{ + DropDownList *list = new DropDownList(); + + if (show_autoreplace) *list->Append() = new DropDownListStringItem(STR_VEHICLE_LIST_REPLACE_VEHICLES, ADI_REPLACE, false); + *list->Append() = new DropDownListStringItem(STR_VEHICLE_LIST_SEND_FOR_SERVICING, ADI_SERVICE, false); + *list->Append() = new DropDownListStringItem(this->vehicle_depot_name[this->vli.vtype], ADI_DEPOT, false); + + if (show_group) { + *list->Append() = new DropDownListStringItem(STR_GROUP_ADD_SHARED_VEHICLE, ADI_ADD_SHARED, false); + *list->Append() = new DropDownListStringItem(STR_GROUP_REMOVE_ALL_VEHICLES, ADI_REMOVE_ALL, false); + } + + return list; +} + +/* cached values for VehicleNameSorter to spare many GetString() calls */ +static const Vehicle *_last_vehicle[2] = { NULL, NULL }; + +void BaseVehicleListWindow::SortVehicleList() +{ + if (this->vehicles.Sort()) return; + + /* invalidate cached values for name sorter - vehicle names could change */ + _last_vehicle[0] = _last_vehicle[1] = NULL; +} + +void DepotSortList(VehicleList *list) +{ + if (list->Length() < 2) return; + QSortT(list->Begin(), list->Length(), &VehicleNumberSorter); +} + +/** draw the vehicle profit button in the vehicle list window. */ +static void DrawVehicleProfitButton(const Vehicle *v, int x, int y) +{ + SpriteID spr; + + /* draw profit-based coloured icons */ + if (v->age <= VEHICLE_PROFIT_MIN_AGE) { + spr = SPR_PROFIT_NA; + } else if (v->GetDisplayProfitLastYear() < 0) { + spr = SPR_PROFIT_NEGATIVE; + } else if (v->GetDisplayProfitLastYear() < VEHICLE_PROFIT_THRESHOLD) { + spr = SPR_PROFIT_SOME; + } else { + spr = SPR_PROFIT_LOT; + } + DrawSprite(spr, PAL_NONE, x, y); +} + +/** Maximum number of refit cycles we try, to prevent infinite loops. And we store only a byte anyway */ +static const uint MAX_REFIT_CYCLE = 256; + +/** + * Get the best fitting subtype when 'cloning'/'replacing' \a v_from with \a v_for. + * All articulated parts of both vehicles are tested to find a possibly shared subtype. + * For \a v_for only vehicle refittable to \a dest_cargo_type are considered. + * @param v_from the vehicle to match the subtype from + * @param v_for the vehicle to get the subtype for + * @param dest_cargo_type Destination cargo type. + * @return the best sub type + */ +byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_type) +{ + v_from = v_from->GetFirstEnginePart(); + v_for = v_for->GetFirstEnginePart(); + + /* Create a list of subtypes used by the various parts of v_for */ + static SmallVector subtypes; + subtypes.Clear(); + for (; v_from != NULL; v_from = v_from->HasArticulatedPart() ? v_from->GetNextArticulatedPart() : NULL) { + const Engine *e_from = v_from->GetEngine(); + if (!e_from->CanCarryCargo() || !HasBit(e_from->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) continue; + subtypes.Include(GetCargoSubtypeText(v_from)); + } + + byte ret_refit_cyc = 0; + bool success = false; + if (subtypes.Length() > 0) { + /* Check whether any articulated part is refittable to 'dest_cargo_type' with a subtype listed in 'subtypes' */ + for (Vehicle *v = v_for; v != NULL; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL) { + const Engine *e = v->GetEngine(); + if (!e->CanCarryCargo() || !HasBit(e->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) continue; + if (!HasBit(e->info.refit_mask, dest_cargo_type) && v->cargo_type != dest_cargo_type) continue; + + CargoID old_cargo_type = v->cargo_type; + byte old_cargo_subtype = v->cargo_subtype; + + /* Set the 'destination' cargo */ + v->cargo_type = dest_cargo_type; + + /* Cycle through the refits */ + for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) { + v->cargo_subtype = refit_cyc; + + /* Make sure we don't pick up anything cached. */ + v->First()->InvalidateNewGRFCache(); + v->InvalidateNewGRFCache(); + + StringID subtype = GetCargoSubtypeText(v); + if (subtype == STR_EMPTY) break; + + if (!subtypes.Contains(subtype)) continue; + + /* We found something matching. */ + ret_refit_cyc = refit_cyc; + success = true; + break; + } + + /* Reset the vehicle's cargo type */ + v->cargo_type = old_cargo_type; + v->cargo_subtype = old_cargo_subtype; + + /* Make sure we don't taint the vehicle. */ + v->First()->InvalidateNewGRFCache(); + v->InvalidateNewGRFCache(); + + if (success) break; + } + } + + return ret_refit_cyc; +} + +/** Option to refit a vehicle chain */ +struct RefitOption { + CargoID cargo; ///< Cargo to refit to + byte subtype; ///< Subcargo to use + StringID string; ///< GRF-local String to display for the cargo + + /** + * Inequality operator for #RefitOption. + * @param other Compare to this #RefitOption. + * @return True if both #RefitOption are different. + */ + inline bool operator != (const RefitOption &other) const + { + return other.cargo != this->cargo || other.string != this->string; + } + + /** + * Equality operator for #RefitOption. + * @param other Compare to this #RefitOption. + * @return True if both #RefitOption are equal. + */ + inline bool operator == (const RefitOption &other) const + { + return other.cargo == this->cargo && other.string == this->string; + } +}; + +typedef SmallVector SubtypeList; ///< List of refit subtypes associated to a cargo. + +/** + * Draw the list of available refit options for a consist and highlight the selected refit option (if any). + * @param list List of subtype options for each (sorted) cargo. + * @param sel Selected refit cargo-type in the window + * @param pos Position of the selected item in caller widow + * @param rows Number of rows(capacity) in caller window + * @param delta Step height in caller window + * @param r Rectangle of the matrix widget. + */ +static void DrawVehicleRefitWindow(const SubtypeList list[NUM_CARGO], const int sel[2], uint pos, uint rows, uint delta, const Rect &r) +{ + uint y = Center(r.top, delta); + uint current = 0; + + bool rtl = _current_text_dir == TD_RTL; + uint iconwidth = max(GetSpriteSize(SPR_CIRCLE_FOLDED).width, GetSpriteSize(SPR_CIRCLE_UNFOLDED).width); + uint iconheight = GetSpriteSize(SPR_CIRCLE_FOLDED).height; + int linecolour = _colour_gradient[COLOUR_ORANGE][4]; + + int iconleft = rtl ? r.right - WD_MATRIX_RIGHT - iconwidth : r.left + WD_MATRIX_LEFT; + int iconcenter = rtl ? r.right - WD_MATRIX_RIGHT - iconwidth / 2 : r.left + WD_MATRIX_LEFT + iconwidth / 2; + int iconinner = rtl ? r.right - WD_MATRIX_RIGHT - iconwidth : r.left + WD_MATRIX_LEFT + iconwidth; + + int textleft = r.left + WD_MATRIX_LEFT + (rtl ? 0 : iconwidth + 4); + int textright = r.right - WD_MATRIX_RIGHT - (rtl ? iconwidth + 4 : 0); + + /* Draw the list of subtypes for each cargo, and find the selected refit option (by its position). */ + for (uint i = 0; current < pos + rows && i < NUM_CARGO; i++) { + for (uint j = 0; current < pos + rows && j < list[i].Length(); j++) { + const RefitOption &refit = list[i][j]; + + /* Hide subtypes if sel[0] does not match */ + if (sel[0] != (int)i && refit.subtype != 0xFF) continue; + + /* Refit options with a position smaller than pos don't have to be drawn. */ + if (current < pos) { + current++; + continue; + } + + if (list[i].Length() > 1) { + if (refit.subtype != 0xFF) { + /* Draw tree lines */ + int ycenter = y + FONT_HEIGHT_NORMAL / 2; + GfxDrawLine(iconcenter, y - WD_MATRIX_TOP, iconcenter, j == list[i].Length() - 1 ? ycenter : y - WD_MATRIX_TOP + delta - 1, linecolour); + GfxDrawLine(iconcenter, ycenter, iconinner, ycenter, linecolour); + } else { + /* Draw expand/collapse icon */ + DrawSprite(sel[0] == (int)i ? SPR_CIRCLE_UNFOLDED : SPR_CIRCLE_FOLDED, PAL_NONE, iconleft, y + (FONT_HEIGHT_NORMAL - iconheight) / 2); + } + } + + TextColour colour = (sel[0] == (int)i && (uint)sel[1] == j) ? TC_WHITE : TC_BLACK; + /* Get the cargo name. */ + SetDParam(0, CargoSpec::Get(refit.cargo)->name); + SetDParam(1, refit.string); + DrawString(textleft, textright, y, STR_JUST_STRING_STRING, colour); + + y += delta; + current++; + } + } +} + +/** Refit cargo window. */ +struct RefitWindow : public Window { + int sel[2]; ///< Index in refit options, sel[0] == -1 if nothing is selected. + RefitOption *cargo; ///< Refit option selected by #sel. + SubtypeList list[NUM_CARGO]; ///< List of refit subtypes available for each sorted cargo. + VehicleOrderID order; ///< If not #INVALID_VEH_ORDER_ID, selection is part of a refit order (rather than execute directly). + uint information_width; ///< Width required for correctly displaying all cargoes in the information panel. + Scrollbar *vscroll; ///< The main scrollbar. + Scrollbar *hscroll; ///< Only used for long vehicles. + int vehicle_width; ///< Width of the vehicle being drawn. + int sprite_left; ///< Left position of the vehicle sprite. + int sprite_right; ///< Right position of the vehicle sprite. + uint vehicle_margin; ///< Margin to use while selecting vehicles when the vehicle image is centered. + int click_x; ///< Position of the first click while dragging. + VehicleID selected_vehicle; ///< First vehicle in the current selection. + uint8 num_vehicles; ///< Number of selected vehicles. + bool auto_refit; ///< Select cargo for auto-refitting. + + /** + * Collects all (cargo, subcargo) refit options of a vehicle chain. + */ + void BuildRefitList() + { + for (uint i = 0; i < NUM_CARGO; i++) this->list[i].Clear(); + Vehicle *v = Vehicle::Get(this->window_number); + + /* Check only the selected vehicles. */ + VehicleSet vehicles_to_refit; + GetVehicleSet(vehicles_to_refit, Vehicle::Get(this->selected_vehicle), this->num_vehicles); + + do { + if (v->type == VEH_TRAIN && !vehicles_to_refit.Contains(v->index)) continue; + const Engine *e = v->GetEngine(); + uint32 cmask = e->info.refit_mask; + byte callback_mask = e->info.callback_mask; + + /* Skip this engine if it does not carry anything */ + if (!e->CanCarryCargo()) continue; + /* Skip this engine if we build the list for auto-refitting and engine doesn't allow it. */ + if (this->auto_refit && !HasBit(e->info.misc_flags, EF_AUTO_REFIT)) continue; + + /* Loop through all cargoes in the refit mask */ + int current_index = 0; + const CargoSpec *cs; + FOR_ALL_SORTED_CARGOSPECS(cs) { + CargoID cid = cs->Index(); + /* Skip cargo type if it's not listed */ + if (!HasBit(cmask, cid)) { + current_index++; + continue; + } + + bool first_vehicle = this->list[current_index].Length() == 0; + if (first_vehicle) { + /* Keeping the current subtype is always an option. It also serves as the option in case of no subtypes */ + RefitOption *option = this->list[current_index].Append(); + option->cargo = cid; + option->subtype = 0xFF; + option->string = STR_EMPTY; + } + + /* Check the vehicle's callback mask for cargo suffixes. + * This is not supported for ordered refits, since subtypes only have a meaning + * for a specific vehicle at a specific point in time, which conflicts with shared orders, + * autoreplace, autorenew, clone, order restoration, ... */ + if (this->order == INVALID_VEH_ORDER_ID && HasBit(callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) { + /* Make a note of the original cargo type. It has to be + * changed to test the cargo & subtype... */ + CargoID temp_cargo = v->cargo_type; + byte temp_subtype = v->cargo_subtype; + + v->cargo_type = cid; + + for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) { + v->cargo_subtype = refit_cyc; + + /* Make sure we don't pick up anything cached. */ + v->First()->InvalidateNewGRFCache(); + v->InvalidateNewGRFCache(); + + StringID subtype = GetCargoSubtypeText(v); + + if (first_vehicle) { + /* Append new subtype (don't add duplicates though) */ + if (subtype == STR_EMPTY) break; + + RefitOption option; + option.cargo = cid; + option.subtype = refit_cyc; + option.string = subtype; + this->list[current_index].Include(option); + } else { + /* Intersect the subtypes of earlier vehicles with the subtypes of this vehicle */ + if (subtype == STR_EMPTY) { + /* No more subtypes for this vehicle, delete all subtypes >= refit_cyc */ + SubtypeList &l = this->list[current_index]; + /* 0xFF item is in front, other subtypes are sorted. So just truncate the list in the right spot */ + for (uint i = 1; i < l.Length(); i++) { + if (l[i].subtype >= refit_cyc) { + l.Resize(i); + break; + } + } + break; + } else { + /* Check whether the subtype matches with the subtype of earlier vehicles. */ + uint pos = 1; + SubtypeList &l = this->list[current_index]; + while (pos < l.Length() && l[pos].subtype != refit_cyc) pos++; + if (pos < l.Length() && l[pos].string != subtype) { + /* String mismatch, remove item keeping the order */ + l.ErasePreservingOrder(pos); + } + } + } + } + + /* Reset the vehicle's cargo type */ + v->cargo_type = temp_cargo; + v->cargo_subtype = temp_subtype; + + /* And make sure we haven't tainted the cache */ + v->First()->InvalidateNewGRFCache(); + v->InvalidateNewGRFCache(); + } + current_index++; + } + } while (v->IsGroundVehicle() && (v = v->Next()) != NULL); + } + + /** + * Refresh scrollbar after selection changed + */ + void RefreshScrollbar() + { + uint scroll_row = 0; + uint row = 0; + + for (uint i = 0; i < NUM_CARGO; i++) { + for (uint j = 0; j < this->list[i].Length(); j++) { + const RefitOption &refit = this->list[i][j]; + + /* Hide subtypes if sel[0] does not match */ + if (this->sel[0] != (int)i && refit.subtype != 0xFF) continue; + + if (this->sel[0] == (int)i && (uint)this->sel[1] == j) scroll_row = row; + + row++; + } + } + + this->vscroll->SetCount(row); + if (scroll_row < row) this->vscroll->ScrollTowards(scroll_row); + } + + /** + * Select a row. + * @param click_row Clicked row + */ + void SetSelection(uint click_row) + { + uint row = 0; + + for (uint i = 0; i < NUM_CARGO; i++) { + for (uint j = 0; j < this->list[i].Length(); j++) { + const RefitOption &refit = this->list[i][j]; + + /* Hide subtypes if sel[0] does not match */ + if (this->sel[0] != (int)i && refit.subtype != 0xFF) continue; + + if (row == click_row) { + this->sel[0] = i; + this->sel[1] = j; + return; + } + + row++; + } + } + + this->sel[0] = -1; + this->sel[1] = 0; + } + + /** + * Gets the #RefitOption placed in the selected index. + * @return Pointer to the #RefitOption currently in use. + */ + RefitOption *GetRefitOption() + { + if (this->sel[0] < 0) return NULL; + + SubtypeList &l = this->list[this->sel[0]]; + if ((uint)this->sel[1] >= l.Length()) return NULL; + + return &l[this->sel[1]]; + } + + RefitWindow(WindowDesc *desc, const Vehicle *v, VehicleOrderID order, bool auto_refit) : Window(desc) + { + this->sel[0] = -1; + this->sel[1] = 0; + this->auto_refit = auto_refit; + this->order = order; + this->CreateNestedTree(); + + this->vscroll = this->GetScrollbar(WID_VR_SCROLLBAR); + this->hscroll = (v->IsGroundVehicle() ? this->GetScrollbar(WID_VR_HSCROLLBAR) : NULL); + this->GetWidget(WID_VR_SELECT_HEADER)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type; + this->GetWidget(WID_VR_MATRIX)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type; + NWidgetCore *nwi = this->GetWidget(WID_VR_REFIT); + nwi->widget_data = STR_REFIT_TRAIN_REFIT_BUTTON + v->type; + nwi->tool_tip = STR_REFIT_TRAIN_REFIT_TOOLTIP + v->type; + this->GetWidget(WID_VR_SHOW_HSCROLLBAR)->SetDisplayedPlane(v->IsGroundVehicle() ? 0 : SZSP_HORIZONTAL); + this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY)->tool_tip = (v->type == VEH_TRAIN) ? STR_REFIT_SELECT_VEHICLES_TOOLTIP : STR_NULL; + + this->FinishInitNested(v->index); + this->owner = v->owner; + + this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0); + } + + virtual void OnInit() + { + if (this->cargo != NULL) { + /* Store the RefitOption currently in use. */ + RefitOption current_refit_option = *(this->cargo); + + /* Rebuild the refit list */ + this->BuildRefitList(); + this->sel[0] = -1; + this->sel[1] = 0; + this->cargo = NULL; + for (uint i = 0; this->cargo == NULL && i < NUM_CARGO; i++) { + for (uint j = 0; j < list[i].Length(); j++) { + if (list[i][j] == current_refit_option) { + this->sel[0] = i; + this->sel[1] = j; + this->cargo = &list[i][j]; + break; + } + } + } + + this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0); + this->RefreshScrollbar(); + } else { + /* Rebuild the refit list */ + this->OnInvalidateData(VIWD_CONSIST_CHANGED); + } + } + + virtual void OnPaint() + { + /* Determine amount of items for scroller. */ + if (this->hscroll != NULL) this->hscroll->SetCount(this->vehicle_width); + + /* Calculate sprite position. */ + NWidgetCore *vehicle_panel_display = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); + int sprite_width = max(0, ((int)vehicle_panel_display->current_x - this->vehicle_width) / 2); + this->sprite_left = vehicle_panel_display->pos_x; + this->sprite_right = vehicle_panel_display->pos_x + vehicle_panel_display->current_x - 1; + if (_current_text_dir == TD_RTL) { + this->sprite_right -= sprite_width; + this->vehicle_margin = vehicle_panel_display->current_x - sprite_right; + } else { + this->sprite_left += sprite_width; + this->vehicle_margin = sprite_left; + } + + this->DrawWidgets(); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_VR_MATRIX: + resize->height = GetMinSizing(NWST_STEP, WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM); + size->height = resize->height * 8; + break; + + case WID_VR_VEHICLE_PANEL_DISPLAY: + size->height = max(GetMinSizing(NWST_STEP), GetVehicleHeight(Vehicle::Get(this->window_number)->type)); + break; + + case WID_VR_INFO: + size->width = WD_FRAMERECT_LEFT + this->information_width + WD_FRAMERECT_RIGHT; + break; + } + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_VR_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index); + } + + /** + * Gets the #StringID to use for displaying capacity. + * @param Cargo and cargo subtype to check for capacity. + * @return INVALID_STRING_ID if there is no capacity. StringID to use in any other case. + * @post String parameters have been set. + */ + StringID GetCapacityString(RefitOption *option) const + { + assert(_current_company == _local_company); + Vehicle *v = Vehicle::Get(this->window_number); + CommandCost cost = DoCommand(v->tile, this->selected_vehicle, option->cargo | (int)this->auto_refit << 6 | option->subtype << 8 | + this->num_vehicles << 16, DC_QUERY_COST, GetCmdRefitVeh(v->type)); + + if (cost.Failed()) return INVALID_STRING_ID; + + SetDParam(0, option->cargo); + SetDParam(1, _returned_refit_capacity); + + Money money = cost.GetCost(); + if (_returned_mail_refit_capacity > 0) { + SetDParam(2, CT_MAIL); + SetDParam(3, _returned_mail_refit_capacity); + if (money <= 0) { + SetDParam(4, -money); + return STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT; + } else { + SetDParam(4, money); + return STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT; + } + } else { + if (money <= 0) { + SetDParam(2, -money); + return STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT; + } else { + SetDParam(2, money); + return STR_REFIT_NEW_CAPACITY_COST_OF_REFIT; + } + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_VR_VEHICLE_PANEL_DISPLAY: { + Vehicle *v = Vehicle::Get(this->window_number); + DrawVehicleImage(v, this->sprite_left + WD_FRAMERECT_LEFT, this->sprite_right - WD_FRAMERECT_RIGHT, + r.top, r.bottom - r.top + 1, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != NULL ? this->hscroll->GetPosition() : 0); + + /* Highlight selected vehicles. */ + if (this->order != INVALID_VEH_ORDER_ID) break; + int x = 0; + int y_offset_frame = Center(0, r.bottom - r.top + 1, 14); + switch (v->type) { + case VEH_TRAIN: { + VehicleSet vehicles_to_refit; + GetVehicleSet(vehicles_to_refit, Vehicle::Get(this->selected_vehicle), this->num_vehicles); + + int left = INT32_MIN; + int width = 0; + + for (Train *u = Train::From(v); u != NULL; u = u->Next()) { + /* Start checking. */ + if (vehicles_to_refit.Contains(u->index) && left == INT32_MIN) { + left = x - this->hscroll->GetPosition() + r.left + this->vehicle_margin; + width = 0; + } + + /* Draw a selection. */ + if ((!vehicles_to_refit.Contains(u->index) || u->Next() == NULL) && left != INT32_MIN) { + if (u->Next() == NULL && vehicles_to_refit.Contains(u->index)) { + int current_width = u->GetDisplayImageWidth(); + width += current_width; + x += current_width; + } + + int right = Clamp(left + width, 0, r.right); + left = max(0, left); + + if (_current_text_dir == TD_RTL) { + right = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY)->current_x - left; + left = right - width; + } + + if (left != right) { + DrawFrameRect(left, r.top + y_offset_frame, right, r.top + y_offset_frame + 13, COLOUR_WHITE, FR_BORDERONLY); + } + + left = INT32_MIN; + } + + int current_width = u->GetDisplayImageWidth(); + width += current_width; + x += current_width; + } + break; + } + + default: break; + } + break; + } + + case WID_VR_MATRIX: + DrawVehicleRefitWindow(this->list, this->sel, this->vscroll->GetPosition(), this->vscroll->GetCapacity(), this->resize.step_height, r); + break; + + case WID_VR_INFO: + if (this->cargo != NULL) { + StringID string = this->GetCapacityString(this->cargo); + if (string != INVALID_STRING_ID) { + DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, + r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, string); + } + } + break; + } + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + switch (data) { + case VIWD_AUTOREPLACE: // Autoreplace replaced the vehicle; selected_vehicle became invalid. + case VIWD_CONSIST_CHANGED: { // The consist has changed; rebuild the entire list. + /* Clear the selection. */ + Vehicle *v = Vehicle::Get(this->window_number); + this->selected_vehicle = v->index; + this->num_vehicles = UINT8_MAX; + /* FALL THROUGH */ + } + + case 2: { // The vehicle selection has changed; rebuild the entire list. + if (!gui_scope) break; + this->BuildRefitList(); + + /* The vehicle width has changed too. */ + this->vehicle_width = GetVehicleWidth(Vehicle::Get(this->window_number), EIT_IN_DETAILS); + uint max_width = 0; + + /* Check the width of all cargo information strings. */ + for (uint i = 0; i < NUM_CARGO; i++) { + for (uint j = 0; j < this->list[i].Length(); j++) { + StringID string = this->GetCapacityString(&list[i][j]); + if (string != INVALID_STRING_ID) { + Dimension dim = GetStringBoundingBox(string); + max_width = max(dim.width, max_width); + } + } + } + + if (this->information_width < max_width) { + this->information_width = max_width; + this->ReInit(); + } + /* FALL THROUGH */ + } + + case 1: // A new cargo has been selected. + if (!gui_scope) break; + this->cargo = GetRefitOption(); + this->RefreshScrollbar(); + break; + } + } + + int GetClickPosition(int click_x) + { + const NWidgetCore *matrix_widget = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); + if (_current_text_dir == TD_RTL) click_x = matrix_widget->current_x - click_x; + click_x -= this->vehicle_margin; + if (this->hscroll != NULL) click_x += this->hscroll->GetPosition(); + + return click_x; + } + + void SetSelectedVehicles(int drag_x) + { + drag_x = GetClickPosition(drag_x); + + int left_x = min(this->click_x, drag_x); + int right_x = max(this->click_x, drag_x); + this->num_vehicles = 0; + + Vehicle *v = Vehicle::Get(this->window_number); + /* Find the vehicle part that was clicked. */ + switch (v->type) { + case VEH_TRAIN: { + /* Don't select anything if we are not clicking in the vehicle. */ + if (left_x >= 0) { + const Train *u = Train::From(v); + bool start_counting = false; + for (; u != NULL; u = u->Next()) { + int current_width = u->GetDisplayImageWidth(); + left_x -= current_width; + right_x -= current_width; + + if (left_x < 0 && !start_counting) { + this->selected_vehicle = u->index; + start_counting = true; + + /* Count the first vehicle, even if articulated part */ + this->num_vehicles++; + } else if (start_counting && !u->IsArticulatedPart()) { + /* Do not count articulated parts */ + this->num_vehicles++; + } + + if (right_x < 0) break; + } + } + + /* If the selection is not correct, clear it. */ + if (this->num_vehicles != 0) { + if (_ctrl_pressed) this->num_vehicles = UINT8_MAX; + break; + } + /* FALL THROUGH */ + } + + default: + /* Clear the selection. */ + this->selected_vehicle = v->index; + this->num_vehicles = UINT8_MAX; + break; + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image. + if (this->order != INVALID_VEH_ORDER_ID) break; + NWidgetBase *nwi = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); + this->click_x = GetClickPosition(pt.x - nwi->pos_x); + this->SetSelectedVehicles(pt.x - nwi->pos_x); + this->SetWidgetDirty(WID_VR_VEHICLE_PANEL_DISPLAY); + if (!_ctrl_pressed) { + SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this); + } else { + /* The vehicle selection has changed. */ + this->InvalidateData(2); + } + break; + } + + case WID_VR_MATRIX: { // listbox + this->SetSelection(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_VR_MATRIX)); + this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0); + this->InvalidateData(1); + + if (click_count == 1) break; + /* FALL THROUGH */ + } + + case WID_VR_REFIT: // refit button + if (this->cargo != NULL) { + const Vehicle *v = Vehicle::Get(this->window_number); + + if (this->order == INVALID_VEH_ORDER_ID) { + bool delete_window = this->selected_vehicle == v->index && this->num_vehicles == UINT8_MAX; + if (DoCommandP(v->tile, this->selected_vehicle, this->cargo->cargo | this->cargo->subtype << 8 | this->num_vehicles << 16, GetCmdRefitVeh(v)) && delete_window) delete this; + } else { + if (DoCommandP(v->tile, v->index, this->cargo->cargo | this->order << 16, CMD_ORDER_REFIT)) delete this; + } + } + break; + } + } + + virtual void OnMouseDrag(Point pt, int widget) + { + switch (widget) { + case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image. + if (this->order != INVALID_VEH_ORDER_ID) break; + NWidgetBase *nwi = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); + this->SetSelectedVehicles(pt.x - nwi->pos_x); + this->SetWidgetDirty(WID_VR_VEHICLE_PANEL_DISPLAY); + break; + } + } + } + + virtual void OnDragDrop(Point pt, int widget) + { + switch (widget) { + case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image. + if (this->order != INVALID_VEH_ORDER_ID) break; + NWidgetBase *nwi = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); + this->SetSelectedVehicles(pt.x - nwi->pos_x); + this->InvalidateData(2); + break; + } + } + } + + virtual void OnResize() + { + this->vehicle_width = GetVehicleWidth(Vehicle::Get(this->window_number), EIT_IN_DETAILS); + this->vscroll->SetCapacityFromWidget(this, WID_VR_MATRIX); + if (this->hscroll != NULL) this->hscroll->SetCapacityFromWidget(this, WID_VR_VEHICLE_PANEL_DISPLAY); + } +}; + +static const NWidgetPart _nested_vehicle_refit_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_VR_CAPTION), SetDataTip(STR_REFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + EndContainer(), + /* Vehicle display + scrollbar. */ + NWidget(NWID_VERTICAL), + NWidget(WWT_PANEL, COLOUR_GREY, WID_VR_VEHICLE_PANEL_DISPLAY), SetMinimalSize(228, 14), SetResize(1, 0), SetScrollbar(WID_VR_HSCROLLBAR), EndContainer(), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VR_SHOW_HSCROLLBAR), + NWidget(NWID_HSCROLLBAR, COLOUR_GREY, WID_VR_HSCROLLBAR), + EndContainer(), + EndContainer(), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_VR_SELECT_HEADER), SetDataTip(STR_REFIT_TITLE, STR_NULL), SetResize(1, 0), + /* Matrix + scrollbar. */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_VR_MATRIX), SetMinimalSize(228, 112), SetResize(1, 14), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_VR_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VR_SCROLLBAR), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_VR_INFO), SetMinimalTextLines(2, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), SetResize(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VR_REFIT), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +static WindowDesc _vehicle_refit_desc( + WDP_AUTO, "view_vehicle_refit", 240, 174, + WC_VEHICLE_REFIT, WC_VEHICLE_VIEW, + WDF_CONSTRUCTION, + _nested_vehicle_refit_widgets, lengthof(_nested_vehicle_refit_widgets) +); + +/** + * Show the refit window for a vehicle + * @param *v The vehicle to show the refit window for + * @param order of the vehicle to assign refit to, or INVALID_VEH_ORDER_ID to refit the vehicle now + * @param parent the parent window of the refit window + * @param auto_refit Choose cargo for auto-refitting + */ +void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit) +{ + DeleteWindowById(WC_VEHICLE_REFIT, v->index); + RefitWindow *w = new RefitWindow(&_vehicle_refit_desc, v, order, auto_refit); + w->parent = parent; +} + +/** Display list of cargo types of the engine, for the purchase information window */ +uint ShowRefitOptionsList(int left, int right, int y, EngineID engine) +{ + /* List of cargo types of this engine */ + uint32 cmask = GetUnionOfArticulatedRefitMasks(engine, false); + /* List of cargo types available in this climate */ + uint32 lmask = _cargo_mask; + + /* Draw nothing if the engine is not refittable */ + if (HasAtMostOneBit(cmask)) return y; + + if (cmask == lmask) { + /* Engine can be refitted to all types in this climate */ + SetDParam(0, STR_PURCHASE_INFO_ALL_TYPES); + } else { + /* Check if we are able to refit to more cargo types and unable to. If + * so, invert the cargo types to list those that we can't refit to. */ + if (CountBits(cmask ^ lmask) < CountBits(cmask) && CountBits(cmask ^ lmask) <= 7) { + cmask ^= lmask; + SetDParam(0, STR_PURCHASE_INFO_ALL_BUT); + } else { + SetDParam(0, STR_JUST_CARGO_LIST); + } + SetDParam(1, cmask); + } + + return DrawStringMultiLine(left, right, y, INT32_MAX, STR_PURCHASE_INFO_REFITTABLE_TO); +} + +/** Get the cargo subtype text from NewGRF for the vehicle details window. */ +StringID GetCargoSubtypeText(const Vehicle *v) +{ + if (HasBit(EngInfo(v->engine_type)->callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) { + uint16 cb = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, v->engine_type, v); + if (cb != CALLBACK_FAILED) { + if (cb > 0x400) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_CARGO_SUFFIX, cb); + if (cb >= 0x400 || (v->GetGRF()->grf_version < 8 && cb == 0xFF)) cb = CALLBACK_FAILED; + } + if (cb != CALLBACK_FAILED) { + return GetGRFStringID(v->GetGRFID(), 0xD000 + cb); + } + } + return STR_EMPTY; +} + +/** Sort vehicles by their number */ +static int CDECL VehicleNumberSorter(const Vehicle * const *a, const Vehicle * const *b) +{ + return (*a)->unitnumber - (*b)->unitnumber; +} + +/** Sort vehicles by their name */ +static int CDECL VehicleNameSorter(const Vehicle * const *a, const Vehicle * const *b) +{ + static char last_name[2][64]; + + if (*a != _last_vehicle[0]) { + _last_vehicle[0] = *a; + SetDParam(0, (*a)->index); + GetString(last_name[0], STR_VEHICLE_NAME, lastof(last_name[0])); + } + + if (*b != _last_vehicle[1]) { + _last_vehicle[1] = *b; + SetDParam(0, (*b)->index); + GetString(last_name[1], STR_VEHICLE_NAME, lastof(last_name[1])); + } + + int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + +/** Sort vehicles by their age */ +static int CDECL VehicleAgeSorter(const Vehicle * const *a, const Vehicle * const *b) +{ + int r = (*a)->age - (*b)->age; + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + +/** Sort vehicles by this year profit */ +static int CDECL VehicleProfitThisYearSorter(const Vehicle * const *a, const Vehicle * const *b) +{ + int r = ClampToI32((*a)->GetDisplayProfitThisYear() - (*b)->GetDisplayProfitThisYear()); + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + +/** Sort vehicles by last year profit */ +static int CDECL VehicleProfitLastYearSorter(const Vehicle * const *a, const Vehicle * const *b) +{ + int r = ClampToI32((*a)->GetDisplayProfitLastYear() - (*b)->GetDisplayProfitLastYear()); + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + +/** Sort vehicles by their cargo */ +static int CDECL VehicleCargoSorter(const Vehicle * const *a, const Vehicle * const *b) +{ + const Vehicle *v; + CargoArray diff; + + /* Append the cargo of the connected waggons */ + for (v = *a; v != NULL; v = v->Next()) diff[v->cargo_type] += v->cargo_cap; + for (v = *b; v != NULL; v = v->Next()) diff[v->cargo_type] -= v->cargo_cap; + + int r = 0; + for (CargoID i = 0; i < NUM_CARGO; i++) { + r = diff[i]; + if (r != 0) break; + } + + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + +/** Sort vehicles by their reliability */ +static int CDECL VehicleReliabilitySorter(const Vehicle * const *a, const Vehicle * const *b) +{ + int r = (*a)->reliability - (*b)->reliability; + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + +/** Sort vehicles by their max speed */ +static int CDECL VehicleMaxSpeedSorter(const Vehicle * const *a, const Vehicle * const *b) +{ + int r = (*a)->vcache.cached_max_speed - (*b)->vcache.cached_max_speed; + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + +/** Sort vehicles by model */ +static int CDECL VehicleModelSorter(const Vehicle * const *a, const Vehicle * const *b) +{ + int r = (*a)->engine_type - (*b)->engine_type; + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + +/** Sort vehicles by their value */ +static int CDECL VehicleValueSorter(const Vehicle * const *a, const Vehicle * const *b) +{ + const Vehicle *u; + Money diff = 0; + + for (u = *a; u != NULL; u = u->Next()) diff += u->value; + for (u = *b; u != NULL; u = u->Next()) diff -= u->value; + + int r = ClampToI32(diff); + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + +/** Sort vehicles by their length */ +static int CDECL VehicleLengthSorter(const Vehicle * const *a, const Vehicle * const *b) +{ + int r = (*a)->GetGroundVehicleCache()->cached_total_length - (*b)->GetGroundVehicleCache()->cached_total_length; + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + +/** Sort vehicles by the time they can still live */ +static int CDECL VehicleTimeToLiveSorter(const Vehicle * const *a, const Vehicle * const *b) +{ + int r = ClampToI32(((*a)->max_age - (*a)->age) - ((*b)->max_age - (*b)->age)); + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + +/** Sort vehicles by the timetable delay */ +static int CDECL VehicleTimetableDelaySorter(const Vehicle * const *a, const Vehicle * const *b) +{ + int r = (*a)->lateness_counter - (*b)->lateness_counter; + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + +void InitializeGUI() +{ + MemSetT(&_sorting, 0); +} + +/** + * Assign a vehicle window a new vehicle + * @param window_class WindowClass to search for + * @param from_index the old vehicle ID + * @param to_index the new vehicle ID + */ +static inline void ChangeVehicleWindow(WindowClass window_class, VehicleID from_index, VehicleID to_index) +{ + Window *w = FindWindowById(window_class, from_index); + if (w != NULL) { + /* Update window_number */ + w->window_number = to_index; + if (w->viewport != NULL) w->viewport->follow_vehicle = to_index; + + /* Update vehicle drag data */ + if (_thd.window_class == window_class && _thd.window_number == (WindowNumber)from_index) { + _thd.window_number = to_index; + } + + /* Notify the window. */ + w->InvalidateData(VIWD_AUTOREPLACE, false); + } +} + +/** + * Report a change in vehicle IDs (due to autoreplace) to affected vehicle windows. + * @param from_index the old vehicle ID + * @param to_index the new vehicle ID + */ +void ChangeVehicleViewWindow(VehicleID from_index, VehicleID to_index) +{ + ChangeVehicleWindow(WC_VEHICLE_VIEW, from_index, to_index); + ChangeVehicleWindow(WC_VEHICLE_ORDERS, from_index, to_index); + ChangeVehicleWindow(WC_VEHICLE_REFIT, from_index, to_index); + ChangeVehicleWindow(WC_VEHICLE_DETAILS, from_index, to_index); + ChangeVehicleWindow(WC_VEHICLE_TIMETABLE, from_index, to_index); +} + +static const NWidgetPart _nested_vehicle_list[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_VL_CAPTION), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VL_SORT_ORDER), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_SORT_BY_PULLDOWN), SetMinimalSize(167, 12), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetFill(1, 1), SetResize(1, 0), + EndContainer(), + EndContainer(), + + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_VL_LIST), SetMinimalSize(248, 0), SetFill(1, 0), SetResize(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_VL_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VL_SCROLLBAR), + EndContainer(), + + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VL_HIDE_BUTTONS), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VL_AVAILABLE_VEHICLES), SetMinimalSize(106, 12), SetFill(0, 1), + SetDataTip(STR_BLACK_STRING, STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetResize(1, 0), SetFill(1, 1), EndContainer(), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_MANAGE_VEHICLES_DROPDOWN), SetMinimalSize(118, 12), SetFill(0, 1), + SetDataTip(STR_VEHICLE_LIST_MANAGE_LIST, STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VL_STOP_ALL), SetMinimalSize(12, 12), SetFill(0, 1), + SetDataTip(SPR_FLAG_VEH_STOPPED, STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VL_START_ALL), SetMinimalSize(12, 12), SetFill(0, 1), + SetDataTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP), + EndContainer(), + /* Widget to be shown for other companies hiding the previous 5 widgets. */ + NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, VehicleOrderID start = 0) +{ + const Order *order = v->GetOrder(start); + if (order == NULL) return; + + int i = 0; + VehicleOrderID oid = start; + + do { + if (oid == v->cur_real_order_index) DrawString(left, right, y, STR_TINY_RIGHT_ARROW, TC_BLACK); + + if (order->IsType(OT_GOTO_STATION)) { + SetDParam(0, order->GetDestination()); + DrawString(left + 6, right - 6, y, STR_TINY_BLACK_STATION); + + y += FONT_HEIGHT_SMALL; + if (++i == 4) break; + } + + oid++; + order = order->next; + if (order == NULL) { + order = v->orders.list->GetFirstOrder(); + oid = 0; + } + } while (oid != start); +} + +/** + * Draws an image of a vehicle chain + * @param v Front vehicle + * @param left The minimum horizontal position + * @param right The maximum horizontal position + * @param y Vertical position to draw at + * @param selection Selected vehicle to draw a frame around + * @param skip Number of pixels to skip at the front (for scrolling) + */ +void DrawVehicleImage(const Vehicle *v, int left, int right, int y, int height, VehicleID selection, EngineImageType image_type, int skip) +{ + y = Center(y, height, GetVehicleHeight(v->type)); + switch (v->type) { + case VEH_TRAIN: DrawTrainImage(Train::From(v), left, right, y, selection, image_type, skip); break; + case VEH_ROAD: DrawRoadVehImage(v, left, right, y, selection, image_type, skip); break; + case VEH_SHIP: DrawShipImage(v, left, right, y, selection, image_type); break; + case VEH_AIRCRAFT: DrawAircraftImage(v, left, right, y, selection, image_type); break; + default: NOT_REACHED(); + } +} + +/** + * Get the height of a vehicle in the vehicle list GUIs. + * @param type the vehicle type to look at + * @param divisor the resulting height must be dividable by this + * @return the height + */ +uint GetVehicleListHeight(VehicleType type, uint divisor) +{ + /* Name + vehicle + profit */ + uint base = GetMinSizing(NWST_STEP, GetVehicleHeight(type) + 2 * FONT_HEIGHT_SMALL); + /* Drawing of the 4 small orders + profit*/ + if (type >= VEH_SHIP) base = max(base, 5U * FONT_HEIGHT_SMALL); + + if (divisor == 1) return base; + + /* Make sure the height is dividable by divisor */ + uint rem = base % divisor; + return base + (rem == 0 ? 0 : divisor - rem); +} + +/** + * Draw all the vehicle list items. + * @param selected_vehicle The vehicle that is to be highlighted. + * @param line_height Height of a single item line. + * @param r Rectangle with edge positions of the matrix widget. + */ +void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int line_height, const Rect &r) const +{ + int left = r.left + WD_MATRIX_LEFT; + int right = r.right - WD_MATRIX_RIGHT; + int width = right - left; + bool rtl = _current_text_dir == TD_RTL; + + int text_offset = GetDigitWidth() * this->unitnumber_digits + WD_FRAMERECT_RIGHT; + int text_left = left + (rtl ? 0 : text_offset); + int text_right = right - (rtl ? text_offset : 0); + + bool show_orderlist = this->vli.vtype >= VEH_SHIP; + int orderlist_left = left + (rtl ? 0 : max(100 + text_offset, width / 2)); + int orderlist_right = right - (rtl ? max(100 + text_offset, width / 2) : 0); + + int image_left = (rtl && show_orderlist) ? orderlist_right : text_left; + int image_right = (!rtl && show_orderlist) ? orderlist_left : text_right; + + int vehicle_button_x = rtl ? right - GetSpriteSize(SPR_PROFIT_LOT).width : left; + + int y = r.top; + uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->vehicles.Length()); + for (uint i = this->vscroll->GetPosition(); i < max; ++i) { + const Vehicle *v = this->vehicles[i]; + StringID str; + + SetDParam(0, v->GetDisplayProfitThisYear()); + SetDParam(1, v->GetDisplayProfitLastYear()); + + DrawVehicleImage(v, image_left, image_right, y, line_height, selected_vehicle, EIT_IN_LIST, 0); + DrawString(text_left, text_right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1, STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR); + + if (v->name != NULL) { + /* The vehicle got a name so we will print it */ + SetDParam(0, v->index); + DrawString(text_left, text_right, y, STR_TINY_BLACK_VEHICLE); + } else if (v->group_id != DEFAULT_GROUP) { + /* The vehicle has no name, but is member of a group, so print group name */ + SetDParam(0, v->group_id); + DrawString(text_left, text_right, y, STR_TINY_GROUP, TC_BLACK); + } + + if (show_orderlist) DrawSmallOrderList(v, orderlist_left, orderlist_right, y, v->cur_real_order_index); + + if (v->IsChainInDepot()) { + str = STR_BLUE_COMMA; + } else { + str = (v->age > v->max_age - DAYS_IN_LEAP_YEAR) ? STR_RED_COMMA : STR_BLACK_COMMA; + } + + SetDParam(0, v->unitnumber); + DrawString(left, right, y + 2, str); + + DrawVehicleProfitButton(v, vehicle_button_x, y + FONT_HEIGHT_NORMAL + 3); + + y += line_height; + } +} + +/** + * Window for the (old) vehicle listing. + * + * bitmask for w->window_number + * 0-7 CompanyID (owner) + * 8-10 window type (use flags in vehicle_gui.h) + * 11-15 vehicle type (using VEH_, but can be compressed to fewer bytes if needed) + * 16-31 StationID or OrderID depending on window type (bit 8-10) + */ +struct VehicleListWindow : public BaseVehicleListWindow { +private: + /** Enumeration of planes of the button row at the bottom. */ + enum ButtonPlanes { + BP_SHOW_BUTTONS, ///< Show the buttons. + BP_HIDE_BUTTONS, ///< Show the empty panel. + }; + +public: + VehicleListWindow(WindowDesc *desc, WindowNumber window_number) : BaseVehicleListWindow(desc, window_number) + { + /* Set up sorting. Make the window-specific _sorting variable + * point to the correct global _sorting struct so we are freed + * from having conditionals during window operation */ + switch (this->vli.vtype) { + case VEH_TRAIN: this->sorting = &_sorting.train; break; + case VEH_ROAD: this->sorting = &_sorting.roadveh; break; + case VEH_SHIP: this->sorting = &_sorting.ship; break; + case VEH_AIRCRAFT: this->sorting = &_sorting.aircraft; break; + default: NOT_REACHED(); + } + + this->CreateNestedTree(); + + this->vscroll = this->GetScrollbar(WID_VL_SCROLLBAR); + + this->vehicles.SetListing(*this->sorting); + this->vehicles.ForceRebuild(); + this->vehicles.NeedResort(); + this->BuildVehicleList(); + this->SortVehicleList(); + + /* Set up the window widgets */ + this->GetWidget(WID_VL_LIST)->tool_tip = STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vli.vtype; + + if (this->vli.type == VL_SHARED_ORDERS) { + this->GetWidget(WID_VL_CAPTION)->widget_data = STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION; + } else { + this->GetWidget(WID_VL_CAPTION)->widget_data = STR_VEHICLE_LIST_TRAIN_CAPTION + this->vli.vtype; + } + + this->FinishInitNested(window_number); + if (this->vli.company != OWNER_NONE) this->owner = this->vli.company; + } + + ~VehicleListWindow() + { + *this->sorting = this->vehicles.GetListing(); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_VL_LIST: + resize->height = GetVehicleListHeight(this->vli.vtype, 1); + + switch (this->vli.vtype) { + case VEH_TRAIN: + case VEH_ROAD: + size->height = 6 * resize->height; + break; + case VEH_SHIP: + case VEH_AIRCRAFT: + size->height = 4 * resize->height; + break; + default: NOT_REACHED(); + } + break; + + case WID_VL_SORT_ORDER: { + Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); + d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_VL_MANAGE_VEHICLES_DROPDOWN: { + Dimension d = this->GetActionDropdownSize(this->vli.type == VL_STANDARD, false); + d.height += padding.height; + d.width += padding.width; + *size = maxdim(*size, d); + break; + } + } + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_VL_AVAILABLE_VEHICLES: + SetDParam(0, STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vli.vtype); + break; + + case WID_VL_CAPTION: { + switch (this->vli.type) { + case VL_SHARED_ORDERS: // Shared Orders + if (this->vehicles.Length() == 0) { + /* We can't open this window without vehicles using this order + * and we should close the window when deleting the order. */ + NOT_REACHED(); + } + SetDParam(0, this->vscroll->GetCount()); + break; + + case VL_STANDARD: // Company Name + SetDParam(0, STR_COMPANY_NAME); + SetDParam(1, this->vli.index); + SetDParam(3, this->vscroll->GetCount()); + break; + + case VL_STATION_LIST: // Station/Waypoint Name + SetDParam(0, Station::IsExpected(BaseStation::Get(this->vli.index)) ? STR_STATION_NAME : STR_WAYPOINT_NAME); + SetDParam(1, this->vli.index); + SetDParam(3, this->vscroll->GetCount()); + break; + + case VL_DEPOT_LIST: + SetDParam(0, STR_DEPOT_CAPTION); + SetDParam(1, this->vli.vtype); + SetDParam(2, this->vli.index); + SetDParam(3, this->vscroll->GetCount()); + break; + default: NOT_REACHED(); + } + break; + } + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_VL_SORT_ORDER: + /* draw arrow pointing up/down for ascending/descending sorting */ + this->DrawSortButtonState(widget, this->vehicles.IsDescSortOrder() ? SBS_DOWN : SBS_UP); + break; + + case WID_VL_LIST: + this->DrawVehicleListItems(INVALID_VEHICLE, this->resize.step_height, r); + break; + } + } + + virtual void OnPaint() + { + this->BuildVehicleList(); + this->SortVehicleList(); + + if (this->vehicles.Length() == 0 && this->IsWidgetLowered(WID_VL_MANAGE_VEHICLES_DROPDOWN)) { + HideDropDownMenu(this); + } + + /* Hide the widgets that we will not use in this window + * Some windows contains actions only fit for the owner */ + int plane_to_show = (this->owner == _local_company) ? BP_SHOW_BUTTONS : BP_HIDE_BUTTONS; + NWidgetStacked *nwi = this->GetWidget(WID_VL_HIDE_BUTTONS); + if (plane_to_show != nwi->shown_plane) { + nwi->SetDisplayedPlane(plane_to_show); + nwi->SetDirty(this); + } + if (this->owner == _local_company) { + this->SetWidgetDisabledState(WID_VL_AVAILABLE_VEHICLES, this->vli.type != VL_STANDARD); + this->SetWidgetsDisabledState(this->vehicles.Length() == 0, + WID_VL_MANAGE_VEHICLES_DROPDOWN, + WID_VL_STOP_ALL, + WID_VL_START_ALL, + WIDGET_LIST_END); + } + + /* Set text of sort by dropdown widget. */ + this->GetWidget(WID_VL_SORT_BY_PULLDOWN)->widget_data = this->vehicle_sorter_names[this->vehicles.SortType()]; + + this->DrawWidgets(); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_VL_SORT_ORDER: // Flip sorting method ascending/descending + this->vehicles.ToggleSortOrder(); + this->SetDirty(); + break; + + case WID_VL_SORT_BY_PULLDOWN:// Select sorting criteria dropdown menu + ShowDropDownMenu(this, this->vehicle_sorter_names, this->vehicles.SortType(), WID_VL_SORT_BY_PULLDOWN, 0, + (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10)); + return; + + case WID_VL_LIST: { // Matrix to show vehicles + uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_VL_LIST); + if (id_v >= this->vehicles.Length()) return; // click out of list bound + + const Vehicle *v = this->vehicles[id_v]; + if (!VehicleClicked(v)) ShowVehicleViewWindow(v); + break; + } + + case WID_VL_AVAILABLE_VEHICLES: + ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype); + break; + + case WID_VL_MANAGE_VEHICLES_DROPDOWN: { + DropDownList *list = this->BuildActionDropdownList(VehicleListIdentifier(this->window_number).type == VL_STANDARD, false); + ShowDropDownList(this, list, 0, WID_VL_MANAGE_VEHICLES_DROPDOWN); + break; + } + + case WID_VL_STOP_ALL: + case WID_VL_START_ALL: + DoCommandP(0, (1 << 1) | (widget == WID_VL_START_ALL ? (1 << 0) : 0), this->window_number, CMD_MASS_START_STOP); + break; + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + switch (widget) { + case WID_VL_SORT_BY_PULLDOWN: + this->vehicles.SetSortType(index); + break; + case WID_VL_MANAGE_VEHICLES_DROPDOWN: + assert(this->vehicles.Length() != 0); + + switch (index) { + case ADI_REPLACE: // Replace window + ShowReplaceGroupVehicleWindow(ALL_GROUP, this->vli.vtype); + break; + case ADI_SERVICE: // Send for servicing + case ADI_DEPOT: // Send to Depots + DoCommandP(0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : (DepotCommand)0), this->window_number, GetCmdSendToDepot(this->vli.vtype)); + break; + + default: NOT_REACHED(); + } + break; + default: NOT_REACHED(); + } + this->SetDirty(); + } + + virtual void OnTick() + { + if (_pause_mode != PM_UNPAUSED) return; + if (this->vehicles.NeedResort()) { + StationID station = (this->vli.type == VL_STATION_LIST) ? this->vli.index : INVALID_STATION; + + DEBUG(misc, 3, "Periodic resort %d list company %d at station %d", this->vli.vtype, this->owner, station); + this->SetDirty(); + } + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_VL_LIST); + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope && HasBit(data, 31) && this->vli.type == VL_SHARED_ORDERS) { + /* Needs to be done in command-scope, so everything stays valid */ + this->vli.index = GB(data, 0, 20); + this->window_number = this->vli.Pack(); + this->vehicles.ForceRebuild(); + return; + } + + if (data == 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ + this->vehicles.ForceRebuild(); + } else { + this->vehicles.ForceResort(); + } + } +}; + +static WindowDesc _vehicle_list_other_desc( + WDP_AUTO, "list_vehicles", 260, 246, + WC_INVALID, WC_NONE, + 0, + _nested_vehicle_list, lengthof(_nested_vehicle_list) +); + +static WindowDesc _vehicle_list_train_desc( + WDP_AUTO, "list_vehicles_train", 325, 246, + WC_TRAINS_LIST, WC_NONE, + 0, + _nested_vehicle_list, lengthof(_nested_vehicle_list) +); + +static void ShowVehicleListWindowLocal(CompanyID company, VehicleListType vlt, VehicleType vehicle_type, uint32 unique_number) +{ + if (!Company::IsValidID(company) && company != OWNER_NONE) return; + + WindowNumber num = VehicleListIdentifier(vlt, vehicle_type, company, unique_number).Pack(); + if (vehicle_type == VEH_TRAIN) { + AllocateWindowDescFront(&_vehicle_list_train_desc, num); + } else { + _vehicle_list_other_desc.cls = GetWindowClassForVehicleType(vehicle_type); + AllocateWindowDescFront(&_vehicle_list_other_desc, num); + } +} + +void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type) +{ + /* If _settings_client.gui.advanced_vehicle_list > 1, display the Advanced list + * if _settings_client.gui.advanced_vehicle_list == 1, display Advanced list only for local company + * if _ctrl_pressed, do the opposite action (Advanced list x Normal list) + */ + + if ((_settings_client.gui.advanced_vehicle_list > (uint)(company != _local_company)) != _ctrl_pressed) { + ShowCompanyGroup(company, vehicle_type); + } else { + ShowVehicleListWindowLocal(company, VL_STANDARD, vehicle_type, company); + } +} + +void ShowVehicleListWindow(const Vehicle *v) +{ + ShowVehicleListWindowLocal(v->owner, VL_SHARED_ORDERS, v->type, v->FirstShared()->index); +} + +void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, StationID station) +{ + ShowVehicleListWindowLocal(company, VL_STATION_LIST, vehicle_type, station); +} + +void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, TileIndex depot_tile) +{ + uint16 depot_airport_index; + + if (vehicle_type == VEH_AIRCRAFT) { + depot_airport_index = GetStationIndex(depot_tile); + } else { + depot_airport_index = GetDepotIndex(depot_tile); + } + ShowVehicleListWindowLocal(company, VL_DEPOT_LIST, vehicle_type, depot_airport_index); +} + + +/* Unified vehicle GUI - Vehicle Details Window */ + +assert_compile(WID_VD_DETAILS_CARGO_CARRIED == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_CARGO ); +assert_compile(WID_VD_DETAILS_TRAIN_VEHICLES == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_INFO ); +assert_compile(WID_VD_DETAILS_CAPACITY_OF_EACH == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_CAPACITY); +assert_compile(WID_VD_DETAILS_TOTAL_CARGO == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_TOTALS ); + +/** Vehicle details widgets (other than train). */ +static const NWidgetPart _nested_nontrain_vehicle_details_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_VD_CAPTION), SetDataTip(STR_VEHICLE_DETAILS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_RENAME_VEHICLE), SetMinimalSize(40, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_VEHICLE_NAME_BUTTON, STR_NULL /* filled in later */), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_TOP_DETAILS), SetMinimalSize(405, 42), SetResize(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_MIDDLE_DETAILS), SetMinimalSize(405, 45), SetResize(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_VD_DECREASE_SERVICING_INTERVAL), SetFill(0, 1), + SetDataTip(AWV_DECREASE, STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_VD_INCREASE_SERVICING_INTERVAL), SetFill(0, 1), + SetDataTip(AWV_INCREASE, STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VD_SERVICE_INTERVAL_DROPDOWN), SetFill(0, 1), + SetDataTip(STR_EMPTY, STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_SERVICING_INTERVAL), SetFill(1, 1), SetResize(1, 0), EndContainer(), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +/** Train details widgets. */ +static const NWidgetPart _nested_train_vehicle_details_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_VD_CAPTION), SetDataTip(STR_VEHICLE_DETAILS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_RENAME_VEHICLE), SetMinimalSize(40, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_VEHICLE_NAME_BUTTON, STR_NULL /* filled in later */), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_TOP_DETAILS), SetResize(1, 0), SetMinimalSize(405, 42), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_VD_MATRIX), SetResize(1, 1), SetMinimalSize(393, 45), SetMatrixDataTip(1, 0, STR_NULL), SetFill(1, 0), SetScrollbar(WID_VD_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VD_SCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_VD_DECREASE_SERVICING_INTERVAL), SetFill(0, 1), + SetDataTip(AWV_DECREASE, STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_VD_INCREASE_SERVICING_INTERVAL), SetFill(0, 1), + SetDataTip(AWV_INCREASE, STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VD_SERVICE_INTERVAL_DROPDOWN), SetFill(0, 1), + SetDataTip(STR_EMPTY, STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_SERVICING_INTERVAL), SetFill(1, 1), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_DETAILS_CARGO_CARRIED), SetMinimalSize(96, 12), + SetDataTip(STR_VEHICLE_DETAIL_TAB_CARGO, STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_DETAILS_TRAIN_VEHICLES), SetMinimalSize(99, 12), + SetDataTip(STR_VEHICLE_DETAIL_TAB_INFORMATION, STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_DETAILS_CAPACITY_OF_EACH), SetMinimalSize(99, 12), + SetDataTip(STR_VEHICLE_DETAIL_TAB_CAPACITIES, STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_DETAILS_TOTAL_CARGO), SetMinimalSize(99, 12), + SetDataTip(STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO, STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + + +extern int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab); +extern void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_pos, uint16 vscroll_cap, TrainDetailsWindowTabs det_tab); +extern void DrawRoadVehDetails(const Vehicle *v, int left, int right, int y); +extern void DrawShipDetails(const Vehicle *v, int left, int right, int y); +extern void DrawAircraftDetails(const Aircraft *v, int left, int right, int y); + +static StringID _service_interval_dropdown[] = { + STR_VEHICLE_DETAILS_DEFAULT, + STR_VEHICLE_DETAILS_DAYS, + STR_VEHICLE_DETAILS_PERCENT, + INVALID_STRING_ID, +}; + +/** Class for managing the vehicle details window. */ +struct VehicleDetailsWindow : Window { + TrainDetailsWindowTabs tab; ///< For train vehicles: which tab is displayed. + Scrollbar *vscroll; + + /** Initialize a newly created vehicle details window */ + VehicleDetailsWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + const Vehicle *v = Vehicle::Get(window_number); + + this->CreateNestedTree(); + this->vscroll = (v->type == VEH_TRAIN ? this->GetScrollbar(WID_VD_SCROLLBAR) : NULL); + this->FinishInitNested(window_number); + + this->GetWidget(WID_VD_RENAME_VEHICLE)->tool_tip = STR_VEHICLE_DETAILS_TRAIN_RENAME + v->type; + + this->owner = v->owner; + this->tab = TDW_TAB_CARGO; + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (data == VIWD_AUTOREPLACE) { + /* Autoreplace replaced the vehicle. + * Nothing to do for this window. */ + return; + } + if (!gui_scope) return; + const Vehicle *v = Vehicle::Get(this->window_number); + if (v->type == VEH_ROAD) { + const NWidgetBase *nwid_info = this->GetWidget(WID_VD_MIDDLE_DETAILS); + uint aimed_height = this->GetRoadVehDetailsHeight(v); + /* If the number of articulated parts changes, the size of the window must change too. */ + if (aimed_height != nwid_info->current_y) { + this->ReInit(); + } + } + } + + /** + * Gets the desired height for the road vehicle details panel. + * @param v Road vehicle being shown. + * @return Desired height in pixels. + */ + uint GetRoadVehDetailsHeight(const Vehicle *v) + { + uint desired_height; + if (v->HasArticulatedPart()) { + /* An articulated RV has its text drawn under the sprite instead of after it, hence 15 pixels extra. */ + desired_height = WD_FRAMERECT_TOP + 15 + 3 * FONT_HEIGHT_NORMAL + 2 + WD_FRAMERECT_BOTTOM; + /* Add space for the cargo amount for each part. */ + for (const Vehicle *u = v; u != NULL; u = u->Next()) { + if (u->cargo_cap != 0) desired_height += FONT_HEIGHT_NORMAL + 1; + } + } else { + desired_height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + 3 + WD_FRAMERECT_BOTTOM; + } + return desired_height; + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_VD_TOP_DETAILS: { + Dimension dim = { 0, 0 }; + size->height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; + + for (uint i = 0; i < 4; i++) SetDParamMaxValue(i, INT16_MAX); + static const StringID info_strings[] = { + STR_VEHICLE_INFO_MAX_SPEED, + STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, + STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE, + STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR, + STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS + }; + for (uint i = 0; i < lengthof(info_strings); i++) { + dim = maxdim(dim, GetStringBoundingBox(info_strings[i])); + } + SetDParam(0, STR_VEHICLE_INFO_AGE); + dim = maxdim(dim, GetStringBoundingBox(STR_VEHICLE_INFO_AGE_RUNNING_COST_YR)); + size->width = dim.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + break; + } + + case WID_VD_MIDDLE_DETAILS: { + const Vehicle *v = Vehicle::Get(this->window_number); + switch (v->type) { + case VEH_ROAD: + size->height = this->GetRoadVehDetailsHeight(v); + break; + + case VEH_SHIP: + size->height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + 3 + WD_FRAMERECT_BOTTOM; + break; + + case VEH_AIRCRAFT: + size->height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + 4 + WD_FRAMERECT_BOTTOM; + break; + + default: + NOT_REACHED(); // Train uses WID_VD_MATRIX instead. + } + break; + } + + case WID_VD_MATRIX: + resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM; + size->height = 4 * resize->height; + break; + + case WID_VD_SERVICE_INTERVAL_DROPDOWN: { + StringID *strs = _service_interval_dropdown; + while (*strs != INVALID_STRING_ID) { + *size = maxdim(*size, GetStringBoundingBox(*strs++)); + } + size->width += padding.width; + size->height = FONT_HEIGHT_NORMAL + WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM; + break; + } + + case WID_VD_SERVICING_INTERVAL: + SetDParamMaxValue(0, MAX_SERVINT_DAYS); // Roughly the maximum interval + SetDParamMaxValue(1, MAX_YEAR * DAYS_IN_YEAR); // Roughly the maximum year + size->width = max(GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT).width, GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + size->height = WD_FRAMERECT_TOP + FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; + break; + } + } + + /** Checks whether service interval is enabled for the vehicle. */ + static bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type, CompanyID company_id) + { + const VehicleDefaultSettings *vds = &Company::Get(company_id)->settings.vehicle; + switch (vehicle_type) { + default: NOT_REACHED(); + case VEH_TRAIN: return vds->servint_trains != 0; + case VEH_ROAD: return vds->servint_roadveh != 0; + case VEH_SHIP: return vds->servint_ships != 0; + case VEH_AIRCRAFT: return vds->servint_aircraft != 0; + } + } + + /** + * Draw the details for the given vehicle at the position of the Details windows + * + * @param v current vehicle + * @param left The left most coordinate to draw + * @param right The right most coordinate to draw + * @param y The y coordinate + * @param vscroll_pos Position of scrollbar (train only) + * @param vscroll_cap Number of lines currently displayed (train only) + * @param det_tab Selected details tab (train only) + */ + static void DrawVehicleDetails(const Vehicle *v, int left, int right, int y, int vscroll_pos, uint vscroll_cap, TrainDetailsWindowTabs det_tab) + { + switch (v->type) { + case VEH_TRAIN: DrawTrainDetails(Train::From(v), left, right, y, vscroll_pos, vscroll_cap, det_tab); break; + case VEH_ROAD: DrawRoadVehDetails(v, left, right, y); break; + case VEH_SHIP: DrawShipDetails(v, left, right, y); break; + case VEH_AIRCRAFT: DrawAircraftDetails(Aircraft::From(v), left, right, y); break; + default: NOT_REACHED(); + } + } + + virtual void SetStringParameters(int widget) const + { + if (widget == WID_VD_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + const Vehicle *v = Vehicle::Get(this->window_number); + + switch (widget) { + case WID_VD_TOP_DETAILS: { + int y = r.top + WD_FRAMERECT_TOP; + + /* Draw running cost */ + SetDParam(1, v->age / DAYS_IN_LEAP_YEAR); + SetDParam(0, (v->age + DAYS_IN_YEAR < v->max_age) ? STR_VEHICLE_INFO_AGE : STR_VEHICLE_INFO_AGE_RED); + SetDParam(2, v->max_age / DAYS_IN_LEAP_YEAR); + SetDParam(3, v->GetDisplayRunningCost()); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_AGE_RUNNING_COST_YR); + y += FONT_HEIGHT_NORMAL; + + /* Draw max speed */ + StringID string; + if (v->type == VEH_TRAIN || + (v->type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL)) { + const GroundVehicleCache *gcache = v->GetGroundVehicleCache(); + SetDParam(2, v->GetDisplayMaxSpeed()); + SetDParam(1, gcache->cached_power); + SetDParam(0, gcache->cached_weight); + SetDParam(3, gcache->cached_max_te / 1000); + if (v->type == VEH_TRAIN && (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL || + GetRailTypeInfo(Train::From(v)->railtype)->acceleration_type == 2)) { + string = STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED; + } else { + string = STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE; + } + } else { + SetDParam(0, v->GetDisplayMaxSpeed()); + if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->GetRange() > 0) { + SetDParam(1, Aircraft::From(v)->GetRange()); + string = STR_VEHICLE_INFO_MAX_SPEED_RANGE; + } else { + string = STR_VEHICLE_INFO_MAX_SPEED; + } + } + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, string); + y += FONT_HEIGHT_NORMAL; + + /* Draw profit */ + SetDParam(0, v->GetDisplayProfitThisYear()); + SetDParam(1, v->GetDisplayProfitLastYear()); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR); + y += FONT_HEIGHT_NORMAL; + + /* Draw breakdown & reliability */ + SetDParam(0, ToPercent16(v->reliability)); + SetDParam(1, v->breakdowns_since_last_service); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS); + break; + } + + case WID_VD_MATRIX: + /* For trains only. */ + DrawVehicleDetails(v, r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, r.top + WD_MATRIX_TOP, this->vscroll->GetPosition(), this->vscroll->GetCapacity(), this->tab); + break; + + case WID_VD_MIDDLE_DETAILS: { + /* For other vehicles, at the place of the matrix. */ + bool rtl = _current_text_dir == TD_RTL; + uint sprite_width = max(UnScaleByZoom(GetSprite(v->GetImage(rtl ? DIR_E : DIR_W, EIT_IN_DETAILS), ST_NORMAL)->width, ZOOM_LVL_GUI), 70U) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + + uint text_left = r.left + (rtl ? 0 : sprite_width); + uint text_right = r.right - (rtl ? sprite_width : 0); + + /* Articulated road vehicles use a complete line. */ + if (v->type == VEH_ROAD && v->HasArticulatedPart()) { + DrawVehicleImage(v, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, 0); + } else { + uint sprite_left = rtl ? text_right : r.left; + uint sprite_right = rtl ? r.right : text_left; + + DrawVehicleImage(v, sprite_left + WD_FRAMERECT_LEFT, sprite_right - WD_FRAMERECT_RIGHT, r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, 0); + } + DrawVehicleDetails(v, text_left + WD_FRAMERECT_LEFT, text_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, 0, 0, this->tab); + break; + } + + case WID_VD_SERVICING_INTERVAL: + /* Draw service interval text */ + SetDParam(0, v->GetServiceInterval()); + SetDParam(1, v->date_of_last_service); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + (r.bottom - r.top + 1 - FONT_HEIGHT_NORMAL) / 2, + v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT : STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS); + break; + } + } + + /** Repaint vehicle details window. */ + virtual void OnPaint() + { + const Vehicle *v = Vehicle::Get(this->window_number); + + this->SetWidgetDisabledState(WID_VD_RENAME_VEHICLE, v->owner != _local_company); + + if (v->type == VEH_TRAIN) { + this->DisableWidget(this->tab + WID_VD_DETAILS_CARGO_CARRIED); + this->vscroll->SetCount(GetTrainDetailsWndVScroll(v->index, this->tab)); + } + + /* Disable service-scroller when interval is set to disabled */ + this->SetWidgetsDisabledState(!IsVehicleServiceIntervalEnabled(v->type, v->owner), + WID_VD_INCREASE_SERVICING_INTERVAL, + WID_VD_DECREASE_SERVICING_INTERVAL, + WIDGET_LIST_END); + + StringID str = v->ServiceIntervalIsCustom() ? + (v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_PERCENT : STR_VEHICLE_DETAILS_DAYS) : + STR_VEHICLE_DETAILS_DEFAULT; + this->GetWidget(WID_VD_SERVICE_INTERVAL_DROPDOWN)->widget_data = str; + + this->DrawWidgets(); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_VD_RENAME_VEHICLE: { // rename + const Vehicle *v = Vehicle::Get(this->window_number); + SetDParam(0, v->index); + ShowQueryString(STR_VEHICLE_NAME, STR_QUERY_RENAME_TRAIN_CAPTION + v->type, + MAX_LENGTH_VEHICLE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); + break; + } + + case WID_VD_INCREASE_SERVICING_INTERVAL: // increase int + case WID_VD_DECREASE_SERVICING_INTERVAL: { // decrease int + int mod = _ctrl_pressed ? 5 : 10; + const Vehicle *v = Vehicle::Get(this->window_number); + + mod = (widget == WID_VD_DECREASE_SERVICING_INTERVAL) ? -mod : mod; + mod = GetServiceIntervalClamped(mod + v->GetServiceInterval(), v->ServiceIntervalIsPercent()); + if (mod == v->GetServiceInterval()) return; + + DoCommandP(v->tile, v->index, mod | (1 << 16) | (v->ServiceIntervalIsPercent() << 17), CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_SERVICING)); + break; + } + + case WID_VD_SERVICE_INTERVAL_DROPDOWN: { + const Vehicle *v = Vehicle::Get(this->window_number); + ShowDropDownMenu(this, _service_interval_dropdown, v->ServiceIntervalIsCustom() ? (v->ServiceIntervalIsPercent() ? 2 : 1) : 0, widget, 0, 0); + break; + } + + case WID_VD_DETAILS_CARGO_CARRIED: + case WID_VD_DETAILS_TRAIN_VEHICLES: + case WID_VD_DETAILS_CAPACITY_OF_EACH: + case WID_VD_DETAILS_TOTAL_CARGO: + this->SetWidgetsDisabledState(false, + WID_VD_DETAILS_CARGO_CARRIED, + WID_VD_DETAILS_TRAIN_VEHICLES, + WID_VD_DETAILS_CAPACITY_OF_EACH, + WID_VD_DETAILS_TOTAL_CARGO, + widget, + WIDGET_LIST_END); + + this->tab = (TrainDetailsWindowTabs)(widget - WID_VD_DETAILS_CARGO_CARRIED); + this->SetDirty(); + break; + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + switch (widget) { + case WID_VD_SERVICE_INTERVAL_DROPDOWN: { + const Vehicle *v = Vehicle::Get(this->window_number); + bool iscustom = index != 0; + bool ispercent = iscustom ? (index == 2) : Company::Get(v->owner)->settings.vehicle.servint_ispercent; + uint16 interval = GetServiceIntervalClamped(v->GetServiceInterval(), ispercent); + DoCommandP(v->tile, v->index, interval | (iscustom << 16) | (ispercent << 17), CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_SERVICING)); + break; + } + } + } + + virtual void OnQueryTextFinished(char *str) + { + if (str == NULL) return; + + DoCommandP(0, this->window_number, 0, CMD_RENAME_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN + Vehicle::Get(this->window_number)->type), NULL, str); + } + + virtual void OnResize() + { + NWidgetCore *nwi = this->GetWidget(WID_VD_MATRIX); + if (nwi != NULL) { + this->vscroll->SetCapacityFromWidget(this, WID_VD_MATRIX); + } + } +}; + +/** Vehicle details window descriptor. */ +static WindowDesc _train_vehicle_details_desc( + WDP_AUTO, "view_vehicle_details_train", 405, 178, + WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW, + 0, + _nested_train_vehicle_details_widgets, lengthof(_nested_train_vehicle_details_widgets) +); + +/** Vehicle details window descriptor for other vehicles than a train. */ +static WindowDesc _nontrain_vehicle_details_desc( + WDP_AUTO, "view_vehicle_details", 405, 113, + WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW, + 0, + _nested_nontrain_vehicle_details_widgets, lengthof(_nested_nontrain_vehicle_details_widgets) +); + +/** Shows the vehicle details window of the given vehicle. */ +static void ShowVehicleDetailsWindow(const Vehicle *v) +{ + DeleteWindowById(WC_VEHICLE_ORDERS, v->index, false); + DeleteWindowById(WC_VEHICLE_TIMETABLE, v->index, false); + AllocateWindowDescFront((v->type == VEH_TRAIN) ? &_train_vehicle_details_desc : &_nontrain_vehicle_details_desc, v->index); +} + + +/* Unified vehicle GUI - Vehicle View Window */ + +/** Vehicle view widgets. */ +static const NWidgetPart _nested_vehicle_view_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_VV_CAPTION), SetDataTip(STR_VEHICLE_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_DEBUGBOX, COLOUR_GREY), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(WWT_INSET, COLOUR_GREY), SetPadding(2, 2, 2, 2), + NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_VV_VIEWPORT), SetMinimalSize(226, 84), SetResize(1, 1), SetPadding(1, 1, 1, 1), + EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_CENTER_MAIN_VIEW), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(SPR_CENTRE_VIEW_VEHICLE, 0x0 /* filled later */), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VV_SELECT_DEPOT_CLONE), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_GOTO_DEPOT), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(0x0 /* filled later */, 0x0 /* filled later */), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_CLONE), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(0x0 /* filled later */, 0x0 /* filled later */), + EndContainer(), + /* For trains only, 'ignore signal' button. */ + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_FORCE_PROCEED), SetMinimalSize(18, 18), SetFill(1, 1), + SetDataTip(SPR_IGNORE_SIGNALS, STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VV_SELECT_REFIT_TURN), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_REFIT), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(SPR_REFIT_VEHICLE, 0x0 /* filled later */), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_TURN_AROUND), SetMinimalSize(18, 18), SetFill(1, 1), + SetDataTip(SPR_FORCE_VEHICLE_TURN, STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP), + EndContainer(), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_SHOW_ORDERS), SetFill(1, 1), SetMinimalSize(18, 18), SetDataTip(SPR_SHOW_ORDERS, 0x0 /* filled later */), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_SHOW_DETAILS), SetFill(1, 1), SetMinimalSize(18, 18), SetDataTip(SPR_SHOW_VEHICLE_DETAILS, 0x0 /* filled later */), + NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetMinimalSize(18, 0), SetResize(0, 1), EndContainer(), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_VV_START_STOP), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetResize(1, 0), SetFill(1, 0), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +/** Vehicle view window descriptor for all vehicles but trains. */ +static WindowDesc _vehicle_view_desc( + WDP_AUTO, "view_vehicle", 250, 116, + WC_VEHICLE_VIEW, WC_NONE, + 0, + _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets) +); + +/** + * Vehicle view window descriptor for trains. Only minimum_height and + * default_height are different for train view. + */ +static WindowDesc _train_view_desc( + WDP_AUTO, "view_vehicle_train", 250, 134, + WC_VEHICLE_VIEW, WC_NONE, + 0, + _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets) +); + + +/* Just to make sure, nobody has changed the vehicle type constants, as we are + using them for array indexing in a number of places here. */ +assert_compile(VEH_TRAIN == 0); +assert_compile(VEH_ROAD == 1); +assert_compile(VEH_SHIP == 2); +assert_compile(VEH_AIRCRAFT == 3); + +/** Zoom levels for vehicle views indexed by vehicle type. */ +static const ZoomLevel _vehicle_view_zoom_levels[] = { + ZOOM_LVL_TRAIN, + ZOOM_LVL_ROADVEH, + ZOOM_LVL_SHIP, + ZOOM_LVL_AIRCRAFT, +}; + +/* Constants for geometry of vehicle view viewport */ +static const int VV_INITIAL_VIEWPORT_WIDTH = 226; +static const int VV_INITIAL_VIEWPORT_HEIGHT = 84; +static const int VV_INITIAL_VIEWPORT_HEIGHT_TRAIN = 102; + +/** Command indices for the _vehicle_command_translation_table. */ +enum VehicleCommandTranslation { + VCT_CMD_START_STOP = 0, + VCT_CMD_CLONE_VEH, + VCT_CMD_TURN_AROUND, +}; + +/** Command codes for the shared buttons indexed by VehicleCommandTranslation and vehicle type. */ +static const uint32 _vehicle_command_translation_table[][4] = { + { // VCT_CMD_START_STOP + CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_TRAIN), + CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE), + CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_SHIP), + CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_AIRCRAFT) + }, + { // VCT_CMD_CLONE_VEH + CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN), + CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_ROAD_VEHICLE), + CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_SHIP), + CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_AIRCRAFT) + }, + { // VCT_CMD_TURN_AROUND + CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN), + CMD_TURN_ROADVEH | CMD_MSG(STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN), + 0xffffffff, // invalid for ships + 0xffffffff // invalid for aircrafts + }, +}; + +/** + * This is the Callback method after the cloning attempt of a vehicle + * @param result the result of the cloning command + * @param tile unused + * @param p1 vehicle ID + * @param p2 unused + */ +void CcStartStopVehicle(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + + const Vehicle *v = Vehicle::GetIfValid(p1); + if (v == NULL || !v->IsPrimaryVehicle() || v->owner != _local_company) return; + + StringID msg = (v->vehstatus & VS_STOPPED) ? STR_VEHICLE_COMMAND_STOPPED : STR_VEHICLE_COMMAND_STARTED; + Point pt = RemapCoords(v->x_pos, v->y_pos, v->z_pos); + AddTextEffect(msg, pt.x, pt.y, DAY_TICKS, TE_RISING); +} + +/** + * Executes #CMD_START_STOP_VEHICLE for given vehicle. + * @param v Vehicle to start/stop + * @param texteffect Should a texteffect be shown? + */ +void StartStopVehicle(const Vehicle *v, bool texteffect) +{ + assert(v->IsPrimaryVehicle()); + DoCommandP(v->tile, v->index, 0, _vehicle_command_translation_table[VCT_CMD_START_STOP][v->type], texteffect ? CcStartStopVehicle : NULL); +} + +/** Checks whether the vehicle may be refitted at the moment.*/ +static bool IsVehicleRefitable(const Vehicle *v) +{ + if (!v->IsStoppedInDepot()) return false; + + do { + if (IsEngineRefittable(v->engine_type)) return true; + } while (v->IsGroundVehicle() && (v = v->Next()) != NULL); + + return false; +} + +/** Window manager class for viewing a vehicle. */ +struct VehicleViewWindow : Window { +private: + /** Display planes available in the vehicle view window. */ + enum PlaneSelections { + SEL_DC_GOTO_DEPOT, ///< Display 'goto depot' button in #WID_VV_SELECT_DEPOT_CLONE stacked widget. + SEL_DC_CLONE, ///< Display 'clone vehicle' button in #WID_VV_SELECT_DEPOT_CLONE stacked widget. + + SEL_RT_REFIT, ///< Display 'refit' button in #WID_VV_SELECT_REFIT_TURN stacked widget. + SEL_RT_TURN_AROUND, ///< Display 'turn around' button in #WID_VV_SELECT_REFIT_TURN stacked widget. + + SEL_DC_BASEPLANE = SEL_DC_GOTO_DEPOT, ///< First plane of the #WID_VV_SELECT_DEPOT_CLONE stacked widget. + SEL_RT_BASEPLANE = SEL_RT_REFIT, ///< First plane of the #WID_VV_SELECT_REFIT_TURN stacked widget. + }; + + /** + * Display a plane in the window. + * @param plane Plane to show. + */ + void SelectPlane(PlaneSelections plane) + { + switch (plane) { + case SEL_DC_GOTO_DEPOT: + case SEL_DC_CLONE: + this->GetWidget(WID_VV_SELECT_DEPOT_CLONE)->SetDisplayedPlane(plane - SEL_DC_BASEPLANE); + break; + + case SEL_RT_REFIT: + case SEL_RT_TURN_AROUND: + this->GetWidget(WID_VV_SELECT_REFIT_TURN)->SetDisplayedPlane(plane - SEL_RT_BASEPLANE); + break; + + default: + NOT_REACHED(); + } + } + +public: + VehicleViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->CreateNestedTree(); + + /* Sprites for the 'send to depot' button indexed by vehicle type. */ + static const SpriteID vehicle_view_goto_depot_sprites[] = { + SPR_SEND_TRAIN_TODEPOT, + SPR_SEND_ROADVEH_TODEPOT, + SPR_SEND_SHIP_TODEPOT, + SPR_SEND_AIRCRAFT_TODEPOT, + }; + const Vehicle *v = Vehicle::Get(window_number); + this->GetWidget(WID_VV_GOTO_DEPOT)->widget_data = vehicle_view_goto_depot_sprites[v->type]; + + /* Sprites for the 'clone vehicle' button indexed by vehicle type. */ + static const SpriteID vehicle_view_clone_sprites[] = { + SPR_CLONE_TRAIN, + SPR_CLONE_ROADVEH, + SPR_CLONE_SHIP, + SPR_CLONE_AIRCRAFT, + }; + this->GetWidget(WID_VV_CLONE)->widget_data = vehicle_view_clone_sprites[v->type]; + + switch (v->type) { + case VEH_TRAIN: + this->GetWidget(WID_VV_TURN_AROUND)->tool_tip = STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP; + break; + + case VEH_ROAD: + break; + + case VEH_SHIP: + case VEH_AIRCRAFT: + this->SelectPlane(SEL_RT_REFIT); + break; + + default: NOT_REACHED(); + } + this->FinishInitNested(window_number); + this->owner = v->owner; + this->GetWidget(WID_VV_VIEWPORT)->InitializeViewport(this, this->window_number | (1 << 31), _vehicle_view_zoom_levels[v->type]); + + this->GetWidget(WID_VV_START_STOP)->tool_tip = STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP + v->type; + this->GetWidget(WID_VV_CENTER_MAIN_VIEW)->tool_tip = STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP + v->type; + this->GetWidget(WID_VV_REFIT)->tool_tip = STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP + v->type; + this->GetWidget(WID_VV_GOTO_DEPOT)->tool_tip = STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP + v->type; + this->GetWidget(WID_VV_SHOW_ORDERS)->tool_tip = STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP + v->type; + this->GetWidget(WID_VV_SHOW_DETAILS)->tool_tip = STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP + v->type; + this->GetWidget(WID_VV_CLONE)->tool_tip = STR_VEHICLE_VIEW_CLONE_TRAIN_INFO + v->type; + } + + ~VehicleViewWindow() + { + DeleteWindowById(WC_VEHICLE_ORDERS, this->window_number, false); + DeleteWindowById(WC_VEHICLE_REFIT, this->window_number, false); + DeleteWindowById(WC_VEHICLE_DETAILS, this->window_number, false); + DeleteWindowById(WC_VEHICLE_TIMETABLE, this->window_number, false); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + const Vehicle *v = Vehicle::Get(this->window_number); + switch (widget) { + case WID_VV_START_STOP: + size->height = max(size->height, max(GetSpriteSize(SPR_FLAG_VEH_STOPPED).height, GetSpriteSize(SPR_FLAG_VEH_RUNNING).height) + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM); + break; + + case WID_VV_FORCE_PROCEED: + if (v->type != VEH_TRAIN) { + size->height = 0; + size->width = 0; + } + break; + + case WID_VV_VIEWPORT: + size->width = VV_INITIAL_VIEWPORT_WIDTH; + size->height = (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT; + break; + } + } + + virtual void OnPaint() + { + const Vehicle *v = Vehicle::Get(this->window_number); + bool is_localcompany = v->owner == _local_company; + bool refitable_and_stopped_in_depot = IsVehicleRefitable(v); + + this->SetWidgetDisabledState(WID_VV_GOTO_DEPOT, !is_localcompany); + this->SetWidgetDisabledState(WID_VV_REFIT, !refitable_and_stopped_in_depot || !is_localcompany); + this->SetWidgetDisabledState(WID_VV_CLONE, !is_localcompany); + + if (v->type == VEH_TRAIN) { + this->SetWidgetLoweredState(WID_VV_FORCE_PROCEED, Train::From(v)->force_proceed == TFP_SIGNAL); + this->SetWidgetDisabledState(WID_VV_FORCE_PROCEED, !is_localcompany); + this->SetWidgetDisabledState(WID_VV_TURN_AROUND, !is_localcompany); + } + + this->DrawWidgets(); + } + + virtual void SetStringParameters(int widget) const + { + if (widget != WID_VV_CAPTION) return; + + const Vehicle *v = Vehicle::Get(this->window_number); + SetDParam(0, v->index); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_VV_START_STOP) return; + + const Vehicle *v = Vehicle::Get(this->window_number); + StringID str; + if (v->vehstatus & VS_CRASHED) { + str = STR_VEHICLE_STATUS_CRASHED; + } else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) { // check for aircraft necessary? + str = STR_VEHICLE_STATUS_BROKEN_DOWN; + } else if (v->vehstatus & VS_STOPPED) { + if (v->type == VEH_TRAIN) { + if (v->cur_speed == 0) { + if (Train::From(v)->gcache.cached_power == 0) { + str = STR_VEHICLE_STATUS_TRAIN_NO_POWER; + } else { + str = STR_VEHICLE_STATUS_STOPPED; + } + } else { + SetDParam(0, v->GetDisplaySpeed()); + str = STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL; + } + } else { // no train + str = STR_VEHICLE_STATUS_STOPPED; + } + } else if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_TRAIN_STUCK) && !v->current_order.IsType(OT_LOADING)) { + str = STR_VEHICLE_STATUS_TRAIN_STUCK; + } else if (v->type == VEH_AIRCRAFT && HasBit(Aircraft::From(v)->flags, VAF_DEST_TOO_FAR) && !v->current_order.IsType(OT_LOADING)) { + str = STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR; + } else { // vehicle is in a "normal" state, show current order + switch (v->current_order.GetType()) { + case OT_GOTO_STATION: { + SetDParam(0, v->current_order.GetDestination()); + SetDParam(1, v->GetDisplaySpeed()); + str = STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL; + break; + } + + case OT_GOTO_DEPOT: { + SetDParam(0, v->type); + SetDParam(1, v->current_order.GetDestination()); + SetDParam(2, v->GetDisplaySpeed()); + if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) { + /* This case *only* happens when multiple nearest depot orders + * follow each other (including an order list only one order: a + * nearest depot order) and there are no reachable depots. + * It is primarily to guard for the case that there is no + * depot with index 0, which would be used as fallback for + * evaluating the string in the status bar. */ + str = STR_EMPTY; + } else if (v->current_order.GetDepotActionType() & ODATFB_HALT) { + str = STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL; + } else { + str = STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL; + } + break; + } + + case OT_LOADING: + str = STR_VEHICLE_STATUS_LOADING_UNLOADING; + break; + + case OT_GOTO_WAYPOINT: { + assert(v->type == VEH_TRAIN || v->type == VEH_SHIP); + SetDParam(0, v->current_order.GetDestination()); + str = STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL; + SetDParam(1, v->GetDisplaySpeed()); + break; + } + + case OT_LEAVESTATION: + if (v->type != VEH_AIRCRAFT) { + str = STR_VEHICLE_STATUS_LEAVING; + break; + } + /* FALL THROUGH, if aircraft. Does this even happen? */ + + default: + if (v->GetNumManualOrders() == 0) { + str = STR_VEHICLE_STATUS_NO_ORDERS_VEL; + SetDParam(0, v->GetDisplaySpeed()); + } else { + str = STR_EMPTY; + } + break; + } + } + + /* Draw the flag plus orders. */ + bool rtl = (_current_text_dir == TD_RTL); + uint text_offset = max(GetSpriteSize(SPR_FLAG_VEH_STOPPED).width, GetSpriteSize(SPR_FLAG_VEH_RUNNING).width) + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; + int text_left = r.left + (rtl ? (uint)WD_FRAMERECT_LEFT : text_offset); + int text_right = r.right - (rtl ? text_offset : (uint)WD_FRAMERECT_RIGHT); + int image_left = (rtl ? text_right + 1 : r.left) + WD_IMGBTN_LEFT; + int image = ((v->vehstatus & VS_STOPPED) != 0) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING; + int lowered = this->IsWidgetLowered(WID_VV_START_STOP) ? 1 : 0; + DrawSprite(image, PAL_NONE, image_left + lowered, r.top + WD_IMGBTN_TOP + lowered); + DrawString(text_left + lowered, text_right + lowered, Center(r.top + lowered, r.bottom - r.top), str, TC_FROMSTRING, SA_HOR_CENTER); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + const Vehicle *v = Vehicle::Get(this->window_number); + + switch (widget) { + case WID_VV_START_STOP: // start stop + if (_ctrl_pressed) { + /* Scroll to current order destination */ + TileIndex tile = v->current_order.GetLocation(v); + if (tile != INVALID_TILE) ScrollMainWindowToTile(tile); + } else { + /* Start/Stop */ + StartStopVehicle(v, false); + } + break; + case WID_VV_CENTER_MAIN_VIEW: {// center main view + const Window *mainwindow = FindWindowById(WC_MAIN_WINDOW, 0); + /* code to allow the main window to 'follow' the vehicle if the ctrl key is pressed */ + if (_ctrl_pressed && mainwindow->viewport->zoom <= ZOOM_LVL_OUT_4X) { + mainwindow->viewport->follow_vehicle = v->index; + } else { + ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos); + } + break; + } + + case WID_VV_GOTO_DEPOT: // goto hangar + DoCommandP(v->tile, v->index | (_ctrl_pressed ? DEPOT_SERVICE : 0U), 0, GetCmdSendToDepot(v)); + break; + case WID_VV_REFIT: // refit + ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID, this); + break; + case WID_VV_SHOW_ORDERS: // show orders + if (_ctrl_pressed) { + ShowTimetableWindow(v); + } else { + ShowOrdersWindow(v); + } + break; + case WID_VV_SHOW_DETAILS: // show details + ShowVehicleDetailsWindow(v); + break; + case WID_VV_CLONE: // clone vehicle + /* Suppress the vehicle GUI when share-cloning. + * There is no point to it except for starting the vehicle. + * For starting the vehicle the player has to open the depot GUI, which is + * most likely already open, but is also visible in the vehicle viewport. */ + DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, + _vehicle_command_translation_table[VCT_CMD_CLONE_VEH][v->type], + _ctrl_pressed ? NULL : CcCloneVehicle); + break; + case WID_VV_TURN_AROUND: // turn around + assert(v->IsGroundVehicle()); + DoCommandP(v->tile, v->index, 0, + _vehicle_command_translation_table[VCT_CMD_TURN_AROUND][v->type]); + break; + case WID_VV_FORCE_PROCEED: // force proceed + assert(v->type == VEH_TRAIN); + DoCommandP(v->tile, v->index, 0, CMD_FORCE_TRAIN_PROCEED | CMD_MSG(STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL)); + break; + } + } + + virtual void OnResize() + { + if (this->viewport != NULL) { + NWidgetViewport *nvp = this->GetWidget(WID_VV_VIEWPORT); + nvp->UpdateViewportCoordinates(this); + } + } + + virtual void OnTick() + { + const Vehicle *v = Vehicle::Get(this->window_number); + bool veh_stopped = v->IsStoppedInDepot(); + + /* Widget WID_VV_GOTO_DEPOT must be hidden if the vehicle is already stopped in depot. + * Widget WID_VV_CLONE_VEH should then be shown, since cloning is allowed only while in depot and stopped. + */ + PlaneSelections plane = veh_stopped ? SEL_DC_CLONE : SEL_DC_GOTO_DEPOT; + NWidgetStacked *nwi = this->GetWidget(WID_VV_SELECT_DEPOT_CLONE); // Selection widget 'send to depot' / 'clone'. + if (nwi->shown_plane + SEL_DC_BASEPLANE != plane) { + this->SelectPlane(plane); + this->SetWidgetDirty(WID_VV_SELECT_DEPOT_CLONE); + } + /* The same system applies to widget WID_VV_REFIT_VEH and VVW_WIDGET_TURN_AROUND.*/ + if (v->IsGroundVehicle()) { + PlaneSelections plane = veh_stopped ? SEL_RT_REFIT : SEL_RT_TURN_AROUND; + NWidgetStacked *nwi = this->GetWidget(WID_VV_SELECT_REFIT_TURN); + if (nwi->shown_plane + SEL_RT_BASEPLANE != plane) { + this->SelectPlane(plane); + this->SetWidgetDirty(WID_VV_SELECT_REFIT_TURN); + } + } + } + + /** + * 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. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (data == VIWD_AUTOREPLACE) { + /* Autoreplace replaced the vehicle. + * Nothing to do for this window. */ + return; + } + } + + virtual bool IsNewGRFInspectable() const + { + return ::IsNewGRFInspectable(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number); + } + + virtual void ShowNewGRFInspectWindow() const + { + ::ShowNewGRFInspectWindow(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number); + } +}; + + +/** Shows the vehicle view window of the given vehicle. */ +void ShowVehicleViewWindow(const Vehicle *v) +{ + AllocateWindowDescFront((v->type == VEH_TRAIN) ? &_train_view_desc : &_vehicle_view_desc, v->index); +} + +/** + * Dispatch a "vehicle selected" event if any window waits for it. + * @param v selected vehicle; + * @return did any window accept vehicle selection? + */ +bool VehicleClicked(const Vehicle *v) +{ + assert(v != NULL); + if (!(_thd.place_mode & HT_VEHICLE)) return false; + + v = v->First(); + if (!v->IsPrimaryVehicle()) return false; + + return _thd.GetCallbackWnd()->OnVehicleSelect(v); +} + +void StopGlobalFollowVehicle(const Vehicle *v) +{ + Window *w = FindWindowById(WC_MAIN_WINDOW, 0); + if (w != NULL && w->viewport->follow_vehicle == v->index) { + ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos, true); // lock the main view on the vehicle's last position + w->viewport->follow_vehicle = INVALID_VEHICLE; + } +} + + +/** + * This is the Callback method after the construction attempt of a primary vehicle + * @param result indicates completion (or not) of the operation + * @param tile unused + * @param p1 unused + * @param p2 unused + */ +void CcBuildPrimaryVehicle(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + + const Vehicle *v = Vehicle::Get(_new_vehicle_id); + ShowVehicleViewWindow(v); +} + +/** + * Get the width of a vehicle (including all parts of the consist) in pixels. + * @param v Vehicle to get the width for. + * @return Width of the vehicle. + */ +int GetVehicleWidth(Vehicle *v, EngineImageType image_type) +{ + int vehicle_width = 0; + + switch (v->type) { + case VEH_TRAIN: + for (const Train *u = Train::From(v); u != NULL; u = u->Next()) { + vehicle_width += u->GetDisplayImageWidth(); + } + break; + + case VEH_ROAD: + for (const RoadVehicle *u = RoadVehicle::From(v); u != NULL; u = u->Next()) { + vehicle_width += u->GetDisplayImageWidth(); + } + break; + + default: + bool rtl = _current_text_dir == TD_RTL; + SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type); + const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); + vehicle_width = UnScaleByZoom(real_sprite->width, ZOOM_LVL_GUI); + + break; + } + + return vehicle_width; +} diff --git a/src/vehicle_gui.h.orig b/src/vehicle_gui.h.orig new file mode 100644 index 0000000000..83e098dcd9 --- /dev/null +++ b/src/vehicle_gui.h.orig @@ -0,0 +1,104 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file vehicle_gui.h Functions related to the vehicle's GUIs. */ + +#ifndef VEHICLE_GUI_H +#define VEHICLE_GUI_H + +#include "window_type.h" +#include "vehicle_type.h" +#include "order_type.h" +#include "station_type.h" +#include "engine_type.h" +#include "company_type.h" + +void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit = false); + +/** The tabs in the train details window */ +enum TrainDetailsWindowTabs { + TDW_TAB_CARGO = 0, ///< Tab with cargo carried by the vehicles + TDW_TAB_INFO, ///< Tab with name and value of the vehicles + TDW_TAB_CAPACITY, ///< Tab with cargo capacity of the vehicles + TDW_TAB_TOTALS, ///< Tab with sum of total cargo transported +}; + +/** Special values for vehicle-related windows for the data parameter of #InvalidateWindowData. */ +enum VehicleInvalidateWindowData { + VIWD_REMOVE_ALL_ORDERS = -1, ///< Removed / replaced all orders (after deleting / sharing). + VIWD_MODIFY_ORDERS = -2, ///< Other order modifications. + VIWD_CONSIST_CHANGED = -3, ///< Vehicle composition was changed. + VIWD_AUTOREPLACE = -4, ///< Autoreplace replaced the vehicle. +}; + +int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number); + +void DrawTrainImage(const Train *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip, VehicleID drag_dest = INVALID_VEHICLE); +void DrawRoadVehImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip = 0); +void DrawShipImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type); +void DrawAircraftImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type); + +void ShowBuildVehicleWindow(TileIndex tile, VehicleType type); + +uint ShowRefitOptionsList(int left, int right, int y, EngineID engine); +StringID GetCargoSubtypeText(const Vehicle *v); + +void ShowVehicleListWindow(const Vehicle *v); +void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type); +void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, StationID station); +void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, TileIndex depot_tile); + +/** + * Get the height of a single vehicle in the GUIs. + * @param type the vehicle type to look at + * @return the height + */ +static inline uint GetVehicleHeight(VehicleType type) +{ + return (type == VEH_TRAIN || type == VEH_ROAD) ? 14 : 24; +} + +int GetVehicleWidth(Vehicle *v, EngineImageType image_type); + +/** Dimensions of a cell in the purchase/depot windows. */ +struct VehicleCellSize { + uint height; ///< Vehicle cell height. + uint extend_left; ///< Extend of the cell to the left. + uint extend_right; ///< Extend of the cell to the right. +}; + +VehicleCellSize GetVehicleImageCellSize(VehicleType type, EngineImageType image_type); + +/** + * Get WindowClass for vehicle list of given vehicle type + * @param vt vehicle type to check + * @return corresponding window class + * @note works only for company buildable vehicle types + */ +static inline WindowClass GetWindowClassForVehicleType(VehicleType vt) +{ + switch (vt) { + default: NOT_REACHED(); + case VEH_TRAIN: return WC_TRAINS_LIST; + case VEH_ROAD: return WC_ROADVEH_LIST; + case VEH_SHIP: return WC_SHIPS_LIST; + case VEH_AIRCRAFT: return WC_AIRCRAFT_LIST; + } +} + +/* Unified window procedure */ +void ShowVehicleViewWindow(const Vehicle *v); +bool VehicleClicked(const Vehicle *v); +void StartStopVehicle(const Vehicle *v, bool texteffect); + +Vehicle *CheckClickOnVehicle(const struct ViewPort *vp, int x, int y); + +void DrawVehicleImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip); + +#endif /* VEHICLE_GUI_H */ diff --git a/src/video/sdl_v.cpp.orig b/src/video/sdl_v.cpp.orig new file mode 100644 index 0000000000..3d80153229 --- /dev/null +++ b/src/video/sdl_v.cpp.orig @@ -0,0 +1,868 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file sdl_v.cpp Implementation of the SDL video driver. */ + +#ifdef WITH_SDL + +#include "../stdafx.h" +#include "../openttd.h" +#include "../gfx_func.h" +#include "../sdl.h" +#include "../rev.h" +#include "../blitter/factory.hpp" +#include "../network/network.h" +#include "../thread/thread.h" +#include "../progress.h" +#include "../core/random_func.hpp" +#include "../core/math_func.hpp" +#include "../fileio_func.h" +#include "sdl_v.h" +#include +#ifdef __ANDROID__ +#include +#endif + +static FVideoDriver_SDL iFVideoDriver_SDL; + +static SDL_Surface *_sdl_screen; +static SDL_Surface *_sdl_realscreen; +static bool _all_modes; + +/** Whether the drawing is/may be done in a separate thread. */ +static bool _draw_threaded; +/** Thread used to 'draw' to the screen, i.e. push data to the screen. */ +static ThreadObject *_draw_thread = NULL; +/** Mutex to keep the access to the shared memory controlled. */ +static ThreadMutex *_draw_mutex = NULL; +/** Should we keep continue drawing? */ +static volatile bool _draw_continue; +static Palette _local_palette; + +#define MAX_DIRTY_RECTS 100 +static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS]; +static int _num_dirty_rects; +static int _use_hwpalette; +static int _requested_hwpalette; /* Did we request a HWPALETTE for the current video mode? */ + +void VideoDriver_SDL::MakeDirty(int left, int top, int width, int height) +{ + if (_num_dirty_rects < MAX_DIRTY_RECTS) { + _dirty_rects[_num_dirty_rects].x = left; + _dirty_rects[_num_dirty_rects].y = top; + _dirty_rects[_num_dirty_rects].w = width; + _dirty_rects[_num_dirty_rects].h = height; + } + _num_dirty_rects++; +} + +static void UpdatePalette(bool init = false) +{ + SDL_Color pal[256]; + + for (int i = 0; i != _local_palette.count_dirty; i++) { + pal[i].r = _local_palette.palette[_local_palette.first_dirty + i].r; + pal[i].g = _local_palette.palette[_local_palette.first_dirty + i].g; + pal[i].b = _local_palette.palette[_local_palette.first_dirty + i].b; + pal[i].unused = 0; + } + + SDL_CALL SDL_SetColors(_sdl_screen, pal, _local_palette.first_dirty, _local_palette.count_dirty); + + if (_sdl_screen != _sdl_realscreen && init) { + /* When using a shadow surface, also set our palette on the real screen. This lets SDL + * allocate as much colors (or approximations) as + * possible, instead of using only the default SDL + * palette. This allows us to get more colors exactly + * right and might allow using better approximations for + * other colors. + * + * Note that colors allocations are tried in-order, so + * this favors colors further up into the palette. Also + * note that if two colors from the same animation + * sequence are approximated using the same color, that + * animation will stop working. + * + * Since changing the system palette causes the colours + * to change right away, and allocations might + * drastically change, we can't use this for animation, + * since that could cause weird coloring between the + * palette change and the blitting below, so we only set + * the real palette during initialisation. + */ + SDL_CALL SDL_SetColors(_sdl_realscreen, pal, _local_palette.first_dirty, _local_palette.count_dirty); + } + + if (_sdl_screen != _sdl_realscreen && !init) { + /* We're not using real hardware palette, but are letting SDL + * approximate the palette during shadow -> screen copy. To + * change the palette, we need to recopy the entire screen. + * + * Note that this operation can slow down the rendering + * considerably, especially since changing the shadow + * palette will need the next blit to re-detect the + * best mapping of shadow palette colors to real palette + * colors from scratch. + */ + SDL_CALL SDL_BlitSurface(_sdl_screen, NULL, _sdl_realscreen, NULL); + SDL_CALL SDL_UpdateRect(_sdl_realscreen, 0, 0, 0, 0); + } +} + +static void InitPalette() +{ + _local_palette = _cur_palette; + _local_palette.first_dirty = 0; + _local_palette.count_dirty = 256; + UpdatePalette(true); +} + +static void CheckPaletteAnim() +{ + if (_cur_palette.count_dirty != 0) { + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + + switch (blitter->UsePaletteAnimation()) { + case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: + UpdatePalette(); + break; + + case Blitter::PALETTE_ANIMATION_BLITTER: + blitter->PaletteAnimate(_local_palette); + break; + + case Blitter::PALETTE_ANIMATION_NONE: + break; + + default: + NOT_REACHED(); + } + _cur_palette.count_dirty = 0; + } +} + +static void DrawSurfaceToScreen() +{ + int n = _num_dirty_rects; + if (n == 0) return; + + _num_dirty_rects = 0; + if (n > MAX_DIRTY_RECTS) { + if (_sdl_screen != _sdl_realscreen) { + SDL_CALL SDL_BlitSurface(_sdl_screen, NULL, _sdl_realscreen, NULL); + } + SDL_CALL SDL_UpdateRect(_sdl_realscreen, 0, 0, 0, 0); + } else { + if (_sdl_screen != _sdl_realscreen) { + for (int i = 0; i < n; i++) { + SDL_CALL SDL_BlitSurface(_sdl_screen, &_dirty_rects[i], _sdl_realscreen, &_dirty_rects[i]); + } + } + SDL_CALL SDL_UpdateRects(_sdl_realscreen, n, _dirty_rects); + } +} + +static void DrawSurfaceToScreenThread(void *) +{ + /* First tell the main thread we're started */ + _draw_mutex->BeginCritical(); + _draw_mutex->SendSignal(); + + /* Now wait for the first thing to draw! */ + _draw_mutex->WaitForSignal(); + + while (_draw_continue) { + CheckPaletteAnim(); + /* Then just draw and wait till we stop */ + DrawSurfaceToScreen(); + _draw_mutex->WaitForSignal(); + } + + _draw_mutex->EndCritical(); + _draw_thread->Exit(); +} + +static const Dimension _default_resolutions[] = { + { 640, 480}, + { 800, 600}, + {1024, 768}, + {1152, 864}, + {1280, 800}, + {1280, 960}, + {1280, 1024}, + {1400, 1050}, + {1600, 1200}, + {1680, 1050}, + {1920, 1200} +}; + +static void GetVideoModes() +{ + SDL_Rect **modes = SDL_CALL SDL_ListModes(NULL, SDL_SWSURFACE | SDL_FULLSCREEN); + if (modes == NULL) usererror("sdl: no modes available"); + + _all_modes = (SDL_CALL SDL_ListModes(NULL, SDL_SWSURFACE | (_fullscreen ? SDL_FULLSCREEN : 0)) == (void*)-1); + if (modes == (void*)-1) { + int n = 0; + for (uint i = 0; i < lengthof(_default_resolutions); i++) { + if (SDL_CALL SDL_VideoModeOK(_default_resolutions[i].width, _default_resolutions[i].height, 8, SDL_FULLSCREEN) != 0) { + _resolutions[n] = _default_resolutions[i]; + if (++n == lengthof(_resolutions)) break; + } + } + _num_resolutions = n; + } else { + int n = 0; + for (int i = 0; modes[i]; i++) { + uint w = modes[i]->w; + uint h = modes[i]->h; + int j; + for (j = 0; j < n; j++) { + if (_resolutions[j].width == w && _resolutions[j].height == h) break; + } + + if (j == n) { + _resolutions[j].width = w; + _resolutions[j].height = h; + if (++n == lengthof(_resolutions)) break; + } + } + _num_resolutions = n; + SortResolutions(_num_resolutions); + } +} + +static void GetAvailableVideoMode(uint *w, uint *h) +{ + /* All modes available? */ + if (_all_modes || _num_resolutions == 0) return; + + /* Is the wanted mode among the available modes? */ + for (int i = 0; i != _num_resolutions; i++) { + if (*w == _resolutions[i].width && *h == _resolutions[i].height) return; + } + + /* Use the closest possible resolution */ + int best = 0; + uint delta = Delta(_resolutions[0].width, *w) * Delta(_resolutions[0].height, *h); + for (int i = 1; i != _num_resolutions; ++i) { + uint newdelta = Delta(_resolutions[i].width, *w) * Delta(_resolutions[i].height, *h); + if (newdelta < delta) { + best = i; + delta = newdelta; + } + } + *w = _resolutions[best].width; + *h = _resolutions[best].height; +} + +#ifdef WIN32 +/* Let's redefine the LoadBMP macro with because we are dynamically + * loading SDL and need to 'SDL_CALL' all functions */ +#undef SDL_LoadBMP +#define SDL_LoadBMP(file) SDL_LoadBMP_RW(SDL_CALL SDL_RWFromFile(file, "rb"), 1) +#endif + +bool VideoDriver_SDL::CreateMainSurface(uint w, uint h) +{ + SDL_Surface *newscreen, *icon; + char caption[50]; + int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); + bool want_hwpalette; + + GetAvailableVideoMode(&w, &h); + + DEBUG(driver, 1, "SDL: using mode %ux%ux%d", w, h, bpp); + + if (bpp == 0) usererror("Can't use a blitter that blits 0 bpp for normal visuals"); + + char icon_path[MAX_PATH]; + if (FioFindFullPath(icon_path, lengthof(icon_path), BASESET_DIR, "openttd.32.bmp") != NULL) { + /* Give the application an icon */ + icon = SDL_CALL SDL_LoadBMP(icon_path); + if (icon != NULL) { + /* Get the colourkey, which will be magenta */ + uint32 rgbmap = SDL_CALL SDL_MapRGB(icon->format, 255, 0, 255); + + SDL_CALL SDL_SetColorKey(icon, SDL_SRCCOLORKEY, rgbmap); + SDL_CALL SDL_WM_SetIcon(icon, NULL); + SDL_CALL SDL_FreeSurface(icon); + } + } + + if (_use_hwpalette == 2) { + /* Default is to autodetect when to use SDL_HWPALETTE. + * In this case, SDL_HWPALETTE is only used for 8bpp + * blitters in fullscreen. + * + * When using an 8bpp blitter on a 8bpp system in + * windowed mode with SDL_HWPALETTE, OpenTTD will claim + * the system palette, making all other applications + * get the wrong colours. In this case, we're better of + * trying to approximate the colors we need using system + * colors, using a shadow surface (see below). + * + * On a 32bpp system, SDL_HWPALETTE is ignored, so it + * doesn't matter what we do. + * + * When using a 32bpp blitter on a 8bpp system, setting + * SDL_HWPALETTE messes up rendering (at least on X11), + * so we don't do that. In this case, SDL takes care of + * color approximation using its own shadow surface + * (which we can't force in 8bpp on 8bpp mode, + * unfortunately). + */ + want_hwpalette = (bpp == 8 && _fullscreen); + } else { + /* User specified a value manually */ + want_hwpalette = _use_hwpalette; + } + + if (want_hwpalette) DEBUG(driver, 1, "SDL: requesting hardware palete"); + + /* Free any previously allocated shadow surface */ + if (_sdl_screen != NULL && _sdl_screen != _sdl_realscreen) SDL_CALL SDL_FreeSurface(_sdl_screen); + + if (_sdl_realscreen != NULL) { + if (_requested_hwpalette != want_hwpalette) { + /* SDL (at least the X11 driver), reuses the + * same window and palette settings when the bpp + * (and a few flags) are the same. Since we need + * to hwpalette value to change (in particular + * when switching between fullscreen and + * windowed), we restart the entire video + * subsystem to force creating a new window. + */ + DEBUG(driver, 0, "SDL: Restarting SDL video subsystem, to force hwpalette change"); + SDL_CALL SDL_QuitSubSystem(SDL_INIT_VIDEO); + SDL_CALL SDL_InitSubSystem(SDL_INIT_VIDEO); + ClaimMousePointer(); + SetupKeyboard(); + } + } + /* Remember if we wanted a hwpalette. We can't reliably query + * SDL for the SDL_HWPALETTE flag, since it might get set even + * though we didn't ask for it (when SDL creates a shadow + * surface, for example). */ + _requested_hwpalette = want_hwpalette; + +#ifdef __ANDROID__ + SDL_Rect r; + r.h = SDL_ListModes(NULL, 0)[0]->h / 10; + r.w = r.h; + r.x = SDL_ListModes(NULL, 0)[0]->w - r.w; + r.y = SDL_ListModes(NULL, 0)[0]->h - r.h; + SDL_ANDROID_SetScreenKeyboardButtonPos(SDL_ANDROID_SCREENKEYBOARD_BUTTON_TEXT, &r); +#endif + + /* DO NOT CHANGE TO HWSURFACE, IT DOES NOT WORK */ + newscreen = SDL_CALL SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE | (want_hwpalette ? SDL_HWPALETTE : 0) | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE)); + if (newscreen == NULL) { + DEBUG(driver, 0, "SDL: Couldn't allocate a window to draw on"); + return false; + } + _sdl_realscreen = newscreen; + + if (bpp == 8 && (_sdl_realscreen->flags & SDL_HWPALETTE) != SDL_HWPALETTE) { + /* Using an 8bpp blitter, if we didn't get a hardware + * palette (most likely because we didn't request one, + * see above), we'll have to set up a shadow surface to + * render on. + * + * Our palette will be applied to this shadow surface, + * while the real screen surface will use the shared + * system palette (which will partly contain our colors, + * but most likely will not have enough free color cells + * for all of our colors). SDL can use these two + * palettes at blit time to approximate colors used in + * the shadow surface using system colors automatically. + * + * Note that when using an 8bpp blitter on a 32bpp + * system, SDL will create an internal shadow surface. + * This shadow surface will have SDL_HWPALLETE set, so + * we won't create a second shadow surface in this case. + */ + DEBUG(driver, 1, "SDL: using shadow surface"); + newscreen = SDL_CALL SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, bpp, 0, 0, 0, 0); + if (newscreen == NULL) { + DEBUG(driver, 0, "SDL: Couldn't allocate a shadow surface to draw on"); + return false; + } + } + + /* Delay drawing for this cycle; the next cycle will redraw the whole screen */ + _num_dirty_rects = 0; + + _screen.width = newscreen->w; + _screen.height = newscreen->h; + _screen.pitch = newscreen->pitch / (bpp / 8); + _screen.dst_ptr = newscreen->pixels; + _sdl_screen = newscreen; + + /* When in full screen, we will always have the mouse cursor + * within the window, even though SDL does not give us the + * appropriate event to know this. */ + if (_fullscreen) _cursor.in_window = true; + + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + blitter->PostResize(); + + InitPalette(); + switch (blitter->UsePaletteAnimation()) { + case Blitter::PALETTE_ANIMATION_NONE: + case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: + UpdatePalette(); + break; + + case Blitter::PALETTE_ANIMATION_BLITTER: + if (_video_driver != NULL) blitter->PaletteAnimate(_local_palette); + break; + + default: + NOT_REACHED(); + } + + snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision); + SDL_CALL SDL_WM_SetCaption(caption, caption); + + GameSizeChanged(); + + return true; +} + +bool VideoDriver_SDL::ClaimMousePointer() +{ + SDL_CALL SDL_ShowCursor(0); + return true; +} + +struct VkMapping { +#if SDL_VERSION_ATLEAST(1, 3, 0) + SDL_Keycode vk_from; +#else + uint16 vk_from; +#endif + byte vk_count; + byte map_to; +}; + +#define AS(x, z) {x, 0, z} +#define AM(x, y, z, w) {x, (byte)(y - x), z} + +static const VkMapping _vk_mapping[] = { + /* Pageup stuff + up/down */ + AM(SDLK_PAGEUP, SDLK_PAGEDOWN, WKC_PAGEUP, WKC_PAGEDOWN), + AS(SDLK_UP, WKC_UP), + AS(SDLK_DOWN, WKC_DOWN), + AS(SDLK_LEFT, WKC_LEFT), + AS(SDLK_RIGHT, WKC_RIGHT), + + AS(SDLK_HOME, WKC_HOME), + AS(SDLK_END, WKC_END), + + AS(SDLK_INSERT, WKC_INSERT), + AS(SDLK_DELETE, WKC_DELETE), + + /* Map letters & digits */ + AM(SDLK_a, SDLK_z, 'A', 'Z'), + AM(SDLK_0, SDLK_9, '0', '9'), + + AS(SDLK_ESCAPE, WKC_ESC), + AS(SDLK_PAUSE, WKC_PAUSE), + AS(SDLK_BACKSPACE, WKC_BACKSPACE), + + AS(SDLK_SPACE, WKC_SPACE), + AS(SDLK_RETURN, WKC_RETURN), + AS(SDLK_TAB, WKC_TAB), + + /* Function keys */ + AM(SDLK_F1, SDLK_F12, WKC_F1, WKC_F12), + + /* Numeric part. */ + AM(SDLK_KP0, SDLK_KP9, '0', '9'), + AS(SDLK_KP_DIVIDE, WKC_NUM_DIV), + AS(SDLK_KP_MULTIPLY, WKC_NUM_MUL), + AS(SDLK_KP_MINUS, WKC_NUM_MINUS), + AS(SDLK_KP_PLUS, WKC_NUM_PLUS), + AS(SDLK_KP_ENTER, WKC_NUM_ENTER), + AS(SDLK_KP_PERIOD, WKC_NUM_DECIMAL), + + /* Other non-letter keys */ + AS(SDLK_SLASH, WKC_SLASH), + AS(SDLK_SEMICOLON, WKC_SEMICOLON), + AS(SDLK_EQUALS, WKC_EQUALS), + AS(SDLK_LEFTBRACKET, WKC_L_BRACKET), + AS(SDLK_BACKSLASH, WKC_BACKSLASH), + AS(SDLK_RIGHTBRACKET, WKC_R_BRACKET), + + AS(SDLK_QUOTE, WKC_SINGLEQUOTE), + AS(SDLK_COMMA, WKC_COMMA), + AS(SDLK_MINUS, WKC_MINUS), + AS(SDLK_PERIOD, WKC_PERIOD) +}; + +static uint ConvertSdlKeyIntoMy(SDL_keysym *sym, WChar *character) +{ + const VkMapping *map; + uint key = 0; + + for (map = _vk_mapping; map != endof(_vk_mapping); ++map) { + if ((uint)(sym->sym - map->vk_from) <= map->vk_count) { + key = sym->sym - map->vk_from + map->map_to; + break; + } + } + + /* check scancode for BACKQUOTE key, because we want the key left of "1", not anything else (on non-US keyboards) */ +#if defined(WIN32) || defined(__OS2__) + if (sym->scancode == 41) key = WKC_BACKQUOTE; +#elif defined(__APPLE__) + if (sym->scancode == 10) key = WKC_BACKQUOTE; +#elif defined(__MORPHOS__) + if (sym->scancode == 0) key = WKC_BACKQUOTE; // yes, that key is code '0' under MorphOS :) +#elif defined(__BEOS__) + if (sym->scancode == 17) key = WKC_BACKQUOTE; +#elif defined(__SVR4) && defined(__sun) + if (sym->scancode == 60) key = WKC_BACKQUOTE; + if (sym->scancode == 49) key = WKC_BACKSPACE; +#elif defined(__sgi__) + if (sym->scancode == 22) key = WKC_BACKQUOTE; +#elif defined(__ANDROID__) + if (sym->scancode == SDLK_BACKQUOTE) key = WKC_BACKQUOTE; +#else + if (sym->scancode == 49) key = WKC_BACKQUOTE; +#endif + + /* META are the command keys on mac */ + if (sym->mod & KMOD_META) key |= WKC_META; + if (sym->mod & KMOD_SHIFT) key |= WKC_SHIFT; + if (sym->mod & KMOD_CTRL) key |= WKC_CTRL; + if (sym->mod & KMOD_ALT) key |= WKC_ALT; + + *character = sym->unicode; + return key; +} + +int VideoDriver_SDL::PollEvent() +{ + SDL_Event ev; + + if (!SDL_CALL SDL_PollEvent(&ev)) return -2; + + switch (ev.type) { + case SDL_MOUSEMOTION: + if (_cursor.fix_at) { + int dx = ev.motion.x - _cursor.pos.x; + int dy = ev.motion.y - _cursor.pos.y; + if (dx != 0 || dy != 0) { + _cursor.delta.x = dx; + _cursor.delta.y = dy; + SDL_CALL SDL_WarpMouse(_cursor.pos.x, _cursor.pos.y); + } + } else { + _cursor.delta.x = ev.motion.x - _cursor.pos.x; + _cursor.delta.y = ev.motion.y - _cursor.pos.y; + _cursor.pos.x = ev.motion.x; + _cursor.pos.y = ev.motion.y; + _cursor.dirty = true; + } + HandleMouseEvents(); + break; + + case SDL_MOUSEBUTTONDOWN: + if (_rightclick_emulate && SDL_CALL SDL_GetModState() & KMOD_CTRL) { + ev.button.button = SDL_BUTTON_RIGHT; + } + + switch (ev.button.button) { + case SDL_BUTTON_LEFT: + _left_button_down = true; + break; + + case SDL_BUTTON_RIGHT: + _right_button_down = true; + _right_button_clicked = true; + break; + + case SDL_BUTTON_WHEELUP: _cursor.wheel--; break; + case SDL_BUTTON_WHEELDOWN: _cursor.wheel++; break; + + default: break; + } + HandleMouseEvents(); + break; + + case SDL_MOUSEBUTTONUP: + if (_rightclick_emulate) { + _right_button_down = false; + _left_button_down = false; + _left_button_clicked = false; + } else if (ev.button.button == SDL_BUTTON_LEFT) { + _left_button_down = false; + _left_button_clicked = false; + } else if (ev.button.button == SDL_BUTTON_RIGHT) { + _right_button_down = false; + } + HandleMouseEvents(); + break; +#ifndef __ANDROID__ + case SDL_ACTIVEEVENT: + if (!(ev.active.state & SDL_APPMOUSEFOCUS)) break; + + if (ev.active.gain) { // mouse entered the window, enable cursor + _cursor.in_window = true; + } else { + UndrawMouseCursor(); // mouse left the window, undraw cursor + _cursor.in_window = false; + } + break; +#endif /* not __ANDROID__ */ + case SDL_QUIT: + HandleExitGameRequest(); + break; + + case SDL_KEYDOWN: // Toggle full-screen on ALT + ENTER/F + if ((ev.key.keysym.mod & (KMOD_ALT | KMOD_META)) && + (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_f)) { + ToggleFullScreen(!_fullscreen); + } else { + WChar character; + uint keycode = ConvertSdlKeyIntoMy(&ev.key.keysym, &character); + HandleKeypress(keycode, character); + } + break; +#ifndef __ANDROID__ + case SDL_VIDEORESIZE: { + int w = max(ev.resize.w, 64); + int h = max(ev.resize.h, 64); + CreateMainSurface(w, h); + break; + } +#endif /* not __ANDROID__ */ + case SDL_VIDEOEXPOSE: { + /* Force a redraw of the entire screen. Note + * that SDL 1.2 seems to do this automatically + * in most cases, but 1.3 / 2.0 does not. */ + _num_dirty_rects = MAX_DIRTY_RECTS + 1; + break; + } + } + return -1; +} + +const char *VideoDriver_SDL::Start(const char * const *parm) +{ + char buf[30]; + _use_hwpalette = GetDriverParamInt(parm, "hw_palette", 2); + + const char *s = SdlOpen(SDL_INIT_VIDEO); + if (s != NULL) return s; + + GetVideoModes(); + if (!CreateMainSurface(_cur_resolution.width, _cur_resolution.height)) { + return SDL_CALL SDL_GetError(); + } + + SDL_CALL SDL_VideoDriverName(buf, sizeof buf); + DEBUG(driver, 1, "SDL: using driver '%s'", buf); + + MarkWholeScreenDirty(); + SetupKeyboard(); + + _draw_threaded = GetDriverParam(parm, "no_threads") == NULL && GetDriverParam(parm, "no_thread") == NULL; +#ifdef __ANDROID__ + _draw_threaded = false; +#endif + + return NULL; +} + +void VideoDriver_SDL::SetupKeyboard() +{ + SDL_CALL SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + SDL_CALL SDL_EnableUNICODE(1); +} + +void VideoDriver_SDL::Stop() +{ + SdlClose(SDL_INIT_VIDEO); +} + +void VideoDriver_SDL::MainLoop() +{ + uint32 cur_ticks = SDL_CALL SDL_GetTicks(); + uint32 last_cur_ticks = cur_ticks; + uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; + uint32 mod; + int numkeys; + Uint8 *keys; + + CheckPaletteAnim(); + + if (_draw_threaded) { + /* Initialise the mutex first, because that's the thing we *need* + * directly in the newly created thread. */ + _draw_mutex = ThreadMutex::New(); + if (_draw_mutex == NULL) { + _draw_threaded = false; + } else { + _draw_mutex->BeginCritical(); + _draw_continue = true; + + _draw_threaded = ThreadObject::New(&DrawSurfaceToScreenThread, NULL, &_draw_thread); + + /* Free the mutex if we won't be able to use it. */ + if (!_draw_threaded) { + _draw_mutex->EndCritical(); + delete _draw_mutex; + _draw_mutex = NULL; + } else { + /* Wait till the draw mutex has started itself. */ + _draw_mutex->WaitForSignal(); + } + } + } + + DEBUG(driver, 1, "SDL: using %sthreads", _draw_threaded ? "" : "no "); + + for (;;) { + uint32 prev_cur_ticks = cur_ticks; // to check for wrapping + InteractiveRandom(); // randomness + + while (PollEvent() == -1) {} + if (_exit_game) break; + + mod = SDL_CALL SDL_GetModState(); +#if SDL_VERSION_ATLEAST(1, 3, 0) + keys = SDL_CALL SDL_GetKeyboardState(&numkeys); +#else + keys = SDL_CALL SDL_GetKeyState(&numkeys); +#endif +#if defined(_DEBUG) + if (_shift_pressed) +#else + /* Speedup when pressing tab, except when using ALT+TAB + * to switch to another application */ +#if SDL_VERSION_ATLEAST(1, 3, 0) + if (keys[SDL_SCANCODE_TAB] && (mod & KMOD_ALT) == 0) +#else + if (keys[SDLK_TAB] && (mod & KMOD_ALT) == 0) +#endif /* SDL_VERSION_ATLEAST(1, 3, 0) */ +#endif /* defined(_DEBUG) */ + { + if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2; + } else if (_fast_forward & 2) { + _fast_forward = 0; + } + + cur_ticks = SDL_CALL SDL_GetTicks(); + if (cur_ticks >= next_tick || (_fast_forward && !_pause_mode) || cur_ticks < prev_cur_ticks) { + _realtime_tick += cur_ticks - last_cur_ticks; + last_cur_ticks = cur_ticks; + next_tick = cur_ticks + MILLISECONDS_PER_TICK; + + bool old_ctrl_pressed = _ctrl_pressed; + + _ctrl_pressed = !!(mod & KMOD_CTRL); + _shift_pressed = !!(mod & KMOD_SHIFT); + + /* determine which directional keys are down */ + _dirkeys = +#if SDL_VERSION_ATLEAST(1, 3, 0) + (keys[SDL_SCANCODE_LEFT] ? 1 : 0) | + (keys[SDL_SCANCODE_UP] ? 2 : 0) | + (keys[SDL_SCANCODE_RIGHT] ? 4 : 0) | + (keys[SDL_SCANCODE_DOWN] ? 8 : 0); +#else + (keys[SDLK_LEFT] ? 1 : 0) | + (keys[SDLK_UP] ? 2 : 0) | + (keys[SDLK_RIGHT] ? 4 : 0) | + (keys[SDLK_DOWN] ? 8 : 0); +#endif + if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged(); + + /* The gameloop is the part that can run asynchronously. The rest + * except sleeping can't. */ + if (_draw_mutex != NULL) _draw_mutex->EndCritical(); + + GameLoop(); + + if (_draw_mutex != NULL) _draw_mutex->BeginCritical(); + + UpdateWindows(); + _local_palette = _cur_palette; + } else { + /* Release the thread while sleeping */ + if (_draw_mutex != NULL) _draw_mutex->EndCritical(); + CSleep(1); + if (_draw_mutex != NULL) _draw_mutex->BeginCritical(); + + NetworkDrawChatMessage(); + DrawMouseCursor(); + } + + /* End of the critical part. */ + if (_draw_mutex != NULL && !HasModalProgress()) { + _draw_mutex->SendSignal(); + } else { + /* Oh, we didn't have threads, then just draw unthreaded */ + CheckPaletteAnim(); + DrawSurfaceToScreen(); + } + } + + if (_draw_mutex != NULL) { + _draw_continue = false; + /* Sending signal if there is no thread blocked + * is very valid and results in noop */ + _draw_mutex->SendSignal(); + _draw_mutex->EndCritical(); + _draw_thread->Join(); + + delete _draw_mutex; + delete _draw_thread; + + _draw_mutex = NULL; + _draw_thread = NULL; + } +} + +bool VideoDriver_SDL::ChangeResolution(int w, int h) +{ + if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + bool ret = CreateMainSurface(w, h); + if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); + return ret; +} + +bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen) +{ + if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + _fullscreen = fullscreen; + GetVideoModes(); // get the list of available video modes + bool ret = _num_resolutions != 0 && CreateMainSurface(_cur_resolution.width, _cur_resolution.height); + + if (!ret) { + /* switching resolution failed, put back full_screen to original status */ + _fullscreen ^= true; + } + + if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); + return ret; +} + +bool VideoDriver_SDL::AfterBlitterChange() +{ + if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + bool ret = CreateMainSurface(_screen.width, _screen.height); + if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); + return ret; +} + +#endif /* WITH_SDL */ diff --git a/src/viewport.cpp.orig b/src/viewport.cpp.orig new file mode 100644 index 0000000000..f6585d4779 --- /dev/null +++ b/src/viewport.cpp.orig @@ -0,0 +1,3012 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** + * @file viewport.cpp Handling of all viewports. + * + * \verbatim + * The in-game coordinate system looks like this * + * * + * ^ Z * + * | * + * | * + * | * + * | * + * / \ * + * / \ * + * / \ * + * / \ * + * X < > Y * + * \endverbatim + */ + +#include "stdafx.h" +#include "landscape.h" +#include "viewport_func.h" +#include "station_base.h" +#include "waypoint_base.h" +#include "town.h" +#include "signs_base.h" +#include "signs_func.h" +#include "vehicle_base.h" +#include "vehicle_gui.h" +#include "blitter/factory.hpp" +#include "strings_func.h" +#include "zoom_func.h" +#include "vehicle_func.h" +#include "company_func.h" +#include "waypoint_func.h" +#include "window_func.h" +#include "tilehighlight_func.h" +#include "window_gui.h" +#include "linkgraph/linkgraph_gui.h" +#include "viewport_sprite_sorter.h" + +#include "table/strings.h" +#include "table/palettes.h" + +Point _tile_fract_coords; + +struct StringSpriteToDraw { + StringID string; + Colours colour; + int32 x; + int32 y; + uint64 params[2]; + uint16 width; +}; + +struct TileSpriteToDraw { + SpriteID image; + PaletteID pal; + const SubSprite *sub; ///< only draw a rectangular part of the sprite + int32 x; ///< screen X coordinate of sprite + int32 y; ///< screen Y coordinate of sprite +}; + +struct ChildScreenSpriteToDraw { + SpriteID image; + PaletteID pal; + const SubSprite *sub; ///< only draw a rectangular part of the sprite + int32 x; + int32 y; + int next; ///< next child to draw (-1 at the end) +}; + +/** Enumeration of multi-part foundations */ +enum FoundationPart { + FOUNDATION_PART_NONE = 0xFF, ///< Neither foundation nor groundsprite drawn yet. + FOUNDATION_PART_NORMAL = 0, ///< First part (normal foundation or no foundation) + FOUNDATION_PART_HALFTILE = 1, ///< Second part (halftile foundation) + FOUNDATION_PART_END +}; + +/** + * Mode of "sprite combining" + * @see StartSpriteCombine + */ +enum SpriteCombineMode { + SPRITE_COMBINE_NONE, ///< Every #AddSortableSpriteToDraw start its own bounding box + SPRITE_COMBINE_PENDING, ///< %Sprite combining will start with the next unclipped sprite. + SPRITE_COMBINE_ACTIVE, ///< %Sprite combining is active. #AddSortableSpriteToDraw outputs child sprites. +}; + +typedef SmallVector TileSpriteToDrawVector; +typedef SmallVector StringSpriteToDrawVector; +typedef SmallVector ParentSpriteToDrawVector; +typedef SmallVector ChildScreenSpriteToDrawVector; + +/** Data structure storing rendering information */ +struct ViewportDrawer { + DrawPixelInfo dpi; + + StringSpriteToDrawVector string_sprites_to_draw; + TileSpriteToDrawVector tile_sprites_to_draw; + ParentSpriteToDrawVector parent_sprites_to_draw; + ParentSpriteToSortVector parent_sprites_to_sort; ///< Parent sprite pointer array used for sorting + ChildScreenSpriteToDrawVector child_screen_sprites_to_draw; + + int *last_child; + + SpriteCombineMode combine_sprites; ///< Current mode of "sprite combining". @see StartSpriteCombine + + int foundation[FOUNDATION_PART_END]; ///< Foundation sprites (index into parent_sprites_to_draw). + FoundationPart foundation_part; ///< Currently active foundation for ground sprite drawing. + int *last_foundation_child[FOUNDATION_PART_END]; ///< Tail of ChildSprite list of the foundations. (index into child_screen_sprites_to_draw) + Point foundation_offset[FOUNDATION_PART_END]; ///< Pixel offset for ground sprites on the foundations. +}; + +static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom); + +static ViewportDrawer _vd; + +TileHighlightData _thd; +static TileInfo *_cur_ti; +bool _draw_bounding_boxes = false; +bool _draw_dirty_blocks = false; +uint _dirty_block_colour = 0; +static VpSpriteSorter _vp_sprite_sorter = NULL; + +static Point MapXYZToViewport(const ViewPort *vp, int x, int y, int z) +{ + Point p = RemapCoords(x, y, z); + p.x -= vp->virtual_width / 2; + p.y -= vp->virtual_height / 2; + return p; +} + +void DeleteWindowViewport(Window *w) +{ + if (w->viewport == NULL) return; + + delete w->viewport->overlay; + free(w->viewport); + w->viewport = NULL; +} + +/** + * Initialize viewport of the window for use. + * @param w Window to use/display the viewport in + * @param x Offset of left edge of viewport with respect to left edge window \a w + * @param y Offset of top edge of viewport with respect to top edge window \a w + * @param width Width of the viewport + * @param height Height of the viewport + * @param follow_flags Flags controlling the viewport. + * - If bit 31 is set, the lower 20 bits are the vehicle that the viewport should follow. + * - If bit 31 is clear, it is a #TileIndex. + * @param zoom Zoomlevel to display + */ +void InitializeWindowViewport(Window *w, int x, int y, + int width, int height, uint32 follow_flags, ZoomLevel zoom) +{ + assert(w->viewport == NULL); + + ViewportData *vp = CallocT(1); + + vp->left = x + w->left; + vp->top = y + w->top; + vp->width = width; + vp->height = height; + + vp->zoom = static_cast(Clamp(zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max)); + + vp->virtual_width = ScaleByZoom(width, zoom); + vp->virtual_height = ScaleByZoom(height, zoom); + + Point pt; + + if (follow_flags & 0x80000000) { + const Vehicle *veh; + + vp->follow_vehicle = (VehicleID)(follow_flags & 0xFFFFF); + veh = Vehicle::Get(vp->follow_vehicle); + pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos); + } else { + uint x = TileX(follow_flags) * TILE_SIZE; + uint y = TileY(follow_flags) * TILE_SIZE; + + vp->follow_vehicle = INVALID_VEHICLE; + pt = MapXYZToViewport(vp, x, y, GetSlopePixelZ(x, y)); + } + + vp->scrollpos_x = pt.x; + vp->scrollpos_y = pt.y; + vp->dest_scrollpos_x = pt.x; + vp->dest_scrollpos_y = pt.y; + + vp->overlay = NULL; + + w->viewport = vp; + vp->virtual_left = 0;//pt.x; + vp->virtual_top = 0;//pt.y; +} + +static Point _vp_move_offs; + +static void DoSetViewportPosition(const Window *w, int left, int top, int width, int height) +{ + FOR_ALL_WINDOWS_FROM_BACK_FROM(w, w) { + if (left + width > w->left && + w->left + w->width > left && + top + height > w->top && + w->top + w->height > top) { + + if (left < w->left) { + DoSetViewportPosition(w, left, top, w->left - left, height); + DoSetViewportPosition(w, left + (w->left - left), top, width - (w->left - left), height); + return; + } + + if (left + width > w->left + w->width) { + DoSetViewportPosition(w, left, top, (w->left + w->width - left), height); + DoSetViewportPosition(w, left + (w->left + w->width - left), top, width - (w->left + w->width - left), height); + return; + } + + if (top < w->top) { + DoSetViewportPosition(w, left, top, width, (w->top - top)); + DoSetViewportPosition(w, left, top + (w->top - top), width, height - (w->top - top)); + return; + } + + if (top + height > w->top + w->height) { + DoSetViewportPosition(w, left, top, width, (w->top + w->height - top)); + DoSetViewportPosition(w, left, top + (w->top + w->height - top), width, height - (w->top + w->height - top)); + return; + } + + return; + } + } + + { + int xo = _vp_move_offs.x; + int yo = _vp_move_offs.y; + + if (abs(xo) >= width || abs(yo) >= height) { + /* fully_outside */ + RedrawScreenRect(left, top, left + width, top + height); + return; + } + + GfxScroll(left, top, width, height, xo, yo); + + if (xo > 0) { + RedrawScreenRect(left, top, xo + left, top + height); + left += xo; + width -= xo; + } else if (xo < 0) { + RedrawScreenRect(left + width + xo, top, left + width, top + height); + width += xo; + } + + if (yo > 0) { + RedrawScreenRect(left, top, width + left, top + yo); + } else if (yo < 0) { + RedrawScreenRect(left, top + height + yo, width + left, top + height); + } + } +} + +static void SetViewportPosition(Window *w, int x, int y) +{ + ViewPort *vp = w->viewport; + int old_left = vp->virtual_left; + int old_top = vp->virtual_top; + int i; + int left, top, width, height; + + vp->virtual_left = x; + vp->virtual_top = y; + + /* Viewport is bound to its left top corner, so it must be rounded down (UnScaleByZoomLower) + * else glitch described in FS#1412 will happen (offset by 1 pixel with zoom level > NORMAL) + */ + old_left = UnScaleByZoomLower(old_left, vp->zoom); + old_top = UnScaleByZoomLower(old_top, vp->zoom); + x = UnScaleByZoomLower(x, vp->zoom); + y = UnScaleByZoomLower(y, vp->zoom); + + old_left -= x; + old_top -= y; + + if (old_top == 0 && old_left == 0) return; + + _vp_move_offs.x = old_left; + _vp_move_offs.y = old_top; + + left = vp->left; + top = vp->top; + width = vp->width; + height = vp->height; + + if (left < 0) { + width += left; + left = 0; + } + + i = left + width - _screen.width; + if (i >= 0) width -= i; + + if (width > 0) { + if (top < 0) { + height += top; + top = 0; + } + + i = top + height - _screen.height; + if (i >= 0) height -= i; + + if (height > 0) DoSetViewportPosition(w->z_front, left, top, width, height); + } +} + +/** + * Is a xy position inside the viewport of the window? + * @param w Window to examine its viewport + * @param x X coordinate of the xy position + * @param y Y coordinate of the xy position + * @return Pointer to the viewport if the xy position is in the viewport of the window, + * otherwise \c NULL is returned. + */ +ViewPort *IsPtInWindowViewport(const Window *w, int x, int y) +{ + ViewPort *vp = w->viewport; + + if (vp != NULL && + IsInsideMM(x, vp->left, vp->left + vp->width) && + IsInsideMM(y, vp->top, vp->top + vp->height)) + return vp; + + return NULL; +} + +/** + * Translate screen coordinate in a viewport to a tile coordinate + * @param vp Viewport that contains the (\a x, \a y) screen coordinate + * @param x Screen x coordinate + * @param y Screen y coordinate + * @return Tile coordinate + */ +static Point TranslateXYToTileCoord(const ViewPort *vp, int x, int y) +{ + Point pt; + int a, b; + int z; + + if ( (uint)(x -= vp->left) >= (uint)vp->width || + (uint)(y -= vp->top) >= (uint)vp->height) { + Point pt = {-1, -1}; + return pt; + } + + x = (ScaleByZoom(x, vp->zoom) + vp->virtual_left) >> (2 + ZOOM_LVL_SHIFT); + y = (ScaleByZoom(y, vp->zoom) + vp->virtual_top) >> (1 + ZOOM_LVL_SHIFT); + + a = y - x; + b = y + x; + + /* we need to move variables in to the valid range, as the + * GetTileZoomCenterWindow() function can call here with invalid x and/or y, + * when the user tries to zoom out along the sides of the map */ + a = Clamp(a, -4 * (int)TILE_SIZE, (int)(MapMaxX() * TILE_SIZE) - 1); + b = Clamp(b, -4 * (int)TILE_SIZE, (int)(MapMaxY() * TILE_SIZE) - 1); + + /* (a, b) is the X/Y-world coordinate that belongs to (x,y) if the landscape would be completely flat on height 0. + * Now find the Z-world coordinate by fix point iteration. + * This is a bit tricky because the tile height is non-continuous at foundations. + * The clicked point should be approached from the back, otherwise there are regions that are not clickable. + * (FOUNDATION_HALFTILE_LOWER on SLOPE_STEEP_S hides north halftile completely) + * So give it a z-malus of 4 in the first iterations. + */ + z = 0; + + int min_coord = _settings_game.construction.freeform_edges ? TILE_SIZE : 0; + + for (int i = 0; i < 5; i++) z = GetSlopePixelZ(Clamp(a + max(z, 4) - 4, min_coord, MapMaxX() * TILE_SIZE - 1), Clamp(b + max(z, 4) - 4, min_coord, MapMaxY() * TILE_SIZE - 1)) / 2; + for (int malus = 3; malus > 0; malus--) z = GetSlopePixelZ(Clamp(a + max(z, malus) - malus, min_coord, MapMaxX() * TILE_SIZE - 1), Clamp(b + max(z, malus) - malus, min_coord, MapMaxY() * TILE_SIZE - 1)) / 2; + for (int i = 0; i < 5; i++) z = GetSlopePixelZ(Clamp(a + z, min_coord, MapMaxX() * TILE_SIZE - 1), Clamp(b + z, min_coord, MapMaxY() * TILE_SIZE - 1)) / 2; + + pt.x = Clamp(a + z, min_coord, MapMaxX() * TILE_SIZE - 1); + pt.y = Clamp(b + z, min_coord, MapMaxY() * TILE_SIZE - 1); + + return pt; +} + +/* When used for zooming, check area below current coordinates (x,y) + * and return the tile of the zoomed out/in position (zoom_x, zoom_y) + * when you just want the tile, make x = zoom_x and y = zoom_y */ +static Point GetTileFromScreenXY(int x, int y, int zoom_x, int zoom_y) +{ + Window *w; + ViewPort *vp; + Point pt; + + if ( (w = FindWindowFromPt(x, y)) != NULL && + (vp = IsPtInWindowViewport(w, x, y)) != NULL) + return TranslateXYToTileCoord(vp, zoom_x, zoom_y); + + pt.y = pt.x = -1; + return pt; +} + +Point GetTileBelowCursor() +{ + return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, _cursor.pos.x, _cursor.pos.y); +} + + +Point GetTileZoomCenterWindow(bool in, Window * w) +{ + int x, y; + ViewPort *vp = w->viewport; + + if (in) { + x = ((_cursor.pos.x - vp->left) >> 1) + (vp->width >> 2); + y = ((_cursor.pos.y - vp->top) >> 1) + (vp->height >> 2); + } else { + x = vp->width - (_cursor.pos.x - vp->left); + y = vp->height - (_cursor.pos.y - vp->top); + } + /* Get the tile below the cursor and center on the zoomed-out center */ + return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp->left, y + vp->top); +} + +/** + * Update the status of the zoom-buttons according to the zoom-level + * of the viewport. This will update their status and invalidate accordingly + * @param w Window pointer to the window that has the zoom buttons + * @param vp pointer to the viewport whose zoom-level the buttons represent + * @param widget_zoom_in widget index for window with zoom-in button + * @param widget_zoom_out widget index for window with zoom-out button + */ +void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out) +{ + w->SetWidgetDisabledState(widget_zoom_in, vp->zoom <= _settings_client.gui.zoom_min); + w->SetWidgetDirty(widget_zoom_in); + + w->SetWidgetDisabledState(widget_zoom_out, vp->zoom >= _settings_client.gui.zoom_max); + w->SetWidgetDirty(widget_zoom_out); +} + +/** + * Schedules a tile sprite for drawing. + * + * @param image the image to draw. + * @param pal the provided palette. + * @param x position x (world coordinates) of the sprite. + * @param y position y (world coordinates) of the sprite. + * @param z position z (world coordinates) of the sprite. + * @param sub Only draw a part of the sprite. + * @param extra_offs_x Pixel X offset for the sprite position. + * @param extra_offs_y Pixel Y offset for the sprite position. + */ +static void AddTileSpriteToDraw(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub = NULL, int extra_offs_x = 0, int extra_offs_y = 0) +{ + assert((image & SPRITE_MASK) < MAX_SPRITES); + + TileSpriteToDraw *ts = _vd.tile_sprites_to_draw.Append(); + ts->image = image; + ts->pal = pal; + ts->sub = sub; + Point pt = RemapCoords(x, y, z); + ts->x = pt.x + extra_offs_x; + ts->y = pt.y + extra_offs_y; +} + +/** + * Adds a child sprite to the active foundation. + * + * The pixel offset of the sprite relative to the ParentSprite is the sum of the offset passed to OffsetGroundSprite() and extra_offs_?. + * + * @param image the image to draw. + * @param pal the provided palette. + * @param sub Only draw a part of the sprite. + * @param foundation_part Foundation part. + * @param extra_offs_x Pixel X offset for the sprite position. + * @param extra_offs_y Pixel Y offset for the sprite position. + */ +static void AddChildSpriteToFoundation(SpriteID image, PaletteID pal, const SubSprite *sub, FoundationPart foundation_part, int extra_offs_x, int extra_offs_y) +{ + assert(IsInsideMM(foundation_part, 0, FOUNDATION_PART_END)); + assert(_vd.foundation[foundation_part] != -1); + Point offs = _vd.foundation_offset[foundation_part]; + + /* Change the active ChildSprite list to the one of the foundation */ + int *old_child = _vd.last_child; + _vd.last_child = _vd.last_foundation_child[foundation_part]; + + AddChildSpriteScreen(image, pal, offs.x + extra_offs_x, offs.y + extra_offs_y, false, sub, false); + + /* Switch back to last ChildSprite list */ + _vd.last_child = old_child; +} + +/** + * Draws a ground sprite at a specific world-coordinate relative to the current tile. + * If the current tile is drawn on top of a foundation the sprite is added as child sprite to the "foundation"-ParentSprite. + * + * @param image the image to draw. + * @param pal the provided palette. + * @param x position x (world coordinates) of the sprite relative to current tile. + * @param y position y (world coordinates) of the sprite relative to current tile. + * @param z position z (world coordinates) of the sprite relative to current tile. + * @param sub Only draw a part of the sprite. + * @param extra_offs_x Pixel X offset for the sprite position. + * @param extra_offs_y Pixel Y offset for the sprite position. + */ +void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub, int extra_offs_x, int extra_offs_y) +{ + /* Switch to first foundation part, if no foundation was drawn */ + if (_vd.foundation_part == FOUNDATION_PART_NONE) _vd.foundation_part = FOUNDATION_PART_NORMAL; + + if (_vd.foundation[_vd.foundation_part] != -1) { + Point pt = RemapCoords(x, y, z); + AddChildSpriteToFoundation(image, pal, sub, _vd.foundation_part, pt.x + extra_offs_x * ZOOM_LVL_BASE, pt.y + extra_offs_y * ZOOM_LVL_BASE); + } else { + AddTileSpriteToDraw(image, pal, _cur_ti->x + x, _cur_ti->y + y, _cur_ti->z + z, sub, extra_offs_x * ZOOM_LVL_BASE, extra_offs_y * ZOOM_LVL_BASE); + } +} + +/** + * Draws a ground sprite for the current tile. + * If the current tile is drawn on top of a foundation the sprite is added as child sprite to the "foundation"-ParentSprite. + * + * @param image the image to draw. + * @param pal the provided palette. + * @param sub Only draw a part of the sprite. + * @param extra_offs_x Pixel X offset for the sprite position. + * @param extra_offs_y Pixel Y offset for the sprite position. + */ +void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y) +{ + DrawGroundSpriteAt(image, pal, 0, 0, 0, sub, extra_offs_x, extra_offs_y); +} + +/** + * Called when a foundation has been drawn for the current tile. + * Successive ground sprites for the current tile will be drawn as child sprites of the "foundation"-ParentSprite, not as TileSprites. + * + * @param x sprite x-offset (screen coordinates) of ground sprites relative to the "foundation"-ParentSprite. + * @param y sprite y-offset (screen coordinates) of ground sprites relative to the "foundation"-ParentSprite. + */ +void OffsetGroundSprite(int x, int y) +{ + /* Switch to next foundation part */ + switch (_vd.foundation_part) { + case FOUNDATION_PART_NONE: + _vd.foundation_part = FOUNDATION_PART_NORMAL; + break; + case FOUNDATION_PART_NORMAL: + _vd.foundation_part = FOUNDATION_PART_HALFTILE; + break; + default: NOT_REACHED(); + } + + /* _vd.last_child == NULL if foundation sprite was clipped by the viewport bounds */ + if (_vd.last_child != NULL) _vd.foundation[_vd.foundation_part] = _vd.parent_sprites_to_draw.Length() - 1; + + _vd.foundation_offset[_vd.foundation_part].x = x * ZOOM_LVL_BASE; + _vd.foundation_offset[_vd.foundation_part].y = y * ZOOM_LVL_BASE; + _vd.last_foundation_child[_vd.foundation_part] = _vd.last_child; +} + +/** + * Adds a child sprite to a parent sprite. + * In contrast to "AddChildSpriteScreen()" the sprite position is in world coordinates + * + * @param image the image to draw. + * @param pal the provided palette. + * @param x position x of the sprite. + * @param y position y of the sprite. + * @param z position z of the sprite. + * @param sub Only draw a part of the sprite. + */ +static void AddCombinedSprite(SpriteID image, PaletteID pal, int x, int y, int z, const SubSprite *sub) +{ + Point pt = RemapCoords(x, y, z); + const Sprite *spr = GetSprite(image & SPRITE_MASK, ST_NORMAL); + + if (pt.x + spr->x_offs >= _vd.dpi.left + _vd.dpi.width || + pt.x + spr->x_offs + spr->width <= _vd.dpi.left || + pt.y + spr->y_offs >= _vd.dpi.top + _vd.dpi.height || + pt.y + spr->y_offs + spr->height <= _vd.dpi.top) + return; + + const ParentSpriteToDraw *pstd = _vd.parent_sprites_to_draw.End() - 1; + AddChildSpriteScreen(image, pal, pt.x - pstd->left, pt.y - pstd->top, false, sub, false); +} + +/** + * Draw a (transparent) sprite at given coordinates with a given bounding box. + * The bounding box extends from (x + bb_offset_x, y + bb_offset_y, z + bb_offset_z) to (x + w - 1, y + h - 1, z + dz - 1), both corners included. + * Bounding boxes with bb_offset_x == w or bb_offset_y == h or bb_offset_z == dz are allowed and produce thin slices. + * + * @note Bounding boxes are normally specified with bb_offset_x = bb_offset_y = bb_offset_z = 0. The extent of the bounding box in negative direction is + * defined by the sprite offset in the grf file. + * However if modifying the sprite offsets is not suitable (e.g. when using existing graphics), the bounding box can be tuned by bb_offset. + * + * @pre w >= bb_offset_x, h >= bb_offset_y, dz >= bb_offset_z. Else w, h or dz are ignored. + * + * @param image the image to combine and draw, + * @param pal the provided palette, + * @param x position X (world) of the sprite, + * @param y position Y (world) of the sprite, + * @param w bounding box extent towards positive X (world), + * @param h bounding box extent towards positive Y (world), + * @param dz bounding box extent towards positive Z (world), + * @param z position Z (world) of the sprite, + * @param transparent if true, switch the palette between the provided palette and the transparent palette, + * @param bb_offset_x bounding box extent towards negative X (world), + * @param bb_offset_y bounding box extent towards negative Y (world), + * @param bb_offset_z bounding box extent towards negative Z (world) + * @param sub Only draw a part of the sprite. + */ +void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub) +{ + int32 left, right, top, bottom; + + assert((image & SPRITE_MASK) < MAX_SPRITES); + + /* make the sprites transparent with the right palette */ + if (transparent) { + SetBit(image, PALETTE_MODIFIER_TRANSPARENT); + pal = PALETTE_TO_TRANSPARENT; + } + + if (_vd.combine_sprites == SPRITE_COMBINE_ACTIVE) { + AddCombinedSprite(image, pal, x, y, z, sub); + return; + } + + _vd.last_child = NULL; + + Point pt = RemapCoords(x, y, z); + int tmp_left, tmp_top, tmp_x = pt.x, tmp_y = pt.y; + + /* Compute screen extents of sprite */ + if (image == SPR_EMPTY_BOUNDING_BOX) { + left = tmp_left = RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x; + right = RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1; + top = tmp_top = RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y; + bottom = RemapCoords(x + w , y + h , z + bb_offset_z).y + 1; + } else { + const Sprite *spr = GetSprite(image & SPRITE_MASK, ST_NORMAL); + left = tmp_left = (pt.x += spr->x_offs); + right = (pt.x + spr->width ); + top = tmp_top = (pt.y += spr->y_offs); + bottom = (pt.y + spr->height); + } + + if (_draw_bounding_boxes && (image != SPR_EMPTY_BOUNDING_BOX)) { + /* Compute maximal extents of sprite and its bounding box */ + left = min(left , RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x); + right = max(right , RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1); + top = min(top , RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y); + bottom = max(bottom, RemapCoords(x + w , y + h , z + bb_offset_z).y + 1); + } + + /* Do not add the sprite to the viewport, if it is outside */ + if (left >= _vd.dpi.left + _vd.dpi.width || + right <= _vd.dpi.left || + top >= _vd.dpi.top + _vd.dpi.height || + bottom <= _vd.dpi.top) { + return; + } + + ParentSpriteToDraw *ps = _vd.parent_sprites_to_draw.Append(); + ps->x = tmp_x; + ps->y = tmp_y; + + ps->left = tmp_left; + ps->top = tmp_top; + + ps->image = image; + ps->pal = pal; + ps->sub = sub; + ps->xmin = x + bb_offset_x; + ps->xmax = x + max(bb_offset_x, w) - 1; + + ps->ymin = y + bb_offset_y; + ps->ymax = y + max(bb_offset_y, h) - 1; + + ps->zmin = z + bb_offset_z; + ps->zmax = z + max(bb_offset_z, dz) - 1; + + ps->comparison_done = false; + ps->first_child = -1; + + _vd.last_child = &ps->first_child; + + if (_vd.combine_sprites == SPRITE_COMBINE_PENDING) _vd.combine_sprites = SPRITE_COMBINE_ACTIVE; +} + +/** + * Starts a block of sprites, which are "combined" into a single bounding box. + * + * Subsequent calls to #AddSortableSpriteToDraw will be drawn into the same bounding box. + * That is: The first sprite that is not clipped by the viewport defines the bounding box, and + * the following sprites will be child sprites to that one. + * + * That implies: + * - The drawing order is definite. No other sprites will be sorted between those of the block. + * - You have to provide a valid bounding box for all sprites, + * as you won't know which one is the first non-clipped one. + * Preferable you use the same bounding box for all. + * - You cannot use #AddChildSpriteScreen inside the block, as its result will be indefinite. + * + * The block is terminated by #EndSpriteCombine. + * + * You cannot nest "combined" blocks. + */ +void StartSpriteCombine() +{ + assert(_vd.combine_sprites == SPRITE_COMBINE_NONE); + _vd.combine_sprites = SPRITE_COMBINE_PENDING; +} + +/** + * Terminates a block of sprites started by #StartSpriteCombine. + * Take a look there for details. + */ +void EndSpriteCombine() +{ + assert(_vd.combine_sprites != SPRITE_COMBINE_NONE); + _vd.combine_sprites = SPRITE_COMBINE_NONE; +} + +/** + * Check if the parameter "check" is inside the interval between + * begin and end, including both begin and end. + * @note Whether \c begin or \c end is the biggest does not matter. + * This method will account for that. + * @param begin The begin of the interval. + * @param end The end of the interval. + * @param check The value to check. + */ +static bool IsInRangeInclusive(int begin, int end, int check) +{ + if (begin > end) Swap(begin, end); + return begin <= check && check <= end; +} + +/** + * Checks whether a point is inside the selected a diagonal rectangle given by _thd.size and _thd.pos + * @param x The x coordinate of the point to be checked. + * @param y The y coordinate of the point to be checked. + * @return True if the point is inside the rectangle, else false. + */ +bool IsInsideRotatedRectangle(int x, int y) +{ + int dist_a = (_thd.size.x + _thd.size.y); // Rotated coordinate system for selected rectangle. + int dist_b = (_thd.size.x - _thd.size.y); // We don't have to divide by 2. It's all relative! + int a = ((x - _thd.pos.x) + (y - _thd.pos.y)); // Rotated coordinate system for the point under scrutiny. + int b = ((x - _thd.pos.x) - (y - _thd.pos.y)); + + /* Check if a and b are between 0 and dist_a or dist_b respectively. */ + return IsInRangeInclusive(dist_a, 0, a) && IsInRangeInclusive(dist_b, 0, b); +} + +/** + * Add a child sprite to a parent sprite. + * + * @param image the image to draw. + * @param pal the provided palette. + * @param x sprite x-offset (screen coordinates) relative to parent sprite. + * @param y sprite y-offset (screen coordinates) relative to parent sprite. + * @param transparent if true, switch the palette between the provided palette and the transparent palette, + * @param sub Only draw a part of the sprite. + */ +void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent, const SubSprite *sub, bool scale) +{ + assert((image & SPRITE_MASK) < MAX_SPRITES); + + /* If the ParentSprite was clipped by the viewport bounds, do not draw the ChildSprites either */ + if (_vd.last_child == NULL) return; + + /* make the sprites transparent with the right palette */ + if (transparent) { + SetBit(image, PALETTE_MODIFIER_TRANSPARENT); + pal = PALETTE_TO_TRANSPARENT; + } + + *_vd.last_child = _vd.child_screen_sprites_to_draw.Length(); + + ChildScreenSpriteToDraw *cs = _vd.child_screen_sprites_to_draw.Append(); + cs->image = image; + cs->pal = pal; + cs->sub = sub; + cs->x = scale ? x * ZOOM_LVL_BASE : x; + cs->y = scale ? y * ZOOM_LVL_BASE : y; + cs->next = -1; + + /* Append the sprite to the active ChildSprite list. + * If the active ParentSprite is a foundation, update last_foundation_child as well. + * Note: ChildSprites of foundations are NOT sequential in the vector, as selection sprites are added at last. */ + if (_vd.last_foundation_child[0] == _vd.last_child) _vd.last_foundation_child[0] = &cs->next; + if (_vd.last_foundation_child[1] == _vd.last_child) _vd.last_foundation_child[1] = &cs->next; + _vd.last_child = &cs->next; +} + +static void AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2, Colours colour, uint16 width) +{ + assert(width != 0); + StringSpriteToDraw *ss = _vd.string_sprites_to_draw.Append(); + ss->string = string; + ss->x = x; + ss->y = y; + ss->params[0] = params_1; + ss->params[1] = params_2; + ss->width = width; + ss->colour = colour; +} + + +/** + * Draws sprites between ground sprite and everything above. + * + * The sprite is either drawn as TileSprite or as ChildSprite of the active foundation. + * + * @param image the image to draw. + * @param pal the provided palette. + * @param ti TileInfo Tile that is being drawn + * @param z_offset Z offset relative to the groundsprite. Only used for the sprite position, not for sprite sorting. + * @param foundation_part Foundation part the sprite belongs to. + */ +static void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part) +{ + /* FIXME: This is not totally valid for some autorail highlights that extend over the edges of the tile. */ + if (_vd.foundation[foundation_part] == -1) { + /* draw on real ground */ + AddTileSpriteToDraw(image, pal, ti->x, ti->y, ti->z + z_offset); + } else { + /* draw on top of foundation */ + AddChildSpriteToFoundation(image, pal, NULL, foundation_part, 0, -z_offset * ZOOM_LVL_BASE); + } +} + +/** + * Draws a selection rectangle on a tile. + * + * @param ti TileInfo Tile that is being drawn + * @param pal Palette to apply. + */ +static void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal) +{ + if (!IsValidTile(ti->tile)) return; + + SpriteID sel; + if (IsHalftileSlope(ti->tileh)) { + Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); + SpriteID sel2 = SPR_HALFTILE_SELECTION_FLAT + halftile_corner; + DrawSelectionSprite(sel2, pal, ti, 7 + TILE_HEIGHT, FOUNDATION_PART_HALFTILE); + + Corner opposite_corner = OppositeCorner(halftile_corner); + if (IsSteepSlope(ti->tileh)) { + sel = SPR_HALFTILE_SELECTION_DOWN; + } else { + sel = ((ti->tileh & SlopeWithOneCornerRaised(opposite_corner)) != 0 ? SPR_HALFTILE_SELECTION_UP : SPR_HALFTILE_SELECTION_FLAT); + } + sel += opposite_corner; + } else { + sel = SPR_SELECT_TILE + SlopeToSpriteOffset(ti->tileh); + } + DrawSelectionSprite(sel, pal, ti, 7, FOUNDATION_PART_NORMAL); +} + +static bool IsPartOfAutoLine(int px, int py) +{ + px -= _thd.selstart.x; + py -= _thd.selstart.y; + + if ((_thd.drawstyle & HT_DRAG_MASK) != HT_LINE) return false; + + switch (_thd.drawstyle & HT_DIR_MASK) { + case HT_DIR_X: return py == 0; // x direction + case HT_DIR_Y: return px == 0; // y direction + case HT_DIR_HU: return px == -py || px == -py - 16; // horizontal upper + case HT_DIR_HL: return px == -py || px == -py + 16; // horizontal lower + case HT_DIR_VL: return px == py || px == py + 16; // vertical left + case HT_DIR_VR: return px == py || px == py - 16; // vertical right + default: + NOT_REACHED(); + } +} + +/* [direction][side] */ +static const HighLightStyle _autorail_type[6][2] = { + { HT_DIR_X, HT_DIR_X }, + { HT_DIR_Y, HT_DIR_Y }, + { HT_DIR_HU, HT_DIR_HL }, + { HT_DIR_HL, HT_DIR_HU }, + { HT_DIR_VL, HT_DIR_VR }, + { HT_DIR_VR, HT_DIR_VL } +}; + +#include "table/autorail.h" + +/** + * Draws autorail highlights. + * + * @param *ti TileInfo Tile that is being drawn + * @param autorail_type Offset into _AutorailTilehSprite[][] + */ +static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type) +{ + SpriteID image; + PaletteID pal; + int offset; + + FoundationPart foundation_part = FOUNDATION_PART_NORMAL; + Slope autorail_tileh = RemoveHalftileSlope(ti->tileh); + if (IsHalftileSlope(ti->tileh)) { + static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U }; + Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); + if (autorail_type != _lower_rail[halftile_corner]) { + foundation_part = FOUNDATION_PART_HALFTILE; + /* Here we draw the highlights of the "three-corners-raised"-slope. That looks ok to me. */ + autorail_tileh = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner)); + } + } + + offset = _AutorailTilehSprite[autorail_tileh][autorail_type]; + if (offset >= 0) { + image = SPR_AUTORAIL_BASE + offset; + pal = PAL_NONE; + } else { + image = SPR_AUTORAIL_BASE - offset; + pal = PALETTE_SEL_TILE_RED; + } + + DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part); +} + +/** + * Checks if the specified tile is selected and if so draws selection using correct selectionstyle. + * @param *ti TileInfo Tile that is being drawn + */ +static void DrawTileSelection(const TileInfo *ti) +{ + /* Draw a red error square? */ + bool is_redsq = _thd.redsq == ti->tile; + if (is_redsq) DrawTileSelectionRect(ti, PALETTE_TILE_RED_PULSATING); + + /* No tile selection active? */ + if ((_thd.drawstyle & HT_DRAG_MASK) == HT_NONE) return; + + if (_thd.diagonal) { // We're drawing a 45 degrees rotated (diagonal) rectangle + if (IsInsideRotatedRectangle((int)ti->x, (int)ti->y)) goto draw_inner; + return; + } + + /* Inside the inner area? */ + if (IsInsideBS(ti->x, _thd.pos.x, _thd.size.x) && + IsInsideBS(ti->y, _thd.pos.y, _thd.size.y)) { +draw_inner: + if (_thd.drawstyle & HT_RECT) { + if (!is_redsq) DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE); + } else if (_thd.drawstyle & HT_POINT) { + /* Figure out the Z coordinate for the single dot. */ + int z = 0; + FoundationPart foundation_part = FOUNDATION_PART_NORMAL; + if (ti->tileh & SLOPE_N) { + z += TILE_HEIGHT; + if (RemoveHalftileSlope(ti->tileh) == SLOPE_STEEP_N) z += TILE_HEIGHT; + } + if (IsHalftileSlope(ti->tileh)) { + Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); + if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z += TILE_HEIGHT; + if (halftile_corner != CORNER_S) { + foundation_part = FOUNDATION_PART_HALFTILE; + if (IsSteepSlope(ti->tileh)) z -= TILE_HEIGHT; + } + } + DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z, foundation_part); + } else if (_thd.drawstyle & HT_RAIL) { + /* autorail highlight piece under cursor */ + HighLightStyle type = _thd.drawstyle & HT_DIR_MASK; + assert(type < HT_DIR_END); + DrawAutorailSelection(ti, _autorail_type[type][0]); + } else if (IsPartOfAutoLine(ti->x, ti->y)) { + /* autorail highlighting long line */ + HighLightStyle dir = _thd.drawstyle & HT_DIR_MASK; + uint side; + + if (dir == HT_DIR_X || dir == HT_DIR_Y) { + side = 0; + } else { + TileIndex start = TileVirtXY(_thd.selstart.x, _thd.selstart.y); + side = Delta(Delta(TileX(start), TileX(ti->tile)), Delta(TileY(start), TileY(ti->tile))); + } + + DrawAutorailSelection(ti, _autorail_type[dir][side]); + } + return; + } + + /* Check if it's inside the outer area? */ + if (!is_redsq && _thd.outersize.x > 0 && + IsInsideBS(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) && + IsInsideBS(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) { + /* Draw a blue rect. */ + DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE); + return; + } +} + +static void ViewportAddLandscape() +{ + int x, y, width, height; + TileInfo ti; + bool direction; + + _cur_ti = &ti; + + /* Transform into tile coordinates and round to closest full tile */ + x = ((_vd.dpi.top >> (1 + ZOOM_LVL_SHIFT)) - (_vd.dpi.left >> (2 + ZOOM_LVL_SHIFT))) & ~TILE_UNIT_MASK; + y = ((_vd.dpi.top >> (1 + ZOOM_LVL_SHIFT)) + (_vd.dpi.left >> (2 + ZOOM_LVL_SHIFT)) - TILE_SIZE) & ~TILE_UNIT_MASK; + + /* determine size of area */ + { + Point pt = RemapCoords(x, y, 241); + width = (_vd.dpi.left + _vd.dpi.width - pt.x + 96 * ZOOM_LVL_BASE - 1) >> (6 + ZOOM_LVL_SHIFT); + height = (_vd.dpi.top + _vd.dpi.height - pt.y) >> (5 + ZOOM_LVL_SHIFT) << 1; + } + + assert(width > 0); + assert(height > 0); + + direction = false; + + do { + int width_cur = width; + uint x_cur = x; + uint y_cur = y; + + do { + TileType tt = MP_VOID; + + ti.x = x_cur; + ti.y = y_cur; + + ti.z = 0; + + ti.tileh = SLOPE_FLAT; + ti.tile = INVALID_TILE; + + if (x_cur < MapMaxX() * TILE_SIZE && + y_cur < MapMaxY() * TILE_SIZE) { + TileIndex tile = TileVirtXY(x_cur, y_cur); + + if (!_settings_game.construction.freeform_edges || (TileX(tile) != 0 && TileY(tile) != 0)) { + if (x_cur == ((int)MapMaxX() - 1) * TILE_SIZE || y_cur == ((int)MapMaxY() - 1) * TILE_SIZE) { + uint maxh = max(TileHeight(tile), 1); + for (uint h = 0; h < maxh; h++) { + AddTileSpriteToDraw(SPR_SHADOW_CELL, PAL_NONE, ti.x, ti.y, h * TILE_HEIGHT); + } + } + + ti.tile = tile; + ti.tileh = GetTilePixelSlope(tile, &ti.z); + tt = GetTileType(tile); + } + } + + _vd.foundation_part = FOUNDATION_PART_NONE; + _vd.foundation[0] = -1; + _vd.foundation[1] = -1; + _vd.last_foundation_child[0] = NULL; + _vd.last_foundation_child[1] = NULL; + + _tile_type_procs[tt]->draw_tile_proc(&ti); + + if ((x_cur == (int)MapMaxX() * TILE_SIZE && IsInsideMM(y_cur, 0, MapMaxY() * TILE_SIZE + 1)) || + (y_cur == (int)MapMaxY() * TILE_SIZE && IsInsideMM(x_cur, 0, MapMaxX() * TILE_SIZE + 1))) { + TileIndex tile = TileVirtXY(x_cur, y_cur); + ti.tile = tile; + ti.tileh = GetTilePixelSlope(tile, &ti.z); + tt = GetTileType(tile); + } + if (ti.tile != INVALID_TILE) DrawTileSelection(&ti); + + y_cur += 0x10; + x_cur -= 0x10; + } while (--width_cur); + + if ((direction ^= 1) != 0) { + y += 0x10; + } else { + x += 0x10; + } + } while (--height); +} + +/** + * Add a string to draw in the viewport + * @param dpi current viewport area + * @param small_from Zoomlevel from when the small font should be used + * @param sign sign position and dimension + * @param string_normal String for normal and 2x zoom level + * @param string_small String for 4x and 8x zoom level + * @param string_small_shadow Shadow string for 4x and 8x zoom level; or #STR_NULL if no shadow + * @param colour colour of the sign background; or INVALID_COLOUR if transparent + */ +void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, uint64 params_1, uint64 params_2, Colours colour) +{ + bool small = dpi->zoom >= small_from; + + int left = dpi->left; + int top = dpi->top; + int right = left + dpi->width; + int bottom = top + dpi->height; + + int sign_height = ScaleByZoom(VPSM_TOP + FONT_HEIGHT_NORMAL + VPSM_BOTTOM, dpi->zoom); + int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, dpi->zoom); + + if (bottom < sign->top || + top > sign->top + sign_height || + right < sign->center - sign_half_width || + left > sign->center + sign_half_width) { + return; + } + + if (!small) { + AddStringToDraw(sign->center - sign_half_width, sign->top, string_normal, params_1, params_2, colour, sign->width_normal); + } else { + int shadow_offset = 0; + if (string_small_shadow != STR_NULL) { + shadow_offset = 4; + AddStringToDraw(sign->center - sign_half_width + shadow_offset, sign->top, string_small_shadow, params_1, params_2, INVALID_COLOUR, sign->width_small); + } + AddStringToDraw(sign->center - sign_half_width, sign->top - shadow_offset, string_small, params_1, params_2, + colour, sign->width_small | 0x8000); + } +} + +static void ViewportAddTownNames(DrawPixelInfo *dpi) +{ + if (!HasBit(_display_opt, DO_SHOW_TOWN_NAMES) || _game_mode == GM_MENU) return; + + const Town *t; + FOR_ALL_TOWNS(t) { + ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &t->cache.sign, + _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN, + STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK, + t->index, t->cache.population); + } +} + + +static void ViewportAddStationNames(DrawPixelInfo *dpi) +{ + if (!(HasBit(_display_opt, DO_SHOW_STATION_NAMES) || HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)) || _game_mode == GM_MENU) return; + + const BaseStation *st; + FOR_ALL_BASE_STATIONS(st) { + /* Check whether the base station is a station or a waypoint */ + bool is_station = Station::IsExpected(st); + + /* Don't draw if the display options are disabled */ + if (!HasBit(_display_opt, is_station ? DO_SHOW_STATION_NAMES : DO_SHOW_WAYPOINT_NAMES)) continue; + + /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */ + if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != st->owner && st->owner != OWNER_NONE) continue; + + ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &st->sign, + is_station ? STR_VIEWPORT_STATION : STR_VIEWPORT_WAYPOINT, + (is_station ? STR_VIEWPORT_STATION : STR_VIEWPORT_WAYPOINT) + 1, STR_NULL, + st->index, st->facilities, (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]); + } +} + + +static void ViewportAddSigns(DrawPixelInfo *dpi) +{ + /* Signs are turned off or are invisible */ + if (!HasBit(_display_opt, DO_SHOW_SIGNS) || IsInvisibilitySet(TO_SIGNS)) return; + + const Sign *si; + FOR_ALL_SIGNS(si) { + /* Don't draw if sign is owned by another company and competitor signs should be hidden. + * Note: It is intentional that also signs owned by OWNER_NONE are hidden. Bankrupt + * companies can leave OWNER_NONE signs after them. */ + if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != si->owner && si->owner != OWNER_DEITY) continue; + + ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &si->sign, + STR_WHITE_SIGN, + (IsTransparencySet(TO_SIGNS) || si->owner == OWNER_DEITY) ? STR_VIEWPORT_SIGN_SMALL_WHITE : STR_VIEWPORT_SIGN_SMALL_BLACK, STR_NULL, + si->index, 0, (si->owner == OWNER_NONE) ? COLOUR_GREY : (si->owner == OWNER_DEITY ? INVALID_COLOUR : _company_colours[si->owner])); + } +} + +/** + * Update the position of the viewport sign. + * @param center the (preferred) center of the viewport sign + * @param top the new top of the sign + * @param str the string to show in the sign + */ +void ViewportSign::UpdatePosition(int center, int top, StringID str) +{ + if (this->width_normal != 0) this->MarkDirty(); + + this->top = top; + + char buffer[DRAW_STRING_BUFFER]; + + GetString(buffer, str, lastof(buffer)); + this->width_normal = VPSM_LEFT + Align(GetStringBoundingBox(buffer).width, 2) + VPSM_RIGHT; + this->center = center; + + /* zoomed out version */ + this->width_small = VPSM_LEFT + Align(GetStringBoundingBox(buffer, FS_SMALL).width, 2) + VPSM_RIGHT; + + this->MarkDirty(); +} + +/** + * Mark the sign dirty in all viewports. + * @param maxzoom Maximum %ZoomLevel at which the text is visible. + * + * @ingroup dirty + */ +void ViewportSign::MarkDirty(ZoomLevel maxzoom) const +{ + Rect zoomlevels[ZOOM_LVL_COUNT]; + + for (ZoomLevel zoom = ZOOM_LVL_BEGIN; zoom != ZOOM_LVL_END; zoom++) { + /* FIXME: This doesn't switch to width_small when appropriate. */ + zoomlevels[zoom].left = this->center - ScaleByZoom(this->width_normal / 2 + 1, zoom); + zoomlevels[zoom].top = this->top - ScaleByZoom(1, zoom); + zoomlevels[zoom].right = this->center + ScaleByZoom(this->width_normal / 2 + 1, zoom); + zoomlevels[zoom].bottom = this->top + ScaleByZoom(VPSM_TOP + FONT_HEIGHT_NORMAL + VPSM_BOTTOM + 1, zoom); + } + + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + ViewPort *vp = w->viewport; + if (vp != NULL && vp->zoom <= maxzoom) { + assert(vp->width != 0); + Rect &zl = zoomlevels[vp->zoom]; + MarkViewportDirty(vp, zl.left, zl.top, zl.right, zl.bottom); + } + } +} + +static void ViewportDrawTileSprites(const TileSpriteToDrawVector *tstdv) +{ + const TileSpriteToDraw *tsend = tstdv->End(); + for (const TileSpriteToDraw *ts = tstdv->Begin(); ts != tsend; ++ts) { + DrawSpriteViewport(ts->image, ts->pal, ts->x, ts->y, ts->sub); + } +} + +/** This fallback sprite checker always exists. */ +static bool ViewportSortParentSpritesChecker() +{ + return true; +} + +/** Sort parent sprites pointer array */ +static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv) +{ + ParentSpriteToDraw **psdvend = psdv->End(); + ParentSpriteToDraw **psd = psdv->Begin(); + while (psd != psdvend) { + ParentSpriteToDraw *ps = *psd; + + if (ps->comparison_done) { + psd++; + continue; + } + + ps->comparison_done = true; + + for (ParentSpriteToDraw **psd2 = psd + 1; psd2 != psdvend; psd2++) { + ParentSpriteToDraw *ps2 = *psd2; + + if (ps2->comparison_done) continue; + + /* Decide which comparator to use, based on whether the bounding + * boxes overlap + */ + if (ps->xmax >= ps2->xmin && ps->xmin <= ps2->xmax && // overlap in X? + ps->ymax >= ps2->ymin && ps->ymin <= ps2->ymax && // overlap in Y? + ps->zmax >= ps2->zmin && ps->zmin <= ps2->zmax) { // overlap in Z? + /* Use X+Y+Z as the sorting order, so sprites closer to the bottom of + * the screen and with higher Z elevation, are drawn in front. + * Here X,Y,Z are the coordinates of the "center of mass" of the sprite, + * i.e. X=(left+right)/2, etc. + * However, since we only care about order, don't actually divide / 2 + */ + if (ps->xmin + ps->xmax + ps->ymin + ps->ymax + ps->zmin + ps->zmax <= + ps2->xmin + ps2->xmax + ps2->ymin + ps2->ymax + ps2->zmin + ps2->zmax) { + continue; + } + } else { + /* We only change the order, if it is definite. + * I.e. every single order of X, Y, Z says ps2 is behind ps or they overlap. + * That is: If one partial order says ps behind ps2, do not change the order. + */ + if (ps->xmax < ps2->xmin || + ps->ymax < ps2->ymin || + ps->zmax < ps2->zmin) { + continue; + } + } + + /* Move ps2 in front of ps */ + ParentSpriteToDraw *temp = ps2; + for (ParentSpriteToDraw **psd3 = psd2; psd3 > psd; psd3--) { + *psd3 = *(psd3 - 1); + } + *psd = temp; + } + } +} + +static void ViewportDrawParentSprites(const ParentSpriteToSortVector *psd, const ChildScreenSpriteToDrawVector *csstdv) +{ + const ParentSpriteToDraw * const *psd_end = psd->End(); + for (const ParentSpriteToDraw * const *it = psd->Begin(); it != psd_end; it++) { + const ParentSpriteToDraw *ps = *it; + if (ps->image != SPR_EMPTY_BOUNDING_BOX) DrawSpriteViewport(ps->image, ps->pal, ps->x, ps->y, ps->sub); + + int child_idx = ps->first_child; + while (child_idx >= 0) { + const ChildScreenSpriteToDraw *cs = csstdv->Get(child_idx); + child_idx = cs->next; + DrawSpriteViewport(cs->image, cs->pal, ps->left + cs->x, ps->top + cs->y, cs->sub); + } + } +} + +/** + * Draws the bounding boxes of all ParentSprites + * @param psd Array of ParentSprites + */ +static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd) +{ + const ParentSpriteToDraw * const *psd_end = psd->End(); + for (const ParentSpriteToDraw * const *it = psd->Begin(); it != psd_end; it++) { + const ParentSpriteToDraw *ps = *it; + Point pt1 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmax + 1); // top front corner + Point pt2 = RemapCoords(ps->xmin , ps->ymax + 1, ps->zmax + 1); // top left corner + Point pt3 = RemapCoords(ps->xmax + 1, ps->ymin , ps->zmax + 1); // top right corner + Point pt4 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmin ); // bottom front corner + + DrawBox( pt1.x, pt1.y, + pt2.x - pt1.x, pt2.y - pt1.y, + pt3.x - pt1.x, pt3.y - pt1.y, + pt4.x - pt1.x, pt4.y - pt1.y); + } +} + +/** + * Draw/colour the blocks that have been redrawn. + */ +static void ViewportDrawDirtyBlocks() +{ + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + const DrawPixelInfo *dpi = _cur_dpi; + void *dst; + int right = UnScaleByZoom(dpi->width, dpi->zoom); + int bottom = UnScaleByZoom(dpi->height, dpi->zoom); + + int colour = _string_colourmap[_dirty_block_colour & 0xF]; + + dst = dpi->dst_ptr; + + byte bo = UnScaleByZoom(dpi->left + dpi->top, dpi->zoom) & 1; + do { + for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8)colour); + dst = blitter->MoveTo(dst, 0, 1); + } while (--bottom > 0); +} + +static void ViewportDrawStrings(ZoomLevel zoom, const StringSpriteToDrawVector *sstdv) +{ + const StringSpriteToDraw *ssend = sstdv->End(); + for (const StringSpriteToDraw *ss = sstdv->Begin(); ss != ssend; ++ss) { + TextColour colour = TC_BLACK; + bool small = HasBit(ss->width, 15); + int w = GB(ss->width, 0, 15); + int x = UnScaleByZoom(ss->x, zoom); + int y = UnScaleByZoom(ss->y, zoom); + int h = VPSM_TOP + (small ? FONT_HEIGHT_SMALL : FONT_HEIGHT_NORMAL) + VPSM_BOTTOM; + + SetDParam(0, ss->params[0]); + SetDParam(1, ss->params[1]); + + if (ss->colour != INVALID_COLOUR) { + /* Do not draw signs nor station names if they are set invisible */ + if (IsInvisibilitySet(TO_SIGNS) && ss->string != STR_WHITE_SIGN) continue; + + if (IsTransparencySet(TO_SIGNS) && ss->string != STR_WHITE_SIGN) { + /* Don't draw the rectangle. + * Real colours need the TC_IS_PALETTE_COLOUR flag. + * Otherwise colours from _string_colourmap are assumed. */ + colour = (TextColour)_colour_gradient[ss->colour][6] | TC_IS_PALETTE_COLOUR; + } else { + /* Draw the rectangle if 'transparent station signs' is off, + * or if we are drawing a general text sign (STR_WHITE_SIGN). */ + DrawFrameRect( + x, y, x + w, y + h, ss->colour, + IsTransparencySet(TO_SIGNS) ? FR_TRANSPARENT : FR_NONE + ); + } + } + + DrawString(x + VPSM_LEFT, x + w - 1 - VPSM_RIGHT, y + VPSM_TOP, ss->string, colour, SA_HOR_CENTER); + } +} + +void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom) +{ + DrawPixelInfo *old_dpi = _cur_dpi; + _cur_dpi = &_vd.dpi; + + _vd.dpi.zoom = vp->zoom; + int mask = ScaleByZoom(-1, vp->zoom); + + _vd.combine_sprites = SPRITE_COMBINE_NONE; + + _vd.dpi.width = (right - left) & mask; + _vd.dpi.height = (bottom - top) & mask; + _vd.dpi.left = left & mask; + _vd.dpi.top = top & mask; + _vd.dpi.pitch = old_dpi->pitch; + _vd.last_child = NULL; + + int x = UnScaleByZoom(_vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left; + int y = UnScaleByZoom(_vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top; + + _vd.dpi.dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(old_dpi->dst_ptr, x - old_dpi->left, y - old_dpi->top); + + ViewportAddLandscape(); + ViewportAddVehicles(&_vd.dpi); + + ViewportAddTownNames(&_vd.dpi); + ViewportAddStationNames(&_vd.dpi); + ViewportAddSigns(&_vd.dpi); + + DrawTextEffects(&_vd.dpi); + + if (_vd.tile_sprites_to_draw.Length() != 0) ViewportDrawTileSprites(&_vd.tile_sprites_to_draw); + + ParentSpriteToDraw *psd_end = _vd.parent_sprites_to_draw.End(); + for (ParentSpriteToDraw *it = _vd.parent_sprites_to_draw.Begin(); it != psd_end; it++) { + *_vd.parent_sprites_to_sort.Append() = it; + } + + _vp_sprite_sorter(&_vd.parent_sprites_to_sort); + ViewportDrawParentSprites(&_vd.parent_sprites_to_sort, &_vd.child_screen_sprites_to_draw); + + if (_draw_bounding_boxes) ViewportDrawBoundingBoxes(&_vd.parent_sprites_to_sort); + if (_draw_dirty_blocks) ViewportDrawDirtyBlocks(); + + DrawPixelInfo dp = _vd.dpi; + ZoomLevel zoom = _vd.dpi.zoom; + dp.zoom = ZOOM_LVL_NORMAL; + dp.width = UnScaleByZoom(dp.width, zoom); + dp.height = UnScaleByZoom(dp.height, zoom); + _cur_dpi = &dp; + + if (vp->overlay != NULL && vp->overlay->GetCargoMask() != 0 && vp->overlay->GetCompanyMask() != 0) { + /* translate to window coordinates */ + dp.left = x; + dp.top = y; + vp->overlay->Draw(&dp); + } + + if (_vd.string_sprites_to_draw.Length() != 0) { + /* translate to world coordinates */ + dp.left = UnScaleByZoom(_vd.dpi.left, zoom); + dp.top = UnScaleByZoom(_vd.dpi.top, zoom); + ViewportDrawStrings(zoom, &_vd.string_sprites_to_draw); + } + + _cur_dpi = old_dpi; + + _vd.string_sprites_to_draw.Clear(); + _vd.tile_sprites_to_draw.Clear(); + _vd.parent_sprites_to_draw.Clear(); + _vd.parent_sprites_to_sort.Clear(); + _vd.child_screen_sprites_to_draw.Clear(); +} + +/** + * Make sure we don't draw a too big area at a time. + * If we do, the sprite memory will overflow. + */ +static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom) +{ + if (ScaleByZoom(bottom - top, vp->zoom) * ScaleByZoom(right - left, vp->zoom) > 180000 * ZOOM_LVL_BASE * ZOOM_LVL_BASE) { + if ((bottom - top) > (right - left)) { + int t = (top + bottom) >> 1; + ViewportDrawChk(vp, left, top, right, t); + ViewportDrawChk(vp, left, t, right, bottom); + } else { + int t = (left + right) >> 1; + ViewportDrawChk(vp, left, top, t, bottom); + ViewportDrawChk(vp, t, top, right, bottom); + } + } else { + ViewportDoDraw(vp, + ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left, + ScaleByZoom(top - vp->top, vp->zoom) + vp->virtual_top, + ScaleByZoom(right - vp->left, vp->zoom) + vp->virtual_left, + ScaleByZoom(bottom - vp->top, vp->zoom) + vp->virtual_top + ); + } +} + +static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right, int bottom) +{ + if (right <= vp->left || bottom <= vp->top) return; + + if (left >= vp->left + vp->width) return; + + if (left < vp->left) left = vp->left; + if (right > vp->left + vp->width) right = vp->left + vp->width; + + if (top >= vp->top + vp->height) return; + + if (top < vp->top) top = vp->top; + if (bottom > vp->top + vp->height) bottom = vp->top + vp->height; + + ViewportDrawChk(vp, left, top, right, bottom); +} + +/** + * Draw the viewport of this window. + */ +void Window::DrawViewport() const +{ + DrawPixelInfo *dpi = _cur_dpi; + + dpi->left += this->left; + dpi->top += this->top; + + ViewportDraw(this->viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height); + + dpi->left -= this->left; + dpi->top -= this->top; +} + +static inline void ClampViewportToMap(const ViewPort *vp, int &x, int &y) +{ + /* Centre of the viewport is hot spot */ + x += vp->virtual_width / 2; + y += vp->virtual_height / 2; + + /* Convert viewport coordinates to map coordinates + * Calculation is scaled by 4 to avoid rounding errors */ + int vx = -x + y * 2; + int vy = x + y * 2; + + /* clamp to size of map */ + vx = Clamp(vx, 0, MapMaxX() * TILE_SIZE * 4 * ZOOM_LVL_BASE); + vy = Clamp(vy, 0, MapMaxY() * TILE_SIZE * 4 * ZOOM_LVL_BASE); + + /* Convert map coordinates to viewport coordinates */ + x = (-vx + vy) / 2; + y = ( vx + vy) / 4; + + /* Remove centering */ + x -= vp->virtual_width / 2; + y -= vp->virtual_height / 2; +} + +/** + * Update the viewport position being displayed. + * @param w %Window owning the viewport. + */ +void UpdateViewportPosition(Window *w) +{ + const ViewPort *vp = w->viewport; + + if (w->viewport->follow_vehicle != INVALID_VEHICLE) { + const Vehicle *veh = Vehicle::Get(w->viewport->follow_vehicle); + Point pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos); + + w->viewport->scrollpos_x = pt.x; + w->viewport->scrollpos_y = pt.y; + SetViewportPosition(w, pt.x, pt.y); + } else { + /* Ensure the destination location is within the map */ + ClampViewportToMap(vp, w->viewport->dest_scrollpos_x, w->viewport->dest_scrollpos_y); + + int delta_x = w->viewport->dest_scrollpos_x - w->viewport->scrollpos_x; + int delta_y = w->viewport->dest_scrollpos_y - w->viewport->scrollpos_y; + + bool update_overlay = false; + if (delta_x != 0 || delta_y != 0) { + if (_settings_client.gui.smooth_scroll) { + int max_scroll = ScaleByMapSize1D(512 * ZOOM_LVL_BASE); + /* Not at our desired position yet... */ + w->viewport->scrollpos_x += Clamp(delta_x / 4, -max_scroll, max_scroll); + w->viewport->scrollpos_y += Clamp(delta_y / 4, -max_scroll, max_scroll); + } else { + w->viewport->scrollpos_x = w->viewport->dest_scrollpos_x; + w->viewport->scrollpos_y = w->viewport->dest_scrollpos_y; + } + update_overlay = (w->viewport->scrollpos_x == w->viewport->dest_scrollpos_x && + w->viewport->scrollpos_y == w->viewport->dest_scrollpos_y); + } + + ClampViewportToMap(vp, w->viewport->scrollpos_x, w->viewport->scrollpos_y); + + SetViewportPosition(w, w->viewport->scrollpos_x, w->viewport->scrollpos_y); + if (update_overlay) RebuildViewportOverlay(w); + } +} + +/** + * Marks a viewport as dirty for repaint if it displays (a part of) the area the needs to be repainted. + * @param vp The viewport to mark as dirty + * @param left Left edge of area to repaint + * @param top Top edge of area to repaint + * @param right Right edge of area to repaint + * @param bottom Bottom edge of area to repaint + * @ingroup dirty + */ +static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom) +{ + right -= vp->virtual_left; + if (right <= 0) return; + + bottom -= vp->virtual_top; + if (bottom <= 0) return; + + left = max(0, left - vp->virtual_left); + + if (left >= vp->virtual_width) return; + + top = max(0, top - vp->virtual_top); + + if (top >= vp->virtual_height) return; + + SetDirtyBlocks( + UnScaleByZoomLower(left, vp->zoom) + vp->left, + UnScaleByZoomLower(top, vp->zoom) + vp->top, + UnScaleByZoom(right, vp->zoom) + vp->left + 1, + UnScaleByZoom(bottom, vp->zoom) + vp->top + 1 + ); +} + +/** + * Mark all viewports that display an area as dirty (in need of repaint). + * @param left Left edge of area to repaint + * @param top Top edge of area to repaint + * @param right Right edge of area to repaint + * @param bottom Bottom edge of area to repaint + * @ingroup dirty + */ +void MarkAllViewportsDirty(int left, int top, int right, int bottom) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + ViewPort *vp = w->viewport; + if (vp != NULL) { + assert(vp->width != 0); + MarkViewportDirty(vp, left, top, right, bottom); + } + } +} + +void ConstrainAllViewportsZoom() +{ + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if (w->viewport == NULL) continue; + + ZoomLevel zoom = static_cast(Clamp(w->viewport->zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max)); + if (zoom != w->viewport->zoom) { + while (w->viewport->zoom < zoom) DoZoomInOutWindow(ZOOM_OUT, w); + while (w->viewport->zoom > zoom) DoZoomInOutWindow(ZOOM_IN, w); + } + } +} + +/** + * Mark a tile given by its index dirty for repaint. + * @param tile The tile to mark dirty. + * @ingroup dirty + */ +void MarkTileDirtyByTile(TileIndex tile) +{ + Point pt = RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, GetTilePixelZ(tile)); + MarkAllViewportsDirty( + pt.x - 31 * ZOOM_LVL_BASE, + pt.y - 122 * ZOOM_LVL_BASE, + pt.x - 31 * ZOOM_LVL_BASE + 67 * ZOOM_LVL_BASE, + pt.y - 122 * ZOOM_LVL_BASE + 154 * ZOOM_LVL_BASE + ); +} + +/** + * Marks the selected tiles as dirty. + * + * This function marks the selected tiles as dirty for repaint + * + * @ingroup dirty + */ +static void SetSelectionTilesDirty() +{ + int x_size = _thd.size.x; + int y_size = _thd.size.y; + + if (!_thd.diagonal) { // Selecting in a straight rectangle (or a single square) + int x_start = _thd.pos.x; + int y_start = _thd.pos.y; + + if (_thd.outersize.x != 0) { + x_size += _thd.outersize.x; + x_start += _thd.offs.x; + y_size += _thd.outersize.y; + y_start += _thd.offs.y; + } + + x_size -= TILE_SIZE; + y_size -= TILE_SIZE; + + assert(x_size >= 0); + assert(y_size >= 0); + + int x_end = Clamp(x_start + x_size, 0, MapSizeX() * TILE_SIZE - TILE_SIZE); + int y_end = Clamp(y_start + y_size, 0, MapSizeY() * TILE_SIZE - TILE_SIZE); + + x_start = Clamp(x_start, 0, MapSizeX() * TILE_SIZE - TILE_SIZE); + y_start = Clamp(y_start, 0, MapSizeY() * TILE_SIZE - TILE_SIZE); + + /* make sure everything is multiple of TILE_SIZE */ + assert((x_end | y_end | x_start | y_start) % TILE_SIZE == 0); + + /* How it works: + * Suppose we have to mark dirty rectangle of 3x4 tiles: + * x + * xxx + * xxxxx + * xxxxx + * xxx + * x + * This algorithm marks dirty columns of tiles, so it is done in 3+4-1 steps: + * 1) x 2) x + * xxx Oxx + * Oxxxx xOxxx + * xxxxx Oxxxx + * xxx xxx + * x x + * And so forth... + */ + + int top_x = x_end; // coordinates of top dirty tile + int top_y = y_start; + int bot_x = top_x; // coordinates of bottom dirty tile + int bot_y = top_y; + + do { + /* topmost dirty point */ + TileIndex top_tile = TileVirtXY(top_x, top_y); + Point top = RemapCoords(top_x, top_y, GetTileMaxPixelZ(top_tile)); + + /* bottommost point */ + TileIndex bottom_tile = TileVirtXY(bot_x, bot_y); + Point bot = RemapCoords(bot_x + TILE_SIZE, bot_y + TILE_SIZE, GetTilePixelZ(bottom_tile)); // bottommost point + + /* the 'x' coordinate of 'top' and 'bot' is the same (and always in the same distance from tile middle), + * tile height/slope affects only the 'y' on-screen coordinate! */ + + int l = top.x - (TILE_PIXELS - 2) * ZOOM_LVL_BASE; // 'x' coordinate of left side of dirty rectangle + int t = top.y; // 'y' coordinate of top side -//- + int r = top.x + (TILE_PIXELS - 2) * ZOOM_LVL_BASE; // right side of dirty rectangle + int b = bot.y; // bottom -//- + + static const int OVERLAY_WIDTH = 4 * ZOOM_LVL_BASE; // part of selection sprites is drawn outside the selected area + + /* For halftile foundations on SLOPE_STEEP_S the sprite extents some more towards the top */ + MarkAllViewportsDirty(l - OVERLAY_WIDTH, t - OVERLAY_WIDTH - TILE_HEIGHT * ZOOM_LVL_BASE, r + OVERLAY_WIDTH, b + OVERLAY_WIDTH * ZOOM_LVL_BASE); + + /* haven't we reached the topmost tile yet? */ + if (top_x != x_start) { + top_x -= TILE_SIZE; + } else { + top_y += TILE_SIZE; + } + + /* the way the bottom tile changes is different when we reach the bottommost tile */ + if (bot_y != y_end) { + bot_y += TILE_SIZE; + } else { + bot_x -= TILE_SIZE; + } + } while (bot_x >= top_x); + } else { // Selecting in a 45 degrees rotated (diagonal) rectangle. + /* a_size, b_size describe a rectangle with rotated coordinates */ + int a_size = x_size + y_size, b_size = x_size - y_size; + + int interval_a = a_size < 0 ? -(int)TILE_SIZE : (int)TILE_SIZE; + int interval_b = b_size < 0 ? -(int)TILE_SIZE : (int)TILE_SIZE; + + for (int a = -interval_a; a != a_size + interval_a; a += interval_a) { + for (int b = -interval_b; b != b_size + interval_b; b += interval_b) { + uint x = (_thd.pos.x + (a + b) / 2) / TILE_SIZE; + uint y = (_thd.pos.y + (a - b) / 2) / TILE_SIZE; + + if (x < MapMaxX() && y < MapMaxY()) { + MarkTileDirtyByTile(TileXY(x, y)); + } + } + } + } +} + + +void SetSelectionRed(bool b) +{ + _thd.make_square_red = b; + SetSelectionTilesDirty(); +} + +/** + * Test whether a sign is below the mouse + * @param vp the clicked viewport + * @param x X position of click + * @param y Y position of click + * @param sign the sign to check + * @return true if the sign was hit + */ +static bool CheckClickOnViewportSign(const ViewPort *vp, int x, int y, const ViewportSign *sign) +{ + bool small = (vp->zoom >= ZOOM_LVL_OUT_16X); + int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, vp->zoom); + int sign_height = ScaleByZoom(VPSM_TOP + (small ? FONT_HEIGHT_SMALL : FONT_HEIGHT_NORMAL) + VPSM_BOTTOM, vp->zoom); + + x = ScaleByZoom(x - vp->left, vp->zoom) + vp->virtual_left; + y = ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top; + + return y >= sign->top && y < sign->top + sign_height && + x >= sign->center - sign_half_width && x < sign->center + sign_half_width; +} + +static bool CheckClickOnTown(const ViewPort *vp, int x, int y) +{ + if (!HasBit(_display_opt, DO_SHOW_TOWN_NAMES)) return false; + + const Town *t; + FOR_ALL_TOWNS(t) { + if (CheckClickOnViewportSign(vp, x, y, &t->cache.sign)) { + ShowTownViewWindow(t->index); + return true; + } + } + + return false; +} + +static bool CheckClickOnStation(const ViewPort *vp, int x, int y) +{ + if (!(HasBit(_display_opt, DO_SHOW_STATION_NAMES) || HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)) || IsInvisibilitySet(TO_SIGNS)) return false; + + const BaseStation *st; + FOR_ALL_BASE_STATIONS(st) { + /* Check whether the base station is a station or a waypoint */ + bool is_station = Station::IsExpected(st); + + /* Don't check if the display options are disabled */ + if (!HasBit(_display_opt, is_station ? DO_SHOW_STATION_NAMES : DO_SHOW_WAYPOINT_NAMES)) continue; + + /* Don't check if competitor signs are not shown and the sign isn't owned by the local company */ + if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != st->owner && st->owner != OWNER_NONE) continue; + + if (CheckClickOnViewportSign(vp, x, y, &st->sign)) { + if (is_station) { + ShowStationViewWindow(st->index); + } else { + ShowWaypointWindow(Waypoint::From(st)); + } + return true; + } + } + + return false; +} + + +static bool CheckClickOnSign(const ViewPort *vp, int x, int y) +{ + /* Signs are turned off, or they are transparent and invisibility is ON, or company is a spectator */ + if (!HasBit(_display_opt, DO_SHOW_SIGNS) || IsInvisibilitySet(TO_SIGNS) || _local_company == COMPANY_SPECTATOR) return false; + + const Sign *si; + FOR_ALL_SIGNS(si) { + /* If competitor signs are hidden, don't check signs that aren't owned by local company */ + if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != si->owner && si->owner != OWNER_DEITY) continue; + if (si->owner == OWNER_DEITY && _game_mode != GM_EDITOR) continue; + + if (CheckClickOnViewportSign(vp, x, y, &si->sign)) { + HandleClickOnSign(si); + return true; + } + } + + return false; +} + + +static bool CheckClickOnLandscape(const ViewPort *vp, int x, int y) +{ + Point pt = TranslateXYToTileCoord(vp, x, y); + + if (pt.x != -1) return ClickTile(TileVirtXY(pt.x, pt.y)); + return true; +} + +static void PlaceObject() +{ + Point pt; + Window *w; + + pt = GetTileBelowCursor(); + if (pt.x == -1) return; + + if ((_thd.place_mode & HT_DRAG_MASK) == HT_POINT) { + pt.x += TILE_SIZE / 2; + pt.y += TILE_SIZE / 2; + } + + _tile_fract_coords.x = pt.x & TILE_UNIT_MASK; + _tile_fract_coords.y = pt.y & TILE_UNIT_MASK; + + w = _thd.GetCallbackWnd(); + if (w != NULL) w->OnPlaceObject(pt, TileVirtXY(pt.x, pt.y)); +} + + +bool HandleViewportClicked(const ViewPort *vp, int x, int y) +{ + const Vehicle *v = CheckClickOnVehicle(vp, x, y); + + if (_thd.place_mode & HT_VEHICLE) { + if (v != NULL && VehicleClicked(v)) return true; + } + + /* Vehicle placement mode already handled above. */ + if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) { + PlaceObject(); + return true; + } + + if (CheckClickOnTown(vp, x, y)) return true; + if (CheckClickOnStation(vp, x, y)) return true; + if (CheckClickOnSign(vp, x, y)) return true; + bool result = CheckClickOnLandscape(vp, x, y); + + if (v != NULL) { + DEBUG(misc, 2, "Vehicle %d (index %d) at %p", v->unitnumber, v->index, v); + if (IsCompanyBuildableVehicleType(v)) { + v = v->First(); + if (_ctrl_pressed && v->owner == _local_company) { + StartStopVehicle(v, true); + } else { + ShowVehicleViewWindow(v); + } + } + return true; + } + return result; +} + +void RebuildViewportOverlay(Window *w) +{ + if (w->viewport->overlay != NULL && + w->viewport->overlay->GetCompanyMask() != 0 && + w->viewport->overlay->GetCargoMask() != 0) { + w->viewport->overlay->RebuildCache(); + w->SetDirty(); + } +} + +/** + * Scrolls the viewport in a window to a given location. + * @param x Desired x location of the map to scroll to (world coordinate). + * @param y Desired y location of the map to scroll to (world coordinate). + * @param z Desired z location of the map to scroll to (world coordinate). Use \c -1 to scroll to the height of the map at the \a x, \a y location. + * @param w %Window containing the viewport. + * @param instant Jump to the location instead of slowly moving to it. + * @return Destination of the viewport was changed (to activate other actions when the viewport is already at the desired position). + */ +bool ScrollWindowTo(int x, int y, int z, Window *w, bool instant) +{ + /* The slope cannot be acquired outside of the map, so make sure we are always within the map. */ + if (z == -1) z = GetSlopePixelZ(Clamp(x, 0, MapSizeX() * TILE_SIZE - 1), Clamp(y, 0, MapSizeY() * TILE_SIZE - 1)); + + Point pt = MapXYZToViewport(w->viewport, x, y, z); + w->viewport->follow_vehicle = INVALID_VEHICLE; + + if (w->viewport->dest_scrollpos_x == pt.x && w->viewport->dest_scrollpos_y == pt.y) return false; + + if (instant) { + w->viewport->scrollpos_x = pt.x; + w->viewport->scrollpos_y = pt.y; + RebuildViewportOverlay(w); + } + + w->viewport->dest_scrollpos_x = pt.x; + w->viewport->dest_scrollpos_y = pt.y; + return true; +} + +/** + * Scrolls the viewport in a window to a given location. + * @param tile Desired tile to center on. + * @param w %Window containing the viewport. + * @param instant Jump to the location instead of slowly moving to it. + * @return Destination of the viewport was changed (to activate other actions when the viewport is already at the desired position). + */ +bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant) +{ + return ScrollWindowTo(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, -1, w, instant); +} + +/** + * Scrolls the viewport of the main window to a given location. + * @param tile Desired tile to center on. + * @param instant Jump to the location instead of slowly moving to it. + * @return Destination of the viewport was changed (to activate other actions when the viewport is already at the desired position). + */ +bool ScrollMainWindowToTile(TileIndex tile, bool instant) +{ + return ScrollMainWindowTo(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, -1, instant); +} + +/** + * Set a tile to display a red error square. + * @param tile Tile that should show the red error square. + */ +void SetRedErrorSquare(TileIndex tile) +{ + TileIndex old; + + old = _thd.redsq; + _thd.redsq = tile; + + if (tile != old) { + if (tile != INVALID_TILE) MarkTileDirtyByTile(tile); + if (old != INVALID_TILE) MarkTileDirtyByTile(old); + } +} + +/** + * Highlight \a w by \a h tiles at the cursor. + * @param w Width of the highlighted tiles rectangle. + * @param h Height of the highlighted tiles rectangle. + */ +void SetTileSelectSize(int w, int h) +{ + _thd.new_size.x = w * TILE_SIZE; + _thd.new_size.y = h * TILE_SIZE; + _thd.new_outersize.x = 0; + _thd.new_outersize.y = 0; +} + +void SetTileSelectBigSize(int ox, int oy, int sx, int sy) +{ + _thd.offs.x = ox * TILE_SIZE; + _thd.offs.y = oy * TILE_SIZE; + _thd.new_outersize.x = sx * TILE_SIZE; + _thd.new_outersize.y = sy * TILE_SIZE; +} + +/** returns the best autorail highlight type from map coordinates */ +static HighLightStyle GetAutorailHT(int x, int y) +{ + return HT_RAIL | _autorail_piece[x & TILE_UNIT_MASK][y & TILE_UNIT_MASK]; +} + +/** + * Reset tile highlighting. + */ +void TileHighlightData::Reset() +{ + this->pos.x = 0; + this->pos.y = 0; + this->new_pos.x = 0; + this->new_pos.y = 0; +} + +/** + * Is the user dragging a 'diagonal rectangle'? + * @return User is dragging a rotated rectangle. + */ +bool TileHighlightData::IsDraggingDiagonal() +{ + return (this->place_mode & HT_DIAGONAL) != 0 && _ctrl_pressed && _left_button_down; +} + +/** + * Get the window that started the current highlighting. + * @return The window that requested the current tile highlighting, or \c NULL if not available. + */ +Window *TileHighlightData::GetCallbackWnd() +{ + return FindWindowById(this->window_class, this->window_number); +} + + + +/** + * Updates tile highlighting for all cases. + * Uses _thd.selstart and _thd.selend and _thd.place_mode (set elsewhere) to determine _thd.pos and _thd.size + * Also drawstyle is determined. Uses _thd.new.* as a buffer and calls SetSelectionTilesDirty() twice, + * Once for the old and once for the new selection. + * _thd is TileHighlightData, found in viewport.h + */ +void UpdateTileSelection() +{ + int x1; + int y1; + + HighLightStyle new_drawstyle = HT_NONE; + bool new_diagonal = false; + + if ((_thd.place_mode & HT_DRAG_MASK) == HT_SPECIAL) { + x1 = _thd.selend.x; + y1 = _thd.selend.y; + if (x1 != -1) { + int x2 = _thd.selstart.x & ~TILE_UNIT_MASK; + int y2 = _thd.selstart.y & ~TILE_UNIT_MASK; + x1 &= ~TILE_UNIT_MASK; + y1 &= ~TILE_UNIT_MASK; + + if (_thd.IsDraggingDiagonal()) { + new_diagonal = true; + } else { + if (x1 >= x2) Swap(x1, x2); + if (y1 >= y2) Swap(y1, y2); + } + _thd.new_pos.x = x1; + _thd.new_pos.y = y1; + _thd.new_size.x = x2 - x1; + _thd.new_size.y = y2 - y1; + if (!new_diagonal) { + _thd.new_size.x += TILE_SIZE; + _thd.new_size.y += TILE_SIZE; + } + new_drawstyle = _thd.next_drawstyle; + } + } else if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) { + Point pt = GetTileBelowCursor(); + x1 = pt.x; + y1 = pt.y; + if (x1 != -1) { + switch (_thd.place_mode & HT_DRAG_MASK) { + case HT_RECT: + new_drawstyle = HT_RECT; + break; + case HT_POINT: + new_drawstyle = HT_POINT; + x1 += TILE_SIZE / 2; + y1 += TILE_SIZE / 2; + break; + case HT_RAIL: + /* Draw one highlighted tile in any direction */ + new_drawstyle = GetAutorailHT(pt.x, pt.y); + break; + case HT_LINE: + switch (_thd.place_mode & HT_DIR_MASK) { + case HT_DIR_X: new_drawstyle = HT_LINE | HT_DIR_X; break; + case HT_DIR_Y: new_drawstyle = HT_LINE | HT_DIR_Y; break; + + case HT_DIR_HU: + case HT_DIR_HL: + new_drawstyle = (pt.x & TILE_UNIT_MASK) + (pt.y & TILE_UNIT_MASK) <= TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL; + break; + + case HT_DIR_VL: + case HT_DIR_VR: + new_drawstyle = (pt.x & TILE_UNIT_MASK) > (pt.y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; + break; + + default: NOT_REACHED(); + } + _thd.selstart.x = x1 & ~TILE_UNIT_MASK; + _thd.selstart.y = y1 & ~TILE_UNIT_MASK; + break; + default: + NOT_REACHED(); + break; + } + _thd.new_pos.x = x1 & ~TILE_UNIT_MASK; + _thd.new_pos.y = y1 & ~TILE_UNIT_MASK; + } + } + + /* redraw selection */ + if (_thd.drawstyle != new_drawstyle || + _thd.pos.x != _thd.new_pos.x || _thd.pos.y != _thd.new_pos.y || + _thd.size.x != _thd.new_size.x || _thd.size.y != _thd.new_size.y || + _thd.outersize.x != _thd.new_outersize.x || + _thd.outersize.y != _thd.new_outersize.y || + _thd.diagonal != new_diagonal) { + /* Clear the old tile selection? */ + if ((_thd.drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty(); + + _thd.drawstyle = new_drawstyle; + _thd.pos = _thd.new_pos; + _thd.size = _thd.new_size; + _thd.outersize = _thd.new_outersize; + _thd.diagonal = new_diagonal; + _thd.dirty = 0xff; + + /* Draw the new tile selection? */ + if ((new_drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty(); + } +} + +/** + * Displays the measurement tooltips when selecting multiple tiles + * @param str String to be displayed + * @param paramcount number of params to deal with + * @param params (optional) up to 5 pieces of additional information that may be added to a tooltip + * @param close_cond Condition for closing this tooltip. + */ +static inline void ShowMeasurementTooltips(StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_cond = TCC_LEFT_CLICK) +{ + if (!_settings_client.gui.measure_tooltip) return; + GuiShowTooltips(_thd.GetCallbackWnd(), str, paramcount, params, close_cond); +} + +/** highlighting tiles while only going over them with the mouse */ +void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process) +{ + _thd.select_method = method; + _thd.select_proc = process; + _thd.selend.x = TileX(tile) * TILE_SIZE; + _thd.selstart.x = TileX(tile) * TILE_SIZE; + _thd.selend.y = TileY(tile) * TILE_SIZE; + _thd.selstart.y = TileY(tile) * TILE_SIZE; + + /* Needed so several things (road, autoroad, bridges, ...) are placed correctly. + * In effect, placement starts from the centre of a tile + */ + if (method == VPM_X_OR_Y || method == VPM_FIX_X || method == VPM_FIX_Y) { + _thd.selend.x += TILE_SIZE / 2; + _thd.selend.y += TILE_SIZE / 2; + _thd.selstart.x += TILE_SIZE / 2; + _thd.selstart.y += TILE_SIZE / 2; + } + + HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK); + if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT) { + _thd.place_mode = HT_SPECIAL | others; + _thd.next_drawstyle = HT_RECT | others; + } else if (_thd.place_mode & (HT_RAIL | HT_LINE)) { + _thd.place_mode = HT_SPECIAL | others; + _thd.next_drawstyle = _thd.drawstyle | others; + } else { + _thd.place_mode = HT_SPECIAL | others; + _thd.next_drawstyle = HT_POINT | others; + } + _special_mouse_mode = WSM_SIZING; +} + +void VpSetPlaceSizingLimit(int limit) +{ + _thd.sizelimit = limit; +} + +/** + * Highlights all tiles between a set of two tiles. Used in dock and tunnel placement + * @param from TileIndex of the first tile to highlight + * @param to TileIndex of the last tile to highlight + */ +void VpSetPresizeRange(TileIndex from, TileIndex to) +{ + uint64 distance = DistanceManhattan(from, to) + 1; + + _thd.selend.x = TileX(to) * TILE_SIZE; + _thd.selend.y = TileY(to) * TILE_SIZE; + _thd.selstart.x = TileX(from) * TILE_SIZE; + _thd.selstart.y = TileY(from) * TILE_SIZE; + _thd.next_drawstyle = HT_RECT; + + /* show measurement only if there is any length to speak of */ + if (distance > 1) ShowMeasurementTooltips(STR_MEASURE_LENGTH, 1, &distance, TCC_HOVER); +} + +void VpStartPreSizing() +{ + _thd.selend.x = -1; + _special_mouse_mode = WSM_PRESIZE; +} + +/** + * returns information about the 2x1 piece to be build. + * The lower bits (0-3) are the track type. + */ +static HighLightStyle Check2x1AutoRail(int mode) +{ + int fxpy = _tile_fract_coords.x + _tile_fract_coords.y; + int sxpy = (_thd.selend.x & TILE_UNIT_MASK) + (_thd.selend.y & TILE_UNIT_MASK); + int fxmy = _tile_fract_coords.x - _tile_fract_coords.y; + int sxmy = (_thd.selend.x & TILE_UNIT_MASK) - (_thd.selend.y & TILE_UNIT_MASK); + + switch (mode) { + default: NOT_REACHED(); + case 0: // end piece is lower right + if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL; + if (fxmy < -3 && sxmy > 3) return HT_DIR_VR; + return HT_DIR_Y; + + case 1: + if (fxmy > 3 && sxmy < -3) return HT_DIR_VL; + if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU; + return HT_DIR_Y; + + case 2: + if (fxmy > 3 && sxmy < -3) return HT_DIR_VL; + if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL; + return HT_DIR_X; + + case 3: + if (fxmy < -3 && sxmy > 3) return HT_DIR_VR; + if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU; + return HT_DIR_X; + } +} + +/** + * Check if the direction of start and end tile should be swapped based on + * the dragging-style. Default directions are: + * in the case of a line (HT_RAIL, HT_LINE): DIR_NE, DIR_NW, DIR_N, DIR_E + * in the case of a rect (HT_RECT, HT_POINT): DIR_S, DIR_E + * For example dragging a rectangle area from south to north should be swapped to + * north-south (DIR_S) to obtain the same results with less code. This is what + * the return value signifies. + * @param style HighLightStyle dragging style + * @param start_tile start tile of drag + * @param end_tile end tile of drag + * @return boolean value which when true means start/end should be swapped + */ +static bool SwapDirection(HighLightStyle style, TileIndex start_tile, TileIndex end_tile) +{ + uint start_x = TileX(start_tile); + uint start_y = TileY(start_tile); + uint end_x = TileX(end_tile); + uint end_y = TileY(end_tile); + + switch (style & HT_DRAG_MASK) { + case HT_RAIL: + case HT_LINE: return (end_x > start_x || (end_x == start_x && end_y > start_y)); + + case HT_RECT: + case HT_POINT: return (end_x != start_x && end_y < start_y); + default: NOT_REACHED(); + } + + return false; +} + +/** + * Calculates height difference between one tile and another. + * Multiplies the result to suit the standard given by #TILE_HEIGHT_STEP. + * + * To correctly get the height difference we need the direction we are dragging + * in, as well as with what kind of tool we are dragging. For example a horizontal + * autorail tool that starts in bottom and ends at the top of a tile will need the + * maximum of SW, S and SE, N corners respectively. This is handled by the lookup table below + * See #_tileoffs_by_dir in map.cpp for the direction enums if you can't figure out the values yourself. + * @param style Highlighting style of the drag. This includes direction and style (autorail, rect, etc.) + * @param distance Number of tiles dragged, important for horizontal/vertical drags, ignored for others. + * @param start_tile Start tile of the drag operation. + * @param end_tile End tile of the drag operation. + * @return Height difference between two tiles. The tile measurement tool utilizes this value in its tooltip. + */ +static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_tile, TileIndex end_tile) +{ + bool swap = SwapDirection(style, start_tile, end_tile); + uint h0, h1; // Start height and end height. + + if (start_tile == end_tile) return 0; + if (swap) Swap(start_tile, end_tile); + + switch (style & HT_DRAG_MASK) { + case HT_RECT: { + static const TileIndexDiffC heightdiff_area_by_dir[] = { + /* Start */ {1, 0}, /* Dragging east */ {0, 0}, // Dragging south + /* End */ {0, 1}, /* Dragging east */ {1, 1} // Dragging south + }; + + /* In the case of an area we can determine whether we were dragging south or + * east by checking the X-coordinates of the tiles */ + byte style_t = (byte)(TileX(end_tile) > TileX(start_tile)); + start_tile = TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_area_by_dir[style_t])); + end_tile = TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_area_by_dir[2 + style_t])); + /* FALL THROUGH */ + } + + case HT_POINT: + h0 = TileHeight(start_tile); + h1 = TileHeight(end_tile); + break; + default: { // All other types, this is mostly only line/autorail + static const HighLightStyle flip_style_direction[] = { + HT_DIR_X, HT_DIR_Y, HT_DIR_HL, HT_DIR_HU, HT_DIR_VR, HT_DIR_VL + }; + static const TileIndexDiffC heightdiff_line_by_dir[] = { + /* Start */ {1, 0}, {1, 1}, /* HT_DIR_X */ {0, 1}, {1, 1}, // HT_DIR_Y + /* Start */ {1, 0}, {0, 0}, /* HT_DIR_HU */ {1, 0}, {1, 1}, // HT_DIR_HL + /* Start */ {1, 0}, {1, 1}, /* HT_DIR_VL */ {0, 1}, {1, 1}, // HT_DIR_VR + + /* Start */ {0, 1}, {0, 0}, /* HT_DIR_X */ {1, 0}, {0, 0}, // HT_DIR_Y + /* End */ {0, 1}, {0, 0}, /* HT_DIR_HU */ {1, 1}, {0, 1}, // HT_DIR_HL + /* End */ {1, 0}, {0, 0}, /* HT_DIR_VL */ {0, 0}, {0, 1}, // HT_DIR_VR + }; + + distance %= 2; // we're only interested if the distance is even or uneven + style &= HT_DIR_MASK; + + /* To handle autorail, we do some magic to be able to use a lookup table. + * Firstly if we drag the other way around, we switch start&end, and if needed + * also flip the drag-position. Eg if it was on the left, and the distance is even + * that means the end, which is now the start is on the right */ + if (swap && distance == 0) style = flip_style_direction[style]; + + /* Use lookup table for start-tile based on HighLightStyle direction */ + byte style_t = style * 2; + assert(style_t < lengthof(heightdiff_line_by_dir) - 13); + h0 = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t]))); + uint ht = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t + 1]))); + h0 = max(h0, ht); + + /* Use lookup table for end-tile based on HighLightStyle direction + * flip around side (lower/upper, left/right) based on distance */ + if (distance == 0) style_t = flip_style_direction[style] * 2; + assert(style_t < lengthof(heightdiff_line_by_dir) - 13); + h1 = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t]))); + ht = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t + 1]))); + h1 = max(h1, ht); + break; + } + } + + if (swap) Swap(h0, h1); + return (int)(h1 - h0) * TILE_HEIGHT_STEP; +} + +static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF}; + +/** + * Check for underflowing the map. + * @param test the variable to test for underflowing + * @param other the other variable to update to keep the line + * @param mult the constant to multiply the difference by for \c other + */ +static void CheckUnderflow(int &test, int &other, int mult) +{ + if (test >= 0) return; + + other += mult * test; + test = 0; +} + +/** + * Check for overflowing the map. + * @param test the variable to test for overflowing + * @param other the other variable to update to keep the line + * @param max the maximum value for the \c test variable + * @param mult the constant to multiply the difference by for \c other + */ +static void CheckOverflow(int &test, int &other, int max, int mult) +{ + if (test <= max) return; + + other += mult * (test - max); + test = max; +} + +/** while dragging */ +static void CalcRaildirsDrawstyle(int x, int y, int method) +{ + HighLightStyle b; + + int dx = _thd.selstart.x - (_thd.selend.x & ~TILE_UNIT_MASK); + int dy = _thd.selstart.y - (_thd.selend.y & ~TILE_UNIT_MASK); + uint w = abs(dx) + TILE_SIZE; + uint h = abs(dy) + TILE_SIZE; + + if (method & ~(VPM_RAILDIRS | VPM_SIGNALDIRS)) { + /* We 'force' a selection direction; first four rail buttons. */ + method &= ~(VPM_RAILDIRS | VPM_SIGNALDIRS); + int raw_dx = _thd.selstart.x - _thd.selend.x; + int raw_dy = _thd.selstart.y - _thd.selend.y; + switch (method) { + case VPM_FIX_X: + b = HT_LINE | HT_DIR_Y; + x = _thd.selstart.x; + break; + + case VPM_FIX_Y: + b = HT_LINE | HT_DIR_X; + y = _thd.selstart.y; + break; + + case VPM_FIX_HORIZONTAL: + if (dx == -dy) { + /* We are on a straight horizontal line. Determine the 'rail' + * to build based the sub tile location. */ + b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU; + } else { + /* We are not on a straight line. Determine the rail to build + * based on whether we are above or below it. */ + b = dx + dy >= (int)TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL; + + /* Calculate where a horizontal line through the start point and + * a vertical line from the selected end point intersect and + * use that point as the end point. */ + int offset = (raw_dx - raw_dy) / 2; + x = _thd.selstart.x - (offset & ~TILE_UNIT_MASK); + y = _thd.selstart.y + (offset & ~TILE_UNIT_MASK); + + /* 'Build' the last half rail tile if needed */ + if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) { + if (dx + dy >= (int)TILE_SIZE) { + x += (dx + dy < 0) ? (int)TILE_SIZE : -(int)TILE_SIZE; + } else { + y += (dx + dy < 0) ? (int)TILE_SIZE : -(int)TILE_SIZE; + } + } + + /* Make sure we do not overflow the map! */ + CheckUnderflow(x, y, 1); + CheckUnderflow(y, x, 1); + CheckOverflow(x, y, (MapMaxX() - 1) * TILE_SIZE, 1); + CheckOverflow(y, x, (MapMaxY() - 1) * TILE_SIZE, 1); + assert(x >= 0 && y >= 0 && x <= (int)(MapMaxX() * TILE_SIZE) && y <= (int)(MapMaxY() * TILE_SIZE)); + } + break; + + case VPM_FIX_VERTICAL: + if (dx == dy) { + /* We are on a straight vertical line. Determine the 'rail' + * to build based the sub tile location. */ + b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; + } else { + /* We are not on a straight line. Determine the rail to build + * based on whether we are left or right from it. */ + b = dx < dy ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; + + /* Calculate where a vertical line through the start point and + * a horizontal line from the selected end point intersect and + * use that point as the end point. */ + int offset = (raw_dx + raw_dy + (int)TILE_SIZE) / 2; + x = _thd.selstart.x - (offset & ~TILE_UNIT_MASK); + y = _thd.selstart.y - (offset & ~TILE_UNIT_MASK); + + /* 'Build' the last half rail tile if needed */ + if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) { + if (dx - dy < 0) { + y += (dx > dy) ? (int)TILE_SIZE : -(int)TILE_SIZE; + } else { + x += (dx < dy) ? (int)TILE_SIZE : -(int)TILE_SIZE; + } + } + + /* Make sure we do not overflow the map! */ + CheckUnderflow(x, y, -1); + CheckUnderflow(y, x, -1); + CheckOverflow(x, y, (MapMaxX() - 1) * TILE_SIZE, -1); + CheckOverflow(y, x, (MapMaxY() - 1) * TILE_SIZE, -1); + assert(x >= 0 && y >= 0 && x <= (int)(MapMaxX() * TILE_SIZE) && y <= (int)(MapMaxY() * TILE_SIZE)); + } + break; + + default: + NOT_REACHED(); + } + } else if (TileVirtXY(_thd.selstart.x, _thd.selstart.y) == TileVirtXY(x, y)) { // check if we're only within one tile + if (method & VPM_RAILDIRS) { + b = GetAutorailHT(x, y); + } else { // rect for autosignals on one tile + b = HT_RECT; + } + } else if (h == TILE_SIZE) { // Is this in X direction? + if (dx == (int)TILE_SIZE) { // 2x1 special handling + b = (Check2x1AutoRail(3)) | HT_LINE; + } else if (dx == -(int)TILE_SIZE) { + b = (Check2x1AutoRail(2)) | HT_LINE; + } else { + b = HT_LINE | HT_DIR_X; + } + y = _thd.selstart.y; + } else if (w == TILE_SIZE) { // Or Y direction? + if (dy == (int)TILE_SIZE) { // 2x1 special handling + b = (Check2x1AutoRail(1)) | HT_LINE; + } else if (dy == -(int)TILE_SIZE) { // 2x1 other direction + b = (Check2x1AutoRail(0)) | HT_LINE; + } else { + b = HT_LINE | HT_DIR_Y; + } + x = _thd.selstart.x; + } else if (w > h * 2) { // still count as x dir? + b = HT_LINE | HT_DIR_X; + y = _thd.selstart.y; + } else if (h > w * 2) { // still count as y dir? + b = HT_LINE | HT_DIR_Y; + x = _thd.selstart.x; + } else { // complicated direction + int d = w - h; + _thd.selend.x = _thd.selend.x & ~TILE_UNIT_MASK; + _thd.selend.y = _thd.selend.y & ~TILE_UNIT_MASK; + + /* four cases. */ + if (x > _thd.selstart.x) { + if (y > _thd.selstart.y) { + /* south */ + if (d == 0) { + b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; + } else if (d >= 0) { + x = _thd.selstart.x + h; + b = HT_LINE | HT_DIR_VL; + } else { + y = _thd.selstart.y + w; + b = HT_LINE | HT_DIR_VR; + } + } else { + /* west */ + if (d == 0) { + b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU; + } else if (d >= 0) { + x = _thd.selstart.x + h; + b = HT_LINE | HT_DIR_HL; + } else { + y = _thd.selstart.y - w; + b = HT_LINE | HT_DIR_HU; + } + } + } else { + if (y > _thd.selstart.y) { + /* east */ + if (d == 0) { + b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU; + } else if (d >= 0) { + x = _thd.selstart.x - h; + b = HT_LINE | HT_DIR_HU; + } else { + y = _thd.selstart.y + w; + b = HT_LINE | HT_DIR_HL; + } + } else { + /* north */ + if (d == 0) { + b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; + } else if (d >= 0) { + x = _thd.selstart.x - h; + b = HT_LINE | HT_DIR_VR; + } else { + y = _thd.selstart.y - w; + b = HT_LINE | HT_DIR_VL; + } + } + } + } + + if (_settings_client.gui.measure_tooltip) { + TileIndex t0 = TileVirtXY(_thd.selstart.x, _thd.selstart.y); + TileIndex t1 = TileVirtXY(x, y); + uint distance = DistanceManhattan(t0, t1) + 1; + byte index = 0; + uint64 params[2]; + + if (distance != 1) { + int heightdiff = CalcHeightdiff(b, distance, t0, t1); + /* If we are showing a tooltip for horizontal or vertical drags, + * 2 tiles have a length of 1. To bias towards the ceiling we add + * one before division. It feels more natural to count 3 lengths as 2 */ + if ((b & HT_DIR_MASK) != HT_DIR_X && (b & HT_DIR_MASK) != HT_DIR_Y) { + distance = CeilDiv(distance, 2); + } + + params[index++] = distance; + if (heightdiff != 0) params[index++] = heightdiff; + } + + ShowMeasurementTooltips(measure_strings_length[index], index, params); + } + + _thd.selend.x = x; + _thd.selend.y = y; + _thd.next_drawstyle = b; +} + +/** + * Selects tiles while dragging + * @param x X coordinate of end of selection + * @param y Y coordinate of end of selection + * @param method modifies the way tiles are selected. Possible + * methods are VPM_* in viewport.h + */ +void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method) +{ + int sx, sy; + HighLightStyle style; + + if (x == -1) { + _thd.selend.x = -1; + return; + } + + /* Special handling of drag in any (8-way) direction */ + if (method & (VPM_RAILDIRS | VPM_SIGNALDIRS)) { + _thd.selend.x = x; + _thd.selend.y = y; + CalcRaildirsDrawstyle(x, y, method); + return; + } + + /* Needed so level-land is placed correctly */ + if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_POINT) { + x += TILE_SIZE / 2; + y += TILE_SIZE / 2; + } + + sx = _thd.selstart.x; + sy = _thd.selstart.y; + + int limit = 0; + + switch (method) { + case VPM_X_OR_Y: // drag in X or Y direction + if (abs(sy - y) < abs(sx - x)) { + y = sy; + style = HT_DIR_X; + } else { + x = sx; + style = HT_DIR_Y; + } + goto calc_heightdiff_single_direction; + + case VPM_X_LIMITED: // Drag in X direction (limited size). + limit = (_thd.sizelimit - 1) * TILE_SIZE; + /* FALL THROUGH */ + + case VPM_FIX_X: // drag in Y direction + x = sx; + style = HT_DIR_Y; + goto calc_heightdiff_single_direction; + + case VPM_Y_LIMITED: // Drag in Y direction (limited size). + limit = (_thd.sizelimit - 1) * TILE_SIZE; + /* FALL THROUGH */ + + case VPM_FIX_Y: // drag in X direction + y = sy; + style = HT_DIR_X; + +calc_heightdiff_single_direction:; + if (limit > 0) { + x = sx + Clamp(x - sx, -limit, limit); + y = sy + Clamp(y - sy, -limit, limit); + } + if (_settings_client.gui.measure_tooltip) { + TileIndex t0 = TileVirtXY(sx, sy); + TileIndex t1 = TileVirtXY(x, y); + uint distance = DistanceManhattan(t0, t1) + 1; + byte index = 0; + uint64 params[2]; + + if (distance != 1) { + /* With current code passing a HT_LINE style to calculate the height + * difference is enough. However if/when a point-tool is created + * with this method, function should be called with new_style (below) + * instead of HT_LINE | style case HT_POINT is handled specially + * new_style := (_thd.next_drawstyle & HT_RECT) ? HT_LINE | style : _thd.next_drawstyle; */ + int heightdiff = CalcHeightdiff(HT_LINE | style, 0, t0, t1); + + params[index++] = distance; + if (heightdiff != 0) params[index++] = heightdiff; + } + + ShowMeasurementTooltips(measure_strings_length[index], index, params); + } + break; + + case VPM_X_AND_Y_LIMITED: // Drag an X by Y constrained rect area. + limit = (_thd.sizelimit - 1) * TILE_SIZE; + x = sx + Clamp(x - sx, -limit, limit); + y = sy + Clamp(y - sy, -limit, limit); + /* FALL THROUGH */ + + case VPM_X_AND_Y: // drag an X by Y area + if (_settings_client.gui.measure_tooltip) { + static const StringID measure_strings_area[] = { + STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF + }; + + TileIndex t0 = TileVirtXY(sx, sy); + TileIndex t1 = TileVirtXY(x, y); + uint dx = Delta(TileX(t0), TileX(t1)) + 1; + uint dy = Delta(TileY(t0), TileY(t1)) + 1; + byte index = 0; + uint64 params[3]; + + /* If dragging an area (eg dynamite tool) and it is actually a single + * row/column, change the type to 'line' to get proper calculation for height */ + style = (HighLightStyle)_thd.next_drawstyle; + if (_thd.IsDraggingDiagonal()) { + /* Determine the "area" of the diagonal dragged selection. + * We assume the area is the number of tiles along the X + * edge and the number of tiles along the Y edge. However, + * multiplying these two numbers does not give the exact + * number of tiles; basically we are counting the black + * squares on a chess board and ignore the white ones to + * make the tile counts at the edges match up. There is no + * other way to make a proper count though. + * + * First convert to the rotated coordinate system. */ + int dist_x = TileX(t0) - TileX(t1); + int dist_y = TileY(t0) - TileY(t1); + int a_max = dist_x + dist_y; + int b_max = dist_y - dist_x; + + /* Now determine the size along the edge, but due to the + * chess board principle this counts double. */ + a_max = abs(a_max + (a_max > 0 ? 2 : -2)) / 2; + b_max = abs(b_max + (b_max > 0 ? 2 : -2)) / 2; + + /* We get a 1x1 on normal 2x1 rectangles, due to it being + * a seen as two sides. As the result for actual building + * will be the same as non-diagonal dragging revert to that + * behaviour to give it a more normally looking size. */ + if (a_max != 1 || b_max != 1) { + dx = a_max; + dy = b_max; + } + } else if (style & HT_RECT) { + if (dx == 1) { + style = HT_LINE | HT_DIR_Y; + } else if (dy == 1) { + style = HT_LINE | HT_DIR_X; + } + } + + if (dx != 1 || dy != 1) { + int heightdiff = CalcHeightdiff(style, 0, t0, t1); + + params[index++] = dx - (style & HT_POINT ? 1 : 0); + params[index++] = dy - (style & HT_POINT ? 1 : 0); + if (heightdiff != 0) params[index++] = heightdiff; + } + + ShowMeasurementTooltips(measure_strings_area[index], index, params); + } + break; + + default: NOT_REACHED(); + } + + _thd.selend.x = x; + _thd.selend.y = y; +} + +/** + * Handle the mouse while dragging for placement/resizing. + * @return State of handling the event. + */ +EventState VpHandlePlaceSizingDrag() +{ + if (_special_mouse_mode != WSM_SIZING) return ES_NOT_HANDLED; + + /* stop drag mode if the window has been closed */ + Window *w = _thd.GetCallbackWnd(); + if (w == NULL) { + ResetObjectToPlace(); + return ES_HANDLED; + } + + /* while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ) */ + if (_left_button_down) { + w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor()); + return ES_HANDLED; + } + + /* mouse button released.. + * keep the selected tool, but reset it to the original mode. */ + _special_mouse_mode = WSM_NONE; + HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK); + if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_RECT) { + _thd.place_mode = HT_RECT | others; + } else if (_thd.select_method & VPM_SIGNALDIRS) { + _thd.place_mode = HT_RECT | others; + } else if (_thd.select_method & VPM_RAILDIRS) { + _thd.place_mode = (_thd.select_method & ~VPM_RAILDIRS) ? _thd.next_drawstyle : (HT_RAIL | others); + } else { + _thd.place_mode = HT_POINT | others; + } + SetTileSelectSize(1, 1); + + w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y)); + + return ES_HANDLED; +} + +void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w) +{ + SetObjectToPlace(icon, pal, mode, w->window_class, w->window_number); +} + +#include "table/animcursors.h" + +void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num) +{ + if (_thd.window_class != WC_INVALID) { + /* Undo clicking on button and drag & drop */ + Window *w = _thd.GetCallbackWnd(); + /* Call the abort function, but set the window class to something + * that will never be used to avoid infinite loops. Setting it to + * the 'next' window class must not be done because recursion into + * this function might in some cases reset the newly set object to + * place or not properly reset the original selection. */ + _thd.window_class = WC_INVALID; + if (w != NULL) w->OnPlaceObjectAbort(); + } + + /* Mark the old selection dirty, in case the selection shape or colour changes */ + if ((_thd.drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty(); + + SetTileSelectSize(1, 1); + + _thd.make_square_red = false; + + if (mode == HT_DRAG) { // HT_DRAG is for dragdropping trains in the depot window + mode = HT_NONE; + _special_mouse_mode = WSM_DRAGDROP; + } else { + _special_mouse_mode = WSM_NONE; + } + + _thd.place_mode = mode; + _thd.window_class = window_class; + _thd.window_number = window_num; + + if ((mode & HT_DRAG_MASK) == HT_SPECIAL) { // special tools, like tunnels or docks start with presizing mode + VpStartPreSizing(); + } + + if ((icon & ANIMCURSOR_FLAG) != 0) { + SetAnimatedMouseCursor(_animcursors[icon & ~ANIMCURSOR_FLAG]); + } else { + SetMouseCursor(icon, pal); + } + +} + +void ResetObjectToPlace() +{ + SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0); +} + +Point GetViewportStationMiddle(const ViewPort *vp, const Station *st) +{ + int x = TileX(st->xy) * TILE_SIZE; + int y = TileY(st->xy) * TILE_SIZE; + int z = GetSlopePixelZ(Clamp(x, 0, MapSizeX() * TILE_SIZE - 1), Clamp(y, 0, MapSizeY() * TILE_SIZE - 1)); + + Point p = RemapCoords(x, y, z); + p.x = UnScaleByZoom(p.x - vp->virtual_left, vp->zoom) + vp->left; + p.y = UnScaleByZoom(p.y - vp->virtual_top, vp->zoom) + vp->top; + return p; +} + +/** Helper class for getting the best sprite sorter. */ +struct ViewportSSCSS { + VpSorterChecker fct_checker; ///< The check function. + VpSpriteSorter fct_sorter; ///< The sorting function. +}; + +/** List of sorters ordered from best to worst. */ +static ViewportSSCSS _vp_sprite_sorters[] = { +#ifdef WITH_SSE + { &ViewportSortParentSpritesSSE41Checker, &ViewportSortParentSpritesSSE41 }, +#endif + { &ViewportSortParentSpritesChecker, &ViewportSortParentSprites } +}; + +/** Choose the "best" sprite sorter and set _vp_sprite_sorter. */ +void InitializeSpriteSorter() +{ + for (uint i = 0; i < lengthof(_vp_sprite_sorters); i++) { + if (_vp_sprite_sorters[i].fct_checker()) { + _vp_sprite_sorter = _vp_sprite_sorters[i].fct_sorter; + break; + } + } + assert(_vp_sprite_sorter != NULL); +} diff --git a/src/widget.cpp.orig b/src/widget.cpp.orig new file mode 100644 index 0000000000..1ead186b78 --- /dev/null +++ b/src/widget.cpp.orig @@ -0,0 +1,2938 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file widget.cpp Handling of the default/simple widgets. */ + +#include "stdafx.h" +#include "company_func.h" +#include "window_gui.h" +#include "viewport_func.h" +#include "zoom_func.h" +#include "strings_func.h" +#include "transparency.h" +#include "core/geometry_func.hpp" +#include "settings_type.h" +#include "querystring_gui.h" + +#include "table/sprites.h" +#include "table/strings.h" +#include "table/palettes.h" + +static const char *UPARROW = "\xEE\x8A\xA0"; ///< String containing an upwards pointing arrow. +static const char *DOWNARROW = "\xEE\x8A\xAA"; ///< String containing a downwards pointing arrow. + +/** + * Compute the vertical position of the draggable part of scrollbar + * @param sb Scrollbar list data + * @param top Top position of the scrollbar (top position of the up-button) + * @param bottom Bottom position of the scrollbar (bottom position of the down-button) + * @param horizontal Whether the scrollbar is horizontal or not + * @return A Point, with x containing the top coordinate of the draggable part, and + * y containing the bottom coordinate of the draggable part + */ +static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom, bool horizontal) +{ + /* Base for reversion */ + int rev_base = top + bottom; + int button_size; + if (horizontal) { + button_size = NWidgetScrollbar::GetHorizontalDimension().width; + } else { + button_size = NWidgetScrollbar::GetVerticalDimension().height; + } + top += button_size; // top points to just below the up-button + bottom -= button_size; // bottom points to top of the down-button + + int height = (bottom - top); + int pos = sb->GetPosition(); + int count = sb->GetCount(); + int cap = sb->GetCapacity(); + + if (count != 0) top += height * pos / count; + + if (cap > count) cap = count; + if (count != 0) bottom -= (count - pos - cap) * height / count; + + Point pt; + if (horizontal && _current_text_dir == TD_RTL) { + pt.x = rev_base - bottom; + pt.y = rev_base - top; + } else { + pt.x = top; + pt.y = bottom; + } + return pt; +} + +/** + * Compute new position of the scrollbar after a click and updates the window flags. + * @param w Window on which a scroll was performed. + * @param sb Scrollbar + * @param mi Minimum coordinate of the scroll bar. + * @param ma Maximum coordinate of the scroll bar. + * @param x The X coordinate of the mouse click. + * @param y The Y coordinate of the mouse click. + */ +static void ScrollbarClickPositioning(Window *w, NWidgetScrollbar *sb, int x, int y, int mi, int ma) +{ + int pos; + int button_size; + bool rtl = false; + + if (sb->type == NWID_HSCROLLBAR) { + pos = x; + rtl = _current_text_dir == TD_RTL; + button_size = NWidgetScrollbar::GetHorizontalDimension().width; + } else { + pos = y; + button_size = NWidgetScrollbar::GetVerticalDimension().height; + } + if (pos < mi + button_size) { + /* Pressing the upper button? */ + SetBit(sb->disp_flags, NDB_SCROLLBAR_UP); + if (_scroller_click_timeout <= 1) { + _scroller_click_timeout = 3; + sb->UpdatePosition(rtl ? 1 : -1); + } + w->scrolling_scrollbar = sb->index; + } else if (pos >= ma - button_size) { + /* Pressing the lower button? */ + SetBit(sb->disp_flags, NDB_SCROLLBAR_DOWN); + + if (_scroller_click_timeout <= 1) { + _scroller_click_timeout = 3; + sb->UpdatePosition(rtl ? -1 : 1); + } + w->scrolling_scrollbar = sb->index; + } else { + Point pt = HandleScrollbarHittest(sb, mi, ma, sb->type == NWID_HSCROLLBAR); + + if (pos < pt.x) { + sb->UpdatePosition(rtl ? 1 : -1, Scrollbar::SS_BIG); + } else if (pos > pt.y) { + sb->UpdatePosition(rtl ? -1 : 1, Scrollbar::SS_BIG); + } else { + _scrollbar_start_pos = pt.x - mi - button_size; + _scrollbar_size = ma - mi - button_size * 2; + w->scrolling_scrollbar = sb->index; + _cursorpos_drag_start = _cursor.pos; + } + } + + w->SetDirty(); +} + +/** + * Special handling for the scrollbar widget type. + * Handles the special scrolling buttons and other scrolling. + * @param w Window on which a scroll was performed. + * @param nw Pointer to the scrollbar widget. + * @param x The X coordinate of the mouse click. + * @param y The Y coordinate of the mouse click. + */ +void ScrollbarClickHandler(Window *w, NWidgetCore *nw, int x, int y) +{ + int mi, ma; + + if (nw->type == NWID_HSCROLLBAR) { + mi = nw->pos_x; + ma = nw->pos_x + nw->current_x; + } else { + mi = nw->pos_y; + ma = nw->pos_y + nw->current_y; + } + NWidgetScrollbar *scrollbar = dynamic_cast(nw); + assert(scrollbar != NULL); + ScrollbarClickPositioning(w, scrollbar, x, y, mi, ma); +} + +/** + * Returns the index for the widget located at the given position + * relative to the window. It includes all widget-corner pixels as well. + * @param *w Window to look inside + * @param x The Window client X coordinate + * @param y The Window client y coordinate + * @return A widget index, or -1 if no widget was found. + */ +int GetWidgetFromPos(const Window *w, int x, int y) +{ + NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y); + return (nw != NULL) ? nw->index : -1; +} + +/** + * Draw frame rectangle. + * @param left Left edge of the frame + * @param top Top edge of the frame + * @param right Right edge of the frame + * @param bottom Bottom edge of the frame + * @param colour Colour table to use. @see _colour_gradient + * @param flags Flags controlling how to draw the frame. @see FrameFlags + */ +void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags) +{ + assert(colour < COLOUR_END); + + uint dark = _colour_gradient[colour][3]; + uint medium_dark = _colour_gradient[colour][5]; + uint medium_light = _colour_gradient[colour][6]; + uint light = _colour_gradient[colour][7]; + + if (flags & FR_TRANSPARENT) { + GfxFillRect(left, top, right, bottom, PALETTE_TO_TRANSPARENT, FILLRECT_RECOLOUR); + } else { + uint interior; + + if (flags & FR_LOWERED) { + GfxFillRect(left, top, left, bottom, dark); + GfxFillRect(left + WD_BEVEL_LEFT, top, right, top, dark); + GfxFillRect(right, top + WD_BEVEL_TOP, right, bottom - WD_BEVEL_BOTTOM, light); + GfxFillRect(left + WD_BEVEL_LEFT, bottom, right, bottom, light); + interior = (flags & FR_DARKENED ? medium_dark : medium_light); + } else { + GfxFillRect(left, top, left, bottom - WD_BEVEL_BOTTOM, light); + GfxFillRect(left + WD_BEVEL_LEFT, top, right - WD_BEVEL_RIGHT, top, light); + GfxFillRect(right, top, right, bottom - WD_BEVEL_BOTTOM, dark); + GfxFillRect(left, bottom, right, bottom, dark); + interior = medium_dark; + } + if (!(flags & FR_BORDERONLY)) { + GfxFillRect(left + WD_BEVEL_LEFT, top + WD_BEVEL_TOP, right - WD_BEVEL_RIGHT, bottom - WD_BEVEL_BOTTOM, interior); + } + } +} + +/** + * Draw an image button. + * @param r Rectangle of the button. + * @param type Widget type (#WWT_IMGBTN or #WWT_IMGBTN_2). + * @param colour Colour of the button. + * @param clicked Button is lowered. + * @param img Sprite to draw. + */ +static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colour, bool clicked, SpriteID img) +{ + assert(img != 0); + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); + + if ((type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++; // Show different image when clicked for #WWT_IMGBTN_2. + Dimension d2 = GetSpriteSize(img); + DrawSprite(img, PAL_NONE, Center(r.left + clicked, r.right - r.left, d2.width), Center(r.top + clicked, r.bottom - r.top, d2.height)); +} + +/** + * Draw the label-part of a widget. + * @param r Rectangle of the label background. + * @param type Widget type (#WWT_TEXTBTN, #WWT_TEXTBTN_2, or #WWT_LABEL). + * @param clicked Label is rendered lowered. + * @param str Text to draw. + */ +static inline void DrawLabel(const Rect &r, WidgetType type, bool clicked, StringID str) +{ + if (str == STR_NULL) return; + if ((type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++; + Dimension d = GetStringBoundingBox(str); + int offset = max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered + DrawString(r.left + clicked, r.right + clicked, r.top + offset + clicked, str, TC_FROMSTRING, SA_HOR_CENTER); +} + +/** + * Draw text. + * @param r Rectangle of the background. + * @param colour Colour of the text. + * @param str Text to draw. + */ +static inline void DrawText(const Rect &r, TextColour colour, StringID str) +{ + Dimension d = GetStringBoundingBox(str); + int offset = max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered + if (str != STR_NULL) DrawString(r.left, r.right, r.top + offset, str, colour); +} + +/** + * Draw an inset widget. + * @param r Rectangle of the background. + * @param colour Colour of the inset. + * @param str Text to draw. + */ +static inline void DrawInset(const Rect &r, Colours colour, StringID str) +{ + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_LOWERED | FR_DARKENED); + if (str != STR_NULL) DrawString(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + WD_INSET_TOP, str); +} + +/** + * Draw a matrix widget. + * @param r Rectangle of the matrix background. + * @param colour Colour of the background. + * @param clicked Matrix is rendered lowered. + * @param data Data of the widget, number of rows and columns of the widget. + * @param resize_x Matrix resize unit size. + * @param resize_y Matrix resize unit size. + */ +static inline void DrawMatrix(const Rect &r, Colours colour, bool clicked, uint16 data, uint resize_x, uint resize_y) +{ + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); + + int num_columns = GB(data, MAT_COL_START, MAT_COL_BITS); // Lower 8 bits of the widget data: Number of columns in the matrix. + int column_width; // Width of a single column in the matrix. + if (num_columns == 0) { + column_width = resize_x; + num_columns = (r.right - r.left + 1) / column_width; + } else { + column_width = (r.right - r.left + 1) / num_columns; + } + + int num_rows = GB(data, MAT_ROW_START, MAT_ROW_BITS); // Upper 8 bits of the widget data: Number of rows in the matrix. + int row_height; // Height of a single row in the matrix. + if (num_rows == 0) { + row_height = resize_y; + num_rows = (r.bottom - r.top + 1) / row_height; + } else { + row_height = (r.bottom - r.top + 1) / num_rows; + } + + int col = _colour_gradient[colour & 0xF][6]; + + int x = r.left; + for (int ctr = num_columns; ctr > 1; ctr--) { + x += column_width; + GfxFillRect(x, r.top + 1, x, r.bottom - 1, col); + } + + x = r.top; + for (int ctr = num_rows; ctr > 1; ctr--) { + x += row_height; + GfxFillRect(r.left + 1, x, r.right - 1, x, col); + } + + col = _colour_gradient[colour & 0xF][4]; + + x = r.left - 1; + for (int ctr = num_columns; ctr > 1; ctr--) { + x += column_width; + GfxFillRect(x, r.top + 1, x, r.bottom - 1, col); + } + + x = r.top - 1; + for (int ctr = num_rows; ctr > 1; ctr--) { + x += row_height; + GfxFillRect(r.left + 1, x, r.right - 1, x, col); + } +} + +/** + * Draw a vertical scrollbar. + * @param r Rectangle of the scrollbar widget. + * @param colour Colour of the scrollbar widget. + * @param up_clicked Up-arrow is clicked. + * @param bar_dragged Bar is dragged. + * @param down_clicked Down-arrow is clicked. + * @param scrollbar Scrollbar size, offset, and capacity information. + */ +static inline void DrawVerticalScrollbar(const Rect &r, Colours colour, bool up_clicked, bool bar_dragged, bool down_clicked, const Scrollbar *scrollbar) +{ + int centre = (r.right - r.left) / 2; + int height = NWidgetScrollbar::GetVerticalDimension().height; + + /* draw up/down buttons */ + DrawFrameRect(r.left, r.top, r.right, r.top + height - 1, colour, (up_clicked) ? FR_LOWERED : FR_NONE); + DrawString(r.left + up_clicked, r.right + up_clicked, r.top + up_clicked, UPARROW, TC_BLACK, SA_HOR_CENTER); + + DrawFrameRect(r.left, r.bottom - (height - 1), r.right, r.bottom, colour, (down_clicked) ? FR_LOWERED : FR_NONE); + DrawString(r.left + down_clicked, r.right + down_clicked, r.bottom - (height - 1) + down_clicked, DOWNARROW, TC_BLACK, SA_HOR_CENTER); + + int c1 = _colour_gradient[colour & 0xF][3]; + int c2 = _colour_gradient[colour & 0xF][7]; + + /* draw "shaded" background */ + GfxFillRect(r.left, r.top + height, r.right, r.bottom - height, c2); + GfxFillRect(r.left, r.top + height, r.right, r.bottom - height, c1, FILLRECT_CHECKER); + + /* draw shaded lines */ + GfxFillRect(r.left + centre - 3, r.top + height, r.left + centre - 3, r.bottom - height, c1); + GfxFillRect(r.left + centre - 2, r.top + height, r.left + centre - 2, r.bottom - height, c2); + GfxFillRect(r.left + centre + 2, r.top + height, r.left + centre + 2, r.bottom - height, c1); + GfxFillRect(r.left + centre + 3, r.top + height, r.left + centre + 3, r.bottom - height, c2); + + Point pt = HandleScrollbarHittest(scrollbar, r.top, r.bottom, false); + DrawFrameRect(r.left, pt.x, r.right, pt.y, colour, bar_dragged ? FR_LOWERED : FR_NONE); +} + +/** + * Draw a horizontal scrollbar. + * @param r Rectangle of the scrollbar widget. + * @param colour Colour of the scrollbar widget. + * @param left_clicked Left-arrow is clicked. + * @param bar_dragged Bar is dragged. + * @param right_clicked Right-arrow is clicked. + * @param scrollbar Scrollbar size, offset, and capacity information. + */ +static inline void DrawHorizontalScrollbar(const Rect &r, Colours colour, bool left_clicked, bool bar_dragged, bool right_clicked, const Scrollbar *scrollbar) +{ + int centre = (r.bottom - r.top) / 2; + int width = NWidgetScrollbar::GetHorizontalDimension().width; + + DrawFrameRect(r.left, r.top, r.left + width - 1, r.bottom, colour, left_clicked ? FR_LOWERED : FR_NONE); + DrawSprite(SPR_ARROW_LEFT, PAL_NONE, r.left + 1 + left_clicked, r.top + 1 + left_clicked); + + DrawFrameRect(r.right - (width - 1), r.top, r.right, r.bottom, colour, right_clicked ? FR_LOWERED : FR_NONE); + DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, r.right - (width - 2) + right_clicked, r.top + 1 + right_clicked); + + int c1 = _colour_gradient[colour & 0xF][3]; + int c2 = _colour_gradient[colour & 0xF][7]; + + /* draw "shaded" background */ + GfxFillRect(r.left + width, r.top, r.right - width, r.bottom, c2); + GfxFillRect(r.left + width, r.top, r.right - width, r.bottom, c1, FILLRECT_CHECKER); + + /* draw shaded lines */ + GfxFillRect(r.left + width, r.top + centre - 3, r.right - width, r.top + centre - 3, c1); + GfxFillRect(r.left + width, r.top + centre - 2, r.right - width, r.top + centre - 2, c2); + GfxFillRect(r.left + width, r.top + centre + 2, r.right - width, r.top + centre + 2, c1); + GfxFillRect(r.left + width, r.top + centre + 3, r.right - width, r.top + centre + 3, c2); + + /* draw actual scrollbar */ + Point pt = HandleScrollbarHittest(scrollbar, r.left, r.right, true); + DrawFrameRect(pt.x, r.top, pt.y, r.bottom, colour, bar_dragged ? FR_LOWERED : FR_NONE); +} + +/** + * Draw a frame widget. + * @param r Rectangle of the frame. + * @param colour Colour of the frame. + * @param str Text of the frame. + */ +static inline void DrawFrame(const Rect &r, Colours colour, StringID str) +{ + int x2 = r.left; // by default the left side is the left side of the widget + + if (str != STR_NULL) x2 = DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top, str); + + int c1 = _colour_gradient[colour][3]; + int c2 = _colour_gradient[colour][7]; + + /* If the frame has text, adjust the top bar to fit half-way through */ + int dy1 = 4; + if (str != STR_NULL) dy1 = FONT_HEIGHT_NORMAL / 2 - 1; + int dy2 = dy1 + 1; + + if (_current_text_dir == TD_LTR) { + /* Line from upper left corner to start of text */ + GfxFillRect(r.left, r.top + dy1, r.left + 4, r.top + dy1, c1); + GfxFillRect(r.left + 1, r.top + dy2, r.left + 4, r.top + dy2, c2); + + /* Line from end of text to upper right corner */ + GfxFillRect(x2, r.top + dy1, r.right - 1, r.top + dy1, c1); + GfxFillRect(x2, r.top + dy2, r.right - 2, r.top + dy2, c2); + } else { + /* Line from upper left corner to start of text */ + GfxFillRect(r.left, r.top + dy1, x2 - 2, r.top + dy1, c1); + GfxFillRect(r.left + 1, r.top + dy2, x2 - 2, r.top + dy2, c2); + + /* Line from end of text to upper right corner */ + GfxFillRect(r.right - 5, r.top + dy1, r.right - 1, r.top + dy1, c1); + GfxFillRect(r.right - 5, r.top + dy2, r.right - 2, r.top + dy2, c2); + } + + /* Line from upper left corner to bottom left corner */ + GfxFillRect(r.left, r.top + dy2, r.left, r.bottom - 1, c1); + GfxFillRect(r.left + 1, r.top + dy2 + 1, r.left + 1, r.bottom - 2, c2); + + /* Line from upper right corner to bottom right corner */ + GfxFillRect(r.right - 1, r.top + dy2, r.right - 1, r.bottom - 2, c1); + GfxFillRect(r.right, r.top + dy1, r.right, r.bottom - 1, c2); + + GfxFillRect(r.left + 1, r.bottom - 1, r.right - 1, r.bottom - 1, c1); + GfxFillRect(r.left, r.bottom, r.right, r.bottom, c2); +} + +/** + * Draw a resize box. + * @param r Rectangle of the box. + * @param colour Colour of the resize box. + * @param at_left Resize box is at left-side of the window, + * @param clicked Box is lowered. + */ +static inline void DrawResizeBox(const Rect &r, Colours colour, bool at_left, bool clicked) +{ + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); + Dimension d = GetSpriteSize(at_left ? SPR_WINDOW_RESIZE_LEFT : SPR_WINDOW_RESIZE_RIGHT); + if (at_left) { + DrawSprite(SPR_WINDOW_RESIZE_LEFT, PAL_NONE, r.left + WD_RESIZEBOX_LEFT + clicked, + r.bottom - WD_RESIZEBOX_BOTTOM - d.height + clicked); + } else { + DrawSprite(SPR_WINDOW_RESIZE_RIGHT, PAL_NONE, r.right - WD_RESIZEBOX_RIGHT - d.width + clicked, + r.bottom - WD_RESIZEBOX_BOTTOM - d.height + clicked); + } +} + +/** + * Draw a close box. + * @param r Rectangle of the box. + * @param colour Colour of the close box. + * @param str Cross to draw (#STR_BLACK_CROSS or #STR_SILVER_CROSS). + */ +static inline void DrawCloseBox(const Rect &r, Colours colour, StringID str) +{ + assert(str == STR_BLACK_CROSS || str == STR_SILVER_CROSS); // black or silver cross + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_NONE); + DrawString(r.left, r.right, r.top + WD_CLOSEBOX_TOP, str, TC_FROMSTRING, SA_HOR_CENTER); +} + +/** + * Draw a caption bar. + * @param r Rectangle of the bar. + * @param colour Colour of the window. + * @param owner 'Owner' of the window. + * @param str Text to draw in the bar. + */ +void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str) +{ + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_BORDERONLY); + DrawFrameRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, colour, (owner == INVALID_OWNER) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY); + + if (owner != INVALID_OWNER) { + GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, _colour_gradient[_company_colours[owner]][4]); + } + + if (str != STR_NULL) { + Dimension d = GetStringBoundingBox(str); + int offset = max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered + DrawString(r.left + WD_CAPTIONTEXT_LEFT, r.right - WD_CAPTIONTEXT_RIGHT, r.top + offset, str, TC_FROMSTRING, SA_HOR_CENTER); + } +} + +/** + * Draw a button with a dropdown (#WWT_DROPDOWN and #NWID_BUTTON_DROPDOWN). + * @param r Rectangle containing the widget. + * @param colour Background colour of the widget. + * @param clicked_button The button-part is lowered. + * @param clicked_dropdown The drop-down part is lowered. + * @param str Text of the button. + * + * @note Magic constants are also used in #NWidgetLeaf::ButtonHit. + */ +static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicked_button, bool clicked_dropdown, StringID str) +{ + int text_offset = max(0, ((int)(r.bottom - r.top + 1) - FONT_HEIGHT_NORMAL) / 2); // Offset for rendering the text vertically centered + + int dd_width = GetMinSizing(NWST_STEP, NWidgetLeaf::dropdown_dimension.width); + + if (_current_text_dir == TD_LTR) { + DrawFrameRect(r.left, r.top, r.right - dd_width, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); + DrawFrameRect(r.right + 1 - dd_width, r.top, r.right, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE); + DrawString(r.right - dd_width + (clicked_dropdown ? 2 : 1), r.right, r.top + (clicked_dropdown ? 2 : 1), DOWNARROW, TC_BLACK, SA_HOR_CENTER); + if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - dd_width - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK); + } else { + DrawFrameRect(r.left + dd_width, r.top, r.right, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); + DrawFrameRect(r.left, r.top, r.left + dd_width - 1, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE); + DrawString(r.left + (clicked_dropdown ? 2 : 1), r.left + dd_width, r.top + (clicked_dropdown ? 2 : 1), DOWNARROW, TC_BLACK, SA_HOR_CENTER); + if (str != STR_NULL) DrawString(r.left + dd_width + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK); + } +} + +/** + * Draw a dropdown #WWT_DROPDOWN widget. + * @param r Rectangle containing the widget. + * @param colour Background colour of the widget. + * @param clicked The widget is lowered. + * @param str Text of the button. + */ +static inline void DrawDropdown(const Rect &r, Colours colour, bool clicked, StringID str) +{ + DrawButtonDropdown(r, colour, false, clicked, str); +} + +/** + * Paint all widgets of a window. + */ +void Window::DrawWidgets() const +{ + this->nested_root->Draw(this); + + if (this->flags & WF_WHITE_BORDER) { + DrawFrameRect(0, 0, this->width - 1, this->height - 1, COLOUR_WHITE, FR_BORDERONLY); + } + + if (this->flags & WF_HIGHLIGHTED) { + extern bool _window_highlight_colour; + for (uint i = 0; i < this->nested_array_size; i++) { + const NWidgetBase *widget = this->GetWidget(i); + if (widget == NULL || !widget->IsHighlighted()) continue; + + int left = widget->pos_x; + int top = widget->pos_y; + int right = left + widget->current_x - 1; + int bottom = top + widget->current_y - 1; + + int colour = _string_colourmap[_window_highlight_colour ? widget->GetHighlightColour() : TC_WHITE]; + + GfxFillRect(left, top, left, bottom - WD_BEVEL_BOTTOM, colour); + GfxFillRect(left + WD_BEVEL_LEFT, top, right - WD_BEVEL_RIGHT, top, colour); + GfxFillRect(right, top, right, bottom - WD_BEVEL_BOTTOM, colour); + GfxFillRect(left, bottom, right, bottom, colour); + } + } +} + +/** + * Draw a sort button's up or down arrow symbol. + * @param widget Sort button widget + * @param state State of sort button + */ +void Window::DrawSortButtonState(int widget, SortButtonState state) const +{ + if (state == SBS_OFF) return; + + assert(this->nested_array != NULL); + const NWidgetBase *nwid = this->GetWidget(widget); + + int offset = this->IsWidgetLowered(widget) ? 1 : 0; + int base = offset + nwid->pos_x + (_current_text_dir == TD_LTR ? nwid->current_x - WD_SORTBUTTON_ARROW_WIDTH : 0); + int top = nwid->pos_y; + + DrawString(base, base + WD_SORTBUTTON_ARROW_WIDTH, top + 1 + offset, state == SBS_DOWN ? DOWNARROW : UPARROW, TC_BLACK, SA_HOR_CENTER); +} + + +/** + * @defgroup NestedWidgets Hierarchical widgets + * Hierarchical widgets, also known as nested widgets, are widgets stored in a tree. At the leafs of the tree are (mostly) the 'real' widgets + * visible to the user. At higher levels, widgets get organized in container widgets, until all widgets of the window are merged. + * + * \section nestedwidgetkinds Hierarchical widget kinds + * A leaf widget is one of + *
    + *
  • #NWidgetLeaf for widgets visible for the user, or + *
  • #NWidgetSpacer for creating (flexible) empty space between widgets. + *
+ * The purpose of a leaf widget is to provide interaction with the user by displaying settings, and/or allowing changing the settings. + * + * A container widget is one of + *
    + *
  • #NWidgetHorizontal for organizing child widgets in a (horizontal) row. The row switches order depending on the language setting (thus supporting + * right-to-left languages), + *
  • #NWidgetHorizontalLTR for organizing child widgets in a (horizontal) row, always in the same order. All children below this container will also + * never swap order. + *
  • #NWidgetVertical for organizing child widgets underneath each other. + *
  • #NWidgetMatrix for organizing child widgets in a matrix form. + *
  • #NWidgetBackground for adding a background behind its child widget. + *
  • #NWidgetStacked for stacking child widgets on top of each other. + *
+ * The purpose of a container widget is to structure its leafs and sub-containers to allow proper resizing. + * + * \section nestedwidgetscomputations Hierarchical widget computations + * The first 'computation' is the creation of the nested widgets tree by calling the constructors of the widgets listed above and calling \c Add() for every child, + * or by means of specifying the tree as a collection of nested widgets parts and instantiating the tree from the array. + * + * After the creation step, + * - The leafs have their own minimal size (\e min_x, \e min_y), filling (\e fill_x, \e fill_y), and resize steps (\e resize_x, \e resize_y). + * - Containers only know what their children are, \e fill_x, \e fill_y, \e resize_x, and \e resize_y are not initialized. + * + * Computations in the nested widgets take place as follows: + *
    + *
  1. A bottom-up sweep by recursively calling NWidgetBase::SetupSmallestSize() to initialize the smallest size (\e smallest_x, \e smallest_y) and + * to propagate filling and resize steps upwards to the root of the tree. + *
  2. A top-down sweep by recursively calling NWidgetBase::AssignSizePosition() with #ST_SMALLEST to make the smallest sizes consistent over + * the entire tree, and to assign the top-left (\e pos_x, \e pos_y) position of each widget in the tree. This step uses \e fill_x and \e fill_y at each + * node in the tree to decide how to fill each widget towards consistent sizes. Also the current size (\e current_x and \e current_y) is set. + *
  3. After initializing the smallest size in the widget tree with #ST_SMALLEST, the tree can be resized (the current size modified) by calling + * NWidgetBase::AssignSizePosition() at the root with #ST_RESIZE and the new size of the window. For proper functioning, the new size should be the smallest + * size + a whole number of resize steps in both directions (ie you can only resize in steps of length resize_{x,y} from smallest_{x,y}). + *
+ * After the second step, the current size of the widgets are set to the smallest size. + * + * To resize, perform the last step with the new window size. This can be done as often as desired. + * When the smallest size of at least one widget changes, the whole procedure has to be redone from the start. + * + * @see NestedWidgetParts + */ + +/** + * Base class constructor. + * @param tp Nested widget type. + */ +NWidgetBase::NWidgetBase(WidgetType tp) : ZeroedMemoryAllocator() +{ + this->type = tp; +} + +/* ~NWidgetContainer() takes care of #next and #prev data members. */ + +/** + * @fn void NWidgetBase::SetupSmallestSize(Window *w, bool init_array) + * Compute smallest size needed by the widget. + * + * The smallest size of a widget is the smallest size that a widget needs to + * display itself properly. In addition, filling and resizing of the widget are computed. + * The function calls #Window::UpdateWidgetSize for each leaf widget and + * background widget without child with a non-negative index. + * + * @param w Window owning the widget. + * @param init_array Initialize the \c w->nested_array. + * + * @note After the computation, the results can be queried by accessing the #smallest_x and #smallest_y data members of the widget. + */ + +/** + * @fn void NWidgetBase::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) + * Assign size and position to the widget. + * @param sizing Type of resizing to perform. + * @param x Horizontal offset of the widget relative to the left edge of the window. + * @param y Vertical offset of the widget relative to the top edge of the window. + * @param given_width Width allocated to the widget. + * @param given_height Height allocated to the widget. + * @param rtl Adapt for right-to-left languages (position contents of horizontal containers backwards). + * + * Afterwards, \e pos_x and \e pos_y contain the top-left position of the widget, \e smallest_x and \e smallest_y contain + * the smallest size such that all widgets of the window are consistent, and \e current_x and \e current_y contain the current size. + */ + +/** + * @fn void FillNestedArray(NWidgetBase **array, uint length) + * Fill the Window::nested_array array with pointers to nested widgets in the tree. + * @param array Base pointer of the array. + * @param length Length of the array. + */ + +/** + * @fn void NWidgetBase::Draw(const Window *w) + * Draw the widgets of the tree. + * The function calls #Window::DrawWidget for each widget with a non-negative index, after the widget itself is painted. + * @param w Window that owns the tree. + */ + +/** + * Mark the widget as 'dirty' (in need of repaint). + * @param w Window owning the widget. + */ +void NWidgetBase::SetDirty(const Window *w) const +{ + int abs_left = w->left + this->pos_x; + int abs_top = w->top + this->pos_y; + SetDirtyBlocks(abs_left, abs_top, abs_left + this->current_x, abs_top + this->current_y); +} + +/** + * @fn NWidgetCore *NWidgetBase::GetWidgetFromPos(int x, int y) + * Retrieve a widget by its position. + * @param x Horizontal position relative to the left edge of the window. + * @param y Vertical position relative to the top edge of the window. + * @return Returns the deepest nested widget that covers the given position, or \c NULL if no widget can be found. + */ + +/** + * Retrieve a widget by its type. + * @param tp Widget type to search for. + * @return Returns the first widget of the specified type, or \c NULL if no widget can be found. + */ +NWidgetBase *NWidgetBase::GetWidgetOfType(WidgetType tp) +{ + return (this->type == tp) ? this : NULL; +} + +/** + * Constructor for resizable nested widgets. + * @param tp Nested widget type. + * @param fill_x Horizontal fill step size, \c 0 means no filling is allowed. + * @param fill_y Vertical fill step size, \c 0 means no filling is allowed. + */ +NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : NWidgetBase(tp) +{ + this->sizing_type = NWST_NONE; + this->fill_x = fill_x; + this->fill_y = fill_y; +} + +/** + * Set minimal size of the widget. + * @param min_x Horizontal minimal size of the widget. + * @param min_y Vertical minimal size of the widget. + */ +void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y) +{ + uint min_size = 0; + switch (this->sizing_type) { + case NWST_NONE: + case NWST_OVERRIDE: + min_size = 0; + break; + case NWST_BUTTON: + min_size = _settings_client.gui.min_button; + break; + case NWST_STEP: + min_size = _settings_client.gui.min_step; + break; + case NWST_VIEWPORT: + min_size = 3 * _settings_client.gui.min_button; + break; + default: NOT_REACHED(); + } + + this->min_x = max(min_x, min_size); + this->min_y = max(min_y, min_size); +} + +/** + * Set minimal text lines for the widget. + * @param min_lines Number of text lines of the widget. + * @param spacing Extra spacing (eg WD_FRAMERECT_TOP + _BOTTOM) of the widget. + * @param size Font size of text. + */ +void NWidgetResizeBase::SetMinimalTextLines(uint8 min_lines, uint8 spacing, FontSize size) +{ + this->min_y = min_lines * GetCharacterHeight(size) + spacing; +} + +/** + * Set the filling of the widget from initial size. + * @param fill_x Horizontal fill step size, \c 0 means no filling is allowed. + * @param fill_y Vertical fill step size, \c 0 means no filling is allowed. + */ +void NWidgetResizeBase::SetFill(uint fill_x, uint fill_y) +{ + this->fill_x = fill_x; + this->fill_y = fill_y; +} + +/** + * Set resize step of the widget. + * @param resize_x Resize step in horizontal direction, value \c 0 means no resize, otherwise the step size in pixels. + * @param resize_y Resize step in vertical direction, value \c 0 means no resize, otherwise the step size in pixels. + */ +void NWidgetResizeBase::SetResize(uint resize_x, uint resize_y) +{ + this->resize_x = resize_x; + this->resize_y = resize_y; +} + +void NWidgetResizeBase::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) +{ + this->StoreSizePosition(sizing, x, y, given_width, given_height); +} + +/** + * Initialization of a 'real' widget. + * @param tp Type of the widget. + * @param colour Colour of the widget. + * @param fill_x Default horizontal filling. + * @param fill_y Default vertical filling. + * @param widget_data Data component of the widget. @see Widget::data + * @param tool_tip Tool tip of the widget. @see Widget::tooltips + */ +NWidgetCore::NWidgetCore(WidgetType tp, Colours colour, uint fill_x, uint fill_y, uint32 widget_data, StringID tool_tip) : NWidgetResizeBase(tp, fill_x, fill_y) +{ + this->sizing_type = NWST_NONE; + this->colour = colour; + this->index = -1; + this->widget_data = widget_data; + this->tool_tip = tool_tip; + this->scrollbar_index = -1; +} + +/** + * Set index of the nested widget in the widget array. + * @param index Index to use. + */ +void NWidgetCore::SetIndex(int index) +{ + assert(index >= 0); + this->index = index; +} + +/** + * Set data and tool tip of the nested widget. + * @param widget_data Data to use. + * @param tool_tip Tool tip string to use. + */ +void NWidgetCore::SetDataTip(uint32 widget_data, StringID tool_tip) +{ + this->widget_data = widget_data; + this->tool_tip = tool_tip; +} + +void NWidgetCore::FillNestedArray(NWidgetBase **array, uint length) +{ + if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; +} + +NWidgetCore *NWidgetCore::GetWidgetFromPos(int x, int y) +{ + return (IsInsideBS(x, this->pos_x, this->current_x) && IsInsideBS(y, this->pos_y, this->current_y)) ? this : NULL; +} + +/** + * Constructor container baseclass. + * @param tp Type of the container. + */ +NWidgetContainer::NWidgetContainer(WidgetType tp) : NWidgetBase(tp) +{ + this->head = NULL; + this->tail = NULL; +} + +NWidgetContainer::~NWidgetContainer() +{ + while (this->head != NULL) { + NWidgetBase *wid = this->head->next; + delete this->head; + this->head = wid; + } + this->tail = NULL; +} + +NWidgetBase *NWidgetContainer::GetWidgetOfType(WidgetType tp) +{ + if (this->type == tp) return this; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + NWidgetBase *nwid = child_wid->GetWidgetOfType(tp); + if (nwid != NULL) return nwid; + } + return NULL; +} + +/** + * Append widget \a wid to container. + * @param wid Widget to append. + */ +void NWidgetContainer::Add(NWidgetBase *wid) +{ + assert(wid->next == NULL && wid->prev == NULL); + + if (this->head == NULL) { + this->head = wid; + this->tail = wid; + } else { + assert(this->tail != NULL); + assert(this->tail->next == NULL); + + this->tail->next = wid; + wid->prev = this->tail; + this->tail = wid; + } +} + +void NWidgetContainer::FillNestedArray(NWidgetBase **array, uint length) +{ + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + child_wid->FillNestedArray(array, length); + } +} + +/** + * Widgets stacked on top of each other. + */ +NWidgetStacked::NWidgetStacked() : NWidgetContainer(NWID_SELECTION) +{ + this->index = -1; +} + +void NWidgetStacked::SetIndex(int index) +{ + this->index = index; +} + +void NWidgetStacked::SetupSmallestSize(Window *w, bool init_array) +{ + if (this->index >= 0 && init_array) { // Fill w->nested_array[] + assert(w->nested_array_size > (uint)this->index); + w->nested_array[this->index] = this; + } + + /* Zero size plane selected */ + if (this->shown_plane >= SZSP_BEGIN) { + Dimension size = {0, 0}; + Dimension padding = {0, 0}; + Dimension fill = {(this->shown_plane == SZSP_HORIZONTAL), (this->shown_plane == SZSP_VERTICAL)}; + Dimension resize = {(this->shown_plane == SZSP_HORIZONTAL), (this->shown_plane == SZSP_VERTICAL)}; + /* Here we're primarily interested in the value of resize */ + if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, padding, &fill, &resize); + + this->smallest_x = size.width; + this->smallest_y = size.height; + this->fill_x = fill.width; + this->fill_y = fill.height; + this->resize_x = resize.width; + this->resize_y = resize.height; + return; + } + + /* First sweep, recurse down and compute minimal size and filling. */ + this->smallest_x = 0; + this->smallest_y = 0; + this->fill_x = (this->head != NULL) ? 1 : 0; + this->fill_y = (this->head != NULL) ? 1 : 0; + this->resize_x = (this->head != NULL) ? 1 : 0; + this->resize_y = (this->head != NULL) ? 1 : 0; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + child_wid->SetupSmallestSize(w, init_array); + + this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); + this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); + this->fill_x = LeastCommonMultiple(this->fill_x, child_wid->fill_x); + this->fill_y = LeastCommonMultiple(this->fill_y, child_wid->fill_y); + this->resize_x = LeastCommonMultiple(this->resize_x, child_wid->resize_x); + this->resize_y = LeastCommonMultiple(this->resize_y, child_wid->resize_y); + } +} + +void NWidgetStacked::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) +{ + assert(given_width >= this->smallest_x && given_height >= this->smallest_y); + this->StoreSizePosition(sizing, x, y, given_width, given_height); + + if (this->shown_plane >= SZSP_BEGIN) return; + + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + uint hor_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing); + uint child_width = ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding_left - child_wid->padding_right, hor_step); + uint child_pos_x = (rtl ? child_wid->padding_right : child_wid->padding_left); + + uint vert_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing); + uint child_height = ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding_top - child_wid->padding_bottom, vert_step); + uint child_pos_y = child_wid->padding_top; + + child_wid->AssignSizePosition(sizing, x + child_pos_x, y + child_pos_y, child_width, child_height, rtl); + } +} + +void NWidgetStacked::FillNestedArray(NWidgetBase **array, uint length) +{ + if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; + NWidgetContainer::FillNestedArray(array, length); +} + +void NWidgetStacked::Draw(const Window *w) +{ + if (this->shown_plane >= SZSP_BEGIN) return; + + int plane = 0; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; plane++, child_wid = child_wid->next) { + if (plane == this->shown_plane) { + child_wid->Draw(w); + return; + } + } + + NOT_REACHED(); +} + +NWidgetCore *NWidgetStacked::GetWidgetFromPos(int x, int y) +{ + if (this->shown_plane >= SZSP_BEGIN) return NULL; + + if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; + int plane = 0; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; plane++, child_wid = child_wid->next) { + if (plane == this->shown_plane) { + return child_wid->GetWidgetFromPos(x, y); + } + } + return NULL; +} + +/** + * Select which plane to show (for #NWID_SELECTION only). + * @param plane Plane number to display. + */ +void NWidgetStacked::SetDisplayedPlane(int plane) +{ + this->shown_plane = plane; +} + +NWidgetPIPContainer::NWidgetPIPContainer(WidgetType tp, NWidContainerFlags flags) : NWidgetContainer(tp) +{ + this->flags = flags; +} + +/** + * Set additional pre/inter/post space for the container. + * + * @param pip_pre Additional space in front of the first child widget (above + * for the vertical container, at the left for the horizontal container). + * @param pip_inter Additional space between two child widgets. + * @param pip_post Additional space after the last child widget (below for the + * vertical container, at the right for the horizontal container). + */ +void NWidgetPIPContainer::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) +{ + this->pip_pre = pip_pre; + this->pip_inter = pip_inter; + this->pip_post = pip_post; +} + +void NWidgetPIPContainer::Draw(const Window *w) +{ + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + child_wid->Draw(w); + } +} + +NWidgetCore *NWidgetPIPContainer::GetWidgetFromPos(int x, int y) +{ + if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; + + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y); + if (nwid != NULL) return nwid; + } + return NULL; +} + +/** Horizontal container widget. */ +NWidgetHorizontal::NWidgetHorizontal(NWidContainerFlags flags) : NWidgetPIPContainer(NWID_HORIZONTAL, flags) +{ +} + +void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) +{ + this->smallest_x = 0; // Sum of minimal size of all children. + this->smallest_y = 0; // Biggest child. + this->fill_x = 0; // smallest non-zero child widget fill step. + this->fill_y = 1; // smallest common child fill step. + this->resize_x = 0; // smallest non-zero child widget resize step. + this->resize_y = 1; // smallest common child resize step. + + /* 1a. Forward call, collect biggest nested array index, and longest/widest child length. */ + uint longest = 0; // Longest child found. + uint max_vert_fill = 0; // Biggest vertical fill step. + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + child_wid->SetupSmallestSize(w, init_array); + longest = max(longest, child_wid->smallest_x); + max_vert_fill = max(max_vert_fill, child_wid->GetVerticalStepSize(ST_SMALLEST)); + this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); + } + /* 1b. Make the container higher if needed to accommodate all children nicely. */ + uint max_smallest = this->smallest_y + 3 * max_vert_fill; // Upper limit to computing smallest height. + uint cur_height = this->smallest_y; + for (;;) { + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + uint step_size = child_wid->GetVerticalStepSize(ST_SMALLEST); + uint child_height = child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom; + if (step_size > 1 && child_height < cur_height) { // Small step sizes or already fitting children are not interesting. + uint remainder = (cur_height - child_height) % step_size; + if (remainder > 0) { // Child did not fit entirely, widen the container. + cur_height += step_size - remainder; + assert(cur_height < max_smallest); // Safeguard against infinite height expansion. + /* Remaining children will adapt to the new cur_height, thus speeding up the computation. */ + } + } + } + if (this->smallest_y == cur_height) break; + this->smallest_y = cur_height; // Smallest height got changed, try again. + } + /* 2. For containers that must maintain equal width, extend child minimal size. */ + if (this->flags & NC_EQUALSIZE) { + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + if (child_wid->fill_x == 1) child_wid->smallest_x = longest; + } + } + /* 3. Move PIP space to the children, compute smallest, fill, and resize values of the container. */ + if (this->head != NULL) this->head->padding_left += this->pip_pre; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + if (child_wid->next != NULL) { + child_wid->padding_right += this->pip_inter; + } else { + child_wid->padding_right += this->pip_post; + } + + this->smallest_x += child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right; + if (child_wid->fill_x > 0) { + if (this->fill_x == 0 || this->fill_x > child_wid->fill_x) this->fill_x = child_wid->fill_x; + } + this->fill_y = LeastCommonMultiple(this->fill_y, child_wid->fill_y); + + if (child_wid->resize_x > 0) { + if (this->resize_x == 0 || this->resize_x > child_wid->resize_x) this->resize_x = child_wid->resize_x; + } + this->resize_y = LeastCommonMultiple(this->resize_y, child_wid->resize_y); + } + /* We need to zero the PIP settings so we can re-initialize the tree. */ + this->pip_pre = this->pip_inter = this->pip_post = 0; +} + +void NWidgetHorizontal::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) +{ + assert(given_width >= this->smallest_x && given_height >= this->smallest_y); + + /* Compute additional width given to us. */ + uint additional_length = given_width; + if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) { + /* For EQUALSIZE containers this does not sum to smallest_x during initialisation */ + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + additional_length -= child_wid->smallest_x + child_wid->padding_right + child_wid->padding_left; + } + } else { + additional_length -= this->smallest_x; + } + + this->StoreSizePosition(sizing, x, y, given_width, given_height); + + /* In principle, the additional horizontal space is distributed evenly over the available resizable children. Due to step sizes, this may not always be feasible. + * To make resizing work as good as possible, first children with biggest step sizes are done. These may get less due to rounding down. + * This additional space is then given to children with smaller step sizes. This will give a good result when resize steps of each child is a multiple + * of the child with the smallest non-zero stepsize. + * + * Since child sizes are computed out of order, positions cannot be calculated until all sizes are known. That means it is not possible to compute the child + * size and position, and directly call child->AssignSizePosition() with the computed values. + * Instead, computed child widths and heights are stored in child->current_x and child->current_y values. That is allowed, since this method overwrites those values + * then we call the child. + */ + + /* First loop: Find biggest stepsize, find number of children that want a piece of the pie, handle vertical size for all children, + * handle horizontal size for non-resizing children. + */ + int num_changing_childs = 0; // Number of children that can change size. + uint biggest_stepsize = 0; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + uint hor_step = child_wid->GetHorizontalStepSize(sizing); + if (hor_step > 0) { + num_changing_childs++; + biggest_stepsize = max(biggest_stepsize, hor_step); + } else { + child_wid->current_x = child_wid->smallest_x; + } + + uint vert_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing); + child_wid->current_y = ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding_top - child_wid->padding_bottom, vert_step); + } + + /* Second loop: Allocate the additional horizontal space over the resizing children, starting with the biggest resize steps. */ + while (biggest_stepsize > 0) { + uint next_biggest_stepsize = 0; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + uint hor_step = child_wid->GetHorizontalStepSize(sizing); + if (hor_step > biggest_stepsize) continue; // Already done + if (hor_step == biggest_stepsize) { + uint increment = additional_length / num_changing_childs; + num_changing_childs--; + if (hor_step > 1) increment -= increment % hor_step; + child_wid->current_x = child_wid->smallest_x + increment; + additional_length -= increment; + continue; + } + next_biggest_stepsize = max(next_biggest_stepsize, hor_step); + } + biggest_stepsize = next_biggest_stepsize; + } + assert(num_changing_childs == 0); + + /* Third loop: Compute position and call the child. */ + uint position = rtl ? this->current_x : 0; // Place to put next child relative to origin of the container. + NWidgetBase *child_wid = this->head; + while (child_wid != NULL) { + uint child_width = child_wid->current_x; + uint child_x = x + (rtl ? position - child_width - child_wid->padding_left : position + child_wid->padding_left); + uint child_y = y + child_wid->padding_top; + + child_wid->AssignSizePosition(sizing, child_x, child_y, child_width, child_wid->current_y, rtl); + uint padded_child_width = child_width + child_wid->padding_right + child_wid->padding_left; + position = rtl ? position - padded_child_width : position + padded_child_width; + + child_wid = child_wid->next; + } +} + +/** Horizontal left-to-right container widget. */ +NWidgetHorizontalLTR::NWidgetHorizontalLTR(NWidContainerFlags flags) : NWidgetHorizontal(flags) +{ + this->type = NWID_HORIZONTAL_LTR; +} + +void NWidgetHorizontalLTR::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) +{ + NWidgetHorizontal::AssignSizePosition(sizing, x, y, given_width, given_height, false); +} + +/** Vertical container widget. */ +NWidgetVertical::NWidgetVertical(NWidContainerFlags flags) : NWidgetPIPContainer(NWID_VERTICAL, flags) +{ +} + +void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) +{ + this->smallest_x = 0; // Biggest child. + this->smallest_y = 0; // Sum of minimal size of all children. + this->fill_x = 1; // smallest common child fill step. + this->fill_y = 0; // smallest non-zero child widget fill step. + this->resize_x = 1; // smallest common child resize step. + this->resize_y = 0; // smallest non-zero child widget resize step. + + /* 1a. Forward call, collect biggest nested array index, and longest/widest child length. */ + uint highest = 0; // Highest child found. + uint max_hor_fill = 0; // Biggest horizontal fill step. + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + child_wid->SetupSmallestSize(w, init_array); + highest = max(highest, child_wid->smallest_y); + max_hor_fill = max(max_hor_fill, child_wid->GetHorizontalStepSize(ST_SMALLEST)); + this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); + } + /* 1b. Make the container wider if needed to accommodate all children nicely. */ + uint max_smallest = this->smallest_x + 3 * max_hor_fill; // Upper limit to computing smallest height. + uint cur_width = this->smallest_x; + for (;;) { + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + uint step_size = child_wid->GetHorizontalStepSize(ST_SMALLEST); + uint child_width = child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right; + if (step_size > 1 && child_width < cur_width) { // Small step sizes or already fitting children are not interesting. + uint remainder = (cur_width - child_width) % step_size; + if (remainder > 0) { // Child did not fit entirely, widen the container. + cur_width += step_size - remainder; + assert(cur_width < max_smallest); // Safeguard against infinite width expansion. + /* Remaining children will adapt to the new cur_width, thus speeding up the computation. */ + } + } + } + if (this->smallest_x == cur_width) break; + this->smallest_x = cur_width; // Smallest width got changed, try again. + } + /* 2. For containers that must maintain equal width, extend children minimal size. */ + if (this->flags & NC_EQUALSIZE) { + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + if (child_wid->fill_y == 1) child_wid->smallest_y = highest; + } + } + /* 3. Move PIP space to the child, compute smallest, fill, and resize values of the container. */ + if (this->head != NULL) this->head->padding_top += this->pip_pre; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + if (child_wid->next != NULL) { + child_wid->padding_bottom += this->pip_inter; + } else { + child_wid->padding_bottom += this->pip_post; + } + + this->smallest_y += child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom; + if (child_wid->fill_y > 0) { + if (this->fill_y == 0 || this->fill_y > child_wid->fill_y) this->fill_y = child_wid->fill_y; + } + this->fill_x = LeastCommonMultiple(this->fill_x, child_wid->fill_x); + + if (child_wid->resize_y > 0) { + if (this->resize_y == 0 || this->resize_y > child_wid->resize_y) this->resize_y = child_wid->resize_y; + } + this->resize_x = LeastCommonMultiple(this->resize_x, child_wid->resize_x); + } + /* We need to zero the PIP settings so we can re-initialize the tree. */ + this->pip_pre = this->pip_inter = this->pip_post = 0; +} + +void NWidgetVertical::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) +{ + assert(given_width >= this->smallest_x && given_height >= this->smallest_y); + + /* Compute additional height given to us. */ + uint additional_length = given_height; + if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) { + /* For EQUALSIZE containers this does not sum to smallest_y during initialisation */ + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + additional_length -= child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom; + } + } else { + additional_length -= this->smallest_y; + } + + this->StoreSizePosition(sizing, x, y, given_width, given_height); + + /* Like the horizontal container, the vertical container also distributes additional height evenly, starting with the children with the biggest resize steps. + * It also stores computed widths and heights into current_x and current_y values of the child. + */ + + /* First loop: Find biggest stepsize, find number of children that want a piece of the pie, handle horizontal size for all children, handle vertical size for non-resizing child. */ + int num_changing_childs = 0; // Number of children that can change size. + uint biggest_stepsize = 0; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + uint vert_step = child_wid->GetVerticalStepSize(sizing); + if (vert_step > 0) { + num_changing_childs++; + biggest_stepsize = max(biggest_stepsize, vert_step); + } else { + child_wid->current_y = child_wid->smallest_y; + } + + uint hor_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing); + child_wid->current_x = ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding_left - child_wid->padding_right, hor_step); + } + + /* Second loop: Allocate the additional vertical space over the resizing children, starting with the biggest resize steps. */ + while (biggest_stepsize > 0) { + uint next_biggest_stepsize = 0; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + uint vert_step = child_wid->GetVerticalStepSize(sizing); + if (vert_step > biggest_stepsize) continue; // Already done + if (vert_step == biggest_stepsize) { + uint increment = additional_length / num_changing_childs; + num_changing_childs--; + if (vert_step > 1) increment -= increment % vert_step; + child_wid->current_y = child_wid->smallest_y + increment; + additional_length -= increment; + continue; + } + next_biggest_stepsize = max(next_biggest_stepsize, vert_step); + } + biggest_stepsize = next_biggest_stepsize; + } + assert(num_changing_childs == 0); + + /* Third loop: Compute position and call the child. */ + uint position = 0; // Place to put next child relative to origin of the container. + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + uint child_x = x + (rtl ? child_wid->padding_right : child_wid->padding_left); + uint child_height = child_wid->current_y; + + child_wid->AssignSizePosition(sizing, child_x, y + position + child_wid->padding_top, child_wid->current_x, child_height, rtl); + position += child_height + child_wid->padding_top + child_wid->padding_bottom; + } +} + +/** + * Generic spacer widget. + * @param length Horizontal size of the spacer widget. + * @param height Vertical size of the spacer widget. + */ +NWidgetSpacer::NWidgetSpacer(int length, int height) : NWidgetResizeBase(NWID_SPACER, 0, 0) +{ + this->SetMinimalSize(length, height); + this->SetResize(0, 0); +} + +void NWidgetSpacer::SetupSmallestSize(Window *w, bool init_array) +{ + this->smallest_x = this->min_x; + this->smallest_y = this->min_y; +} + +void NWidgetSpacer::FillNestedArray(NWidgetBase **array, uint length) +{ +} + +void NWidgetSpacer::Draw(const Window *w) +{ + /* Spacer widget is never visible. */ +} + +void NWidgetSpacer::SetDirty(const Window *w) const +{ + /* Spacer widget never need repainting. */ +} + +NWidgetCore *NWidgetSpacer::GetWidgetFromPos(int x, int y) +{ + return NULL; +} + +NWidgetMatrix::NWidgetMatrix() : NWidgetPIPContainer(NWID_MATRIX, NC_EQUALSIZE), index(-1), clicked(-1), count(-1) +{ +} + +void NWidgetMatrix::SetIndex(int index) +{ + this->index = index; +} + +void NWidgetMatrix::SetColour(Colours colour) +{ + this->colour = colour; +} + +/** + * Sets the clicked widget in the matrix. + * @param clicked The clicked widget. + */ +void NWidgetMatrix::SetClicked(int clicked) +{ + this->clicked = clicked; + if (this->clicked >= 0 && this->sb != NULL && this->widgets_x != 0) { + int vpos = (this->clicked / this->widgets_x) * this->widget_h; // Vertical position of the top. + /* Need to scroll down -> Scroll to the bottom. + * However, last entry has no 'this->pip_inter' underneath, and we must stay below this->sb->GetCount() */ + if (this->sb->GetPosition() < vpos) vpos += this->widget_h - this->pip_inter - 1; + this->sb->ScrollTowards(vpos); + } +} + +/** + * Set the number of elements in this matrix. + * @note Updates the number of elements/capacity of the real scrollbar. + * @param count The number of elements. + */ +void NWidgetMatrix::SetCount(int count) +{ + this->count = count; + + if (this->sb == NULL || this->widgets_x == 0) return; + + /* We need to get the number of pixels the matrix is high/wide. + * So, determine the number of rows/columns based on the number of + * columns/rows (one is constant/unscrollable). + * Then multiply that by the height of a widget, and add the pre + * and post spacing "offsets". */ + count = CeilDiv(count, this->sb->IsVertical() ? this->widgets_x : this->widgets_y); + count *= (this->sb->IsVertical() ? this->head->smallest_y : this->head->smallest_x) + this->pip_inter; + if (count > 0) count -= this->pip_inter; // We counted an inter too much in the multiplication above + count += this->pip_pre + this->pip_post; + this->sb->SetCount(count); + this->sb->SetCapacity(this->sb->IsVertical() ? this->current_y : this->current_x); + this->sb->SetStepSize(this->sb->IsVertical() ? this->widget_h : this->widget_w); +} + +/** + * Assign a scrollbar to this matrix. + * @param sb The scrollbar to assign to us. + */ +void NWidgetMatrix::SetScrollbar(Scrollbar *sb) +{ + this->sb = sb; +} + +void NWidgetMatrix::SetupSmallestSize(Window *w, bool init_array) +{ + assert(this->head != NULL); + assert(this->head->next == NULL); + + if (this->index >= 0 && init_array) { // Fill w->nested_array[] + assert(w->nested_array_size > (uint)this->index); + w->nested_array[this->index] = this; + } + + /* Reset the widget number. */ + NWidgetCore *nw = dynamic_cast(this->head); + assert(nw != NULL); + SB(nw->index, 16, 16, 0); + this->head->SetupSmallestSize(w, init_array); + + Dimension padding = {this->pip_pre + this->pip_post, this->pip_pre + this->pip_post}; + Dimension size = {this->head->smallest_x + padding.width, this->head->smallest_y + padding.height}; + Dimension fill = {0, 0}; + Dimension resize = {this->pip_inter + this->head->smallest_x, this->pip_inter + this->head->smallest_y}; + + if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, padding, &fill, &resize); + + this->smallest_x = size.width; + this->smallest_y = size.height; + this->fill_x = fill.width; + this->fill_y = fill.height; + this->resize_x = resize.width; + this->resize_y = resize.height; +} + +void NWidgetMatrix::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) +{ + assert(given_width >= this->smallest_x && given_height >= this->smallest_y); + + this->pos_x = x; + this->pos_y = y; + this->current_x = given_width; + this->current_y = given_height; + + /* Determine the size of the widgets, and the number of visible widgets on each of the axis. */ + this->widget_w = this->head->smallest_x + this->pip_inter; + this->widget_h = this->head->smallest_y + this->pip_inter; + + /* Account for the pip_inter is between widgets, so we need to account for that when + * the division assumes pip_inter is used for all widgets. */ + this->widgets_x = CeilDiv(this->current_x - this->pip_pre - this->pip_post + this->pip_inter, this->widget_w); + this->widgets_y = CeilDiv(this->current_y - this->pip_pre - this->pip_post + this->pip_inter, this->widget_h); + + /* When resizing, update the scrollbar's count. E.g. with a vertical + * scrollbar becoming wider or narrower means the amount of rows in + * the scrollbar becomes respectively smaller or higher. */ + this->SetCount(this->count); +} + +void NWidgetMatrix::FillNestedArray(NWidgetBase **array, uint length) +{ + if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; + NWidgetContainer::FillNestedArray(array, length); +} + +NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y) +{ + /* Falls outside of the matrix widget. */ + if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; + + int start_x, start_y, base_offs_x, base_offs_y; + this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y); + + bool rtl = _current_text_dir == TD_RTL; + + int widget_col = (rtl ? + -x + (int)this->pip_post + (int)this->pos_x + base_offs_x + (int)this->widget_w - 1 - (int)this->pip_inter : + x - (int)this->pip_pre - (int)this->pos_x - base_offs_x + ) / this->widget_w; + + int widget_row = (y - base_offs_y - (int)this->pip_pre - (int)this->pos_y) / this->widget_h; + + int sub_wid = (widget_row + start_y) * this->widgets_x + start_x + widget_col; + if (sub_wid >= this->count) return NULL; + + NWidgetCore *child = dynamic_cast(this->head); + assert(child != NULL); + child->AssignSizePosition(ST_RESIZE, + this->pos_x + (rtl ? this->pip_post - widget_col * this->widget_w : this->pip_pre + widget_col * this->widget_w) + base_offs_x, + this->pos_y + this->pip_pre + widget_row * this->widget_h + base_offs_y, + child->smallest_x, child->smallest_y, rtl); + + SB(child->index, 16, 16, sub_wid); + + return child->GetWidgetFromPos(x, y); +} + +/* virtual */ void NWidgetMatrix::Draw(const Window *w) +{ + /* Fill the background. */ + GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, _colour_gradient[this->colour & 0xF][5]); + + /* Set up a clipping area for the previews. */ + bool rtl = _current_text_dir == TD_RTL; + DrawPixelInfo tmp_dpi; + if (!FillDrawPixelInfo(&tmp_dpi, this->pos_x + (rtl ? this->pip_post : this->pip_pre), this->pos_y + this->pip_pre, this->current_x - this->pip_pre - this->pip_post, this->current_y - this->pip_pre - this->pip_post)) return; + DrawPixelInfo *old_dpi = _cur_dpi; + _cur_dpi = &tmp_dpi; + + /* Get the appropriate offsets so we can draw the right widgets. */ + NWidgetCore *child = dynamic_cast(this->head); + assert(child != NULL); + int start_x, start_y, base_offs_x, base_offs_y; + this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y); + + int offs_y = base_offs_y; + for (int y = start_y; y < start_y + this->widgets_y + 1; y++, offs_y += this->widget_h) { + /* Are we within bounds? */ + if (offs_y + child->smallest_y <= 0) continue; + if (offs_y >= (int)this->current_y) break; + + /* We've passed our amount of widgets. */ + if (y * this->widgets_x >= this->count) break; + + int offs_x = base_offs_x; + for (int x = start_x; x < start_x + this->widgets_x + 1; x++, offs_x += rtl ? -this->widget_w : this->widget_w) { + /* Are we within bounds? */ + if (offs_x + child->smallest_x <= 0) continue; + if (offs_x >= (int)this->current_x) continue; + + /* Do we have this many widgets? */ + int sub_wid = y * this->widgets_x + x; + if (sub_wid >= this->count) break; + + child->AssignSizePosition(ST_RESIZE, offs_x, offs_y, child->smallest_x, child->smallest_y, rtl); + child->SetLowered(this->clicked == sub_wid); + SB(child->index, 16, 16, sub_wid); + child->Draw(w); + } + } + + /* Restore the clipping area. */ + _cur_dpi = old_dpi; +} + +/** + * Get the different offsets that are influenced by scrolling. + * @param [out] start_x The start position in columns (index of the left-most column, swapped in RTL). + * @param [out] start_y The start position in rows. + * @param [out] base_offs_x The base horizontal offset in pixels (X position of the column \a start_x). + * @param [out] base_offs_y The base vertical offset in pixels (Y position of the column \a start_y). + */ +void NWidgetMatrix::GetScrollOffsets(int &start_x, int &start_y, int &base_offs_x, int &base_offs_y) +{ + base_offs_x = _current_text_dir == TD_RTL ? this->widget_w * (this->widgets_x - 1) : 0; + base_offs_y = 0; + start_x = 0; + start_y = 0; + if (this->sb != NULL) { + if (this->sb->IsVertical()) { + start_y = this->sb->GetPosition() / this->widget_h; + base_offs_y += -this->sb->GetPosition() + start_y * this->widget_h; + } else { + start_x = this->sb->GetPosition() / this->widget_w; + int sub_x = this->sb->GetPosition() - start_x * this->widget_w; + if (_current_text_dir == TD_RTL) { + base_offs_x += sub_x; + } else { + base_offs_x -= sub_x; + } + } + } +} + +/** + * Constructor parent nested widgets. + * @param tp Type of parent widget. + * @param colour Colour of the parent widget. + * @param index Index in the widget array used by the window system. + * @param child Child container widget (if supplied). If not supplied, a + * vertical container will be inserted while adding the first + * child widget. + */ +NWidgetBackground::NWidgetBackground(WidgetType tp, Colours colour, int index, NWidgetPIPContainer *child) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL) +{ + assert(tp == WWT_PANEL || tp == WWT_INSET || tp == WWT_FRAME); + if (index >= 0) this->SetIndex(index); + this->child = child; +} + +NWidgetBackground::~NWidgetBackground() +{ + if (this->child != NULL) delete this->child; +} + +/** + * Add a child to the parent. + * @param nwid Nested widget to add to the background widget. + * + * Unless a child container has been given in the constructor, a parent behaves as a vertical container. + * You can add several children to it, and they are put underneath each other. + */ +void NWidgetBackground::Add(NWidgetBase *nwid) +{ + if (this->child == NULL) { + this->child = new NWidgetVertical(); + } + this->child->Add(nwid); +} + +/** + * Set additional pre/inter/post space for the background widget. + * + * @param pip_pre Additional space in front of the first child widget (above + * for the vertical container, at the left for the horizontal container). + * @param pip_inter Additional space between two child widgets. + * @param pip_post Additional space after the last child widget (below for the + * vertical container, at the right for the horizontal container). + * @note Using this function implies that the widget has (or will have) child widgets. + */ +void NWidgetBackground::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) +{ + if (this->child == NULL) { + this->child = new NWidgetVertical(); + } + this->child->SetPIP(pip_pre, pip_inter, pip_post); +} + +void NWidgetBackground::SetupSmallestSize(Window *w, bool init_array) +{ + if (init_array && this->index >= 0) { + assert(w->nested_array_size > (uint)this->index); + w->nested_array[this->index] = this; + } + if (this->child != NULL) { + this->child->SetupSmallestSize(w, init_array); + + this->smallest_x = this->child->smallest_x; + this->smallest_y = this->child->smallest_y; + this->fill_x = this->child->fill_x; + this->fill_y = this->child->fill_y; + this->resize_x = this->child->resize_x; + this->resize_y = this->child->resize_y; + + /* Account for the size of the frame's text if that exists */ + if (w != NULL && this->type == WWT_FRAME) { + this->child->padding_left = WD_FRAMETEXT_LEFT; + this->child->padding_right = WD_FRAMETEXT_RIGHT; + this->child->padding_top = max((int)WD_FRAMETEXT_TOP, this->widget_data != STR_NULL ? FONT_HEIGHT_NORMAL + WD_FRAMETEXT_TOP / 2 : 0); + this->child->padding_bottom = WD_FRAMETEXT_BOTTOM; + + this->smallest_x += this->child->padding_left + this->child->padding_right; + this->smallest_y += this->child->padding_top + this->child->padding_bottom; + + if (this->index >= 0) w->SetStringParameters(this->index); + this->smallest_x = max(this->smallest_x, GetStringBoundingBox(this->widget_data).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT); + } + } else { + Dimension d = {this->min_x, this->min_y}; + Dimension fill = {this->fill_x, this->fill_y}; + Dimension resize = {this->resize_x, this->resize_y}; + if (w != NULL) { // A non-NULL window pointer acts as switch to turn dynamic widget size on. + if (this->type == WWT_FRAME || this->type == WWT_INSET) { + if (this->index >= 0) w->SetStringParameters(this->index); + Dimension background = GetStringBoundingBox(this->widget_data); + background.width += (this->type == WWT_FRAME) ? (WD_FRAMETEXT_LEFT + WD_FRAMERECT_RIGHT) : (WD_INSET_LEFT + WD_INSET_RIGHT); + d = maxdim(d, background); + } + if (this->index >= 0) { + static const Dimension padding = {0, 0}; + w->UpdateWidgetSize(this->index, &d, padding, &fill, &resize); + } + } + this->smallest_x = d.width; + this->smallest_y = d.height; + this->fill_x = fill.width; + this->fill_y = fill.height; + this->resize_x = resize.width; + this->resize_y = resize.height; + } +} + +void NWidgetBackground::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) +{ + this->StoreSizePosition(sizing, x, y, given_width, given_height); + + if (this->child != NULL) { + uint x_offset = (rtl ? this->child->padding_right : this->child->padding_left); + uint width = given_width - this->child->padding_right - this->child->padding_left; + uint height = given_height - this->child->padding_top - this->child->padding_bottom; + this->child->AssignSizePosition(sizing, x + x_offset, y + this->child->padding_top, width, height, rtl); + } +} + +void NWidgetBackground::FillNestedArray(NWidgetBase **array, uint length) +{ + if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; + if (this->child != NULL) this->child->FillNestedArray(array, length); +} + +void NWidgetBackground::Draw(const Window *w) +{ + if (this->current_x == 0 || this->current_y == 0) return; + + Rect r; + r.left = this->pos_x; + r.right = this->pos_x + this->current_x - 1; + r.top = this->pos_y; + r.bottom = this->pos_y + this->current_y - 1; + + const DrawPixelInfo *dpi = _cur_dpi; + if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return; + + switch (this->type) { + case WWT_PANEL: + assert(this->widget_data == 0); + DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, this->IsLowered() ? FR_LOWERED : FR_NONE); + break; + + case WWT_FRAME: + if (this->index >= 0) w->SetStringParameters(this->index); + DrawFrame(r, this->colour, this->widget_data); + break; + + case WWT_INSET: + if (this->index >= 0) w->SetStringParameters(this->index); + DrawInset(r, this->colour, this->widget_data); + break; + + default: + NOT_REACHED(); + } + + if (this->index >= 0) w->DrawWidget(r, this->index); + if (this->child != NULL) this->child->Draw(w); + + if (this->IsDisabled()) { + GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); + } +} + +NWidgetCore *NWidgetBackground::GetWidgetFromPos(int x, int y) +{ + NWidgetCore *nwid = NULL; + if (IsInsideBS(x, this->pos_x, this->current_x) && IsInsideBS(y, this->pos_y, this->current_y)) { + if (this->child != NULL) nwid = this->child->GetWidgetFromPos(x, y); + if (nwid == NULL) nwid = this; + } + return nwid; +} + +NWidgetBase *NWidgetBackground::GetWidgetOfType(WidgetType tp) +{ + NWidgetBase *nwid = NULL; + if (this->child != NULL) nwid = this->child->GetWidgetOfType(tp); + if (nwid == NULL && this->type == tp) nwid = this; + return nwid; +} + +NWidgetViewport::NWidgetViewport(int index) : NWidgetCore(NWID_VIEWPORT, INVALID_COLOUR, 1, 1, 0x0, STR_NULL) +{ + this->SetIndex(index); +} + +void NWidgetViewport::SetupSmallestSize(Window *w, bool init_array) +{ + if (init_array && this->index >= 0) { + assert(w->nested_array_size > (uint)this->index); + w->nested_array[this->index] = this; + } + this->smallest_x = this->min_x; + this->smallest_y = this->min_y; +} + +void NWidgetViewport::Draw(const Window *w) +{ + if (this->disp_flags & ND_NO_TRANSPARENCY) { + TransparencyOptionBits to_backup = _transparency_opt; + _transparency_opt &= (1 << TO_SIGNS) | (1 << TO_LOADING); // Disable all transparency, except textual stuff + w->DrawViewport(); + _transparency_opt = to_backup; + } else { + w->DrawViewport(); + } + + /* Optionally shade the viewport. */ + if (this->disp_flags & (ND_SHADE_GREY | ND_SHADE_DIMMED)) { + GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, + (this->disp_flags & ND_SHADE_DIMMED) ? PALETTE_TO_TRANSPARENT : PALETTE_NEWSPAPER, FILLRECT_RECOLOUR); + } +} + +/** + * Initialize the viewport of the window. + * @param w Window owning the viewport. + * @param follow_flags Type of viewport, see #InitializeWindowViewport(). + * @param zoom Zoom level. + */ +void NWidgetViewport::InitializeViewport(Window *w, uint32 follow_flags, ZoomLevel zoom) +{ + InitializeWindowViewport(w, this->pos_x, this->pos_y, this->current_x, this->current_y, follow_flags, zoom); +} + +/** + * Update the position and size of the viewport (after eg a resize). + * @param w Window owning the viewport. + */ +void NWidgetViewport::UpdateViewportCoordinates(Window *w) +{ + ViewPort *vp = w->viewport; + if (vp != NULL) { + vp->left = w->left + this->pos_x; + vp->top = w->top + this->pos_y; + vp->width = this->current_x; + vp->height = this->current_y; + + vp->virtual_width = ScaleByZoom(vp->width, vp->zoom); + vp->virtual_height = ScaleByZoom(vp->height, vp->zoom); + } +} + +/** + * Compute the row of a scrolled widget that a user clicked in. + * @param clickpos Vertical position of the mouse click (without taking scrolling into account). + * @param w The window the click was in. + * @param widget Widget number of the widget clicked in. + * @param padding Amount of empty space between the widget edge and the top of the first row. Default value is \c 0. + * @param line_height Height of a single row. A negative value means using the vertical resize step of the widget. + * @return Row number clicked at. If clicked at a wrong position, #INT_MAX is returned. + */ +int Scrollbar::GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding, int line_height) const +{ + uint pos = w->GetRowFromWidget(clickpos, widget, padding, line_height); + if (pos != INT_MAX) pos += this->GetPosition(); + return (pos >= this->GetCount()) ? INT_MAX : pos; +} + +/** + * Set capacity of visible elements from the size and resize properties of a widget. + * @param w Window. + * @param widget Widget with size and resize properties. + * @param padding Padding to subtract from the size. + * @note Updates the position if needed. + */ +void Scrollbar::SetCapacityFromWidget(Window *w, int widget, int padding) +{ + NWidgetBase *nwid = w->GetWidget(widget); + if (this->IsVertical()) { + this->SetCapacity(((int)nwid->current_y - padding) / (int)nwid->resize_y); + } else { + this->SetCapacity(((int)nwid->current_x - padding) / (int)nwid->resize_x); + } +} + +/** + * Scrollbar widget. + * @param tp Scrollbar type. (horizontal/vertical) + * @param colour Colour of the scrollbar. + * @param index Index in the widget array used by the window system. + */ +NWidgetScrollbar::NWidgetScrollbar(WidgetType tp, Colours colour, int index) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL), Scrollbar(tp != NWID_HSCROLLBAR) +{ + assert(tp == NWID_HSCROLLBAR || tp == NWID_VSCROLLBAR); + this->sizing_type = NWST_STEP; + this->SetIndex(index); + + switch (this->type) { + case NWID_HSCROLLBAR: + this->SetMinimalSize(0, NWidgetScrollbar::GetHorizontalDimension().height); + this->SetResize(1, 0); + this->SetFill(1, 0); + this->SetDataTip(0x0, STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST); + break; + + case NWID_VSCROLLBAR: + this->SetMinimalSize(NWidgetScrollbar::GetVerticalDimension().width, 0); + this->SetResize(0, 1); + this->SetFill(0, 1); + this->SetDataTip(0x0, STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST); + break; + + default: NOT_REACHED(); + } +} + +void NWidgetScrollbar::SetupSmallestSize(Window *w, bool init_array) +{ + if (init_array && this->index >= 0) { + assert(w->nested_array_size > (uint)this->index); + w->nested_array[this->index] = this; + } + this->smallest_x = this->min_x; + this->smallest_y = this->min_y; +} + +void NWidgetScrollbar::Draw(const Window *w) +{ + if (this->current_x == 0 || this->current_y == 0) return; + + Rect r; + r.left = this->pos_x; + r.right = this->pos_x + this->current_x - 1; + r.top = this->pos_y; + r.bottom = this->pos_y + this->current_y - 1; + + const DrawPixelInfo *dpi = _cur_dpi; + if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return; + + bool up_lowered = HasBit(this->disp_flags, NDB_SCROLLBAR_UP); + bool down_lowered = HasBit(this->disp_flags, NDB_SCROLLBAR_DOWN); + bool middle_lowered = !(this->disp_flags & ND_SCROLLBAR_BTN) && w->scrolling_scrollbar == this->index; + + if (this->type == NWID_HSCROLLBAR) { + DrawHorizontalScrollbar(r, this->colour, up_lowered, middle_lowered, down_lowered, this); + } else { + DrawVerticalScrollbar(r, this->colour, up_lowered, middle_lowered, down_lowered, this); + } + + if (this->IsDisabled()) { + GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); + } +} + +/* static */ void NWidgetScrollbar::InvalidateDimensionCache() +{ + vertical_dimension.width = vertical_dimension.height = 0; + horizontal_dimension.width = horizontal_dimension.height = 0; +} + +/* static */ Dimension NWidgetScrollbar::GetVerticalDimension() +{ + static const Dimension extra = {WD_SCROLLBAR_LEFT + WD_SCROLLBAR_RIGHT, WD_SCROLLBAR_TOP + WD_SCROLLBAR_BOTTOM}; + if (vertical_dimension.width == 0) { + vertical_dimension = maxdim(GetSpriteSize(SPR_ARROW_UP), GetSpriteSize(SPR_ARROW_DOWN)); + vertical_dimension.width += extra.width; + vertical_dimension.width = GetMinSizing(NWST_STEP, vertical_dimension.width); + vertical_dimension.height += extra.height; + vertical_dimension.height = GetMinSizing(NWST_STEP, vertical_dimension.height); + } + return vertical_dimension; +} + +/* static */ Dimension NWidgetScrollbar::GetHorizontalDimension() +{ + static const Dimension extra = {WD_SCROLLBAR_LEFT + WD_SCROLLBAR_RIGHT, WD_SCROLLBAR_TOP + WD_SCROLLBAR_BOTTOM}; + if (horizontal_dimension.width == 0) { + horizontal_dimension = maxdim(GetSpriteSize(SPR_ARROW_LEFT), GetSpriteSize(SPR_ARROW_RIGHT)); + horizontal_dimension.width += extra.width; + horizontal_dimension.width = GetMinSizing(NWST_STEP, horizontal_dimension.width); + horizontal_dimension.height += extra.height; + horizontal_dimension.height = GetMinSizing(NWST_STEP, horizontal_dimension.height); + } + return horizontal_dimension; +} + +Dimension NWidgetScrollbar::vertical_dimension = {0, 0}; +Dimension NWidgetScrollbar::horizontal_dimension = {0, 0}; + +/** Reset the cached dimensions. */ +/* static */ void NWidgetLeaf::InvalidateDimensionCache() +{ + shadebox_dimension.width = shadebox_dimension.height = 0; + debugbox_dimension.width = debugbox_dimension.height = 0; + defsizebox_dimension.width = defsizebox_dimension.height = 0; + stickybox_dimension.width = stickybox_dimension.height = 0; + resizebox_dimension.width = resizebox_dimension.height = 0; + closebox_dimension.width = closebox_dimension.height = 0; + dropdown_dimension.width = dropdown_dimension.height = 0; +} + +Dimension NWidgetLeaf::shadebox_dimension = {0, 0}; +Dimension NWidgetLeaf::debugbox_dimension = {0, 0}; +Dimension NWidgetLeaf::defsizebox_dimension = {0, 0}; +Dimension NWidgetLeaf::stickybox_dimension = {0, 0}; +Dimension NWidgetLeaf::resizebox_dimension = {0, 0}; +Dimension NWidgetLeaf::closebox_dimension = {0, 0}; +Dimension NWidgetLeaf::dropdown_dimension = {0, 0}; + +/** + * Nested leaf widget. + * @param tp Type of leaf widget. + * @param colour Colour of the leaf widget. + * @param index Index in the widget array used by the window system. + * @param data Data of the widget. + * @param tip Tooltip of the widget. + */ +NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, StringID tip) : NWidgetCore(tp, colour, 1, 1, data, tip) +{ + assert(this->sizing_type < NWST_END); + assert(index >= 0 || tp == WWT_LABEL || tp == WWT_TEXT || tp == WWT_CAPTION || tp == WWT_RESIZEBOX || tp == WWT_SHADEBOX || tp == WWT_DEFSIZEBOX || tp == WWT_DEBUGBOX || tp == WWT_STICKYBOX || tp == WWT_CLOSEBOX); + if (index >= 0) this->SetIndex(index); + + if (this->sizing_type == NWST_NONE) { + switch (tp) { + case WWT_PUSHBTN: + case WWT_IMGBTN: + case WWT_PUSHIMGBTN: + case WWT_IMGBTN_2: + case WWT_TEXTBTN: + case WWT_PUSHTXTBTN: + case WWT_TEXTBTN_2: + case WWT_PUSHARROWBTN: + case WWT_EDITBOX: + case WWT_CAPTION: + case WWT_STICKYBOX: + case WWT_SHADEBOX: + case WWT_DEBUGBOX: + case WWT_DEFSIZEBOX: + case WWT_RESIZEBOX: + case WWT_CLOSEBOX: + this->sizing_type = NWST_BUTTON; + break; + case NWID_PUSHBUTTON_DROPDOWN: + case NWID_BUTTON_DROPDOWN: + case WWT_DROPDOWN: + this->sizing_type = NWST_STEP; + break; + default: + this->sizing_type = NWST_OVERRIDE; + } + } + + this->SetMinimalSize(0, 0); + this->SetResize(0, 0); + + switch (tp) { + case WWT_EMPTY: + break; + + case WWT_PUSHBTN: + case WWT_IMGBTN: + case WWT_PUSHIMGBTN: + case WWT_IMGBTN_2: + case WWT_TEXTBTN: + case WWT_PUSHTXTBTN: + case WWT_TEXTBTN_2: + case WWT_LABEL: + case WWT_TEXT: + case WWT_MATRIX: + case NWID_BUTTON_DROPDOWN: + case NWID_PUSHBUTTON_DROPDOWN: + case WWT_ARROWBTN: + case WWT_PUSHARROWBTN: + this->SetFill(0, 0); + break; + + case WWT_EDITBOX: { + Dimension sprite_size = GetSpriteSize(_current_text_dir == TD_RTL ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); + this->SetMinimalSize(30 + GetMinSizing(NWST_BUTTON, sprite_size.width), sprite_size.height); + this->SetFill(0, 0); + break; + } + + case WWT_CAPTION: + this->SetFill(1, 0); + this->SetResize(1, 0); + this->min_y = WD_CAPTION_HEIGHT; + this->SetDataTip(data, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); + break; + + case WWT_STICKYBOX: + this->SetFill(0, 0); + this->SetMinimalSize(WD_STICKYBOX_WIDTH, WD_CAPTION_HEIGHT); + this->SetDataTip(STR_NULL, STR_TOOLTIP_STICKY); + break; + + case WWT_SHADEBOX: + this->SetFill(0, 0); + this->SetMinimalSize(WD_SHADEBOX_TOP, WD_CAPTION_HEIGHT); + this->SetDataTip(STR_NULL, STR_TOOLTIP_SHADE); + break; + + case WWT_DEBUGBOX: + this->SetFill(0, 0); + this->SetMinimalSize(WD_DEBUGBOX_TOP, WD_CAPTION_HEIGHT); + this->SetDataTip(STR_NULL, STR_TOOLTIP_DEBUG); + break; + + case WWT_DEFSIZEBOX: + this->SetFill(0, 0); + this->SetMinimalSize(WD_DEFSIZEBOX_TOP, WD_CAPTION_HEIGHT); + this->SetDataTip(STR_NULL, STR_TOOLTIP_DEFSIZE); + break; + + case WWT_RESIZEBOX: + this->SetFill(0, 0); + this->SetMinimalSize(WD_RESIZEBOX_WIDTH, 12); + this->SetDataTip(STR_NULL, STR_TOOLTIP_RESIZE); + break; + + case WWT_CLOSEBOX: + this->SetFill(0, 0); + this->SetMinimalSize(WD_CLOSEBOX_WIDTH, WD_CAPTION_HEIGHT); + this->SetDataTip(STR_BLACK_CROSS, STR_TOOLTIP_CLOSE_WINDOW); + break; + + case WWT_DROPDOWN: + this->SetFill(0, 0); + this->min_y = WD_DROPDOWN_HEIGHT; + break; + + default: + NOT_REACHED(); + } +} + +void NWidgetLeaf::SetupSmallestSize(Window *w, bool init_array) +{ + if (this->index >= 0 && init_array) { // Fill w->nested_array[] + assert(w->nested_array_size > (uint)this->index); + w->nested_array[this->index] = this; + } + + Dimension size = {this->min_x, this->min_y}; + Dimension fill = {this->fill_x, this->fill_y}; + Dimension resize = {this->resize_x, this->resize_y}; + /* Get padding, and update size with the real content size if appropriate. */ + const Dimension *padding = NULL; + switch (this->type) { + case WWT_EMPTY: { + static const Dimension extra = {0, 0}; + padding = &extra; + break; + } + case WWT_MATRIX: { + static const Dimension extra = {WD_MATRIX_LEFT + WD_MATRIX_RIGHT, WD_MATRIX_TOP + WD_MATRIX_BOTTOM}; + padding = &extra; + break; + } + case WWT_SHADEBOX: { + static const Dimension extra = {WD_SHADEBOX_LEFT + WD_SHADEBOX_RIGHT, WD_SHADEBOX_TOP + WD_SHADEBOX_BOTTOM}; + padding = &extra; + if (NWidgetLeaf::shadebox_dimension.width == 0) { + NWidgetLeaf::shadebox_dimension = maxdim(GetSpriteSize(SPR_WINDOW_SHADE), GetSpriteSize(SPR_WINDOW_UNSHADE)); + NWidgetLeaf::shadebox_dimension.width += extra.width; + NWidgetLeaf::shadebox_dimension.height += extra.height; + } + size = maxdim(size, NWidgetLeaf::shadebox_dimension); + break; + } + case WWT_DEBUGBOX: + if (_settings_client.gui.newgrf_developer_tools && w->IsNewGRFInspectable()) { + static const Dimension extra = {WD_DEBUGBOX_LEFT + WD_DEBUGBOX_RIGHT, WD_DEBUGBOX_TOP + WD_DEBUGBOX_BOTTOM}; + padding = &extra; + if (NWidgetLeaf::debugbox_dimension.width == 0) { + NWidgetLeaf::debugbox_dimension = GetSpriteSize(SPR_WINDOW_DEBUG); + NWidgetLeaf::debugbox_dimension.width += extra.width; + NWidgetLeaf::debugbox_dimension.height += extra.height; + } + size = maxdim(size, NWidgetLeaf::debugbox_dimension); + } else { + /* If the setting is disabled we don't want to see it! */ + size.width = 0; + fill.width = 0; + resize.width = 0; + } + break; + + case WWT_STICKYBOX: { + static const Dimension extra = {WD_STICKYBOX_LEFT + WD_STICKYBOX_RIGHT, WD_STICKYBOX_TOP + WD_STICKYBOX_BOTTOM}; + padding = &extra; + if (NWidgetLeaf::stickybox_dimension.width == 0) { + NWidgetLeaf::stickybox_dimension = maxdim(GetSpriteSize(SPR_PIN_UP), GetSpriteSize(SPR_PIN_DOWN)); + NWidgetLeaf::stickybox_dimension.width += extra.width; + NWidgetLeaf::stickybox_dimension.height += extra.height; + } + size = maxdim(size, NWidgetLeaf::stickybox_dimension); + break; + } + + case WWT_DEFSIZEBOX: { + static const Dimension extra = {WD_DEFSIZEBOX_LEFT + WD_DEFSIZEBOX_RIGHT, WD_DEFSIZEBOX_TOP + WD_DEFSIZEBOX_BOTTOM}; + padding = &extra; + if (NWidgetLeaf::defsizebox_dimension.width == 0) { + NWidgetLeaf::defsizebox_dimension = GetSpriteSize(SPR_WINDOW_DEFSIZE); + NWidgetLeaf::defsizebox_dimension.width += extra.width; + NWidgetLeaf::defsizebox_dimension.height += extra.height; + } + size = maxdim(size, NWidgetLeaf::defsizebox_dimension); + break; + } + + case WWT_RESIZEBOX: { + static const Dimension extra = {WD_RESIZEBOX_LEFT + WD_RESIZEBOX_RIGHT, WD_RESIZEBOX_TOP + WD_RESIZEBOX_BOTTOM}; + padding = &extra; + if (NWidgetLeaf::resizebox_dimension.width == 0) { + NWidgetLeaf::resizebox_dimension = maxdim(GetSpriteSize(SPR_WINDOW_RESIZE_LEFT), GetSpriteSize(SPR_WINDOW_RESIZE_RIGHT)); + NWidgetLeaf::resizebox_dimension.width += extra.width; + NWidgetLeaf::resizebox_dimension.height += extra.height; + } + size = maxdim(size, NWidgetLeaf::resizebox_dimension); + break; + } + case WWT_EDITBOX: + size.height = max(size.height, GetStringBoundingBox("_").height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); + /* FALL THROUGH */ + case WWT_PUSHBTN: { + static const Dimension extra = {WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM}; + padding = &extra; + break; + } + case WWT_IMGBTN: + case WWT_IMGBTN_2: + case WWT_PUSHIMGBTN: { + static const Dimension extra = {WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT, WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM}; + padding = &extra; + Dimension d2 = GetSpriteSize(this->widget_data); + if (this->type == WWT_IMGBTN_2) d2 = maxdim(d2, GetSpriteSize(this->widget_data + 1)); + d2.width += extra.width; + d2.height += extra.height; + size = maxdim(size, d2); + break; + } + case WWT_ARROWBTN: + case WWT_PUSHARROWBTN: { + static const Dimension extra = {WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT, WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM}; + padding = &extra; + Dimension d2 = maxdim(GetSpriteSize(SPR_ARROW_LEFT), GetSpriteSize(SPR_ARROW_RIGHT)); + d2.width += extra.width; + d2.height += extra.height; + size = maxdim(size, d2); + break; + } + + case WWT_CLOSEBOX: { + static const Dimension extra = {WD_CLOSEBOX_LEFT + WD_CLOSEBOX_RIGHT, WD_CLOSEBOX_TOP + WD_CLOSEBOX_BOTTOM}; + padding = &extra; + if (NWidgetLeaf::closebox_dimension.width == 0) { + NWidgetLeaf::closebox_dimension = maxdim(GetStringBoundingBox(STR_BLACK_CROSS), GetStringBoundingBox(STR_SILVER_CROSS)); + NWidgetLeaf::closebox_dimension.width += extra.width; + NWidgetLeaf::closebox_dimension.height += extra.height; + } + size = maxdim(size, NWidgetLeaf::closebox_dimension); + break; + } + case WWT_TEXTBTN: + case WWT_PUSHTXTBTN: + case WWT_TEXTBTN_2: { + static const Dimension extra = {WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM}; + padding = &extra; + if (this->index >= 0) w->SetStringParameters(this->index); + Dimension d2 = GetStringBoundingBox(this->widget_data); + d2.width += extra.width; + d2.height += extra.height; + size = maxdim(size, d2); + break; + } + case WWT_LABEL: + case WWT_TEXT: { + static const Dimension extra = {0, 0}; + padding = &extra; + if (this->index >= 0) w->SetStringParameters(this->index); + size = maxdim(size, GetStringBoundingBox(this->widget_data)); + break; + } + case WWT_CAPTION: { + static const Dimension extra = {WD_CAPTIONTEXT_LEFT + WD_CAPTIONTEXT_RIGHT, WD_CAPTIONTEXT_TOP + WD_CAPTIONTEXT_BOTTOM}; + padding = &extra; + if (this->index >= 0) w->SetStringParameters(this->index); + Dimension d2 = GetStringBoundingBox(this->widget_data); + d2.width += extra.width; + d2.height += extra.height; + size = maxdim(size, d2); + break; + } + case WWT_DROPDOWN: + case NWID_BUTTON_DROPDOWN: + case NWID_PUSHBUTTON_DROPDOWN: { + static Dimension extra = {WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM}; + padding = &extra; + if (NWidgetLeaf::dropdown_dimension.width == 0) { + NWidgetLeaf::dropdown_dimension = GetSpriteSize(SPR_ARROW_DOWN); + NWidgetLeaf::dropdown_dimension.width += WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT; + NWidgetLeaf::dropdown_dimension.height += WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM; + extra.width = WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT + NWidgetLeaf::dropdown_dimension.width; + } + if (this->index >= 0) w->SetStringParameters(this->index); + Dimension d2 = GetStringBoundingBox(this->widget_data); + d2.width += extra.width; + d2.height += extra.height; + size = maxdim(size, d2); + break; + } + default: + NOT_REACHED(); + } + + if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, *padding, &fill, &resize); + + this->smallest_x = size.width; + this->smallest_y = size.height; + this->fill_x = fill.width; + this->fill_y = fill.height; + this->resize_x = resize.width; + this->resize_y = resize.height; +} + +void NWidgetLeaf::Draw(const Window *w) +{ + if (this->current_x == 0 || this->current_y == 0) return; + + Rect r; + r.left = this->pos_x; + r.right = this->pos_x + this->current_x - 1; + r.top = this->pos_y; + r.bottom = this->pos_y + this->current_y - 1; + + const DrawPixelInfo *dpi = _cur_dpi; + if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return; + + bool clicked = this->IsLowered(); + switch (this->type) { + case WWT_EMPTY: + break; + + case WWT_PUSHBTN: + assert(this->widget_data == 0); + DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, (clicked) ? FR_LOWERED : FR_NONE); + break; + + case WWT_IMGBTN: + case WWT_PUSHIMGBTN: + case WWT_IMGBTN_2: + DrawImageButtons(r, this->type, this->colour, clicked, this->widget_data); + break; + + case WWT_TEXTBTN: + case WWT_PUSHTXTBTN: + case WWT_TEXTBTN_2: + if (this->index >= 0) w->SetStringParameters(this->index); + DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, (clicked) ? FR_LOWERED : FR_NONE); + DrawLabel(r, this->type, clicked, this->widget_data); + break; + + case WWT_ARROWBTN: + case WWT_PUSHARROWBTN: { + SpriteID sprite; + switch (this->widget_data) { + case AWV_DECREASE: sprite = _current_text_dir != TD_RTL ? SPR_ARROW_LEFT : SPR_ARROW_RIGHT; break; + case AWV_INCREASE: sprite = _current_text_dir == TD_RTL ? SPR_ARROW_LEFT : SPR_ARROW_RIGHT; break; + case AWV_LEFT: sprite = SPR_ARROW_LEFT; break; + case AWV_RIGHT: sprite = SPR_ARROW_RIGHT; break; + default: NOT_REACHED(); + } + DrawImageButtons(r, WWT_PUSHIMGBTN, this->colour, clicked, sprite); + break; + } + + case WWT_LABEL: + if (this->index >= 0) w->SetStringParameters(this->index); + DrawLabel(r, this->type, clicked, this->widget_data); + break; + + case WWT_TEXT: + if (this->index >= 0) w->SetStringParameters(this->index); + DrawText(r, (TextColour)this->colour, this->widget_data); + break; + + case WWT_MATRIX: + DrawMatrix(r, this->colour, clicked, this->widget_data, this->resize_x, this->resize_y); + break; + + case WWT_EDITBOX: { + const QueryString *query = w->GetQueryString(this->index); + if (query != NULL) query->DrawEditBox(w, this->index); + break; + } + + case WWT_CAPTION: + if (this->index >= 0) w->SetStringParameters(this->index); + DrawCaption(r, this->colour, w->owner, this->widget_data); + break; + + case WWT_SHADEBOX: + assert(this->widget_data == 0); + DrawImageButtons(r, WWT_SHADEBOX, this->colour, w->IsShaded(), w->IsShaded() ? SPR_WINDOW_SHADE : SPR_WINDOW_UNSHADE); + break; + + case WWT_DEBUGBOX: + DrawImageButtons(r, WWT_DEBUGBOX, this->colour, clicked, SPR_WINDOW_DEBUG); + break; + + case WWT_STICKYBOX: { + assert(this->widget_data == 0); + bool clicked = !!(w->flags & WF_STICKY); + DrawImageButtons(r, WWT_STICKYBOX, this->colour, clicked, clicked ? SPR_PIN_DOWN : SPR_PIN_UP); + break; + } + + case WWT_DEFSIZEBOX: + assert(this->widget_data == 0); + DrawImageButtons(r, WWT_DEFSIZEBOX, this->colour, clicked, SPR_WINDOW_DEFSIZE); + break; + + case WWT_RESIZEBOX: + assert(this->widget_data == 0); + DrawResizeBox(r, this->colour, this->pos_x < (uint)(w->width / 2), !!(w->flags & WF_SIZING)); + break; + + case WWT_CLOSEBOX: + DrawCloseBox(r, this->colour, this->widget_data); + break; + + case WWT_DROPDOWN: + if (this->index >= 0) w->SetStringParameters(this->index); + DrawDropdown(r, this->colour, clicked, this->widget_data); + break; + + case NWID_BUTTON_DROPDOWN: + case NWID_PUSHBUTTON_DROPDOWN: + if (this->index >= 0) w->SetStringParameters(this->index); + DrawButtonDropdown(r, this->colour, clicked, (this->disp_flags & ND_DROPDOWN_ACTIVE) != 0, this->widget_data); + break; + + default: + NOT_REACHED(); + } + if (this->index >= 0) w->DrawWidget(r, this->index); + + if (this->IsDisabled()) { + GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); + } +} + +/** + * For a #NWID_BUTTON_DROPDOWN, test whether \a pt refers to the button or to the drop-down. + * @param pt Point in the widget. + * @return The point refers to the button. + * + * @note The magic constants are also used at #DrawButtonDropdown. + */ +bool NWidgetLeaf::ButtonHit(const Point &pt) +{ + uint button_size = GetMinSizing(NWST_STEP, 12); + if (_current_text_dir == TD_LTR) { + int button_width = this->pos_x + this->current_x - button_size; + return pt.x < button_width; + } else { + int button_left = this->pos_x + button_size; + return pt.x >= button_left; + } +} + +/* == Conversion code from NWidgetPart array to NWidgetBase* tree == */ + +/** + * Construct a single nested widget in \a *dest from its parts. + * + * Construct a NWidgetBase object from a #NWidget function, and apply all + * settings that follow it, until encountering a #EndContainer, another + * #NWidget, or the end of the parts array. + * + * @param parts Array with parts of the nested widget. + * @param count Length of the \a parts array. + * @param dest Address of pointer to use for returning the composed widget. + * @param fill_dest Fill the composed widget with child widgets. + * @param biggest_index Pointer to biggest nested widget index in the tree encountered so far. + * @return Number of widget part elements used to compose the widget. + * @pre \c biggest_index != NULL. + */ +static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, bool *fill_dest, int *biggest_index) +{ + int num_used = 0; + + *dest = NULL; + *fill_dest = false; + + while (count > num_used) { + switch (parts->type) { + case NWID_SPACER: + if (*dest != NULL) return num_used; + *dest = new NWidgetSpacer(0, 0); + break; + + case NWID_HORIZONTAL: + if (*dest != NULL) return num_used; + *dest = new NWidgetHorizontal(parts->u.cont_flags); + *fill_dest = true; + break; + + case NWID_HORIZONTAL_LTR: + if (*dest != NULL) return num_used; + *dest = new NWidgetHorizontalLTR(parts->u.cont_flags); + *fill_dest = true; + break; + + case WWT_PANEL: + case WWT_INSET: + case WWT_FRAME: + if (*dest != NULL) return num_used; + *dest = new NWidgetBackground(parts->type, parts->u.widget.colour, parts->u.widget.index); + *biggest_index = max(*biggest_index, (int)parts->u.widget.index); + *fill_dest = true; + break; + + case NWID_VERTICAL: + if (*dest != NULL) return num_used; + *dest = new NWidgetVertical(parts->u.cont_flags); + *fill_dest = true; + break; + + case NWID_MATRIX: { + if (*dest != NULL) return num_used; + NWidgetMatrix *nwm = new NWidgetMatrix(); + *dest = nwm; + *fill_dest = true; + nwm->SetIndex(parts->u.widget.index); + nwm->SetColour(parts->u.widget.colour); + *biggest_index = max(*biggest_index, (int)parts->u.widget.index); + break; + } + + case WPT_FUNCTION: { + if (*dest != NULL) return num_used; + /* Ensure proper functioning even when the called code simply writes its largest index. */ + int biggest = -1; + *dest = parts->u.func_ptr(&biggest); + *biggest_index = max(*biggest_index, biggest); + *fill_dest = false; + break; + } + + case WPT_RESIZE: { + NWidgetResizeBase *nwrb = dynamic_cast(*dest); + if (nwrb != NULL) { + assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0); + nwrb->SetResize(parts->u.xy.x, parts->u.xy.y); + } + break; + } + + case WPT_SIZINGTYPE: { + NWidgetResizeBase *nwrb = dynamic_cast(*dest); + if (nwrb != NULL) { + assert(parts->u.sizing_type < NWST_END); + nwrb->sizing_type = parts->u.sizing_type; + nwrb->SetMinimalSize(0, 0); + } + break; + } + + case WPT_MINSIZE: { + NWidgetResizeBase *nwrb = dynamic_cast(*dest); + if (nwrb != NULL) { + assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0); + nwrb->SetMinimalSize(parts->u.xy.x, parts->u.xy.y); + } + break; + } + + case WPT_MINTEXTLINES: { + NWidgetResizeBase *nwrb = dynamic_cast(*dest); + if (nwrb != NULL) { + assert(parts->u.text_lines.size >= FS_BEGIN && parts->u.text_lines.size < FS_END); + nwrb->SetMinimalTextLines(parts->u.text_lines.lines, parts->u.text_lines.spacing, parts->u.text_lines.size); + } + break; + } + + case WPT_FILL: { + NWidgetResizeBase *nwrb = dynamic_cast(*dest); + if (nwrb != NULL) nwrb->SetFill(parts->u.xy.x, parts->u.xy.y); + break; + } + + case WPT_DATATIP: { + NWidgetCore *nwc = dynamic_cast(*dest); + if (nwc != NULL) { + nwc->widget_data = parts->u.data_tip.data; + nwc->tool_tip = parts->u.data_tip.tooltip; + } + break; + } + + case WPT_PADDING: + if (*dest != NULL) (*dest)->SetPadding(parts->u.padding.top, parts->u.padding.right, parts->u.padding.bottom, parts->u.padding.left); + break; + + case WPT_PIPSPACE: { + NWidgetPIPContainer *nwc = dynamic_cast(*dest); + if (nwc != NULL) nwc->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); + + NWidgetBackground *nwb = dynamic_cast(*dest); + if (nwb != NULL) nwb->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); + break; + } + + case WPT_SCROLLBAR: { + NWidgetCore *nwc = dynamic_cast(*dest); + if (nwc != NULL) { + nwc->scrollbar_index = parts->u.widget.index; + } + break; + } + + case WPT_ENDCONTAINER: + return num_used; + + case NWID_VIEWPORT: + if (*dest != NULL) return num_used; + *dest = new NWidgetViewport(parts->u.widget.index); + *biggest_index = max(*biggest_index, (int)parts->u.widget.index); + break; + + case NWID_HSCROLLBAR: + case NWID_VSCROLLBAR: + if (*dest != NULL) return num_used; + *dest = new NWidgetScrollbar(parts->type, parts->u.widget.colour, parts->u.widget.index); + *biggest_index = max(*biggest_index, (int)parts->u.widget.index); + break; + + case NWID_SELECTION: { + if (*dest != NULL) return num_used; + NWidgetStacked *nws = new NWidgetStacked(); + *dest = nws; + *fill_dest = true; + nws->SetIndex(parts->u.widget.index); + *biggest_index = max(*biggest_index, (int)parts->u.widget.index); + break; + } + + default: + if (*dest != NULL) return num_used; + assert((parts->type & WWT_MASK) < WWT_LAST || (parts->type & WWT_MASK) == NWID_BUTTON_DROPDOWN); + *dest = new NWidgetLeaf(parts->type, parts->u.widget.colour, parts->u.widget.index, 0x0, STR_NULL); + *biggest_index = max(*biggest_index, (int)parts->u.widget.index); + break; + } + num_used++; + parts++; + } + + return num_used; +} + +/** + * Build a nested widget tree by recursively filling containers with nested widgets read from their parts. + * @param parts Array with parts of the nested widgets. + * @param count Length of the \a parts array. + * @param parent Pointer or container to use for storing the child widgets (*parent == NULL or *parent == container or background widget). + * @param biggest_index Pointer to biggest nested widget index in the tree. + * @return Number of widget part elements used to fill the container. + * @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used. + */ +static int MakeWidgetTree(const NWidgetPart *parts, int count, NWidgetBase **parent, int *biggest_index) +{ + /* If *parent == NULL, only the first widget is read and returned. Otherwise, *parent must point to either + * a #NWidgetContainer or a #NWidgetBackground object, and parts are added as much as possible. */ + NWidgetContainer *nwid_cont = dynamic_cast(*parent); + NWidgetBackground *nwid_parent = dynamic_cast(*parent); + assert(*parent == NULL || (nwid_cont != NULL && nwid_parent == NULL) || (nwid_cont == NULL && nwid_parent != NULL)); + + int total_used = 0; + for (;;) { + NWidgetBase *sub_widget = NULL; + bool fill_sub = false; + int num_used = MakeNWidget(parts, count - total_used, &sub_widget, &fill_sub, biggest_index); + parts += num_used; + total_used += num_used; + + /* Break out of loop when end reached */ + if (sub_widget == NULL) break; + + /* If sub-widget is a container, recursively fill that container. */ + WidgetType tp = sub_widget->type; + if (fill_sub && (tp == NWID_HORIZONTAL || tp == NWID_HORIZONTAL_LTR || tp == NWID_VERTICAL || tp == NWID_MATRIX + || tp == WWT_PANEL || tp == WWT_FRAME || tp == WWT_INSET || tp == NWID_SELECTION)) { + NWidgetBase *sub_ptr = sub_widget; + int num_used = MakeWidgetTree(parts, count - total_used, &sub_ptr, biggest_index); + parts += num_used; + total_used += num_used; + } + + /* Add sub_widget to parent container if available, otherwise return the widget to the caller. */ + if (nwid_cont != NULL) nwid_cont->Add(sub_widget); + if (nwid_parent != NULL) nwid_parent->Add(sub_widget); + if (nwid_cont == NULL && nwid_parent == NULL) { + *parent = sub_widget; + return total_used; + } + } + + if (count == total_used) return total_used; // Reached the end of the array of parts? + + assert(total_used < count); + assert(parts->type == WPT_ENDCONTAINER); + return total_used + 1; // *parts is also 'used' +} + +/** + * Construct a nested widget tree from an array of parts. + * @param parts Array with parts of the widgets. + * @param count Length of the \a parts array. + * @param biggest_index Pointer to biggest nested widget index collected in the tree. + * @param container Container to add the nested widgets to. In case it is NULL a vertical container is used. + * @return Root of the nested widget tree, a vertical container containing the entire GUI. + * @ingroup NestedWidgetParts + * @pre \c biggest_index != NULL + * @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used. + */ +NWidgetContainer *MakeNWidgets(const NWidgetPart *parts, int count, int *biggest_index, NWidgetContainer *container) +{ + *biggest_index = -1; + if (container == NULL) container = new NWidgetVertical(); + NWidgetBase *cont_ptr = container; + MakeWidgetTree(parts, count, &cont_ptr, biggest_index); + return container; +} + +/** + * Make a nested widget tree for a window from a parts array. Besides loading, it inserts a shading selection widget + * between the title bar and the window body if the first widget in the parts array looks like a title bar (it is a horizontal + * container with a caption widget) and has a shade box widget. + * @param parts Array with parts of the widgets. + * @param count Length of the \a parts array. + * @param biggest_index Pointer to biggest nested widget index collected in the tree. + * @param [out] shade_select Pointer to the inserted shade selection widget (\c NULL if not unserted). + * @return Root of the nested widget tree, a vertical container containing the entire GUI. + * @ingroup NestedWidgetParts + * @pre \c biggest_index != NULL + * @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used. + */ +NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *parts, int count, int *biggest_index, NWidgetStacked **shade_select) +{ + *biggest_index = -1; + + /* Read the first widget recursively from the array. */ + NWidgetBase *nwid = NULL; + int num_used = MakeWidgetTree(parts, count, &nwid, biggest_index); + assert(nwid != NULL); + parts += num_used; + count -= num_used; + + NWidgetContainer *root = new NWidgetVertical; + root->Add(nwid); + if (count == 0) { // There is no body at all. + *shade_select = NULL; + return root; + } + + /* If the first widget looks like a titlebar, treat it as such. + * If it has a shading box, silently add a shade selection widget in the tree. */ + NWidgetHorizontal *hor_cont = dynamic_cast(nwid); + NWidgetContainer *body; + if (hor_cont != NULL && hor_cont->GetWidgetOfType(WWT_CAPTION) != NULL && hor_cont->GetWidgetOfType(WWT_SHADEBOX) != NULL) { + *shade_select = new NWidgetStacked; + root->Add(*shade_select); + body = new NWidgetVertical; + (*shade_select)->Add(body); + } else { + *shade_select = NULL; + body = root; + } + + /* Load the remaining parts into 'body'. */ + int biggest2 = -1; + MakeNWidgets(parts, count, &biggest2, body); + + *biggest_index = max(*biggest_index, biggest2); + return root; +} + +/** + * Make a number of rows with button-like graphics, for enabling/disabling each company. + * @param biggest_index Storage for collecting the biggest index used in the returned tree. + * @param widget_first The first widget index to use. + * @param widget_last The last widget index to use. + * @param max_length Maximal number of company buttons in one row. + * @param button_tooltip The tooltip-string of every button. + * @return Panel with rows of company buttons. + * @post \c *biggest_index contains the largest used index in the tree. + */ +NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int widget_last, int max_length, StringID button_tooltip) +{ + assert(max_length >= 1); + NWidgetVertical *vert = NULL; // Storage for all rows. + NWidgetHorizontal *hor = NULL; // Storage for buttons in one row. + int hor_length = 0; + + Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON); + sprite_size.width += WD_MATRIX_LEFT + WD_MATRIX_RIGHT; + sprite_size.height += WD_MATRIX_TOP + WD_MATRIX_BOTTOM + 1; // 1 for the 'offset' of being pressed + + for (int widnum = widget_first; widnum <= widget_last; widnum++) { + /* Ensure there is room in 'hor' for another button. */ + if (hor_length == max_length) { + if (vert == NULL) vert = new NWidgetVertical(); + vert->Add(hor); + hor = NULL; + hor_length = 0; + } + if (hor == NULL) { + hor = new NWidgetHorizontal(); + hor_length = 0; + } + + NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum); + panel->sizing_type = NWST_STEP; + panel->SetMinimalSize(sprite_size.width, sprite_size.height); + panel->SetFill(1, 1); + panel->SetResize(1, 0); + panel->SetDataTip(0x0, button_tooltip); + hor->Add(panel); + hor_length++; + } + *biggest_index = widget_last; + if (vert == NULL) return hor; // All buttons fit in a single row. + + if (hor_length > 0 && hor_length < max_length) { + /* Last row is partial, add a spacer at the end to force all buttons to the left. */ + NWidgetSpacer *spc = new NWidgetSpacer(sprite_size.width, sprite_size.height); + spc->SetFill(1, 1); + spc->SetResize(1, 0); + hor->Add(spc); + } + if (hor != NULL) vert->Add(hor); + return vert; +} + +/** + * Return the minimal automatic size for a widget. + * @param type The automatic sizing type to use. + * @param min_1 Minimal passed value. + * @return At least the passed value, or the minimal size for the associated sizing type. + */ +uint GetMinSizing(NWidSizingType type, uint min_1) +{ + uint min_sizing; + switch (type) { + case NWST_NONE: + case NWST_OVERRIDE: + return min_1; + case NWST_BUTTON: + min_sizing = _settings_client.gui.min_button; + break; + case NWST_STEP: + min_sizing = _settings_client.gui.min_step; + break; + case NWST_KEYBOARD: + min_sizing = 2 * _settings_client.gui.min_button; + break; + case NWST_WINDOW_LENGTH: + min_sizing = 8 * _settings_client.gui.min_button; + break; + default: NOT_REACHED(); + } + + return max(min_sizing, min_1); +} diff --git a/src/window.cpp.orig b/src/window.cpp.orig new file mode 100644 index 0000000000..710a9f4140 --- /dev/null +++ b/src/window.cpp.orig @@ -0,0 +1,3515 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file window.cpp Windowing system, widgets and events */ + +#include "stdafx.h" +#include +#include "company_func.h" +#include "gfx_func.h" +#include "console_func.h" +#include "console_gui.h" +#include "viewport_func.h" +#include "progress.h" +#include "blitter/factory.hpp" +#include "zoom_func.h" +#include "vehicle_base.h" +#include "window_func.h" +#include "tilehighlight_func.h" +#include "network/network.h" +#include "querystring_gui.h" +#include "widgets/dropdown_func.h" +#include "strings_func.h" +#include "settings_type.h" +#include "settings_func.h" +#include "ini_type.h" +#include "newgrf_debug.h" +#include "hotkeys.h" +#include "toolbar_gui.h" +#include "statusbar_gui.h" +#include "error.h" +#include "game/game.hpp" +#include "video/video_driver.hpp" +#include "settings_gui.h" +#include "fontcache.h" +#include "error.h" +#include "station_base.h" +#include "waypoint_base.h" +#include "command_func.h" + +#include "table/strings.h" + +/** Values for _settings_client.gui.auto_scrolling */ +enum ViewportAutoscrolling { + VA_DISABLED, //!< Do not autoscroll when mouse is at edge of viewport. + VA_MAIN_VIEWPORT_FULLSCREEN, //!< Scroll main viewport at edge when using fullscreen. + VA_MAIN_VIEWPORT, //!< Scroll main viewport at edge. + VA_EVERY_VIEWPORT, //!< Scroll all viewports at their edges. +}; + +static Point _drag_delta; ///< delta between mouse cursor and upper left corner of dragged window +static Window *_mouseover_last_w = NULL; ///< Window of the last #MOUSEOVER event. +static Window *_last_scroll_window = NULL; ///< Window of the last scroll event. + +/** List of windows opened at the screen sorted from the front. */ +Window *_z_front_window = NULL; +/** List of windows opened at the screen sorted from the back. */ +Window *_z_back_window = NULL; + +/** If false, highlight is white, otherwise the by the widget defined colour. */ +bool _window_highlight_colour = false; + +/* + * Window that currently has focus. - The main purpose is to generate + * #FocusLost events, not to give next window in z-order focus when a + * window is closed. + */ +Window *_focused_window; + +Point _cursorpos_drag_start; + +int _scrollbar_start_pos; +int _scrollbar_size; +byte _scroller_click_timeout = 0; + +bool _scrolling_viewport; ///< A viewport is being scrolled with the mouse. +bool _mouse_hovering; ///< The mouse is hovering over the same point. + +SpecialMouseMode _special_mouse_mode; ///< Mode of the mouse. + +/** + * List of all WindowDescs. + * This is a pointer to ensure initialisation order with the various static WindowDesc instances. + */ +static SmallVector *_window_descs = NULL; + +/** Config file to store WindowDesc */ +char *_windows_file; + +/** Window description constructor. */ +WindowDesc::WindowDesc(WindowPosition def_pos, const char *ini_key, int16 def_width, int16 def_height, + WindowClass window_class, WindowClass parent_class, uint32 flags, + const NWidgetPart *nwid_parts, int16 nwid_length, HotkeyList *hotkeys) : + default_pos(def_pos), + default_width(def_width), + default_height(def_height), + cls(window_class), + parent_cls(parent_class), + ini_key(ini_key), + flags(flags), + nwid_parts(nwid_parts), + nwid_length(nwid_length), + hotkeys(hotkeys), + pref_sticky(false), + pref_width(0), + pref_height(0) +{ + if (_window_descs == NULL) _window_descs = new SmallVector(); + *_window_descs->Append() = this; +} + +WindowDesc::~WindowDesc() +{ + _window_descs->Erase(_window_descs->Find(this)); +} + +/** + * Load all WindowDesc settings from _windows_file. + */ +void WindowDesc::LoadFromConfig() +{ + IniFile *ini = new IniFile(); + ini->LoadFromDisk(_windows_file, BASE_DIR); + for (WindowDesc **it = _window_descs->Begin(); it != _window_descs->End(); ++it) { + if ((*it)->ini_key == NULL) continue; + IniLoadWindowSettings(ini, (*it)->ini_key, *it); + } + delete ini; +} + +/** + * Sort WindowDesc by ini_key. + */ +static int CDECL DescSorter(WindowDesc * const *a, WindowDesc * const *b) +{ + if ((*a)->ini_key != NULL && (*b)->ini_key != NULL) return strcmp((*a)->ini_key, (*b)->ini_key); + return ((*b)->ini_key != NULL ? 1 : 0) - ((*a)->ini_key != NULL ? 1 : 0); +} + +/** + * Save all WindowDesc settings to _windows_file. + */ +void WindowDesc::SaveToConfig() +{ + /* Sort the stuff to get a nice ini file on first write */ + QSortT(_window_descs->Begin(), _window_descs->Length(), DescSorter); + + IniFile *ini = new IniFile(); + ini->LoadFromDisk(_windows_file, BASE_DIR); + for (WindowDesc **it = _window_descs->Begin(); it != _window_descs->End(); ++it) { + if ((*it)->ini_key == NULL) continue; + IniSaveWindowSettings(ini, (*it)->ini_key, *it); + } + ini->SaveToDisk(_windows_file); + delete ini; +} + +/** + * Read default values from WindowDesc configuration an apply them to the window. + */ +void Window::ApplyDefaults() +{ + if (this->nested_root != NULL && this->nested_root->GetWidgetOfType(WWT_STICKYBOX) != NULL) { + if (this->window_desc->pref_sticky) this->flags |= WF_STICKY; + } else { + /* There is no stickybox; clear the preference in case someone tried to be funny */ + this->window_desc->pref_sticky = false; + } +} + +/** + * Compute the row of a widget that a user clicked in. + * @param clickpos Vertical position of the mouse click. + * @param widget Widget number of the widget clicked in. + * @param padding Amount of empty space between the widget edge and the top of the first row. + * @param line_height Height of a single row. A negative value means using the vertical resize step of the widget. + * @return Row number clicked at. If clicked at a wrong position, #INT_MAX is returned. + * @note The widget does not know where a list printed at the widget ends, so below a list is not a wrong position. + */ +int Window::GetRowFromWidget(int clickpos, int widget, int padding, int line_height) const +{ + const NWidgetBase *wid = this->GetWidget(widget); + if (line_height < 0) line_height = wid->resize_y; + if (clickpos < (int)wid->pos_y + padding) return INT_MAX; + return (clickpos - (int)wid->pos_y - padding) / line_height; +} + +/** + * Disable the highlighted status of all widgets. + */ +void Window::DisableAllWidgetHighlight() +{ + for (uint i = 0; i < this->nested_array_size; i++) { + NWidgetBase *nwid = this->GetWidget(i); + if (nwid == NULL) continue; + + if (nwid->IsHighlighted()) { + nwid->SetHighlighted(TC_INVALID); + this->SetWidgetDirty(i); + } + } + + CLRBITS(this->flags, WF_HIGHLIGHTED); +} + +/** + * Sets the highlighted status of a widget. + * @param widget_index index of this widget in the window + * @param highlighted_colour Colour of highlight, or TC_INVALID to disable. + */ +void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour) +{ + assert(widget_index < this->nested_array_size); + + NWidgetBase *nwid = this->GetWidget(widget_index); + if (nwid == NULL) return; + + nwid->SetHighlighted(highlighted_colour); + this->SetWidgetDirty(widget_index); + + if (highlighted_colour != TC_INVALID) { + /* If we set a highlight, the window has a highlight */ + this->flags |= WF_HIGHLIGHTED; + } else { + /* If we disable a highlight, check all widgets if anyone still has a highlight */ + bool valid = false; + for (uint i = 0; i < this->nested_array_size; i++) { + NWidgetBase *nwid = this->GetWidget(i); + if (nwid == NULL) continue; + if (!nwid->IsHighlighted()) continue; + + valid = true; + } + /* If nobody has a highlight, disable the flag on the window */ + if (!valid) CLRBITS(this->flags, WF_HIGHLIGHTED); + } +} + +/** + * Gets the highlighted status of a widget. + * @param widget_index index of this widget in the window + * @return status of the widget ie: highlighted = true, not highlighted = false + */ +bool Window::IsWidgetHighlighted(byte widget_index) const +{ + assert(widget_index < this->nested_array_size); + + const NWidgetBase *nwid = this->GetWidget(widget_index); + if (nwid == NULL) return false; + + return nwid->IsHighlighted(); +} + +/** + * A dropdown window associated to this window has been closed. + * @param pt the point inside the window the mouse resides on after closure. + * @param widget the widget (button) that the dropdown is associated with. + * @param index the element in the dropdown that is selected. + * @param instant_close whether the dropdown was configured to close on mouse up. + */ +void Window::OnDropdownClose(Point pt, int widget, int index, bool instant_close) +{ + if (widget < 0) return; + + if (instant_close) { + /* Send event for selected option if we're still + * on the parent button of the dropdown (behaviour of the dropdowns in the main toolbar). */ + if (GetWidgetFromPos(this, pt.x, pt.y) == widget) { + this->OnDropdownSelect(widget, index); + } + } + + /* Raise the dropdown button */ + NWidgetCore *nwi2 = this->GetWidget(widget); + if ((nwi2->type & WWT_MASK) == NWID_BUTTON_DROPDOWN) { + nwi2->disp_flags &= ~ND_DROPDOWN_ACTIVE; + } else { + this->RaiseWidget(widget); + } + this->SetWidgetDirty(widget); +} + +/** + * Return the Scrollbar to a widget index. + * @param widnum Scrollbar widget index + * @return Scrollbar to the widget + */ +const Scrollbar *Window::GetScrollbar(uint widnum) const +{ + return this->GetWidget(widnum); +} + +/** + * Return the Scrollbar to a widget index. + * @param widnum Scrollbar widget index + * @return Scrollbar to the widget + */ +Scrollbar *Window::GetScrollbar(uint widnum) +{ + return this->GetWidget(widnum); +} + +/** + * Return the querystring associated to a editbox. + * @param widnum Editbox widget index + * @return QueryString or NULL. + */ +const QueryString *Window::GetQueryString(uint widnum) const +{ + const SmallMap::Pair *query = this->querystrings.Find(widnum); + return query != this->querystrings.End() ? query->second : NULL; +} + +/** + * Return the querystring associated to a editbox. + * @param widnum Editbox widget index + * @return QueryString or NULL. + */ +QueryString *Window::GetQueryString(uint widnum) +{ + SmallMap::Pair *query = this->querystrings.Find(widnum); + return query != this->querystrings.End() ? query->second : NULL; +} + +/** + * Get the current input text if an edit box has the focus. + * @return The currently focused input text or NULL if no input focused. + */ +/* virtual */ const char *Window::GetFocusedText() const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetText(); + } + + return NULL; +} + +/** + * Get the string at the caret if an edit box has the focus. + * @return The text at the caret or NULL if no edit box is focused. + */ +/* virtual */ const char *Window::GetCaret() const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetCaret(); + } + + return NULL; +} + +/** + * Get the range of the currently marked input text. + * @param[out] length Length of the marked text. + * @return Pointer to the start of the marked text or NULL if no text is marked. + */ +/* virtual */ const char *Window::GetMarkedText(size_t *length) const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetMarkedText(length); + } + + return NULL; +} + +/** + * Get the current caret position if an edit box has the focus. + * @return Top-left location of the caret, relative to the window. + */ +/* virtual */ Point Window::GetCaretPosition() const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetCaretPosition(this, this->nested_focus->index); + } + + Point pt = {0, 0}; + return pt; +} + +/** + * Get the bounding rectangle for a text range if an edit box has the focus. + * @param from Start of the string range. + * @param to End of the string range. + * @return Rectangle encompassing the string range, relative to the window. + */ +/* virtual */ Rect Window::GetTextBoundingRect(const char *from, const char *to) const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetBoundingRect(this, this->nested_focus->index, from, to); + } + + Rect r = {0, 0, 0, 0}; + return r; +} + +/** + * Get the character that is rendered at a position by the focused edit box. + * @param pt The position to test. + * @return Pointer to the character at the position or NULL if no character is at the position. + */ +/* virtual */ const char *Window::GetTextCharacterAtPosition(const Point &pt) const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetCharAtPosition(this, this->nested_focus->index, pt); + } + + return NULL; +} + +/** + * Set the window that has the focus + * @param w The window to set the focus on + */ +void SetFocusedWindow(Window *w) +{ + if (_focused_window == w) return; + + /* Invalidate focused widget */ + if (_focused_window != NULL) { + if (_focused_window->nested_focus != NULL) _focused_window->nested_focus->SetDirty(_focused_window); + } + + /* Remember which window was previously focused */ + Window *old_focused = _focused_window; + _focused_window = w; + + /* So we can inform it that it lost focus */ + if (old_focused != NULL) old_focused->OnFocusLost(); + if (_focused_window != NULL) _focused_window->OnFocus(); +} + +/** + * Check if an edit box is in global focus. That is if focused window + * has a edit box as focused widget, or if a console is focused. + * @return returns true if an edit box is in global focus or if the focused window is a console, else false + */ +bool EditBoxInGlobalFocus() +{ + if (_focused_window == NULL) return false; + + /* The console does not have an edit box so a special case is needed. */ + if (_focused_window->window_class == WC_CONSOLE) return true; + + return _focused_window->nested_focus != NULL && _focused_window->nested_focus->type == WWT_EDITBOX; +} + +/** + * Makes no widget on this window have focus. The function however doesn't change which window has focus. + */ +void Window::UnfocusFocusedWidget() +{ + if (this->nested_focus != NULL) { + if (this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus(); + + /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ + this->nested_focus->SetDirty(this); + this->nested_focus = NULL; + } +} + +/** + * Set focus within this window to the given widget. The function however doesn't change which window has focus. + * @param widget_index Index of the widget in the window to set the focus to. + * @return Focus has changed. + */ +bool Window::SetFocusedWidget(int widget_index) +{ + /* Do nothing if widget_index is already focused, or if it wasn't a valid widget. */ + if ((uint)widget_index >= this->nested_array_size) return false; + + assert(this->nested_array[widget_index] != NULL); // Setting focus to a non-existing widget is a bad idea. + if (this->nested_focus != NULL) { + if (this->GetWidget(widget_index) == this->nested_focus) return false; + + /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ + this->nested_focus->SetDirty(this); + if (this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus(); + } + this->nested_focus = this->GetWidget(widget_index); + return true; +} + +/** + * Called when window looses focus + */ +void Window::OnFocusLost() +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus(); +} + +/** + * Sets the enabled/disabled status of a list of widgets. + * By default, widgets are enabled. + * On certain conditions, they have to be disabled. + * @param disab_stat status to use ie: disabled = true, enabled = false + * @param widgets list of widgets ended by WIDGET_LIST_END + */ +void CDECL Window::SetWidgetsDisabledState(bool disab_stat, int widgets, ...) +{ + va_list wdg_list; + + va_start(wdg_list, widgets); + + while (widgets != WIDGET_LIST_END) { + SetWidgetDisabledState(widgets, disab_stat); + widgets = va_arg(wdg_list, int); + } + + va_end(wdg_list); +} + +/** + * Sets the lowered/raised status of a list of widgets. + * @param lowered_stat status to use ie: lowered = true, raised = false + * @param widgets list of widgets ended by WIDGET_LIST_END + */ +void CDECL Window::SetWidgetsLoweredState(bool lowered_stat, int widgets, ...) +{ + va_list wdg_list; + + va_start(wdg_list, widgets); + + while (widgets != WIDGET_LIST_END) { + SetWidgetLoweredState(widgets, lowered_stat); + widgets = va_arg(wdg_list, int); + } + + va_end(wdg_list); +} + +/** + * Raise the buttons of the window. + * @param autoraise Raise only the push buttons of the window. + */ +void Window::RaiseButtons(bool autoraise) +{ + for (uint i = 0; i < this->nested_array_size; i++) { + if (this->nested_array[i] == NULL) continue; + WidgetType type = this->nested_array[i]->type; + if (((type & ~WWB_PUSHBUTTON) < WWT_LAST || type == NWID_PUSHBUTTON_DROPDOWN) && + (!autoraise || (type & WWB_PUSHBUTTON) || type == WWT_EDITBOX) && this->IsWidgetLowered(i)) { + this->RaiseWidget(i); + this->SetWidgetDirty(i); + } + } + + /* Special widgets without widget index */ + NWidgetCore *wid = this->nested_root != NULL ? (NWidgetCore*)this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX) : NULL; + if (wid != NULL) { + wid->SetLowered(false); + wid->SetDirty(this); + } +} + +/** + * Invalidate a widget, i.e. mark it as being changed and in need of redraw. + * @param widget_index the widget to redraw. + */ +void Window::SetWidgetDirty(byte widget_index) const +{ + /* Sometimes this function is called before the window is even fully initialized */ + if (this->nested_array == NULL) return; + + this->nested_array[widget_index]->SetDirty(this); +} + +/** + * A hotkey has been pressed. + * @param hotkey Hotkey index, by default a widget index of a button or editbox. + * @return #ES_HANDLED if the key press has been handled, and the hotkey is not unavailable for some reason. + */ +EventState Window::OnHotkey(int hotkey) +{ + if (hotkey < 0) return ES_NOT_HANDLED; + + NWidgetCore *nw = this->GetWidget(hotkey); + if (nw == NULL || nw->IsDisabled()) return ES_NOT_HANDLED; + + if (nw->type == WWT_EDITBOX) { + if (this->IsShaded()) return ES_NOT_HANDLED; + + /* Focus editbox */ + this->SetFocusedWidget(hotkey); + SetFocusedWindow(this); + } else { + /* Click button */ + this->OnClick(Point(), hotkey, 1); + } + return ES_HANDLED; +} + +/** + * Do all things to make a button look clicked and mark it to be + * unclicked in a few ticks. + * @param widget the widget to "click" + */ +void Window::HandleButtonClick(byte widget) +{ + this->LowerWidget(widget); + this->SetTimeout(); + this->SetWidgetDirty(widget); +} + +static void StartWindowDrag(Window *w); +static void StartWindowSizing(Window *w, bool to_left); + +/** + * Dispatch left mouse-button (possibly double) click in window. + * @param w Window to dispatch event in + * @param x X coordinate of the click + * @param y Y coordinate of the click + * @param click_count Number of fast consecutive clicks at same position + */ +static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count) +{ + NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y); + WidgetType widget_type = (nw != NULL) ? nw->type : WWT_EMPTY; + + bool focused_widget_changed = false; + /* If clicked on a window that previously did dot have focus */ + if (_focused_window != w && // We already have focus, right? + (w->window_desc->flags & WDF_NO_FOCUS) == 0 && // Don't lose focus to toolbars + widget_type != WWT_CLOSEBOX) { // Don't change focused window if 'X' (close button) was clicked + focused_widget_changed = true; + SetFocusedWindow(w); + } + + if (nw == NULL) return; // exit if clicked outside of widgets + + /* don't allow any interaction if the button has been disabled */ + if (nw->IsDisabled()) return; + + int widget_index = nw->index; ///< Index of the widget + + /* Clicked on a widget that is not disabled. + * So unless the clicked widget is the caption bar, change focus to this widget. + * Exception: In the OSK we always want the editbox to stay focussed. */ + if (widget_type != WWT_CAPTION && w->window_class != WC_OSK) { + /* focused_widget_changed is 'now' only true if the window this widget + * is in gained focus. In that case it must remain true, also if the + * local widget focus did not change. As such it's the logical-or of + * both changed states. + * + * If this is not preserved, then the OSK window would be opened when + * a user has the edit box focused and then click on another window and + * then back again on the edit box (to type some text). + */ + focused_widget_changed |= w->SetFocusedWidget(widget_index); + } + + /* Close any child drop down menus. If the button pressed was the drop down + * list's own button, then we should not process the click any further. */ + if (HideDropDownMenu(w) == widget_index && widget_index >= 0) return; + + if ((widget_type & ~WWB_PUSHBUTTON) < WWT_LAST && (widget_type & WWB_PUSHBUTTON)) w->HandleButtonClick(widget_index); + + Point pt = { x, y }; + + switch (widget_type) { + case NWID_VSCROLLBAR: + case NWID_HSCROLLBAR: + ScrollbarClickHandler(w, nw, x, y); + break; + + case WWT_EDITBOX: { + QueryString *query = w->GetQueryString(widget_index); + if (query != NULL) query->ClickEditBox(w, pt, widget_index, click_count, focused_widget_changed); + break; + } + + case WWT_CLOSEBOX: // 'X' + delete w; + return; + + case WWT_CAPTION: // 'Title bar' + StartWindowDrag(w); + return; + + case WWT_RESIZEBOX: + /* When the resize widget is on the left size of the window + * we assume that that button is used to resize to the left. */ + StartWindowSizing(w, (int)nw->pos_x < (w->width / 2)); + nw->SetDirty(w); + return; + + case WWT_DEFSIZEBOX: { + if (_ctrl_pressed) { + w->window_desc->pref_width = w->width; + w->window_desc->pref_height = w->height; + } else { + int16 def_width = max(min(w->window_desc->GetDefaultWidth(), _screen.width), w->nested_root->smallest_x); + int16 def_height = max(min(w->window_desc->GetDefaultHeight(), _screen.height - 50), w->nested_root->smallest_y); + + int dx = (w->resize.step_width == 0) ? 0 : def_width - w->width; + int dy = (w->resize.step_height == 0) ? 0 : def_height - w->height; + /* dx and dy has to go by step.. calculate it. + * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */ + if (w->resize.step_width > 1) dx -= dx % (int)w->resize.step_width; + if (w->resize.step_height > 1) dy -= dy % (int)w->resize.step_height; + ResizeWindow(w, dx, dy, false); + } + + nw->SetLowered(true); + nw->SetDirty(w); + w->SetTimeout(); + break; + } + + case WWT_DEBUGBOX: + w->ShowNewGRFInspectWindow(); + break; + + case WWT_SHADEBOX: + nw->SetDirty(w); + w->SetShaded(!w->IsShaded()); + return; + + case WWT_STICKYBOX: + w->flags ^= WF_STICKY; + nw->SetDirty(w); + if (_ctrl_pressed) w->window_desc->pref_sticky = (w->flags & WF_STICKY) != 0; + return; + + default: + break; + } + + /* Widget has no index, so the window is not interested in it. */ + if (widget_index < 0) return; + + /* Check if the widget is highlighted; if so, disable highlight and dispatch an event to the GameScript */ + if (w->IsWidgetHighlighted(widget_index)) { + w->SetWidgetHighlight(widget_index, TC_INVALID); + Game::NewEvent(new ScriptEventWindowWidgetClick((ScriptWindow::WindowClass)w->window_class, w->window_number, widget_index)); + } + + w->OnClick(pt, widget_index, click_count); +} + +/** + * Dispatch right mouse-button click in window. + * @param w Window to dispatch event in + * @param x X coordinate of the click + * @param y Y coordinate of the click + */ +static void DispatchRightClickEvent(Window *w, int x, int y) +{ + NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y); + if (wid == NULL) return; + + /* No widget to handle, or the window is not interested in it. */ + if (wid->index >= 0) { + Point pt = { x, y }; + if (w->OnRightClick(pt, wid->index)) return; + } + + if (_settings_client.gui.hover_delay == 0 && wid->tool_tip != 0) GuiShowTooltips(w, wid->tool_tip, 0, NULL, TCC_RIGHT_CLICK); +} + +/** + * Dispatch hover of the mouse over a window. + * @param w Window to dispatch event in. + * @param x X coordinate of the click. + * @param y Y coordinate of the click. + */ +static void DispatchHoverEvent(Window *w, int x, int y) +{ + NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y); + + /* No widget to handle */ + if (wid == NULL) return; + + /* Show the tooltip if there is any */ + if (wid->tool_tip != 0) { + GuiShowTooltips(w, wid->tool_tip); + return; + } + + /* Widget has no index, so the window is not interested in it. */ + if (wid->index < 0) return; + + Point pt = { x, y }; + w->OnHover(pt, wid->index); +} + +/** + * Dispatch the mousewheel-action to the window. + * The window will scroll any compatible scrollbars if the mouse is pointed over the bar or its contents + * @param w Window + * @param nwid the widget where the scrollwheel was used + * @param wheel scroll up or down + */ +static void DispatchMouseWheelEvent(Window *w, NWidgetCore *nwid, int wheel) +{ + if (nwid == NULL) return; + + /* Using wheel on caption/shade-box shades or unshades the window. */ + if (nwid->type == WWT_CAPTION || nwid->type == WWT_SHADEBOX) { + w->SetShaded(wheel < 0); + return; + } + + /* Wheeling a vertical scrollbar. */ + if (nwid->type == NWID_VSCROLLBAR) { + NWidgetScrollbar *sb = static_cast(nwid); + if (sb->GetCount() > sb->GetCapacity()) { + sb->UpdatePosition(wheel); + w->SetDirty(); + } + return; + } + + /* Scroll the widget attached to the scrollbar. */ + Scrollbar *sb = (nwid->scrollbar_index >= 0 ? w->GetScrollbar(nwid->scrollbar_index) : NULL); + if (sb != NULL && sb->GetCount() > sb->GetCapacity()) { + sb->UpdatePosition(wheel); + w->SetDirty(); + } +} + +/** + * Returns whether a window may be shown or not. + * @param w The window to consider. + * @return True iff it may be shown, otherwise false. + */ +static bool MayBeShown(const Window *w) +{ + /* If we're not modal, everything is okay. */ + if (!HasModalProgress()) return true; + + switch (w->window_class) { + case WC_MAIN_WINDOW: ///< The background, i.e. the game. + case WC_MODAL_PROGRESS: ///< The actual progress window. + case WC_CONFIRM_POPUP_QUERY: ///< The abort window. + return true; + + default: + return false; + } +} + +/** + * Generate repaint events for the visible part of window w within the rectangle. + * + * The function goes recursively upwards in the window stack, and splits the rectangle + * into multiple pieces at the window edges, so obscured parts are not redrawn. + * + * @param w Window that needs to be repainted + * @param left Left edge of the rectangle that should be repainted + * @param top Top edge of the rectangle that should be repainted + * @param right Right edge of the rectangle that should be repainted + * @param bottom Bottom edge of the rectangle that should be repainted + */ +static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom) +{ + const Window *v; + FOR_ALL_WINDOWS_FROM_BACK_FROM(v, w->z_front) { + if (MayBeShown(v) && + right > v->left && + bottom > v->top && + left < v->left + v->width && + top < v->top + v->height) { + /* v and rectangle intersect with each other */ + int x; + + if (left < (x = v->left)) { + DrawOverlappedWindow(w, left, top, x, bottom); + DrawOverlappedWindow(w, x, top, right, bottom); + return; + } + + if (right > (x = v->left + v->width)) { + DrawOverlappedWindow(w, left, top, x, bottom); + DrawOverlappedWindow(w, x, top, right, bottom); + return; + } + + if (top < (x = v->top)) { + DrawOverlappedWindow(w, left, top, right, x); + DrawOverlappedWindow(w, left, x, right, bottom); + return; + } + + if (bottom > (x = v->top + v->height)) { + DrawOverlappedWindow(w, left, top, right, x); + DrawOverlappedWindow(w, left, x, right, bottom); + return; + } + + return; + } + } + + /* Setup blitter, and dispatch a repaint event to window *wz */ + DrawPixelInfo *dp = _cur_dpi; + dp->width = right - left; + dp->height = bottom - top; + dp->left = left - w->left; + dp->top = top - w->top; + dp->pitch = _screen.pitch; + dp->dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(_screen.dst_ptr, left, top); + dp->zoom = ZOOM_LVL_NORMAL; + w->OnPaint(); +} + +/** + * From a rectangle that needs redrawing, find the windows that intersect with the rectangle. + * These windows should be re-painted. + * @param left Left edge of the rectangle that should be repainted + * @param top Top edge of the rectangle that should be repainted + * @param right Right edge of the rectangle that should be repainted + * @param bottom Bottom edge of the rectangle that should be repainted + */ +void DrawOverlappedWindowForAll(int left, int top, int right, int bottom) +{ + Window *w; + DrawPixelInfo bk; + _cur_dpi = &bk; + + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (MayBeShown(w) && + right > w->left && + bottom > w->top && + left < w->left + w->width && + top < w->top + w->height) { + /* Window w intersects with the rectangle => needs repaint */ + DrawOverlappedWindow(w, left, top, right, bottom); + } + } +} + +/** + * Mark entire window as dirty (in need of re-paint) + * @ingroup dirty + */ +void Window::SetDirty() const +{ + SetDirtyBlocks(this->left, this->top, this->left + this->width, this->top + this->height); +} + +/** + * Re-initialize a window, and optionally change its size. + * @param rx Horizontal resize of the window. + * @param ry Vertical resize of the window. + * @note For just resizing the window, use #ResizeWindow instead. + */ +void Window::ReInit(int rx, int ry) +{ + this->SetDirty(); // Mark whole current window as dirty. + + /* Save current size. */ + int window_width = this->width; + int window_height = this->height; + + this->OnInit(); + /* Re-initialize the window from the ground up. No need to change the nested_array, as all widgets stay where they are. */ + this->nested_root->SetupSmallestSize(this, false); + this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL); + this->width = this->nested_root->smallest_x; + this->height = this->nested_root->smallest_y; + this->resize.step_width = this->nested_root->resize_x; + this->resize.step_height = this->nested_root->resize_y; + + /* Resize as close to the original size + requested resize as possible. */ + window_width = max(window_width + rx, this->width); + window_height = max(window_height + ry, this->height); + int dx = (this->resize.step_width == 0) ? 0 : window_width - this->width; + int dy = (this->resize.step_height == 0) ? 0 : window_height - this->height; + /* dx and dy has to go by step.. calculate it. + * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */ + if (this->resize.step_width > 1) dx -= dx % (int)this->resize.step_width; + if (this->resize.step_height > 1) dy -= dy % (int)this->resize.step_height; + + ResizeWindow(this, dx, dy); + /* ResizeWindow() does this->SetDirty() already, no need to do it again here. */ +} + +/** + * Set the shaded state of the window to \a make_shaded. + * @param make_shaded If \c true, shade the window (roll up until just the title bar is visible), else unshade/unroll the window to its original size. + * @note The method uses #Window::ReInit(), thus after the call, the whole window should be considered changed. + */ +void Window::SetShaded(bool make_shaded) +{ + if (this->shade_select == NULL) return; + + int desired = make_shaded ? SZSP_HORIZONTAL : 0; + if (this->shade_select->shown_plane != desired) { + if (make_shaded) { + if (this->nested_focus != NULL) this->UnfocusFocusedWidget(); + this->unshaded_size.width = this->width; + this->unshaded_size.height = this->height; + this->shade_select->SetDisplayedPlane(desired); + this->ReInit(0, -this->height); + } else { + this->shade_select->SetDisplayedPlane(desired); + int dx = ((int)this->unshaded_size.width > this->width) ? (int)this->unshaded_size.width - this->width : 0; + int dy = ((int)this->unshaded_size.height > this->height) ? (int)this->unshaded_size.height - this->height : 0; + this->ReInit(dx, dy); + } + } +} + +/** + * Find the Window whose parent pointer points to this window + * @param w parent Window to find child of + * @param wc Window class of the window to remove; #WC_INVALID if class does not matter + * @return a Window pointer that is the child of \a w, or \c NULL otherwise + */ +static Window *FindChildWindow(const Window *w, WindowClass wc) +{ + Window *v; + FOR_ALL_WINDOWS_FROM_BACK(v) { + if ((wc == WC_INVALID || wc == v->window_class) && v->parent == w) return v; + } + + return NULL; +} + +/** + * Delete all children a window might have in a head-recursive manner + * @param wc Window class of the window to remove; #WC_INVALID if class does not matter + */ +void Window::DeleteChildWindows(WindowClass wc) const +{ + Window *child = FindChildWindow(this, wc); + while (child != NULL) { + delete child; + child = FindChildWindow(this, wc); + } +} + +/** + * Remove window and all its child windows from the window stack. + */ +Window::~Window() +{ + if (_thd.window_class == this->window_class && + _thd.window_number == this->window_number) { + ResetObjectToPlace(); + } + + /* Prevent Mouseover() from resetting mouse-over coordinates on a non-existing window */ + if (_mouseover_last_w == this) _mouseover_last_w = NULL; + + /* We can't scroll the window when it's closed. */ + if (_last_scroll_window == this) _last_scroll_window = NULL; + + /* Make sure we don't try to access this window as the focused window when it doesn't exist anymore. */ + if (_focused_window == this) { + this->OnFocusLost(); + _focused_window = NULL; + } + + this->DeleteChildWindows(); + + if (this->viewport != NULL) DeleteWindowViewport(this); + + this->SetDirty(); + + free(this->nested_array); // Contents is released through deletion of #nested_root. + delete this->nested_root; + + this->window_class = WC_INVALID; +} + +/** + * Find a window by its class and window number + * @param cls Window class + * @param number Number of the window within the window class + * @return Pointer to the found window, or \c NULL if not available + */ +Window *FindWindowById(WindowClass cls, WindowNumber number) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls && w->window_number == number) return w; + } + + return NULL; +} + +/** + * Find any window by its class. Useful when searching for a window that uses + * the window number as a #WindowType, like #WC_SEND_NETWORK_MSG. + * @param cls Window class + * @return Pointer to the found window, or \c NULL if not available + */ +Window *FindWindowByClass(WindowClass cls) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls) return w; + } + + return NULL; +} + +/** + * Delete a window by its class and window number (if it is open). + * @param cls Window class + * @param number Number of the window within the window class + * @param force force deletion; if false don't delete when stickied + */ +void DeleteWindowById(WindowClass cls, WindowNumber number, bool force) +{ + Window *w = FindWindowById(cls, number); + if (force || w == NULL || + (w->flags & WF_STICKY) == 0) { + delete w; + } +} + +/** + * Delete all windows of a given class + * @param cls Window class of windows to delete + */ +void DeleteWindowByClass(WindowClass cls) +{ + Window *w; + +restart_search: + /* When we find the window to delete, we need to restart the search + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls) { + delete w; + goto restart_search; + } + } +} + +/** + * Delete all windows of a company. We identify windows of a company + * by looking at the caption colour. If it is equal to the company ID + * then we say the window belongs to the company and should be deleted + * @param id company identifier + */ +void DeleteCompanyWindows(CompanyID id) +{ + Window *w; + +restart_search: + /* When we find the window to delete, we need to restart the search + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->owner == id) { + delete w; + goto restart_search; + } + } + + /* Also delete the company specific windows that don't have a company-colour. */ + DeleteWindowById(WC_BUY_COMPANY, id); +} + +/** + * Change the owner of all the windows one company can take over from another + * company in the case of a company merger. Do not change ownership of windows + * that need to be deleted once takeover is complete + * @param old_owner original owner of the window + * @param new_owner the new owner of the window + */ +void ChangeWindowOwner(Owner old_owner, Owner new_owner) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->owner != old_owner) continue; + + switch (w->window_class) { + case WC_COMPANY_COLOUR: + case WC_FINANCES: + case WC_STATION_LIST: + case WC_TRAINS_LIST: + case WC_ROADVEH_LIST: + case WC_SHIPS_LIST: + case WC_AIRCRAFT_LIST: + case WC_BUY_COMPANY: + case WC_COMPANY: + case WC_COMPANY_INFRASTRUCTURE: + continue; + + default: + w->owner = new_owner; + break; + } + } +} + +static void BringWindowToFront(Window *w); + +/** + * Find a window and make it the relative top-window on the screen. + * The window gets unshaded if it was shaded, and a white border is drawn at its edges for a brief period of time to visualize its "activation". + * @param cls WindowClass of the window to activate + * @param number WindowNumber of the window to activate + * @return a pointer to the window thus activated + */ +Window *BringWindowToFrontById(WindowClass cls, WindowNumber number) +{ + Window *w = FindWindowById(cls, number); + + if (w != NULL) { + if (w->IsShaded()) w->SetShaded(false); // Restore original window size if it was shaded. + + w->SetWhiteBorder(); + BringWindowToFront(w); + w->SetDirty(); + } + + return w; +} + +static inline bool IsVitalWindow(const Window *w) +{ + switch (w->window_class) { + case WC_MAIN_TOOLBAR: + case WC_STATUS_BAR: + case WC_NEWS_WINDOW: + case WC_SEND_NETWORK_MSG: + return true; + + default: + return false; + } +} + +/** + * Get the z-priority for a given window. This is used in comparison with other z-priority values; + * a window with a given z-priority will appear above other windows with a lower value, and below + * those with a higher one (the ordering within z-priorities is arbitrary). + * @param w The window to get the z-priority for + * @pre w->window_class != WC_INVALID + * @return The window's z-priority + */ +static uint GetWindowZPriority(const Window *w) +{ + assert(w->window_class != WC_INVALID); + + uint z_priority = 0; + + switch (w->window_class) { + case WC_ENDSCREEN: + ++z_priority; + + case WC_HIGHSCORE: + ++z_priority; + + case WC_TOOLTIPS: + ++z_priority; + + case WC_DROPDOWN_MENU: + ++z_priority; + + case WC_MAIN_TOOLBAR: + case WC_STATUS_BAR: + ++z_priority; + + case WC_OSK: + ++z_priority; + + case WC_QUERY_STRING: + case WC_SEND_NETWORK_MSG: + ++z_priority; + + case WC_ERRMSG: + case WC_CONFIRM_POPUP_QUERY: + case WC_MODAL_PROGRESS: + case WC_NETWORK_STATUS_WINDOW: + ++z_priority; + + case WC_GENERATE_LANDSCAPE: + case WC_SAVELOAD: + case WC_GAME_OPTIONS: + case WC_CUSTOM_CURRENCY: + case WC_NETWORK_WINDOW: + case WC_GRF_PARAMETERS: + case WC_AI_LIST: + case WC_AI_SETTINGS: + case WC_TEXTFILE: + ++z_priority; + + case WC_CONSOLE: + ++z_priority; + + case WC_NEWS_WINDOW: + ++z_priority; + + default: + ++z_priority; + + case WC_MAIN_WINDOW: + return z_priority; + } +} + +/** + * Adds a window to the z-ordering, according to its z-priority. + * @param w Window to add + */ +static void AddWindowToZOrdering(Window *w) +{ + assert(w->z_front == NULL && w->z_back == NULL); + + if (_z_front_window == NULL) { + /* It's the only window. */ + _z_front_window = _z_back_window = w; + w->z_front = w->z_back = NULL; + } else { + /* Search down the z-ordering for its location. */ + Window *v = _z_front_window; + uint last_z_priority = UINT_MAX; + while (v != NULL && (v->window_class == WC_INVALID || GetWindowZPriority(v) > GetWindowZPriority(w))) { + if (v->window_class != WC_INVALID) { + /* Sanity check z-ordering, while we're at it. */ + assert(last_z_priority >= GetWindowZPriority(v)); + last_z_priority = GetWindowZPriority(v); + } + + v = v->z_back; + } + + if (v == NULL) { + /* It's the new back window. */ + w->z_front = _z_back_window; + w->z_back = NULL; + _z_back_window->z_back = w; + _z_back_window = w; + } else if (v == _z_front_window) { + /* It's the new front window. */ + w->z_front = NULL; + w->z_back = _z_front_window; + _z_front_window->z_front = w; + _z_front_window = w; + } else { + /* It's somewhere else in the z-ordering. */ + w->z_front = v->z_front; + w->z_back = v; + v->z_front->z_back = w; + v->z_front = w; + } + } +} + + +/** + * Removes a window from the z-ordering. + * @param w Window to remove + */ +static void RemoveWindowFromZOrdering(Window *w) +{ + if (w->z_front == NULL) { + assert(_z_front_window == w); + _z_front_window = w->z_back; + } else { + w->z_front->z_back = w->z_back; + } + + if (w->z_back == NULL) { + assert(_z_back_window == w); + _z_back_window = w->z_front; + } else { + w->z_back->z_front = w->z_front; + } + + w->z_front = w->z_back = NULL; +} + +/** + * On clicking on a window, make it the frontmost window of all windows with an equal + * or lower z-priority. The window is marked dirty for a repaint + * @param w window that is put into the relative foreground + */ +static void BringWindowToFront(Window *w) +{ + RemoveWindowFromZOrdering(w); + AddWindowToZOrdering(w); + + w->SetDirty(); +} + +/** + * Initializes the data (except the position and initial size) of a new Window. + * @param desc Window description. + * @param window_number Number being assigned to the new window + * @return Window pointer of the newly created window + * @pre If nested widgets are used (\a widget is \c NULL), #nested_root and #nested_array_size must be initialized. + * In addition, #nested_array is either \c NULL, or already initialized. + */ +void Window::InitializeData(WindowNumber window_number) +{ + /* Set up window properties; some of them are needed to set up smallest size below */ + this->window_class = this->window_desc->cls; + this->SetWhiteBorder(); + if (this->window_desc->default_pos == WDP_CENTER) this->flags |= WF_CENTERED; + this->owner = INVALID_OWNER; + this->nested_focus = NULL; + this->window_number = window_number; + + this->OnInit(); + /* Initialize nested widget tree. */ + if (this->nested_array == NULL) { + this->nested_array = CallocT(this->nested_array_size); + this->nested_root->SetupSmallestSize(this, true); + } else { + this->nested_root->SetupSmallestSize(this, false); + } + /* Initialize to smallest size. */ + this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL); + + /* Further set up window properties, + * this->left, this->top, this->width, this->height, this->resize.width, and this->resize.height are initialized later. */ + this->resize.step_width = this->nested_root->resize_x; + this->resize.step_height = this->nested_root->resize_y; + + /* Give focus to the opened window unless a text box + * of focused window has focus (so we don't interrupt typing). But if the new + * window has a text box, then take focus anyway. */ + if (!EditBoxInGlobalFocus() || this->nested_root->GetWidgetOfType(WWT_EDITBOX) != NULL) SetFocusedWindow(this); + + /* Insert the window into the correct location in the z-ordering. */ + AddWindowToZOrdering(this); +} + +/** + * Set the position and smallest size of the window. + * @param x Offset in pixels from the left of the screen of the new window. + * @param y Offset in pixels from the top of the screen of the new window. + * @param sm_width Smallest width in pixels of the window. + * @param sm_height Smallest height in pixels of the window. + */ +void Window::InitializePositionSize(int x, int y, int sm_width, int sm_height) +{ + this->left = x; + this->top = y; + this->width = sm_width; + this->height = sm_height; +} + +/** + * Resize window towards the default size. + * Prior to construction, a position for the new window (for its default size) + * has been found with LocalGetWindowPlacement(). Initially, the window is + * constructed with minimal size. Resizing the window to its default size is + * done here. + * @param def_width default width in pixels of the window + * @param def_height default height in pixels of the window + * @see Window::Window(), Window::InitializeData(), Window::InitializePositionSize() + */ +void Window::FindWindowPlacementAndResize(int def_width, int def_height) +{ + def_width = max(def_width, this->width); // Don't allow default size to be smaller than smallest size + def_height = max(def_height, this->height); + /* Try to make windows smaller when our window is too small. + * w->(width|height) is normally the same as min_(width|height), + * but this way the GUIs can be made a little more dynamic; + * one can use the same spec for multiple windows and those + * can then determine the real minimum size of the window. */ + if (this->width != def_width || this->height != def_height) { + /* Think about the overlapping toolbars when determining the minimum window size */ + int free_height = _screen.height; + const Window *wt = FindWindowById(WC_STATUS_BAR, 0); + if (wt != NULL) free_height -= wt->height; + wt = FindWindowById(WC_MAIN_TOOLBAR, 0); + if (wt != NULL) free_height -= wt->height; + + int enlarge_x = max(min(def_width - this->width, _screen.width - this->width), 0); + int enlarge_y = max(min(def_height - this->height, free_height - this->height), 0); + + /* X and Y has to go by step.. calculate it. + * The cast to int is necessary else x/y are implicitly casted to + * unsigned int, which won't work. */ + if (this->resize.step_width > 1) enlarge_x -= enlarge_x % (int)this->resize.step_width; + if (this->resize.step_height > 1) enlarge_y -= enlarge_y % (int)this->resize.step_height; + + ResizeWindow(this, enlarge_x, enlarge_y); + /* ResizeWindow() calls this->OnResize(). */ + } else { + /* Always call OnResize; that way the scrollbars and matrices get initialized. */ + this->OnResize(); + } + + int nx = this->left; + int ny = this->top; + + if (nx + this->width > _screen.width) nx -= (nx + this->width - _screen.width); + + const Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0); + ny = max(ny, (wt == NULL || this == wt || this->top == 0) ? 0 : wt->height); + nx = max(nx, 0); + + if (this->viewport != NULL) { + this->viewport->left += nx - this->left; + this->viewport->top += ny - this->top; + } + this->left = nx; + this->top = ny; + + this->SetDirty(); +} + +/** + * Decide whether a given rectangle is a good place to open a completely visible new window. + * The new window should be within screen borders, and not overlap with another already + * existing window (except for the main window in the background). + * @param left Left edge of the rectangle + * @param top Top edge of the rectangle + * @param width Width of the rectangle + * @param height Height of the rectangle + * @param pos If rectangle is good, use this parameter to return the top-left corner of the new window + * @return Boolean indication that the rectangle is a good place for the new window + */ +static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &pos) +{ + int right = width + left; + int bottom = height + top; + + const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); + if (left < 0 || (main_toolbar != NULL && top < main_toolbar->height) || right > _screen.width || bottom > _screen.height) return false; + + /* Make sure it is not obscured by any window. */ + const Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == WC_MAIN_WINDOW) continue; + + if (right > w->left && + w->left + w->width > left && + bottom > w->top && + w->top + w->height > top) { + return false; + } + } + + pos.x = left; + pos.y = top; + return true; +} + +/** + * Decide whether a given rectangle is a good place to open a mostly visible new window. + * The new window should be mostly within screen borders, and not overlap with another already + * existing window (except for the main window in the background). + * @param left Left edge of the rectangle + * @param top Top edge of the rectangle + * @param width Width of the rectangle + * @param height Height of the rectangle + * @param pos If rectangle is good, use this parameter to return the top-left corner of the new window + * @return Boolean indication that the rectangle is a good place for the new window + */ +static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &pos) +{ + /* Left part of the rectangle may be at most 1/4 off-screen, + * right part of the rectangle may be at most 1/2 off-screen + */ + if (left < -(width >> 2) || left > _screen.width - (width >> 1)) return false; + /* Bottom part of the rectangle may be at most 1/4 off-screen */ + if (top < 22 || top > _screen.height - (height >> 2)) return false; + + /* Make sure it is not obscured by any window. */ + const Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == WC_MAIN_WINDOW) continue; + + if (left + width > w->left && + w->left + w->width > left && + top + height > w->top && + w->top + w->height > top) { + return false; + } + } + + pos.x = left; + pos.y = top; + return true; +} + +/** + * Find a good place for opening a new window of a given width and height. + * @param width Width of the new window + * @param height Height of the new window + * @return Top-left coordinate of the new window + */ +static Point GetAutoPlacePosition(int width, int height) +{ + Point pt; + + /* First attempt, try top-left of the screen */ + const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); + if (IsGoodAutoPlace1(0, main_toolbar != NULL ? main_toolbar->height + 2 : 2, width, height, pt)) return pt; + + /* Second attempt, try around all existing windows with a distance of 2 pixels. + * The new window must be entirely on-screen, and not overlap with an existing window. + * Eight starting points are tried, two at each corner. + */ + const Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == WC_MAIN_WINDOW) continue; + + if (IsGoodAutoPlace1(w->left + w->width + 2, w->top, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left - width - 2, w->top, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left, w->top + w->height + 2, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left, w->top - height - 2, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left + w->width + 2, w->top + w->height - height, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left - width - 2, w->top + w->height - height, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left + w->width - width, w->top + w->height + 2, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left + w->width - width, w->top - height - 2, width, height, pt)) return pt; + } + + /* Third attempt, try around all existing windows with a distance of 2 pixels. + * The new window may be partly off-screen, and must not overlap with an existing window. + * Only four starting points are tried. + */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == WC_MAIN_WINDOW) continue; + + if (IsGoodAutoPlace2(w->left + w->width + 2, w->top, width, height, pt)) return pt; + if (IsGoodAutoPlace2(w->left - width - 2, w->top, width, height, pt)) return pt; + if (IsGoodAutoPlace2(w->left, w->top + w->height + 2, width, height, pt)) return pt; + if (IsGoodAutoPlace2(w->left, w->top - height - 2, width, height, pt)) return pt; + } + + /* Fourth and final attempt, put window at diagonal starting from (0, 24), try multiples + * of (+5, +5) + */ + int left = 0, top = 24; + +restart: + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->left == left && w->top == top) { + left += 5; + top += 5; + goto restart; + } + } + + pt.x = left; + pt.y = top; + return pt; +} + +/** + * Computer the position of the top-left corner of a window to be opened right + * under the toolbar. + * @param window_width the width of the window to get the position for + * @return Coordinate of the top-left corner of the new window. + */ +Point GetToolbarAlignedWindowPosition(int window_width) +{ + const Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); + assert(w != NULL); + Point pt = { _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width, w->top + w->height }; + return pt; +} + +/** + * Compute the position of the top-left corner of a new window that is opened. + * + * By default position a child window at an offset of 10/10 of its parent. + * With the exception of WC_BUILD_TOOLBAR (build railway/roads/ship docks/airports) + * and WC_SCEN_LAND_GEN (landscaping). Whose child window has an offset of 0/toolbar-height of + * its parent. So it's exactly under the parent toolbar and no buttons will be covered. + * However if it falls too extremely outside window positions, reposition + * it to an automatic place. + * + * @param *desc The pointer to the WindowDesc to be created. + * @param sm_width Smallest width of the window. + * @param sm_height Smallest height of the window. + * @param window_number The window number of the new window. + * + * @return Coordinate of the top-left corner of the new window. + */ +static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number) +{ + Point pt; + const Window *w; + + int16 default_width = max(desc->GetDefaultWidth(), sm_width); + int16 default_height = max(desc->GetDefaultHeight(), sm_height); + + if (desc->parent_cls != 0 /* WC_MAIN_WINDOW */ && + (w = FindWindowById(desc->parent_cls, window_number)) != NULL && + w->left < _screen.width - 20 && w->left > -60 && w->top < _screen.height - 20) { + + pt.x = w->left + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? 0 : 10); + if (pt.x > _screen.width + 10 - default_width) { + pt.x = (_screen.width + 10 - default_width) - 20; + } + pt.y = w->top + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? w->height : 10); + return pt; + } + + switch (desc->default_pos) { + case WDP_ALIGN_TOOLBAR: // Align to the toolbar + return GetToolbarAlignedWindowPosition(default_width); + + case WDP_AUTO: // Find a good automatic position for the window + return GetAutoPlacePosition(default_width, default_height); + + case WDP_CENTER: // Centre the window horizontally + pt.x = (_screen.width - default_width) / 2; + pt.y = (_screen.height - default_height) / 2; + break; + + case WDP_MANUAL: + pt.x = 0; + pt.y = 0; + break; + + default: + NOT_REACHED(); + } + + return pt; +} + +/* virtual */ Point Window::OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) +{ + return LocalGetWindowPlacement(this->window_desc, sm_width, sm_height, window_number); +} + +/** + * Perform the first part of the initialization of a nested widget tree. + * Construct a nested widget tree in #nested_root, and optionally fill the #nested_array array to provide quick access to the uninitialized widgets. + * This is mainly useful for setting very basic properties. + * @param fill_nested Fill the #nested_array (enabling is expensive!). + * @note Filling the nested array requires an additional traversal through the nested widget tree, and is best performed by #FinishInitNested rather than here. + */ +void Window::CreateNestedTree(bool fill_nested) +{ + int biggest_index = -1; + this->nested_root = MakeWindowNWidgetTree(this->window_desc->nwid_parts, this->window_desc->nwid_length, &biggest_index, &this->shade_select); + this->nested_array_size = (uint)(biggest_index + 1); + + if (fill_nested) { + this->nested_array = CallocT(this->nested_array_size); + this->nested_root->FillNestedArray(this->nested_array, this->nested_array_size); + } +} + +/** + * Perform the second part of the initialization of a nested widget tree. + * @param window_number Number of the new window. + */ +void Window::FinishInitNested(WindowNumber window_number) +{ + this->InitializeData(window_number); + this->ApplyDefaults(); + Point pt = this->OnInitialPosition(this->nested_root->smallest_x, this->nested_root->smallest_y, window_number); + this->InitializePositionSize(pt.x, pt.y, this->nested_root->smallest_x, this->nested_root->smallest_y); + this->FindWindowPlacementAndResize(this->window_desc->GetDefaultWidth(), this->window_desc->GetDefaultHeight()); +} + +/** + * Perform complete initialization of the #Window with nested widgets, to allow use. + * @param window_number Number of the new window. + */ +void Window::InitNested(WindowNumber window_number) +{ + this->CreateNestedTree(false); + this->FinishInitNested(window_number); +} + +/** + * Empty constructor, initialization has been moved to #InitNested() called from the constructor of the derived class. + * @param desc The description of the window. + */ +Window::Window(WindowDesc *desc) : window_desc(desc), scrolling_scrollbar(-1) +{ +} + +/** + * Do a search for a window at specific coordinates. For this we start + * at the topmost window, obviously and work our way down to the bottom + * @param x position x to query + * @param y position y to query + * @return a pointer to the found window if any, NULL otherwise + */ +Window *FindWindowFromPt(int x, int y) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if (MayBeShown(w) && IsInsideBS(x, w->left, w->width) && IsInsideBS(y, w->top, w->height)) { + return w; + } + } + + return NULL; +} + +int SETTING_BUTTON_WIDTH = 20; +int SETTING_BUTTON_HEIGHT = 10; + +/** + * Set button size of settings. If automatic sizing is also enabled, it also sets + * the sizing of buttons, scrollbars and font size (recommend restart). + * @todo Check if it can be moved to another file, so we do not need to include error, string and fontcache headers. + * @todo Fix magic numbers 16/18/20/30/32 + */ +void CheckWindowMinSizings() +{ + if (_settings_client.gui.manage_min_sizing) { + /* Fill the min sizing values for the current resolution. */ + uint swap_x = 32; // in longest border, let main toolbar to have 30 buttons. + uint swap_y = 16; // if short border, let main toolbar have 16/18/20 buttons..) + if (_cur_resolution.width < _cur_resolution.height) Swap(swap_x, swap_y); + _settings_client.gui.min_button = min(_cur_resolution.width / swap_x, _cur_resolution.height / swap_y); + _settings_client.gui.min_step = _settings_client.gui.min_button * 3 / 4; + } + + SETTING_BUTTON_HEIGHT = max(GetMinSizing(NWST_STEP) - 10, 10); + SETTING_BUTTON_WIDTH = 2 * SETTING_BUTTON_HEIGHT; + + extern uint _tooltip_width; + _tooltip_width = max(194, 10 * _settings_client.gui.min_button); + + if (!_settings_client.gui.manage_min_sizing) return; + + _freetype.large.size = _settings_client.gui.min_button; + _freetype.medium.size = max(_settings_client.gui.min_step * 2 / 3, 10U); + _freetype.mono.size = _freetype.medium.size; + _freetype.small.size = max(_freetype.medium.size * 2 / 3, 8U); + + InitFreeType(true); + CheckForMissingGlyphs(); + + if (_z_front_window == NULL) return; + + DeleteAllNonVitalWindows(); + + switch (_game_mode) { + default: break; + case GM_MENU: + DeleteWindowById(WC_SELECT_GAME, 0); + extern void ShowSelectGameWindow(); + ShowSelectGameWindow(); + break; + + case GM_NORMAL: + case GM_EDITOR: { + Station *st; + FOR_ALL_STATIONS(st) { st->UpdateVirtCoord(); } + Waypoint *wp; + FOR_ALL_WAYPOINTS(wp) { wp->UpdateVirtCoord(); } + + HideVitalWindows(); + ShowVitalWindows(); + break; + } + } + + ShowErrorMessage(STR_ERROR_RESET_WINDOWS, STR_ERROR_AUTOMATIC_SIZING, WL_WARNING); +} + +/** + * (re)initialize the windowing system + */ +void InitWindowSystem() +{ + IConsoleClose(); + + _z_back_window = NULL; + _z_front_window = NULL; + _focused_window = NULL; + _mouseover_last_w = NULL; + _last_scroll_window = NULL; + _scrolling_viewport = false; + _mouse_hovering = false; + + NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets. + NWidgetScrollbar::InvalidateDimensionCache(); + + ShowFirstError(); +} + +/** + * Close down the windowing system + */ +void UnInitWindowSystem() +{ + UnshowCriticalError(); + + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) delete w; + + for (w = _z_front_window; w != NULL; /* nothing */) { + Window *to_del = w; + w = w->z_back; + free(to_del); + } + + _z_front_window = NULL; + _z_back_window = NULL; +} + +/** + * Reset the windowing system, by means of shutting it down followed by re-initialization + */ +void ResetWindowSystem() +{ + UnInitWindowSystem(); + InitWindowSystem(); + _thd.Reset(); +} + +static void DecreaseWindowCounters() +{ + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if (_scroller_click_timeout == 0) { + /* Unclick scrollbar buttons if they are pressed. */ + for (uint i = 0; i < w->nested_array_size; i++) { + NWidgetBase *nwid = w->nested_array[i]; + if (nwid != NULL && (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR)) { + NWidgetScrollbar *sb = static_cast(nwid); + if (sb->disp_flags & (ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN)) { + sb->disp_flags &= ~(ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN); + w->scrolling_scrollbar = -1; + sb->SetDirty(w); + } + } + } + } + + /* Handle editboxes */ + for (SmallMap::Pair *it = w->querystrings.Begin(); it != w->querystrings.End(); ++it) { + it->second->HandleEditBox(w, it->first); + } + + w->OnMouseLoop(); + } + + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if ((w->flags & WF_TIMEOUT) && --w->timeout_timer == 0) { + CLRBITS(w->flags, WF_TIMEOUT); + + w->OnTimeout(); + w->RaiseButtons(true); + } + } +} + +static void HandlePlacePresize() +{ + if (_special_mouse_mode != WSM_PRESIZE) return; + + Window *w = _thd.GetCallbackWnd(); + if (w == NULL) return; + + Point pt = GetTileBelowCursor(); + if (pt.x == -1) { + _thd.selend.x = -1; + return; + } + + w->OnPlacePresize(pt, TileVirtXY(pt.x, pt.y)); +} + +/** + * Handle dragging and dropping in mouse dragging mode (#WSM_DRAGDROP). + * @return State of handling the event. + */ +static EventState HandleMouseDragDrop() +{ + if (_special_mouse_mode != WSM_DRAGDROP) return ES_NOT_HANDLED; + + if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; // Dragging, but the mouse did not move. + + Window *w = _thd.GetCallbackWnd(); + if (w != NULL) { + /* Send an event in client coordinates. */ + Point pt; + pt.x = _cursor.pos.x - w->left; + pt.y = _cursor.pos.y - w->top; + if (_left_button_down) { + w->OnMouseDrag(pt, GetWidgetFromPos(w, pt.x, pt.y)); + } else { + w->OnDragDrop(pt, GetWidgetFromPos(w, pt.x, pt.y)); + } + } + + if (!_left_button_down) ResetObjectToPlace(); // Button released, finished dragging. + return ES_HANDLED; +} + +/** Report position of the mouse to the underlying window. */ +static void HandleMouseOver() +{ + Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); + + /* We changed window, put a MOUSEOVER event to the last window */ + if (_mouseover_last_w != NULL && _mouseover_last_w != w) { + /* Reset mouse-over coordinates of previous window */ + Point pt = { -1, -1 }; + _mouseover_last_w->OnMouseOver(pt, 0); + } + + /* _mouseover_last_w will get reset when the window is deleted, see DeleteWindow() */ + _mouseover_last_w = w; + + if (w != NULL) { + /* send an event in client coordinates. */ + Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top }; + const NWidgetCore *widget = w->nested_root->GetWidgetFromPos(pt.x, pt.y); + if (widget != NULL) w->OnMouseOver(pt, widget->index); + } +} + +/** The minimum number of pixels of the title bar must be visible in both the X or Y direction */ +static const int MIN_VISIBLE_TITLE_BAR = 13; + +/** Direction for moving the window. */ +enum PreventHideDirection { + PHD_UP, ///< Above v is a safe position. + PHD_DOWN, ///< Below v is a safe position. +}; + +/** + * Do not allow hiding of the rectangle with base coordinates \a nx and \a ny behind window \a v. + * If needed, move the window base coordinates to keep it visible. + * @param nx Base horizontal coordinate of the rectangle. + * @param ny Base vertical coordinate of the rectangle. + * @param rect Rectangle that must stay visible for #MIN_VISIBLE_TITLE_BAR pixels (horizontally, vertically, or both) + * @param v Window lying in front of the rectangle. + * @param px Previous horizontal base coordinate. + * @param dir If no room horizontally, move the rectangle to the indicated position. + */ +static void PreventHiding(int *nx, int *ny, const Rect &rect, const Window *v, int px, PreventHideDirection dir) +{ + if (v == NULL) return; + + int v_bottom = v->top + v->height; + int v_right = v->left + v->width; + int safe_y = (dir == PHD_UP) ? (v->top - MIN_VISIBLE_TITLE_BAR - rect.top) : (v_bottom + MIN_VISIBLE_TITLE_BAR - rect.bottom); // Compute safe vertical position. + + if (*ny + rect.top <= v->top - MIN_VISIBLE_TITLE_BAR) return; // Above v is enough space + if (*ny + rect.bottom >= v_bottom + MIN_VISIBLE_TITLE_BAR) return; // Below v is enough space + + /* Vertically, the rectangle is hidden behind v. */ + if (*nx + rect.left + MIN_VISIBLE_TITLE_BAR < v->left) { // At left of v. + if (v->left < MIN_VISIBLE_TITLE_BAR) *ny = safe_y; // But enough room, force it to a safe position. + return; + } + if (*nx + rect.right - MIN_VISIBLE_TITLE_BAR > v_right) { // At right of v. + if (v_right > _screen.width - MIN_VISIBLE_TITLE_BAR) *ny = safe_y; // Not enough room, force it to a safe position. + return; + } + + /* Horizontally also hidden, force movement to a safe area. */ + if (px + rect.left < v->left && v->left >= MIN_VISIBLE_TITLE_BAR) { // Coming from the left, and enough room there. + *nx = v->left - MIN_VISIBLE_TITLE_BAR - rect.left; + } else if (px + rect.right > v_right && v_right <= _screen.width - MIN_VISIBLE_TITLE_BAR) { // Coming from the right, and enough room there. + *nx = v_right + MIN_VISIBLE_TITLE_BAR - rect.right; + } else { + *ny = safe_y; + } +} + +/** + * Make sure at least a part of the caption bar is still visible by moving + * the window if necessary. + * @param w The window to check. + * @param nx The proposed new x-location of the window. + * @param ny The proposed new y-location of the window. + */ +static void EnsureVisibleCaption(Window *w, int nx, int ny) +{ + /* Search for the title bar rectangle. */ + Rect caption_rect; + const NWidgetBase *caption = w->nested_root->GetWidgetOfType(WWT_CAPTION); + if (caption != NULL) { + caption_rect.left = caption->pos_x; + caption_rect.right = caption->pos_x + caption->current_x; + caption_rect.top = caption->pos_y; + caption_rect.bottom = caption->pos_y + caption->current_y; + + /* Make sure the window doesn't leave the screen */ + nx = Clamp(nx, MIN_VISIBLE_TITLE_BAR - caption_rect.right, _screen.width - MIN_VISIBLE_TITLE_BAR - caption_rect.left); + ny = Clamp(ny, 0, _screen.height - MIN_VISIBLE_TITLE_BAR); + + /* Make sure the title bar isn't hidden behind the main tool bar or the status bar. */ + PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_MAIN_TOOLBAR, 0), w->left, PHD_DOWN); + PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_STATUS_BAR, 0), w->left, PHD_UP); + } + + if (w->viewport != NULL) { + w->viewport->left += nx - w->left; + w->viewport->top += ny - w->top; + } + + w->left = nx; + w->top = ny; +} + +/** + * Resize the window. + * Update all the widgets of a window based on their resize flags + * Both the areas of the old window and the new sized window are set dirty + * ensuring proper redrawal. + * @param w Window to resize + * @param delta_x Delta x-size of changed window (positive if larger, etc.) + * @param delta_y Delta y-size of changed window + * @param clamp_to_screen Whether to make sure the whole window stays visible + */ +void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen) +{ + if (delta_x != 0 || delta_y != 0) { + if (clamp_to_screen) { + /* Determine the new right/bottom position. If that is outside of the bounds of + * the resolution clamp it in such a manner that it stays within the bounds. */ + int new_right = w->left + w->width + delta_x; + int new_bottom = w->top + w->height + delta_y; + if (new_right >= (int)_cur_resolution.width) delta_x -= Ceil(new_right - _cur_resolution.width, max(1U, w->nested_root->resize_x)); + if (new_bottom >= (int)_cur_resolution.height) delta_y -= Ceil(new_bottom - _cur_resolution.height, max(1U, w->nested_root->resize_y)); + } + + w->SetDirty(); + + uint new_xinc = max(0, (w->nested_root->resize_x == 0) ? 0 : (int)(w->nested_root->current_x - w->nested_root->smallest_x) + delta_x); + uint new_yinc = max(0, (w->nested_root->resize_y == 0) ? 0 : (int)(w->nested_root->current_y - w->nested_root->smallest_y) + delta_y); + assert(w->nested_root->resize_x == 0 || new_xinc % w->nested_root->resize_x == 0); + assert(w->nested_root->resize_y == 0 || new_yinc % w->nested_root->resize_y == 0); + + w->nested_root->AssignSizePosition(ST_RESIZE, 0, 0, w->nested_root->smallest_x + new_xinc, w->nested_root->smallest_y + new_yinc, _current_text_dir == TD_RTL); + w->width = w->nested_root->current_x; + w->height = w->nested_root->current_y; + } + + EnsureVisibleCaption(w, w->left, w->top); + + /* Always call OnResize to make sure everything is initialised correctly if it needs to be. */ + w->OnResize(); + w->SetDirty(); +} + +/** + * Return the top of the main view available for general use. + * @return Uppermost vertical coordinate available. + * @note Above the upper y coordinate is often the main toolbar. + */ +int GetMainViewTop() +{ + Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); + return (w == NULL) ? 0 : w->top + w->height; +} + +/** + * Return the bottom of the main view available for general use. + * @return The vertical coordinate of the first unusable row, so 'top + height <= bottom' gives the correct result. + * @note At and below the bottom y coordinate is often the status bar. + */ +int GetMainViewBottom() +{ + Window *w = FindWindowById(WC_STATUS_BAR, 0); + return (w == NULL) ? _screen.height : w->top; +} + +static bool _dragging_window; ///< A window is being dragged or resized. + +/** + * Handle dragging/resizing of a window. + * @return State of handling the event. + */ +static EventState HandleWindowDragging() +{ + /* Get out immediately if no window is being dragged at all. */ + if (!_dragging_window) return ES_NOT_HANDLED; + + /* If button still down, but cursor hasn't moved, there is nothing to do. */ + if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; + + /* Otherwise find the window... */ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->flags & WF_DRAGGING) { + /* Stop the dragging if the left mouse button was released */ + if (!_left_button_down) { + w->flags &= ~WF_DRAGGING; + break; + } + + w->SetDirty(); + + int x = _cursor.pos.x + _drag_delta.x; + int y = _cursor.pos.y + _drag_delta.y; + int nx = x; + int ny = y; + + if (_settings_client.gui.window_snap_radius != 0) { + const Window *v; + + int hsnap = _settings_client.gui.window_snap_radius; + int vsnap = _settings_client.gui.window_snap_radius; + int delta; + + FOR_ALL_WINDOWS_FROM_BACK(v) { + if (v == w) continue; // Don't snap at yourself + + if (y + w->height > v->top && y < v->top + v->height) { + /* Your left border <-> other right border */ + delta = abs(v->left + v->width - x); + if (delta <= hsnap) { + nx = v->left + v->width; + hsnap = delta; + } + + /* Your right border <-> other left border */ + delta = abs(v->left - x - w->width); + if (delta <= hsnap) { + nx = v->left - w->width; + hsnap = delta; + } + } + + if (w->top + w->height >= v->top && w->top <= v->top + v->height) { + /* Your left border <-> other left border */ + delta = abs(v->left - x); + if (delta <= hsnap) { + nx = v->left; + hsnap = delta; + } + + /* Your right border <-> other right border */ + delta = abs(v->left + v->width - x - w->width); + if (delta <= hsnap) { + nx = v->left + v->width - w->width; + hsnap = delta; + } + } + + if (x + w->width > v->left && x < v->left + v->width) { + /* Your top border <-> other bottom border */ + delta = abs(v->top + v->height - y); + if (delta <= vsnap) { + ny = v->top + v->height; + vsnap = delta; + } + + /* Your bottom border <-> other top border */ + delta = abs(v->top - y - w->height); + if (delta <= vsnap) { + ny = v->top - w->height; + vsnap = delta; + } + } + + if (w->left + w->width >= v->left && w->left <= v->left + v->width) { + /* Your top border <-> other top border */ + delta = abs(v->top - y); + if (delta <= vsnap) { + ny = v->top; + vsnap = delta; + } + + /* Your bottom border <-> other bottom border */ + delta = abs(v->top + v->height - y - w->height); + if (delta <= vsnap) { + ny = v->top + v->height - w->height; + vsnap = delta; + } + } + } + } + + EnsureVisibleCaption(w, nx, ny); + + w->SetDirty(); + return ES_HANDLED; + } else if (w->flags & WF_SIZING) { + /* Stop the sizing if the left mouse button was released */ + if (!_left_button_down) { + w->flags &= ~WF_SIZING; + w->SetDirty(); + break; + } + + /* Compute difference in pixels between cursor position and reference point in the window. + * If resizing the left edge of the window, moving to the left makes the window bigger not smaller. + */ + int x, y = _cursor.pos.y - _drag_delta.y; + if (w->flags & WF_SIZING_LEFT) { + x = _drag_delta.x - _cursor.pos.x; + } else { + x = _cursor.pos.x - _drag_delta.x; + } + + /* resize.step_width and/or resize.step_height may be 0, which means no resize is possible. */ + if (w->resize.step_width == 0) x = 0; + if (w->resize.step_height == 0) y = 0; + + /* Check the resize button won't go past the bottom of the screen */ + if (w->top + w->height + y > _screen.height) { + y = _screen.height - w->height - w->top; + } + + /* X and Y has to go by step.. calculate it. + * The cast to int is necessary else x/y are implicitly casted to + * unsigned int, which won't work. */ + if (w->resize.step_width > 1) x -= x % (int)w->resize.step_width; + if (w->resize.step_height > 1) y -= y % (int)w->resize.step_height; + + /* Check that we don't go below the minimum set size */ + if ((int)w->width + x < (int)w->nested_root->smallest_x) { + x = w->nested_root->smallest_x - w->width; + } + if ((int)w->height + y < (int)w->nested_root->smallest_y) { + y = w->nested_root->smallest_y - w->height; + } + + /* Window already on size */ + if (x == 0 && y == 0) return ES_HANDLED; + + /* Now find the new cursor pos.. this is NOT _cursor, because we move in steps. */ + _drag_delta.y += y; + if ((w->flags & WF_SIZING_LEFT) && x != 0) { + _drag_delta.x -= x; // x > 0 -> window gets longer -> left-edge moves to left -> subtract x to get new position. + w->SetDirty(); + w->left -= x; // If dragging left edge, move left window edge in opposite direction by the same amount. + /* ResizeWindow() below ensures marking new position as dirty. */ + } else { + _drag_delta.x += x; + } + + /* ResizeWindow sets both pre- and after-size to dirty for redrawal */ + ResizeWindow(w, x, y); + return ES_HANDLED; + } + } + + _dragging_window = false; + return ES_HANDLED; +} + +/** + * Start window dragging + * @param w Window to start dragging + */ +static void StartWindowDrag(Window *w) +{ + w->flags |= WF_DRAGGING; + w->flags &= ~WF_CENTERED; + _dragging_window = true; + + _drag_delta.x = w->left - _cursor.pos.x; + _drag_delta.y = w->top - _cursor.pos.y; + + BringWindowToFront(w); + DeleteWindowById(WC_DROPDOWN_MENU, 0); +} + +/** + * Start resizing a window. + * @param w Window to start resizing. + * @param to_left Whether to drag towards the left or not + */ +static void StartWindowSizing(Window *w, bool to_left) +{ + w->flags |= to_left ? WF_SIZING_LEFT : WF_SIZING_RIGHT; + w->flags &= ~WF_CENTERED; + _dragging_window = true; + + _drag_delta.x = _cursor.pos.x; + _drag_delta.y = _cursor.pos.y; + + BringWindowToFront(w); + DeleteWindowById(WC_DROPDOWN_MENU, 0); +} + +/** + * handle scrollbar scrolling with the mouse. + * @return State of handling the event. + */ +static EventState HandleScrollbarScrolling() +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->scrolling_scrollbar >= 0) { + /* Abort if no button is clicked any more. */ + if (!_left_button_down) { + w->scrolling_scrollbar = -1; + w->SetDirty(); + return ES_HANDLED; + } + + int i; + NWidgetScrollbar *sb = w->GetWidget(w->scrolling_scrollbar); + bool rtl = false; + + if (sb->type == NWID_HSCROLLBAR) { + i = _cursor.pos.x - _cursorpos_drag_start.x; + rtl = _current_text_dir == TD_RTL; + } else { + i = _cursor.pos.y - _cursorpos_drag_start.y; + } + + if (sb->disp_flags & ND_SCROLLBAR_BTN) { + if (_scroller_click_timeout == 1) { + _scroller_click_timeout = 3; + sb->UpdatePosition(rtl == HasBit(sb->disp_flags, NDB_SCROLLBAR_UP) ? 1 : -1); + w->SetDirty(); + } + return ES_HANDLED; + } + + /* Find the item we want to move to and make sure it's inside bounds. */ + int pos = min(max(0, i + _scrollbar_start_pos) * sb->GetCount() / _scrollbar_size, max(0, sb->GetCount() - sb->GetCapacity())); + if (rtl) pos = max(0, sb->GetCount() - sb->GetCapacity() - pos); + if (pos != sb->GetPosition()) { + sb->SetPosition(pos); + w->SetDirty(); + } + return ES_HANDLED; + } + } + + return ES_NOT_HANDLED; +} + +/** + * Handle viewport scrolling with the mouse. + * @return State of handling the event. + */ +static EventState HandleViewportScroll() +{ + bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); + + if (!_scrolling_viewport) return ES_NOT_HANDLED; + + /* When we don't have a last scroll window we are starting to scroll. + * When the last scroll window and this are not the same we went + * outside of the window and should not left-mouse scroll anymore. */ + if (_last_scroll_window == NULL) _last_scroll_window = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); + + if (_last_scroll_window == NULL || !(_right_button_down || scrollwheel_scrolling || (_settings_client.gui.left_mouse_btn_scrolling && _left_button_down))) { + _cursor.fix_at = false; + _scrolling_viewport = false; + _last_scroll_window = NULL; + return ES_NOT_HANDLED; + } + + if (_last_scroll_window == FindWindowById(WC_MAIN_WINDOW, 0) && _last_scroll_window->viewport->follow_vehicle != INVALID_VEHICLE) { + /* If the main window is following a vehicle, then first let go of it! */ + const Vehicle *veh = Vehicle::Get(_last_scroll_window->viewport->follow_vehicle); + ScrollMainWindowTo(veh->x_pos, veh->y_pos, veh->z_pos, true); // This also resets follow_vehicle + return ES_NOT_HANDLED; + } + + Point delta; + if (_settings_client.gui.reverse_scroll || (_settings_client.gui.left_mouse_btn_scrolling && _left_button_down)) { + delta.x = -_cursor.delta.x; + delta.y = -_cursor.delta.y; + } else { + delta.x = _cursor.delta.x; + delta.y = _cursor.delta.y; + } + + if (scrollwheel_scrolling) { + /* We are using scrollwheels for scrolling */ + delta.x = _cursor.h_wheel; + delta.y = _cursor.v_wheel; + _cursor.v_wheel = 0; + _cursor.h_wheel = 0; + } + + /* Create a scroll-event and send it to the window */ + if (delta.x != 0 || delta.y != 0) _last_scroll_window->OnScroll(delta); + + _cursor.delta.x = 0; + _cursor.delta.y = 0; + return ES_HANDLED; +} + +/** + * Check if a window can be made relative top-most window, and if so do + * it. If a window does not obscure any other windows, it will not + * be brought to the foreground. Also if the only obscuring windows + * are so-called system-windows, the window will not be moved. + * The function will return false when a child window of this window is a + * modal-popup; function returns a false and child window gets a white border + * @param w Window to bring relatively on-top + * @return false if the window has an active modal child, true otherwise + */ +static bool MaybeBringWindowToFront(Window *w) +{ + bool bring_to_front = false; + + if (w->window_class == WC_MAIN_WINDOW || + IsVitalWindow(w) || + w->window_class == WC_TOOLTIPS || + w->window_class == WC_DROPDOWN_MENU) { + return true; + } + + /* Use unshaded window size rather than current size for shaded windows. */ + int w_width = w->width; + int w_height = w->height; + if (w->IsShaded()) { + w_width = w->unshaded_size.width; + w_height = w->unshaded_size.height; + } + + Window *u; + FOR_ALL_WINDOWS_FROM_BACK_FROM(u, w->z_front) { + /* A modal child will prevent the activation of the parent window */ + if (u->parent == w && (u->window_desc->flags & WDF_MODAL)) { + u->SetWhiteBorder(); + u->SetDirty(); + return false; + } + + if (u->window_class == WC_MAIN_WINDOW || + IsVitalWindow(u) || + u->window_class == WC_TOOLTIPS || + u->window_class == WC_DROPDOWN_MENU) { + continue; + } + + /* Window sizes don't interfere, leave z-order alone */ + if (w->left + w_width <= u->left || + u->left + u->width <= w->left || + w->top + w_height <= u->top || + u->top + u->height <= w->top) { + continue; + } + + bring_to_front = true; + } + + if (bring_to_front) BringWindowToFront(w); + return true; +} + +/** + * Process keypress for editbox widget. + * @param wid Editbox widget. + * @param key the Unicode value of the key. + * @param keycode the untranslated key code including shift state. + * @return #ES_HANDLED if the key press has been handled and no other + * window should receive the event. + */ +EventState Window::HandleEditBoxKey(int wid, WChar key, uint16 keycode) +{ + QueryString *query = this->GetQueryString(wid); + if (query == NULL) return ES_NOT_HANDLED; + + int action = QueryString::ACTION_NOTHING; + + switch (query->text.HandleKeyPress(key, keycode)) { + case HKPR_EDITING: + this->SetWidgetDirty(wid); + this->OnEditboxChanged(wid); + break; + + case HKPR_CURSOR: + this->SetWidgetDirty(wid); + /* For the OSK also invalidate the parent window */ + if (this->window_class == WC_OSK) this->InvalidateData(); + break; + + case HKPR_CONFIRM: + if (this->window_class == WC_OSK) { + this->OnClick(Point(), WID_OSK_OK, 1); + } else if (query->ok_button >= 0) { + this->OnClick(Point(), query->ok_button, 1); + } else { + action = query->ok_button; + } + break; + + case HKPR_CANCEL: + if (this->window_class == WC_OSK) { + this->OnClick(Point(), WID_OSK_CANCEL, 1); + } else if (query->cancel_button >= 0) { + this->OnClick(Point(), query->cancel_button, 1); + } else { + action = query->cancel_button; + } + break; + + case HKPR_NOT_HANDLED: + return ES_NOT_HANDLED; + + default: break; + } + + switch (action) { + case QueryString::ACTION_DESELECT: + this->UnfocusFocusedWidget(); + break; + + case QueryString::ACTION_CLEAR: + if (query->text.bytes <= 1) { + /* If already empty, unfocus instead */ + this->UnfocusFocusedWidget(); + } else { + query->text.DeleteAll(); + this->SetWidgetDirty(wid); + this->OnEditboxChanged(wid); + } + break; + + default: + break; + } + + return ES_HANDLED; +} + +/** + * Handle keyboard input. + * @param keycode Virtual keycode of the key. + * @param key Unicode character of the key. + */ +void HandleKeypress(uint keycode, WChar key) +{ + /* World generation is multithreaded and messes with companies. + * But there is no company related window open anyway, so _current_company is not used. */ + assert(HasModalProgress() || IsLocalCompany()); + + /* + * The Unicode standard defines an area called the private use area. Code points in this + * area are reserved for private use and thus not portable between systems. For instance, + * Apple defines code points for the arrow keys in this area, but these are only printable + * on a system running OS X. We don't want these keys to show up in text fields and such, + * and thus we have to clear the unicode character when we encounter such a key. + */ + if (key >= 0xE000 && key <= 0xF8FF) key = 0; + + /* + * If both key and keycode is zero, we don't bother to process the event. + */ + if (key == 0 && keycode == 0) return; + + /* Check if the focused window has a focused editbox */ + if (EditBoxInGlobalFocus()) { + /* All input will in this case go to the focused editbox */ + if (_focused_window->window_class == WC_CONSOLE) { + if (_focused_window->OnKeyPress(key, keycode) == ES_HANDLED) return; + } else { + if (_focused_window->HandleEditBoxKey(_focused_window->nested_focus->index, key, keycode) == ES_HANDLED) return; + } + } + + /* Call the event, start with the uppermost window, but ignore the toolbar. */ + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if (w->window_class == WC_MAIN_TOOLBAR) continue; + if (w->window_desc->hotkeys != NULL) { + int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); + if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return; + } + if (w->OnKeyPress(key, keycode) == ES_HANDLED) return; + } + + w = FindWindowById(WC_MAIN_TOOLBAR, 0); + /* When there is no toolbar w is null, check for that */ + if (w != NULL) { + if (w->window_desc->hotkeys != NULL) { + int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); + if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return; + } + if (w->OnKeyPress(key, keycode) == ES_HANDLED) return; + } + + HandleGlobalHotkeys(key, keycode); +} + +/** + * State of CONTROL key has changed + */ +void HandleCtrlChanged() +{ + /* Call the event, start with the uppermost window. */ + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if (w->OnCTRLStateChange() == ES_HANDLED) return; + } +} + +/** + * Insert a text string at the cursor position into the edit box widget. + * @param wid Edit box widget. + * @param str Text string to insert. + */ +/* virtual */ void Window::InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) +{ + QueryString *query = this->GetQueryString(wid); + if (query == NULL) return; + + if (query->text.InsertString(str, marked, caret, insert_location, replacement_end) || marked) { + this->SetWidgetDirty(wid); + this->OnEditboxChanged(wid); + } +} + +/** + * Handle text input. + * @param str Text string to input. + * @param marked Is the input a marked composition string from an IME? + * @param caret Move the caret to this point in the insertion string. + */ +void HandleTextInput(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) +{ + if (!EditBoxInGlobalFocus()) return; + + _focused_window->InsertTextString(_focused_window->window_class == WC_CONSOLE ? 0 : _focused_window->nested_focus->index, str, marked, caret, insert_location, replacement_end); +} + +/** + * Local counter that is incremented each time an mouse input event is detected. + * The counter is used to stop auto-scrolling. + * @see HandleAutoscroll() + * @see HandleMouseEvents() + */ +static int _input_events_this_tick = 0; + +/** + * If needed and switched on, perform auto scrolling (automatically + * moving window contents when mouse is near edge of the window). + */ +static void HandleAutoscroll() +{ + if (_game_mode == GM_MENU || HasModalProgress()) return; + if (_settings_client.gui.auto_scrolling == VA_DISABLED) return; + if (_settings_client.gui.auto_scrolling == VA_MAIN_VIEWPORT_FULLSCREEN && !_fullscreen) return; + + int x = _cursor.pos.x; + int y = _cursor.pos.y; + Window *w = FindWindowFromPt(x, y); + if (w == NULL || w->flags & WF_DISABLE_VP_SCROLL) return; + if (_settings_client.gui.auto_scrolling != VA_EVERY_VIEWPORT && w->window_class != WC_MAIN_WINDOW) return; + + ViewPort *vp = IsPtInWindowViewport(w, x, y); + if (vp == NULL) return; + + x -= vp->left; + y -= vp->top; + + /* here allows scrolling in both x and y axis */ +#define scrollspeed 3 + if (x - 15 < 0) { + w->viewport->dest_scrollpos_x += ScaleByZoom((x - 15) * scrollspeed, vp->zoom); + } else if (15 - (vp->width - x) > 0) { + w->viewport->dest_scrollpos_x += ScaleByZoom((15 - (vp->width - x)) * scrollspeed, vp->zoom); + } + if (y - 15 < 0) { + w->viewport->dest_scrollpos_y += ScaleByZoom((y - 15) * scrollspeed, vp->zoom); + } else if (15 - (vp->height - y) > 0) { + w->viewport->dest_scrollpos_y += ScaleByZoom((15 - (vp->height - y)) * scrollspeed, vp->zoom); + } +#undef scrollspeed +} + +enum MouseClick { + MC_NONE = 0, + MC_LEFT, + MC_RIGHT, + MC_DOUBLE_LEFT, + MC_HOVER, + + MAX_OFFSET_DOUBLE_CLICK = 5, ///< How much the mouse is allowed to move to call it a double click + TIME_BETWEEN_DOUBLE_CLICK = 500, ///< Time between 2 left clicks before it becoming a double click, in ms + MAX_OFFSET_HOVER = 5, ///< Maximum mouse movement before stopping a hover event. +}; +extern EventState VpHandlePlaceSizingDrag(); + +static void ScrollMainViewport(int x, int y) +{ + if (_game_mode != GM_MENU) { + Window *w = FindWindowById(WC_MAIN_WINDOW, 0); + assert(w); + + w->viewport->dest_scrollpos_x += ScaleByZoom(x, w->viewport->zoom); + w->viewport->dest_scrollpos_y += ScaleByZoom(y, w->viewport->zoom); + } +} + +/** + * Describes all the different arrow key combinations the game allows + * when it is in scrolling mode. + * The real arrow keys are bitwise numbered as + * 1 = left + * 2 = up + * 4 = right + * 8 = down + */ +static const int8 scrollamt[16][2] = { + { 0, 0}, ///< no key specified + {-2, 0}, ///< 1 : left + { 0, -2}, ///< 2 : up + {-2, -1}, ///< 3 : left + up + { 2, 0}, ///< 4 : right + { 0, 0}, ///< 5 : left + right = nothing + { 2, -1}, ///< 6 : right + up + { 0, -2}, ///< 7 : right + left + up = up + { 0, 2}, ///< 8 : down + {-2, 1}, ///< 9 : down + left + { 0, 0}, ///< 10 : down + up = nothing + {-2, 0}, ///< 11 : left + up + down = left + { 2, 1}, ///< 12 : down + right + { 0, 2}, ///< 13 : left + right + down = down + { 2, 0}, ///< 14 : right + up + down = right + { 0, 0}, ///< 15 : left + up + right + down = nothing +}; + +static void HandleKeyScrolling() +{ + /* + * Check that any of the dirkeys is pressed and that the focused window + * doesn't have an edit-box as focused widget. + */ + if (_dirkeys && !EditBoxInGlobalFocus()) { + int factor = _shift_pressed ? 50 : 10; + ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor); + } +} + +static void MouseLoop(MouseClick click, int mousewheel) +{ + /* World generation is multithreaded and messes with companies. + * But there is no company related window open anyway, so _current_company is not used. */ + assert(HasModalProgress() || IsLocalCompany()); + + HandlePlacePresize(); + UpdateTileSelection(); + + if (VpHandlePlaceSizingDrag() == ES_HANDLED) return; + if (HandleMouseDragDrop() == ES_HANDLED) return; + if (HandleWindowDragging() == ES_HANDLED) return; + if (HandleScrollbarScrolling() == ES_HANDLED) return; + if (HandleViewportScroll() == ES_HANDLED) return; + + HandleMouseOver(); + + bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); + if (click == MC_NONE && mousewheel == 0 && !scrollwheel_scrolling) return; + + int x = _cursor.pos.x; + int y = _cursor.pos.y; + Window *w = FindWindowFromPt(x, y); + if (w == NULL) return; + + if (click != MC_HOVER && !MaybeBringWindowToFront(w)) return; + ViewPort *vp = IsPtInWindowViewport(w, x, y); + + /* Don't allow any action in a viewport if either in menu or when having a modal progress window */ + if (vp != NULL && (_game_mode == GM_MENU || HasModalProgress())) return; + + if (mousewheel != 0) { + /* Send mousewheel event to window */ + w->OnMouseWheel(mousewheel); + + /* Dispatch a MouseWheelEvent for widgets if it is not a viewport */ + if (vp == NULL) DispatchMouseWheelEvent(w, w->nested_root->GetWidgetFromPos(x - w->left, y - w->top), mousewheel); + } + + if (vp != NULL) { + if (scrollwheel_scrolling) click = MC_RIGHT; // we are using the scrollwheel in a viewport, so we emulate right mouse button + switch (click) { + case MC_DOUBLE_LEFT: + case MC_LEFT: + DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite); + if (!HandleViewportClicked(vp, x, y) && + !(w->flags & WF_DISABLE_VP_SCROLL) && + _settings_client.gui.left_mouse_btn_scrolling) { + _scrolling_viewport = true; + _cursor.fix_at = false; + } + break; + + case MC_RIGHT: + if (!(w->flags & WF_DISABLE_VP_SCROLL)) { + _scrolling_viewport = true; + _cursor.fix_at = true; + + /* clear 2D scrolling caches before we start a 2D scroll */ + _cursor.h_wheel = 0; + _cursor.v_wheel = 0; + } + break; + + default: + break; + } + } else { + switch (click) { + case MC_LEFT: + case MC_DOUBLE_LEFT: + DispatchLeftClickEvent(w, x - w->left, y - w->top, click == MC_DOUBLE_LEFT ? 2 : 1); + break; + + default: + if (!scrollwheel_scrolling || w == NULL || w->window_class != WC_SMALLMAP) break; + /* We try to use the scrollwheel to scroll since we didn't touch any of the buttons. + * Simulate a right button click so we can get started. */ + /* FALL THROUGH */ + + case MC_RIGHT: DispatchRightClickEvent(w, x - w->left, y - w->top); break; + + case MC_HOVER: DispatchHoverEvent(w, x - w->left, y - w->top); break; + } + } +} + +/** + * Handle a mouse event from the video driver + */ +void HandleMouseEvents() +{ + /* World generation is multithreaded and messes with companies. + * But there is no company related window open anyway, so _current_company is not used. */ + assert(HasModalProgress() || IsLocalCompany()); + + static int double_click_time = 0; + static Point double_click_pos = {0, 0}; + + /* Mouse event? */ + MouseClick click = MC_NONE; + if (_left_button_down && !_left_button_clicked) { + click = MC_LEFT; + if (double_click_time != 0 && _realtime_tick - double_click_time < TIME_BETWEEN_DOUBLE_CLICK && + double_click_pos.x != 0 && abs(_cursor.pos.x - double_click_pos.x) < MAX_OFFSET_DOUBLE_CLICK && + double_click_pos.y != 0 && abs(_cursor.pos.y - double_click_pos.y) < MAX_OFFSET_DOUBLE_CLICK) { + click = MC_DOUBLE_LEFT; + } + double_click_time = _realtime_tick; + double_click_pos = _cursor.pos; + _left_button_clicked = true; + _input_events_this_tick++; + } else if (_right_button_clicked) { + _right_button_clicked = false; + click = MC_RIGHT; + _input_events_this_tick++; + } + + int mousewheel = 0; + if (_cursor.wheel) { + mousewheel = _cursor.wheel; + _cursor.wheel = 0; + _input_events_this_tick++; + } + + static uint32 hover_time = 0; + static Point hover_pos = {0, 0}; + + if (_settings_client.gui.hover_delay > 0) { + if (!_cursor.in_window || click != MC_NONE || mousewheel != 0 || _left_button_down || _right_button_down || + hover_pos.x == 0 || abs(_cursor.pos.x - hover_pos.x) >= MAX_OFFSET_HOVER || + hover_pos.y == 0 || abs(_cursor.pos.y - hover_pos.y) >= MAX_OFFSET_HOVER) { + hover_pos = _cursor.pos; + hover_time = _realtime_tick; + _mouse_hovering = false; + } else { + if (hover_time != 0 && _realtime_tick > hover_time + _settings_client.gui.hover_delay * 1000) { + click = MC_HOVER; + _input_events_this_tick++; + _mouse_hovering = true; + } + } + } + + /* Handle sprite picker before any GUI interaction */ + if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW && _newgrf_debug_sprite_picker.click_time != _realtime_tick) { + /* Next realtime tick? Then redraw has finished */ + _newgrf_debug_sprite_picker.mode = SPM_NONE; + InvalidateWindowData(WC_SPRITE_ALIGNER, 0, 1); + } + + if (click == MC_LEFT && _newgrf_debug_sprite_picker.mode == SPM_WAIT_CLICK) { + /* Mark whole screen dirty, and wait for the next realtime tick, when drawing is finished. */ + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + _newgrf_debug_sprite_picker.clicked_pixel = blitter->MoveTo(_screen.dst_ptr, _cursor.pos.x, _cursor.pos.y); + _newgrf_debug_sprite_picker.click_time = _realtime_tick; + _newgrf_debug_sprite_picker.sprites.Clear(); + _newgrf_debug_sprite_picker.mode = SPM_REDRAW; + MarkWholeScreenDirty(); + } else { + MouseLoop(click, mousewheel); + } + + /* We have moved the mouse the required distance, + * no need to move it at any later time. */ + _cursor.delta.x = 0; + _cursor.delta.y = 0; +} + +/** + * Check the soft limit of deletable (non vital, non sticky) windows. + */ +static void CheckSoftLimit() +{ + if (_settings_client.gui.window_soft_limit == 0) return; + + for (;;) { + uint deletable_count = 0; + Window *w, *last_deletable = NULL; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if (w->window_class == WC_MAIN_WINDOW || IsVitalWindow(w) || (w->flags & WF_STICKY)) continue; + + last_deletable = w; + deletable_count++; + } + + /* We've not reached the soft limit yet. */ + if (deletable_count <= _settings_client.gui.window_soft_limit) break; + + assert(last_deletable != NULL); + delete last_deletable; + } +} + +/** + * Regular call from the global game loop + */ +void InputLoop() +{ + /* World generation is multithreaded and messes with companies. + * But there is no company related window open anyway, so _current_company is not used. */ + assert(HasModalProgress() || IsLocalCompany()); + + CheckSoftLimit(); + HandleKeyScrolling(); + + /* Do the actual free of the deleted windows. */ + for (Window *v = _z_front_window; v != NULL; /* nothing */) { + Window *w = v; + v = v->z_back; + + if (w->window_class != WC_INVALID) continue; + + RemoveWindowFromZOrdering(w); + free(w); + } + + if (_scroller_click_timeout != 0) _scroller_click_timeout--; + DecreaseWindowCounters(); + + if (_input_events_this_tick != 0) { + /* The input loop is called only once per GameLoop() - so we can clear the counter here */ + _input_events_this_tick = 0; + /* there were some inputs this tick, don't scroll ??? */ + return; + } + + /* HandleMouseEvents was already called for this tick */ + HandleMouseEvents(); + HandleAutoscroll(); +} + +/** + * Update the continuously changing contents of the windows, such as the viewports + */ +void UpdateWindows() +{ + Window *w; + + static int highlight_timer = 1; + if (--highlight_timer == 0) { + highlight_timer = 15; + _window_highlight_colour = !_window_highlight_colour; + } + + FOR_ALL_WINDOWS_FROM_FRONT(w) { + w->ProcessScheduledInvalidations(); + w->ProcessHighlightedInvalidations(); + } + + static int we4_timer = 0; + int t = we4_timer + 1; + + if (t >= 100) { + FOR_ALL_WINDOWS_FROM_FRONT(w) { + w->OnHundredthTick(); + } + t = 0; + } + we4_timer = t; + + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if ((w->flags & WF_WHITE_BORDER) && --w->white_border_timer == 0) { + CLRBITS(w->flags, WF_WHITE_BORDER); + w->SetDirty(); + } + } + + DrawDirtyBlocks(); + + FOR_ALL_WINDOWS_FROM_BACK(w) { + /* Update viewport only if window is not shaded. */ + if (w->viewport != NULL && !w->IsShaded()) UpdateViewportPosition(w); + } + NetworkDrawChatMessage(); + /* Redraw mouse cursor in case it was hidden */ + DrawMouseCursor(); +} + +/** + * Mark window as dirty (in need of repainting) + * @param cls Window class + * @param number Window number in that class + */ +void SetWindowDirty(WindowClass cls, WindowNumber number) +{ + const Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls && w->window_number == number) w->SetDirty(); + } +} + +/** + * Mark a particular widget in a particular window as dirty (in need of repainting) + * @param cls Window class + * @param number Window number in that class + * @param widget_index Index number of the widget that needs repainting + */ +void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index) +{ + const Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls && w->window_number == number) { + w->SetWidgetDirty(widget_index); + } + } +} + +/** + * Mark all windows of a particular class as dirty (in need of repainting) + * @param cls Window class + */ +void SetWindowClassesDirty(WindowClass cls) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls) w->SetDirty(); + } +} + +/** + * Mark this window's data as invalid (in need of re-computing) + * @param data The data to invalidate with + * @param gui_scope Whether the function is called from GUI scope. + */ +void Window::InvalidateData(int data, bool gui_scope) +{ + this->SetDirty(); + if (!gui_scope) { + /* Schedule GUI-scope invalidation for next redraw. */ + *this->scheduled_invalidation_data.Append() = data; + } + this->OnInvalidateData(data, gui_scope); +} + +/** + * Process all scheduled invalidations. + */ +void Window::ProcessScheduledInvalidations() +{ + for (int *data = this->scheduled_invalidation_data.Begin(); this->window_class != WC_INVALID && data != this->scheduled_invalidation_data.End(); data++) { + this->OnInvalidateData(*data, true); + } + this->scheduled_invalidation_data.Clear(); +} + +/** + * Process all invalidation of highlighted widgets. + */ +void Window::ProcessHighlightedInvalidations() +{ + if ((this->flags & WF_HIGHLIGHTED) == 0) return; + + for (uint i = 0; i < this->nested_array_size; i++) { + if (this->IsWidgetHighlighted(i)) this->SetWidgetDirty(i); + } +} + +/** + * Mark window data of the window of a given class and specific window number as invalid (in need of re-computing) + * + * Note that by default the invalidation is not considered to be called from GUI scope. + * That means only a part of invalidation is executed immediately. The rest is scheduled for the next redraw. + * The asynchronous execution is important to prevent GUI code being executed from command scope. + * When not in GUI-scope: + * - OnInvalidateData() may not do test-runs on commands, as they might affect the execution of + * the command which triggered the invalidation. (town rating and such) + * - OnInvalidateData() may not rely on _current_company == _local_company. + * This implies that no NewGRF callbacks may be run. + * + * However, when invalidations are scheduled, then multiple calls may be scheduled before execution starts. Earlier scheduled + * invalidations may be called with invalidation-data, which is already invalid at the point of execution. + * That means some stuff requires to be executed immediately in command scope, while not everything may be executed in command + * scope. While GUI-scope calls have no restrictions on what they may do, they cannot assume the game to still be in the state + * when the invalidation was scheduled; passed IDs may have got invalid in the mean time. + * + * Finally, note that invalidations triggered from commands or the game loop result in OnInvalidateData() being called twice. + * Once in command-scope, once in GUI-scope. So make sure to not process differential-changes twice. + * + * @param cls Window class + * @param number Window number within the class + * @param data The data to invalidate with + * @param gui_scope Whether the call is done from GUI scope + */ +void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls && w->window_number == number) { + w->InvalidateData(data, gui_scope); + } + } +} + +/** + * Mark window data of all windows of a given class as invalid (in need of re-computing) + * Note that by default the invalidation is not considered to be called from GUI scope. + * See InvalidateWindowData() for details on GUI-scope vs. command-scope. + * @param cls Window class + * @param data The data to invalidate with + * @param gui_scope Whether the call is done from GUI scope + */ +void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope) +{ + Window *w; + + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls) { + w->InvalidateData(data, gui_scope); + } + } +} + +/** + * Dispatch WE_TICK event over all windows + */ +void CallWindowTickEvent() +{ + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + w->OnTick(); + } +} + +/** + * Try to delete a non-vital window. + * Non-vital windows are windows other than the game selection, main toolbar, + * status bar, toolbar menu, and tooltip windows. Stickied windows are also + * considered vital. + */ +void DeleteNonVitalWindows() +{ + Window *w; + +restart_search: + /* When we find the window to delete, we need to restart the search + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class != WC_MAIN_WINDOW && + w->window_class != WC_SELECT_GAME && + w->window_class != WC_MAIN_TOOLBAR && + w->window_class != WC_STATUS_BAR && + w->window_class != WC_TOOLTIPS && + (w->flags & WF_STICKY) == 0) { // do not delete windows which are 'pinned' + + delete w; + goto restart_search; + } + } +} + +/** + * It is possible that a stickied window gets to a position where the + * 'close' button is outside the gaming area. You cannot close it then; except + * with this function. It closes all windows calling the standard function, + * then, does a little hacked loop of closing all stickied windows. Note + * that standard windows (status bar, etc.) are not stickied, so these aren't affected + */ +void DeleteAllNonVitalWindows() +{ + Window *w; + + /* Delete every window except for stickied ones, then sticky ones as well */ + DeleteNonVitalWindows(); + +restart_search: + /* When we find the window to delete, we need to restart the search + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->flags & WF_STICKY) { + delete w; + goto restart_search; + } + } +} + +/** + * Delete all windows that are used for construction of vehicle etc. + * Once done with that invalidate the others to ensure they get refreshed too. + */ +void DeleteConstructionWindows() +{ + Window *w; + +restart_search: + /* When we find the window to delete, we need to restart the search + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_desc->flags & WDF_CONSTRUCTION) { + delete w; + goto restart_search; + } + } + + FOR_ALL_WINDOWS_FROM_BACK(w) w->SetDirty(); +} + +/** Delete all always on-top windows to get an empty screen */ +void HideVitalWindows() +{ + DeleteWindowById(WC_MAIN_TOOLBAR, 0); + DeleteWindowById(WC_STATUS_BAR, 0); +} + +/** Re-initialize all windows. */ +void ReInitAllWindows() +{ + NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets. + NWidgetScrollbar::InvalidateDimensionCache(); + + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + w->ReInit(); + } +#ifdef ENABLE_NETWORK + void NetworkReInitChatBoxSize(); + NetworkReInitChatBoxSize(); +#endif + + /* Make sure essential parts of all windows are visible */ + RelocateAllWindows(_cur_resolution.width, _cur_resolution.height); + MarkWholeScreenDirty(); +} + +/** + * (Re)position a window at the screen. + * @param w Window structure of the window, may also be \c NULL. + * @param clss The class of the window to position. + * @param setting The actual setting used for the window's position. + * @return X coordinate of left edge of the repositioned window. + */ +static int PositionWindow(Window *w, WindowClass clss, int setting) +{ + if (w == NULL || w->window_class != clss) { + w = FindWindowById(clss, 0); + } + if (w == NULL) return 0; + + int old_left = w->left; + switch (setting) { + case 1: w->left = (_screen.width - w->width) / 2; break; + case 2: w->left = _screen.width - w->width; break; + default: w->left = 0; break; + } + if (w->viewport != NULL) w->viewport->left += w->left - old_left; + SetDirtyBlocks(0, w->top, _screen.width, w->top + w->height); // invalidate the whole row + return w->left; +} + +/** + * (Re)position main toolbar window at the screen. + * @param w Window structure of the main toolbar window, may also be \c NULL. + * @return X coordinate of left edge of the repositioned toolbar window. + */ +int PositionMainToolbar(Window *w) +{ + DEBUG(misc, 5, "Repositioning Main Toolbar..."); + return PositionWindow(w, WC_MAIN_TOOLBAR, _settings_client.gui.toolbar_pos); +} + +/** + * (Re)position statusbar window at the screen. + * @param w Window structure of the statusbar window, may also be \c NULL. + * @return X coordinate of left edge of the repositioned statusbar. + */ +int PositionStatusbar(Window *w) +{ + DEBUG(misc, 5, "Repositioning statusbar..."); + return PositionWindow(w, WC_STATUS_BAR, _settings_client.gui.statusbar_pos); +} + +/** + * (Re)position news message window at the screen. + * @param w Window structure of the news message window, may also be \c NULL. + * @return X coordinate of left edge of the repositioned news message. + */ +int PositionNewsMessage(Window *w) +{ + DEBUG(misc, 5, "Repositioning news message..."); + return PositionWindow(w, WC_NEWS_WINDOW, _settings_client.gui.statusbar_pos); +} + +/** + * (Re)position network chat window at the screen. + * @param w Window structure of the network chat window, may also be \c NULL. + * @return X coordinate of left edge of the repositioned network chat window. + */ +int PositionNetworkChatWindow(Window *w) +{ + DEBUG(misc, 5, "Repositioning network chat window..."); + return PositionWindow(w, WC_SEND_NETWORK_MSG, _settings_client.gui.statusbar_pos); +} + + +/** + * Switches viewports following vehicles, which get autoreplaced + * @param from_index the old vehicle ID + * @param to_index the new vehicle ID + */ +void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->viewport != NULL && w->viewport->follow_vehicle == from_index) { + w->viewport->follow_vehicle = to_index; + w->SetDirty(); + } + } +} + + +/** + * Relocate all windows to fit the new size of the game application screen + * @param neww New width of the game application screen + * @param newh New height of the game application screen. + */ +void RelocateAllWindows(int neww, int newh) +{ + Window *w; + + FOR_ALL_WINDOWS_FROM_BACK(w) { + int left, top; + /* XXX - this probably needs something more sane. For example specifying + * in a 'backup'-desc that the window should always be centered. */ + switch (w->window_class) { + case WC_MAIN_WINDOW: + case WC_BOOTSTRAP: + ResizeWindow(w, neww, newh); + continue; + + case WC_MAIN_TOOLBAR: + ResizeWindow(w, min(neww, w->window_desc->default_width) - w->width, 0, false); + + top = w->top; + left = PositionMainToolbar(w); // changes toolbar orientation + break; + + case WC_NEWS_WINDOW: + top = newh - w->height; + left = PositionNewsMessage(w); + break; + + case WC_STATUS_BAR: + ResizeWindow(w, min(neww, w->window_desc->default_width) - w->width, 0, false); + + top = newh - w->height; + left = PositionStatusbar(w); + break; + + case WC_SEND_NETWORK_MSG: + ResizeWindow(w, Clamp(neww, 320, 640) - w->width, 0, false); + top = newh - w->height - FindWindowById(WC_STATUS_BAR, 0)->height; + left = PositionNetworkChatWindow(w); + break; + + case WC_CONSOLE: + IConsoleResize(w); + continue; + + default: { + if (w->flags & WF_CENTERED) { + top = (newh - w->height) >> 1; + left = (neww - w->width) >> 1; + break; + } + + left = w->left; + if (left + (w->width >> 1) >= neww) left = neww - w->width; + if (left < 0) left = 0; + + top = w->top; + if (top + (w->height >> 1) >= newh) top = newh - w->height; + break; + } + } + + EnsureVisibleCaption(w, left, top); + } +} + +/** + * Destructor of the base class PickerWindowBase + * Main utility is to stop the base Window destructor from triggering + * a free while the child will already be free, in this case by the ResetObjectToPlace(). + */ +PickerWindowBase::~PickerWindowBase() +{ + this->window_class = WC_INVALID; // stop the ancestor from freeing the already (to be) child + ResetObjectToPlace(); +} From 2959bcdbe7be422739a425d4b5caa7453d3e9fb6 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 6 Jul 2013 22:08:58 +0200 Subject: [PATCH 004/187] Allow dropdown to be drawn above the origin widget, even in the case the dropdown needs a scrollbar. --- src/widgets/dropdown.cpp | 45 ++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 6b0f60e37d..fa5753d7d0 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -334,10 +334,10 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b { DeleteWindowById(WC_DROPDOWN_MENU, 0); - /* The preferred position is just below the dropdown calling widget */ + /* The preferred position is just below the dropdown calling widget. */ int top = w->top + wi_rect.bottom + 1; - /* The preferred width equals the calling widget */ + /* The preferred width equals the calling widget. */ uint width = wi_rect.right - wi_rect.left + 1; uint max_item_width = 0; @@ -350,7 +350,7 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b } } - /* Total length of list */ + /* Total length of list. */ int list_height = 0; for (const DropDownListItem * const *it = list->Begin(); it != list->End(); ++it) { @@ -358,28 +358,47 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b list_height += item->Height(width); } - /* Height of window visible */ + /* Height of the dropdown window; by default, the total length of the list. */ int height = list_height; /* Check if the status bar is visible, as we don't want to draw over it */ int screen_bottom = GetMainViewBottom(); bool scroll = false; - /* Check if the dropdown will fully fit below the widget */ + /* Check if the dropdown will fully fit below the widget. */ if (top + height + 4 >= screen_bottom) { - /* If not, check if it will fit above the widget */ - if (w->top + wi_rect.top - height > GetMainViewTop()) { + /* If not, check if it will fit above the widget. */ + int screen_top = GetMainViewTop(); + if (w->top + wi_rect.top > screen_top + height) { top = w->top + wi_rect.top - height - 4; } else { - /* ... and lastly if it won't, enable the scroll bar and fit the - * list in below the widget */ + /* If it doesn't fit above the widget, we need to enable a scrollbar... */ int avg_height = list_height / (int)list->Length(); - int rows = (screen_bottom - 4 - top) / avg_height; - height = rows * avg_height; scroll = true; - /* Add space for the scroll bar if we automatically determined - * the width of the list. */ + + /* ... and choose whether to put the list above or below the widget. */ + bool put_above = false; + int available_height = screen_bottom - w->top - wi_rect.bottom; + if (w->top + wi_rect.top - screen_top > available_height) { + // Put it above. + available_height = w->top + wi_rect.top - screen_top; + put_above = true; + } + + /* Check at least there is space for one item. */ + assert(available_height >= avg_height); + + /* And lastly, fit the list,... */ + int rows = available_height / avg_height; + height = rows * avg_height; + + /* ... add space for the scrollbar,... */ max_item_width += NWidgetScrollbar::GetVerticalDimension().width; + + /* ... and set the top position if needed. */ + if (put_above) { + top = w->top + wi_rect.top - height - 4; + } } } From 6a426ed2df3548603b71a67ddf01e9825002dff3 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Wed, 24 Apr 2013 18:40:21 +0200 Subject: [PATCH 005/187] Modify the length of the Group GUI. Set it to the length of the 'a' character * maximum length of a group name. --- src/group_gui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/group_gui.cpp b/src/group_gui.cpp index ed3176e270..3048f17102 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -165,7 +165,8 @@ private: uint ComputeGroupInfoSize() { this->column_size[VGC_NAME] = maxdim(GetStringBoundingBox(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype), GetStringBoundingBox(STR_GROUP_ALL_TRAINS + this->vli.vtype)); - this->column_size[VGC_NAME].width = max(170u, this->column_size[VGC_NAME].width); +/* We consider the max average length of characters to be the one of "a" */ + this->column_size[VGC_NAME].width = max(GetCharacterWidth(FS_NORMAL, 97) * (MAX_LENGTH_GROUP_NAME_CHARS - 4), this->column_size[VGC_NAME].width); this->tiny_step_height = this->column_size[VGC_NAME].height; this->column_size[VGC_PROTECT] = GetSpriteSize(SPR_GROUP_REPLACE_PROTECT); From 7e91026ec884e587a096203883d32f7064e9d7bd Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 31 Dec 2012 11:47:07 +0100 Subject: [PATCH 006/187] The space between the group name and the sprite is set to 2 instead of 8. Less unused space. --- src/group_gui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 3048f17102..d8dbadd1a2 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -191,7 +191,7 @@ private: this->tiny_step_height += WD_MATRIX_TOP; return WD_FRAMERECT_LEFT + 8 + - this->column_size[VGC_NAME].width + 8 + + this->column_size[VGC_NAME].width + 2 + this->column_size[VGC_PROTECT].width + 2 + this->column_size[VGC_AUTOREPLACE].width + 2 + this->column_size[VGC_PROFIT].width + 2 + @@ -235,7 +235,7 @@ private: DrawString(x, x + this->column_size[VGC_NAME].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour); /* draw autoreplace protection */ - x = rtl ? x - 8 - this->column_size[VGC_PROTECT].width : x + 8 + this->column_size[VGC_NAME].width; + x = rtl ? x - 2 - this->column_size[VGC_PROTECT].width : x + 2 + this->column_size[VGC_NAME].width; if (protection) DrawSprite(SPR_GROUP_REPLACE_PROTECT, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROTECT].height) / 2); /* draw autoreplace status */ From 9fa95981fc31fa5125c0849dda519cbc39750610 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 31 Dec 2012 11:47:33 +0100 Subject: [PATCH 007/187] Display of group names is longer when autoreplace/protection sprites are hidden. --- src/group_gui.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/group_gui.cpp b/src/group_gui.cpp index d8dbadd1a2..11502c7907 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -222,6 +222,7 @@ private: bool rtl = _current_text_dir == TD_RTL; /* draw group name */ + int longer_name = 0; StringID str; if (IsAllGroupID(g_id)) { str = STR_GROUP_ALL_TRAINS + this->vli.vtype; @@ -230,9 +231,13 @@ private: } else { SetDParam(0, g_id); str = STR_GROUP_NAME; + if (!protection) { + longer_name += this->column_size[VGC_PROTECT].width + 2; + if (!stats.autoreplace_defined) longer_name += this->column_size[VGC_AUTOREPLACE].width + 2; + } } - int x = rtl ? right - WD_FRAMERECT_RIGHT - 8 - this->column_size[VGC_NAME].width + 1 : left + WD_FRAMERECT_LEFT + 8; - DrawString(x, x + this->column_size[VGC_NAME].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour); + int x = rtl ? right - WD_FRAMERECT_RIGHT - 8 - this->column_size[VGC_NAME].width - longer_name + 1 : left + WD_FRAMERECT_LEFT + 8; + DrawString(x, x + this->column_size[VGC_NAME].width + longer_name - 1, y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour); /* draw autoreplace protection */ x = rtl ? x - 2 - this->column_size[VGC_PROTECT].width : x + 2 + this->column_size[VGC_NAME].width; From b792189e59a79a40175cf1ce2df91a7227f214a2 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 31 Dec 2012 11:25:18 +0100 Subject: [PATCH 008/187] Some small helpers to draw strings and sprites dealing with left-to-right/right-to-left. --- src/gfx.cpp | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ src/gfx_func.h | 11 ++++++ 2 files changed, 112 insertions(+) diff --git a/src/gfx.cpp b/src/gfx.cpp index a6ab37a23f..13a0d4b8c8 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -1592,3 +1592,104 @@ void SortResolutions(int count) { QSortT(_resolutions, count, &compare_res); } + + +/** + * Returns the initial value for a margin, after telling where are the left and right margins and where we want to draw/write (begining/end of line) + * @param left is the left margin of the horizontal space we want to draw to + * @param right: right margin + * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end + * @return the margin we asked + */ +int InitTempMargin(int left, int right, bool to_end_line) +{ + return to_end_line ^ (_current_text_dir == TD_RTL) ? right :left; +} + +/** + * Consumes a space in an horizontal margin + * @param space: amount of space used + * @param here: the margin where to add the space + * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end + */ +void AddSpace(int space, int &here, bool to_end_line) +{ + here += to_end_line ^ (_current_text_dir == TD_RTL) ? -space : space; +} + +/** + * After drawing something, update a margin + * @param end is where we ended drawing (usually the return value of a DrawString function) + * @param margin is the margin we want to update + * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end + */ +void UpdateMarginEnd(int end, int &margin, bool to_end_line) +{ + margin = to_end_line ^ (_current_text_dir == TD_RTL) ? min(end, margin) : max(end, margin); +} + +/** + * After drawing something, horizontal margins are updated + * @param end: last position drawn + * @param left is the left margin of the horizontal space drawn + * @param right: right margin + * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end + */ +void UpdateMarginsEnd(int end, int &left, int &right, bool to_end_line) +{ + if (to_end_line ^ (_current_text_dir == TD_RTL)) { + right = end; + } else { + left = end; + } +} + +/** + * After drawing something of a certain width, update margins + * @param width: used space + * @param initial left margin + * @param initial right margin + * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end + */ +void UpdateMarginsWidth(int width, int &left, int &right, bool to_end_line) +{ + if (to_end_line ^ (_current_text_dir == TD_RTL)) { + right -= width; + } else { + left += width; + } +} + +/** + * Draws a string in a delimited space; temporal margin gets updated + * @param left is the left margin of the horizontal space we want to draw to + * @param right: right margin of the horizontal space we want to draw to + * @param top: vertical position + * @param margin keeps the most extreme limit used of the line (this should be previously initialized with InitTempLimit) + * @param string to draw + * @param colour for the string + * @param alignment of the string (only left or right alignment) + * @param underline + */ +void DrawString2(int left, int right, int top, int &margin, StringID str, TextColour colour, StringAlignment align, bool underline) +{ + int end = DrawString(left, right, top, str, colour, align, underline); + UpdateMarginEnd(end, margin, align == SA_RIGHT); +} + +/** + * Draws a sprite in a delimited space; temporal margin gets updated + * @param width of the sprite + * @param left is the left margin of the horizontal space we want to draw to + * @param right: right margin of the horizontal space + * @param top: vertical position + * @param margin keeps the most extreme limit used of the line (this should be previously initialized with InitTempLimit) + * @param sprite + * @param palette + * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end + */ +void DrawSprite2(int width, int left, int right, int top, int &margin, SpriteID img, PaletteID pal, bool to_end_line, SubSprite *sub) +{ + DrawSprite(img, pal, to_end_line ^ (_current_text_dir == TD_RTL) ? right - width : left, top, sub); + margin = to_end_line ^ (_current_text_dir == TD_RTL) ? min(right - width, margin): max(margin, left + width); +} diff --git a/src/gfx_func.h b/src/gfx_func.h index 38c9ea5e31..33b13c1fd8 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -171,6 +171,17 @@ int GetCharacterHeight(FontSize size); /** Height of characters in the large (#FS_MONO) font. */ #define FONT_HEIGHT_MONO (GetCharacterHeight(FS_MONO)) +int InitTempMargin(int left, int right, bool to_end_line); +void AddSpace(int space, int &here, bool to_end_line); + +void UpdateMarginEnd(int end, int &margin, bool to_end_line); +void UpdateMarginWidth(int adding, int &margin, bool to_end_line); +void UpdateMarginsEnd(int end, int &left, int &right, bool to_end_line); +void UpdateMarginsWidth(int width, int &left, int &right, bool to_end_line); + +void DrawString2(int left, int right, int top, int &margin, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false); +void DrawSprite2(int width, int left, int right, int top, int &margin, SpriteID img, PaletteID pal, bool to_end_line = false, SubSprite *sub = NULL); + extern DrawPixelInfo *_cur_dpi; TextColour GetContrastColour(uint8 background); From 4f2f3c52c6514d1ca3094df8f68bb6e47ccd2678 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Wed, 24 Apr 2013 18:58:14 +0200 Subject: [PATCH 009/187] Adapt the boxes showing waiting cargo on the Station List: - rtl suport. - size of the boxes adapted to the height of the normal font. - draw a shadowed box if there is no cargo waiting but cargo has been accepted in that station. - also always draw the box for a cargo if cargo has been produced but there are no waiting units. --- src/station_base.h | 8 +++ src/station_gui.cpp | 119 +++++++++++++++++++++++++++----------------- 2 files changed, 81 insertions(+), 46 deletions(-) diff --git a/src/station_base.h b/src/station_base.h index a4ad69547e..82fd00d751 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -292,6 +292,14 @@ struct GoodsEntry { FlowStatMap::const_iterator flow_it(this->flows.find(source)); return flow_it != this->flows.end() ? flow_it->second.GetVia(excluded, excluded2) : INVALID_STATION; } + + /** + * Return true if a cargo type has a rating here or if there is cargo waiting for this type. + */ + inline bool IsSourceStationForCargo() const + { + return this->HasRating() || this->cargo.TotalCount() > 0; + } }; /** All airport-related information. Only valid if tile != INVALID_TILE. */ diff --git a/src/station_gui.cpp b/src/station_gui.cpp index e658c1f20e..e46bcacbd6 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -100,44 +100,90 @@ void CheckRedrawStationCoverage(const Window *w) * @param type Cargo type * @param amount Cargo amount * @param rating ratings data for that particular cargo - * - * @note Each cargo-bar is 16 pixels wide and 6 pixels high - * @note Each rating 14 pixels wide and 1 pixel high and is 1 pixel below the cargo-bar */ static void StationsWndShowStationRating(int left, int right, int y, CargoID type, uint amount, byte rating) { - static const uint units_full = 576; ///< number of units to show station as 'full' - static const uint rating_full = 224; ///< rating needed so it is shown as 'full' + static const uint units_full = 1 << 9; ///< Number of units to show station as full. + static const uint rating_full = 224; ///< Rating needed so it is shown as full. const CargoSpec *cs = CargoSpec::Get(type); if (!cs->IsValid()) return; + y++; ///< Make boxes 1 pixel shorter. + int left_start = left; + int right_start = right; + int height = GetCharacterHeight(FS_SMALL) - 2; int colour = cs->rating_colour; - TextColour tc = GetContrastColour(colour); - uint w = (minu(amount, units_full) + 5) / 36; - int height = GetCharacterHeight(FS_SMALL); + /* Get width of the box to draw. */ + uint width = minu(amount, units_full) * (right - left) / units_full; - /* Draw total cargo (limited) on station (fits into 16 pixels) */ - if (w != 0) GfxFillRect(left, y, left + w - 1, y + height, colour); + /* Update the end margin, adding the width of the box not to be drawn... */ + if (width != 0) UpdateMarginsWidth(right - left - width, left_start, right_start, true); + /* ... or prepare margins in case width == 0 and amount > 0 (just one pixel bar). */ + else left_start = right_start = _current_text_dir ? right : left; - /* Draw a one pixel-wide bar of additional cargo meter, useful - * for stations with only a small amount (<=30) */ - if (w == 0) { - uint rest = amount / 5; - if (rest != 0) { - w += left; - GfxFillRect(w, y + height - rest, w, y + height, colour); + /* Draw total cargo (limited) on station */ + if (amount > 0) GfxFillRect(left_start, y, right_start, y + height, colour); + + DrawString(left, right, y, cs->abbrev, GetContrastColour(colour), SA_CENTER); + + /* Draw green/red ratings bar*/ + y += height + 2; + left_start = left + 1; + right_start = right - 1; + if (rating != 0) { + GfxFillRect(left_start, y, right_start, y, PC_GREEN); + width = minu(rating, rating_full) * (right_start - left_start) / rating_full; + UpdateMarginsWidth(width, left_start, right_start, false); + } + GfxFillRect(left_start, y, right_start, y, PC_RED); +} + +/** + * Draw small boxes of cargo accepted. + * @param left Left most coordinate to draw the box at. + * @param right Right most coordinate to draw the box at. + * @param y Coordinate to draw the box at. + * @param type Cargo type. + * @param acceptance_pickup_byte Acceptance byte. + */ +static void StationsWndShowAcceptance(int left, int right, int y, CargoID type) +{ + const CargoSpec *cs = CargoSpec::Get(type); + if (!cs->IsValid()) return; + y++; + GfxFillRect(left, y, right, y + GetCharacterHeight(FS_SMALL), cs->rating_colour, FILLRECT_CHECKER); + DrawString(left, right, y, cs->abbrev, TC_BLACK, SA_CENTER); +} + +/** + * Draw small boxes showing cargo waiting, ratings... for a given station. + * @param st Station to draw statistics of. + * @param x Position to start drawing at. + * @param width Width for each box. + * @param y Height position to draw the box at. + */ +void StationsWndShowStationRating(const Station *st, int left, int right, int x, int width, int y) +{ + bool rtl = _current_text_dir == TD_RTL; + AddSpace(5, x, false); + + /* For RTL we work in exactly the opposite direction. So + * decrement the space needed first, then draw to the left + * instead of drawing to the left and then incrementing + * the space. */ + if (rtl) x -= width + 4; + for (uint j = 0; j < _sorted_standard_cargo_specs_size && ( x > left && x + width < right ); j++) { + CargoID cid = _sorted_cargo_specs[j]->Index(); + if (st->goods[cid].IsSourceStationForCargo()) { + StationsWndShowStationRating(x, x + width, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating); + AddSpace(width + 4, x, false); + } else if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_EVER_ACCEPTED)) { + StationsWndShowAcceptance(x, x + width, y, cid); + AddSpace(width + 4, x, false); } } - - DrawString(left + 1, right, y, cs->abbrev, tc); - - /* Draw green/red ratings bar (fits into 14 pixels) */ - y += height + 2; - GfxFillRect(left + 1, y, left + 14, y, PC_RED); - rating = minu(rating, rating_full) / 16; - if (rating != 0) GfxFillRect(left + 1, y, left + rating, y, PC_GREEN); } typedef GUIList GUIStationList; @@ -404,7 +450,6 @@ public: break; case WID_STL_LIST: { - bool rtl = _current_text_dir == TD_RTL; int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.Length()); int y = r.top + WD_FRAMERECT_TOP; for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner @@ -418,27 +463,9 @@ public: SetDParam(0, st->index); SetDParam(1, st->facilities); int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION); - x += rtl ? -5 : 5; - /* show cargo waiting and station ratings */ - for (uint j = 0; j < _sorted_standard_cargo_specs_size; j++) { - CargoID cid = _sorted_cargo_specs[j]->Index(); - if (st->goods[cid].cargo.TotalCount() > 0) { - /* For RTL we work in exactly the opposite direction. So - * decrement the space needed first, then draw to the left - * instead of drawing to the left and then incrementing - * the space. */ - if (rtl) { - x -= 20; - if (x < r.left + WD_FRAMERECT_LEFT) break; - } - StationsWndShowStationRating(x, x + 16, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating); - if (!rtl) { - x += 20; - if (x > r.right - WD_FRAMERECT_RIGHT) break; - } - } - } + StationsWndShowStationRating(st, r.left, r.right, x, FONT_HEIGHT_NORMAL + 2, y); + y += FONT_HEIGHT_NORMAL; } From ea0961682d433b1eee836bbdb778aaf70394b5a5 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Fri, 9 Aug 2013 09:33:12 +0000 Subject: [PATCH 010/187] Center yes/no buttons on query string. --- src/misc_gui.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 55bef30e34..71af9c33ae 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -1163,9 +1163,13 @@ static const NWidgetPart _nested_query_widgets[] = { EndContainer(), NWidget(WWT_PANEL, COLOUR_RED), SetPIP(8, 15, 8), NWidget(WWT_TEXT, COLOUR_RED, WID_Q_TEXT), SetMinimalSize(200, 12), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(20, 29, 20), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_Q_NO), SetMinimalSize(71, 12), SetDataTip(STR_QUIT_NO, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_Q_YES), SetMinimalSize(71, 12), SetDataTip(STR_QUIT_YES, STR_NULL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY), SetFill(1, 1), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(20, 29, 20), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_Q_NO), SetMinimalSize(71, 12), SetDataTip(STR_QUIT_NO, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_Q_YES), SetMinimalSize(71, 12), SetDataTip(STR_QUIT_YES, STR_NULL), + EndContainer(), + NWidget(WWT_EMPTY), SetFill(1, 1), EndContainer(), EndContainer(), }; From 1dbcfe02f58fd9406846c96c633c8d7418b722cb Mon Sep 17 00:00:00 2001 From: Juanjo Date: Wed, 26 Jun 2013 20:34:38 +0200 Subject: [PATCH 011/187] Reorder DrawWidget on StatusBarWindow. --- src/statusbar_gui.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/statusbar_gui.cpp b/src/statusbar_gui.cpp index 62799e18bf..fe9b2b3324 100644 --- a/src/statusbar_gui.cpp +++ b/src/statusbar_gui.cpp @@ -128,11 +128,13 @@ struct StatusBarWindow : Window { virtual void DrawWidget(const Rect &r, int widget) const { + StringID str = INVALID_STRING_ID; + switch (widget) { case WID_S_LEFT: /* Draw the date */ SetDParam(0, _date); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_WHITE_DATE_LONG, TC_FROMSTRING, SA_HOR_CENTER); + str = STR_WHITE_DATE_LONG; break; case WID_S_RIGHT: { @@ -140,7 +142,7 @@ struct StatusBarWindow : Window { const Company *c = Company::GetIfValid(_local_company); if (c != NULL) { SetDParam(0, c->money); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_COMPANY_MONEY, TC_FROMSTRING, SA_HOR_CENTER); + str = STR_COMPANY_MONEY; } break; } @@ -148,11 +150,11 @@ struct StatusBarWindow : Window { case WID_S_MIDDLE: /* Draw status bar */ if (this->saving) { // true when saving is active - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_SAVING_GAME, TC_FROMSTRING, SA_HOR_CENTER); + str = STR_STATUSBAR_SAVING_GAME; } else if (_do_autosave) { - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_AUTOSAVE, TC_FROMSTRING, SA_HOR_CENTER); + str = STR_STATUSBAR_AUTOSAVE; } else if (_pause_mode != PM_UNPAUSED) { - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_PAUSED, TC_FROMSTRING, SA_HOR_CENTER); + str = STR_STATUSBAR_PAUSED; } else if (this->ticker_scroll < TICKER_STOP && FindWindowById(WC_NEWS_WINDOW, 0) == NULL && _statusbar_news_item != NULL && _statusbar_news_item->string_id != 0) { /* Draw the scrolling news text */ if (!DrawScrollingStatusText(_statusbar_news_item, this->ticker_scroll, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom)) { @@ -160,22 +162,23 @@ struct StatusBarWindow : Window { if (Company::IsValidID(_local_company)) { /* This is the default text */ SetDParam(0, _local_company); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_COMPANY_NAME, TC_FROMSTRING, SA_HOR_CENTER); + str = STR_STATUSBAR_COMPANY_NAME; } } } else { if (Company::IsValidID(_local_company)) { /* This is the default text */ SetDParam(0, _local_company); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_COMPANY_NAME, TC_FROMSTRING, SA_HOR_CENTER); + str = STR_STATUSBAR_COMPANY_NAME; } } + } - if (this->reminder_timeout > 0) { - Dimension icon_size = GetSpriteSize(SPR_UNREAD_NEWS); - DrawSprite(SPR_UNREAD_NEWS, PAL_NONE, r.right - WD_FRAMERECT_RIGHT - icon_size.width, r.top + WD_FRAMERECT_TOP + (int)(FONT_HEIGHT_NORMAL - icon_size.height) / 2); - } - break; + if (str != INVALID_STRING_ID) DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_FROMSTRING, SA_HOR_CENTER); + + if (widget == WID_S_MIDDLE && this->reminder_timeout > 0) { + Dimension icon_size = GetSpriteSize(SPR_UNREAD_NEWS); + DrawSprite(SPR_UNREAD_NEWS, PAL_NONE, r.right - WD_FRAMERECT_RIGHT - icon_size.width, r.top + WD_FRAMERECT_TOP + (int)(FONT_HEIGHT_NORMAL - icon_size.height) / 2); } } From c715c1073afe8118c3b1c875b1f0a77713749390 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Fri, 9 Aug 2013 09:33:00 +0000 Subject: [PATCH 012/187] Get better sizes for widgets of statusbar. --- src/statusbar_gui.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/statusbar_gui.cpp b/src/statusbar_gui.cpp index fe9b2b3324..a6123e54f6 100644 --- a/src/statusbar_gui.cpp +++ b/src/statusbar_gui.cpp @@ -103,20 +103,30 @@ struct StatusBarWindow : Window { { Dimension d; switch (widget) { + /* Left and right should have same sizing. */ case WID_S_LEFT: + case WID_S_RIGHT: { SetDParamMaxValue(0, MAX_YEAR * DAYS_IN_YEAR); d = GetStringBoundingBox(STR_WHITE_DATE_LONG); - break; - case WID_S_RIGHT: { int64 max_money = UINT32_MAX; const Company *c; FOR_ALL_COMPANIES(c) max_money = max(c->money, max_money); SetDParam(0, 100LL * max_money); - d = GetStringBoundingBox(STR_COMPANY_MONEY); + d = maxdim(d, GetStringBoundingBox(STR_COMPANY_MONEY)); break; } + case WID_S_MIDDLE: + d = GetStringBoundingBox(STR_STATUSBAR_AUTOSAVE); + d = maxdim(d, GetStringBoundingBox(STR_STATUSBAR_PAUSED)); + + if (Company::IsValidID(_local_company)) { + SetDParam(0, _local_company); + d = maxdim(d, GetStringBoundingBox(STR_STATUSBAR_COMPANY_NAME)); + } + break; + default: return; } From dfa346f89f595178be836892fe52d0acbfda3b59 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 10 Aug 2013 19:44:28 +0000 Subject: [PATCH 013/187] Make icons for selling, selling all, autoreplacing,... the same height. --- src/depot_gui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index c677d039d9..c71089b9dd 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -60,8 +60,8 @@ static const NWidgetPart _nested_train_depot_widgets[] = { NWidget(NWID_SELECTION, INVALID_COLOUR, WID_D_SHOW_SELL_CHAIN), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_D_SELL_CHAIN), SetDataTip(SPR_SELL_CHAIN_TRAIN, STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP), SetResize(0, 1), SetFill(0, 1), EndContainer(), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_D_SELL_ALL), SetDataTip(0x0, STR_NULL), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_D_AUTOREPLACE), SetDataTip(0x0, STR_NULL), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_D_SELL_ALL), SetResize(0, 1), SetFill(0, 1), SetDataTip(0x0, STR_NULL), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_D_AUTOREPLACE), SetResize(0, 1), SetFill(0, 1), SetDataTip(0x0, STR_NULL), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_D_V_SCROLL), EndContainer(), From b5ea121dbc24ad674a82829362e1eac0e7638941 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sun, 11 Aug 2013 13:33:33 +0000 Subject: [PATCH 014/187] Change the SetFill/Resize status of order/group by widgets on station GUI. --- src/station_gui.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/station_gui.cpp b/src/station_gui.cpp index e46bcacbd6..b1bb1787df 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -784,12 +784,12 @@ static const NWidgetPart _nested_station_view_widgets[] = { NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(1, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_GROUP), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_STATION_VIEW_GROUP, 0x0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_GROUP_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_GROUP), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_STATION_VIEW_GROUP, 0x0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_GROUP_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(1, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_SV_WAITING), SetMinimalSize(237, 44), SetResize(1, 10), SetScrollbar(WID_SV_SCROLLBAR), EndContainer(), @@ -1406,6 +1406,12 @@ struct StationViewWindow : public Window { fill->width = 0; } break; + + case WID_SV_SORT_ORDER: + case WID_SV_GROUP: + *size = maxdim(GetStringBoundingBox(STR_BUTTON_SORT_BY), GetStringBoundingBox(STR_STATION_VIEW_GROUP)); + size->width += padding.width; + break; } } From 829c5f8dd2b36213065c77217181daed55a87b07 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Wed, 26 Jun 2013 20:13:41 +0200 Subject: [PATCH 015/187] Use resize.step_height, so the height of each element doesn't need to be FONT_HEIGHT_NORMAL. --- src/town_gui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/town_gui.cpp b/src/town_gui.cpp index a36919ad98..7dd009d885 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -202,7 +202,7 @@ public: if (--pos < 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTIONS_TITLE); - y += FONT_HEIGHT_NORMAL; + y += this->resize.step_height; } for (int i = 0; buttons; i++, buttons >>= 1) { @@ -211,7 +211,7 @@ public: if ((buttons & 1) && --pos < 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i, this->sel_index == i ? TC_WHITE : TC_ORANGE); - y += FONT_HEIGHT_NORMAL; + y += this->resize.step_height; } } break; From cc62096ac4eb314048e147de02ea7491d8dc7421 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 22 Jun 2013 20:09:00 +0200 Subject: [PATCH 016/187] Functions for drawing vertically aligned strings. --- src/gfx_func.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/gfx_func.h b/src/gfx_func.h index 33b13c1fd8..80437b5448 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -182,6 +182,18 @@ void UpdateMarginsWidth(int width, int &left, int &right, bool to_end_line); void DrawString2(int left, int right, int top, int &margin, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false); void DrawSprite2(int width, int left, int right, int top, int &margin, SpriteID img, PaletteID pal, bool to_end_line = false, SubSprite *sub = NULL); +/** + * Return where to start drawing a centered object inside a widget. + * @param top The top coordinate (or the left coordinate) of the widget. + * @param height The height (or width) of the widget. + * @param size The height (or width) of the object to draw. + * @return The coordinate where to start drawing the centered object. + */ +static inline int Center(int top, int height, uint size = FONT_HEIGHT_NORMAL) +{ + return top + (height - size) / 2; +} + extern DrawPixelInfo *_cur_dpi; TextColour GetContrastColour(uint8 background); From cab76bd7afb942ba3cc7b7001e40c098db3c56cc Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 29 Jun 2013 11:53:50 +0200 Subject: [PATCH 017/187] Draw strings vertically aligned on some windows. --- src/airport_gui.cpp | 4 ++- src/autoreplace_gui.cpp | 2 +- src/build_vehicle_gui.cpp | 13 +++------ src/build_vehicle_gui.cpp.orig | 13 ++++++--- src/industry_gui.cpp | 2 +- src/industry_gui.cpp.orig | 45 ++++++++++++++--------------- src/misc_gui.cpp | 5 ++-- src/misc_gui.cpp.orig | 10 ++----- src/network/network_chat_gui.cpp | 2 +- src/network/network_content_gui.cpp | 13 +++++---- src/settings_gui.cpp | 4 +-- src/settings_gui.cpp.orig | 16 +++++----- src/station_gui.cpp | 2 +- src/station_gui.cpp.orig | 19 ++++++------ src/statusbar_gui.cpp | 9 ++++-- src/town_gui.cpp | 2 +- src/town_gui.cpp.orig | 23 +++++++-------- src/vehicle_gui.cpp | 4 +-- src/vehicle_gui.cpp.orig | 24 +++++++-------- src/widgets/dropdown.cpp | 2 +- 20 files changed, 103 insertions(+), 111 deletions(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 408dbc50c2..0ba237c024 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -335,7 +335,9 @@ public: if (!as->IsAvailable()) { GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->line_height - 2, PC_BLACK, FILLRECT_CHECKER); } - DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, as->name, ((int)i == _selected_airport_index) ? TC_WHITE : TC_BLACK); + + DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, Center(y, this->line_height), as->name, ((int)i == _selected_airport_index) ? TC_WHITE : TC_BLACK); + y += this->line_height; } break; diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp index dc1f5ed738..485df66b04 100644 --- a/src/autoreplace_gui.cpp +++ b/src/autoreplace_gui.cpp @@ -364,7 +364,7 @@ public: SetDParam(0, STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED); } - DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_BLACK_STRING, TC_FROMSTRING, SA_HOR_CENTER); + DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, Center(r.top, r.bottom - r.top), STR_BLACK_STRING, TC_FROMSTRING, SA_HOR_CENTER); break; } diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 0719f29ec6..410b2dbb3b 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -886,7 +886,6 @@ void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList * int sprite_width = sprite_left + sprite_right; int sprite_x = rtl ? r - sprite_right - 1 : l + sprite_left + 1; - int sprite_y_offset = sprite_y_offsets[type] + step_size / 2; Dimension replace_icon = {0, 0}; int count_width = 0; @@ -902,22 +901,18 @@ void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList * int count_left = l; int count_right = rtl ? text_left : r - WD_FRAMERECT_RIGHT - replace_icon.width - 8; - int normal_text_y_offset = (step_size - FONT_HEIGHT_NORMAL) / 2; - int small_text_y_offset = step_size - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1; - int replace_icon_y_offset = (step_size - replace_icon.height) / 2 - 1; - for (; min < max; min++, y += step_size) { const EngineID engine = (*eng_list)[min]; /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */ const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine); SetDParam(0, engine); - DrawString(text_left, text_right, y + normal_text_y_offset, STR_ENGINE_NAME, engine == selected_id ? TC_WHITE : TC_BLACK); - DrawVehicleEngine(l, r, sprite_x, y + sprite_y_offset, engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); + DrawString(text_left, text_right, Center(y, step_size), STR_ENGINE_NAME, text_colour); + DrawVehicleEngine(l, r, sprite_x, Center(y, step_size, sprite_y_offsets[type]), engine, palette_crash ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); if (show_count) { SetDParam(0, num_engines); - DrawString(count_left, count_right, y + small_text_y_offset, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); - if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, replace_icon_left, y + replace_icon_y_offset); + DrawString(count_left, count_right, Center(y, step_size, FONT_HEIGHT_SMALL), STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); + if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, replace_icon_left, Center(y, step_size, replace_icon.height)); } } } diff --git a/src/build_vehicle_gui.cpp.orig b/src/build_vehicle_gui.cpp.orig index 410b2dbb3b..0719f29ec6 100644 --- a/src/build_vehicle_gui.cpp.orig +++ b/src/build_vehicle_gui.cpp.orig @@ -886,6 +886,7 @@ void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList * int sprite_width = sprite_left + sprite_right; int sprite_x = rtl ? r - sprite_right - 1 : l + sprite_left + 1; + int sprite_y_offset = sprite_y_offsets[type] + step_size / 2; Dimension replace_icon = {0, 0}; int count_width = 0; @@ -901,18 +902,22 @@ void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList * int count_left = l; int count_right = rtl ? text_left : r - WD_FRAMERECT_RIGHT - replace_icon.width - 8; + int normal_text_y_offset = (step_size - FONT_HEIGHT_NORMAL) / 2; + int small_text_y_offset = step_size - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1; + int replace_icon_y_offset = (step_size - replace_icon.height) / 2 - 1; + for (; min < max; min++, y += step_size) { const EngineID engine = (*eng_list)[min]; /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */ const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine); SetDParam(0, engine); - DrawString(text_left, text_right, Center(y, step_size), STR_ENGINE_NAME, text_colour); - DrawVehicleEngine(l, r, sprite_x, Center(y, step_size, sprite_y_offsets[type]), engine, palette_crash ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); + DrawString(text_left, text_right, y + normal_text_y_offset, STR_ENGINE_NAME, engine == selected_id ? TC_WHITE : TC_BLACK); + DrawVehicleEngine(l, r, sprite_x, y + sprite_y_offset, engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); if (show_count) { SetDParam(0, num_engines); - DrawString(count_left, count_right, Center(y, step_size, FONT_HEIGHT_SMALL), STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); - if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, replace_icon_left, Center(y, step_size, replace_icon.height)); + DrawString(count_left, count_right, y + small_text_y_offset, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); + if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, replace_icon_left, y + replace_icon_y_offset); } } } diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index cc305509f2..1dabde2646 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -1260,7 +1260,7 @@ public: case WID_ID_INDUSTRY_LIST: { int n = 0; - int y = r.top + WD_FRAMERECT_TOP; + int y = Center(r.top, this->resize.step_height); if (this->industries.Length() == 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_DIRECTORY_NONE); break; diff --git a/src/industry_gui.cpp.orig b/src/industry_gui.cpp.orig index 45a62a7fd3..cc305509f2 100644 --- a/src/industry_gui.cpp.orig +++ b/src/industry_gui.cpp.orig @@ -206,6 +206,9 @@ class BuildIndustryWindow : public Window { bool enabled[NUM_INDUSTRYTYPES + 1]; ///< availability state, coming from CBID_INDUSTRY_PROBABILITY (if ever) Scrollbar *vscroll; + /** The offset for the text in the matrix. */ + static const int MATRIX_TEXT_OFFSET = 17; + void SetupArrays() { this->count = 0; @@ -293,8 +296,8 @@ public: if (this->index[i] == INVALID_INDUSTRYTYPE) continue; d = maxdim(d, GetStringBoundingBox(GetIndustrySpec(this->index[i])->name)); } - resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); - d.width += FONT_HEIGHT_NORMAL * 5 / 4 + padding.width; + resize->height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + d.width += MATRIX_TEXT_OFFSET + padding.width; d.height = 5 * resize->height; *size = maxdim(*size, d); break; @@ -378,22 +381,20 @@ public: switch (widget) { case WID_DPI_MATRIX_WIDGET: { uint text_left, text_right, icon_left, icon_right; - uint square_size = FONT_HEIGHT_NORMAL - 2; - uint text_offset = FONT_HEIGHT_NORMAL * 5 / 4; if (_current_text_dir == TD_RTL) { icon_right = r.right - WD_MATRIX_RIGHT; - icon_left = icon_right - square_size; - text_right = icon_right - text_offset; + icon_left = icon_right - 10; + text_right = icon_right - BuildIndustryWindow::MATRIX_TEXT_OFFSET; text_left = r.left + WD_MATRIX_LEFT; } else { icon_left = r.left + WD_MATRIX_LEFT; - icon_right = icon_left + square_size; - text_left = icon_left + text_offset; + icon_right = icon_left + 10; + text_left = icon_left + BuildIndustryWindow::MATRIX_TEXT_OFFSET; text_right = r.right - WD_MATRIX_RIGHT; } - int y = Center(r.top, this->resize.step_height); - for (byte i = 0; i < this->vscroll->GetCapacity() && i + this->vscroll->GetPosition() < this->count; i++, y += this->resize.step_height) { + for (byte i = 0; i < this->vscroll->GetCapacity() && i + this->vscroll->GetPosition() < this->count; i++) { + int y = r.top + WD_MATRIX_TOP + i * this->resize.step_height; bool selected = this->selected_index == i + this->vscroll->GetPosition(); if (this->index[i + this->vscroll->GetPosition()] == INVALID_INDUSTRYTYPE) { @@ -404,8 +405,8 @@ public: /* Draw the name of the industry in white is selected, otherwise, in orange */ DrawString(text_left, text_right, y, indsp->name, selected ? TC_WHITE : TC_ORANGE); - GfxFillRect(icon_left, y + 1, icon_right, y + square_size, selected ? PC_WHITE : PC_BLACK); - GfxFillRect(icon_left + 1, y + 2, icon_right - 1, y + square_size - 1, indsp->map_colour); + GfxFillRect(icon_left, y + 1, icon_right, y + 7, selected ? PC_WHITE : PC_BLACK); + GfxFillRect(icon_left + 1, y + 2, icon_right - 1, y + 6, indsp->map_colour); } break; } @@ -757,7 +758,7 @@ public: if (first) { if (has_accept) y += WD_PAR_VSEP_WIDE; DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE); - y += this->editable == EA_RATE ? GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL) : FONT_HEIGHT_NORMAL; + y += FONT_HEIGHT_NORMAL; if (this->editable == EA_RATE) this->production_offset_y = y; first = false; } @@ -772,10 +773,8 @@ public: if (this->editable == EA_RATE) { DrawArrowButtons(left + WD_FRAMETEXT_LEFT, y, COLOUR_YELLOW, (this->clicked_line == IL_RATE1 + j) ? this->clicked_button : 0, i->production_rate[j] > 0, i->production_rate[j] < 255); - y += GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - } else { - y += FONT_HEIGHT_NORMAL; } + y += FONT_HEIGHT_NORMAL; } /* Display production multiplier if editable */ @@ -787,7 +786,7 @@ public: DrawString(x, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_PRODUCTION_LEVEL); DrawArrowButtons(left + WD_FRAMETEXT_LEFT, y, COLOUR_YELLOW, (this->clicked_line == IL_MULTIPLIER) ? this->clicked_button : 0, i->prod_level > PRODLEVEL_MINIMUM, i->prod_level < PRODLEVEL_MAXIMUM); - y += GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + y += FONT_HEIGHT_NORMAL; } /* Get the extra message for the GUI */ @@ -835,14 +834,12 @@ public: case EA_NONE: break; case EA_MULTIPLIER: - if (IsInsideBS(pt.y, this->production_offset_y, SETTING_BUTTON_HEIGHT)) line = IL_MULTIPLIER; + if (IsInsideBS(pt.y, this->production_offset_y, FONT_HEIGHT_NORMAL)) line = IL_MULTIPLIER; break; case EA_RATE: if (pt.y >= this->production_offset_y) { - if ((pt.y - this->production_offset_y) % GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL) > (uint)SETTING_BUTTON_HEIGHT) break;; - - int row = (pt.y - this->production_offset_y) / GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + int row = (pt.y - this->production_offset_y) / FONT_HEIGHT_NORMAL; for (uint j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] == CT_INVALID) continue; row--; @@ -1058,7 +1055,7 @@ static const NWidgetPart _nested_industry_directory_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetSizingType(NWST_STEP), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), EndContainer(), @@ -1263,7 +1260,7 @@ public: case WID_ID_INDUSTRY_LIST: { int n = 0; - int y = Center(r.top, this->resize.step_height); + int y = r.top + WD_FRAMERECT_TOP; if (this->industries.Length() == 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_DIRECTORY_NONE); break; @@ -1306,7 +1303,7 @@ public: for (uint i = 0; i < this->industries.Length(); i++) { d = maxdim(d, GetStringBoundingBox(this->GetIndustryString(this->industries[i]))); } - resize->height = d.height = GetMinSizing(NWST_STEP, d.height); + resize->height = d.height; d.height *= 5; d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 71af9c33ae..1746573c90 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -786,11 +786,12 @@ void QueryString::DrawEditBox(const Window *w, int wid) const /* If we have a marked area, draw a background highlight. */ if (tb->marklength != 0) GfxFillRect(delta + tb->markxoffs, 0, delta + tb->markxoffs + tb->marklength - 1, bottom - top, PC_GREY); - DrawString(delta, tb->pixels, 0, tb->buf, TC_YELLOW); + DrawString(delta, tb->pixels, Center(0, bottom - top), tb->buf, TC_YELLOW); + bool focussed = w->IsWidgetGloballyFocused(wid) || IsOSKOpenedFor(w, wid); if (focussed && tb->caret) { int caret_width = GetStringBoundingBox("_").width; - DrawString(tb->caretxoffs + delta, tb->caretxoffs + delta + caret_width, 0, "_", TC_WHITE); + DrawString(tb->caretxoffs + delta, tb->caretxoffs + delta + caret_width, Center(0, bottom - top), "_", TC_WHITE); } _cur_dpi = old_dpi; diff --git a/src/misc_gui.cpp.orig b/src/misc_gui.cpp.orig index d0075fe038..71af9c33ae 100644 --- a/src/misc_gui.cpp.orig +++ b/src/misc_gui.cpp.orig @@ -631,8 +631,6 @@ static WindowDesc _tool_tips_desc( _nested_tooltips_widgets, lengthof(_nested_tooltips_widgets) ); -uint _tooltip_width = 194; - /** Window for displaying a tooltip. */ struct TooltipsWindow : public Window { @@ -681,7 +679,7 @@ struct TooltipsWindow : public Window /* There is only one widget. */ for (uint i = 0; i != this->paramcount; i++) SetDParam(i, this->params[i]); - size->width = min(GetStringBoundingBox(this->string_id).width, _tooltip_width); + size->width = min(GetStringBoundingBox(this->string_id).width, 194); size->height = GetStringHeight(this->string_id, size->width); /* Increase slightly to have some space around the box. */ @@ -788,12 +786,11 @@ void QueryString::DrawEditBox(const Window *w, int wid) const /* If we have a marked area, draw a background highlight. */ if (tb->marklength != 0) GfxFillRect(delta + tb->markxoffs, 0, delta + tb->markxoffs + tb->marklength - 1, bottom - top, PC_GREY); - DrawString(delta, tb->pixels, Center(0, bottom - top), tb->buf, TC_YELLOW); - + DrawString(delta, tb->pixels, 0, tb->buf, TC_YELLOW); bool focussed = w->IsWidgetGloballyFocused(wid) || IsOSKOpenedFor(w, wid); if (focussed && tb->caret) { int caret_width = GetStringBoundingBox("_").width; - DrawString(tb->caretxoffs + delta, tb->caretxoffs + delta + caret_width, Center(0, bottom - top), "_", TC_WHITE); + DrawString(tb->caretxoffs + delta, tb->caretxoffs + delta + caret_width, 0, "_", TC_WHITE); } _cur_dpi = old_dpi; @@ -1103,7 +1100,6 @@ struct QueryWindow : public Window { { if (widget != WID_Q_TEXT) return; - size->width = GetMinSizing(NWST_WINDOW_LENGTH, size->width); Dimension d = GetStringMultiLineBoundingBox(this->message, *size); d.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index 8b965feff2..4791a51a38 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -478,7 +478,7 @@ struct NetworkChatWindow : public Window { if (this->dtype == DESTTYPE_CLIENT) { SetDParamStr(0, NetworkClientInfo::GetByClientID((ClientID)this->dest)->client_name); } - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, this->dest_string, TC_BLACK, SA_RIGHT); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(r.top, r.bottom - r.top), this->dest_string, TC_BLACK, SA_RIGHT); } virtual void OnClick(Point pt, int widget, int click_count) diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index 808c3ea232..b0d7cbbc18 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -535,7 +535,7 @@ public: { switch (widget) { case WID_NCL_FILTER_CAPT: - DrawString(r.left, r.right, r.top, STR_CONTENT_FILTER_TITLE, TC_FROMSTRING, SA_RIGHT); + DrawString(r.left, r.right, Center(r.top, r.bottom - r.top), STR_CONTENT_FILTER_TITLE, TC_FROMSTRING, SA_RIGHT); break; case WID_NCL_DETAILS: @@ -577,13 +577,13 @@ public: /* Fill the matrix with the information */ - int sprite_y_offset = WD_MATRIX_TOP + (FONT_HEIGHT_NORMAL - 10) / 2; + Dimension sprite_dim = GetSpriteSize(SPR_BOX_EMPTY); uint y = r.top; int cnt = 0; for (ConstContentIterator iter = this->content.Get(this->vscroll->GetPosition()); iter != this->content.End() && cnt < this->vscroll->GetCapacity(); iter++, cnt++) { const ContentInfo *ci = *iter; - if (ci == this->selected) GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->resize.step_height - 1, PC_GREY); + if (ci == this->selected) GfxFillRect(r.left + 1, y + WD_FRAMERECT_TOP, r.right - 1, y + this->resize.step_height - WD_FRAMERECT_BOTTOM, PC_GREY); SpriteID sprite; SpriteID pal = PAL_NONE; @@ -595,12 +595,13 @@ public: case ContentInfo::DOES_NOT_EXIST: sprite = SPR_BLOT; pal = PALETTE_TO_RED; break; default: NOT_REACHED(); } - DrawSprite(sprite, pal, nwi_checkbox->pos_x + (pal == PAL_NONE ? 2 : 3), y + sprite_y_offset + (pal == PAL_NONE ? 1 : 0)); + + DrawSprite(sprite, pal, Center(nwi_checkbox->pos_x + (pal == PAL_NONE ? 2 : 3), nwi_checkbox->current_x, sprite_dim.width), Center(y, this->resize.step_height, sprite_dim.height + (pal == PAL_NONE ? 0 : -2))); StringID str = STR_CONTENT_TYPE_BASE_GRAPHICS + ci->type - CONTENT_TYPE_BASE_GRAPHICS; - DrawString(nwi_type->pos_x, nwi_type->pos_x + nwi_type->current_x - 1, y + WD_MATRIX_TOP, str, TC_BLACK, SA_HOR_CENTER); + DrawString(nwi_type->pos_x, nwi_type->pos_x + nwi_type->current_x - 1, Center(y, this->resize.step_height), str, TC_BLACK, SA_HOR_CENTER); - DrawString(nwi_name->pos_x + WD_FRAMERECT_LEFT, nwi_name->pos_x + nwi_name->current_x - WD_FRAMERECT_RIGHT, y + WD_MATRIX_TOP, ci->name, TC_BLACK); + DrawString(nwi_name->pos_x + WD_FRAMERECT_LEFT, nwi_name->pos_x + nwi_name->current_x - WD_FRAMERECT_RIGHT, Center(y,this->resize.step_height), ci->name, TC_BLACK); y += this->resize.step_height; } } diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 5775e73732..c01d8391b8 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1151,7 +1151,7 @@ uint SettingEntry::Draw(GameSettings *settings_ptr, int left, int right, int bas case SEF_SUBTREE_KIND: if (cur_row >= first_row) { DrawSprite((this->d.sub.folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED), PAL_NONE, rtl ? x - 8 : x, y + (SETTING_HEIGHT - 11) / 2); - DrawString(rtl ? left : x + 12, rtl ? x - 12 : right, y, this->d.sub.title); + DrawString(rtl ? left : x + 12, rtl ? x - 12 : right, Center(y, SETTING_HEIGHT), this->d.sub.title); } cur_row++; if (!this->d.sub.folded) { @@ -1243,7 +1243,7 @@ void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, editable && value != (sdb->flags & SGF_0ISDISABLED ? 0 : sdb->min), editable && (uint32)value != sdb->max); } this->SetValueDParams(1, value); - DrawString(text_left, text_right, y, sdb->str, highlight ? TC_WHITE : TC_LIGHT_BLUE); + DrawString(text_left, text_right, Center(y, SETTING_HEIGHT), sdb->str, highlight ? TC_WHITE : TC_LIGHT_BLUE); } diff --git a/src/settings_gui.cpp.orig b/src/settings_gui.cpp.orig index 755b829ff9..5775e73732 100644 --- a/src/settings_gui.cpp.orig +++ b/src/settings_gui.cpp.orig @@ -1151,7 +1151,7 @@ uint SettingEntry::Draw(GameSettings *settings_ptr, int left, int right, int bas case SEF_SUBTREE_KIND: if (cur_row >= first_row) { DrawSprite((this->d.sub.folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED), PAL_NONE, rtl ? x - 8 : x, y + (SETTING_HEIGHT - 11) / 2); - DrawString(rtl ? left : x + 12, rtl ? x - 12 : right, Center(y, SETTING_HEIGHT), this->d.sub.title); + DrawString(rtl ? left : x + 12, rtl ? x - 12 : right, y, this->d.sub.title); } cur_row++; if (!this->d.sub.folded) { @@ -1243,7 +1243,7 @@ void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, editable && value != (sdb->flags & SGF_0ISDISABLED ? 0 : sdb->min), editable && (uint32)value != sdb->max); } this->SetValueDParams(1, value); - DrawString(text_left, text_right, Center(y, SETTING_HEIGHT), sdb->str, highlight ? TC_WHITE : TC_LIGHT_BLUE); + DrawString(text_left, text_right, y, sdb->str, highlight ? TC_WHITE : TC_LIGHT_BLUE); } @@ -1797,7 +1797,7 @@ struct GameSettingsWindow : Window { { switch (widget) { case WID_GS_OPTIONSPANEL: - resize->height = SETTING_HEIGHT = GetMinSizing(NWST_STEP, max(11, FONT_HEIGHT_NORMAL + 1)); + resize->height = SETTING_HEIGHT = max(11, FONT_HEIGHT_NORMAL + 1); resize->width = 1; size->height = 5 * resize->height + SETTINGTREE_TOP_OFFSET + SETTINGTREE_BOTTOM_OFFSET; @@ -2368,13 +2368,11 @@ void ShowGameSettings() void DrawArrowButtons(int x, int y, Colours button_colour, byte state, bool clickable_left, bool clickable_right) { int colour = _colour_gradient[button_colour][2]; - int half_button = SETTING_BUTTON_WIDTH / 2; - DrawFrameRect(x, y, x + half_button - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, (state == 1) ? FR_LOWERED : FR_NONE); - DrawFrameRect(x + half_button, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, (state == 2) ? FR_LOWERED : FR_NONE); - Dimension d = GetSpriteSize(SPR_ARROW_LEFT); - DrawSprite(SPR_ARROW_LEFT, PAL_NONE, Center(x, half_button, d.width), Center(y, SETTING_BUTTON_HEIGHT, d.height)); - DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, Center(x + half_button, half_button, d.width), Center(y, SETTING_BUTTON_HEIGHT, d.height)); + DrawFrameRect(x, y, x + SETTING_BUTTON_WIDTH / 2 - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, (state == 1) ? FR_LOWERED : FR_NONE); + DrawFrameRect(x + SETTING_BUTTON_WIDTH / 2, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, (state == 2) ? FR_LOWERED : FR_NONE); + DrawSprite(SPR_ARROW_LEFT, PAL_NONE, x + WD_IMGBTN_LEFT, y + WD_IMGBTN_TOP); + DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, x + WD_IMGBTN_LEFT + SETTING_BUTTON_WIDTH / 2, y + WD_IMGBTN_TOP); /* Grey out the buttons that aren't clickable */ bool rtl = _current_text_dir == TD_RTL; diff --git a/src/station_gui.cpp b/src/station_gui.cpp index b1bb1787df..48a82f8d45 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -2303,7 +2303,7 @@ struct SelectStationWindow : Window { { if (widget != WID_JS_PANEL) return; - uint y = r.top + WD_FRAMERECT_TOP; + uint y = Center(r.top, this->resize.step_height); if (this->vscroll->GetPosition() == 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); y += this->resize.step_height; diff --git a/src/station_gui.cpp.orig b/src/station_gui.cpp.orig index e57be72c86..b1bb1787df 100644 --- a/src/station_gui.cpp.orig +++ b/src/station_gui.cpp.orig @@ -400,7 +400,7 @@ public: } case WID_STL_LIST: - resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + resize->height = FONT_HEIGHT_NORMAL; size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; break; @@ -451,8 +451,7 @@ public: case WID_STL_LIST: { int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.Length()); - uint line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - int y = Center(r.top + WD_FRAMERECT_TOP, line_height); + int y = r.top + WD_FRAMERECT_TOP; for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner const Station *st = this->stations[i]; assert(st->xy != INVALID_TILE); @@ -465,9 +464,9 @@ public: SetDParam(1, st->facilities); int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION); - StationsWndShowStationRating(st, r.left, r.right, x, line_height + 2, y); + StationsWndShowStationRating(st, r.left, r.right, x, FONT_HEIGHT_NORMAL + 2, y); - y += line_height; + y += FONT_HEIGHT_NORMAL; } if (this->vscroll->GetCount() == 0) { // company has no stations @@ -519,7 +518,7 @@ public: { switch (widget) { case WID_STL_LIST: { - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, this->resize.step_height); + uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, FONT_HEIGHT_NORMAL); if (id_v >= this->stations.Length()) return; // click out of list bound const Station *st = this->stations[id_v]; @@ -744,7 +743,7 @@ static const NWidgetPart _nested_company_stations_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetSizingType(NWST_STEP), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_SORTDROPBTN), SetMinimalSize(163, 12), SetDataTip(STR_SORT_BY_NAME, STR_TOOLTIP_SORT_CRITERIA), // widget_data gets overwritten. NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(), EndContainer(), @@ -2293,8 +2292,8 @@ struct SelectStationWindow : Window { d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION)); } - resize->height = GetMinSizing(NWST_STEP, d.height); - d.height = 5 * resize->height; + resize->height = d.height; + d.height *= 5; d.width += WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = d; @@ -2304,7 +2303,7 @@ struct SelectStationWindow : Window { { if (widget != WID_JS_PANEL) return; - uint y = Center(r.top, this->resize.step_height); + uint y = r.top + WD_FRAMERECT_TOP; if (this->vscroll->GetPosition() == 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); y += this->resize.step_height; diff --git a/src/statusbar_gui.cpp b/src/statusbar_gui.cpp index a6123e54f6..c06976fe2a 100644 --- a/src/statusbar_gui.cpp +++ b/src/statusbar_gui.cpp @@ -67,7 +67,7 @@ static bool DrawScrollingStatusText(const NewsItem *ni, int scroll_pos, int left DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; - DrawString(pos, INT16_MAX, 0, buffer, TC_LIGHT_BLUE, SA_LEFT | SA_FORCE); + DrawString(pos, INT16_MAX, Center(0, bottom - top), buffer, TC_LIGHT_BLUE, SA_LEFT | SA_FORCE); _cur_dpi = old_dpi; return (_current_text_dir == TD_RTL) ? (pos < right - left) : (pos + width > 0); @@ -182,13 +182,16 @@ struct StatusBarWindow : Window { str = STR_STATUSBAR_COMPANY_NAME; } } + break; } - if (str != INVALID_STRING_ID) DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_FROMSTRING, SA_HOR_CENTER); + int center_top = Center(r.top + WD_FRAMERECT_TOP, r.bottom - r.top); + if (str != INVALID_STRING_ID) DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, center_top, str, TC_FROMSTRING, SA_HOR_CENTER); if (widget == WID_S_MIDDLE && this->reminder_timeout > 0) { Dimension icon_size = GetSpriteSize(SPR_UNREAD_NEWS); - DrawSprite(SPR_UNREAD_NEWS, PAL_NONE, r.right - WD_FRAMERECT_RIGHT - icon_size.width, r.top + WD_FRAMERECT_TOP + (int)(FONT_HEIGHT_NORMAL - icon_size.height) / 2); + center_top = Center(r.top + WD_FRAMERECT_TOP, r.bottom - r.top, icon_size.height); + DrawSprite(SPR_UNREAD_NEWS, PAL_NONE, r.right - WD_FRAMERECT_RIGHT - icon_size.width, center_top); } } diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 7dd009d885..052fe4119d 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -197,7 +197,7 @@ public: case WID_TA_COMMAND_LIST: { int numact; uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); - int y = r.top + WD_FRAMERECT_TOP; + int y = Center(r.top, this->resize.step_height); int pos = this->vscroll->GetPosition(); if (--pos < 0) { diff --git a/src/town_gui.cpp.orig b/src/town_gui.cpp.orig index e6ad46e33b..7dd009d885 100644 --- a/src/town_gui.cpp.orig +++ b/src/town_gui.cpp.orig @@ -47,12 +47,12 @@ static const NWidgetPart _nested_town_authority_widgets[] = { NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), SetFill(1, 1), EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_COMMAND_LIST), SetMinimalSize(305, 52), SetResize(1, 0), SetDataTip(0x0, STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), SetScrollbar(WID_TA_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_TA_SCROLLBAR), EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 1), SetFill(1, 1), EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TA_EXECUTE), SetMinimalSize(317, 12), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_LOCAL_AUTHORITY_DO_IT_BUTTON, STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), @@ -65,7 +65,6 @@ private: Town *town; ///< Town being displayed. int sel_index; ///< Currently selected town action, \c 0 to \c TACT_COUNT-1, \c -1 means no action selected. Scrollbar *vscroll; - uint actions_step; uint displayed_actions_on_previous_painting; ///< Actions that were available on the previous call to OnPaint() /** @@ -95,8 +94,7 @@ public: this->town = Town::Get(window_number); this->InitNested(window_number); this->vscroll = this->GetScrollbar(WID_TA_SCROLLBAR); - this->actions_step = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - this->vscroll->SetCapacity((this->GetWidget(WID_TA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / this->actions_step); + this->vscroll->SetCapacity((this->GetWidget(WID_TA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / FONT_HEIGHT_NORMAL); } virtual void OnPaint() @@ -199,12 +197,12 @@ public: case WID_TA_COMMAND_LIST: { int numact; uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); - int y = Center(r.top, this->actions_step); + int y = r.top + WD_FRAMERECT_TOP; int pos = this->vscroll->GetPosition(); if (--pos < 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTIONS_TITLE); - y += this->actions_step; + y += this->resize.step_height; } for (int i = 0; buttons; i++, buttons >>= 1) { @@ -213,7 +211,7 @@ public: if ((buttons & 1) && --pos < 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i, this->sel_index == i ? TC_WHITE : TC_ORANGE); - y += this->actions_step; + y += this->resize.step_height; } } break; @@ -240,8 +238,7 @@ public: } case WID_TA_COMMAND_LIST: - resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; + size->height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; size->width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width; for (uint i = 0; i < TACT_COUNT; i++ ) { size->width = max(size->width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i).width); @@ -260,7 +257,7 @@ public: { switch (widget) { case WID_TA_COMMAND_LIST: { - int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, this->actions_step); + int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, FONT_HEIGHT_NORMAL); if (!IsInsideMM(y, 0, 5)) return; y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_company, this->town), y + this->vscroll->GetPosition() - 1); @@ -614,7 +611,7 @@ static const NWidgetPart _nested_town_directory_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TD_SORT_ORDER), SetSizingType(NWST_STEP), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TD_SORT_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_TD_SORT_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), EndContainer(), @@ -826,7 +823,7 @@ public: } Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD); d.width += icon_size.width + 2; - d.height = GetMinSizing(NWST_STEP, max(d.height, icon_size.height)); + d.height = max(d.height, icon_size.height); resize->height = d.height; d.height *= 5; d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index b1cd7ce2be..d335312217 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -318,7 +318,7 @@ typedef SmallVector SubtypeList; ///< List of refit subtypes as */ static void DrawVehicleRefitWindow(const SubtypeList list[NUM_CARGO], const int sel[2], uint pos, uint rows, uint delta, const Rect &r) { - uint y = r.top + WD_MATRIX_TOP; + uint y = Center(r.top, delta); uint current = 0; bool rtl = _current_text_dir == TD_RTL; @@ -2632,7 +2632,7 @@ public: int image = ((v->vehstatus & VS_STOPPED) != 0) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING; int lowered = this->IsWidgetLowered(WID_VV_START_STOP) ? 1 : 0; DrawSprite(image, PAL_NONE, image_left + lowered, r.top + WD_IMGBTN_TOP + lowered); - DrawString(text_left + lowered, text_right + lowered, r.top + WD_FRAMERECT_TOP + lowered, str, TC_FROMSTRING, SA_HOR_CENTER); + DrawString(text_left + lowered, text_right + lowered, Center(r.top + lowered, r.bottom - r.top), str, TC_FROMSTRING, SA_HOR_CENTER); } virtual void OnClick(Point pt, int widget, int click_count) diff --git a/src/vehicle_gui.cpp.orig b/src/vehicle_gui.cpp.orig index 79e9e9216b..b1cd7ce2be 100644 --- a/src/vehicle_gui.cpp.orig +++ b/src/vehicle_gui.cpp.orig @@ -318,7 +318,7 @@ typedef SmallVector SubtypeList; ///< List of refit subtypes as */ static void DrawVehicleRefitWindow(const SubtypeList list[NUM_CARGO], const int sel[2], uint pos, uint rows, uint delta, const Rect &r) { - uint y = Center(r.top, delta); + uint y = r.top + WD_MATRIX_TOP; uint current = 0; bool rtl = _current_text_dir == TD_RTL; @@ -648,12 +648,12 @@ struct RefitWindow : public Window { { switch (widget) { case WID_VR_MATRIX: - resize->height = GetMinSizing(NWST_STEP, WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM); + resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM; size->height = resize->height * 8; break; case WID_VR_VEHICLE_PANEL_DISPLAY: - size->height = max(GetMinSizing(NWST_STEP), GetVehicleHeight(Vehicle::Get(this->window_number)->type)); + size->height = GetVehicleHeight(Vehicle::Get(this->window_number)->type); break; case WID_VR_INFO: @@ -713,12 +713,11 @@ struct RefitWindow : public Window { case WID_VR_VEHICLE_PANEL_DISPLAY: { Vehicle *v = Vehicle::Get(this->window_number); DrawVehicleImage(v, this->sprite_left + WD_FRAMERECT_LEFT, this->sprite_right - WD_FRAMERECT_RIGHT, - r.top, r.bottom - r.top + 1, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != NULL ? this->hscroll->GetPosition() : 0); + r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != NULL ? this->hscroll->GetPosition() : 0); /* Highlight selected vehicles. */ if (this->order != INVALID_VEH_ORDER_ID) break; int x = 0; - int y_offset_frame = Center(0, r.bottom - r.top + 1, 14); switch (v->type) { case VEH_TRAIN: { VehicleSet vehicles_to_refit; @@ -751,7 +750,7 @@ struct RefitWindow : public Window { } if (left != right) { - DrawFrameRect(left, r.top + y_offset_frame, right, r.top + y_offset_frame + 13, COLOUR_WHITE, FR_BORDERONLY); + DrawFrameRect(left, r.top + WD_FRAMERECT_TOP, right, r.top + WD_FRAMERECT_TOP + 13, COLOUR_WHITE, FR_BORDERONLY); } left = INT32_MIN; @@ -1309,9 +1308,8 @@ static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, Veh * @param selection Selected vehicle to draw a frame around * @param skip Number of pixels to skip at the front (for scrolling) */ -void DrawVehicleImage(const Vehicle *v, int left, int right, int y, int height, VehicleID selection, EngineImageType image_type, int skip) +void DrawVehicleImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip) { - y = Center(y, height, GetVehicleHeight(v->type)); switch (v->type) { case VEH_TRAIN: DrawTrainImage(Train::From(v), left, right, y, selection, image_type, skip); break; case VEH_ROAD: DrawRoadVehImage(v, left, right, y, selection, image_type, skip); break; @@ -1330,7 +1328,7 @@ void DrawVehicleImage(const Vehicle *v, int left, int right, int y, int height, uint GetVehicleListHeight(VehicleType type, uint divisor) { /* Name + vehicle + profit */ - uint base = GetMinSizing(NWST_STEP, GetVehicleHeight(type) + 2 * FONT_HEIGHT_SMALL); + uint base = GetVehicleHeight(type) + 2 * FONT_HEIGHT_SMALL; /* Drawing of the 4 small orders + profit*/ if (type >= VEH_SHIP) base = max(base, 5U * FONT_HEIGHT_SMALL); @@ -1376,7 +1374,7 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int SetDParam(0, v->GetDisplayProfitThisYear()); SetDParam(1, v->GetDisplayProfitLastYear()); - DrawVehicleImage(v, image_left, image_right, y, line_height, selected_vehicle, EIT_IN_LIST, 0); + DrawVehicleImage(v, image_left, image_right, y + FONT_HEIGHT_SMALL - 1, selected_vehicle, EIT_IN_LIST, 0); DrawString(text_left, text_right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1, STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR); if (v->name != NULL) { @@ -2087,12 +2085,12 @@ struct VehicleDetailsWindow : Window { /* Articulated road vehicles use a complete line. */ if (v->type == VEH_ROAD && v->HasArticulatedPart()) { - DrawVehicleImage(v, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, 0); + DrawVehicleImage(v, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, 0); } else { uint sprite_left = rtl ? text_right : r.left; uint sprite_right = rtl ? r.right : text_left; - DrawVehicleImage(v, sprite_left + WD_FRAMERECT_LEFT, sprite_right - WD_FRAMERECT_RIGHT, r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, 0); + DrawVehicleImage(v, sprite_left + WD_FRAMERECT_LEFT, sprite_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, 0); } DrawVehicleDetails(v, text_left + WD_FRAMERECT_LEFT, text_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, 0, 0, this->tab); break; @@ -2634,7 +2632,7 @@ public: int image = ((v->vehstatus & VS_STOPPED) != 0) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING; int lowered = this->IsWidgetLowered(WID_VV_START_STOP) ? 1 : 0; DrawSprite(image, PAL_NONE, image_left + lowered, r.top + WD_IMGBTN_TOP + lowered); - DrawString(text_left + lowered, text_right + lowered, Center(r.top + lowered, r.bottom - r.top), str, TC_FROMSTRING, SA_HOR_CENTER); + DrawString(text_left + lowered, text_right + lowered, r.top + WD_FRAMERECT_TOP + lowered, str, TC_FROMSTRING, SA_HOR_CENTER); } virtual void OnClick(Point pt, int widget, int click_count) diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index fa5753d7d0..6603dd588a 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -38,7 +38,7 @@ uint DropDownListStringItem::Width() const void DropDownListStringItem::Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const { - DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, this->String(), sel ? TC_WHITE : TC_BLACK); + DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, Center(top, bottom - top), this->String(), sel ? TC_WHITE : TC_BLACK); } /** From a315c978f6168735321b5189b9102f90fe3f69ee Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 8 Jul 2013 22:49:02 +0200 Subject: [PATCH 018/187] Center group gui strings (and other minor changes). --- src/group_gui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 11502c7907..93349a3f5d 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -211,7 +211,7 @@ private: { /* Highlight the group if a vehicle is dragged over it */ if (g_id == this->group_over) { - GfxFillRect(left + WD_FRAMERECT_LEFT, y + WD_FRAMERECT_TOP, right - WD_FRAMERECT_RIGHT, y + this->tiny_step_height - WD_FRAMERECT_BOTTOM - WD_MATRIX_TOP, _colour_gradient[COLOUR_GREY][7]); + GfxFillRect(left + WD_FRAMERECT_LEFT, y + WD_FRAMERECT_TOP + WD_MATRIX_TOP, right - WD_FRAMERECT_RIGHT, y + this->tiny_step_height - WD_FRAMERECT_BOTTOM - WD_MATRIX_TOP, _colour_gradient[COLOUR_GREY][7]); } if (g_id == NEW_GROUP) return; @@ -499,15 +499,15 @@ public: { switch (widget) { case WID_GL_ALL_VEHICLES: - DrawGroupInfo(r.top + WD_FRAMERECT_TOP, r.left, r.right, ALL_GROUP); + DrawGroupInfo(r.top, r.left, r.right, ALL_GROUP); break; case WID_GL_DEFAULT_VEHICLES: - DrawGroupInfo(r.top + WD_FRAMERECT_TOP, r.left, r.right, DEFAULT_GROUP); + DrawGroupInfo(r.top, r.left, r.right, DEFAULT_GROUP); break; case WID_GL_LIST_GROUP: { - int y1 = r.top + WD_FRAMERECT_TOP; + int y1 = r.top; int max = min(this->group_sb->GetPosition() + this->group_sb->GetCapacity(), this->groups.Length()); for (int i = this->group_sb->GetPosition(); i < max; ++i) { const Group *g = this->groups[i]; From 1fe633b7b73e3af12a2e05e09234425a639d13c9 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Tue, 16 Jul 2013 21:50:42 +0200 Subject: [PATCH 019/187] Draw vehicles vertically aligned on vehicle list, vehicle info panel, etc. --- src/depot_gui.cpp | 25 ++++++++++++++----------- src/newgrf_debug_gui.cpp | 4 ++-- src/vehicle_gui.cpp | 11 ++++++----- src/vehicle_gui.h | 2 +- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index c71089b9dd..35d44dd54a 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -272,7 +272,7 @@ struct DepotWindow : Window { void DrawVehicleInDepot(const Vehicle *v, int left, int right, int y) const { bool free_wagon = false; - int sprite_y = y + (this->resize.step_height - GetVehicleHeight(v->type)) / 2; + int sprite_y = Center(y, this->resize.step_height, GetVehicleHeight(v->type)); bool rtl = _current_text_dir == TD_RTL; int image_left = rtl ? left + this->count_width : left + this->header_width; @@ -284,13 +284,13 @@ struct DepotWindow : Window { free_wagon = u->IsFreeWagon(); uint x_space = free_wagon ? TRAININFO_DEFAULT_VEHICLE_WIDTH : 0; - DrawTrainImage(u, image_left + (rtl ? 0 : x_space), image_right - (rtl ? x_space : 0), sprite_y - 1, + DrawTrainImage(u, image_left + (rtl ? 0 : x_space), image_right - (rtl ? x_space : 0), sprite_y, this->sel, EIT_IN_DEPOT, free_wagon ? 0 : this->hscroll->GetPosition(), this->vehicle_over); /* Length of consist in tiles with 1 fractional digit (rounded up) */ SetDParam(0, CeilDiv(u->gcache.cached_total_length * 10, TILE_SIZE)); SetDParam(1, 1); - DrawString(rtl ? left + WD_FRAMERECT_LEFT : right - this->count_width, rtl ? left + this->count_width : right - WD_FRAMERECT_RIGHT, y + (this->resize.step_height - FONT_HEIGHT_SMALL) / 2, STR_TINY_BLACK_DECIMAL, TC_FROMSTRING, SA_RIGHT); // Draw the counter + DrawString(rtl ? left + WD_FRAMERECT_LEFT : right - this->count_width, rtl ? left + this->count_width : right - WD_FRAMERECT_RIGHT, Center(y, this->resize.step_height, FONT_HEIGHT_SMALL), STR_TINY_BLACK_DECIMAL, TC_FROMSTRING, SA_RIGHT); // Draw the counter break; } @@ -299,33 +299,35 @@ struct DepotWindow : Window { case VEH_AIRCRAFT: { const Sprite *spr = GetSprite(v->GetImage(DIR_W, EIT_IN_DEPOT), ST_NORMAL); DrawAircraftImage(v, image_left, image_right, - y + max(UnScaleByZoom(spr->height, ZOOM_LVL_GUI) + UnScaleByZoom(spr->y_offs, ZOOM_LVL_GUI) - 14, 0), // tall sprites needs an y offset + Center(y, this->resize.step_height, UnScaleByZoom(spr->height, ZOOM_LVL_GUI) + UnScaleByZoom(spr->y_offs, ZOOM_LVL_GUI)), // tall sprites needs an y offset this->sel, EIT_IN_DEPOT); break; } default: NOT_REACHED(); } - uint diff_x, diff_y; + uint diff_x, y_sprite, y_num; if (v->IsGroundVehicle()) { /* Arrange unitnumber and flag horizontally */ diff_x = this->flag_width + WD_FRAMERECT_LEFT; - diff_y = (this->resize.step_height - this->flag_height) / 2 - 2; + y_sprite = Center(y, this->resize.step_height, this->flag_height); + y_num = Center(y, this->resize.step_height); } else { /* Arrange unitnumber and flag vertically */ diff_x = WD_FRAMERECT_LEFT; - diff_y = FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + y_num = Center(y, this->resize.step_height, FONT_HEIGHT_NORMAL + this->flag_height + 2); + y_sprite = y_num + FONT_HEIGHT_NORMAL; } int text_left = rtl ? right - this->header_width - 1 : left + diff_x; int text_right = rtl ? right - diff_x : left + this->header_width - 1; if (free_wagon) { - DrawString(text_left, text_right, y + 2, STR_DEPOT_NO_ENGINE); + DrawString(text_left, text_right, Center(y, this->resize.step_height), STR_DEPOT_NO_ENGINE); } else { - DrawSprite((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, rtl ? right - this->flag_width : left + WD_FRAMERECT_LEFT, y + diff_y); + DrawSprite((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, rtl ? right - this->flag_width : left + WD_FRAMERECT_LEFT, y_sprite); SetDParam(0, v->unitnumber); - DrawString(text_left, text_right, y + 2, (uint16)(v->max_age - DAYS_IN_LEAP_YEAR) >= v->age ? STR_BLACK_COMMA : STR_RED_COMMA); + DrawString(text_left, text_right, y_num, (uint16)(v->max_age - DAYS_IN_LEAP_YEAR) >= v->age ? STR_BLACK_COMMA : STR_RED_COMMA); } } @@ -342,7 +344,7 @@ struct DepotWindow : Window { uint16 num = this->vscroll->GetPosition() * this->num_columns; int maxval = min(this->vehicle_list.Length(), num + (rows_in_display * this->num_columns)); int y; - for (y = r.top + 1; num < maxval; y += this->resize.step_height) { // Draw the rows + for (y = r.top; num < maxval; y += this->resize.step_height) { // Draw the rows for (byte i = 0; i < this->num_columns && num < maxval; i++, num++) { /* Draw all vehicles in the current row */ const Vehicle *v = this->vehicle_list[num]; @@ -623,6 +625,7 @@ struct DepotWindow : Window { int base_width = this->count_width + this->header_width; resize->height = max(GetVehicleImageCellSize(this->type, EIT_IN_DEPOT).height, min_height); + resize->height = GetMinSizing(NWST_STEP, resize->height); if (this->type == VEH_TRAIN) { resize->width = 1; size->width = base_width + 2 * 29; // about 2 parts diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index cead62750e..be4e992130 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -434,8 +434,8 @@ struct NewGRFInspectWindow : Window { 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); + int y = Center(r.top, r.bottom - r.top, h); + DrawVehicleImage(v->First(), r.left + WD_BEVEL_LEFT, r.right - WD_BEVEL_RIGHT, y + 1, h, 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) { diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index d335312217..3a077e4e50 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -713,7 +713,7 @@ struct RefitWindow : public Window { case WID_VR_VEHICLE_PANEL_DISPLAY: { Vehicle *v = Vehicle::Get(this->window_number); DrawVehicleImage(v, this->sprite_left + WD_FRAMERECT_LEFT, this->sprite_right - WD_FRAMERECT_RIGHT, - r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != NULL ? this->hscroll->GetPosition() : 0); + r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != NULL ? this->hscroll->GetPosition() : 0); /* Highlight selected vehicles. */ if (this->order != INVALID_VEH_ORDER_ID) break; @@ -1308,8 +1308,9 @@ static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, Veh * @param selection Selected vehicle to draw a frame around * @param skip Number of pixels to skip at the front (for scrolling) */ -void DrawVehicleImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip) +void DrawVehicleImage(const Vehicle *v, int left, int right, int y, int height, VehicleID selection, EngineImageType image_type, int skip) { + y = Center(y, height, GetVehicleHeight(v->type)); switch (v->type) { case VEH_TRAIN: DrawTrainImage(Train::From(v), left, right, y, selection, image_type, skip); break; case VEH_ROAD: DrawRoadVehImage(v, left, right, y, selection, image_type, skip); break; @@ -1374,7 +1375,7 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int SetDParam(0, v->GetDisplayProfitThisYear()); SetDParam(1, v->GetDisplayProfitLastYear()); - DrawVehicleImage(v, image_left, image_right, y + FONT_HEIGHT_SMALL - 1, selected_vehicle, EIT_IN_LIST, 0); + DrawVehicleImage(v, image_left, image_right, y, line_height, selected_vehicle, EIT_IN_LIST, 0); DrawString(text_left, text_right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1, STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR); if (v->name != NULL) { @@ -2085,12 +2086,12 @@ struct VehicleDetailsWindow : Window { /* Articulated road vehicles use a complete line. */ if (v->type == VEH_ROAD && v->HasArticulatedPart()) { - DrawVehicleImage(v, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, 0); + DrawVehicleImage(v, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, 0); } else { uint sprite_left = rtl ? text_right : r.left; uint sprite_right = rtl ? r.right : text_left; - DrawVehicleImage(v, sprite_left + WD_FRAMERECT_LEFT, sprite_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, 0); + DrawVehicleImage(v, sprite_left + WD_FRAMERECT_LEFT, sprite_right - WD_FRAMERECT_RIGHT, r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, 0); } DrawVehicleDetails(v, text_left + WD_FRAMERECT_LEFT, text_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, 0, 0, this->tab); break; diff --git a/src/vehicle_gui.h b/src/vehicle_gui.h index 83e098dcd9..935e6efe8d 100644 --- a/src/vehicle_gui.h +++ b/src/vehicle_gui.h @@ -99,6 +99,6 @@ void StartStopVehicle(const Vehicle *v, bool texteffect); Vehicle *CheckClickOnVehicle(const struct ViewPort *vp, int x, int y); -void DrawVehicleImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip); +void DrawVehicleImage(const Vehicle *v, int left, int right, int y, int height, VehicleID selection, EngineImageType image_type, int skip); #endif /* VEHICLE_GUI_H */ From 020e62fbd64fcadae74aba234f1c94f741c74417 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Wed, 24 Jul 2013 22:20:06 +0000 Subject: [PATCH 020/187] Center images on buttons. --- src/widget.cpp | 72 ++++++++++---------------------------------------- 1 file changed, 14 insertions(+), 58 deletions(-) diff --git a/src/widget.cpp b/src/widget.cpp index 31c5ea8532..534909066a 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -222,7 +222,8 @@ static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colo DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); if ((type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++; // Show different image when clicked for #WWT_IMGBTN_2. - DrawSprite(img, PAL_NONE, r.left + WD_IMGBTN_LEFT + clicked, r.top + WD_IMGBTN_TOP + clicked); + Dimension d2 = GetSpriteSize(img); + DrawSprite(img, PAL_NONE, Center(r.left + clicked, r.right - r.left, d2.width), Center(r.top + clicked, r.bottom - r.top, d2.height)); } /** @@ -452,54 +453,6 @@ static inline void DrawFrame(const Rect &r, Colours colour, StringID str) GfxFillRect(r.left, r.bottom, r.right, r.bottom, c2); } -/** - * Draw a shade box. - * @param r Rectangle of the box. - * @param colour Colour of the shade box. - * @param clicked Box is lowered. - */ -static inline void DrawShadeBox(const Rect &r, Colours colour, bool clicked) -{ - DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawSprite((clicked) ? SPR_WINDOW_SHADE : SPR_WINDOW_UNSHADE, PAL_NONE, r.left + WD_SHADEBOX_LEFT + clicked, r.top + WD_SHADEBOX_TOP + clicked); -} - -/** - * Draw a sticky box. - * @param r Rectangle of the box. - * @param colour Colour of the sticky box. - * @param clicked Box is lowered. - */ -static inline void DrawStickyBox(const Rect &r, Colours colour, bool clicked) -{ - DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, PAL_NONE, r.left + WD_STICKYBOX_LEFT + clicked, r.top + WD_STICKYBOX_TOP + clicked); -} - -/** - * Draw a defsize box. - * @param r Rectangle of the box. - * @param colour Colour of the defsize box. - * @param clicked Box is lowered. - */ -static inline void DrawDefSizeBox(const Rect &r, Colours colour, bool clicked) -{ - DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawSprite(SPR_WINDOW_DEFSIZE, PAL_NONE, r.left + WD_DEFSIZEBOX_LEFT + clicked, r.top + WD_DEFSIZEBOX_TOP + clicked); -} - -/** - * Draw a NewGRF debug box. - * @param r Rectangle of the box. - * @param colour Colour of the debug box. - * @param clicked Box is lowered. - */ -static inline void DrawDebugBox(const Rect &r, Colours colour, bool clicked) -{ - DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawSprite(SPR_WINDOW_DEBUG, PAL_NONE, r.left + WD_DEBUGBOX_LEFT + clicked, r.top + WD_DEBUGBOX_TOP + clicked); -} - /** * Draw a resize box. * @param r Rectangle of the box. @@ -510,12 +463,13 @@ static inline void DrawDebugBox(const Rect &r, Colours colour, bool clicked) static inline void DrawResizeBox(const Rect &r, Colours colour, bool at_left, bool clicked) { DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); + Dimension d = GetSpriteSize(at_left ? SPR_WINDOW_RESIZE_LEFT : SPR_WINDOW_RESIZE_RIGHT); if (at_left) { - DrawSprite(SPR_WINDOW_RESIZE_LEFT, PAL_NONE, r.left + WD_RESIZEBOX_RIGHT + clicked, - r.bottom - WD_RESIZEBOX_BOTTOM - GetSpriteSize(SPR_WINDOW_RESIZE_LEFT).height + clicked); + DrawSprite(SPR_WINDOW_RESIZE_LEFT, PAL_NONE, r.left + WD_RESIZEBOX_LEFT + clicked, + r.bottom - WD_RESIZEBOX_BOTTOM - d.height + clicked); } else { - DrawSprite(SPR_WINDOW_RESIZE_RIGHT, PAL_NONE, r.left + WD_RESIZEBOX_LEFT + clicked, - r.bottom - WD_RESIZEBOX_BOTTOM - GetSpriteSize(SPR_WINDOW_RESIZE_RIGHT).height + clicked); + DrawSprite(SPR_WINDOW_RESIZE_RIGHT, PAL_NONE, r.right - WD_RESIZEBOX_RIGHT - d.width + clicked, + r.bottom - WD_RESIZEBOX_BOTTOM - d.height + clicked); } } @@ -2451,21 +2405,23 @@ void NWidgetLeaf::Draw(const Window *w) case WWT_SHADEBOX: assert(this->widget_data == 0); - DrawShadeBox(r, this->colour, w->IsShaded()); + DrawImageButtons(r, WWT_SHADEBOX, this->colour, w->IsShaded(), w->IsShaded() ? SPR_WINDOW_SHADE : SPR_WINDOW_UNSHADE); break; case WWT_DEBUGBOX: - DrawDebugBox(r, this->colour, clicked); + DrawImageButtons(r, WWT_DEBUGBOX, this->colour, clicked, SPR_WINDOW_DEBUG); break; - case WWT_STICKYBOX: + case WWT_STICKYBOX: { assert(this->widget_data == 0); - DrawStickyBox(r, this->colour, !!(w->flags & WF_STICKY)); + bool clicked = !!(w->flags & WF_STICKY); + DrawImageButtons(r, WWT_STICKYBOX, this->colour, clicked, clicked ? SPR_PIN_DOWN : SPR_PIN_UP); break; + } case WWT_DEFSIZEBOX: assert(this->widget_data == 0); - DrawDefSizeBox(r, this->colour, clicked); + DrawImageButtons(r, WWT_DEFSIZEBOX, this->colour, clicked, SPR_WINDOW_DEFSIZE); break; case WWT_RESIZEBOX: From 034e8677adb327a8f98d6ae0a3214a65a5c1dc24 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Fri, 2 Aug 2013 19:22:04 +0000 Subject: [PATCH 021/187] Center company icon on league table. --- src/graph_gui.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 10779502da..99cff0eaaf 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -1128,6 +1128,7 @@ private: uint ordinal_width; ///< The width of the ordinal number uint text_width; ///< The width of the actual text uint icon_width; ///< The width of the company icon + uint icon_y_offset; ///< The vertical offset for drawing the company icon. int line_height; ///< Height of the text lines /** @@ -1174,8 +1175,7 @@ public: { if (widget != WID_CL_BACKGROUND) return; - int icon_y_offset = 1 + (FONT_HEIGHT_NORMAL - this->line_height) / 2; - uint y = r.top + WD_FRAMERECT_TOP - icon_y_offset; + uint y = r.top + WD_FRAMERECT_TOP; bool rtl = _current_text_dir == TD_RTL; uint ordinal_left = rtl ? r.right - WD_FRAMERECT_LEFT - this->ordinal_width : r.left + WD_FRAMERECT_LEFT; @@ -1188,7 +1188,7 @@ public: const Company *c = this->companies[i]; DrawString(ordinal_left, ordinal_right, y, i + STR_ORDINAL_NUMBER_1ST, i == 0 ? TC_WHITE : TC_YELLOW); - DrawCompanyIcon(c->index, icon_left, y + icon_y_offset); + DrawCompanyIcon(c->index, icon_left, y + this->icon_y_offset); SetDParam(0, c->index); SetDParam(1, c->index); @@ -1221,6 +1221,7 @@ public: Dimension d = GetSpriteSize(SPR_COMPANY_ICON); this->icon_width = d.width + 2; this->line_height = max(d.height + 2, FONT_HEIGHT_NORMAL); + this->icon_y_offset = Center(1, this->line_height, d.height); const Company *c; FOR_ALL_COMPANIES(c) { From 0442649289afe19a76262ff01818e5db3095fb62 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 29 Jun 2013 15:12:06 +0200 Subject: [PATCH 022/187] Add min sizing. --- src/ai/ai_gui.cpp | 8 +- src/airport_gui.cpp | 9 ++- src/build_vehicle_gui.cpp | 10 ++- src/build_vehicle_gui.cpp.orig | 13 +--- src/company_gui.cpp | 3 +- src/fios_gui.cpp | 2 +- src/genworld_gui.cpp | 3 +- src/graph_gui.cpp | 1 + src/group_gui.cpp | 15 ++-- src/industry_gui.cpp | 4 +- src/industry_gui.cpp.orig | 2 +- src/linkgraph/linkgraph_gui.cpp | 1 + src/network/network_content_gui.cpp | 2 +- src/network/network_gui.cpp | 18 ++--- src/newgrf_gui.cpp | 10 ++- src/settings_gui.cpp | 2 +- src/settings_gui.cpp.orig | 4 +- src/settings_type.h | 2 + src/signs_gui.cpp | 1 + src/station_gui.cpp | 15 ++-- src/station_gui.cpp.orig | 2 +- src/table/misc_settings.ini | 19 +++++ src/toolbar_gui.cpp | 2 +- src/toolbar_gui.cpp.orig | 6 +- src/town_gui.cpp | 21 +++--- src/town_gui.cpp.orig | 2 +- src/vehicle_gui.cpp | 4 +- src/vehicle_gui.cpp.orig | 15 ++-- src/widget.cpp | 101 +++++++++++++++++++++++-- src/widget.cpp.orig | 112 ++-------------------------- src/widget_type.h | 41 ++++++++-- src/widgets/dropdown_type.h | 3 +- 32 files changed, 252 insertions(+), 201 deletions(-) diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index 8bcc41455d..62fed7debf 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -107,7 +107,7 @@ struct AIListWindow : public Window { virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_AIL_LIST) { - this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + this->line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); resize->width = 1; resize->height = this->line_height; @@ -345,7 +345,7 @@ struct AISettingsWindow : public Window { virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_AIS_BACKGROUND) { - this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + this->line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); resize->width = 1; resize->height = this->line_height; @@ -761,7 +761,7 @@ struct AIConfigWindow : public Window { break; case WID_AIC_LIST: - this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + this->line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); size->height = 8 * this->line_height; break; } @@ -1072,7 +1072,7 @@ struct AIDebugWindow : public Window { virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_AID_LOG_PANEL) { - resize->height = FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL); size->height = 14 * resize->height + this->top_offset + this->bottom_offset; } } diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 0ba237c024..623a047d59 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -272,6 +272,7 @@ public: d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); + size->height = GetMinSizing(NWST_STEP, size->height); break; } @@ -283,7 +284,7 @@ public: size->width = max(size->width, GetStringBoundingBox(as->name).width); } - this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + this->line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); size->height = 5 * this->line_height; break; } @@ -524,7 +525,7 @@ static const NWidgetPart _nested_build_airport_widgets[] = { NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 0), SetPIP(2, 0, 2), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL, STR_NULL), SetFill(1, 0), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetSizingType(NWST_STEP), SetDataTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_AP_CLASS_DROPDOWN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_STATION_BUILD_AIRPORT_TOOLTIP), NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_AIRPORT_SPRITE), SetFill(1, 0), NWidget(NWID_HORIZONTAL), @@ -532,9 +533,9 @@ static const NWidgetPart _nested_build_airport_widgets[] = { NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AP_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_DECREASE), SetMinimalSize(12, 0), SetDataTip(AWV_DECREASE, STR_NULL), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_DECREASE), SetSizingType(NWST_STEP), SetMinimalSize(12, 0), SetDataTip(AWV_DECREASE, STR_NULL), NWidget(WWT_LABEL, COLOUR_GREY, WID_AP_LAYOUT_NUM), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NULL), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_INCREASE), SetMinimalSize(12, 0), SetDataTip(AWV_INCREASE, STR_NULL), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_INCREASE), SetSizingType(NWST_STEP), SetMinimalSize(12, 0), SetDataTip(AWV_INCREASE, STR_NULL), EndContainer(), NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_EXTRA_TEXT), SetFill(1, 0), SetMinimalSize(150, 0), EndContainer(), diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 410b2dbb3b..1e6468f359 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -44,7 +44,8 @@ */ uint GetEngineListHeight(VehicleType type) { - return max(FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM, GetVehicleImageCellSize(type, EIT_PURCHASE).height); + uint size = max(FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM, GetVehicleImageCellSize(type, EIT_PURCHASE).height); + return GetMinSizing(NWST_STEP, size); } static const NWidgetPart _nested_build_vehicle_widgets[] = { @@ -58,12 +59,12 @@ static const NWidgetPart _nested_build_vehicle_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASSENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASSENDING_DESCENDING), SetSizingType(NWST_STEP), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), NWidget(NWID_SPACER), SetFill(1, 1), EndContainer(), NWidget(NWID_VERTICAL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN), SetSizingType(NWST_STEP), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetSizingType(NWST_STEP), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), EndContainer(), EndContainer(), EndContainer(), @@ -1323,6 +1324,7 @@ struct BuildVehicleWindow : Window { Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. d.height += padding.height; + d.height = GetMinSizing(NWST_STEP, d.height); *size = maxdim(*size, d); break; } diff --git a/src/build_vehicle_gui.cpp.orig b/src/build_vehicle_gui.cpp.orig index 0719f29ec6..410b2dbb3b 100644 --- a/src/build_vehicle_gui.cpp.orig +++ b/src/build_vehicle_gui.cpp.orig @@ -886,7 +886,6 @@ void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList * int sprite_width = sprite_left + sprite_right; int sprite_x = rtl ? r - sprite_right - 1 : l + sprite_left + 1; - int sprite_y_offset = sprite_y_offsets[type] + step_size / 2; Dimension replace_icon = {0, 0}; int count_width = 0; @@ -902,22 +901,18 @@ void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList * int count_left = l; int count_right = rtl ? text_left : r - WD_FRAMERECT_RIGHT - replace_icon.width - 8; - int normal_text_y_offset = (step_size - FONT_HEIGHT_NORMAL) / 2; - int small_text_y_offset = step_size - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1; - int replace_icon_y_offset = (step_size - replace_icon.height) / 2 - 1; - for (; min < max; min++, y += step_size) { const EngineID engine = (*eng_list)[min]; /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */ const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine); SetDParam(0, engine); - DrawString(text_left, text_right, y + normal_text_y_offset, STR_ENGINE_NAME, engine == selected_id ? TC_WHITE : TC_BLACK); - DrawVehicleEngine(l, r, sprite_x, y + sprite_y_offset, engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); + DrawString(text_left, text_right, Center(y, step_size), STR_ENGINE_NAME, text_colour); + DrawVehicleEngine(l, r, sprite_x, Center(y, step_size, sprite_y_offsets[type]), engine, palette_crash ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); if (show_count) { SetDParam(0, num_engines); - DrawString(count_left, count_right, y + small_text_y_offset, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); - if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, replace_icon_left, y + replace_icon_y_offset); + DrawString(count_left, count_right, Center(y, step_size, FONT_HEIGHT_SMALL), STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); + if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, replace_icon_left, Center(y, step_size, replace_icon.height)); } } } diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 1cf38fc521..060c796d00 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -35,6 +35,7 @@ #include "road_func.h" #include "water.h" #include "station_func.h" +#include "widget_type.h" #include "widgets/company_widget.h" @@ -526,7 +527,7 @@ public: uint Height(uint width) const { - return max(FONT_HEIGHT_NORMAL, 14); + return GetMinSizing(NWST_STEP, max(FONT_HEIGHT_NORMAL, 14)); } bool Selectable() const diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 9551bb843e..287d98d4b4 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -473,7 +473,7 @@ public: break; case WID_SL_DRIVES_DIRECTORIES_LIST: - resize->height = FONT_HEIGHT_NORMAL; + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); size->height = resize->height * 10 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; break; case WID_SL_SORT_BYNAME: diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index f1b561ef18..d43899c4ab 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -451,6 +451,7 @@ struct GenerateLandscapeWindow : public Window { case WID_GL_MAPSIZE_Y_PULLDOWN: SetDParamMaxValue(0, MAX_MAP_SIZE); *size = GetStringBoundingBox(STR_JUST_INT); + size->width = size->width + GetMinSizing(NWST_BUTTON); break; case WID_GL_SNOW_LEVEL_TEXT: @@ -508,7 +509,7 @@ struct GenerateLandscapeWindow : public Window { } } size->width += padding.width; - size->height = FONT_HEIGHT_NORMAL + WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM; + size->height = GetMinSizing(NWST_BUTTON, FONT_HEIGHT_NORMAL + WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM); } virtual void DrawWidget(const Rect &r, int widget) const diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 99cff0eaaf..4e8e3aeeb6 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -114,6 +114,7 @@ static NWidgetBase *MakeNWidgetCompanyLines(int *biggest_index) for (int widnum = WID_GL_FIRST_COMPANY; widnum <= WID_GL_LAST_COMPANY; widnum++) { NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum); + panel->sizing_type = NWST_STEP; panel->SetMinimalSize(246, line_height); panel->SetFill(1, 0); panel->SetDataTip(0x0, STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP); diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 93349a3f5d..6889d6eb16 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -66,7 +66,7 @@ static const NWidgetPart _nested_group_widgets[] = { /* right part */ NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_SORT_BY_ORDER), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_SORT_BY_ORDER), SetSizingType(NWST_STEP), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_SORT_BY_DROPDOWN), SetMinimalSize(167, 12), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetResize(1, 0), EndContainer(), EndContainer(), @@ -74,7 +74,7 @@ static const NWidgetPart _nested_group_widgets[] = { NWidget(WWT_MATRIX, COLOUR_GREY, WID_GL_LIST_VEHICLE), SetMinimalSize(248, 0), SetMatrixDataTip(1, 0, STR_NULL), SetResize(1, 1), SetFill(1, 0), SetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_GL_LIST_VEHICLE_SCROLLBAR), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(1, 0), SetFill(1, 1), SetResize(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_AVAILABLE_VEHICLES), SetMinimalSize(106, 12), SetFill(0, 1), SetDataTip(STR_BLACK_STRING, STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP), @@ -167,7 +167,7 @@ private: this->column_size[VGC_NAME] = maxdim(GetStringBoundingBox(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype), GetStringBoundingBox(STR_GROUP_ALL_TRAINS + this->vli.vtype)); /* We consider the max average length of characters to be the one of "a" */ this->column_size[VGC_NAME].width = max(GetCharacterWidth(FS_NORMAL, 97) * (MAX_LENGTH_GROUP_NAME_CHARS - 4), this->column_size[VGC_NAME].width); - this->tiny_step_height = this->column_size[VGC_NAME].height; + this->tiny_step_height = max(11U, this->column_size[VGC_NAME].height); this->column_size[VGC_PROTECT] = GetSpriteSize(SPR_GROUP_REPLACE_PROTECT); this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_PROTECT].height); @@ -189,6 +189,7 @@ private: this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_NUMBER].height); this->tiny_step_height += WD_MATRIX_TOP; + this->tiny_step_height = GetMinSizing(NWST_STEP, this->tiny_step_height); return WD_FRAMERECT_LEFT + 8 + this->column_size[VGC_NAME].width + 2 + @@ -343,14 +344,8 @@ public: /* Minimum height is the height of the list widget minus all and default vehicles... */ size->height = 4 * GetVehicleListHeight(this->vli.vtype, this->tiny_step_height) - 2 * this->tiny_step_height; - /* ... minus the buttons at the bottom ... */ - uint max_icon_height = GetSpriteSize(this->GetWidget(WID_GL_CREATE_GROUP)->widget_data).height; - max_icon_height = max(max_icon_height, GetSpriteSize(this->GetWidget(WID_GL_RENAME_GROUP)->widget_data).height); - max_icon_height = max(max_icon_height, GetSpriteSize(this->GetWidget(WID_GL_DELETE_GROUP)->widget_data).height); - max_icon_height = max(max_icon_height, GetSpriteSize(this->GetWidget(WID_GL_REPLACE_PROTECTION)->widget_data).height); - /* Get a multiple of tiny_step_height of that amount */ - size->height = Ceil(size->height - max_icon_height, tiny_step_height); + size->height = Ceil(size->height, tiny_step_height); break; } diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 1dabde2646..ca39e8f1cb 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -296,7 +296,7 @@ public: if (this->index[i] == INVALID_INDUSTRYTYPE) continue; d = maxdim(d, GetStringBoundingBox(GetIndustrySpec(this->index[i])->name)); } - resize->height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); d.width += MATRIX_TEXT_OFFSET + padding.width; d.height = 5 * resize->height; *size = maxdim(*size, d); @@ -1303,7 +1303,7 @@ public: for (uint i = 0; i < this->industries.Length(); i++) { d = maxdim(d, GetStringBoundingBox(this->GetIndustryString(this->industries[i]))); } - resize->height = d.height; + resize->height = d.height = GetMinSizing(NWST_STEP, d.height); d.height *= 5; d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; diff --git a/src/industry_gui.cpp.orig b/src/industry_gui.cpp.orig index cc305509f2..1dabde2646 100644 --- a/src/industry_gui.cpp.orig +++ b/src/industry_gui.cpp.orig @@ -1260,7 +1260,7 @@ public: case WID_ID_INDUSTRY_LIST: { int n = 0; - int y = r.top + WD_FRAMERECT_TOP; + int y = Center(r.top, this->resize.step_height); if (this->industries.Length() == 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_DIRECTORY_NONE); break; diff --git a/src/linkgraph/linkgraph_gui.cpp b/src/linkgraph/linkgraph_gui.cpp index ae4cdee1a5..9889ad87ae 100644 --- a/src/linkgraph/linkgraph_gui.cpp +++ b/src/linkgraph/linkgraph_gui.cpp @@ -344,6 +344,7 @@ NWidgetBase *MakeCargoesLegendLinkGraphGUI(int *biggest_index) row = new NWidgetHorizontal(NC_EQUALSIZE); } NWidgetBackground * wid = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, i + WID_LGL_CARGO_FIRST); + wid->sizing_type = NWST_STEP; wid->SetMinimalSize(25, FONT_HEIGHT_SMALL); wid->SetFill(1, 1); wid->SetResize(0, 0); diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index b0d7cbbc18..6988be2055 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -524,7 +524,7 @@ public: } case WID_NCL_MATRIX: - resize->height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); size->height = 10 * resize->height; break; } diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 615710465d..18135dfedf 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -499,12 +499,12 @@ public: break; case WID_NG_MATRIX: - resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM; + resize->height = GetMinSizing(NWST_STEP, WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM); size->height = 10 * resize->height; break; case WID_NG_LASTJOINED: - size->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM; + size->height = GetMinSizing(NWST_STEP, WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM); break; case WID_NG_LASTJOINED_SPACER: @@ -931,7 +931,7 @@ static const NWidgetPart _nested_network_game_widgets[] = { /* LEFT SIDE */ NWidget(NWID_VERTICAL), SetPIP(0, 7, 0), NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0), - NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CONNECTION), SetDataTip(STR_NETWORK_SERVER_LIST_ADVERTISED, STR_NULL), + NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CONNECTION), SetSizingType(NWST_STEP), SetDataTip(STR_NETWORK_SERVER_LIST_ADVERTISED, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NG_CONN_BTN), SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP), NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0), @@ -1080,8 +1080,8 @@ struct NetworkStartServerWindow : public Window { switch (widget) { case WID_NSS_CONNTYPE_BTN: *size = maxdim(GetStringBoundingBox(_connection_types_dropdown[0]), GetStringBoundingBox(_connection_types_dropdown[1])); - size->width += padding.width; - size->height += padding.height; + size->width = GetMinSizing(NWST_BUTTON, size->width + padding.width); + size->height = GetMinSizing(NWST_BUTTON, size->height + padding.height); break; } } @@ -1264,15 +1264,15 @@ static const NWidgetPart _nested_network_start_server_window_widgets[] = { NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10), NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_ADVERTISED, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP), + NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetSizingType(NWST_BUTTON), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP), + NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_BTN), SetSizingType(NWST_BUTTON), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), NWidget(NWID_SPACER), SetFill(1, 1), - NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_SETPWD), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_SETPWD), SetSizingType(NWST_BUTTON), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP), EndContainer(), EndContainer(), @@ -1375,7 +1375,7 @@ struct NetworkLobbyWindow : public Window { break; case WID_NL_MATRIX: - resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM; + resize->height = GetMinSizing(NWST_STEP, WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM); size->height = 10 * resize->height; break; diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 47cca029a9..aedb4fddd3 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -681,14 +681,14 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WID_NS_FILE_LIST: { Dimension d = maxdim(GetSpriteSize(SPR_SQUARE), GetSpriteSize(SPR_WARNING_SIGN)); - resize->height = max(d.height + 2U, FONT_HEIGHT_NORMAL + 2U); - size->height = max(size->height, WD_FRAMERECT_TOP + 6 * resize->height + WD_FRAMERECT_BOTTOM); + resize->height = GetMinSizing(NWST_STEP, max(d.height + 2U, FONT_HEIGHT_NORMAL + 2U)); + size->height = max(size->height, WD_FRAMERECT_TOP + 4 * resize->height + WD_FRAMERECT_BOTTOM); break; } case WID_NS_AVAIL_LIST: - resize->height = max(12, FONT_HEIGHT_NORMAL + 2); - size->height = max(size->height, WD_FRAMERECT_TOP + 8 * resize->height + WD_FRAMERECT_BOTTOM); + resize->height = GetMinSizing(NWST_STEP, max(12, FONT_HEIGHT_NORMAL + 2)); + size->height = max(size->height, WD_FRAMERECT_TOP + 4 * resize->height + WD_FRAMERECT_BOTTOM); break; case WID_NS_NEWGRF_INFO_TITLE: { @@ -711,6 +711,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } } d.width += padding.width; + d.height = GetMinSizing(NWST_BUTTON, d.height); *size = maxdim(d, *size); break; } @@ -721,6 +722,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { *size = maxdim(d, GetStringBoundingBox(STR_INTRO_ONLINE_CONTENT)); size->width += padding.width; size->height += padding.height; + size->height = GetMinSizing(NWST_BUTTON, size->height); break; } } diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index c01d8391b8..80f26b5282 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1797,7 +1797,7 @@ struct GameSettingsWindow : Window { { switch (widget) { case WID_GS_OPTIONSPANEL: - resize->height = SETTING_HEIGHT = max(11, FONT_HEIGHT_NORMAL + 1); + resize->height = SETTING_HEIGHT = GetMinSizing(NWST_STEP, max(11, FONT_HEIGHT_NORMAL + 1)); resize->width = 1; size->height = 5 * resize->height + SETTINGTREE_TOP_OFFSET + SETTINGTREE_BOTTOM_OFFSET; diff --git a/src/settings_gui.cpp.orig b/src/settings_gui.cpp.orig index 5775e73732..c01d8391b8 100644 --- a/src/settings_gui.cpp.orig +++ b/src/settings_gui.cpp.orig @@ -1151,7 +1151,7 @@ uint SettingEntry::Draw(GameSettings *settings_ptr, int left, int right, int bas case SEF_SUBTREE_KIND: if (cur_row >= first_row) { DrawSprite((this->d.sub.folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED), PAL_NONE, rtl ? x - 8 : x, y + (SETTING_HEIGHT - 11) / 2); - DrawString(rtl ? left : x + 12, rtl ? x - 12 : right, y, this->d.sub.title); + DrawString(rtl ? left : x + 12, rtl ? x - 12 : right, Center(y, SETTING_HEIGHT), this->d.sub.title); } cur_row++; if (!this->d.sub.folded) { @@ -1243,7 +1243,7 @@ void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, editable && value != (sdb->flags & SGF_0ISDISABLED ? 0 : sdb->min), editable && (uint32)value != sdb->max); } this->SetValueDParams(1, value); - DrawString(text_left, text_right, y, sdb->str, highlight ? TC_WHITE : TC_LIGHT_BLUE); + DrawString(text_left, text_right, Center(y, SETTING_HEIGHT), sdb->str, highlight ? TC_WHITE : TC_LIGHT_BLUE); } diff --git a/src/settings_type.h b/src/settings_type.h index 7731e40c9c..175ce651cf 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -77,6 +77,8 @@ struct GUISettings { bool lost_vehicle_warn; ///< if a vehicle can't find its destination, show a warning uint8 order_review_system; ///< perform order reviews on vehicles bool vehicle_income_warn; ///< if a vehicle isn't generating income, show a warning + uint min_button; ///< min size of most button widgets + uint min_step; ///< min size of scrollbar/dropdown elements bool show_finances; ///< show finances at end of year bool sg_new_nonstop; ///< ttdpatch compatible nonstop handling read from pre v93 savegames bool new_nonstop; ///< ttdpatch compatible nonstop handling diff --git a/src/signs_gui.cpp b/src/signs_gui.cpp index aeac02eb96..2ec36775cf 100644 --- a/src/signs_gui.cpp +++ b/src/signs_gui.cpp @@ -267,6 +267,7 @@ struct SignListWindow : Window, SignList { Dimension spr_dim = GetSpriteSize(SPR_COMPANY_ICON); this->text_offset = WD_FRAMETEXT_LEFT + spr_dim.width + 2; // 2 pixels space between icon and the sign text. resize->height = max(FONT_HEIGHT_NORMAL, spr_dim.height); + resize->height = GetMinSizing(NWST_STEP, resize->height); Dimension d = {this->text_offset + WD_FRAMETEXT_RIGHT, WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM}; *size = maxdim(*size, d); break; diff --git a/src/station_gui.cpp b/src/station_gui.cpp index 48a82f8d45..5df21155c1 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -400,7 +400,7 @@ public: } case WID_STL_LIST: - resize->height = FONT_HEIGHT_NORMAL; + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; break; @@ -451,7 +451,8 @@ public: case WID_STL_LIST: { int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.Length()); - int y = r.top + WD_FRAMERECT_TOP; + uint line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + int y = Center(r.top + WD_FRAMERECT_TOP, line_height); for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner const Station *st = this->stations[i]; assert(st->xy != INVALID_TILE); @@ -464,9 +465,9 @@ public: SetDParam(1, st->facilities); int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION); - StationsWndShowStationRating(st, r.left, r.right, x, FONT_HEIGHT_NORMAL + 2, y); + StationsWndShowStationRating(st, r.left, r.right, x, line_height + 2, y); - y += FONT_HEIGHT_NORMAL; + y += line_height; } if (this->vscroll->GetCount() == 0) { // company has no stations @@ -518,7 +519,7 @@ public: { switch (widget) { case WID_STL_LIST: { - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, FONT_HEIGHT_NORMAL); + uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, this->resize.step_height); if (id_v >= this->stations.Length()) return; // click out of list bound const Station *st = this->stations[id_v]; @@ -2292,8 +2293,8 @@ struct SelectStationWindow : Window { d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION)); } - resize->height = d.height; - d.height *= 5; + resize->height = GetMinSizing(NWST_STEP, d.height); + d.height = 5 * resize->height; d.width += WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = d; diff --git a/src/station_gui.cpp.orig b/src/station_gui.cpp.orig index b1bb1787df..48a82f8d45 100644 --- a/src/station_gui.cpp.orig +++ b/src/station_gui.cpp.orig @@ -2303,7 +2303,7 @@ struct SelectStationWindow : Window { { if (widget != WID_JS_PANEL) return; - uint y = r.top + WD_FRAMERECT_TOP; + uint y = Center(r.top, this->resize.step_height); if (this->vscroll->GetPosition() == 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); y += this->resize.step_height; diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini index 1a2b5ef6b8..0b02e69b8d 100644 --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -219,6 +219,25 @@ name = ""mono_aa"" var = _freetype.mono.aa def = false +[SDTG_VAR] +name = ""min_button_size"" +type = SLE_UINT +var = _settings_client.gui.min_button +def = 0 +min = 0 +max = 100 +cat = SC_EXPERT + +[SDTG_VAR] +name = ""min_step_size"" +type = SLE_UINT +var = _settings_client.gui.min_step +def = 0 +min = 0 +max = 100 +cat = SC_EXPERT + + [SDTG_VAR] name = ""sprite_cache_size_px"" type = SLE_UINT diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 57bc4d4124..c06fe88b31 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -133,7 +133,7 @@ public: uint Height(uint width) const { - return max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL); + return GetMinSizing(NWST_STEP, max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL)); } void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const diff --git a/src/toolbar_gui.cpp.orig b/src/toolbar_gui.cpp.orig index 9bac4f406d..57bc4d4124 100644 --- a/src/toolbar_gui.cpp.orig +++ b/src/toolbar_gui.cpp.orig @@ -133,7 +133,7 @@ public: uint Height(uint width) const { - return GetMinSizing(NWST_STEP, max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL)); + return max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL); } void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const @@ -958,7 +958,7 @@ static CallBackFunction MenuClickBuildAir(int index) static CallBackFunction ToolbarForestClick(Window *w) { - PopupMainToolbMenu(w, WID_TN_LANDSCAPE, STR_LANDSCAPING_MENU_LANDSCAPING, 1); + PopupMainToolbMenu(w, WID_TN_LANDSCAPE, STR_LANDSCAPING_MENU_LANDSCAPING, 3); return CBF_NONE; } @@ -972,6 +972,8 @@ static CallBackFunction MenuClickForest(int index) { switch (index) { case 0: ShowTerraformToolbar(); break; + case 1: ShowBuildTreesToolbar(); break; + case 2: return SelectSignTool(); } return CBF_NONE; } diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 052fe4119d..76ee227e29 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -47,12 +47,12 @@ static const NWidgetPart _nested_town_authority_widgets[] = { NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), SetFill(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_COMMAND_LIST), SetMinimalSize(305, 52), SetResize(1, 0), SetDataTip(0x0, STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), SetScrollbar(WID_TA_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_TA_SCROLLBAR), EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 1), SetFill(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TA_EXECUTE), SetMinimalSize(317, 12), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_LOCAL_AUTHORITY_DO_IT_BUTTON, STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), @@ -65,6 +65,7 @@ private: Town *town; ///< Town being displayed. int sel_index; ///< Currently selected town action, \c 0 to \c TACT_COUNT-1, \c -1 means no action selected. Scrollbar *vscroll; + uint actions_step; uint displayed_actions_on_previous_painting; ///< Actions that were available on the previous call to OnPaint() /** @@ -94,7 +95,8 @@ public: this->town = Town::Get(window_number); this->InitNested(window_number); this->vscroll = this->GetScrollbar(WID_TA_SCROLLBAR); - this->vscroll->SetCapacity((this->GetWidget(WID_TA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / FONT_HEIGHT_NORMAL); + this->actions_step = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + this->vscroll->SetCapacity((this->GetWidget(WID_TA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / this->actions_step); } virtual void OnPaint() @@ -197,12 +199,12 @@ public: case WID_TA_COMMAND_LIST: { int numact; uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); - int y = Center(r.top, this->resize.step_height); + int y = Center(r.top, this->actions_step); int pos = this->vscroll->GetPosition(); if (--pos < 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTIONS_TITLE); - y += this->resize.step_height; + y += this->actions_step; } for (int i = 0; buttons; i++, buttons >>= 1) { @@ -211,7 +213,7 @@ public: if ((buttons & 1) && --pos < 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i, this->sel_index == i ? TC_WHITE : TC_ORANGE); - y += this->resize.step_height; + y += this->actions_step; } } break; @@ -238,7 +240,8 @@ public: } case WID_TA_COMMAND_LIST: - size->height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; size->width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width; for (uint i = 0; i < TACT_COUNT; i++ ) { size->width = max(size->width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i).width); @@ -257,7 +260,7 @@ public: { switch (widget) { case WID_TA_COMMAND_LIST: { - int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, FONT_HEIGHT_NORMAL); + int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, this->actions_step); if (!IsInsideMM(y, 0, 5)) return; y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_company, this->town), y + this->vscroll->GetPosition() - 1); @@ -823,7 +826,7 @@ public: } Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD); d.width += icon_size.width + 2; - d.height = max(d.height, icon_size.height); + d.height = GetMinSizing(NWST_STEP, max(d.height, icon_size.height)); resize->height = d.height; d.height *= 5; d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; diff --git a/src/town_gui.cpp.orig b/src/town_gui.cpp.orig index 7dd009d885..052fe4119d 100644 --- a/src/town_gui.cpp.orig +++ b/src/town_gui.cpp.orig @@ -197,7 +197,7 @@ public: case WID_TA_COMMAND_LIST: { int numact; uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); - int y = r.top + WD_FRAMERECT_TOP; + int y = Center(r.top, this->resize.step_height); int pos = this->vscroll->GetPosition(); if (--pos < 0) { diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 3a077e4e50..8b1700e7c0 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -648,7 +648,7 @@ struct RefitWindow : public Window { { switch (widget) { case WID_VR_MATRIX: - resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM; + resize->height = GetMinSizing(NWST_STEP, WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM); size->height = resize->height * 8; break; @@ -1329,7 +1329,7 @@ void DrawVehicleImage(const Vehicle *v, int left, int right, int y, int height, uint GetVehicleListHeight(VehicleType type, uint divisor) { /* Name + vehicle + profit */ - uint base = GetVehicleHeight(type) + 2 * FONT_HEIGHT_SMALL; + uint base = GetMinSizing(NWST_STEP, GetVehicleHeight(type) + 2 * FONT_HEIGHT_SMALL); /* Drawing of the 4 small orders + profit*/ if (type >= VEH_SHIP) base = max(base, 5U * FONT_HEIGHT_SMALL); diff --git a/src/vehicle_gui.cpp.orig b/src/vehicle_gui.cpp.orig index b1cd7ce2be..3a077e4e50 100644 --- a/src/vehicle_gui.cpp.orig +++ b/src/vehicle_gui.cpp.orig @@ -318,7 +318,7 @@ typedef SmallVector SubtypeList; ///< List of refit subtypes as */ static void DrawVehicleRefitWindow(const SubtypeList list[NUM_CARGO], const int sel[2], uint pos, uint rows, uint delta, const Rect &r) { - uint y = r.top + WD_MATRIX_TOP; + uint y = Center(r.top, delta); uint current = 0; bool rtl = _current_text_dir == TD_RTL; @@ -713,7 +713,7 @@ struct RefitWindow : public Window { case WID_VR_VEHICLE_PANEL_DISPLAY: { Vehicle *v = Vehicle::Get(this->window_number); DrawVehicleImage(v, this->sprite_left + WD_FRAMERECT_LEFT, this->sprite_right - WD_FRAMERECT_RIGHT, - r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != NULL ? this->hscroll->GetPosition() : 0); + r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != NULL ? this->hscroll->GetPosition() : 0); /* Highlight selected vehicles. */ if (this->order != INVALID_VEH_ORDER_ID) break; @@ -1308,8 +1308,9 @@ static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, Veh * @param selection Selected vehicle to draw a frame around * @param skip Number of pixels to skip at the front (for scrolling) */ -void DrawVehicleImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip) +void DrawVehicleImage(const Vehicle *v, int left, int right, int y, int height, VehicleID selection, EngineImageType image_type, int skip) { + y = Center(y, height, GetVehicleHeight(v->type)); switch (v->type) { case VEH_TRAIN: DrawTrainImage(Train::From(v), left, right, y, selection, image_type, skip); break; case VEH_ROAD: DrawRoadVehImage(v, left, right, y, selection, image_type, skip); break; @@ -1374,7 +1375,7 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int SetDParam(0, v->GetDisplayProfitThisYear()); SetDParam(1, v->GetDisplayProfitLastYear()); - DrawVehicleImage(v, image_left, image_right, y + FONT_HEIGHT_SMALL - 1, selected_vehicle, EIT_IN_LIST, 0); + DrawVehicleImage(v, image_left, image_right, y, line_height, selected_vehicle, EIT_IN_LIST, 0); DrawString(text_left, text_right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1, STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR); if (v->name != NULL) { @@ -2085,12 +2086,12 @@ struct VehicleDetailsWindow : Window { /* Articulated road vehicles use a complete line. */ if (v->type == VEH_ROAD && v->HasArticulatedPart()) { - DrawVehicleImage(v, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, 0); + DrawVehicleImage(v, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, 0); } else { uint sprite_left = rtl ? text_right : r.left; uint sprite_right = rtl ? r.right : text_left; - DrawVehicleImage(v, sprite_left + WD_FRAMERECT_LEFT, sprite_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, 0); + DrawVehicleImage(v, sprite_left + WD_FRAMERECT_LEFT, sprite_right - WD_FRAMERECT_RIGHT, r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, 0); } DrawVehicleDetails(v, text_left + WD_FRAMERECT_LEFT, text_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, 0, 0, this->tab); break; @@ -2632,7 +2633,7 @@ public: int image = ((v->vehstatus & VS_STOPPED) != 0) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING; int lowered = this->IsWidgetLowered(WID_VV_START_STOP) ? 1 : 0; DrawSprite(image, PAL_NONE, image_left + lowered, r.top + WD_IMGBTN_TOP + lowered); - DrawString(text_left + lowered, text_right + lowered, r.top + WD_FRAMERECT_TOP + lowered, str, TC_FROMSTRING, SA_HOR_CENTER); + DrawString(text_left + lowered, text_right + lowered, Center(r.top + lowered, r.bottom - r.top), str, TC_FROMSTRING, SA_HOR_CENTER); } virtual void OnClick(Point pt, int widget, int click_count) diff --git a/src/widget.cpp b/src/widget.cpp index 534909066a..98e1561771 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -523,7 +523,7 @@ static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicke { int text_offset = max(0, ((int)(r.bottom - r.top + 1) - FONT_HEIGHT_NORMAL) / 2); // Offset for rendering the text vertically centered - int dd_width = NWidgetLeaf::dropdown_dimension.width; + int dd_width = GetMinSizing(NWST_STEP, NWidgetLeaf::dropdown_dimension.width); if (_current_text_dir == TD_LTR) { DrawFrameRect(r.left, r.top, r.right - dd_width, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); @@ -746,6 +746,7 @@ NWidgetBase *NWidgetBase::GetWidgetOfType(WidgetType tp) */ NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : NWidgetBase(tp) { + this->sizing_type = NWST_NONE; this->fill_x = fill_x; this->fill_y = fill_y; } @@ -757,8 +758,23 @@ NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : */ void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y) { - this->min_x = min_x; - this->min_y = min_y; + uint min_size = 0; + switch (this->sizing_type) { + case NWST_NONE: + case NWST_OVERRIDE: + min_size = 0; + break; + case NWST_BUTTON: + min_size = _settings_client.gui.min_button; + break; + case NWST_STEP: + min_size = _settings_client.gui.min_step; + break; + default: NOT_REACHED(); + } + + this->min_x = max(min_x, min_size); + this->min_y = max(min_y, min_size); } /** @@ -810,6 +826,7 @@ void NWidgetResizeBase::AssignSizePosition(SizingType sizing, uint x, uint y, ui */ NWidgetCore::NWidgetCore(WidgetType tp, Colours colour, uint fill_x, uint fill_y, uint32 widget_data, StringID tool_tip) : NWidgetResizeBase(tp, fill_x, fill_y) { + this->sizing_type = NWST_NONE; this->colour = colour; this->index = -1; this->widget_data = widget_data; @@ -1930,6 +1947,7 @@ void Scrollbar::SetCapacityFromWidget(Window *w, int widget, int padding) NWidgetScrollbar::NWidgetScrollbar(WidgetType tp, Colours colour, int index) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL), Scrollbar(tp != NWID_HSCROLLBAR) { assert(tp == NWID_HSCROLLBAR || tp == NWID_VSCROLLBAR); + this->sizing_type = NWST_STEP; this->SetIndex(index); switch (this->type) { @@ -2001,7 +2019,9 @@ void NWidgetScrollbar::Draw(const Window *w) if (vertical_dimension.width == 0) { vertical_dimension = maxdim(GetSpriteSize(SPR_ARROW_UP), GetSpriteSize(SPR_ARROW_DOWN)); vertical_dimension.width += extra.width; + vertical_dimension.width = GetMinSizing(NWST_STEP, vertical_dimension.width); vertical_dimension.height += extra.height; + vertical_dimension.height = GetMinSizing(NWST_STEP, vertical_dimension.height); } return vertical_dimension; } @@ -2012,7 +2032,9 @@ void NWidgetScrollbar::Draw(const Window *w) if (horizontal_dimension.width == 0) { horizontal_dimension = maxdim(GetSpriteSize(SPR_ARROW_LEFT), GetSpriteSize(SPR_ARROW_RIGHT)); horizontal_dimension.width += extra.width; + horizontal_dimension.width = GetMinSizing(NWST_STEP, horizontal_dimension.width); horizontal_dimension.height += extra.height; + horizontal_dimension.height = GetMinSizing(NWST_STEP, horizontal_dimension.height); } return horizontal_dimension; } @@ -2050,8 +2072,40 @@ Dimension NWidgetLeaf::dropdown_dimension = {0, 0}; */ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, StringID tip) : NWidgetCore(tp, colour, 1, 1, data, tip) { + assert(this->sizing_type < NWST_END); assert(index >= 0 || tp == WWT_LABEL || tp == WWT_TEXT || tp == WWT_CAPTION || tp == WWT_RESIZEBOX || tp == WWT_SHADEBOX || tp == WWT_DEFSIZEBOX || tp == WWT_DEBUGBOX || tp == WWT_STICKYBOX || tp == WWT_CLOSEBOX); if (index >= 0) this->SetIndex(index); + + if (this->sizing_type == NWST_NONE) { + switch (tp) { + case WWT_PUSHBTN: + case WWT_IMGBTN: + case WWT_PUSHIMGBTN: + case WWT_IMGBTN_2: + case WWT_TEXTBTN: + case WWT_PUSHTXTBTN: + case WWT_TEXTBTN_2: + case WWT_PUSHARROWBTN: + case WWT_EDITBOX: + case WWT_CAPTION: + case WWT_STICKYBOX: + case WWT_SHADEBOX: + case WWT_DEBUGBOX: + case WWT_DEFSIZEBOX: + case WWT_RESIZEBOX: + case WWT_CLOSEBOX: + this->sizing_type = NWST_BUTTON; + break; + case NWID_PUSHBUTTON_DROPDOWN: + case NWID_BUTTON_DROPDOWN: + case WWT_DROPDOWN: + this->sizing_type = NWST_STEP; + break; + default: + this->sizing_type = NWST_OVERRIDE; + } + } + this->SetMinimalSize(0, 0); this->SetResize(0, 0); @@ -2463,11 +2517,12 @@ void NWidgetLeaf::Draw(const Window *w) */ bool NWidgetLeaf::ButtonHit(const Point &pt) { + uint button_size = GetMinSizing(NWST_STEP, 12); if (_current_text_dir == TD_LTR) { - int button_width = this->pos_x + this->current_x - 12; + int button_width = this->pos_x + this->current_x - button_size; return pt.x < button_width; } else { - int button_left = this->pos_x + 12; + int button_left = this->pos_x + button_size; return pt.x >= button_left; } } @@ -2560,6 +2615,16 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, break; } + case WPT_SIZINGTYPE: { + NWidgetResizeBase *nwrb = dynamic_cast(*dest); + if (nwrb != NULL) { + assert(parts->u.sizing_type < NWST_END); + nwrb->sizing_type = parts->u.sizing_type; + nwrb->SetMinimalSize(0, 0); + } + break; + } + case WPT_MINSIZE: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); if (nwrb != NULL) { @@ -2816,6 +2881,7 @@ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int wid } NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum); + panel->sizing_type = NWST_STEP; panel->SetMinimalSize(sprite_size.width, sprite_size.height); panel->SetFill(1, 1); panel->SetResize(1, 0); @@ -2836,3 +2902,28 @@ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int wid if (hor != NULL) vert->Add(hor); return vert; } + +/** + * Return the minimal automatic size for a widget. + * @param type The automatic sizing type to use. + * @param min_1 Minimal passed value. + * @return At least the passed value, or the minimal size for the associated sizing type. + */ +uint GetMinSizing(NWidSizingType type, uint min_1) +{ + uint min_sizing; + switch (type) { + case NWST_NONE: + case NWST_OVERRIDE: + return min_1; + case NWST_BUTTON: + min_sizing = _settings_client.gui.min_button; + break; + case NWST_STEP: + min_sizing = _settings_client.gui.min_step; + break; + default: NOT_REACHED(); + } + + return max(min_sizing, min_1); +} diff --git a/src/widget.cpp.orig b/src/widget.cpp.orig index 1ead186b78..534909066a 100644 --- a/src/widget.cpp.orig +++ b/src/widget.cpp.orig @@ -523,7 +523,7 @@ static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicke { int text_offset = max(0, ((int)(r.bottom - r.top + 1) - FONT_HEIGHT_NORMAL) / 2); // Offset for rendering the text vertically centered - int dd_width = GetMinSizing(NWST_STEP, NWidgetLeaf::dropdown_dimension.width); + int dd_width = NWidgetLeaf::dropdown_dimension.width; if (_current_text_dir == TD_LTR) { DrawFrameRect(r.left, r.top, r.right - dd_width, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); @@ -746,7 +746,6 @@ NWidgetBase *NWidgetBase::GetWidgetOfType(WidgetType tp) */ NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : NWidgetBase(tp) { - this->sizing_type = NWST_NONE; this->fill_x = fill_x; this->fill_y = fill_y; } @@ -758,26 +757,8 @@ NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : */ void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y) { - uint min_size = 0; - switch (this->sizing_type) { - case NWST_NONE: - case NWST_OVERRIDE: - min_size = 0; - break; - case NWST_BUTTON: - min_size = _settings_client.gui.min_button; - break; - case NWST_STEP: - min_size = _settings_client.gui.min_step; - break; - case NWST_VIEWPORT: - min_size = 3 * _settings_client.gui.min_button; - break; - default: NOT_REACHED(); - } - - this->min_x = max(min_x, min_size); - this->min_y = max(min_y, min_size); + this->min_x = min_x; + this->min_y = min_y; } /** @@ -829,7 +810,6 @@ void NWidgetResizeBase::AssignSizePosition(SizingType sizing, uint x, uint y, ui */ NWidgetCore::NWidgetCore(WidgetType tp, Colours colour, uint fill_x, uint fill_y, uint32 widget_data, StringID tool_tip) : NWidgetResizeBase(tp, fill_x, fill_y) { - this->sizing_type = NWST_NONE; this->colour = colour; this->index = -1; this->widget_data = widget_data; @@ -1950,7 +1930,6 @@ void Scrollbar::SetCapacityFromWidget(Window *w, int widget, int padding) NWidgetScrollbar::NWidgetScrollbar(WidgetType tp, Colours colour, int index) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL), Scrollbar(tp != NWID_HSCROLLBAR) { assert(tp == NWID_HSCROLLBAR || tp == NWID_VSCROLLBAR); - this->sizing_type = NWST_STEP; this->SetIndex(index); switch (this->type) { @@ -2022,9 +2001,7 @@ void NWidgetScrollbar::Draw(const Window *w) if (vertical_dimension.width == 0) { vertical_dimension = maxdim(GetSpriteSize(SPR_ARROW_UP), GetSpriteSize(SPR_ARROW_DOWN)); vertical_dimension.width += extra.width; - vertical_dimension.width = GetMinSizing(NWST_STEP, vertical_dimension.width); vertical_dimension.height += extra.height; - vertical_dimension.height = GetMinSizing(NWST_STEP, vertical_dimension.height); } return vertical_dimension; } @@ -2035,9 +2012,7 @@ void NWidgetScrollbar::Draw(const Window *w) if (horizontal_dimension.width == 0) { horizontal_dimension = maxdim(GetSpriteSize(SPR_ARROW_LEFT), GetSpriteSize(SPR_ARROW_RIGHT)); horizontal_dimension.width += extra.width; - horizontal_dimension.width = GetMinSizing(NWST_STEP, horizontal_dimension.width); horizontal_dimension.height += extra.height; - horizontal_dimension.height = GetMinSizing(NWST_STEP, horizontal_dimension.height); } return horizontal_dimension; } @@ -2075,40 +2050,8 @@ Dimension NWidgetLeaf::dropdown_dimension = {0, 0}; */ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, StringID tip) : NWidgetCore(tp, colour, 1, 1, data, tip) { - assert(this->sizing_type < NWST_END); assert(index >= 0 || tp == WWT_LABEL || tp == WWT_TEXT || tp == WWT_CAPTION || tp == WWT_RESIZEBOX || tp == WWT_SHADEBOX || tp == WWT_DEFSIZEBOX || tp == WWT_DEBUGBOX || tp == WWT_STICKYBOX || tp == WWT_CLOSEBOX); if (index >= 0) this->SetIndex(index); - - if (this->sizing_type == NWST_NONE) { - switch (tp) { - case WWT_PUSHBTN: - case WWT_IMGBTN: - case WWT_PUSHIMGBTN: - case WWT_IMGBTN_2: - case WWT_TEXTBTN: - case WWT_PUSHTXTBTN: - case WWT_TEXTBTN_2: - case WWT_PUSHARROWBTN: - case WWT_EDITBOX: - case WWT_CAPTION: - case WWT_STICKYBOX: - case WWT_SHADEBOX: - case WWT_DEBUGBOX: - case WWT_DEFSIZEBOX: - case WWT_RESIZEBOX: - case WWT_CLOSEBOX: - this->sizing_type = NWST_BUTTON; - break; - case NWID_PUSHBUTTON_DROPDOWN: - case NWID_BUTTON_DROPDOWN: - case WWT_DROPDOWN: - this->sizing_type = NWST_STEP; - break; - default: - this->sizing_type = NWST_OVERRIDE; - } - } - this->SetMinimalSize(0, 0); this->SetResize(0, 0); @@ -2135,7 +2078,7 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, case WWT_EDITBOX: { Dimension sprite_size = GetSpriteSize(_current_text_dir == TD_RTL ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); - this->SetMinimalSize(30 + GetMinSizing(NWST_BUTTON, sprite_size.width), sprite_size.height); + this->SetMinimalSize(30 + sprite_size.width, sprite_size.height); this->SetFill(0, 0); break; } @@ -2520,12 +2463,11 @@ void NWidgetLeaf::Draw(const Window *w) */ bool NWidgetLeaf::ButtonHit(const Point &pt) { - uint button_size = GetMinSizing(NWST_STEP, 12); if (_current_text_dir == TD_LTR) { - int button_width = this->pos_x + this->current_x - button_size; + int button_width = this->pos_x + this->current_x - 12; return pt.x < button_width; } else { - int button_left = this->pos_x + button_size; + int button_left = this->pos_x + 12; return pt.x >= button_left; } } @@ -2618,16 +2560,6 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, break; } - case WPT_SIZINGTYPE: { - NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != NULL) { - assert(parts->u.sizing_type < NWST_END); - nwrb->sizing_type = parts->u.sizing_type; - nwrb->SetMinimalSize(0, 0); - } - break; - } - case WPT_MINSIZE: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); if (nwrb != NULL) { @@ -2884,7 +2816,6 @@ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int wid } NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum); - panel->sizing_type = NWST_STEP; panel->SetMinimalSize(sprite_size.width, sprite_size.height); panel->SetFill(1, 1); panel->SetResize(1, 0); @@ -2905,34 +2836,3 @@ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int wid if (hor != NULL) vert->Add(hor); return vert; } - -/** - * Return the minimal automatic size for a widget. - * @param type The automatic sizing type to use. - * @param min_1 Minimal passed value. - * @return At least the passed value, or the minimal size for the associated sizing type. - */ -uint GetMinSizing(NWidSizingType type, uint min_1) -{ - uint min_sizing; - switch (type) { - case NWST_NONE: - case NWST_OVERRIDE: - return min_1; - case NWST_BUTTON: - min_sizing = _settings_client.gui.min_button; - break; - case NWST_STEP: - min_sizing = _settings_client.gui.min_step; - break; - case NWST_KEYBOARD: - min_sizing = 2 * _settings_client.gui.min_button; - break; - case NWST_WINDOW_LENGTH: - min_sizing = 8 * _settings_client.gui.min_button; - break; - default: NOT_REACHED(); - } - - return max(min_sizing, min_1); -} diff --git a/src/widget_type.h b/src/widget_type.h index 6d8b32bc9c..100309632e 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -40,6 +40,17 @@ enum ArrowWidgetValues { AWV_RIGHT, ///< Force the arrow to the right }; +/** Values for different minimal sizing of widgets. */ +enum NWidSizingType { + NWST_NONE, ///< No sizing type is yet defined. + ///< Most buttons and scrollbars are initialized with this value. + ///< Later, they are automatically set to NWST_BUTTON or NWST_STEP. + NWST_BUTTON, ///< Size will be set at least _settings_client.gui.min_button. + NWST_STEP, ///< Size will be set at least _settings_client.gui.min_step (scrollbars and dropdowns). + NWST_OVERRIDE, ///< Avoid widgets to use automatic minimal sizing. + NWST_END +}; + /** * Window widget types, nested widget types, and nested widget part types. */ @@ -85,6 +96,7 @@ enum WidgetType { /* Nested widget part types. */ WPT_RESIZE, ///< Widget part for specifying resizing. + WPT_SIZINGTYPE, ///< Widget part for specifying sizing mode. WPT_MINSIZE, ///< Widget part for specifying minimal size. WPT_MINTEXTLINES, ///< Widget part for specifying minimal number of lines of text. WPT_FILL, ///< Widget part for specifying fill. @@ -160,11 +172,12 @@ public: virtual void Draw(const Window *w) = 0; virtual void SetDirty(const Window *w) const; - WidgetType type; ///< Type of the widget / nested widget. - uint fill_x; ///< Horizontal fill stepsize (from initial size, \c 0 means not resizable). - uint fill_y; ///< Vertical fill stepsize (from initial size, \c 0 means not resizable). - uint resize_x; ///< Horizontal resize step (\c 0 means not resizable). - uint resize_y; ///< Vertical resize step (\c 0 means not resizable). + WidgetType type; ///< Type of the widget / nested widget. + NWidSizingType sizing_type; ///< Type for deciding minimal sizes of the widget. + uint fill_x; ///< Horizontal fill stepsize (from initial size, \c 0 means not resizable). + uint fill_y; ///< Vertical fill stepsize (from initial size, \c 0 means not resizable). + uint resize_x; ///< Horizontal resize step (\c 0 means not resizable). + uint resize_y; ///< Vertical resize step (\c 0 means not resizable). /* Size of the widget in the smallest window possible. * Computed by #SetupSmallestSize() followed by #AssignSizePosition(). */ @@ -918,6 +931,7 @@ struct NWidgetPart { NWidgetPartTextLines text_lines; ///< Part with text line data. NWidgetFunctionType *func_ptr; ///< Part with a function call. NWidContainerFlags cont_flags; ///< Part with container flags. + NWidSizingType sizing_type; ///< Part with sizing type. } u; }; @@ -938,6 +952,23 @@ static inline NWidgetPart SetResize(int16 dx, int16 dy) return part; } +/** + * Widget part function for setting the automatic minimal size. + * @param type How to decide the minimal size of the widget. + * @ingroup NestedWidgetParts + */ +static inline NWidgetPart SetSizingType(NWidSizingType type) +{ + NWidgetPart part; + + part.type = WPT_SIZINGTYPE; + part.u.sizing_type = type; + + return part; +} + +uint GetMinSizing(NWidSizingType type, uint min_1 = 0); + /** * Widget part function for setting the minimal size. * @param x Horizontal minimal size. diff --git a/src/widgets/dropdown_type.h b/src/widgets/dropdown_type.h index b65d4557bd..4c330117e7 100644 --- a/src/widgets/dropdown_type.h +++ b/src/widgets/dropdown_type.h @@ -13,6 +13,7 @@ #define WIDGETS_DROPDOWN_TYPE_H #include "../window_type.h" +#include "../widget_type.h" #include "../gfx_func.h" #include "../core/smallvec_type.hpp" #include "table/strings.h" @@ -30,7 +31,7 @@ public: virtual ~DropDownListItem() {} virtual bool Selectable() const { return false; } - virtual uint Height(uint width) const { return FONT_HEIGHT_NORMAL; } + virtual uint Height(uint width) const { return GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); } virtual uint Width() const { return 0; } virtual void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const; }; From f63ed5b6e73cb727f58f6e66ce1b3a2717a3f30c Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sun, 21 Jul 2013 22:03:46 +0200 Subject: [PATCH 023/187] Add min sizing on smallmap window. --- src/smallmap_gui.cpp | 20 +++++++++++--------- src/smallmap_gui.h | 3 ++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index b4137038fc..1d566255d6 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -1046,7 +1046,10 @@ void SmallMapWindow::SetupWidgetData() this->GetWidget(WID_SM_SELECT_BUTTONS)->SetDisplayedPlane(plane); } -SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : Window(desc), refresh(FORCE_REFRESH_PERIOD) +SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : + Window(desc), + row_height(GetMinSizing(NWST_STEP, FONT_HEIGHT_SMALL)), + refresh(FORCE_REFRESH_PERIOD) { _smallmap_industry_highlight = INVALID_INDUSTRYTYPE; this->overlay = new LinkGraphOverlay(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1); @@ -1156,9 +1159,8 @@ SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : Window(des bool rtl = _current_text_dir == TD_RTL; uint y_org = r.top + WD_FRAMERECT_TOP; uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT; - uint y = y_org; + uint y = Center(y_org, this->row_height, FONT_HEIGHT_SMALL); uint i = 0; // Row counter for industry legend. - uint row_height = FONT_HEIGHT_SMALL; uint text_left = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT; uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0); @@ -1185,7 +1187,7 @@ SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : Window(des /* Column break needed, continue at top, COLUMN_WIDTH pixels * (one "row") to the right. */ x += rtl ? -(int)this->column_width : this->column_width; - y = y_org; + y = Center(y_org, this->row_height, FONT_HEIGHT_SMALL); i = 1; } @@ -1213,7 +1215,7 @@ SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : Window(des DrawString(x + text_left, x + text_right, y, string, TC_GREY); } else { DrawString(x + text_left, x + text_right, y, string, TC_BLACK); - GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK); // Outer border of the legend colour + GfxFillRect(x + blob_left, y + 1, x + blob_right, y + FONT_HEIGHT_SMALL - 1, PC_BLACK); // Outer border of the legend colour } break; } @@ -1221,13 +1223,13 @@ SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : Window(des default: if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP); /* Anything that is not an industry or a company is using normal process */ - GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK); + GfxFillRect(x + blob_left, y + 1, x + blob_right, y + FONT_HEIGHT_SMALL - 1, PC_BLACK); DrawString(x + text_left, x + text_right, y, tbl->legend); break; } - GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, legend_colour); // Legend colour + GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + FONT_HEIGHT_SMALL - 2, legend_colour); // Legend colour - y += row_height; + y += this->row_height; } } } @@ -1319,7 +1321,7 @@ void SmallMapWindow::SetOverlayCargoMask() int SmallMapWindow::GetPositionOnLegend(Point pt) { const NWidgetBase *wi = this->GetWidget(WID_SM_LEGEND); - uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL; + uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / this->row_height; uint columns = this->GetNumberColumnsLegend(wi->current_x); uint number_of_rows = this->GetNumberRowsLegend(columns); if (line >= number_of_rows) return -1; diff --git a/src/smallmap_gui.h b/src/smallmap_gui.h index 6652f83d8c..d54969d915 100644 --- a/src/smallmap_gui.h +++ b/src/smallmap_gui.h @@ -72,6 +72,7 @@ protected: uint min_number_of_columns; ///< Minimal number of columns in legends. uint min_number_of_fixed_rows; ///< Minimal number of rows in the legends for the fixed layouts only (all except #SMT_INDUSTRY). uint column_width; ///< Width of a column in the #WID_SM_LEGEND widget. + const uint row_height; ///< Heigth of each row in the #WID_SM_LEGEND widget. int32 scroll_x; ///< Horizontal world coordinate of the base tile left of the top-left corner of the smallmap display. int32 scroll_y; ///< Vertical world coordinate of the base tile left of the top-left corner of the smallmap display. @@ -133,7 +134,7 @@ protected: inline uint GetLegendHeight(uint num_columns) const { return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + - this->GetNumberRowsLegend(num_columns) * FONT_HEIGHT_SMALL; + this->GetNumberRowsLegend(num_columns) * this->row_height; } /** From 4c8c1ce146c94d4ee6c3d1293792bf58dc1d398d Mon Sep 17 00:00:00 2001 From: Juanjo Date: Fri, 2 Aug 2013 18:33:46 +0000 Subject: [PATCH 024/187] Add min sizings to some construction buttons. --- src/dock_gui.cpp | 4 ++-- src/rail_gui.cpp | 16 ++++++++-------- src/road_gui.cpp | 20 ++++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index 03c661dd0b..89e925073a 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -531,10 +531,10 @@ static const NWidgetPart _nested_build_docks_depot_widgets[] = { NWidget(NWID_SPACER), SetMinimalSize(0, 3), NWidget(NWID_HORIZONTAL_LTR), NWidget(NWID_SPACER), SetMinimalSize(3, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BDD_X), SetMinimalSize(98, 66), SetDataTip(0x0, STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BDD_X), SetSizingType(NWST_BUTTON), SetMinimalSize(98, 66), SetDataTip(0x0, STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(2, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BDD_Y), SetMinimalSize(98, 66), SetDataTip(0x0, STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BDD_Y), SetSizingType(NWST_BUTTON), SetMinimalSize(98, 66), SetDataTip(0x0, STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(3, 0), EndContainer(), diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 1808164c50..cb4f16f12f 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1368,9 +1368,9 @@ static const NWidgetPart _nested_station_builder_widgets[] = { NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetPadding(1, 2, 0, 2), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_X), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_X), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_Y), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_Y), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0), EndContainer(), NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BRAS_SHOW_NEWST_TYPE), SetMinimalSize(144, 11), SetDataTip(STR_ORANGE_STRING, STR_NULL), SetPadding(1, 2, 4, 2), @@ -1642,8 +1642,8 @@ static const NWidgetPart _nested_signal_builder_widgets[] = { NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BS_DRAG_SIGNALS_DENSITY_LABEL), SetDataTip(STR_ORANGE_INT, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_DECREASE), SetMinimalSize(9, 12), SetDataTip(AWV_DECREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_INCREASE), SetMinimalSize(9, 12), SetDataTip(AWV_INCREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_DECREASE), SetSizingType(NWST_STEP), SetMinimalSize(9, 12), SetDataTip(AWV_DECREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_INCREASE), SetSizingType(NWST_STEP), SetMinimalSize(9, 12), SetDataTip(AWV_INCREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0), @@ -1710,18 +1710,18 @@ static const NWidgetPart _nested_build_depot_widgets[] = { NWidget(NWID_HORIZONTAL_LTR), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(2, 0), NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), diff --git a/src/road_gui.cpp b/src/road_gui.cpp index a35dab23c6..04387cbb7d 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -897,18 +897,18 @@ static const NWidgetPart _nested_build_road_depot_widgets[] = { NWidget(NWID_HORIZONTAL_LTR), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(2, 0), NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), @@ -1043,17 +1043,17 @@ static const NWidgetPart _nested_rv_station_picker_widgets[] = { NWidget(NWID_SPACER), SetMinimalSize(0, 3), NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NW), SetMinimalSize(66, 50), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NE), SetMinimalSize(66, 50), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetMinimalSize(66, 50), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SW), SetMinimalSize(66, 50), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SE), SetMinimalSize(66, 50), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetMinimalSize(66, 50), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 1), From 3f81edb6640e7e23143151ecff5b2b7e2e0f1bc6 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 27 Jul 2013 22:03:06 +0000 Subject: [PATCH 025/187] More sizing and centering. --- src/ai/ai_gui.cpp | 27 ++++++++++++++------------- src/cheat_gui.cpp | 16 +++++++++++----- src/industry_gui.cpp | 39 +++++++++++++++++++++------------------ src/industry_gui.cpp.orig | 4 ++-- src/intro_gui.cpp | 2 +- src/newgrf_debug_gui.cpp | 6 +++--- src/newgrf_gui.cpp | 1 + src/news_gui.cpp | 12 ++++++------ src/osk_gui.cpp | 5 +++-- src/osk_gui.cpp.orig | 5 ++--- src/settings_gui.cpp | 10 ++++++---- src/settings_gui.cpp.orig | 2 +- src/signs_gui.cpp | 2 +- src/station_gui.cpp | 2 +- src/station_gui.cpp.orig | 15 ++++++++------- src/town_gui.cpp | 2 +- src/town_gui.cpp.orig | 21 ++++++++++++--------- src/transparency_gui.cpp | 2 +- 18 files changed, 95 insertions(+), 78 deletions(-) diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index 62fed7debf..1fec5ff746 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -120,16 +120,16 @@ struct AIListWindow : public Window { switch (widget) { case WID_AIL_LIST: { /* Draw a list of all available AIs. */ - int y = this->GetWidget(WID_AIL_LIST)->pos_y; + int y = Center(r.top, this->line_height); /* First AI in the list is hardcoded to random */ if (this->vscroll->IsVisible(0)) { - DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_LEFT, y + WD_MATRIX_TOP, this->slot == OWNER_DEITY ? STR_AI_CONFIG_NONE : STR_AI_CONFIG_RANDOM_AI, this->selected == -1 ? TC_WHITE : TC_ORANGE); + DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_LEFT, y, this->slot == OWNER_DEITY ? STR_AI_CONFIG_NONE : STR_AI_CONFIG_RANDOM_AI, this->selected == -1 ? TC_WHITE : TC_ORANGE); y += this->line_height; } ScriptInfoList::const_iterator it = this->info_list->begin(); for (int i = 1; it != this->info_list->end(); i++, it++) { if (this->vscroll->IsVisible(i)) { - DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, (*it).second->GetName(), (this->selected == i - 1) ? TC_WHITE : TC_ORANGE); + DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y, (*it).second->GetName(), (this->selected == i - 1) ? TC_WHITE : TC_ORANGE); y += this->line_height; } } @@ -367,7 +367,6 @@ struct AISettingsWindow : public Window { uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : SETTING_BUTTON_WIDTH + 8); uint text_right = r.right - (rtl ? SETTING_BUTTON_WIDTH + 8 : WD_FRAMERECT_RIGHT); - int y = r.top; int button_y_offset = (this->line_height - SETTING_BUTTON_HEIGHT) / 2; for (; this->vscroll->IsVisible(i) && it != visible_settings.end(); i++, it++) { @@ -411,7 +410,7 @@ struct AISettingsWindow : public Window { } } - DrawString(text_left, text_right, y + WD_MATRIX_TOP, str, colour); + DrawString(text_left, text_right, Center(y, this->line_height), str, colour); y += this->line_height; } } @@ -679,7 +678,7 @@ static const NWidgetPart _nested_ai_config_widgets[] = { EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 9), NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_GAMESCRIPT, STR_NULL), SetPadding(0, 5, 4, 5), - NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_GAMELIST), SetMinimalSize(288, 14), SetFill(1, 0), SetMatrixDataTip(1, 1, STR_AI_CONFIG_GAMELIST_TOOLTIP), + NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_GAMELIST), SetSizingType(NWST_STEP), SetMinimalSize(288, 14), SetFill(1, 0), SetMatrixDataTip(1, 1, STR_AI_CONFIG_GAMELIST_TOOLTIP), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CHANGE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_CONFIG_CHANGE, STR_AI_CONFIG_CHANGE_TOOLTIP), @@ -756,8 +755,8 @@ struct AIConfigWindow : public Window { { switch (widget) { case WID_AIC_GAMELIST: - this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; - size->height = 1 * this->line_height; + this->line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); + size->height = this->line_height; break; case WID_AIC_LIST: @@ -799,14 +798,14 @@ struct AIConfigWindow : public Window { text = STR_JUST_RAW_STRING; } - DrawString(r.left + 10, r.right - 10, r.top + WD_MATRIX_TOP, text, + DrawString(r.left + 10, r.right - 10, Center(r.top, this->line_height), text, (this->selected_slot == OWNER_DEITY) ? TC_WHITE : (IsEditable(OWNER_DEITY) ? TC_ORANGE : TC_SILVER)); break; } case WID_AIC_LIST: { - int y = r.top; + int y = Center(r.top, this->line_height); for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < MAX_COMPANIES; i++) { StringID text; @@ -818,7 +817,7 @@ struct AIConfigWindow : public Window { } else { text = STR_AI_CONFIG_RANDOM_AI; } - DrawString(r.left + 10, r.right - 10, y + WD_MATRIX_TOP, text, + DrawString(r.left + 10, r.right - 10, y, text, (this->selected_slot == i) ? TC_WHITE : (IsEditable((CompanyID)i) ? TC_ORANGE : TC_SILVER)); y += this->line_height; } @@ -1088,6 +1087,8 @@ struct AIDebugWindow : public Window { bool dirty = false; + Dimension d = GetSpriteSize(SPR_COMPANY_ICON); + uint offset_y = Center(0, GetMinSizing(NWST_STEP, d.height + WD_MATRIX_TOP + WD_MATRIX_BOTTOM + 1), d.height); /* Paint the company icons */ for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { NWidgetCore *button = this->GetWidget(i + WID_AID_COMPANY_BUTTON_START); @@ -1108,7 +1109,7 @@ struct AIDebugWindow : public Window { if (!valid) continue; byte offset = (i == ai_debug_company) ? 1 : 0; - DrawCompanyIcon(i, button->pos_x + button->current_x / 2 - 7 + offset, this->GetWidget(WID_AID_COMPANY_BUTTON_START + i)->pos_y + 2 + offset); + DrawCompanyIcon(i, Center(button->pos_x + offset, button->current_x, d.width), button->pos_y + offset + offset_y); } /* Set button colour for Game Script. */ @@ -1187,7 +1188,7 @@ struct AIDebugWindow : public Window { ScriptLog::LogData *log = this->GetLogPointer(); if (log == NULL) return; - int y = this->top_offset; + int y = Center(this->top_offset, this->resize.step_height); for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < log->used; i++) { int pos = (i + log->pos + 1 - log->used + log->count) % log->count; if (log->lines[pos] == NULL) break; diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp index 9eb405d2ab..01ea1a488e 100644 --- a/src/cheat_gui.cpp +++ b/src/cheat_gui.cpp @@ -172,9 +172,11 @@ static const NWidgetPart _nested_cheat_widgets[] = { struct CheatWindow : Window { int clicked; int header_height; + int line_height; CheatWindow(WindowDesc *desc) : Window(desc) { + this->line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL); this->InitNested(); } @@ -190,11 +192,12 @@ struct CheatWindow : Window { uint button_left = rtl ? r.right - 20 - SETTING_BUTTON_WIDTH : r.left + 20; uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : 30 + SETTING_BUTTON_WIDTH); uint text_right = r.right - (rtl ? 30 + SETTING_BUTTON_WIDTH : WD_FRAMERECT_RIGHT); + uint box_height = GetSpriteSize(SPR_BOX_EMPTY).height; for (int i = 0; i != lengthof(_cheats_ui); i++) { const CheatEntry *ce = &_cheats_ui[i]; - DrawSprite((*ce->been_used) ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, box_left, y + 2); + DrawSprite((*ce->been_used) ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, box_left, Center(y, SETTING_BUTTON_HEIGHT, box_height)); switch (ce->type) { case SLE_BOOL: { @@ -233,7 +236,7 @@ struct CheatWindow : Window { DrawString(text_left, text_right, y + 1, ce->str); - y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + y += this->line_height; } } @@ -275,15 +278,18 @@ struct CheatWindow : Window { } } - size->width = width + 50 /* stuff on the left */ + 10 /* extra spacing on right */; + size->width = width + 30 + SETTING_BUTTON_WIDTH /* stuff on the left */ + 10 /* extra spacing on right */; this->header_height = GetStringHeight(STR_CHEATS_WARNING, size->width - WD_FRAMERECT_LEFT - WD_FRAMERECT_RIGHT) + WD_PAR_VSEP_WIDE; - size->height = this->header_height + WD_FRAMERECT_TOP + WD_PAR_VSEP_NORMAL + WD_FRAMERECT_BOTTOM + (FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL) * lengthof(_cheats_ui); + size->height = this->header_height + WD_FRAMERECT_TOP + WD_PAR_VSEP_NORMAL + WD_FRAMERECT_BOTTOM + this->line_height * lengthof(_cheats_ui); } virtual void OnClick(Point pt, int widget, int click_count) { const NWidgetBase *wid = this->GetWidget(WID_C_PANEL); - uint btn = (pt.y - wid->pos_y - WD_FRAMERECT_TOP - this->header_height) / (FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL); + + if ((pt.y - wid->pos_y - WD_FRAMERECT_TOP - this->header_height) % this->line_height > SETTING_BUTTON_HEIGHT) return; + + uint btn = (pt.y - wid->pos_y - WD_FRAMERECT_TOP - this->header_height) / this->line_height; uint x = pt.x - wid->pos_x; bool rtl = _current_text_dir == TD_RTL; if (rtl) x = wid->current_x - x; diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index ca39e8f1cb..c14265c087 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -206,9 +206,6 @@ class BuildIndustryWindow : public Window { bool enabled[NUM_INDUSTRYTYPES + 1]; ///< availability state, coming from CBID_INDUSTRY_PROBABILITY (if ever) Scrollbar *vscroll; - /** The offset for the text in the matrix. */ - static const int MATRIX_TEXT_OFFSET = 17; - void SetupArrays() { this->count = 0; @@ -297,7 +294,7 @@ public: d = maxdim(d, GetStringBoundingBox(GetIndustrySpec(this->index[i])->name)); } resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); - d.width += MATRIX_TEXT_OFFSET + padding.width; + d.width += FONT_HEIGHT_NORMAL * 5 / 4 + padding.width; d.height = 5 * resize->height; *size = maxdim(*size, d); break; @@ -381,20 +378,22 @@ public: switch (widget) { case WID_DPI_MATRIX_WIDGET: { uint text_left, text_right, icon_left, icon_right; + uint square_size = FONT_HEIGHT_NORMAL - 2; + uint text_offset = FONT_HEIGHT_NORMAL * 5 / 4; if (_current_text_dir == TD_RTL) { icon_right = r.right - WD_MATRIX_RIGHT; - icon_left = icon_right - 10; - text_right = icon_right - BuildIndustryWindow::MATRIX_TEXT_OFFSET; + icon_left = icon_right - square_size; + text_right = icon_right - text_offset; text_left = r.left + WD_MATRIX_LEFT; } else { icon_left = r.left + WD_MATRIX_LEFT; - icon_right = icon_left + 10; - text_left = icon_left + BuildIndustryWindow::MATRIX_TEXT_OFFSET; + icon_right = icon_left + square_size; + text_left = icon_left + text_offset; text_right = r.right - WD_MATRIX_RIGHT; } - for (byte i = 0; i < this->vscroll->GetCapacity() && i + this->vscroll->GetPosition() < this->count; i++) { - int y = r.top + WD_MATRIX_TOP + i * this->resize.step_height; + int y = Center(r.top, this->resize.step_height); + for (byte i = 0; i < this->vscroll->GetCapacity() && i + this->vscroll->GetPosition() < this->count; i++, y += this->resize.step_height) { bool selected = this->selected_index == i + this->vscroll->GetPosition(); if (this->index[i + this->vscroll->GetPosition()] == INVALID_INDUSTRYTYPE) { @@ -405,8 +404,8 @@ public: /* Draw the name of the industry in white is selected, otherwise, in orange */ DrawString(text_left, text_right, y, indsp->name, selected ? TC_WHITE : TC_ORANGE); - GfxFillRect(icon_left, y + 1, icon_right, y + 7, selected ? PC_WHITE : PC_BLACK); - GfxFillRect(icon_left + 1, y + 2, icon_right - 1, y + 6, indsp->map_colour); + GfxFillRect(icon_left, y + 1, icon_right, y + square_size, selected ? PC_WHITE : PC_BLACK); + GfxFillRect(icon_left + 1, y + 2, icon_right - 1, y + square_size - 1, indsp->map_colour); } break; } @@ -758,7 +757,7 @@ public: if (first) { if (has_accept) y += WD_PAR_VSEP_WIDE; DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE); - y += FONT_HEIGHT_NORMAL; + y += this->editable == EA_RATE ? GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL) : FONT_HEIGHT_NORMAL; if (this->editable == EA_RATE) this->production_offset_y = y; first = false; } @@ -773,8 +772,10 @@ public: if (this->editable == EA_RATE) { DrawArrowButtons(left + WD_FRAMETEXT_LEFT, y, COLOUR_YELLOW, (this->clicked_line == IL_RATE1 + j) ? this->clicked_button : 0, i->production_rate[j] > 0, i->production_rate[j] < 255); + y += GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + } else { + y += FONT_HEIGHT_NORMAL; } - y += FONT_HEIGHT_NORMAL; } /* Display production multiplier if editable */ @@ -786,7 +787,7 @@ public: DrawString(x, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_PRODUCTION_LEVEL); DrawArrowButtons(left + WD_FRAMETEXT_LEFT, y, COLOUR_YELLOW, (this->clicked_line == IL_MULTIPLIER) ? this->clicked_button : 0, i->prod_level > PRODLEVEL_MINIMUM, i->prod_level < PRODLEVEL_MAXIMUM); - y += FONT_HEIGHT_NORMAL; + y += GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); } /* Get the extra message for the GUI */ @@ -834,12 +835,14 @@ public: case EA_NONE: break; case EA_MULTIPLIER: - if (IsInsideBS(pt.y, this->production_offset_y, FONT_HEIGHT_NORMAL)) line = IL_MULTIPLIER; + if (IsInsideBS(pt.y, this->production_offset_y, SETTING_BUTTON_HEIGHT)) line = IL_MULTIPLIER; break; case EA_RATE: if (pt.y >= this->production_offset_y) { - int row = (pt.y - this->production_offset_y) / FONT_HEIGHT_NORMAL; + if ((pt.y - this->production_offset_y) % GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL) > SETTING_BUTTON_HEIGHT) break;; + + int row = (pt.y - this->production_offset_y) / GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); for (uint j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] == CT_INVALID) continue; row--; @@ -1055,7 +1058,7 @@ static const NWidgetPart _nested_industry_directory_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetSizingType(NWST_STEP), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), EndContainer(), diff --git a/src/industry_gui.cpp.orig b/src/industry_gui.cpp.orig index 1dabde2646..ca39e8f1cb 100644 --- a/src/industry_gui.cpp.orig +++ b/src/industry_gui.cpp.orig @@ -296,7 +296,7 @@ public: if (this->index[i] == INVALID_INDUSTRYTYPE) continue; d = maxdim(d, GetStringBoundingBox(GetIndustrySpec(this->index[i])->name)); } - resize->height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); d.width += MATRIX_TEXT_OFFSET + padding.width; d.height = 5 * resize->height; *size = maxdim(*size, d); @@ -1303,7 +1303,7 @@ public: for (uint i = 0; i < this->industries.Length(); i++) { d = maxdim(d, GetStringBoundingBox(this->GetIndustryString(this->industries[i]))); } - resize->height = d.height; + resize->height = d.height = GetMinSizing(NWST_STEP, d.height); d.height *= 5; d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; diff --git a/src/intro_gui.cpp b/src/intro_gui.cpp index 5d13058944..3d07096d6b 100644 --- a/src/intro_gui.cpp +++ b/src/intro_gui.cpp @@ -145,7 +145,7 @@ struct SelectGameWindow : public Window { }; static const NWidgetPart _nested_select_game_widgets[] = { - NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_INTRO_CAPTION, STR_NULL), + NWidget(WWT_CAPTION, COLOUR_BROWN), SetSizingType(NWST_BUTTON), SetDataTip(STR_INTRO_CAPTION, STR_NULL), NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(NWID_SPACER), SetMinimalSize(0, 8), diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index be4e992130..2f14e6c518 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -840,7 +840,7 @@ struct SpriteAlignerWindow : Window { { if (widget != WID_SA_LIST) return; - resize->height = max(11, FONT_HEIGHT_NORMAL + 1); + resize->height = GetMinSizing(NWST_STEP, max(11, FONT_HEIGHT_NORMAL + 1)); resize->width = 1; /* Resize to about 200 pixels (for the preview) */ @@ -877,10 +877,10 @@ struct SpriteAlignerWindow : Window { SmallVector &list = _newgrf_debug_sprite_picker.sprites; int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), list.Length()); - int y = r.top + WD_FRAMERECT_TOP; + int y = Center(r.top + WD_FRAMERECT_TOP, step_size, FONT_HEIGHT_NORMAL); for (int i = this->vscroll->GetPosition(); i < max; i++) { 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); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_BLACK_COMMA, TC_FROMSTRING, SA_CENTER | SA_FORCE); y += step_size; } break; diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index aedb4fddd3..a46aa79b26 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -1943,6 +1943,7 @@ void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFC /** Widgets for the progress window. */ static const NWidgetPart _nested_scan_progress_widgets[] = { NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NEWGRF_SCAN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + SetSizingType(NWST_BUTTON), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(NWID_HORIZONTAL), SetPIP(20, 0, 20), NWidget(NWID_VERTICAL), SetPIP(11, 8, 11), diff --git a/src/news_gui.cpp b/src/news_gui.cpp index 5639001b71..97d4f795ea 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -78,7 +78,7 @@ static TileIndex GetReferenceTile(NewsReferenceType reftype, uint32 ref) static const NWidgetPart _nested_normal_news_widgets[] = { NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL), NWidget(NWID_HORIZONTAL), SetPadding(1, 1, 0, 1), - NWidget(WWT_TEXT, COLOUR_WHITE, WID_N_CLOSEBOX), SetDataTip(STR_SILVER_CROSS, STR_NULL), SetPadding(0, 0, 0, 1), + NWidget(WWT_TEXT, COLOUR_WHITE, WID_N_CLOSEBOX), SetSizingType(NWST_BUTTON), SetDataTip(STR_SILVER_CROSS, STR_NULL), SetPadding(0, 0, 0, 1), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(NWID_VERTICAL), NWidget(WWT_LABEL, COLOUR_WHITE, WID_N_DATE), SetDataTip(STR_DATE_LONG_SMALL, STR_NULL), @@ -101,7 +101,7 @@ static const NWidgetPart _nested_vehicle_news_widgets[] = { NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL), NWidget(NWID_HORIZONTAL), SetPadding(1, 1, 0, 1), NWidget(NWID_VERTICAL), - NWidget(WWT_TEXT, COLOUR_WHITE, WID_N_CLOSEBOX), SetDataTip(STR_SILVER_CROSS, STR_NULL), SetPadding(0, 0, 0, 1), + NWidget(WWT_TEXT, COLOUR_WHITE, WID_N_CLOSEBOX), SetSizingType(NWST_BUTTON), SetDataTip(STR_SILVER_CROSS, STR_NULL), SetPadding(0, 0, 0, 1), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), NWidget(WWT_LABEL, COLOUR_WHITE, WID_N_VEH_TITLE), SetFill(1, 1), SetMinimalSize(419, 55), SetDataTip(STR_EMPTY, STR_NULL), @@ -128,7 +128,7 @@ static const NWidgetPart _nested_company_news_widgets[] = { NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL), NWidget(NWID_HORIZONTAL), SetPadding(1, 1, 0, 1), NWidget(NWID_VERTICAL), - NWidget(WWT_TEXT, COLOUR_WHITE, WID_N_CLOSEBOX), SetDataTip(STR_SILVER_CROSS, STR_NULL), SetPadding(0, 0, 0, 1), + NWidget(WWT_TEXT, COLOUR_WHITE, WID_N_CLOSEBOX), SetSizingType(NWST_BUTTON), SetDataTip(STR_SILVER_CROSS, STR_NULL), SetPadding(0, 0, 0, 1), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), NWidget(WWT_LABEL, COLOUR_WHITE, WID_N_TITLE), SetFill(1, 1), SetMinimalSize(410, 20), SetDataTip(STR_EMPTY, STR_NULL), @@ -158,7 +158,7 @@ static WindowDesc _company_news_desc( static const NWidgetPart _nested_thin_news_widgets[] = { NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL), NWidget(NWID_HORIZONTAL), SetPadding(1, 1, 0, 1), - NWidget(WWT_TEXT, COLOUR_WHITE, WID_N_CLOSEBOX), SetDataTip(STR_SILVER_CROSS, STR_NULL), SetPadding(0, 0, 0, 1), + NWidget(WWT_TEXT, COLOUR_WHITE, WID_N_CLOSEBOX), SetSizingType(NWST_STEP), SetDataTip(STR_SILVER_CROSS, STR_NULL), SetPadding(0, 0, 0, 1), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(NWID_VERTICAL), NWidget(WWT_LABEL, COLOUR_WHITE, WID_N_DATE), SetDataTip(STR_DATE_LONG_SMALL, STR_NULL), @@ -1007,7 +1007,7 @@ struct MessageHistoryWindow : Window { virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_MH_BACKGROUND) { - this->line_height = FONT_HEIGHT_NORMAL + 2; + this->line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + 2); resize->height = this->line_height; /* Months are off-by-one, so it's actually 8. Not using @@ -1038,7 +1038,7 @@ struct MessageHistoryWindow : Window { } /* Fill the widget with news items. */ - int y = r.top + this->top_spacing; + int y = Center(r.top + this->top_spacing, this->line_height, FONT_HEIGHT_NORMAL); bool rtl = _current_text_dir == TD_RTL; uint date_left = rtl ? r.right - WD_FRAMERECT_RIGHT - this->date_width : r.left + WD_FRAMERECT_LEFT; uint date_right = rtl ? r.right - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT + this->date_width; diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp index d8d70e70c8..9445595ec2 100644 --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -230,7 +230,8 @@ static const int INTER_KEY_SPACE = 2; // Number of pixels between two keys. */ static void AddKey(NWidgetHorizontal *hor, int height, int num_half, WidgetType widtype, int widnum, uint16 widdata, int *biggest_index) { - int key_width = HALF_KEY_WIDTH + (INTER_KEY_SPACE + HALF_KEY_WIDTH) * (num_half - 1); + int min_half_key = max(GetMinSizing(NWST_BUTTON) / 2, HALF_KEY_WIDTH); + int key_width = min_half_key + (INTER_KEY_SPACE + min_half_key) * (num_half - 1); if (widtype == NWID_SPACER) { if (!hor->IsEmpty()) key_width += INTER_KEY_SPACE; @@ -330,7 +331,7 @@ static NWidgetBase *MakeSpacebarKeys(int *biggest_index) static const NWidgetPart _nested_osk_widgets[] = { - NWidget(WWT_CAPTION, COLOUR_GREY, WID_OSK_CAPTION), SetDataTip(STR_WHITE_STRING, STR_NULL), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_OSK_CAPTION), SetSizingType(NWST_BUTTON), SetDataTip(STR_WHITE_STRING, STR_NULL), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_OSK_TEXT), SetMinimalSize(252, 12), SetPadding(2, 2, 2, 2), EndContainer(), diff --git a/src/osk_gui.cpp.orig b/src/osk_gui.cpp.orig index 9445595ec2..d8d70e70c8 100644 --- a/src/osk_gui.cpp.orig +++ b/src/osk_gui.cpp.orig @@ -230,8 +230,7 @@ static const int INTER_KEY_SPACE = 2; // Number of pixels between two keys. */ static void AddKey(NWidgetHorizontal *hor, int height, int num_half, WidgetType widtype, int widnum, uint16 widdata, int *biggest_index) { - int min_half_key = max(GetMinSizing(NWST_BUTTON) / 2, HALF_KEY_WIDTH); - int key_width = min_half_key + (INTER_KEY_SPACE + min_half_key) * (num_half - 1); + int key_width = HALF_KEY_WIDTH + (INTER_KEY_SPACE + HALF_KEY_WIDTH) * (num_half - 1); if (widtype == NWID_SPACER) { if (!hor->IsEmpty()) key_width += INTER_KEY_SPACE; @@ -331,7 +330,7 @@ static NWidgetBase *MakeSpacebarKeys(int *biggest_index) static const NWidgetPart _nested_osk_widgets[] = { - NWidget(WWT_CAPTION, COLOUR_GREY, WID_OSK_CAPTION), SetSizingType(NWST_BUTTON), SetDataTip(STR_WHITE_STRING, STR_NULL), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_OSK_CAPTION), SetDataTip(STR_WHITE_STRING, STR_NULL), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_OSK_TEXT), SetMinimalSize(252, 12), SetPadding(2, 2, 2, 2), EndContainer(), diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 80f26b5282..755b829ff9 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -2368,11 +2368,13 @@ void ShowGameSettings() void DrawArrowButtons(int x, int y, Colours button_colour, byte state, bool clickable_left, bool clickable_right) { int colour = _colour_gradient[button_colour][2]; + int half_button = SETTING_BUTTON_WIDTH / 2; - DrawFrameRect(x, y, x + SETTING_BUTTON_WIDTH / 2 - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, (state == 1) ? FR_LOWERED : FR_NONE); - DrawFrameRect(x + SETTING_BUTTON_WIDTH / 2, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, (state == 2) ? FR_LOWERED : FR_NONE); - DrawSprite(SPR_ARROW_LEFT, PAL_NONE, x + WD_IMGBTN_LEFT, y + WD_IMGBTN_TOP); - DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, x + WD_IMGBTN_LEFT + SETTING_BUTTON_WIDTH / 2, y + WD_IMGBTN_TOP); + DrawFrameRect(x, y, x + half_button - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, (state == 1) ? FR_LOWERED : FR_NONE); + DrawFrameRect(x + half_button, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, (state == 2) ? FR_LOWERED : FR_NONE); + Dimension d = GetSpriteSize(SPR_ARROW_LEFT); + DrawSprite(SPR_ARROW_LEFT, PAL_NONE, Center(x, half_button, d.width), Center(y, SETTING_BUTTON_HEIGHT, d.height)); + DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, Center(x + half_button, half_button, d.width), Center(y, SETTING_BUTTON_HEIGHT, d.height)); /* Grey out the buttons that aren't clickable */ bool rtl = _current_text_dir == TD_RTL; diff --git a/src/settings_gui.cpp.orig b/src/settings_gui.cpp.orig index c01d8391b8..80f26b5282 100644 --- a/src/settings_gui.cpp.orig +++ b/src/settings_gui.cpp.orig @@ -1797,7 +1797,7 @@ struct GameSettingsWindow : Window { { switch (widget) { case WID_GS_OPTIONSPANEL: - resize->height = SETTING_HEIGHT = max(11, FONT_HEIGHT_NORMAL + 1); + resize->height = SETTING_HEIGHT = GetMinSizing(NWST_STEP, max(11, FONT_HEIGHT_NORMAL + 1)); resize->width = 1; size->height = 5 * resize->height + SETTINGTREE_TOP_OFFSET + SETTINGTREE_BOTTOM_OFFSET; diff --git a/src/signs_gui.cpp b/src/signs_gui.cpp index 2ec36775cf..e572f51a33 100644 --- a/src/signs_gui.cpp +++ b/src/signs_gui.cpp @@ -195,7 +195,7 @@ struct SignListWindow : Window, SignList { { switch (widget) { case WID_SIL_LIST: { - uint y = r.top + WD_FRAMERECT_TOP; // Offset from top of widget. + uint y = Center(r.top + WD_FRAMERECT_TOP, this->resize.step_height); // Offset from top of widget. /* No signs? */ if (this->vscroll->GetCount() == 0) { DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_STATION_LIST_NONE); diff --git a/src/station_gui.cpp b/src/station_gui.cpp index 5df21155c1..e57be72c86 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -744,7 +744,7 @@ static const NWidgetPart _nested_company_stations_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetSizingType(NWST_STEP), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_SORTDROPBTN), SetMinimalSize(163, 12), SetDataTip(STR_SORT_BY_NAME, STR_TOOLTIP_SORT_CRITERIA), // widget_data gets overwritten. NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(), EndContainer(), diff --git a/src/station_gui.cpp.orig b/src/station_gui.cpp.orig index 48a82f8d45..5df21155c1 100644 --- a/src/station_gui.cpp.orig +++ b/src/station_gui.cpp.orig @@ -400,7 +400,7 @@ public: } case WID_STL_LIST: - resize->height = FONT_HEIGHT_NORMAL; + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; break; @@ -451,7 +451,8 @@ public: case WID_STL_LIST: { int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.Length()); - int y = r.top + WD_FRAMERECT_TOP; + uint line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + int y = Center(r.top + WD_FRAMERECT_TOP, line_height); for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner const Station *st = this->stations[i]; assert(st->xy != INVALID_TILE); @@ -464,9 +465,9 @@ public: SetDParam(1, st->facilities); int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION); - StationsWndShowStationRating(st, r.left, r.right, x, FONT_HEIGHT_NORMAL + 2, y); + StationsWndShowStationRating(st, r.left, r.right, x, line_height + 2, y); - y += FONT_HEIGHT_NORMAL; + y += line_height; } if (this->vscroll->GetCount() == 0) { // company has no stations @@ -518,7 +519,7 @@ public: { switch (widget) { case WID_STL_LIST: { - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, FONT_HEIGHT_NORMAL); + uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, this->resize.step_height); if (id_v >= this->stations.Length()) return; // click out of list bound const Station *st = this->stations[id_v]; @@ -2292,8 +2293,8 @@ struct SelectStationWindow : Window { d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION)); } - resize->height = d.height; - d.height *= 5; + resize->height = GetMinSizing(NWST_STEP, d.height); + d.height = 5 * resize->height; d.width += WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = d; diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 76ee227e29..e6ad46e33b 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -614,7 +614,7 @@ static const NWidgetPart _nested_town_directory_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TD_SORT_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TD_SORT_ORDER), SetSizingType(NWST_STEP), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_TD_SORT_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), EndContainer(), diff --git a/src/town_gui.cpp.orig b/src/town_gui.cpp.orig index 052fe4119d..76ee227e29 100644 --- a/src/town_gui.cpp.orig +++ b/src/town_gui.cpp.orig @@ -47,12 +47,12 @@ static const NWidgetPart _nested_town_authority_widgets[] = { NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), SetFill(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_COMMAND_LIST), SetMinimalSize(305, 52), SetResize(1, 0), SetDataTip(0x0, STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), SetScrollbar(WID_TA_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_TA_SCROLLBAR), EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 1), SetFill(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TA_EXECUTE), SetMinimalSize(317, 12), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_LOCAL_AUTHORITY_DO_IT_BUTTON, STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), @@ -65,6 +65,7 @@ private: Town *town; ///< Town being displayed. int sel_index; ///< Currently selected town action, \c 0 to \c TACT_COUNT-1, \c -1 means no action selected. Scrollbar *vscroll; + uint actions_step; uint displayed_actions_on_previous_painting; ///< Actions that were available on the previous call to OnPaint() /** @@ -94,7 +95,8 @@ public: this->town = Town::Get(window_number); this->InitNested(window_number); this->vscroll = this->GetScrollbar(WID_TA_SCROLLBAR); - this->vscroll->SetCapacity((this->GetWidget(WID_TA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / FONT_HEIGHT_NORMAL); + this->actions_step = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + this->vscroll->SetCapacity((this->GetWidget(WID_TA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / this->actions_step); } virtual void OnPaint() @@ -197,12 +199,12 @@ public: case WID_TA_COMMAND_LIST: { int numact; uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); - int y = Center(r.top, this->resize.step_height); + int y = Center(r.top, this->actions_step); int pos = this->vscroll->GetPosition(); if (--pos < 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTIONS_TITLE); - y += this->resize.step_height; + y += this->actions_step; } for (int i = 0; buttons; i++, buttons >>= 1) { @@ -211,7 +213,7 @@ public: if ((buttons & 1) && --pos < 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i, this->sel_index == i ? TC_WHITE : TC_ORANGE); - y += this->resize.step_height; + y += this->actions_step; } } break; @@ -238,7 +240,8 @@ public: } case WID_TA_COMMAND_LIST: - size->height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; size->width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width; for (uint i = 0; i < TACT_COUNT; i++ ) { size->width = max(size->width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i).width); @@ -257,7 +260,7 @@ public: { switch (widget) { case WID_TA_COMMAND_LIST: { - int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, FONT_HEIGHT_NORMAL); + int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, this->actions_step); if (!IsInsideMM(y, 0, 5)) return; y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_company, this->town), y + this->vscroll->GetPosition() - 1); @@ -823,7 +826,7 @@ public: } Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD); d.width += icon_size.width + 2; - d.height = max(d.height, icon_size.height); + d.height = GetMinSizing(NWST_STEP, max(d.height, icon_size.height)); resize->height = d.height; d.height *= 5; d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; diff --git a/src/transparency_gui.cpp b/src/transparency_gui.cpp index 9e00552b68..50778fcc10 100644 --- a/src/transparency_gui.cpp +++ b/src/transparency_gui.cpp @@ -142,7 +142,7 @@ static const NWidgetPart _nested_transparency_widgets[] = { NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 1), EndContainer(), EndContainer(), /* Panel with 'invisibility' buttons. */ - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_TT_BUTTONS), SetMinimalSize(219, 13), SetDataTip(0x0, STR_TRANSPARENT_INVISIBLE_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_TT_BUTTONS), SetSizingType(NWST_STEP), SetMinimalSize(219, 13), SetDataTip(0x0, STR_TRANSPARENT_INVISIBLE_TOOLTIP), EndContainer(), }; From 94c01f0c6629da30cc70cff1270a1577d458fb41 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Fri, 9 Aug 2013 09:33:23 +0000 Subject: [PATCH 026/187] Sizing and centering of owner face window. --- src/company_gui.cpp | 206 +++++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 98 deletions(-) diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 060c796d00..3be6dec6be 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -921,102 +921,108 @@ static const NWidgetPart _nested_select_company_manager_face_widgets[] = { EndContainer(), EndContainer(), EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_MALEFEMALE), // Simple male/female face setting. - NWidget(NWID_VERTICAL), - NWidget(NWID_SPACER), SetFill(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP), - NWidget(NWID_SPACER), SetFill(0, 1), - EndContainer(), - EndContainer(), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_PARTS), // Advanced face parts setting. - NWidget(NWID_VERTICAL), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE2), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE2), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_EUR), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN, STR_FACE_SELECT_EUROPEAN), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_AFR), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN, STR_FACE_SELECT_AFRICAN), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 4), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetFill(0, 1), + + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetFill(0, 1), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_MALEFEMALE), // Simple male/female face setting. + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetFill(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP), + NWidget(NWID_SPACER), SetFill(0, 1), + EndContainer(), + EndContainer(), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_PARTS), // Advanced face parts setting. + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE2), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE2), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_EUR), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN, STR_FACE_SELECT_EUROPEAN), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_AFR), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN, STR_FACE_SELECT_AFRICAN), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 4), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetFill(0, 1), + EndContainer(), EndContainer(), EndContainer(), + NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), @@ -1066,7 +1072,7 @@ class SelectCompanyManagerFaceWindow : public Window /* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */ DrawString(nwi_widget->pos_x + nwi_widget->IsLowered(), nwi_widget->pos_x + nwi_widget->current_x - 1 - nwi_widget->IsLowered(), - nwi_widget->pos_y + 1 + nwi_widget->IsLowered(), str, TC_WHITE, SA_HOR_CENTER); + Center(nwi_widget->pos_y + nwi_widget->IsLowered(), nwi_widget->current_y), str, TC_WHITE, SA_HOR_CENTER); } } @@ -1116,6 +1122,10 @@ public: Dimension yesno_dim = maxdim(GetStringBoundingBox(STR_FACE_YES), GetStringBoundingBox(STR_FACE_NO)); yesno_dim.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; yesno_dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + + yesno_dim.width = GetMinSizing(NWST_STEP, yesno_dim.width); + yesno_dim.height = GetMinSizing(NWST_STEP, yesno_dim.height); + /* Size of the number button + arrows. */ Dimension number_dim = {0, 0}; for (int val = 1; val <= 12; val++) { @@ -1252,12 +1262,12 @@ public: case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT: case WID_SCMF_TIE_EARRING_TEXT: { StringID str = PART_TEXTS_IS_FEMALE[(widget - WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT) * 2 + this->is_female]; - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_GOLD, SA_RIGHT); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(r.top, r.bottom - r.top), str, TC_GOLD, SA_RIGHT); break; } case WID_SCMF_LIPS_MOUSTACHE_TEXT: - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, (this->is_moust_male) ? STR_FACE_MOUSTACHE : STR_FACE_LIPS, TC_GOLD, SA_RIGHT); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(r.top, r.bottom - r.top), (this->is_moust_male) ? STR_FACE_MOUSTACHE : STR_FACE_LIPS, TC_GOLD, SA_RIGHT); break; case WID_SCMF_HAS_GLASSES_TEXT: @@ -1269,7 +1279,7 @@ public: case WID_SCMF_CHIN_TEXT: case WID_SCMF_JACKET_TEXT: case WID_SCMF_COLLAR_TEXT: - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, PART_TEXTS[widget - WID_SCMF_HAS_GLASSES_TEXT], TC_GOLD, SA_RIGHT); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(r.top, r.bottom - r.top), PART_TEXTS[widget - WID_SCMF_HAS_GLASSES_TEXT], TC_GOLD, SA_RIGHT); break; From 7b2156d15ede23c893700e2b90315e0cbc04c3c5 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sun, 11 Aug 2013 12:27:04 +0000 Subject: [PATCH 027/187] Sizing and centering of vehicle image on refit window. --- src/vehicle_gui.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 8b1700e7c0..79e9e9216b 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -653,7 +653,7 @@ struct RefitWindow : public Window { break; case WID_VR_VEHICLE_PANEL_DISPLAY: - size->height = GetVehicleHeight(Vehicle::Get(this->window_number)->type); + size->height = max(GetMinSizing(NWST_STEP), GetVehicleHeight(Vehicle::Get(this->window_number)->type)); break; case WID_VR_INFO: @@ -713,11 +713,12 @@ struct RefitWindow : public Window { case WID_VR_VEHICLE_PANEL_DISPLAY: { Vehicle *v = Vehicle::Get(this->window_number); DrawVehicleImage(v, this->sprite_left + WD_FRAMERECT_LEFT, this->sprite_right - WD_FRAMERECT_RIGHT, - r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != NULL ? this->hscroll->GetPosition() : 0); + r.top, r.bottom - r.top + 1, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != NULL ? this->hscroll->GetPosition() : 0); /* Highlight selected vehicles. */ if (this->order != INVALID_VEH_ORDER_ID) break; int x = 0; + int y_offset_frame = Center(0, r.bottom - r.top + 1, 14); switch (v->type) { case VEH_TRAIN: { VehicleSet vehicles_to_refit; @@ -750,7 +751,7 @@ struct RefitWindow : public Window { } if (left != right) { - DrawFrameRect(left, r.top + WD_FRAMERECT_TOP, right, r.top + WD_FRAMERECT_TOP + 13, COLOUR_WHITE, FR_BORDERONLY); + DrawFrameRect(left, r.top + y_offset_frame, right, r.top + y_offset_frame + 13, COLOUR_WHITE, FR_BORDERONLY); } left = INT32_MIN; From 7b1560dcb6ee6674be83ef3b2094124355ece23b Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 10 Aug 2013 15:23:33 +0000 Subject: [PATCH 028/187] Center sprites on station picker for road stations and rail stations. --- src/rail_gui.cpp | 15 +++++++++------ src/road_gui.cpp | 6 +++++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index cb4f16f12f..6b90d00a05 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1092,8 +1092,9 @@ public: if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; - if (!DrawStationTile(32, 28, _cur_railtype, AXIS_X, _railstation.station_class, _railstation.station_type)) { - StationPickerDrawSprite(32, 28, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2); + int x = Center(TILE_PIXELS, r.right - r.left, 2 * TILE_PIXELS); + if (!DrawStationTile(x, 28, _cur_railtype, AXIS_X, _railstation.station_class, _railstation.station_type)) { + StationPickerDrawSprite(x, 28, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2); } _cur_dpi = old_dpi; } @@ -1104,8 +1105,9 @@ public: if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; - if (!DrawStationTile(32, 28, _cur_railtype, AXIS_Y, _railstation.station_class, _railstation.station_type)) { - StationPickerDrawSprite(32, 28, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 3); + int x = Center(TILE_PIXELS, r.right - r.left, 2 * TILE_PIXELS); + if (!DrawStationTile(x, 28, _cur_railtype, AXIS_Y, _railstation.station_class, _railstation.station_type)) { + StationPickerDrawSprite(x, 28, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 3); } _cur_dpi = old_dpi; } @@ -1140,8 +1142,9 @@ public: if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; - if (!DrawStationTile(32, 28, _cur_railtype, _railstation.orientation, _railstation.station_class, type)) { - StationPickerDrawSprite(32, 28, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2 + _railstation.orientation); + int x = Center(TILE_PIXELS, r.right - r.left, 2 * TILE_PIXELS); + if (!DrawStationTile(x, 28, _cur_railtype, _railstation.orientation, _railstation.station_class, type)) { + StationPickerDrawSprite(x, 28, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2 + _railstation.orientation); } _cur_dpi = old_dpi; } diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 04387cbb7d..e0b83758ca 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -992,8 +992,12 @@ struct BuildRoadStationWindow : public PickerWindowBase { { if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return; + int x = Center(r.left + TILE_PIXELS, r.right - r.left, 2 * TILE_PIXELS); + /* Height of bus/truck sprite in OpenGFX is TILE_PIXELS + 11. */ + int y = Center(r.top + WD_FRAMERECT_TOP - WD_MATRIX_BOTTOM + IsWidgetLowered(widget) + 11, r.bottom - r.top, TILE_PIXELS + 11); + StationType st = (this->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK; - StationPickerDrawSprite(r.left + TILE_PIXELS, r.bottom - TILE_PIXELS, st, INVALID_RAILTYPE, widget < WID_BROS_STATION_X ? ROADTYPE_ROAD : _cur_roadtype, widget - WID_BROS_STATION_NE); + StationPickerDrawSprite(x, y, st, INVALID_RAILTYPE, widget < WID_BROS_STATION_X ? ROADTYPE_ROAD : _cur_roadtype, widget - WID_BROS_STATION_NE); } virtual void OnClick(Point pt, int widget, int click_count) From a8a48d097b0d80987c191961897f96d66149835b Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 10 Aug 2013 15:19:00 +0000 Subject: [PATCH 029/187] Center sprites on bridge picker window. --- src/bridge_gui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp index 61c477aeac..78e7ff811f 100644 --- a/src/bridge_gui.cpp +++ b/src/bridge_gui.cpp @@ -231,7 +231,8 @@ public: SetDParam(1, b->speed); SetDParam(0, b->material); - DrawSprite(b->sprite, b->pal, r.left + WD_MATRIX_LEFT, y + this->resize.step_height - 1 - GetSpriteSize(b->sprite).height); + uint y_sprite = Center(y, this->resize.step_height, GetSpriteSize(b->sprite).height); + DrawSprite(b->sprite, b->pal, r.left + WD_MATRIX_LEFT, y_sprite); DrawStringMultiLine(r.left + this->bridgetext_offset, r.right, y + 2, y + this->resize.step_height, _game_mode == GM_EDITOR ? STR_SELECT_BRIDGE_SCENEDIT_INFO : STR_SELECT_BRIDGE_INFO); y += this->resize.step_height; From 4be55758ae6ae46c50784f61633d742fa845160a Mon Sep 17 00:00:00 2001 From: Juanjo Date: Thu, 26 Sep 2013 11:50:35 +0000 Subject: [PATCH 030/187] Center vehicle status icon. --- src/vehicle_gui.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 79e9e9216b..ce1865db70 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -2627,13 +2627,14 @@ public: /* Draw the flag plus orders. */ bool rtl = (_current_text_dir == TD_RTL); - uint text_offset = max(GetSpriteSize(SPR_FLAG_VEH_STOPPED).width, GetSpriteSize(SPR_FLAG_VEH_RUNNING).width) + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; + int image = ((v->vehstatus & VS_STOPPED) != 0) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING; + Dimension d = GetSpriteSize(image); + uint text_offset = d.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; int text_left = r.left + (rtl ? (uint)WD_FRAMERECT_LEFT : text_offset); int text_right = r.right - (rtl ? text_offset : (uint)WD_FRAMERECT_RIGHT); int image_left = (rtl ? text_right + 1 : r.left) + WD_IMGBTN_LEFT; - int image = ((v->vehstatus & VS_STOPPED) != 0) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING; int lowered = this->IsWidgetLowered(WID_VV_START_STOP) ? 1 : 0; - DrawSprite(image, PAL_NONE, image_left + lowered, r.top + WD_IMGBTN_TOP + lowered); + DrawSprite(image, PAL_NONE, image_left + lowered, Center(r.top + WD_IMGBTN_TOP + lowered, r.bottom - r.top, d.height)); DrawString(text_left + lowered, text_right + lowered, Center(r.top + lowered, r.bottom - r.top), str, TC_FROMSTRING, SA_HOR_CENTER); } From 723d9b6256f70e1844cb0bf7ba150f9694cf544c Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sun, 6 Oct 2013 14:52:43 +0000 Subject: [PATCH 031/187] Center cargo icons on station GUI. --- src/station_gui.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/station_gui.cpp b/src/station_gui.cpp index e57be72c86..f6b1d1f804 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -826,17 +826,19 @@ static const NWidgetPart _nested_station_view_widgets[] = { * @param y y coordinate * @param width the width of the view */ -static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int y) +static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int top, int bottom) { - uint num = min((waiting + 5) / 10, (right - left) / 10); // maximum is width / 10 icons so it won't overflow + SpriteID sprite = CargoSpec::Get(i)->GetCargoIcon(); + Dimension d = GetSpriteSize(sprite); + + uint num = min((waiting + 5) / d.width, (right - left) / d.width); // maximum is width / 10 icons so it won't overflow if (num == 0) return; - SpriteID sprite = CargoSpec::Get(i)->GetCargoIcon(); - - int x = _current_text_dir == TD_RTL ? left : right - num * 10; + int x = _current_text_dir == TD_RTL ? left : right - num * d.width; + int y = Center(top, bottom - top, d.height); do { DrawSprite(sprite, PAL_NONE, x, y); - x += 10; + x += d.width; } while (--num); } @@ -1762,7 +1764,7 @@ struct StationViewWindow : public Window { if (this->groupings[column] == GR_CARGO) { str = STR_STATION_VIEW_WAITING_CARGO; - DrawCargoIcons(cd->GetCargo(), cd->GetCount(), r.left + WD_FRAMERECT_LEFT + this->expand_shrink_width, r.right - WD_FRAMERECT_RIGHT - this->expand_shrink_width, y); + DrawCargoIcons(cd->GetCargo(), cd->GetCount(), r.left + WD_FRAMERECT_LEFT + this->expand_shrink_width, r.right - WD_FRAMERECT_RIGHT - this->expand_shrink_width, y, y + FONT_HEIGHT_NORMAL); } else { if (!auto_distributed) grouping = GR_SOURCE; StationID station = cd->GetStation(); From d0c26fac56c15653a9b60ca3d25c7645ebbdd556 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Fri, 2 Aug 2013 18:36:00 +0000 Subject: [PATCH 032/187] Add a specific min sizing for onscreen keyboard. --- src/osk_gui.cpp | 16 ++++++++-------- src/widget.cpp | 3 +++ src/widget_type.h | 1 + 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp index 9445595ec2..104f6f4921 100644 --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -106,7 +106,7 @@ struct OskWindow : public Window { widget -= WID_OSK_LETTERS; DrawCharCentered(_keyboard[this->shift][widget], - r.left + 8, + (r.left + r.right) / 2, r.top + 3, TC_BLACK); } @@ -230,7 +230,7 @@ static const int INTER_KEY_SPACE = 2; // Number of pixels between two keys. */ static void AddKey(NWidgetHorizontal *hor, int height, int num_half, WidgetType widtype, int widnum, uint16 widdata, int *biggest_index) { - int min_half_key = max(GetMinSizing(NWST_BUTTON) / 2, HALF_KEY_WIDTH); + int min_half_key = max(GetMinSizing(NWST_BUTTON), HALF_KEY_WIDTH); int key_width = min_half_key + (INTER_KEY_SPACE + min_half_key) * (num_half - 1); if (widtype == NWID_SPACER) { @@ -254,7 +254,7 @@ static void AddKey(NWidgetHorizontal *hor, int height, int num_half, WidgetType static NWidgetBase *MakeTopKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontal(); - int key_height = FONT_HEIGHT_NORMAL + 2; + int key_height = GetMinSizing(NWST_KEYBOARD, FONT_HEIGHT_NORMAL + 2); AddKey(hor, key_height, 6 * 2, WWT_TEXTBTN, WID_OSK_CANCEL, STR_BUTTON_CANCEL, biggest_index); AddKey(hor, key_height, 6 * 2, WWT_TEXTBTN, WID_OSK_OK, STR_BUTTON_OK, biggest_index); @@ -266,7 +266,7 @@ static NWidgetBase *MakeTopKeys(int *biggest_index) static NWidgetBase *MakeNumberKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); - int key_height = FONT_HEIGHT_NORMAL + 6; + int key_height = GetMinSizing(NWST_KEYBOARD, FONT_HEIGHT_NORMAL + 6); for (int widnum = WID_OSK_NUMBERS_FIRST; widnum <= WID_OSK_NUMBERS_LAST; widnum++) { AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); @@ -278,7 +278,7 @@ static NWidgetBase *MakeNumberKeys(int *biggest_index) static NWidgetBase *MakeQwertyKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); - int key_height = FONT_HEIGHT_NORMAL + 6; + int key_height = GetMinSizing(NWST_KEYBOARD, FONT_HEIGHT_NORMAL + 6); AddKey(hor, key_height, 3, WWT_PUSHIMGBTN, WID_OSK_SPECIAL, SPR_OSK_SPECIAL, biggest_index); for (int widnum = WID_OSK_QWERTY_FIRST; widnum <= WID_OSK_QWERTY_LAST; widnum++) { @@ -292,7 +292,7 @@ static NWidgetBase *MakeQwertyKeys(int *biggest_index) static NWidgetBase *MakeAsdfgKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); - int key_height = FONT_HEIGHT_NORMAL + 6; + int key_height = GetMinSizing(NWST_KEYBOARD, FONT_HEIGHT_NORMAL + 6); AddKey(hor, key_height, 4, WWT_IMGBTN, WID_OSK_CAPS, SPR_OSK_CAPS, biggest_index); for (int widnum = WID_OSK_ASDFG_FIRST; widnum <= WID_OSK_ASDFG_LAST; widnum++) { @@ -305,7 +305,7 @@ static NWidgetBase *MakeAsdfgKeys(int *biggest_index) static NWidgetBase *MakeZxcvbKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); - int key_height = FONT_HEIGHT_NORMAL + 6; + int key_height = GetMinSizing(NWST_KEYBOARD, FONT_HEIGHT_NORMAL + 6); AddKey(hor, key_height, 3, WWT_IMGBTN, WID_OSK_SHIFT, SPR_OSK_SHIFT, biggest_index); for (int widnum = WID_OSK_ZXCVB_FIRST; widnum <= WID_OSK_ZXCVB_LAST; widnum++) { @@ -319,7 +319,7 @@ static NWidgetBase *MakeZxcvbKeys(int *biggest_index) static NWidgetBase *MakeSpacebarKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontal(); - int key_height = FONT_HEIGHT_NORMAL + 6; + int key_height = GetMinSizing(NWST_KEYBOARD, FONT_HEIGHT_NORMAL + 6); AddKey(hor, key_height, 8, NWID_SPACER, 0, 0, biggest_index); AddKey(hor, key_height, 13, WWT_PUSHTXTBTN, WID_OSK_SPACE, STR_EMPTY, biggest_index); diff --git a/src/widget.cpp b/src/widget.cpp index 98e1561771..1acdcf74d7 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -2922,6 +2922,9 @@ uint GetMinSizing(NWidSizingType type, uint min_1) case NWST_STEP: min_sizing = _settings_client.gui.min_step; break; + case NWST_KEYBOARD: + min_sizing = 2 * _settings_client.gui.min_button; + break; default: NOT_REACHED(); } diff --git a/src/widget_type.h b/src/widget_type.h index 100309632e..f2e015c957 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -47,6 +47,7 @@ enum NWidSizingType { ///< Later, they are automatically set to NWST_BUTTON or NWST_STEP. NWST_BUTTON, ///< Size will be set at least _settings_client.gui.min_button. NWST_STEP, ///< Size will be set at least _settings_client.gui.min_step (scrollbars and dropdowns). + NWST_KEYBOARD, ///< Size for keyboard keys. NWST_OVERRIDE, ///< Avoid widgets to use automatic minimal sizing. NWST_END }; From 97e285fee56a669e24649aead0e6d4da71d96069 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Fri, 9 Aug 2013 08:34:39 +0000 Subject: [PATCH 033/187] Add a min sizing for width of command errors, news and query windows. --- src/error_gui.cpp | 1 + src/misc_gui.cpp | 1 + src/misc_gui.cpp.orig | 5 +- src/news_gui.cpp | 1 + src/widget.cpp | 3 ++ src/widget.cpp.orig | 104 ++++++++++++++++++++++++++++++++++++++++-- src/widget_type.h | 15 +++--- 7 files changed, 116 insertions(+), 14 deletions(-) diff --git a/src/error_gui.cpp b/src/error_gui.cpp index 5e8f52432d..1914826b7e 100644 --- a/src/error_gui.cpp +++ b/src/error_gui.cpp @@ -185,6 +185,7 @@ public: CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack); + size->width = GetMinSizing(NWST_WINDOW_LENGTH, size->width); int text_width = max(0, (int)size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT); this->height_summary = GetStringHeight(this->summary_msg, text_width); this->height_detailed = (this->detailed_msg == INVALID_STRING_ID) ? 0 : GetStringHeight(this->detailed_msg, text_width); diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 1746573c90..62838285a2 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -1101,6 +1101,7 @@ struct QueryWindow : public Window { { if (widget != WID_Q_TEXT) return; + size->width = GetMinSizing(NWST_WINDOW_LENGTH, size->width); Dimension d = GetStringMultiLineBoundingBox(this->message, *size); d.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; diff --git a/src/misc_gui.cpp.orig b/src/misc_gui.cpp.orig index 71af9c33ae..1746573c90 100644 --- a/src/misc_gui.cpp.orig +++ b/src/misc_gui.cpp.orig @@ -786,11 +786,12 @@ void QueryString::DrawEditBox(const Window *w, int wid) const /* If we have a marked area, draw a background highlight. */ if (tb->marklength != 0) GfxFillRect(delta + tb->markxoffs, 0, delta + tb->markxoffs + tb->marklength - 1, bottom - top, PC_GREY); - DrawString(delta, tb->pixels, 0, tb->buf, TC_YELLOW); + DrawString(delta, tb->pixels, Center(0, bottom - top), tb->buf, TC_YELLOW); + bool focussed = w->IsWidgetGloballyFocused(wid) || IsOSKOpenedFor(w, wid); if (focussed && tb->caret) { int caret_width = GetStringBoundingBox("_").width; - DrawString(tb->caretxoffs + delta, tb->caretxoffs + delta + caret_width, 0, "_", TC_WHITE); + DrawString(tb->caretxoffs + delta, tb->caretxoffs + delta + caret_width, Center(0, bottom - top), "_", TC_WHITE); } _cur_dpi = old_dpi; diff --git a/src/news_gui.cpp b/src/news_gui.cpp index 97d4f795ea..ba4b557db3 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -315,6 +315,7 @@ struct NewsWindow : Window { StringID str = STR_NULL; switch (widget) { case WID_N_MESSAGE: + size->width = GetMinSizing(NWST_WINDOW_LENGTH, size->width); CopyInDParam(0, this->ni->params, lengthof(this->ni->params)); str = this->ni->string_id; break; diff --git a/src/widget.cpp b/src/widget.cpp index 1acdcf74d7..437d2fdf3f 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -2925,6 +2925,9 @@ uint GetMinSizing(NWidSizingType type, uint min_1) case NWST_KEYBOARD: min_sizing = 2 * _settings_client.gui.min_button; break; + case NWST_WINDOW_LENGTH: + min_sizing = 8 * _settings_client.gui.min_button; + break; default: NOT_REACHED(); } diff --git a/src/widget.cpp.orig b/src/widget.cpp.orig index 534909066a..1acdcf74d7 100644 --- a/src/widget.cpp.orig +++ b/src/widget.cpp.orig @@ -523,7 +523,7 @@ static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicke { int text_offset = max(0, ((int)(r.bottom - r.top + 1) - FONT_HEIGHT_NORMAL) / 2); // Offset for rendering the text vertically centered - int dd_width = NWidgetLeaf::dropdown_dimension.width; + int dd_width = GetMinSizing(NWST_STEP, NWidgetLeaf::dropdown_dimension.width); if (_current_text_dir == TD_LTR) { DrawFrameRect(r.left, r.top, r.right - dd_width, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); @@ -746,6 +746,7 @@ NWidgetBase *NWidgetBase::GetWidgetOfType(WidgetType tp) */ NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : NWidgetBase(tp) { + this->sizing_type = NWST_NONE; this->fill_x = fill_x; this->fill_y = fill_y; } @@ -757,8 +758,23 @@ NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : */ void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y) { - this->min_x = min_x; - this->min_y = min_y; + uint min_size = 0; + switch (this->sizing_type) { + case NWST_NONE: + case NWST_OVERRIDE: + min_size = 0; + break; + case NWST_BUTTON: + min_size = _settings_client.gui.min_button; + break; + case NWST_STEP: + min_size = _settings_client.gui.min_step; + break; + default: NOT_REACHED(); + } + + this->min_x = max(min_x, min_size); + this->min_y = max(min_y, min_size); } /** @@ -810,6 +826,7 @@ void NWidgetResizeBase::AssignSizePosition(SizingType sizing, uint x, uint y, ui */ NWidgetCore::NWidgetCore(WidgetType tp, Colours colour, uint fill_x, uint fill_y, uint32 widget_data, StringID tool_tip) : NWidgetResizeBase(tp, fill_x, fill_y) { + this->sizing_type = NWST_NONE; this->colour = colour; this->index = -1; this->widget_data = widget_data; @@ -1930,6 +1947,7 @@ void Scrollbar::SetCapacityFromWidget(Window *w, int widget, int padding) NWidgetScrollbar::NWidgetScrollbar(WidgetType tp, Colours colour, int index) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL), Scrollbar(tp != NWID_HSCROLLBAR) { assert(tp == NWID_HSCROLLBAR || tp == NWID_VSCROLLBAR); + this->sizing_type = NWST_STEP; this->SetIndex(index); switch (this->type) { @@ -2001,7 +2019,9 @@ void NWidgetScrollbar::Draw(const Window *w) if (vertical_dimension.width == 0) { vertical_dimension = maxdim(GetSpriteSize(SPR_ARROW_UP), GetSpriteSize(SPR_ARROW_DOWN)); vertical_dimension.width += extra.width; + vertical_dimension.width = GetMinSizing(NWST_STEP, vertical_dimension.width); vertical_dimension.height += extra.height; + vertical_dimension.height = GetMinSizing(NWST_STEP, vertical_dimension.height); } return vertical_dimension; } @@ -2012,7 +2032,9 @@ void NWidgetScrollbar::Draw(const Window *w) if (horizontal_dimension.width == 0) { horizontal_dimension = maxdim(GetSpriteSize(SPR_ARROW_LEFT), GetSpriteSize(SPR_ARROW_RIGHT)); horizontal_dimension.width += extra.width; + horizontal_dimension.width = GetMinSizing(NWST_STEP, horizontal_dimension.width); horizontal_dimension.height += extra.height; + horizontal_dimension.height = GetMinSizing(NWST_STEP, horizontal_dimension.height); } return horizontal_dimension; } @@ -2050,8 +2072,40 @@ Dimension NWidgetLeaf::dropdown_dimension = {0, 0}; */ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, StringID tip) : NWidgetCore(tp, colour, 1, 1, data, tip) { + assert(this->sizing_type < NWST_END); assert(index >= 0 || tp == WWT_LABEL || tp == WWT_TEXT || tp == WWT_CAPTION || tp == WWT_RESIZEBOX || tp == WWT_SHADEBOX || tp == WWT_DEFSIZEBOX || tp == WWT_DEBUGBOX || tp == WWT_STICKYBOX || tp == WWT_CLOSEBOX); if (index >= 0) this->SetIndex(index); + + if (this->sizing_type == NWST_NONE) { + switch (tp) { + case WWT_PUSHBTN: + case WWT_IMGBTN: + case WWT_PUSHIMGBTN: + case WWT_IMGBTN_2: + case WWT_TEXTBTN: + case WWT_PUSHTXTBTN: + case WWT_TEXTBTN_2: + case WWT_PUSHARROWBTN: + case WWT_EDITBOX: + case WWT_CAPTION: + case WWT_STICKYBOX: + case WWT_SHADEBOX: + case WWT_DEBUGBOX: + case WWT_DEFSIZEBOX: + case WWT_RESIZEBOX: + case WWT_CLOSEBOX: + this->sizing_type = NWST_BUTTON; + break; + case NWID_PUSHBUTTON_DROPDOWN: + case NWID_BUTTON_DROPDOWN: + case WWT_DROPDOWN: + this->sizing_type = NWST_STEP; + break; + default: + this->sizing_type = NWST_OVERRIDE; + } + } + this->SetMinimalSize(0, 0); this->SetResize(0, 0); @@ -2463,11 +2517,12 @@ void NWidgetLeaf::Draw(const Window *w) */ bool NWidgetLeaf::ButtonHit(const Point &pt) { + uint button_size = GetMinSizing(NWST_STEP, 12); if (_current_text_dir == TD_LTR) { - int button_width = this->pos_x + this->current_x - 12; + int button_width = this->pos_x + this->current_x - button_size; return pt.x < button_width; } else { - int button_left = this->pos_x + 12; + int button_left = this->pos_x + button_size; return pt.x >= button_left; } } @@ -2560,6 +2615,16 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, break; } + case WPT_SIZINGTYPE: { + NWidgetResizeBase *nwrb = dynamic_cast(*dest); + if (nwrb != NULL) { + assert(parts->u.sizing_type < NWST_END); + nwrb->sizing_type = parts->u.sizing_type; + nwrb->SetMinimalSize(0, 0); + } + break; + } + case WPT_MINSIZE: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); if (nwrb != NULL) { @@ -2816,6 +2881,7 @@ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int wid } NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum); + panel->sizing_type = NWST_STEP; panel->SetMinimalSize(sprite_size.width, sprite_size.height); panel->SetFill(1, 1); panel->SetResize(1, 0); @@ -2836,3 +2902,31 @@ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int wid if (hor != NULL) vert->Add(hor); return vert; } + +/** + * Return the minimal automatic size for a widget. + * @param type The automatic sizing type to use. + * @param min_1 Minimal passed value. + * @return At least the passed value, or the minimal size for the associated sizing type. + */ +uint GetMinSizing(NWidSizingType type, uint min_1) +{ + uint min_sizing; + switch (type) { + case NWST_NONE: + case NWST_OVERRIDE: + return min_1; + case NWST_BUTTON: + min_sizing = _settings_client.gui.min_button; + break; + case NWST_STEP: + min_sizing = _settings_client.gui.min_step; + break; + case NWST_KEYBOARD: + min_sizing = 2 * _settings_client.gui.min_button; + break; + default: NOT_REACHED(); + } + + return max(min_sizing, min_1); +} diff --git a/src/widget_type.h b/src/widget_type.h index f2e015c957..6d95a2ce27 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -42,13 +42,14 @@ enum ArrowWidgetValues { /** Values for different minimal sizing of widgets. */ enum NWidSizingType { - NWST_NONE, ///< No sizing type is yet defined. - ///< Most buttons and scrollbars are initialized with this value. - ///< Later, they are automatically set to NWST_BUTTON or NWST_STEP. - NWST_BUTTON, ///< Size will be set at least _settings_client.gui.min_button. - NWST_STEP, ///< Size will be set at least _settings_client.gui.min_step (scrollbars and dropdowns). - NWST_KEYBOARD, ///< Size for keyboard keys. - NWST_OVERRIDE, ///< Avoid widgets to use automatic minimal sizing. + NWST_NONE, ///< No sizing type is yet defined. + ///< Most buttons and scrollbars are initialized with this value. + ///< Later, they are automatically set to NWST_BUTTON or NWST_STEP. + NWST_BUTTON, ///< Size will be set at least _settings_client.gui.min_button. + NWST_STEP, ///< Size will be set at least _settings_client.gui.min_step (scrollbars and dropdowns). + NWST_KEYBOARD, ///< Size for keyboard keys. + NWST_WINDOW_LENGTH, ///< Width for command errors, message windows and statusbar middle part. + NWST_OVERRIDE, ///< Avoid widgets to use automatic minimal sizing. NWST_END }; From 923bb00c0952c0bb848f6edc917c00a591732e39 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Fri, 9 Aug 2013 09:32:52 +0000 Subject: [PATCH 034/187] Add a min sizing for viewports. --- src/news_gui.cpp | 4 ++-- src/viewport_gui.cpp | 2 +- src/widget.cpp | 3 +++ src/widget_type.h | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/news_gui.cpp b/src/news_gui.cpp index ba4b557db3..9760ac8021 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -166,7 +166,7 @@ static const NWidgetPart _nested_thin_news_widgets[] = { EndContainer(), EndContainer(), NWidget(WWT_EMPTY, COLOUR_WHITE, WID_N_MESSAGE), SetMinimalSize(428, 48), SetFill(1, 0), SetPadding(0, 5, 0, 5), - NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_N_VIEWPORT), SetMinimalSize(426, 70), SetPadding(1, 2, 2, 2), + NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_N_VIEWPORT), SetSizingType(NWST_VIEWPORT), SetMinimalSize(426, 70), SetPadding(1, 2, 2, 2), EndContainer(), }; @@ -188,7 +188,7 @@ static const NWidgetPart _nested_small_news_widgets[] = { /* Main part */ NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_N_HEADLINE), NWidget(WWT_INSET, COLOUR_LIGHT_BLUE, WID_N_INSET), SetPadding(2, 2, 2, 2), - NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_N_VIEWPORT), SetPadding(1, 1, 1, 1), SetMinimalSize(274, 47), SetFill(1, 0), + NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_N_VIEWPORT), SetSizingType(NWST_VIEWPORT), SetPadding(1, 1, 1, 1), SetMinimalSize(274, 47), SetFill(1, 0), EndContainer(), NWidget(WWT_EMPTY, COLOUR_WHITE, WID_N_MESSAGE), SetMinimalSize(275, 20), SetFill(1, 0), SetPadding(0, 5, 0, 5), EndContainer(), diff --git a/src/viewport_gui.cpp b/src/viewport_gui.cpp index ab8125fa1f..7e9b3b3cc0 100644 --- a/src/viewport_gui.cpp +++ b/src/viewport_gui.cpp @@ -32,7 +32,7 @@ static const NWidgetPart _nested_extra_view_port_widgets[] = { NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), - NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_EV_VIEWPORT), SetPadding(2, 2, 2, 2), SetResize(1, 1), SetFill(1, 1), + NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_EV_VIEWPORT), SetSizingType(NWST_VIEWPORT), SetPadding(2, 2, 2, 2), SetResize(1, 1), SetFill(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_EV_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), diff --git a/src/widget.cpp b/src/widget.cpp index 437d2fdf3f..9217de0053 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -770,6 +770,9 @@ void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y) case NWST_STEP: min_size = _settings_client.gui.min_step; break; + case NWST_VIEWPORT: + min_size = 3 * _settings_client.gui.min_button; + break; default: NOT_REACHED(); } diff --git a/src/widget_type.h b/src/widget_type.h index 6d95a2ce27..43ec2e4b69 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -49,6 +49,7 @@ enum NWidSizingType { NWST_STEP, ///< Size will be set at least _settings_client.gui.min_step (scrollbars and dropdowns). NWST_KEYBOARD, ///< Size for keyboard keys. NWST_WINDOW_LENGTH, ///< Width for command errors, message windows and statusbar middle part. + NWST_VIEWPORT, ///< Sizing type for viewports. NWST_OVERRIDE, ///< Avoid widgets to use automatic minimal sizing. NWST_END }; From d95a9c61604b290557c28fd82a4bb8404bc57eef Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 27 Jul 2013 22:04:33 +0000 Subject: [PATCH 035/187] Add a setting for automatically set min sizing values. --- src/cheat_gui.cpp | 9 ++--- src/gfx.cpp | 2 ++ src/industry_gui.cpp | 2 +- src/lang/english.txt | 2 ++ src/misc_gui.cpp | 4 ++- src/settings_gui.h | 4 +-- src/settings_type.h | 1 + src/table/misc_settings.ini | 5 +++ src/window.cpp | 72 +++++++++++++++++++++++++++++++++++++ src/window_func.h | 1 + 10 files changed, 94 insertions(+), 8 deletions(-) diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp index 01ea1a488e..db6102476e 100644 --- a/src/cheat_gui.cpp +++ b/src/cheat_gui.cpp @@ -287,7 +287,7 @@ struct CheatWindow : Window { { const NWidgetBase *wid = this->GetWidget(WID_C_PANEL); - if ((pt.y - wid->pos_y - WD_FRAMERECT_TOP - this->header_height) % this->line_height > SETTING_BUTTON_HEIGHT) return; + if ((pt.y - wid->pos_y - WD_FRAMERECT_TOP - this->header_height) % this->line_height > (uint)SETTING_BUTTON_HEIGHT) return; uint btn = (pt.y - wid->pos_y - WD_FRAMERECT_TOP - this->header_height) / this->line_height; uint x = pt.x - wid->pos_x; @@ -300,7 +300,7 @@ struct CheatWindow : Window { int value = (int32)ReadValue(ce->variable, ce->type); int oldvalue = value; - if (btn == CHT_CHANGE_DATE && x >= 20 + SETTING_BUTTON_WIDTH) { + if (btn == CHT_CHANGE_DATE && x >= (20 + (uint)SETTING_BUTTON_WIDTH)) { /* Click at the date text directly. */ SetDParam(0, value); ShowQueryString(STR_JUST_INT, STR_CHEAT_CHANGE_DATE_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED); @@ -320,10 +320,11 @@ struct CheatWindow : Window { default: /* Take whatever the function returns */ - value = ce->proc(value + ((x >= 20 + SETTING_BUTTON_WIDTH / 2) ? 1 : -1), (x >= 20 + SETTING_BUTTON_WIDTH / 2) ? 1 : -1); + bool clicked_right = x >= 20 + (uint)(SETTING_BUTTON_WIDTH / 2); + value = ce->proc(value + (clicked_right ? 1 : -1), clicked_right ? 1 : -1); /* The first cheat (money), doesn't return a different value. */ - if (value != oldvalue || btn == CHT_MONEY) this->clicked = btn * 2 + 1 + ((x >= 20 + SETTING_BUTTON_WIDTH / 2) != rtl ? 1 : 0); + if (value != oldvalue || btn == CHT_MONEY) this->clicked = btn * 2 + 1 + (clicked_right != rtl ? 1 : 0); break; } diff --git a/src/gfx.cpp b/src/gfx.cpp index 13a0d4b8c8..01f29b9fb9 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -1165,6 +1165,8 @@ void ScreenSizeChanged() /* screen size changed and the old bitmap is invalid now, so we don't want to undraw it */ _cursor.visible = false; + + CheckWindowMinSizings(); } void UndrawMouseCursor() diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index c14265c087..45a62a7fd3 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -840,7 +840,7 @@ public: case EA_RATE: if (pt.y >= this->production_offset_y) { - if ((pt.y - this->production_offset_y) % GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL) > SETTING_BUTTON_HEIGHT) break;; + if ((pt.y - this->production_offset_y) % GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL) > (uint)SETTING_BUTTON_HEIGHT) break;; int row = (pt.y - this->production_offset_y) / GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); for (uint j = 0; j < lengthof(i->produced_cargo); j++) { diff --git a/src/lang/english.txt b/src/lang/english.txt index f1ef46ccf9..c6f76f5cd0 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -972,6 +972,8 @@ STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} corr STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Additional information about the base music set STR_ERROR_FULLSCREEN_FAILED :{WHITE}Fullscreen mode failed +STR_ERROR_RESET_WINDOWS :{WHITE}All windows have been reseted... +STR_ERROR_AUTOMATIC_SIZING :{WHITE}Sizes of buttons and fonts have changed # Custom currency window diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 62838285a2..d0075fe038 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -631,6 +631,8 @@ static WindowDesc _tool_tips_desc( _nested_tooltips_widgets, lengthof(_nested_tooltips_widgets) ); +uint _tooltip_width = 194; + /** Window for displaying a tooltip. */ struct TooltipsWindow : public Window { @@ -679,7 +681,7 @@ struct TooltipsWindow : public Window /* There is only one widget. */ for (uint i = 0; i != this->paramcount; i++) SetDParam(i, this->params[i]); - size->width = min(GetStringBoundingBox(this->string_id).width, 194); + size->width = min(GetStringBoundingBox(this->string_id).width, _tooltip_width); size->height = GetStringHeight(this->string_id, size->width); /* Increase slightly to have some space around the box. */ diff --git a/src/settings_gui.h b/src/settings_gui.h index 2ca418b11f..bb2a1ecfe0 100644 --- a/src/settings_gui.h +++ b/src/settings_gui.h @@ -14,8 +14,8 @@ #include "gfx_type.h" -static const int SETTING_BUTTON_WIDTH = 20; ///< Width of setting buttons -static const int SETTING_BUTTON_HEIGHT = 10; ///< Height of setting buttons +extern int SETTING_BUTTON_WIDTH; ///< Width of setting buttons +extern int SETTING_BUTTON_HEIGHT; ///< Height of setting buttons void DrawArrowButtons(int x, int y, Colours button_colour, byte state, bool clickable_left, bool clickable_right); void DrawDropDownButton(int x, int y, Colours button_colour, bool state, bool clickable); diff --git a/src/settings_type.h b/src/settings_type.h index 175ce651cf..f87c6bf354 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -79,6 +79,7 @@ struct GUISettings { bool vehicle_income_warn; ///< if a vehicle isn't generating income, show a warning uint min_button; ///< min size of most button widgets uint min_step; ///< min size of scrollbar/dropdown elements + bool manage_min_sizing; ///< automatically set min_button and min_step bool show_finances; ///< show finances at end of year bool sg_new_nonstop; ///< ttdpatch compatible nonstop handling read from pre v93 savegames bool new_nonstop; ///< ttdpatch compatible nonstop handling diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini index 0b02e69b8d..fd0207c4f3 100644 --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -228,6 +228,11 @@ min = 0 max = 100 cat = SC_EXPERT +[SDTG_BOOL] +name = ""manage_min_sizing"" +var = _settings_client.gui.manage_min_sizing +def = false + [SDTG_VAR] name = ""min_step_size"" type = SLE_UINT diff --git a/src/window.cpp b/src/window.cpp index 8f97693f60..710a9f4140 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -36,6 +36,14 @@ #include "error.h" #include "game/game.hpp" #include "video/video_driver.hpp" +#include "settings_gui.h" +#include "fontcache.h" +#include "error.h" +#include "station_base.h" +#include "waypoint_base.h" +#include "command_func.h" + +#include "table/strings.h" /** Values for _settings_client.gui.auto_scrolling */ enum ViewportAutoscrolling { @@ -1785,6 +1793,70 @@ Window *FindWindowFromPt(int x, int y) return NULL; } +int SETTING_BUTTON_WIDTH = 20; +int SETTING_BUTTON_HEIGHT = 10; + +/** + * Set button size of settings. If automatic sizing is also enabled, it also sets + * the sizing of buttons, scrollbars and font size (recommend restart). + * @todo Check if it can be moved to another file, so we do not need to include error, string and fontcache headers. + * @todo Fix magic numbers 16/18/20/30/32 + */ +void CheckWindowMinSizings() +{ + if (_settings_client.gui.manage_min_sizing) { + /* Fill the min sizing values for the current resolution. */ + uint swap_x = 32; // in longest border, let main toolbar to have 30 buttons. + uint swap_y = 16; // if short border, let main toolbar have 16/18/20 buttons..) + if (_cur_resolution.width < _cur_resolution.height) Swap(swap_x, swap_y); + _settings_client.gui.min_button = min(_cur_resolution.width / swap_x, _cur_resolution.height / swap_y); + _settings_client.gui.min_step = _settings_client.gui.min_button * 3 / 4; + } + + SETTING_BUTTON_HEIGHT = max(GetMinSizing(NWST_STEP) - 10, 10); + SETTING_BUTTON_WIDTH = 2 * SETTING_BUTTON_HEIGHT; + + extern uint _tooltip_width; + _tooltip_width = max(194, 10 * _settings_client.gui.min_button); + + if (!_settings_client.gui.manage_min_sizing) return; + + _freetype.large.size = _settings_client.gui.min_button; + _freetype.medium.size = max(_settings_client.gui.min_step * 2 / 3, 10U); + _freetype.mono.size = _freetype.medium.size; + _freetype.small.size = max(_freetype.medium.size * 2 / 3, 8U); + + InitFreeType(true); + CheckForMissingGlyphs(); + + if (_z_front_window == NULL) return; + + DeleteAllNonVitalWindows(); + + switch (_game_mode) { + default: break; + case GM_MENU: + DeleteWindowById(WC_SELECT_GAME, 0); + extern void ShowSelectGameWindow(); + ShowSelectGameWindow(); + break; + + case GM_NORMAL: + case GM_EDITOR: { + Station *st; + FOR_ALL_STATIONS(st) { st->UpdateVirtCoord(); } + Waypoint *wp; + FOR_ALL_WAYPOINTS(wp) { wp->UpdateVirtCoord(); } + + HideVitalWindows(); + ShowVitalWindows(); + break; + } + } + + ShowErrorMessage(STR_ERROR_RESET_WINDOWS, STR_ERROR_AUTOMATIC_SIZING, WL_WARNING); +} + /** * (re)initialize the windowing system */ diff --git a/src/window_func.h b/src/window_func.h index 453b889789..a0fff7c098 100644 --- a/src/window_func.h +++ b/src/window_func.h @@ -29,6 +29,7 @@ int PositionNetworkChatWindow(Window *w); int GetMainViewTop(); int GetMainViewBottom(); +void CheckWindowMinSizings(); void InitWindowSystem(); void UnInitWindowSystem(); void ResetWindowSystem(); From fd9b7efa97b31bac7edbb1e3bd447188fc7cd515 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Fri, 2 Aug 2013 18:37:51 +0000 Subject: [PATCH 036/187] Amend some widgets properties for high resolution screens. --- src/statusbar_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/statusbar_gui.cpp b/src/statusbar_gui.cpp index c06976fe2a..ed56f4b6e5 100644 --- a/src/statusbar_gui.cpp +++ b/src/statusbar_gui.cpp @@ -246,7 +246,7 @@ struct StatusBarWindow : Window { static const NWidgetPart _nested_main_status_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_S_LEFT), SetMinimalSize(140, 12), EndContainer(), - NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_S_MIDDLE), SetMinimalSize(40, 12), SetDataTip(0x0, STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS), SetResize(1, 0), + NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_S_MIDDLE), SetMinimalSize(360, 12), SetDataTip(0x0, STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS), SetResize(1, 0), NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_S_RIGHT), SetMinimalSize(140, 12), EndContainer(), }; From 0ae63b4c287579c1132bac3cd30a6aa076bf8c16 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Thu, 26 Sep 2013 11:50:14 +0000 Subject: [PATCH 037/187] Sizing and centering editbox icon. --- src/misc_gui.cpp | 4 ++-- src/widget.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index d0075fe038..8fbffbda92 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -754,7 +754,7 @@ void QueryString::DrawEditBox(const Window *w, int wid) const bool rtl = _current_text_dir == TD_RTL; Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); - int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; + int clearbtn_width = GetMinSizing(NWST_BUTTON, sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT); int clearbtn_left = wi->pos_x + (rtl ? 0 : wi->current_x - clearbtn_width); int clearbtn_right = wi->pos_x + (rtl ? clearbtn_width : wi->current_x) - 1; @@ -765,7 +765,7 @@ void QueryString::DrawEditBox(const Window *w, int wid) const int bottom = wi->pos_y + wi->current_y - 1; DrawFrameRect(clearbtn_left, top, clearbtn_right, bottom, wi->colour, wi->IsLowered() ? FR_LOWERED : FR_NONE); - DrawSprite(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT, PAL_NONE, clearbtn_left + WD_IMGBTN_LEFT + (wi->IsLowered() ? 1 : 0), (top + bottom - sprite_size.height) / 2 + (wi->IsLowered() ? 1 : 0)); + DrawSprite(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT, PAL_NONE, Center(clearbtn_left + wi->IsLowered(), clearbtn_width, sprite_size.width), Center(top + wi->IsLowered(), bottom - top, sprite_size.height)); if (this->text.bytes == 1) GfxFillRect(clearbtn_left + 1, top + 1, clearbtn_right - 1, bottom - 1, _colour_gradient[wi->colour & 0xF][2], FILLRECT_CHECKER); DrawFrameRect(left, top, right, bottom, wi->colour, FR_LOWERED | FR_DARKENED); diff --git a/src/widget.cpp b/src/widget.cpp index 9217de0053..1ead186b78 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -2135,7 +2135,7 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, case WWT_EDITBOX: { Dimension sprite_size = GetSpriteSize(_current_text_dir == TD_RTL ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); - this->SetMinimalSize(30 + sprite_size.width, sprite_size.height); + this->SetMinimalSize(30 + GetMinSizing(NWST_BUTTON, sprite_size.width), sprite_size.height); this->SetFill(0, 0); break; } From e69bbbf0dab7d6c7e9cdeea43d27dca58e29dbe2 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 21 Oct 2013 20:34:05 +0000 Subject: [PATCH 038/187] Sizing and centering on create scenario window. --- src/genworld_gui.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index d43899c4ab..902f47a097 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -936,7 +936,9 @@ struct CreateScenarioWindow : public Window } *size = GetStringBoundingBox(str); size->width += padding.width; + size->width = GetMinSizing(NWST_BUTTON, size->width); size->height += padding.height; + size->height = GetMinSizing(NWST_BUTTON, size->height); } virtual void OnClick(Point pt, int widget, int click_count) @@ -1055,11 +1057,16 @@ static const NWidgetPart _nested_create_scenario_widgets[] = { NWidget(NWID_SPACER), SetMinimalSize(0, 10), /* Landscape style selection. */ NWidget(NWID_HORIZONTAL), SetPIP(10, 3, 10), + NWidget(NWID_SPACER), SetFill(1, 1), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_CS_TEMPERATE), SetDataTip(SPR_SELECT_TEMPERATE, STR_INTRO_TOOLTIP_TEMPERATE), + NWidget(NWID_SPACER), SetFill(1, 1), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_CS_ARCTIC), SetDataTip(SPR_SELECT_SUB_ARCTIC, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE), + NWidget(NWID_SPACER), SetFill(1, 1), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_CS_TROPICAL), SetDataTip(SPR_SELECT_SUB_TROPICAL, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE), + NWidget(NWID_SPACER), SetFill(1, 1), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_CS_TOYLAND), SetDataTip(SPR_SELECT_TOYLAND, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE), - EndContainer(), + NWidget(NWID_SPACER), SetFill(1, 1), + EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(10, 8, 10), /* Green generation type buttons: 'Flat land' and 'Random land'. */ NWidget(NWID_VERTICAL), SetPIP(10, 6, 10), From 98c2f0647ed6fcbf3f2c70676cb5046aa1b8450e Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 15 Mar 2014 21:39:03 +0200 Subject: [PATCH 039/187] Removing leftovers of my sloppy merging --- src/airport_gui.cpp.orig | 574 -- src/autoreplace_gui.cpp.orig | 624 --- src/build_vehicle_gui.cpp.orig | 1427 ----- src/error_gui.cpp.orig | 432 -- src/gfx.cpp.orig | 1697 ------ src/gfx_func.h.orig | 226 - src/group_gui.cpp.orig | 891 --- src/industry_gui.cpp.orig | 2715 --------- src/lang/english.txt.orig | 4887 ----------------- src/misc_gui.cpp.orig | 1210 ---- src/osk_gui.cpp.orig | 459 -- src/rail_gui.cpp.orig | 1991 ------- src/road_gui.cpp.orig | 1092 ---- src/script/api/game/game_window.hpp.sq.orig | 1328 ----- src/script/api/script_window.hpp.orig | 2579 --------- .../api/template/template_window.hpp.sq.orig | 257 - src/settings.cpp.orig | 2174 -------- src/settings.cpp.rej | 11 - src/settings_gui.cpp.orig | 2649 --------- src/smallmap_gui.cpp.orig | 1827 ------ src/smallmap_gui.h.orig | 192 - src/station_base.h.orig | 534 -- src/station_gui.cpp.orig | 2450 --------- src/terraform_gui.cpp.orig | 760 --- src/toolbar_gui.cpp.orig | 2230 -------- src/town_gui.cpp.orig | 1199 ---- src/vehicle_gui.cpp.orig | 2840 ---------- src/vehicle_gui.h.orig | 104 - src/video/sdl_v.cpp.orig | 868 --- src/viewport.cpp.orig | 3012 ---------- src/widget.cpp.orig | 2932 ---------- src/window.cpp.orig | 3515 ------------ 32 files changed, 49686 deletions(-) delete mode 100644 src/airport_gui.cpp.orig delete mode 100644 src/autoreplace_gui.cpp.orig delete mode 100644 src/build_vehicle_gui.cpp.orig delete mode 100644 src/error_gui.cpp.orig delete mode 100644 src/gfx.cpp.orig delete mode 100644 src/gfx_func.h.orig delete mode 100644 src/group_gui.cpp.orig delete mode 100644 src/industry_gui.cpp.orig delete mode 100644 src/lang/english.txt.orig delete mode 100644 src/misc_gui.cpp.orig delete mode 100644 src/osk_gui.cpp.orig delete mode 100644 src/rail_gui.cpp.orig delete mode 100644 src/road_gui.cpp.orig delete mode 100644 src/script/api/game/game_window.hpp.sq.orig delete mode 100644 src/script/api/script_window.hpp.orig delete mode 100644 src/script/api/template/template_window.hpp.sq.orig delete mode 100644 src/settings.cpp.orig delete mode 100644 src/settings.cpp.rej delete mode 100644 src/settings_gui.cpp.orig delete mode 100644 src/smallmap_gui.cpp.orig delete mode 100644 src/smallmap_gui.h.orig delete mode 100644 src/station_base.h.orig delete mode 100644 src/station_gui.cpp.orig delete mode 100644 src/terraform_gui.cpp.orig delete mode 100644 src/toolbar_gui.cpp.orig delete mode 100644 src/town_gui.cpp.orig delete mode 100644 src/vehicle_gui.cpp.orig delete mode 100644 src/vehicle_gui.h.orig delete mode 100644 src/video/sdl_v.cpp.orig delete mode 100644 src/viewport.cpp.orig delete mode 100644 src/widget.cpp.orig delete mode 100644 src/window.cpp.orig diff --git a/src/airport_gui.cpp.orig b/src/airport_gui.cpp.orig deleted file mode 100644 index 0ba237c024..0000000000 --- a/src/airport_gui.cpp.orig +++ /dev/null @@ -1,574 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file airport_gui.cpp The GUI for airports. */ - -#include "stdafx.h" -#include "window_gui.h" -#include "station_gui.h" -#include "terraform_gui.h" -#include "sound_func.h" -#include "window_func.h" -#include "strings_func.h" -#include "viewport_func.h" -#include "company_func.h" -#include "tilehighlight_func.h" -#include "company_base.h" -#include "station_type.h" -#include "newgrf_airport.h" -#include "newgrf_callbacks.h" -#include "widgets/dropdown_type.h" -#include "core/geometry_func.hpp" -#include "hotkeys.h" -#include "vehicle_func.h" -#include "gui.h" - -#include "widgets/airport_widget.h" - - -static AirportClassID _selected_airport_class; ///< the currently visible airport class -static int _selected_airport_index; ///< the index of the selected airport in the current class or -1 -static byte _selected_airport_layout; ///< selected airport layout number. - -static void ShowBuildAirportPicker(Window *parent); - -SpriteID GetCustomAirportSprite(const AirportSpec *as, byte layout); - -void CcBuildAirport(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Failed()) return; - - if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); - if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); -} - -/** - * Place an airport. - * @param tile Position to put the new airport. - */ -static void PlaceAirport(TileIndex tile) -{ - if (_selected_airport_index == -1) return; - uint32 p2 = _ctrl_pressed; - SB(p2, 16, 16, INVALID_STATION); // no station to join - - uint32 p1 = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index)->GetIndex(); - p1 |= _selected_airport_layout << 8; - CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_AIRPORT | CMD_MSG(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE), CcBuildAirport, "" }; - ShowSelectStationIfNeeded(cmdcont, TileArea(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE)); -} - -/** Airport build toolbar window handler. */ -struct BuildAirToolbarWindow : Window { - int last_user_action; // Last started user action. - - BuildAirToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) - { - this->InitNested(window_number); - if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); - this->last_user_action = WIDGET_LIST_END; - } - - ~BuildAirToolbarWindow() - { - if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_AT_AIRPORT: - if (HandlePlacePushButton(this, WID_AT_AIRPORT, SPR_CURSOR_AIRPORT, HT_RECT)) { - ShowBuildAirportPicker(this); - this->last_user_action = widget; - } - break; - - case WID_AT_DEMOLISH: - HandlePlacePushButton(this, WID_AT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); - this->last_user_action = widget; - break; - - default: break; - } - } - - - virtual void OnPlaceObject(Point pt, TileIndex tile) - { - switch (this->last_user_action) { - case WID_AT_AIRPORT: - PlaceAirport(tile); - break; - - case WID_AT_DEMOLISH: - PlaceProc_DemolishArea(tile); - break; - - default: NOT_REACHED(); - } - } - - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) - { - VpSelectTilesWithMethod(pt.x, pt.y, select_method); - } - - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) - { - if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) { - GUIPlaceProcDragXY(select_proc, start_tile, end_tile); - } - } - - virtual void OnPlaceObjectAbort() - { - this->RaiseButtons(); - - DeleteWindowById(WC_BUILD_STATION, TRANSPORT_AIR); - DeleteWindowById(WC_SELECT_STATION, 0); - } - - static HotkeyList hotkeys; -}; - -/** - * Handler for global hotkeys of the BuildAirToolbarWindow. - * @param hotkey Hotkey - * @return ES_HANDLED if hotkey was accepted. - */ -static EventState AirportToolbarGlobalHotkeys(int hotkey) -{ - if (_game_mode != GM_NORMAL || !CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) return ES_NOT_HANDLED; - Window *w = ShowBuildAirToolbar(); - if (w == NULL) return ES_NOT_HANDLED; - return w->OnHotkey(hotkey); -} - -static Hotkey airtoolbar_hotkeys[] = { - Hotkey('1', "airport", WID_AT_AIRPORT), - Hotkey('2', "demolish", WID_AT_DEMOLISH), - HOTKEY_LIST_END -}; -HotkeyList BuildAirToolbarWindow::hotkeys("airtoolbar", airtoolbar_hotkeys, AirportToolbarGlobalHotkeys); - -static const NWidgetPart _nested_air_toolbar_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_TOOLBAR_AIRCRAFT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_AIRPORT), SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_AIRPORT, STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetFill(1, 1), EndContainer(), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_DEMOLISH), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), - EndContainer(), -}; - -static WindowDesc _air_toolbar_desc( - WDP_ALIGN_TOOLBAR, "toolbar_air", 0, 0, - WC_BUILD_TOOLBAR, WC_NONE, - WDF_CONSTRUCTION, - _nested_air_toolbar_widgets, lengthof(_nested_air_toolbar_widgets), - &BuildAirToolbarWindow::hotkeys -); - -/** - * Open the build airport toolbar window - * - * If the terraform toolbar is linked to the toolbar, that window is also opened. - * - * @return newly opened airport toolbar, or NULL if the toolbar could not be opened. - */ -Window *ShowBuildAirToolbar() -{ - if (!Company::IsValidID(_local_company)) return NULL; - - DeleteWindowByClass(WC_BUILD_TOOLBAR); - return AllocateWindowDescFront(&_air_toolbar_desc, TRANSPORT_AIR); -} - -class BuildAirportWindow : public PickerWindowBase { - SpriteID preview_sprite; ///< Cached airport preview sprite. - int line_height; - Scrollbar *vscroll; - - /** Build a dropdown list of available airport classes */ - static DropDownList *BuildAirportClassDropDown() - { - DropDownList *list = new DropDownList(); - - for (uint i = 0; i < AirportClass::GetClassCount(); i++) { - *list->Append() = new DropDownListStringItem(AirportClass::Get((AirportClassID)i)->name, i, false); - } - - return list; - } - -public: - BuildAirportWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) - { - this->CreateNestedTree(); - - this->vscroll = this->GetScrollbar(WID_AP_SCROLLBAR); - this->vscroll->SetCapacity(5); - this->vscroll->SetPosition(0); - - this->FinishInitNested(TRANSPORT_AIR); - - this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT, !_settings_client.gui.station_show_coverage); - this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT, _settings_client.gui.station_show_coverage); - this->OnInvalidateData(); - - this->vscroll->SetCount(AirportClass::Get(_selected_airport_class)->GetSpecCount()); - this->SelectFirstAvailableAirport(true); - } - - virtual ~BuildAirportWindow() - { - DeleteWindowById(WC_SELECT_STATION, 0); - } - - virtual void SetStringParameters(int widget) const - { - switch (widget) { - case WID_AP_CLASS_DROPDOWN: - SetDParam(0, AirportClass::Get(_selected_airport_class)->name); - break; - - case WID_AP_LAYOUT_NUM: - SetDParam(0, STR_EMPTY); - if (_selected_airport_index != -1) { - const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); - StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_LAYOUT_NAME); - if (string != STR_UNDEFINED) { - SetDParam(0, string); - } else if (as->num_table > 1) { - SetDParam(0, STR_STATION_BUILD_AIRPORT_LAYOUT_NAME); - SetDParam(1, _selected_airport_layout + 1); - } - } - break; - - default: break; - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_AP_CLASS_DROPDOWN: { - Dimension d = {0, 0}; - for (uint i = 0; i < AirportClass::GetClassCount(); i++) { - SetDParam(0, AirportClass::Get((AirportClassID)i)->name); - d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING)); - } - d.width += padding.width; - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - - case WID_AP_AIRPORT_LIST: { - for (int i = 0; i < NUM_AIRPORTS; i++) { - const AirportSpec *as = AirportSpec::Get(i); - if (!as->enabled) continue; - - size->width = max(size->width, GetStringBoundingBox(as->name).width); - } - - this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; - size->height = 5 * this->line_height; - break; - } - - case WID_AP_AIRPORT_SPRITE: - for (int i = 0; i < NUM_AIRPORTS; i++) { - const AirportSpec *as = AirportSpec::Get(i); - if (!as->enabled) continue; - for (byte layout = 0; layout < as->num_table; layout++) { - SpriteID sprite = GetCustomAirportSprite(as, layout); - if (sprite != 0) { - Dimension d = GetSpriteSize(sprite); - d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - *size = maxdim(d, *size); - } - } - } - break; - - case WID_AP_EXTRA_TEXT: - for (int i = NEW_AIRPORT_OFFSET; i < NUM_AIRPORTS; i++) { - const AirportSpec *as = AirportSpec::Get(i); - if (!as->enabled) continue; - for (byte layout = 0; layout < as->num_table; layout++) { - StringID string = GetAirportTextCallback(as, layout, CBID_AIRPORT_ADDITIONAL_TEXT); - if (string == STR_UNDEFINED) continue; - - /* STR_BLACK_STRING is used to start the string with {BLACK} */ - SetDParam(0, string); - Dimension d = GetStringMultiLineBoundingBox(STR_BLACK_STRING, *size); - *size = maxdim(d, *size); - } - } - break; - - default: break; - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_AP_AIRPORT_LIST: { - int y = r.top; - AirportClass *apclass = AirportClass::Get(_selected_airport_class); - for (uint i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < apclass->GetSpecCount(); i++) { - const AirportSpec *as = apclass->GetSpec(i); - if (!as->IsAvailable()) { - GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->line_height - 2, PC_BLACK, FILLRECT_CHECKER); - } - - DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, Center(y, this->line_height), as->name, ((int)i == _selected_airport_index) ? TC_WHITE : TC_BLACK); - - y += this->line_height; - } - break; - } - - case WID_AP_AIRPORT_SPRITE: - if (this->preview_sprite != 0) { - Dimension d = GetSpriteSize(this->preview_sprite); - DrawSprite(this->preview_sprite, COMPANY_SPRITE_COLOUR(_local_company), (r.left + r.right - d.width) / 2, (r.top + r.bottom - d.height) / 2); - } - break; - - case WID_AP_EXTRA_TEXT: - if (_selected_airport_index != -1) { - const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); - StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_ADDITIONAL_TEXT); - if (string != STR_UNDEFINED) { - SetDParam(0, string); - DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BLACK_STRING); - } - } - break; - } - } - - virtual void OnPaint() - { - this->DrawWidgets(); - - uint16 top = this->GetWidget(WID_AP_BTN_DOHILIGHT)->pos_y + this->GetWidget(WID_AP_BTN_DOHILIGHT)->current_y + WD_PAR_VSEP_NORMAL; - NWidgetBase *panel_nwi = this->GetWidget(WID_AP_BOTTOMPANEL); - - int right = panel_nwi->pos_x + panel_nwi->current_x; - int bottom = panel_nwi->pos_y + panel_nwi->current_y; - - if (_selected_airport_index != -1) { - const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); - int rad = _settings_game.station.modified_catchment ? as->catchment : (uint)CA_UNMODIFIED; - - /* only show the station (airport) noise, if the noise option is activated */ - if (_settings_game.economy.station_noise_level) { - /* show the noise of the selected airport */ - SetDParam(0, as->noise_level); - DrawString(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_STATION_BUILD_NOISE); - top += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; - } - - /* strings such as 'Size' and 'Coverage Area' */ - top = DrawStationCoverageAreaText(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, false) + WD_PAR_VSEP_NORMAL; - top = DrawStationCoverageAreaText(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, true) + WD_PAR_VSEP_NORMAL; - } - - /* Resize background if the window is too small. - * Never make the window smaller to avoid oscillating if the size change affects the acceptance. - * (This is the case, if making the window bigger moves the mouse into the window.) */ - if (top > bottom) { - ResizeWindow(this, 0, top - bottom); - } - } - - void SelectOtherAirport(int airport_index) - { - _selected_airport_index = airport_index; - _selected_airport_layout = 0; - - this->UpdateSelectSize(); - this->SetDirty(); - } - - void UpdateSelectSize() - { - if (_selected_airport_index == -1) { - SetTileSelectSize(1, 1); - this->DisableWidget(WID_AP_LAYOUT_DECREASE); - this->DisableWidget(WID_AP_LAYOUT_INCREASE); - } else { - const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); - int w = as->size_x; - int h = as->size_y; - Direction rotation = as->rotation[_selected_airport_layout]; - if (rotation == DIR_E || rotation == DIR_W) Swap(w, h); - SetTileSelectSize(w, h); - - this->preview_sprite = GetCustomAirportSprite(as, _selected_airport_layout); - - this->SetWidgetDisabledState(WID_AP_LAYOUT_DECREASE, _selected_airport_layout == 0); - this->SetWidgetDisabledState(WID_AP_LAYOUT_INCREASE, _selected_airport_layout + 1 >= as->num_table); - - int rad = _settings_game.station.modified_catchment ? as->catchment : (uint)CA_UNMODIFIED; - if (_settings_client.gui.station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_AP_CLASS_DROPDOWN: - ShowDropDownList(this, BuildAirportClassDropDown(), _selected_airport_class, WID_AP_CLASS_DROPDOWN); - break; - - case WID_AP_AIRPORT_LIST: { - int num_clicked = this->vscroll->GetPosition() + (pt.y - this->nested_array[widget]->pos_y) / this->line_height; - if (num_clicked >= this->vscroll->GetCount()) break; - const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(num_clicked); - if (as->IsAvailable()) this->SelectOtherAirport(num_clicked); - break; - } - - case WID_AP_BTN_DONTHILIGHT: case WID_AP_BTN_DOHILIGHT: - _settings_client.gui.station_show_coverage = (widget != WID_AP_BTN_DONTHILIGHT); - this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT, !_settings_client.gui.station_show_coverage); - this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT, _settings_client.gui.station_show_coverage); - this->SetDirty(); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->UpdateSelectSize(); - break; - - case WID_AP_LAYOUT_DECREASE: - _selected_airport_layout--; - this->UpdateSelectSize(); - this->SetDirty(); - break; - - case WID_AP_LAYOUT_INCREASE: - _selected_airport_layout++; - this->UpdateSelectSize(); - this->SetDirty(); - break; - } - } - - /** - * Select the first available airport. - * @param change_class If true, change the class if no airport in the current - * class is available. - */ - void SelectFirstAvailableAirport(bool change_class) - { - /* First try to select an airport in the selected class. */ - AirportClass *sel_apclass = AirportClass::Get(_selected_airport_class); - for (uint i = 0; i < sel_apclass->GetSpecCount(); i++) { - const AirportSpec *as = sel_apclass->GetSpec(i); - if (as->IsAvailable()) { - this->SelectOtherAirport(i); - return; - } - } - if (change_class) { - /* If that fails, select the first available airport - * from a random class. */ - for (AirportClassID j = APC_BEGIN; j < APC_MAX; j++) { - AirportClass *apclass = AirportClass::Get(j); - for (uint i = 0; i < apclass->GetSpecCount(); i++) { - const AirportSpec *as = apclass->GetSpec(i); - if (as->IsAvailable()) { - _selected_airport_class = j; - this->SelectOtherAirport(i); - return; - } - } - } - } - /* If all airports are unavailable, select nothing. */ - this->SelectOtherAirport(-1); - } - - virtual void OnDropdownSelect(int widget, int index) - { - assert(widget == WID_AP_CLASS_DROPDOWN); - _selected_airport_class = (AirportClassID)index; - this->vscroll->SetCount(AirportClass::Get(_selected_airport_class)->GetSpecCount()); - this->SelectFirstAvailableAirport(false); - } - - virtual void OnTick() - { - CheckRedrawStationCoverage(this); - } -}; - -static const NWidgetPart _nested_build_airport_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 0), SetPIP(2, 0, 2), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL, STR_NULL), SetFill(1, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_AP_CLASS_DROPDOWN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_STATION_BUILD_AIRPORT_TOOLTIP), - NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_AIRPORT_SPRITE), SetFill(1, 0), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_AP_AIRPORT_LIST), SetFill(1, 0), SetMatrixDataTip(1, 5, STR_STATION_BUILD_AIRPORT_TOOLTIP), SetScrollbar(WID_AP_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AP_SCROLLBAR), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_DECREASE), SetMinimalSize(12, 0), SetDataTip(AWV_DECREASE, STR_NULL), - NWidget(WWT_LABEL, COLOUR_GREY, WID_AP_LAYOUT_NUM), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NULL), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_INCREASE), SetMinimalSize(12, 0), SetDataTip(AWV_INCREASE, STR_NULL), - EndContainer(), - NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_EXTRA_TEXT), SetFill(1, 0), SetMinimalSize(150, 0), - EndContainer(), - /* Bottom panel. */ - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_AP_BOTTOMPANEL), SetPIP(2, 2, 2), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetFill(1, 0), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DONTHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), - SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DOHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), - SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1), SetFill(1, 0), - EndContainer(), -}; - -static WindowDesc _build_airport_desc( - WDP_AUTO, "build_station_air", 0, 0, - WC_BUILD_STATION, WC_BUILD_TOOLBAR, - WDF_CONSTRUCTION, - _nested_build_airport_widgets, lengthof(_nested_build_airport_widgets) -); - -static void ShowBuildAirportPicker(Window *parent) -{ - new BuildAirportWindow(&_build_airport_desc, parent); -} - -void InitializeAirportGui() -{ - _selected_airport_class = APC_BEGIN; - _selected_airport_index = -1; -} diff --git a/src/autoreplace_gui.cpp.orig b/src/autoreplace_gui.cpp.orig deleted file mode 100644 index dc1f5ed738..0000000000 --- a/src/autoreplace_gui.cpp.orig +++ /dev/null @@ -1,624 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file autoreplace_gui.cpp GUI for autoreplace handling. */ - -#include "stdafx.h" -#include "command_func.h" -#include "vehicle_gui.h" -#include "newgrf_engine.h" -#include "rail.h" -#include "strings_func.h" -#include "window_func.h" -#include "autoreplace_func.h" -#include "company_func.h" -#include "engine_base.h" -#include "window_gui.h" -#include "engine_gui.h" -#include "settings_func.h" -#include "core/geometry_func.hpp" -#include "rail_gui.h" -#include "widgets/dropdown_func.h" - -#include "widgets/autoreplace_widget.h" - - -uint GetEngineListHeight(VehicleType type); -void DrawEngineList(VehicleType type, int x, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group); - -static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b) -{ - int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; - - return r; -} - -/** - * Rebuild the left autoreplace list if an engine is removed or added - * @param e Engine to check if it is removed or added - * @param id_g The group the engine belongs to - * Note: this function only works if it is called either - * - when a new vehicle is build, but before it's counted in num_engines - * - when a vehicle is deleted and after it's subtracted from num_engines - * - when not changing the count (used when changing replace orders) - */ -void InvalidateAutoreplaceWindow(EngineID e, GroupID id_g) -{ - if (GetGroupNumEngines(_local_company, id_g, e) == 0 || GetGroupNumEngines(_local_company, ALL_GROUP, e) == 0) { - /* We don't have any of this engine type. - * Either we just sold the last one, we build a new one or we stopped replacing it. - * In all cases, we need to update the left list */ - InvalidateWindowData(WC_REPLACE_VEHICLE, Engine::Get(e)->type, 1); - } -} - -/** - * When an engine is made buildable or is removed from being buildable, add/remove it from the build/autoreplace lists - * @param type The type of engine - */ -void AddRemoveEngineFromAutoreplaceAndBuildWindows(VehicleType type) -{ - InvalidateWindowData(WC_REPLACE_VEHICLE, type, 0); // Update the autoreplace window - InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well -} - -static const StringID _start_replace_dropdown[] = { - STR_REPLACE_VEHICLES_NOW, - STR_REPLACE_VEHICLES_WHEN_OLD, - INVALID_STRING_ID -}; - -/** - * Window for the autoreplacing of vehicles. - */ -class ReplaceVehicleWindow : public Window { - EngineID sel_engine[2]; ///< Selected engine left and right. - GUIEngineList engines[2]; ///< Left and right list of engines. - bool replace_engines; ///< If \c true, engines are replaced, if \c false, wagons are replaced (only for trains). - bool reset_sel_engine; ///< Also reset #sel_engine while updating left and/or right (#update_left and/or #update_right) and no valid engine selected. - GroupID sel_group; ///< Group selected to replace. - int details_height; ///< Minimal needed height of the details panels (found so far). - RailType sel_railtype; ///< Type of rail tracks selected. - Scrollbar *vscroll[2]; - - /** - * Figure out if an engine should be added to a list. - * @param e The EngineID. - * @param draw_left If \c true, the left list is drawn (the engines specific to the railtype you selected). - * @param show_engines If \c true, the locomotives are drawn, else the wagons are drawn (never both). - * @return \c true if the engine should be in the list (based on this check), else \c false. - */ - bool GenerateReplaceRailList(EngineID e, bool draw_left, bool show_engines) - { - const RailVehicleInfo *rvi = RailVehInfo(e); - - /* Ensure that the wagon/engine selection fits the engine. */ - if ((rvi->railveh_type == RAILVEH_WAGON) == show_engines) return false; - - if (draw_left && show_engines) { - /* Ensure that the railtype is specific to the selected one */ - if (rvi->railtype != this->sel_railtype) return false; - } - return true; - } - - - /** - * Generate an engines list - * @param draw_left true if generating the left list, otherwise false - */ - void GenerateReplaceVehList(bool draw_left) - { - EngineID selected_engine = INVALID_ENGINE; - VehicleType type = (VehicleType)this->window_number; - byte side = draw_left ? 0 : 1; - - GUIEngineList *list = &this->engines[side]; - list->Clear(); - - const Engine *e; - FOR_ALL_ENGINES_OF_TYPE(e, type) { - EngineID eid = e->index; - if (type == VEH_TRAIN && !this->GenerateReplaceRailList(eid, draw_left, this->replace_engines)) continue; // special rules for trains - - if (draw_left) { - const uint num_engines = GetGroupNumEngines(_local_company, this->sel_group, eid); - - /* Skip drawing the engines we don't have any of and haven't set for replacement */ - if (num_engines == 0 && EngineReplacementForCompany(Company::Get(_local_company), eid, this->sel_group) == INVALID_ENGINE) continue; - } else { - if (!CheckAutoreplaceValidity(this->sel_engine[0], eid, _local_company)) continue; - } - - *list->Append() = eid; - if (eid == this->sel_engine[side]) selected_engine = eid; // The selected engine is still in the list - } - this->sel_engine[side] = selected_engine; // update which engine we selected (the same or none, if it's not in the list anymore) - EngList_Sort(list, &EngineNumberSorter); - } - - /** Generate the lists */ - void GenerateLists() - { - EngineID e = this->sel_engine[0]; - - if (this->engines[0].NeedRebuild()) { - /* We need to rebuild the left engines list */ - this->GenerateReplaceVehList(true); - this->vscroll[0]->SetCount(this->engines[0].Length()); - if (this->reset_sel_engine && this->sel_engine[0] == INVALID_ENGINE && this->engines[0].Length() != 0) { - this->sel_engine[0] = this->engines[0][0]; - } - } - - if (this->engines[1].NeedRebuild() || e != this->sel_engine[0]) { - /* Either we got a request to rebuild the right engines list, or the left engines list selected a different engine */ - if (this->sel_engine[0] == INVALID_ENGINE) { - /* Always empty the right engines list when nothing is selected in the left engines list */ - this->engines[1].Clear(); - this->sel_engine[1] = INVALID_ENGINE; - } else { - if (this->reset_sel_engine && this->sel_engine[0] != INVALID_ENGINE) { - /* Select the current replacement for sel_engine[0]. */ - const Company *c = Company::Get(_local_company); - this->sel_engine[1] = EngineReplacementForCompany(c, this->sel_engine[0], this->sel_group); - } - /* Regenerate the list on the right. Note: This resets sel_engine[1] to INVALID_ENGINE, if it is no longer available. */ - this->GenerateReplaceVehList(false); - this->vscroll[1]->SetCount(this->engines[1].Length()); - if (this->reset_sel_engine && this->sel_engine[1] != INVALID_ENGINE) { - int position = 0; - for (EngineID *it = this->engines[1].Begin(); it != this->engines[1].End(); ++it) { - if (*it == this->sel_engine[1]) break; - ++position; - } - this->vscroll[1]->ScrollTowards(position); - } - } - } - /* Reset the flags about needed updates */ - this->engines[0].RebuildDone(); - this->engines[1].RebuildDone(); - this->reset_sel_engine = false; - } - - /** - * Handle click on the start replace button. - * @param replace_when_old Replace now or only when old? - */ - void ReplaceClick_StartReplace(bool replace_when_old) - { - EngineID veh_from = this->sel_engine[0]; - EngineID veh_to = this->sel_engine[1]; - DoCommandP(0, (replace_when_old ? 1 : 0) | (this->sel_group << 16), veh_from + (veh_to << 16), CMD_SET_AUTOREPLACE); - } - -public: - ReplaceVehicleWindow(WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc) - { - if (vehicletype == VEH_TRAIN) { - /* For rail vehicles find the most used vehicle type, which is usually - * better than 'just' the first/previous vehicle type. */ - uint type_count[RAILTYPE_END]; - memset(type_count, 0, sizeof(type_count)); - - const Engine *e; - FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { - if (e->u.rail.railveh_type == RAILVEH_WAGON) continue; - type_count[e->u.rail.railtype] += GetGroupNumEngines(_local_company, id_g, e->index); - } - - this->sel_railtype = RAILTYPE_BEGIN; - for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) { - if (type_count[this->sel_railtype] < type_count[rt]) this->sel_railtype = rt; - } - } - - this->replace_engines = true; // start with locomotives (all other vehicles will not read this bool) - this->engines[0].ForceRebuild(); - this->engines[1].ForceRebuild(); - this->reset_sel_engine = true; - this->details_height = ((vehicletype == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - this->sel_engine[0] = INVALID_ENGINE; - this->sel_engine[1] = INVALID_ENGINE; - - this->CreateNestedTree(); - this->vscroll[0] = this->GetScrollbar(WID_RV_LEFT_SCROLLBAR); - this->vscroll[1] = this->GetScrollbar(WID_RV_RIGHT_SCROLLBAR); - this->FinishInitNested(vehicletype); - - this->owner = _local_company; - this->sel_group = id_g; - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_RV_LEFT_MATRIX: - case WID_RV_RIGHT_MATRIX: - resize->height = GetEngineListHeight((VehicleType)this->window_number); - size->height = (this->window_number <= VEH_ROAD ? 8 : 4) * resize->height; - break; - - case WID_RV_LEFT_DETAILS: - case WID_RV_RIGHT_DETAILS: - size->height = this->details_height; - break; - - case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: { - StringID str = this->GetWidget(widget)->widget_data; - SetDParam(0, STR_CONFIG_SETTING_ON); - Dimension d = GetStringBoundingBox(str); - SetDParam(0, STR_CONFIG_SETTING_OFF); - d = maxdim(d, GetStringBoundingBox(str)); - d.width += padding.width; - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - - case WID_RV_TRAIN_ENGINEWAGON_TOGGLE: { - StringID str = this->GetWidget(widget)->widget_data; - SetDParam(0, STR_REPLACE_ENGINES); - Dimension d = GetStringBoundingBox(str); - SetDParam(0, STR_REPLACE_WAGONS); - d = maxdim(d, GetStringBoundingBox(str)); - d.width += padding.width; - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - - case WID_RV_INFO_TAB: { - SetDParam(0, STR_REPLACE_NOT_REPLACING); - Dimension d = GetStringBoundingBox(STR_BLACK_STRING); - SetDParam(0, STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED); - d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING)); - d.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; - d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - *size = maxdim(*size, d); - break; - } - - case WID_RV_TRAIN_RAILTYPE_DROPDOWN: { - Dimension d = {0, 0}; - for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { - const RailtypeInfo *rti = GetRailTypeInfo(rt); - /* Skip rail type if it has no label */ - if (rti->label == 0) continue; - d = maxdim(d, GetStringBoundingBox(rti->strings.replace_text)); - } - d.width += padding.width; - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - - case WID_RV_START_REPLACE: { - Dimension d = GetStringBoundingBox(STR_REPLACE_VEHICLES_START); - for (int i = 0; _start_replace_dropdown[i] != INVALID_STRING_ID; i++) { - d = maxdim(d, GetStringBoundingBox(_start_replace_dropdown[i])); - } - d.width += padding.width; - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - } - } - - virtual void SetStringParameters(int widget) const - { - switch (widget) { - case WID_RV_CAPTION: - SetDParam(0, STR_REPLACE_VEHICLE_TRAIN + this->window_number); - switch (this->sel_group) { - case ALL_GROUP: - SetDParam(1, STR_GROUP_ALL_TRAINS + this->window_number); - break; - - case DEFAULT_GROUP: - SetDParam(1, STR_GROUP_DEFAULT_TRAINS + this->window_number); - break; - - default: - SetDParam(1, STR_GROUP_NAME); - SetDParam(2, sel_group); - break; - } - break; - - case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: { - const Company *c = Company::Get(_local_company); - SetDParam(0, c->settings.renew_keep_length ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); - break; - } - - case WID_RV_TRAIN_ENGINEWAGON_TOGGLE: - SetDParam(0, this->replace_engines ? STR_REPLACE_ENGINES : STR_REPLACE_WAGONS); - break; - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_RV_INFO_TAB: { - const Company *c = Company::Get(_local_company); - if (this->sel_engine[0] != INVALID_ENGINE) { - if (!EngineHasReplacementForCompany(c, this->sel_engine[0], this->sel_group)) { - SetDParam(0, STR_REPLACE_NOT_REPLACING); - } else { - bool when_old = false; - EngineID e = EngineReplacementForCompany(c, this->sel_engine[0], this->sel_group, &when_old); - SetDParam(0, when_old ? STR_REPLACE_REPLACING_WHEN_OLD : STR_ENGINE_NAME); - SetDParam(1, e); - } - } else { - SetDParam(0, STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED); - } - - DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_BLACK_STRING, TC_FROMSTRING, SA_HOR_CENTER); - break; - } - - case WID_RV_LEFT_MATRIX: - case WID_RV_RIGHT_MATRIX: { - int side = (widget == WID_RV_LEFT_MATRIX) ? 0 : 1; - EngineID start = this->vscroll[side]->GetPosition(); // what is the offset for the start (scrolling) - EngineID end = min(this->vscroll[side]->GetCapacity() + start, this->engines[side].Length()); - - /* Do the actual drawing */ - DrawEngineList((VehicleType)this->window_number, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, - &this->engines[side], start, end, this->sel_engine[side], side == 0, this->sel_group); - break; - } - } - } - - virtual void OnPaint() - { - if (this->engines[0].NeedRebuild() || this->engines[1].NeedRebuild()) this->GenerateLists(); - - Company *c = Company::Get(_local_company); - - /* Disable the "Start Replacing" button if: - * Either engines list is empty - * or The selected replacement engine has a replacement (to prevent loops). */ - this->SetWidgetDisabledState(WID_RV_START_REPLACE, - this->sel_engine[0] == INVALID_ENGINE || - this->sel_engine[1] == INVALID_ENGINE || - EngineReplacementForCompany(c, this->sel_engine[1], this->sel_group) != INVALID_ENGINE); - - /* Disable the "Stop Replacing" button if: - * The left engines list (existing vehicle) is empty - * or The selected vehicle has no replacement set up */ - this->SetWidgetDisabledState(WID_RV_STOP_REPLACE, - this->sel_engine[0] == INVALID_ENGINE || - !EngineHasReplacementForCompany(c, this->sel_engine[0], this->sel_group)); - - if (this->window_number == VEH_TRAIN) { - /* sets the colour of that art thing */ - this->GetWidget(WID_RV_TRAIN_FLUFF_LEFT)->colour = _company_colours[_local_company]; - this->GetWidget(WID_RV_TRAIN_FLUFF_RIGHT)->colour = _company_colours[_local_company]; - - /* Show the selected railtype in the pulldown menu */ - this->GetWidget(WID_RV_TRAIN_RAILTYPE_DROPDOWN)->widget_data = GetRailTypeInfo(sel_railtype)->strings.replace_text; - } - - this->DrawWidgets(); - - if (!this->IsShaded()) { - int needed_height = this->details_height; - /* Draw details panels. */ - for (int side = 0; side < 2; side++) { - if (this->sel_engine[side] != INVALID_ENGINE) { - NWidgetBase *nwi = this->GetWidget(side == 0 ? WID_RV_LEFT_DETAILS : WID_RV_RIGHT_DETAILS); - int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, - nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine[side]); - needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); - } - } - if (needed_height != this->details_height) { // Details window are not high enough, enlarge them. - this->details_height = needed_height; - this->ReInit(); - return; - } - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_RV_TRAIN_ENGINEWAGON_TOGGLE: - this->replace_engines = !(this->replace_engines); - this->engines[0].ForceRebuild(); - this->reset_sel_engine = true; - this->SetDirty(); - break; - - case WID_RV_TRAIN_RAILTYPE_DROPDOWN: // Railtype selection dropdown menu - ShowDropDownList(this, GetRailTypeDropDownList(true), sel_railtype, WID_RV_TRAIN_RAILTYPE_DROPDOWN); - break; - - case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: // toggle renew_keep_length - DoCommandP(0, GetCompanySettingIndex("company.renew_keep_length"), Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1, CMD_CHANGE_COMPANY_SETTING); - break; - - case WID_RV_START_REPLACE: { // Start replacing - if (this->GetWidget(widget)->ButtonHit(pt)) { - this->HandleButtonClick(WID_RV_START_REPLACE); - ReplaceClick_StartReplace(false); - } else { - bool replacment_when_old = EngineHasReplacementWhenOldForCompany(Company::Get(_local_company), this->sel_engine[0], this->sel_group); - ShowDropDownMenu(this, _start_replace_dropdown, replacment_when_old ? 1 : 0, WID_RV_START_REPLACE, !this->replace_engines ? 1 << 1 : 0, 0); - } - break; - } - - case WID_RV_STOP_REPLACE: { // Stop replacing - EngineID veh_from = this->sel_engine[0]; - DoCommandP(0, this->sel_group << 16, veh_from + (INVALID_ENGINE << 16), CMD_SET_AUTOREPLACE); - break; - } - - case WID_RV_LEFT_MATRIX: - case WID_RV_RIGHT_MATRIX: { - byte click_side; - if (widget == WID_RV_LEFT_MATRIX) { - click_side = 0; - } else { - click_side = 1; - } - uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget); - size_t engine_count = this->engines[click_side].Length(); - - EngineID e = engine_count > i ? this->engines[click_side][i] : INVALID_ENGINE; - if (e == this->sel_engine[click_side]) break; // we clicked the one we already selected - this->sel_engine[click_side] = e; - if (click_side == 0) { - this->engines[1].ForceRebuild(); - this->reset_sel_engine = true; - } - this->SetDirty(); - break; - } - } - } - - virtual void OnDropdownSelect(int widget, int index) - { - switch (widget) { - case WID_RV_TRAIN_RAILTYPE_DROPDOWN: { - RailType temp = (RailType)index; - if (temp == sel_railtype) return; // we didn't select a new one. No need to change anything - sel_railtype = temp; - /* Reset scrollbar positions */ - this->vscroll[0]->SetPosition(0); - this->vscroll[1]->SetPosition(0); - /* Rebuild the lists */ - this->engines[0].ForceRebuild(); - this->engines[1].ForceRebuild(); - this->reset_sel_engine = true; - this->SetDirty(); - break; - } - - case WID_RV_START_REPLACE: - this->ReplaceClick_StartReplace(index != 0); - break; - } - } - - virtual void OnResize() - { - this->vscroll[0]->SetCapacityFromWidget(this, WID_RV_LEFT_MATRIX); - this->vscroll[1]->SetCapacityFromWidget(this, WID_RV_RIGHT_MATRIX); - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (data != 0) { - /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ - this->engines[0].ForceRebuild(); - } else { - this->engines[1].ForceRebuild(); - } - } -}; - -static const NWidgetPart _nested_replace_rail_vehicle_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetDataTip(STR_REPLACE_VEHICLES_WHITE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_GREY), - NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), - NWidget(WWT_STICKYBOX, COLOUR_GREY), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_LEFT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_LEFT_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_LEFT_SCROLLBAR), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_RIGHT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_RIGHT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_RIGHT_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_RIGHT_SCROLLBAR), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_LEFT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_PUSHBUTTON_DROPDOWN, COLOUR_GREY, WID_RV_START_REPLACE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON), - NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_INFO_TAB), SetMinimalSize(167, 12), SetDataTip(0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB), SetResize(1, 0), - EndContainer(), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_STOP_REPLACE), SetMinimalSize(150, 12), SetDataTip(STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_TRAIN_ENGINEWAGON_TOGGLE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_ENGINE_WAGON_SELECT, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), - NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_TRAIN_FLUFF_LEFT), SetMinimalSize(15, 12), EndContainer(), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_TRAIN_RAILTYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(0x0, STR_REPLACE_HELP_RAILTYPE), SetResize(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_TRAIN_FLUFF_RIGHT), SetMinimalSize(16, 12), EndContainer(), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_TRAIN_WAGONREMOVE_TOGGLE), SetMinimalSize(138, 12), SetDataTip(STR_REPLACE_REMOVE_WAGON, STR_REPLACE_REMOVE_WAGON_HELP), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), - EndContainer(), -}; - -static WindowDesc _replace_rail_vehicle_desc( - WDP_AUTO, "replace_vehicle_train", 500, 140, - WC_REPLACE_VEHICLE, WC_NONE, - WDF_CONSTRUCTION, - _nested_replace_rail_vehicle_widgets, lengthof(_nested_replace_rail_vehicle_widgets) -); - -static const NWidgetPart _nested_replace_vehicle_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetMinimalSize(433, 14), SetDataTip(STR_REPLACE_VEHICLES_WHITE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_GREY), - NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), - NWidget(WWT_STICKYBOX, COLOUR_GREY), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_LEFT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_LEFT_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_LEFT_SCROLLBAR), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_RIGHT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_RIGHT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_RIGHT_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_RIGHT_SCROLLBAR), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_LEFT_DETAILS), SetMinimalSize(228, 92), SetResize(1, 0), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(228, 92), SetResize(1, 0), EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_PUSHBUTTON_DROPDOWN, COLOUR_GREY, WID_RV_START_REPLACE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON), - NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_INFO_TAB), SetMinimalSize(167, 12), SetDataTip(0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB), SetResize(1, 0), EndContainer(), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_STOP_REPLACE), SetMinimalSize(138, 12), SetDataTip(STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), - EndContainer(), -}; - -static WindowDesc _replace_vehicle_desc( - WDP_AUTO, "replace_vehicle", 456, 118, - WC_REPLACE_VEHICLE, WC_NONE, - WDF_CONSTRUCTION, - _nested_replace_vehicle_widgets, lengthof(_nested_replace_vehicle_widgets) -); - -/** - * Show the autoreplace configuration window for a particular group. - * @param id_g The group to replace the vehicles for. - * @param vehicletype The type of vehicles in the group. - */ -void ShowReplaceGroupVehicleWindow(GroupID id_g, VehicleType vehicletype) -{ - DeleteWindowById(WC_REPLACE_VEHICLE, vehicletype); - new ReplaceVehicleWindow(vehicletype == VEH_TRAIN ? &_replace_rail_vehicle_desc : &_replace_vehicle_desc, vehicletype, id_g); -} diff --git a/src/build_vehicle_gui.cpp.orig b/src/build_vehicle_gui.cpp.orig deleted file mode 100644 index 410b2dbb3b..0000000000 --- a/src/build_vehicle_gui.cpp.orig +++ /dev/null @@ -1,1427 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file build_vehicle_gui.cpp GUI for building vehicles. */ - -#include "stdafx.h" -#include "engine_base.h" -#include "engine_func.h" -#include "station_base.h" -#include "network/network.h" -#include "articulated_vehicles.h" -#include "textbuf_gui.h" -#include "command_func.h" -#include "company_func.h" -#include "vehicle_gui.h" -#include "newgrf_engine.h" -#include "newgrf_text.h" -#include "group.h" -#include "string_func.h" -#include "strings_func.h" -#include "window_func.h" -#include "date_func.h" -#include "vehicle_func.h" -#include "widgets/dropdown_func.h" -#include "engine_gui.h" -#include "cargotype.h" -#include "core/geometry_func.hpp" -#include "autoreplace_func.h" - -#include "widgets/build_vehicle_widget.h" - -#include "table/strings.h" - -/** - * Get the height of a single 'entry' in the engine lists. - * @param type the vehicle type to get the height of - * @return the height for the entry - */ -uint GetEngineListHeight(VehicleType type) -{ - return max(FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM, GetVehicleImageCellSize(type, EIT_PURCHASE).height); -} - -static const NWidgetPart _nested_build_vehicle_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, WID_BV_CAPTION), SetDataTip(STR_WHITE_STRING, 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(NWID_VERTICAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASSENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), - NWidget(NWID_SPACER), SetFill(1, 1), - EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), - EndContainer(), - EndContainer(), - EndContainer(), - /* Vehicle list. */ - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_BV_LIST), SetResize(1, 1), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_BV_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BV_SCROLLBAR), - EndContainer(), - /* Panel with details. */ - NWidget(WWT_PANEL, COLOUR_GREY, WID_BV_PANEL), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), - /* Build/rename buttons, resize button. */ - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BV_BUILD_SEL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_BUILD), SetResize(1, 0), SetFill(1, 0), - EndContainer(), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_RENAME), SetResize(1, 0), SetFill(1, 0), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), - EndContainer(), -}; - -/** Special cargo filter criteria */ -static const CargoID CF_ANY = CT_NO_REFIT; ///< Show all vehicles independent of carried cargo (i.e. no filtering) -static const CargoID CF_NONE = CT_INVALID; ///< Show only vehicles which do not carry cargo (e.g. train engines) - -static bool _internal_sort_order; ///< false = descending, true = ascending -static byte _last_sort_criteria[] = {0, 0, 0, 0}; -static bool _last_sort_order[] = {false, false, false, false}; -static CargoID _last_filter_criteria[] = {CF_ANY, CF_ANY, CF_ANY, CF_ANY}; - -/** - * Determines order of engines by engineID - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b) -{ - int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; - - return _internal_sort_order ? -r : r; -} - -/** - * Determines order of engines by introduction date - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL EngineIntroDateSorter(const EngineID *a, const EngineID *b) -{ - const int va = Engine::Get(*a)->intro_date; - const int vb = Engine::Get(*b)->intro_date; - const int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/** - * Determines order of engines by name - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL EngineNameSorter(const EngineID *a, const EngineID *b) -{ - static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE }; - static char last_name[2][64] = { "\0", "\0" }; - - const EngineID va = *a; - const EngineID vb = *b; - - if (va != last_engine[0]) { - last_engine[0] = va; - SetDParam(0, va); - GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); - } - - if (vb != last_engine[1]) { - last_engine[1] = vb; - SetDParam(0, vb); - GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); - } - - int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/** - * Determines order of engines by reliability - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL EngineReliabilitySorter(const EngineID *a, const EngineID *b) -{ - const int va = Engine::Get(*a)->reliability; - const int vb = Engine::Get(*b)->reliability; - const int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/** - * Determines order of engines by purchase cost - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL EngineCostSorter(const EngineID *a, const EngineID *b) -{ - Money va = Engine::Get(*a)->GetCost(); - Money vb = Engine::Get(*b)->GetCost(); - int r = ClampToI32(va - vb); - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/** - * Determines order of engines by speed - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL EngineSpeedSorter(const EngineID *a, const EngineID *b) -{ - int va = Engine::Get(*a)->GetDisplayMaxSpeed(); - int vb = Engine::Get(*b)->GetDisplayMaxSpeed(); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/** - * Determines order of engines by power - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL EnginePowerSorter(const EngineID *a, const EngineID *b) -{ - int va = Engine::Get(*a)->GetPower(); - int vb = Engine::Get(*b)->GetPower(); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/** - * Determines order of engines by tractive effort - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL EngineTractiveEffortSorter(const EngineID *a, const EngineID *b) -{ - int va = Engine::Get(*a)->GetDisplayMaxTractiveEffort(); - int vb = Engine::Get(*b)->GetDisplayMaxTractiveEffort(); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/** - * Determines order of engines by running costs - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL EngineRunningCostSorter(const EngineID *a, const EngineID *b) -{ - Money va = Engine::Get(*a)->GetRunningCost(); - Money vb = Engine::Get(*b)->GetRunningCost(); - int r = ClampToI32(va - vb); - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/** - * Determines order of engines by running costs - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL EnginePowerVsRunningCostSorter(const EngineID *a, const EngineID *b) -{ - const Engine *e_a = Engine::Get(*a); - const Engine *e_b = Engine::Get(*b); - - /* Here we are using a few tricks to get the right sort. - * We want power/running cost, but since we usually got higher running cost than power and we store the result in an int, - * we will actually calculate cunning cost/power (to make it more than 1). - * Because of this, the return value have to be reversed as well and we return b - a instead of a - b. - * Another thing is that both power and running costs should be doubled for multiheaded engines. - * Since it would be multiplying with 2 in both numerator and denominator, it will even themselves out and we skip checking for multiheaded. */ - Money va = (e_a->GetRunningCost()) / max(1U, (uint)e_a->GetPower()); - Money vb = (e_b->GetRunningCost()) / max(1U, (uint)e_b->GetPower()); - int r = ClampToI32(vb - va); - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/* Train sorting functions */ - -/** - * Determines order of train engines by capacity - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL TrainEngineCapacitySorter(const EngineID *a, const EngineID *b) -{ - const RailVehicleInfo *rvi_a = RailVehInfo(*a); - const RailVehicleInfo *rvi_b = RailVehInfo(*b); - - int va = GetTotalCapacityOfArticulatedParts(*a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); - int vb = GetTotalCapacityOfArticulatedParts(*b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/** - * Determines order of train engines by engine / wagon - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL TrainEnginesThenWagonsSorter(const EngineID *a, const EngineID *b) -{ - int val_a = (RailVehInfo(*a)->railveh_type == RAILVEH_WAGON ? 1 : 0); - int val_b = (RailVehInfo(*b)->railveh_type == RAILVEH_WAGON ? 1 : 0); - int r = val_a - val_b; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/* Road vehicle sorting functions */ - -/** - * Determines order of road vehicles by capacity - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL RoadVehEngineCapacitySorter(const EngineID *a, const EngineID *b) -{ - int va = GetTotalCapacityOfArticulatedParts(*a); - int vb = GetTotalCapacityOfArticulatedParts(*b); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/* Ship vehicle sorting functions */ - -/** - * Determines order of ships by capacity - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL ShipEngineCapacitySorter(const EngineID *a, const EngineID *b) -{ - const Engine *e_a = Engine::Get(*a); - const Engine *e_b = Engine::Get(*b); - - int va = e_a->GetDisplayDefaultCapacity(); - int vb = e_b->GetDisplayDefaultCapacity(); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -/* Aircraft sorting functions */ - -/** - * Determines order of aircraft by cargo - * @param *a first engine to compare - * @param *b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static int CDECL AircraftEngineCargoSorter(const EngineID *a, const EngineID *b) -{ - const Engine *e_a = Engine::Get(*a); - const Engine *e_b = Engine::Get(*b); - - uint16 mail_a, mail_b; - int va = e_a->GetDisplayDefaultCapacity(&mail_a); - int vb = e_b->GetDisplayDefaultCapacity(&mail_b); - int r = va - vb; - - if (r == 0) { - /* The planes have the same passenger capacity. Check mail capacity instead */ - r = mail_a - mail_b; - - if (r == 0) { - /* Use EngineID to sort instead since we want consistent sorting */ - return EngineNumberSorter(a, b); - } - } - return _internal_sort_order ? -r : r; -} - -/** - * Determines order of aircraft by range. - * @param *a first engine to compare. - * @param *b second engine to compare. - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal. - */ -static int CDECL AircraftRangeSorter(const EngineID *a, const EngineID *b) -{ - uint16 r_a = Engine::Get(*a)->GetRange(); - uint16 r_b = Engine::Get(*b)->GetRange(); - - int r = r_a - r_b; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return _internal_sort_order ? -r : r; -} - -static EngList_SortTypeFunction * const _sorter[][11] = {{ - /* Trains */ - &EngineNumberSorter, - &EngineCostSorter, - &EngineSpeedSorter, - &EnginePowerSorter, - &EngineTractiveEffortSorter, - &EngineIntroDateSorter, - &EngineNameSorter, - &EngineRunningCostSorter, - &EnginePowerVsRunningCostSorter, - &EngineReliabilitySorter, - &TrainEngineCapacitySorter, -}, { - /* Road vehicles */ - &EngineNumberSorter, - &EngineCostSorter, - &EngineSpeedSorter, - &EnginePowerSorter, - &EngineTractiveEffortSorter, - &EngineIntroDateSorter, - &EngineNameSorter, - &EngineRunningCostSorter, - &EnginePowerVsRunningCostSorter, - &EngineReliabilitySorter, - &RoadVehEngineCapacitySorter, -}, { - /* Ships */ - &EngineNumberSorter, - &EngineCostSorter, - &EngineSpeedSorter, - &EngineIntroDateSorter, - &EngineNameSorter, - &EngineRunningCostSorter, - &EngineReliabilitySorter, - &ShipEngineCapacitySorter, -}, { - /* Aircraft */ - &EngineNumberSorter, - &EngineCostSorter, - &EngineSpeedSorter, - &EngineIntroDateSorter, - &EngineNameSorter, - &EngineRunningCostSorter, - &EngineReliabilitySorter, - &AircraftEngineCargoSorter, - &AircraftRangeSorter, -}}; - -static const StringID _sort_listing[][12] = {{ - /* Trains */ - STR_SORT_BY_ENGINE_ID, - STR_SORT_BY_COST, - STR_SORT_BY_MAX_SPEED, - STR_SORT_BY_POWER, - STR_SORT_BY_TRACTIVE_EFFORT, - STR_SORT_BY_INTRO_DATE, - STR_SORT_BY_NAME, - STR_SORT_BY_RUNNING_COST, - STR_SORT_BY_POWER_VS_RUNNING_COST, - STR_SORT_BY_RELIABILITY, - STR_SORT_BY_CARGO_CAPACITY, - INVALID_STRING_ID -}, { - /* Road vehicles */ - STR_SORT_BY_ENGINE_ID, - STR_SORT_BY_COST, - STR_SORT_BY_MAX_SPEED, - STR_SORT_BY_POWER, - STR_SORT_BY_TRACTIVE_EFFORT, - STR_SORT_BY_INTRO_DATE, - STR_SORT_BY_NAME, - STR_SORT_BY_RUNNING_COST, - STR_SORT_BY_POWER_VS_RUNNING_COST, - STR_SORT_BY_RELIABILITY, - STR_SORT_BY_CARGO_CAPACITY, - INVALID_STRING_ID -}, { - /* Ships */ - STR_SORT_BY_ENGINE_ID, - STR_SORT_BY_COST, - STR_SORT_BY_MAX_SPEED, - STR_SORT_BY_INTRO_DATE, - STR_SORT_BY_NAME, - STR_SORT_BY_RUNNING_COST, - STR_SORT_BY_RELIABILITY, - STR_SORT_BY_CARGO_CAPACITY, - INVALID_STRING_ID -}, { - /* Aircraft */ - STR_SORT_BY_ENGINE_ID, - STR_SORT_BY_COST, - STR_SORT_BY_MAX_SPEED, - STR_SORT_BY_INTRO_DATE, - STR_SORT_BY_NAME, - STR_SORT_BY_RUNNING_COST, - STR_SORT_BY_RELIABILITY, - STR_SORT_BY_CARGO_CAPACITY, - STR_SORT_BY_RANGE, - INVALID_STRING_ID -}}; - -/** Cargo filter functions */ -static bool CDECL CargoFilter(const EngineID *eid, const CargoID cid) -{ - if (cid == CF_ANY) return true; - uint32 refit_mask = GetUnionOfArticulatedRefitMasks(*eid, true) & _standard_cargo_mask; - return (cid == CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cid)); -} - -static GUIEngineList::FilterFunction * const _filter_funcs[] = { - &CargoFilter, -}; - -static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine, bool refittable) -{ - CargoArray cap = GetCapacityOfArticulatedParts(engine); - - for (CargoID c = 0; c < NUM_CARGO; c++) { - if (cap[c] == 0) continue; - - SetDParam(0, c); - SetDParam(1, cap[c]); - SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); - DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); - y += FONT_HEIGHT_NORMAL; - - /* Only show as refittable once */ - refittable = false; - } - - return y; -} - -/* Draw rail wagon specific details */ -static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi) -{ - const Engine *e = Engine::Get(engine_number); - - /* Purchase cost */ - SetDParam(0, e->GetCost()); - DrawString(left, right, y, STR_PURCHASE_INFO_COST); - y += FONT_HEIGHT_NORMAL; - - /* Wagon weight - (including cargo) */ - uint weight = e->GetDisplayWeight(); - SetDParam(0, weight); - uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16 : 0); - SetDParam(1, cargo_weight + weight); - DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT); - y += FONT_HEIGHT_NORMAL; - - /* Wagon speed limit, displayed if above zero */ - if (_settings_game.vehicle.wagon_speed_limits) { - uint max_speed = e->GetDisplayMaxSpeed(); - if (max_speed > 0) { - SetDParam(0, max_speed); - DrawString(left, right, y, STR_PURCHASE_INFO_SPEED); - y += FONT_HEIGHT_NORMAL; - } - } - - /* Running cost */ - if (rvi->running_cost_class != INVALID_PRICE) { - SetDParam(0, e->GetRunningCost()); - DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); - y += FONT_HEIGHT_NORMAL; - } - - return y; -} - -/* Draw locomotive specific details */ -static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi) -{ - const Engine *e = Engine::Get(engine_number); - - /* Purchase Cost - Engine weight */ - SetDParam(0, e->GetCost()); - SetDParam(1, e->GetDisplayWeight()); - DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT); - y += FONT_HEIGHT_NORMAL; - - /* Max speed - Engine power */ - SetDParam(0, e->GetDisplayMaxSpeed()); - SetDParam(1, e->GetPower()); - DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER); - y += FONT_HEIGHT_NORMAL; - - /* Max tractive effort - not applicable if old acceleration or maglev */ - if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(rvi->railtype)->acceleration_type != 2) { - SetDParam(0, e->GetDisplayMaxTractiveEffort()); - DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE); - y += FONT_HEIGHT_NORMAL; - } - - /* Running cost */ - if (rvi->running_cost_class != INVALID_PRICE) { - SetDParam(0, e->GetRunningCost()); - DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); - y += FONT_HEIGHT_NORMAL; - } - - /* Powered wagons power - Powered wagons extra weight */ - if (rvi->pow_wag_power != 0) { - SetDParam(0, rvi->pow_wag_power); - SetDParam(1, rvi->pow_wag_weight); - DrawString(left, right, y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT); - y += FONT_HEIGHT_NORMAL; - } - - return y; -} - -/* Draw road vehicle specific details */ -static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number) -{ - const Engine *e = Engine::Get(engine_number); - - if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) { - /* Purchase Cost */ - SetDParam(0, e->GetCost()); - DrawString(left, right, y, STR_PURCHASE_INFO_COST); - y += FONT_HEIGHT_NORMAL; - - /* Road vehicle weight - (including cargo) */ - int16 weight = e->GetDisplayWeight(); - SetDParam(0, weight); - uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16 : 0); - SetDParam(1, cargo_weight + weight); - DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT); - y += FONT_HEIGHT_NORMAL; - - /* Max speed - Engine power */ - SetDParam(0, e->GetDisplayMaxSpeed()); - SetDParam(1, e->GetPower()); - DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER); - y += FONT_HEIGHT_NORMAL; - - /* Max tractive effort */ - SetDParam(0, e->GetDisplayMaxTractiveEffort()); - DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE); - y += FONT_HEIGHT_NORMAL; - } else { - /* Purchase cost - Max speed */ - SetDParam(0, e->GetCost()); - SetDParam(1, e->GetDisplayMaxSpeed()); - DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); - y += FONT_HEIGHT_NORMAL; - } - - /* Running cost */ - SetDParam(0, e->GetRunningCost()); - DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); - y += FONT_HEIGHT_NORMAL; - - return y; -} - -/* Draw ship specific details */ -static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable) -{ - const Engine *e = Engine::Get(engine_number); - - /* Purchase cost - Max speed */ - uint raw_speed = e->GetDisplayMaxSpeed(); - uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true); - uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false); - - SetDParam(0, e->GetCost()); - if (ocean_speed == canal_speed) { - SetDParam(1, ocean_speed); - DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); - y += FONT_HEIGHT_NORMAL; - } else { - DrawString(left, right, y, STR_PURCHASE_INFO_COST); - y += FONT_HEIGHT_NORMAL; - - SetDParam(0, ocean_speed); - DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_OCEAN); - y += FONT_HEIGHT_NORMAL; - - SetDParam(0, canal_speed); - DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_CANAL); - y += FONT_HEIGHT_NORMAL; - } - - /* Cargo type + capacity */ - SetDParam(0, e->GetDefaultCargoType()); - SetDParam(1, e->GetDisplayDefaultCapacity()); - SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); - DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); - y += FONT_HEIGHT_NORMAL; - - /* Running cost */ - SetDParam(0, e->GetRunningCost()); - DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); - y += FONT_HEIGHT_NORMAL; - - return y; -} - -/* Draw aircraft specific details */ -static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable) -{ - const Engine *e = Engine::Get(engine_number); - CargoID cargo = e->GetDefaultCargoType(); - - /* Purchase cost - Max speed */ - SetDParam(0, e->GetCost()); - SetDParam(1, e->GetDisplayMaxSpeed()); - DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); - y += FONT_HEIGHT_NORMAL; - - /* Cargo capacity */ - uint16 mail_capacity; - uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity); - if (mail_capacity > 0) { - SetDParam(0, cargo); - SetDParam(1, capacity); - SetDParam(2, CT_MAIL); - SetDParam(3, mail_capacity); - DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY); - } else { - /* Note, if the default capacity is selected by the refit capacity - * callback, then the capacity shown is likely to be incorrect. */ - SetDParam(0, cargo); - SetDParam(1, capacity); - SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); - DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); - } - y += FONT_HEIGHT_NORMAL; - - /* Running cost */ - SetDParam(0, e->GetRunningCost()); - DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); - y += FONT_HEIGHT_NORMAL; - - uint16 range = e->GetRange(); - if (range != 0) { - SetDParam(0, range); - DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_RANGE); - y += FONT_HEIGHT_NORMAL; - } - - return y; -} - -/** - * Display additional text from NewGRF in the purchase information window - * @param left Left border of text bounding box - * @param right Right border of text bounding box - * @param y Top border of text bounding box - * @param engine Engine to query the additional purchase information for - * @return Bottom border of text bounding box - */ -static uint ShowAdditionalText(int left, int right, int y, EngineID engine) -{ - uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, NULL); - if (callback == CALLBACK_FAILED || callback == 0x400) return y; - const GRFFile *grffile = Engine::Get(engine)->GetGRF(); - if (callback > 0x400) { - ErrorUnknownCallbackResult(grffile->grfid, CBID_VEHICLE_ADDITIONAL_TEXT, callback); - return y; - } - - StartTextRefStackUsage(grffile, 6); - uint result = DrawStringMultiLine(left, right, y, INT32_MAX, GetGRFStringID(grffile->grfid, 0xD000 + callback), TC_BLACK); - StopTextRefStackUsage(); - return result; -} - -/** - * Draw the purchase info details of a vehicle at a given location. - * @param left,right,y location where to draw the info - * @param engine_number the engine of which to draw the info of - * @return y after drawing all the text - */ -int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number) -{ - const Engine *e = Engine::Get(engine_number); - YearMonthDay ymd; - ConvertDateToYMD(e->intro_date, &ymd); - bool refittable = IsArticulatedVehicleRefittable(engine_number); - bool articulated_cargo = false; - - switch (e->type) { - default: NOT_REACHED(); - case VEH_TRAIN: - if (e->u.rail.railveh_type == RAILVEH_WAGON) { - y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail); - } else { - y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail); - } - articulated_cargo = true; - break; - - case VEH_ROAD: - y = DrawRoadVehPurchaseInfo(left, right, y, engine_number); - articulated_cargo = true; - break; - - case VEH_SHIP: - y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable); - break; - - case VEH_AIRCRAFT: - y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable); - break; - } - - if (articulated_cargo) { - /* Cargo type + capacity, or N/A */ - int new_y = DrawCargoCapacityInfo(left, right, y, engine_number, refittable); - - if (new_y == y) { - SetDParam(0, CT_INVALID); - SetDParam(2, STR_EMPTY); - DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); - y += FONT_HEIGHT_NORMAL; - } else { - y = new_y; - } - } - - /* Draw details that apply to all types except rail wagons. */ - if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) { - /* Design date - Life length */ - SetDParam(0, ymd.year); - SetDParam(1, e->GetLifeLengthInDays() / DAYS_IN_LEAP_YEAR); - DrawString(left, right, y, STR_PURCHASE_INFO_DESIGNED_LIFE); - y += FONT_HEIGHT_NORMAL; - - /* Reliability */ - SetDParam(0, ToPercent16(e->reliability)); - DrawString(left, right, y, STR_PURCHASE_INFO_RELIABILITY); - y += FONT_HEIGHT_NORMAL; - } - - if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number); - - /* Additional text from NewGRF */ - y = ShowAdditionalText(left, right, y, engine_number); - - return y; -} - -/** - * Engine drawing loop - * @param type Type of vehicle (VEH_*) - * @param l The left most location of the list - * @param r The right most location of the list - * @param y The top most location of the list - * @param eng_list What engines to draw - * @param min where to start in the list - * @param max where in the list to end - * @param selected_id what engine to highlight as selected, if any - * @param show_count Whether to show the amount of engines or not - * @param selected_group the group to list the engines of - */ -void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group) -{ - static const int sprite_y_offsets[] = { -1, -1, -2, -2 }; - - /* Obligatory sanity checks! */ - assert(max <= eng_list->Length()); - - bool rtl = _current_text_dir == TD_RTL; - int step_size = GetEngineListHeight(type); - int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left; - int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right; - int sprite_width = sprite_left + sprite_right; - - int sprite_x = rtl ? r - sprite_right - 1 : l + sprite_left + 1; - - Dimension replace_icon = {0, 0}; - int count_width = 0; - if (show_count) { - replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE); - SetDParamMaxDigits(0, 3, FS_SMALL); - count_width = GetStringBoundingBox(STR_TINY_BLACK_COMA).width; - } - - int text_left = l + (rtl ? WD_FRAMERECT_LEFT + replace_icon.width + 8 + count_width : sprite_width + WD_FRAMETEXT_LEFT); - int text_right = r - (rtl ? sprite_width + WD_FRAMETEXT_RIGHT : WD_FRAMERECT_RIGHT + replace_icon.width + 8 + count_width); - int replace_icon_left = rtl ? l + WD_FRAMERECT_LEFT : r - WD_FRAMERECT_RIGHT - replace_icon.width; - int count_left = l; - int count_right = rtl ? text_left : r - WD_FRAMERECT_RIGHT - replace_icon.width - 8; - - for (; min < max; min++, y += step_size) { - const EngineID engine = (*eng_list)[min]; - /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */ - const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine); - - SetDParam(0, engine); - DrawString(text_left, text_right, Center(y, step_size), STR_ENGINE_NAME, text_colour); - DrawVehicleEngine(l, r, sprite_x, Center(y, step_size, sprite_y_offsets[type]), engine, palette_crash ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); - if (show_count) { - SetDParam(0, num_engines); - DrawString(count_left, count_right, Center(y, step_size, FONT_HEIGHT_SMALL), STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); - if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, replace_icon_left, Center(y, step_size, replace_icon.height)); - } - } -} - - -struct BuildVehicleWindow : Window { - VehicleType vehicle_type; - union { - RailTypeByte railtype; - RoadTypes roadtypes; - } filter; - bool descending_sort_order; - byte sort_criteria; - bool listview_mode; - EngineID sel_engine; - EngineID rename_engine; - GUIEngineList eng_list; - CargoID cargo_filter[NUM_CARGO + 2]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE - StringID cargo_filter_texts[NUM_CARGO + 3]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID - byte cargo_filter_criteria; ///< Selected cargo filter - int details_height; ///< Minimal needed height of the details panels (found so far). - Scrollbar *vscroll; - - BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc) - { - this->vehicle_type = type; - this->window_number = tile == INVALID_TILE ? (int)type : tile; - - this->sel_engine = INVALID_ENGINE; - - this->sort_criteria = _last_sort_criteria[type]; - this->descending_sort_order = _last_sort_order[type]; - - switch (type) { - default: NOT_REACHED(); - case VEH_TRAIN: - this->filter.railtype = (tile == INVALID_TILE) ? RAILTYPE_END : GetRailType(tile); - break; - case VEH_ROAD: - this->filter.roadtypes = (tile == INVALID_TILE) ? ROADTYPES_ALL : GetRoadTypes(tile); - case VEH_SHIP: - case VEH_AIRCRAFT: - break; - } - - this->listview_mode = (this->window_number <= VEH_END); - - this->CreateNestedTree(); - - this->vscroll = this->GetScrollbar(WID_BV_SCROLLBAR); - - /* If we are just viewing the list of vehicles, we do not need the Build button. - * So we just hide it, and enlarge the Rename button by the now vacant place. */ - if (this->listview_mode) this->GetWidget(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE); - - /* disable renaming engines in network games if you are not the server */ - this->SetWidgetDisabledState(WID_BV_RENAME, _networking && !_network_server); - - NWidgetCore *widget = this->GetWidget(WID_BV_LIST); - widget->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + type; - - widget = this->GetWidget(WID_BV_BUILD); - widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + type; - widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + type; - - widget = this->GetWidget(WID_BV_RENAME); - widget->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + type; - widget->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + type; - - this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - - this->FinishInitNested(tile == INVALID_TILE ? (int)type : tile); - - this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company; - - this->eng_list.ForceRebuild(); - this->GenerateBuildList(); // generate the list, since we need it in the next line - /* Select the first engine in the list as default when opening the window */ - if (this->eng_list.Length() > 0) this->sel_engine = this->eng_list[0]; - } - - /** Populate the filter list and set the cargo filter criteria. */ - void SetCargoFilterArray() - { - uint filter_items = 0; - - /* Add item for disabling filtering. */ - this->cargo_filter[filter_items] = CF_ANY; - this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_ALL_TYPES; - filter_items++; - - /* Add item for vehicles not carrying anything, e.g. train engines. - * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */ - if (this->vehicle_type == VEH_TRAIN) { - this->cargo_filter[filter_items] = CF_NONE; - this->cargo_filter_texts[filter_items] = STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE; - filter_items++; - } - - /* Collect available cargo types for filtering. */ - const CargoSpec *cs; - FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { - this->cargo_filter[filter_items] = cs->Index(); - this->cargo_filter_texts[filter_items] = cs->name; - filter_items++; - } - - /* Terminate the filter list. */ - this->cargo_filter_texts[filter_items] = INVALID_STRING_ID; - - /* If not found, the cargo criteria will be set to all cargoes. */ - this->cargo_filter_criteria = 0; - - /* Find the last cargo filter criteria. */ - for (uint i = 0; i < filter_items; i++) { - if (this->cargo_filter[i] == _last_filter_criteria[this->vehicle_type]) { - this->cargo_filter_criteria = i; - break; - } - } - - this->eng_list.SetFilterFuncs(_filter_funcs); - this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY); - } - - void OnInit() - { - this->SetCargoFilterArray(); - } - - /** Filter the engine list against the currently selected cargo filter */ - void FilterEngineList() - { - this->eng_list.Filter(this->cargo_filter[this->cargo_filter_criteria]); - if (0 == this->eng_list.Length()) { // no engine passed through the filter, invalidate the previously selected engine - this->sel_engine = INVALID_ENGINE; - } else if (!this->eng_list.Contains(this->sel_engine)) { // previously selected engine didn't pass the filter, select the first engine of the list - this->sel_engine = this->eng_list[0]; - } - } - - /** Filter a single engine */ - bool FilterSingleEngine(EngineID eid) - { - CargoID filter_type = this->cargo_filter[this->cargo_filter_criteria]; - return (filter_type == CF_ANY || CargoFilter(&eid, filter_type)); - } - - /* Figure out what train EngineIDs to put in the list */ - void GenerateBuildTrainList() - { - EngineID sel_id = INVALID_ENGINE; - int num_engines = 0; - int num_wagons = 0; - - this->filter.railtype = (this->listview_mode) ? RAILTYPE_END : GetRailType(this->window_number); - - this->eng_list.Clear(); - - /* Make list of all available train engines and wagons. - * Also check to see if the previously selected engine is still available, - * and if not, reset selection to INVALID_ENGINE. This could be the case - * when engines become obsolete and are removed */ - const Engine *e; - FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { - EngineID eid = e->index; - const RailVehicleInfo *rvi = &e->u.rail; - - if (this->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue; - if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; - - /* Filter now! So num_engines and num_wagons is valid */ - if (!FilterSingleEngine(eid)) continue; - - *this->eng_list.Append() = eid; - - if (rvi->railveh_type != RAILVEH_WAGON) { - num_engines++; - } else { - num_wagons++; - } - - if (eid == this->sel_engine) sel_id = eid; - } - - this->sel_engine = sel_id; - - /* make engines first, and then wagons, sorted by selected sort_criteria */ - _internal_sort_order = false; - EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter); - - /* and then sort engines */ - _internal_sort_order = this->descending_sort_order; - EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], 0, num_engines); - - /* and finally sort wagons */ - EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], num_engines, num_wagons); - } - - /* Figure out what road vehicle EngineIDs to put in the list */ - void GenerateBuildRoadVehList() - { - EngineID sel_id = INVALID_ENGINE; - - this->eng_list.Clear(); - - const Engine *e; - FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { - EngineID eid = e->index; - if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue; - if (!HasBit(this->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue; - *this->eng_list.Append() = eid; - - if (eid == this->sel_engine) sel_id = eid; - } - this->sel_engine = sel_id; - } - - /* Figure out what ship EngineIDs to put in the list */ - void GenerateBuildShipList() - { - EngineID sel_id = INVALID_ENGINE; - this->eng_list.Clear(); - - const Engine *e; - FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) { - EngineID eid = e->index; - if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue; - *this->eng_list.Append() = eid; - - if (eid == this->sel_engine) sel_id = eid; - } - this->sel_engine = sel_id; - } - - /* Figure out what aircraft EngineIDs to put in the list */ - void GenerateBuildAircraftList() - { - EngineID sel_id = INVALID_ENGINE; - - this->eng_list.Clear(); - - const Station *st = this->listview_mode ? NULL : Station::GetByTile(this->window_number); - - /* Make list of all available planes. - * Also check to see if the previously selected plane is still available, - * and if not, reset selection to INVALID_ENGINE. This could be the case - * when planes become obsolete and are removed */ - const Engine *e; - FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) { - EngineID eid = e->index; - if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_company)) continue; - /* First VEH_END window_numbers are fake to allow a window open for all different types at once */ - if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue; - - *this->eng_list.Append() = eid; - if (eid == this->sel_engine) sel_id = eid; - } - - this->sel_engine = sel_id; - } - - /* Generate the list of vehicles */ - void GenerateBuildList() - { - if (!this->eng_list.NeedRebuild()) return; - switch (this->vehicle_type) { - default: NOT_REACHED(); - case VEH_TRAIN: - this->GenerateBuildTrainList(); - this->eng_list.Compact(); - this->eng_list.RebuildDone(); - return; // trains should not reach the last sorting - case VEH_ROAD: - this->GenerateBuildRoadVehList(); - break; - case VEH_SHIP: - this->GenerateBuildShipList(); - break; - case VEH_AIRCRAFT: - this->GenerateBuildAircraftList(); - break; - } - - this->FilterEngineList(); - - _internal_sort_order = this->descending_sort_order; - EngList_Sort(&this->eng_list, _sorter[this->vehicle_type][this->sort_criteria]); - - this->eng_list.Compact(); - this->eng_list.RebuildDone(); - } - - void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_BV_SORT_ASSENDING_DESCENDING: - this->descending_sort_order ^= true; - _last_sort_order[this->vehicle_type] = this->descending_sort_order; - this->eng_list.ForceRebuild(); - this->SetDirty(); - break; - - case WID_BV_LIST: { - uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST); - size_t num_items = this->eng_list.Length(); - this->sel_engine = (i < num_items) ? this->eng_list[i] : INVALID_ENGINE; - this->SetDirty(); - if (click_count > 1 && !this->listview_mode) this->OnClick(pt, WID_BV_BUILD, 1); - break; - } - - case WID_BV_SORT_DROPDOWN: { // Select sorting criteria dropdown menu - uint32 hidden_mask = 0; - /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */ - if (this->vehicle_type == VEH_ROAD && - _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) { - SetBit(hidden_mask, 3); // power - SetBit(hidden_mask, 4); // tractive effort - SetBit(hidden_mask, 8); // power by running costs - } - /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */ - if (this->vehicle_type == VEH_TRAIN && - _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) { - SetBit(hidden_mask, 4); // tractive effort - } - ShowDropDownMenu(this, _sort_listing[this->vehicle_type], this->sort_criteria, WID_BV_SORT_DROPDOWN, 0, hidden_mask); - break; - } - - case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu - ShowDropDownMenu(this, this->cargo_filter_texts, this->cargo_filter_criteria, WID_BV_CARGO_FILTER_DROPDOWN, 0, 0); - break; - - case WID_BV_BUILD: { - EngineID sel_eng = this->sel_engine; - if (sel_eng != INVALID_ENGINE) { - CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle; - DoCommandP(this->window_number, sel_eng, 0, GetCmdBuildVeh(this->vehicle_type), callback); - } - break; - } - - case WID_BV_RENAME: { - EngineID sel_eng = this->sel_engine; - if (sel_eng != INVALID_ENGINE) { - this->rename_engine = sel_eng; - SetDParam(0, sel_eng); - ShowQueryString(STR_ENGINE_NAME, STR_QUERY_RENAME_TRAIN_TYPE_CAPTION + this->vehicle_type, MAX_LENGTH_ENGINE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); - } - break; - } - } - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */ - if (this->vehicle_type == VEH_ROAD && - _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL && - this->sort_criteria > 7) { - this->sort_criteria = 0; - _last_sort_criteria[VEH_ROAD] = 0; - } - this->eng_list.ForceRebuild(); - } - - virtual void SetStringParameters(int widget) const - { - switch (widget) { - case WID_BV_CAPTION: - if (this->vehicle_type == VEH_TRAIN && !this->listview_mode) { - const RailtypeInfo *rti = GetRailTypeInfo(this->filter.railtype); - SetDParam(0, rti->strings.build_caption); - } else { - SetDParam(0, (this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type); - } - break; - - case WID_BV_SORT_DROPDOWN: - SetDParam(0, _sort_listing[this->vehicle_type][this->sort_criteria]); - break; - - case WID_BV_CARGO_FILTER_DROPDOWN: - SetDParam(0, this->cargo_filter_texts[this->cargo_filter_criteria]); - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_BV_LIST: - resize->height = GetEngineListHeight(this->vehicle_type); - size->height = 3 * resize->height; - break; - - case WID_BV_PANEL: - size->height = this->details_height; - break; - - case WID_BV_SORT_ASSENDING_DESCENDING: { - Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); - d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_BV_LIST: - DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list, this->vscroll->GetPosition(), min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->eng_list.Length()), this->sel_engine, false, DEFAULT_GROUP); - break; - - case WID_BV_SORT_ASSENDING_DESCENDING: - this->DrawSortButtonState(WID_BV_SORT_ASSENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP); - break; - } - } - - virtual void OnPaint() - { - this->GenerateBuildList(); - this->vscroll->SetCount(this->eng_list.Length()); - - this->DrawWidgets(); - - if (!this->IsShaded()) { - int needed_height = this->details_height; - /* Draw details panels. */ - if (this->sel_engine != INVALID_ENGINE) { - NWidgetBase *nwi = this->GetWidget(WID_BV_PANEL); - int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, - nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine); - needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); - } - if (needed_height != this->details_height) { // Details window are not high enough, enlarge them. - int resize = needed_height - this->details_height; - this->details_height = needed_height; - this->ReInit(0, resize); - return; - } - } - } - - virtual void OnQueryTextFinished(char *str) - { - if (str == NULL) return; - - DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), NULL, str); - } - - virtual void OnDropdownSelect(int widget, int index) - { - switch (widget) { - case WID_BV_SORT_DROPDOWN: - if (this->sort_criteria != index) { - this->sort_criteria = index; - _last_sort_criteria[this->vehicle_type] = this->sort_criteria; - this->eng_list.ForceRebuild(); - } - break; - - case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria - if (this->cargo_filter_criteria != index) { - this->cargo_filter_criteria = index; - _last_filter_criteria[this->vehicle_type] = this->cargo_filter[this->cargo_filter_criteria]; - /* deactivate filter if criteria is 'Show All', activate it otherwise */ - this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY); - this->eng_list.ForceRebuild(); - } - break; - } - this->SetDirty(); - } - - virtual void OnResize() - { - this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST); - } -}; - -static WindowDesc _build_vehicle_desc( - WDP_AUTO, "build_vehicle", 240, 268, - WC_BUILD_VEHICLE, WC_NONE, - WDF_CONSTRUCTION, - _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets) -); - -void ShowBuildVehicleWindow(TileIndex tile, VehicleType type) -{ - /* We want to be able to open both Available Train as Available Ships, - * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number. - * As it always is a low value, it won't collide with any real tile - * number. */ - uint num = (tile == INVALID_TILE) ? (int)type : tile; - - assert(IsCompanyBuildableVehicleType(type)); - - DeleteWindowById(WC_BUILD_VEHICLE, num); - - new BuildVehicleWindow(&_build_vehicle_desc, tile, type); -} diff --git a/src/error_gui.cpp.orig b/src/error_gui.cpp.orig deleted file mode 100644 index 5e8f52432d..0000000000 --- a/src/error_gui.cpp.orig +++ /dev/null @@ -1,432 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file error_gui.cpp GUI related to errors. */ - -#include "stdafx.h" -#include "landscape.h" -#include "newgrf_text.h" -#include "error.h" -#include "viewport_func.h" -#include "gfx_func.h" -#include "string_func.h" -#include "company_base.h" -#include "company_manager_face.h" -#include "strings_func.h" -#include "zoom_func.h" -#include "window_func.h" -#include "console_func.h" -#include "window_gui.h" - -#include "widgets/error_widget.h" - -#include "table/strings.h" -#include - -static const NWidgetPart _nested_errmsg_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_RED), - NWidget(WWT_CAPTION, COLOUR_RED, WID_EM_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION, STR_NULL), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_RED), - NWidget(WWT_EMPTY, COLOUR_RED, WID_EM_MESSAGE), SetPadding(0, 2, 0, 2), SetMinimalSize(236, 32), - EndContainer(), -}; - -static WindowDesc _errmsg_desc( - WDP_MANUAL, "error", 0, 0, - WC_ERRMSG, WC_NONE, - 0, - _nested_errmsg_widgets, lengthof(_nested_errmsg_widgets) -); - -static const NWidgetPart _nested_errmsg_face_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_RED), - NWidget(WWT_CAPTION, COLOUR_RED, WID_EM_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, STR_NULL), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_RED), - NWidget(NWID_HORIZONTAL), SetPIP(2, 1, 2), - NWidget(WWT_EMPTY, COLOUR_RED, WID_EM_FACE), SetMinimalSize(92, 119), SetFill(0, 1), SetPadding(2, 0, 1, 0), - NWidget(WWT_EMPTY, COLOUR_RED, WID_EM_MESSAGE), SetFill(0, 1), SetMinimalSize(238, 123), - EndContainer(), - EndContainer(), -}; - -static WindowDesc _errmsg_face_desc( - WDP_MANUAL, "error_face", 0, 0, - WC_ERRMSG, WC_NONE, - 0, - _nested_errmsg_face_widgets, lengthof(_nested_errmsg_face_widgets) -); - -/** - * Copy the given data into our instance. - * @param data The data to copy. - */ -ErrorMessageData::ErrorMessageData(const ErrorMessageData &data) -{ - *this = data; - for (size_t i = 0; i < lengthof(this->strings); i++) { - if (this->strings[i] != NULL) { - this->strings[i] = strdup(this->strings[i]); - this->decode_params[i] = (size_t)this->strings[i]; - } - } -} - -/** Free all the strings. */ -ErrorMessageData::~ErrorMessageData() -{ - for (size_t i = 0; i < lengthof(this->strings); i++) free(this->strings[i]); -} - -/** - * Display an error message in a window. - * @param summary_msg General error message showed in first line. Must be valid. - * @param detailed_msg Detailed error message showed in second line. Can be INVALID_STRING_ID. - * @param duration The amount of time to show this error message. - * @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. - * @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. - * @param textref_stack_grffile NewGRF that provides the #TextRefStack for the error message. - * @param textref_stack_size Number of uint32 values to put on the #TextRefStack for the error message; 0 if the #TextRefStack shall not be used. - * @param textref_stack Values to put on the #TextRefStack. - */ -ErrorMessageData::ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32 *textref_stack) : - duration(duration), - textref_stack_grffile(textref_stack_grffile), - textref_stack_size(textref_stack_size), - summary_msg(summary_msg), - detailed_msg(detailed_msg), - face(INVALID_COMPANY) -{ - this->position.x = x; - this->position.y = y; - - memset(this->decode_params, 0, sizeof(this->decode_params)); - memset(this->strings, 0, sizeof(this->strings)); - - if (textref_stack_size > 0) MemCpyT(this->textref_stack, textref_stack, textref_stack_size); - - assert(summary_msg != INVALID_STRING_ID); -} - -/** - * Copy error parameters from current DParams. - */ -void ErrorMessageData::CopyOutDParams() -{ - /* Reset parameters */ - for (size_t i = 0; i < lengthof(this->strings); i++) free(this->strings[i]); - memset(this->decode_params, 0, sizeof(this->decode_params)); - memset(this->strings, 0, sizeof(this->strings)); - - /* Get parameters using type information */ - if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack); - CopyOutDParam(this->decode_params, this->strings, this->detailed_msg == INVALID_STRING_ID ? this->summary_msg : this->detailed_msg, lengthof(this->decode_params)); - if (this->textref_stack_size > 0) StopTextRefStackUsage(); - - if (this->detailed_msg == STR_ERROR_OWNED_BY) { - CompanyID company = (CompanyID)GetDParamX(this->decode_params, 2); - if (company < MAX_COMPANIES) face = company; - } -} - -/** - * Set a error string parameter. - * @param n Parameter index - * @param v Parameter value - */ -void ErrorMessageData::SetDParam(uint n, uint64 v) -{ - this->decode_params[n] = v; -} - -/** - * Set a rawstring parameter. - * @param n Parameter index - * @param str Raw string - */ -void ErrorMessageData::SetDParamStr(uint n, const char *str) -{ - free(this->strings[n]); - this->strings[n] = strdup(str); -} - -/** Define a queue with errors. */ -typedef std::list ErrorList; -/** The actual queue with errors. */ -ErrorList _error_list; -/** Whether the window system is initialized or not. */ -bool _window_system_initialized = false; - -/** Window class for displaying an error message window. */ -struct ErrmsgWindow : public Window, ErrorMessageData { -private: - uint height_summary; ///< Height of the #summary_msg string in pixels in the #WID_EM_MESSAGE widget. - uint height_detailed; ///< Height of the #detailed_msg string in pixels in the #WID_EM_MESSAGE widget. - -public: - ErrmsgWindow(const ErrorMessageData &data) : Window(data.HasFace() ? &_errmsg_face_desc : &_errmsg_desc), ErrorMessageData(data) - { - this->InitNested(); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - if (widget != WID_EM_MESSAGE) return; - - CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); - if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack); - - int text_width = max(0, (int)size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT); - this->height_summary = GetStringHeight(this->summary_msg, text_width); - this->height_detailed = (this->detailed_msg == INVALID_STRING_ID) ? 0 : GetStringHeight(this->detailed_msg, text_width); - - if (this->textref_stack_size > 0) StopTextRefStackUsage(); - - uint panel_height = WD_FRAMERECT_TOP + this->height_summary + WD_FRAMERECT_BOTTOM; - if (this->detailed_msg != INVALID_STRING_ID) panel_height += this->height_detailed + WD_PAR_VSEP_WIDE; - - size->height = max(size->height, panel_height); - } - - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) - { - /* Position (0, 0) given, center the window. */ - if (this->position.x == 0 && this->position.y == 0) { - Point pt = {(_screen.width - sm_width) >> 1, (_screen.height - sm_height) >> 1}; - return pt; - } - - /* Find the free screen space between the main toolbar at the top, and the statusbar at the bottom. - * Add a fixed distance 20 to make it less cluttered. - */ - int scr_top = GetMainViewTop() + 20; - int scr_bot = GetMainViewBottom() - 20; - - Point pt = RemapCoords2(this->position.x, this->position.y); - const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; - if (this->face == INVALID_COMPANY) { - /* move x pos to opposite corner */ - pt.x = UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left; - pt.x = (pt.x < (_screen.width >> 1)) ? _screen.width - sm_width - 20 : 20; // Stay 20 pixels away from the edge of the screen. - - /* move y pos to opposite corner */ - pt.y = UnScaleByZoom(pt.y - vp->virtual_top, vp->zoom) + vp->top; - pt.y = (pt.y < (_screen.height >> 1)) ? scr_bot - sm_height : scr_top; - } else { - pt.x = Clamp(UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left - (sm_width / 2), 0, _screen.width - sm_width); - pt.y = Clamp(UnScaleByZoom(pt.y - vp->virtual_top, vp->zoom) + vp->top - (sm_height / 2), scr_top, scr_bot - sm_height); - } - return pt; - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - /* If company gets shut down, while displaying an error about it, remove the error message. */ - if (this->face != INVALID_COMPANY && !Company::IsValidID(this->face)) delete this; - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_EM_CAPTION) CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_EM_FACE: { - const Company *c = Company::Get(this->face); - DrawCompanyManagerFace(c->face, c->colour, r.left, r.top); - break; - } - - case WID_EM_MESSAGE: - CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); - if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack); - - if (this->detailed_msg == INVALID_STRING_ID) { - DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, - this->summary_msg, TC_FROMSTRING, SA_CENTER); - } else { - int extra = (r.bottom - r.top + 1 - this->height_summary - this->height_detailed - WD_PAR_VSEP_WIDE) / 2; - - /* Note: NewGRF supplied error message often do not start with a colour code, so default to white. */ - int top = r.top + WD_FRAMERECT_TOP; - int bottom = top + this->height_summary + extra; - DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, top, bottom, this->summary_msg, TC_WHITE, SA_CENTER); - - bottom = r.bottom - WD_FRAMERECT_BOTTOM; - top = bottom - this->height_detailed - extra; - DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, top, bottom, this->detailed_msg, TC_WHITE, SA_CENTER); - } - - if (this->textref_stack_size > 0) StopTextRefStackUsage(); - break; - - default: - break; - } - } - - virtual void OnMouseLoop() - { - /* Disallow closing the window too easily, if timeout is disabled */ - if (_right_button_down && this->duration != 0) delete this; - } - - virtual void OnHundredthTick() - { - /* Timeout enabled? */ - if (this->duration != 0) { - this->duration--; - if (this->duration == 0) delete this; - } - } - - ~ErrmsgWindow() - { - SetRedErrorSquare(INVALID_TILE); - if (_window_system_initialized) ShowFirstError(); - } - - virtual EventState OnKeyPress(WChar key, uint16 keycode) - { - if (keycode != WKC_SPACE) return ES_NOT_HANDLED; - delete this; - return ES_HANDLED; - } - - /** - * Check whether the currently shown error message was critical or not. - * @return True iff the message was critical. - */ - bool IsCritical() - { - return this->duration == 0; - } -}; - -/** - * Clear all errors from the queue. - */ -void ClearErrorMessages() -{ - UnshowCriticalError(); - _error_list.clear(); -} - -/** Show the first error of the queue. */ -void ShowFirstError() -{ - _window_system_initialized = true; - if (!_error_list.empty()) { - new ErrmsgWindow(_error_list.front()); - _error_list.pop_front(); - } -} - -/** - * Unshow the critical error. This has to happen when a critical - * error is shown and we uninitialise the window system, i.e. - * remove all the windows. - */ -void UnshowCriticalError() -{ - ErrmsgWindow *w = (ErrmsgWindow*)FindWindowById(WC_ERRMSG, 0); - if (_window_system_initialized && w != NULL) { - if (w->IsCritical()) _error_list.push_front(*w); - _window_system_initialized = false; - delete w; - } -} - -/** - * Display an error message in a window. - * @param summary_msg General error message showed in first line. Must be valid. - * @param detailed_msg Detailed error message showed in second line. Can be INVALID_STRING_ID. - * @param wl Message severity. - * @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. - * @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. - * @param textref_stack_grffile NewGRF providing the #TextRefStack for the error message. - * @param textref_stack_size Number of uint32 values to put on the #TextRefStack for the error message; 0 if the #TextRefStack shall not be used. - * @param textref_stack Values to put on the #TextRefStack. - */ -void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32 *textref_stack) -{ - assert(textref_stack_size == 0 || (textref_stack_grffile != NULL && textref_stack != NULL)); - if (summary_msg == STR_NULL) summary_msg = STR_EMPTY; - - if (wl != WL_INFO) { - /* Print message to console */ - char buf[DRAW_STRING_BUFFER]; - - if (textref_stack_size > 0) StartTextRefStackUsage(textref_stack_grffile, textref_stack_size, textref_stack); - - char *b = GetString(buf, summary_msg, lastof(buf)); - if (detailed_msg != INVALID_STRING_ID) { - b += seprintf(b, lastof(buf), " "); - GetString(b, detailed_msg, lastof(buf)); - } - - if (textref_stack_size > 0) StopTextRefStackUsage(); - - switch (wl) { - case WL_WARNING: IConsolePrint(CC_WARNING, buf); break; - default: IConsoleError(buf); break; - } - } - - bool no_timeout = wl == WL_CRITICAL; - - if (_settings_client.gui.errmsg_duration == 0 && !no_timeout) return; - - ErrorMessageData data(summary_msg, detailed_msg, no_timeout ? 0 : _settings_client.gui.errmsg_duration, x, y, textref_stack_grffile, textref_stack_size, textref_stack); - data.CopyOutDParams(); - - ErrmsgWindow *w = (ErrmsgWindow*)FindWindowById(WC_ERRMSG, 0); - if (w != NULL && w->IsCritical()) { - /* A critical error is currently shown. */ - if (wl == WL_CRITICAL) { - /* Push another critical error in the queue of errors, - * but do not put other errors in the queue. */ - _error_list.push_back(data); - } - } else { - /* Nothing or a non-critical error was shown. */ - delete w; - new ErrmsgWindow(data); - } -} - -/** - * Schedule a list of errors. - * Note: This does not try to display the error now. This is useful if the window system is not yet running. - * @param data Error message datas; cleared afterwards - */ -void ScheduleErrorMessage(ErrorList &datas) -{ - _error_list.splice(_error_list.end(), datas); -} - -/** - * Schedule an error. - * Note: This does not try to display the error now. This is useful if the window system is not yet running. - * @param data Error message data; cleared afterwards - */ -void ScheduleErrorMessage(const ErrorMessageData &data) -{ - _error_list.push_back(data); -} diff --git a/src/gfx.cpp.orig b/src/gfx.cpp.orig deleted file mode 100644 index 01f29b9fb9..0000000000 --- a/src/gfx.cpp.orig +++ /dev/null @@ -1,1697 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file gfx.cpp Handling of drawing text and other gfx related stuff. */ - -#include "stdafx.h" -#include "gfx_layout.h" -#include "progress.h" -#include "zoom_func.h" -#include "blitter/factory.hpp" -#include "video/video_driver.hpp" -#include "strings_func.h" -#include "settings_type.h" -#include "network/network.h" -#include "network/network_func.h" -#include "window_func.h" -#include "newgrf_debug.h" - -#include "table/palettes.h" -#include "table/sprites.h" -#include "table/control_codes.h" - -byte _dirkeys; ///< 1 = left, 2 = up, 4 = right, 8 = down -bool _fullscreen; -CursorVars _cursor; -bool _ctrl_pressed; ///< Is Ctrl pressed? -bool _shift_pressed; ///< Is Shift pressed? -byte _fast_forward; -bool _left_button_down; ///< Is left mouse button pressed? -bool _left_button_clicked; ///< Is left mouse button clicked? -bool _right_button_down; ///< Is right mouse button pressed? -bool _right_button_clicked; ///< Is right mouse button clicked? -DrawPixelInfo _screen; -bool _screen_disable_anim = false; ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot) -bool _exit_game; -GameMode _game_mode; -SwitchMode _switch_mode; ///< The next mainloop command. -PauseModeByte _pause_mode; -Palette _cur_palette; - -static byte _stringwidth_table[FS_END][224]; ///< Cache containing width of often used characters. @see GetCharacterWidth() -DrawPixelInfo *_cur_dpi; -byte _colour_gradient[COLOUR_END][8]; - -static void GfxMainBlitterViewport(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL, SpriteID sprite_id = SPR_CURSOR_MOUSE); -static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL, SpriteID sprite_id = SPR_CURSOR_MOUSE, ZoomLevel zoom = ZOOM_LVL_NORMAL); - -static ReusableBuffer _cursor_backup; - -/** - * The rect for repaint. - * - * This rectangle defines the area which should be repaint by the video driver. - * - * @ingroup dirty - */ -static Rect _invalid_rect; -static const byte *_colour_remap_ptr; -static byte _string_colourremap[3]; ///< Recoloursprite for stringdrawing. The grf loader ensures that #ST_FONT sprites only use colours 0 to 2. - -static const uint DIRTY_BLOCK_HEIGHT = 8; -static const uint DIRTY_BLOCK_WIDTH = 64; - -static uint _dirty_bytes_per_line = 0; -static byte *_dirty_blocks = NULL; -extern uint _dirty_block_colour; - -void GfxScroll(int left, int top, int width, int height, int xo, int yo) -{ - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - - if (xo == 0 && yo == 0) return; - - if (_cursor.visible) UndrawMouseCursor(); - -#ifdef ENABLE_NETWORK - if (_networking) NetworkUndrawChatMessage(); -#endif /* ENABLE_NETWORK */ - - blitter->ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo); - /* This part of the screen is now dirty. */ - _video_driver->MakeDirty(left, top, width, height); -} - - -/** - * Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen. - * - * @pre dpi->zoom == ZOOM_LVL_NORMAL, right >= left, bottom >= top - * @param left Minimum X (inclusive) - * @param top Minimum Y (inclusive) - * @param right Maximum X (inclusive) - * @param bottom Maximum Y (inclusive) - * @param colour A 8 bit palette index (FILLRECT_OPAQUE and FILLRECT_CHECKER) or a recolour spritenumber (FILLRECT_RECOLOUR) - * @param mode - * FILLRECT_OPAQUE: Fill the rectangle with the specified colour - * FILLRECT_CHECKER: Like FILLRECT_OPAQUE, but only draw every second pixel (used to grey out things) - * FILLRECT_RECOLOUR: Apply a recolour sprite to every pixel in the rectangle currently on screen - */ -void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode) -{ - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - const DrawPixelInfo *dpi = _cur_dpi; - void *dst; - const int otop = top; - const int oleft = left; - - if (dpi->zoom != ZOOM_LVL_NORMAL) return; - if (left > right || top > bottom) return; - if (right < dpi->left || left >= dpi->left + dpi->width) return; - if (bottom < dpi->top || top >= dpi->top + dpi->height) return; - - if ( (left -= dpi->left) < 0) left = 0; - right = right - dpi->left + 1; - if (right > dpi->width) right = dpi->width; - right -= left; - assert(right > 0); - - if ( (top -= dpi->top) < 0) top = 0; - bottom = bottom - dpi->top + 1; - if (bottom > dpi->height) bottom = dpi->height; - bottom -= top; - assert(bottom > 0); - - dst = blitter->MoveTo(dpi->dst_ptr, left, top); - - switch (mode) { - default: // FILLRECT_OPAQUE - blitter->DrawRect(dst, right, bottom, (uint8)colour); - break; - - case FILLRECT_RECOLOUR: - blitter->DrawColourMappingRect(dst, right, bottom, GB(colour, 0, PALETTE_WIDTH)); - break; - - case FILLRECT_CHECKER: { - byte bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1; - do { - for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8)colour); - dst = blitter->MoveTo(dst, 0, 1); - } while (--bottom > 0); - break; - } - } -} - -/** - * Check line clipping by using a linear equation and draw the visible part of - * the line given by x/y and x2/y2. - * @param video Destination pointer to draw into. - * @param x X coordinate of first point. - * @param y Y coordinate of first point. - * @param x2 X coordinate of second point. - * @param y2 Y coordinate of second point. - * @param screen_width With of the screen to check clipping against. - * @param screen_height Height of the screen to check clipping against. - * @param colour Colour of the line. - * @param width Width of the line. - * @param dash Length of dashes for dashed lines. 0 means solid line. - */ -static inline void GfxDoDrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash = 0) -{ - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - - assert(width > 0); - - if (y2 == y) { - /* Special case: horizontal line. */ - blitter->DrawLine(video, - Clamp(x, 0, screen_width), y, - Clamp(x2, 0, screen_width), y2, - screen_width, screen_height, colour, width, dash); - return; - } - if (x2 == x) { - /* Special case: vertical line. */ - blitter->DrawLine(video, - x, Clamp(y, 0, screen_height), - x2, Clamp(y2, 0, screen_height), - screen_width, screen_height, colour, width, dash); - return; - } - - int grade_y = y2 - y; - int grade_x = x2 - x; - - /* prevent integer overflows. */ - int margin = 1; - while (INT_MAX / abs(grade_y) < max(abs(x), abs(screen_width - x))) { - grade_y /= 2; - grade_x /= 2; - margin *= 2; // account for rounding errors - } - - /* If the line is outside the screen on the same side at X positions 0 - * and screen_width, we don't need to draw anything. */ - int offset_0 = y - x * grade_y / grade_x; - int offset_width = y + (screen_width - x) * grade_y / grade_x; - if ((offset_0 > screen_height + width / 2 + margin && offset_width > screen_height + width / 2 + margin) || - (offset_0 < -width / 2 - margin && offset_width < -width / 2 - margin)) { - return; - } - - /* It is possible to use the line equation to further reduce the amount of - * work the blitter has to do by shortening the effective line segment. - * However, in order to get that right and prevent the flickering effects - * of rounding errors so much additional code has to be run here that in - * the general case the effect is not noticable. */ - - blitter->DrawLine(video, x, y, x2, y2, screen_width, screen_height, colour, width, dash); -} - -/** - * Align parameters of a line to the given DPI and check simple clipping. - * @param dpi Screen parameters to align with. - * @param x X coordinate of first point. - * @param y Y coordinate of first point. - * @param x2 X coordinate of second point. - * @param y2 Y coordinate of second point. - * @param width Width of the line. - * @return True if the line is likely to be visible, false if it's certainly - * invisible. - */ -static inline bool GfxPreprocessLine(DrawPixelInfo *dpi, int &x, int &y, int &x2, int &y2, int width) -{ - x -= dpi->left; - x2 -= dpi->left; - y -= dpi->top; - y2 -= dpi->top; - - /* Check simple clipping */ - if (x + width / 2 < 0 && x2 + width / 2 < 0 ) return false; - if (y + width / 2 < 0 && y2 + width / 2 < 0 ) return false; - if (x - width / 2 > dpi->width && x2 - width / 2 > dpi->width ) return false; - if (y - width / 2 > dpi->height && y2 - width / 2 > dpi->height) return false; - return true; -} - -void GfxDrawLine(int x, int y, int x2, int y2, int colour, int width, int dash) -{ - DrawPixelInfo *dpi = _cur_dpi; - if (GfxPreprocessLine(dpi, x, y, x2, y2, width)) { - GfxDoDrawLine(dpi->dst_ptr, x, y, x2, y2, dpi->width, dpi->height, colour, width, dash); - } -} - -void GfxDrawLineUnscaled(int x, int y, int x2, int y2, int colour) -{ - DrawPixelInfo *dpi = _cur_dpi; - if (GfxPreprocessLine(dpi, x, y, x2, y2, 1)) { - GfxDoDrawLine(dpi->dst_ptr, - UnScaleByZoom(x, dpi->zoom), UnScaleByZoom(y, dpi->zoom), - UnScaleByZoom(x2, dpi->zoom), UnScaleByZoom(y2, dpi->zoom), - UnScaleByZoom(dpi->width, dpi->zoom), UnScaleByZoom(dpi->height, dpi->zoom), colour, 1); - } -} - -/** - * Draws the projection of a parallelepiped. - * This can be used to draw boxes in world coordinates. - * - * @param x Screen X-coordinate of top front corner. - * @param y Screen Y-coordinate of top front corner. - * @param dx1 Screen X-length of first edge. - * @param dy1 Screen Y-length of first edge. - * @param dx2 Screen X-length of second edge. - * @param dy2 Screen Y-length of second edge. - * @param dx3 Screen X-length of third edge. - * @param dy3 Screen Y-length of third edge. - */ -void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3) -{ - /* .... - * .. .... - * .. .... - * .. ^ - * <--__(dx1,dy1) /(dx2,dy2) - * : --__ / : - * : --__ / : - * : *(x,y) : - * : | : - * : | .. - * .... |(dx3,dy3) - * .... | .. - * ....V. - */ - - static const byte colour = PC_WHITE; - - GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, colour); - GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, colour); - GfxDrawLineUnscaled(x, y, x + dx3, y + dy3, colour); - - GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx2, y + dy1 + dy2, colour); - GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx3, y + dy1 + dy3, colour); - GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx1, y + dy2 + dy1, colour); - GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx3, y + dy2 + dy3, colour); - GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx1, y + dy3 + dy1, colour); - GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx2, y + dy3 + dy2, colour); -} - -/** - * Set the colour remap to be for the given colour. - * @param colour the new colour of the remap. - */ -static void SetColourRemap(TextColour colour) -{ - if (colour == TC_INVALID) return; - - /* Black strings have no shading ever; the shading is black, so it - * would be invisible at best, but it actually makes it illegible. */ - bool no_shade = (colour & TC_NO_SHADE) != 0 || colour == TC_BLACK; - bool raw_colour = (colour & TC_IS_PALETTE_COLOUR) != 0; - colour &= ~(TC_NO_SHADE | TC_IS_PALETTE_COLOUR); - - _string_colourremap[1] = raw_colour ? (byte)colour : _string_colourmap[colour]; - _string_colourremap[2] = no_shade ? 0 : 1; - _colour_remap_ptr = _string_colourremap; -} - -/** - * Drawing routine for drawing a laid out line of text. - * @param line String to draw. - * @param y The top most position to draw on. - * @param left The left most position to draw on. - * @param right The right most position to draw on. - * @param align The alignment of the string when drawing left-to-right. In the - * case a right-to-left language is chosen this is inverted so it - * will be drawn in the right direction. - * @param underline Whether to underline what has been drawn or not. - * @param truncation Whether to perform string truncation or not. - * - * @return In case of left or center alignment the right most pixel we have drawn to. - * In case of right alignment the left most pixel we have drawn to. - */ -static int DrawLayoutLine(const ParagraphLayouter::Line *line, int y, int left, int right, StringAlignment align, bool underline, bool truncation) -{ - if (line->CountRuns() == 0) return 0; - - int w = line->GetWidth(); - int h = line->GetLeading(); - - /* - * The following is needed for truncation. - * Depending on the text direction, we either remove bits at the rear - * or the front. For this we shift the entire area to draw so it fits - * within the left/right bounds and the side we do not truncate it on. - * Then we determine the truncation location, i.e. glyphs that fall - * outside of the range min_x - max_x will not be drawn; they are thus - * the truncated glyphs. - * - * At a later step we insert the dots. - */ - - int max_w = right - left + 1; // The maximum width. - - int offset_x = 0; // The offset we need for positioning the glyphs - int min_x = left; // The minimum x position to draw normal glyphs on. - int max_x = right; // The maximum x position to draw normal glyphs on. - - truncation &= max_w < w; // Whether we need to do truncation. - int dot_width = 0; // Cache for the width of the dot. - const Sprite *dot_sprite = NULL; // Cache for the sprite of the dot. - - if (truncation) { - /* - * Assumption may be made that all fonts of a run are of the same size. - * In any case, we'll use these dots for the abbreviation, so even if - * another size would be chosen it won't have truncated too little for - * the truncation dots. - */ - FontCache *fc = ((const Font*)line->GetVisualRun(0)->GetFont())->fc; - GlyphID dot_glyph = fc->MapCharToGlyph('.'); - dot_width = fc->GetGlyphWidth(dot_glyph); - dot_sprite = fc->GetGlyph(dot_glyph); - - if (_current_text_dir == TD_RTL) { - min_x += 3 * dot_width; - offset_x = w - 3 * dot_width - max_w; - } else { - max_x -= 3 * dot_width; - } - - w = max_w; - } - - /* In case we have a RTL language we swap the alignment. */ - if (!(align & SA_FORCE) && _current_text_dir == TD_RTL && (align & SA_HOR_MASK) != SA_HOR_CENTER) align ^= SA_RIGHT; - - /* right is the right most position to draw on. In this case we want to do - * calculations with the width of the string. In comparison right can be - * seen as lastof(todraw) and width as lengthof(todraw). They differ by 1. - * So most +1/-1 additions are to move from lengthof to 'indices'. - */ - switch (align & SA_HOR_MASK) { - case SA_LEFT: - /* right + 1 = left + w */ - right = left + w - 1; - break; - - case SA_HOR_CENTER: - left = RoundDivSU(right + 1 + left - w, 2); - /* right + 1 = left + w */ - right = left + w - 1; - break; - - case SA_RIGHT: - left = right + 1 - w; - break; - - default: - NOT_REACHED(); - } - - for (int run_index = 0; run_index < line->CountRuns(); run_index++) { - const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index); - const Font *f = (const Font*)run->GetFont(); - - FontCache *fc = f->fc; - TextColour colour = f->colour; - SetColourRemap(colour); - - DrawPixelInfo *dpi = _cur_dpi; - int dpi_left = dpi->left; - int dpi_right = dpi->left + dpi->width - 1; - - bool draw_shadow = fc->GetDrawGlyphShadow() && colour != TC_BLACK; - - for (int i = 0; i < run->GetGlyphCount(); i++) { - GlyphID glyph = run->GetGlyphs()[i]; - - /* Not a valid glyph (empty) */ - if (glyph == 0xFFFF) continue; - - int begin_x = (int)run->GetPositions()[i * 2] + left - offset_x; - int end_x = (int)run->GetPositions()[i * 2 + 2] + left - offset_x - 1; - int top = (int)run->GetPositions()[i * 2 + 1] + y; - - /* Truncated away. */ - if (truncation && (begin_x < min_x || end_x > max_x)) continue; - - const Sprite *sprite = fc->GetGlyph(glyph); - /* Check clipping (the "+ 1" is for the shadow). */ - if (begin_x + sprite->x_offs > dpi_right || begin_x + sprite->x_offs + sprite->width /* - 1 + 1 */ < dpi_left) continue; - - if (draw_shadow && (glyph & SPRITE_GLYPH) == 0) { - SetColourRemap(TC_BLACK); - GfxMainBlitter(sprite, begin_x + 1, top + 1, BM_COLOUR_REMAP); - SetColourRemap(colour); - } - GfxMainBlitter(sprite, begin_x, top, BM_COLOUR_REMAP); - } - } - - if (truncation) { - int x = (_current_text_dir == TD_RTL) ? left : (right - 3 * dot_width); - for (int i = 0; i < 3; i++, x += dot_width) { - GfxMainBlitter(dot_sprite, x, y, BM_COLOUR_REMAP); - } - } - - if (underline) { - GfxFillRect(left, y + h, right, y + h, _string_colourremap[1]); - } - - return (align & SA_HOR_MASK) == SA_RIGHT ? left : right; -} - -/** - * Draw string, possibly truncated to make it fit in its allocated space - * - * @param left The left most position to draw on. - * @param right The right most position to draw on. - * @param top The top most position to draw on. - * @param str String to draw. - * @param colour Colour used for drawing the string, see DoDrawString() for details - * @param align The alignment of the string when drawing left-to-right. In the - * case a right-to-left language is chosen this is inverted so it - * will be drawn in the right direction. - * @param underline Whether to underline what has been drawn or not. - * @param fontsize The size of the initial characters. - * @return In case of left or center alignment the right most pixel we have drawn to. - * In case of right alignment the left most pixel we have drawn to. - */ -int DrawString(int left, int right, int top, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) -{ - /* The string may contain control chars to change the font, just use the biggest font for clipping. */ - int max_height = max(max(FONT_HEIGHT_SMALL, FONT_HEIGHT_NORMAL), max(FONT_HEIGHT_LARGE, FONT_HEIGHT_MONO)); - - /* Funny glyphs may extent outside the usual bounds, so relax the clipping somewhat. */ - int extra = max_height / 2; - - if (_cur_dpi->top + _cur_dpi->height + extra < top || _cur_dpi->top > top + max_height + extra || - _cur_dpi->left + _cur_dpi->width + extra < left || _cur_dpi->left > right + extra) { - return 0; - } - - Layouter layout(str, INT32_MAX, colour, fontsize); - if (layout.Length() == 0) return 0; - - return DrawLayoutLine(*layout.Begin(), top, left, right, align, underline, true); -} - -/** - * Draw string, possibly truncated to make it fit in its allocated space - * - * @param left The left most position to draw on. - * @param right The right most position to draw on. - * @param top The top most position to draw on. - * @param str String to draw. - * @param colour Colour used for drawing the string, see DoDrawString() for details - * @param align The alignment of the string when drawing left-to-right. In the - * case a right-to-left language is chosen this is inverted so it - * will be drawn in the right direction. - * @param underline Whether to underline what has been drawn or not. - * @param fontsize The size of the initial characters. - * @return In case of left or center alignment the right most pixel we have drawn to. - * In case of right alignment the left most pixel we have drawn to. - */ -int DrawString(int left, int right, int top, StringID str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) -{ - char buffer[DRAW_STRING_BUFFER]; - GetString(buffer, str, lastof(buffer)); - return DrawString(left, right, top, buffer, colour, align, underline, fontsize); -} - -/** - * Calculates height of string (in pixels). The string is changed to a multiline string if needed. - * @param str string to check - * @param maxw maximum string width - * @return height of pixels of string when it is drawn - */ -int GetStringHeight(const char *str, int maxw, FontSize fontsize) -{ - Layouter layout(str, maxw, TC_FROMSTRING, fontsize); - return layout.GetBounds().height; -} - -/** - * Calculates height of string (in pixels). The string is changed to a multiline string if needed. - * @param str string to check - * @param maxw maximum string width - * @return height of pixels of string when it is drawn - */ -int GetStringHeight(StringID str, int maxw) -{ - char buffer[DRAW_STRING_BUFFER]; - GetString(buffer, str, lastof(buffer)); - return GetStringHeight(buffer, maxw); -} - -/** - * Calculates number of lines of string. The string is changed to a multiline string if needed. - * @param str string to check - * @param maxw maximum string width - * @return number of lines of string when it is drawn - */ -int GetStringLineCount(StringID str, int maxw) -{ - char buffer[DRAW_STRING_BUFFER]; - GetString(buffer, str, lastof(buffer)); - - Layouter layout(buffer, maxw); - return layout.Length(); -} - -/** - * Calculate string bounding box for multi-line strings. - * @param str String to check. - * @param suggestion Suggested bounding box. - * @return Bounding box for the multi-line string, may be bigger than \a suggestion. - */ -Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion) -{ - Dimension box = {suggestion.width, GetStringHeight(str, suggestion.width)}; - return box; -} - -/** - * Calculate string bounding box for multi-line strings. - * @param str String to check. - * @param suggestion Suggested bounding box. - * @return Bounding box for the multi-line string, may be bigger than \a suggestion. - */ -Dimension GetStringMultiLineBoundingBox(const char *str, const Dimension &suggestion) -{ - Dimension box = {suggestion.width, GetStringHeight(str, suggestion.width)}; - return box; -} - -/** - * Draw string, possibly over multiple lines. - * - * @param left The left most position to draw on. - * @param right The right most position to draw on. - * @param top The top most position to draw on. - * @param bottom The bottom most position to draw on. - * @param str String to draw. - * @param colour Colour used for drawing the string, see DoDrawString() for details - * @param align The horizontal and vertical alignment of the string. - * @param underline Whether to underline all strings - * @param fontsize The size of the initial characters. - * - * @return If \a align is #SA_BOTTOM, the top to where we have written, else the bottom to where we have written. - */ -int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) -{ - int maxw = right - left + 1; - int maxh = bottom - top + 1; - - /* It makes no sense to even try if it can't be drawn anyway, or - * do we really want to support fonts of 0 or less pixels high? */ - if (maxh <= 0) return top; - - Layouter layout(str, maxw, colour, fontsize); - int total_height = layout.GetBounds().height; - int y; - switch (align & SA_VERT_MASK) { - case SA_TOP: - y = top; - break; - - case SA_VERT_CENTER: - y = RoundDivSU(bottom + top - total_height, 2); - break; - - case SA_BOTTOM: - y = bottom - total_height; - break; - - default: NOT_REACHED(); - } - - int last_line = top; - int first_line = bottom; - - for (const ParagraphLayouter::Line **iter = layout.Begin(); iter != layout.End(); iter++) { - const ParagraphLayouter::Line *line = *iter; - - int line_height = line->GetLeading(); - if (y >= top && y < bottom) { - last_line = y + line_height; - if (first_line > y) first_line = y; - - DrawLayoutLine(line, y, left, right, align, underline, false); - } - y += line_height; - } - - return ((align & SA_VERT_MASK) == SA_BOTTOM) ? first_line : last_line; -} - -/** - * Draw string, possibly over multiple lines. - * - * @param left The left most position to draw on. - * @param right The right most position to draw on. - * @param top The top most position to draw on. - * @param bottom The bottom most position to draw on. - * @param str String to draw. - * @param colour Colour used for drawing the string, see DoDrawString() for details - * @param align The horizontal and vertical alignment of the string. - * @param underline Whether to underline all strings - * @param fontsize The size of the initial characters. - * - * @return If \a align is #SA_BOTTOM, the top to where we have written, else the bottom to where we have written. - */ -int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) -{ - char buffer[DRAW_STRING_BUFFER]; - GetString(buffer, str, lastof(buffer)); - return DrawStringMultiLine(left, right, top, bottom, buffer, colour, align, underline, fontsize); -} - -/** - * Return the string dimension in pixels. The height and width are returned - * in a single Dimension value. TINYFONT, BIGFONT modifiers are only - * supported as the first character of the string. The returned dimensions - * are therefore a rough estimation correct for all the current strings - * but not every possible combination - * @param str string to calculate pixel-width - * @param start_fontsize Fontsize to start the text with - * @return string width and height in pixels - */ -Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize) -{ - Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); - return layout.GetBounds(); -} - -/** - * Get bounding box of a string. Uses parameters set by #DParam if needed. - * Has the same restrictions as #GetStringBoundingBox(const char *str). - * @param strid String to examine. - * @return Width and height of the bounding box for the string in pixels. - */ -Dimension GetStringBoundingBox(StringID strid) -{ - char buffer[DRAW_STRING_BUFFER]; - - GetString(buffer, strid, lastof(buffer)); - return GetStringBoundingBox(buffer); -} - -/** - * Get the leading corner of a character in a single-line string relative - * to the start of the string. - * @param str String containing the character. - * @param ch Pointer to the character in the string. - * @param start_fontsize Font size to start the text with. - * @return Upper left corner of the glyph associated with the character. - */ -Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsize) -{ - Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); - return layout.GetCharPosition(ch); -} - -/** - * Get the character from a string that is drawn at a specific position. - * @param str String to test. - * @param x Position relative to the start of the string. - * @param start_fontsize Font size to start the text with. - * @return Pointer to the character at the position or NULL if there is no character at the position. - */ -const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize) -{ - if (x < 0) return NULL; - - Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); - return layout.GetCharAtPosition(x); -} - -/** - * Draw single character horizontally centered around (x,y) - * @param c Character (glyph) to draw - * @param x X position to draw character - * @param y Y position to draw character - * @param colour Colour to use, see DoDrawString() for details - */ -void DrawCharCentered(WChar c, int x, int y, TextColour colour) -{ - SetColourRemap(colour); - GfxMainBlitter(GetGlyph(FS_NORMAL, c), x - GetCharacterWidth(FS_NORMAL, c) / 2, y, BM_COLOUR_REMAP); -} - -/** - * Get the size of a sprite. - * @param sprid Sprite to examine. - * @param [out] offset Optionally returns the sprite position offset. - * @return Sprite size in pixels. - * @note The size assumes (0, 0) as top-left coordinate and ignores any part of the sprite drawn at the left or above that position. - */ -Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom) -{ - const Sprite *sprite = GetSprite(sprid, ST_NORMAL); - - if (offset != NULL) { - offset->x = UnScaleByZoom(sprite->x_offs, zoom); - offset->y = UnScaleByZoom(sprite->y_offs, zoom); - } - - Dimension d; - d.width = max(0, UnScaleByZoom(sprite->x_offs + sprite->width, zoom)); - d.height = max(0, UnScaleByZoom(sprite->y_offs + sprite->height, zoom)); - return d; -} - -/** - * Draw a sprite in a viewport. - * @param img Image number to draw - * @param pal Palette to use. - * @param x Left coordinate of image in viewport, scaled by zoom - * @param y Top coordinate of image in viewport, scaled by zoom - * @param sub If available, draw only specified part of the sprite - */ -void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub) -{ - SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH); - if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) { - _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; - GfxMainBlitterViewport(GetSprite(real_sprite, ST_NORMAL), x, y, BM_TRANSPARENT, sub, real_sprite); - } else if (pal != PAL_NONE) { - _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; - GfxMainBlitterViewport(GetSprite(real_sprite, ST_NORMAL), x, y, BM_COLOUR_REMAP, sub, real_sprite); - } else { - GfxMainBlitterViewport(GetSprite(real_sprite, ST_NORMAL), x, y, BM_NORMAL, sub, real_sprite); - } -} - -/** - * Draw a sprite, not in a viewport - * @param img Image number to draw - * @param pal Palette to use. - * @param x Left coordinate of image in pixels - * @param y Top coordinate of image in pixels - * @param sub If available, draw only specified part of the sprite - * @param zoom Zoom level of sprite - */ -void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom) -{ - SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH); - if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) { - _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; - GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_TRANSPARENT, sub, real_sprite, zoom); - } else if (pal != PAL_NONE) { - _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; - GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_COLOUR_REMAP, sub, real_sprite, zoom); - } else { - GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_NORMAL, sub, real_sprite, zoom); - } -} - -/** - * The code for setting up the blitter mode and sprite information before finally drawing the sprite. - * @param sprite The sprite to draw. - * @param x The X location to draw. - * @param y The Y location to draw. - * @param mode The settings for the blitter to pass. - * @param sub Whether to only draw a sub set of the sprite. - * @param zoom The zoom level at which to draw the sprites. - * @tparam ZOOM_BASE The factor required to get the sub sprite information into the right size. - * @tparam SCALED_XY Whether the X and Y are scaled or unscaled. - */ -template -static void GfxBlitter(const Sprite * const sprite, int x, int y, BlitterMode mode, const SubSprite * const sub, SpriteID sprite_id, ZoomLevel zoom) -{ - const DrawPixelInfo *dpi = _cur_dpi; - Blitter::BlitterParams bp; - - if (SCALED_XY) { - /* Scale it */ - x = ScaleByZoom(x, zoom); - y = ScaleByZoom(y, zoom); - } - - /* Move to the correct offset */ - x += sprite->x_offs; - y += sprite->y_offs; - - if (sub == NULL) { - /* No clipping. */ - bp.skip_left = 0; - bp.skip_top = 0; - bp.width = UnScaleByZoom(sprite->width, zoom); - bp.height = UnScaleByZoom(sprite->height, zoom); - } else { - /* Amount of pixels to clip from the source sprite */ - int clip_left = max(0, -sprite->x_offs + sub->left * ZOOM_BASE ); - int clip_top = max(0, -sprite->y_offs + sub->top * ZOOM_BASE ); - int clip_right = max(0, sprite->width - (-sprite->x_offs + (sub->right + 1) * ZOOM_BASE)); - int clip_bottom = max(0, sprite->height - (-sprite->y_offs + (sub->bottom + 1) * ZOOM_BASE)); - - if (clip_left + clip_right >= sprite->width) return; - if (clip_top + clip_bottom >= sprite->height) return; - - bp.skip_left = UnScaleByZoomLower(clip_left, zoom); - bp.skip_top = UnScaleByZoomLower(clip_top, zoom); - bp.width = UnScaleByZoom(sprite->width - clip_left - clip_right, zoom); - bp.height = UnScaleByZoom(sprite->height - clip_top - clip_bottom, zoom); - - x += ScaleByZoom(bp.skip_left, zoom); - y += ScaleByZoom(bp.skip_top, zoom); - } - - /* Copy the main data directly from the sprite */ - bp.sprite = sprite->data; - bp.sprite_width = sprite->width; - bp.sprite_height = sprite->height; - bp.top = 0; - bp.left = 0; - - bp.dst = dpi->dst_ptr; - bp.pitch = dpi->pitch; - bp.remap = _colour_remap_ptr; - - assert(sprite->width > 0); - assert(sprite->height > 0); - - if (bp.width <= 0) return; - if (bp.height <= 0) return; - - y -= SCALED_XY ? ScaleByZoom(dpi->top, zoom) : dpi->top; - int y_unscaled = UnScaleByZoom(y, zoom); - /* Check for top overflow */ - if (y < 0) { - bp.height -= -y_unscaled; - if (bp.height <= 0) return; - bp.skip_top += -y_unscaled; - y = 0; - } else { - bp.top = y_unscaled; - } - - /* Check for bottom overflow */ - y += SCALED_XY ? ScaleByZoom(bp.height - dpi->height, zoom) : ScaleByZoom(bp.height, zoom) - dpi->height; - if (y > 0) { - bp.height -= UnScaleByZoom(y, zoom); - if (bp.height <= 0) return; - } - - x -= SCALED_XY ? ScaleByZoom(dpi->left, zoom) : dpi->left; - int x_unscaled = UnScaleByZoom(x, zoom); - /* Check for left overflow */ - if (x < 0) { - bp.width -= -x_unscaled; - if (bp.width <= 0) return; - bp.skip_left += -x_unscaled; - x = 0; - } else { - bp.left = x_unscaled; - } - - /* Check for right overflow */ - x += SCALED_XY ? ScaleByZoom(bp.width - dpi->width, zoom) : ScaleByZoom(bp.width, zoom) - dpi->width; - if (x > 0) { - bp.width -= UnScaleByZoom(x, zoom); - if (bp.width <= 0) return; - } - - assert(bp.skip_left + bp.width <= UnScaleByZoom(sprite->width, zoom)); - assert(bp.skip_top + bp.height <= UnScaleByZoom(sprite->height, zoom)); - - /* We do not want to catch the mouse. However we also use that spritenumber for unknown (text) sprites. */ - if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW && sprite_id != SPR_CURSOR_MOUSE) { - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - void *topleft = blitter->MoveTo(bp.dst, bp.left, bp.top); - void *bottomright = blitter->MoveTo(topleft, bp.width - 1, bp.height - 1); - - void *clicked = _newgrf_debug_sprite_picker.clicked_pixel; - - if (topleft <= clicked && clicked <= bottomright) { - uint offset = (((size_t)clicked - (size_t)topleft) / (blitter->GetScreenDepth() / 8)) % bp.pitch; - if (offset < (uint)bp.width) { - _newgrf_debug_sprite_picker.sprites.Include(sprite_id); - } - } - } - - BlitterFactory::GetCurrentBlitter()->Draw(&bp, mode, zoom); -} - -static void GfxMainBlitterViewport(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub, SpriteID sprite_id) -{ - GfxBlitter(sprite, x, y, mode, sub, sprite_id, _cur_dpi->zoom); -} - -static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub, SpriteID sprite_id, ZoomLevel zoom) -{ - GfxBlitter<1, true>(sprite, x, y, mode, sub, sprite_id, zoom); -} - -void DoPaletteAnimations(); - -void GfxInitPalettes() -{ - memcpy(&_cur_palette, &_palette, sizeof(_cur_palette)); - DoPaletteAnimations(); -} - -#define EXTR(p, q) (((uint16)(palette_animation_counter * (p)) * (q)) >> 16) -#define EXTR2(p, q) (((uint16)(~palette_animation_counter * (p)) * (q)) >> 16) - -void DoPaletteAnimations() -{ - /* Animation counter for the palette animation. */ - static int palette_animation_counter = 0; - palette_animation_counter += 8; - - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - const Colour *s; - const ExtraPaletteValues *ev = &_extra_palette_values; - Colour old_val[PALETTE_ANIM_SIZE]; - const uint old_tc = palette_animation_counter; - uint i; - uint j; - - if (blitter != NULL && blitter->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_NONE) { - palette_animation_counter = 0; - } - - Colour *palette_pos = &_cur_palette.palette[PALETTE_ANIM_START]; // Points to where animations are taking place on the palette - /* Makes a copy of the current animation palette in old_val, - * so the work on the current palette could be compared, see if there has been any changes */ - memcpy(old_val, palette_pos, sizeof(old_val)); - - /* Fizzy Drink bubbles animation */ - s = ev->fizzy_drink; - j = EXTR2(512, EPV_CYCLES_FIZZY_DRINK); - for (i = 0; i != EPV_CYCLES_FIZZY_DRINK; i++) { - *palette_pos++ = s[j]; - j++; - if (j == EPV_CYCLES_FIZZY_DRINK) j = 0; - } - - /* Oil refinery fire animation */ - s = ev->oil_refinery; - j = EXTR2(512, EPV_CYCLES_OIL_REFINERY); - for (i = 0; i != EPV_CYCLES_OIL_REFINERY; i++) { - *palette_pos++ = s[j]; - j++; - if (j == EPV_CYCLES_OIL_REFINERY) j = 0; - } - - /* Radio tower blinking */ - { - byte i = (palette_animation_counter >> 1) & 0x7F; - byte v; - - if (i < 0x3f) { - v = 255; - } else if (i < 0x4A || i >= 0x75) { - v = 128; - } else { - v = 20; - } - palette_pos->r = v; - palette_pos->g = 0; - palette_pos->b = 0; - palette_pos++; - - i ^= 0x40; - if (i < 0x3f) { - v = 255; - } else if (i < 0x4A || i >= 0x75) { - v = 128; - } else { - v = 20; - } - palette_pos->r = v; - palette_pos->g = 0; - palette_pos->b = 0; - palette_pos++; - } - - /* Handle lighthouse and stadium animation */ - s = ev->lighthouse; - j = EXTR(256, EPV_CYCLES_LIGHTHOUSE); - for (i = 0; i != EPV_CYCLES_LIGHTHOUSE; i++) { - *palette_pos++ = s[j]; - j++; - if (j == EPV_CYCLES_LIGHTHOUSE) j = 0; - } - - /* Dark blue water */ - s = (_settings_game.game_creation.landscape == LT_TOYLAND) ? ev->dark_water_toyland : ev->dark_water; - j = EXTR(320, EPV_CYCLES_DARK_WATER); - for (i = 0; i != EPV_CYCLES_DARK_WATER; i++) { - *palette_pos++ = s[j]; - j++; - if (j == EPV_CYCLES_DARK_WATER) j = 0; - } - - /* Glittery water */ - s = (_settings_game.game_creation.landscape == LT_TOYLAND) ? ev->glitter_water_toyland : ev->glitter_water; - j = EXTR(128, EPV_CYCLES_GLITTER_WATER); - for (i = 0; i != EPV_CYCLES_GLITTER_WATER / 3; i++) { - *palette_pos++ = s[j]; - j += 3; - if (j >= EPV_CYCLES_GLITTER_WATER) j -= EPV_CYCLES_GLITTER_WATER; - } - - if (blitter != NULL && blitter->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_NONE) { - palette_animation_counter = old_tc; - } else { - if (memcmp(old_val, &_cur_palette.palette[PALETTE_ANIM_START], sizeof(old_val)) != 0 && _cur_palette.count_dirty == 0) { - /* Did we changed anything on the palette? Seems so. Mark it as dirty */ - _cur_palette.first_dirty = PALETTE_ANIM_START; - _cur_palette.count_dirty = PALETTE_ANIM_SIZE; - } - } -} - -/** - * Determine a contrasty text colour for a coloured background. - * @param background Background colour. - * @return TC_BLACK or TC_WHITE depending on what gives a better contrast. - */ -TextColour GetContrastColour(uint8 background) -{ - Colour c = _cur_palette.palette[background]; - /* Compute brightness according to http://www.w3.org/TR/AERT#color-contrast. - * The following formula computes 1000 * brightness^2, with brightness being in range 0 to 255. */ - uint sq1000_brightness = c.r * c.r * 299 + c.g * c.g * 587 + c.b * c.b * 114; - /* Compare with threshold brightness 128 (50%) */ - return sq1000_brightness < 128 * 128 * 1000 ? TC_WHITE : TC_BLACK; -} - -/** - * Initialize _stringwidth_table cache - * @param monospace Whether to load the monospace cache or the normal fonts. - */ -void LoadStringWidthTable(bool monospace) -{ - for (FontSize fs = monospace ? FS_MONO : FS_BEGIN; fs < (monospace ? FS_END : FS_MONO); fs++) { - for (uint i = 0; i != 224; i++) { - _stringwidth_table[fs][i] = GetGlyphWidth(fs, i + 32); - } - } - - ReInitAllWindows(); -} - -/** - * Return width of character glyph. - * @param size Font of the character - * @param key Character code glyph - * @return Width of the character glyph - */ -byte GetCharacterWidth(FontSize size, WChar key) -{ - /* Use _stringwidth_table cache if possible */ - if (key >= 32 && key < 256) return _stringwidth_table[size][key - 32]; - - return GetGlyphWidth(size, key); -} - -/** - * Return the maximum width of single digit. - * @param size Font of the digit - * @return Width of the digit. - */ -byte GetDigitWidth(FontSize size) -{ - byte width = 0; - for (char c = '0'; c <= '9'; c++) { - width = max(GetCharacterWidth(size, c), width); - } - return width; -} - -/** - * Determine the broadest digits for guessing the maximum width of a n-digit number. - * @param [out] front Broadest digit, which is not 0. (Use this digit as first digit for numbers with more than one digit.) - * @param [out] next Broadest digit, including 0. (Use this digit for all digits, except the first one; or for numbers with only one digit.) - * @param size Font of the digit - */ -void GetBroadestDigit(uint *front, uint *next, FontSize size) -{ - int width = -1; - for (char c = '9'; c >= '0'; c--) { - int w = GetCharacterWidth(size, c); - if (w > width) { - width = w; - *next = c - '0'; - if (c != '0') *front = c - '0'; - } - } -} - -void ScreenSizeChanged() -{ - _dirty_bytes_per_line = CeilDiv(_screen.width, DIRTY_BLOCK_WIDTH); - _dirty_blocks = ReallocT(_dirty_blocks, _dirty_bytes_per_line * CeilDiv(_screen.height, DIRTY_BLOCK_HEIGHT)); - - /* check the dirty rect */ - if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width; - if (_invalid_rect.bottom >= _screen.height) _invalid_rect.bottom = _screen.height; - - /* screen size changed and the old bitmap is invalid now, so we don't want to undraw it */ - _cursor.visible = false; - - CheckWindowMinSizings(); -} - -void UndrawMouseCursor() -{ - /* Don't undraw the mouse cursor if the screen is not ready */ - if (_screen.dst_ptr == NULL) return; - - if (_cursor.visible) { - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - _cursor.visible = false; - blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, _cursor.draw_pos.x, _cursor.draw_pos.y), _cursor_backup.GetBuffer(), _cursor.draw_size.x, _cursor.draw_size.y); - _video_driver->MakeDirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y); - } -} - -void DrawMouseCursor() -{ -#if defined(WINCE) - /* Don't ever draw the mouse for WinCE, as we work with a stylus */ - return; -#endif - - /* Don't draw the mouse cursor if the screen is not ready */ - if (_screen.dst_ptr == NULL) return; - - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - int x; - int y; - int w; - int h; - - /* Redraw mouse cursor but only when it's inside the window */ - if (!_cursor.in_window) return; - - /* Don't draw the mouse cursor if it's already drawn */ - if (_cursor.visible) { - if (!_cursor.dirty) return; - UndrawMouseCursor(); - } - - w = _cursor.size.x; - x = _cursor.pos.x + _cursor.offs.x + _cursor.short_vehicle_offset; - if (x < 0) { - w += x; - x = 0; - } - if (w > _screen.width - x) w = _screen.width - x; - if (w <= 0) return; - _cursor.draw_pos.x = x; - _cursor.draw_size.x = w; - - h = _cursor.size.y; - y = _cursor.pos.y + _cursor.offs.y; - if (y < 0) { - h += y; - y = 0; - } - if (h > _screen.height - y) h = _screen.height - y; - if (h <= 0) return; - _cursor.draw_pos.y = y; - _cursor.draw_size.y = h; - - uint8 *buffer = _cursor_backup.Allocate(blitter->BufferSize(w, h)); - - /* Make backup of stuff below cursor */ - blitter->CopyToBuffer(blitter->MoveTo(_screen.dst_ptr, _cursor.draw_pos.x, _cursor.draw_pos.y), buffer, _cursor.draw_size.x, _cursor.draw_size.y); - - /* Draw cursor on screen */ - _cur_dpi = &_screen; - DrawSprite(_cursor.sprite, _cursor.pal, _cursor.pos.x + _cursor.short_vehicle_offset, _cursor.pos.y); - - _video_driver->MakeDirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y); - - _cursor.visible = true; - _cursor.dirty = false; -} - -void RedrawScreenRect(int left, int top, int right, int bottom) -{ - assert(right <= _screen.width && bottom <= _screen.height); - if (_cursor.visible) { - if (right > _cursor.draw_pos.x && - left < _cursor.draw_pos.x + _cursor.draw_size.x && - bottom > _cursor.draw_pos.y && - top < _cursor.draw_pos.y + _cursor.draw_size.y) { - UndrawMouseCursor(); - } - } - -#ifdef ENABLE_NETWORK - if (_networking) NetworkUndrawChatMessage(); -#endif /* ENABLE_NETWORK */ - - DrawOverlappedWindowForAll(left, top, right, bottom); - - _video_driver->MakeDirty(left, top, right - left, bottom - top); -} - -/** - * Repaints the rectangle blocks which are marked as 'dirty'. - * - * @see SetDirtyBlocks - */ -void DrawDirtyBlocks() -{ - byte *b = _dirty_blocks; - const int w = Align(_screen.width, DIRTY_BLOCK_WIDTH); - const int h = Align(_screen.height, DIRTY_BLOCK_HEIGHT); - int x; - int y; - - if (HasModalProgress()) { - /* We are generating the world, so release our rights to the map and - * painting while we are waiting a bit. */ - _modal_progress_paint_mutex->EndCritical(); - _modal_progress_work_mutex->EndCritical(); - - /* Wait a while and update _realtime_tick so we are given the rights */ - if (!IsFirstModalProgressLoop()) CSleep(MODAL_PROGRESS_REDRAW_TIMEOUT); - _realtime_tick += MODAL_PROGRESS_REDRAW_TIMEOUT; - _modal_progress_paint_mutex->BeginCritical(); - _modal_progress_work_mutex->BeginCritical(); - - /* When we ended with the modal progress, do not draw the blocks. - * Simply let the next run do so, otherwise we would be loading - * the new state (and possibly change the blitter) when we hold - * the drawing lock, which we must not do. */ - if (_switch_mode != SM_NONE && !HasModalProgress()) return; - } - - y = 0; - do { - x = 0; - do { - if (*b != 0) { - int left; - int top; - int right = x + DIRTY_BLOCK_WIDTH; - int bottom = y; - byte *p = b; - int h2; - - /* First try coalescing downwards */ - do { - *p = 0; - p += _dirty_bytes_per_line; - bottom += DIRTY_BLOCK_HEIGHT; - } while (bottom != h && *p != 0); - - /* Try coalescing to the right too. */ - h2 = (bottom - y) / DIRTY_BLOCK_HEIGHT; - assert(h2 > 0); - p = b; - - while (right != w) { - byte *p2 = ++p; - int h = h2; - /* Check if a full line of dirty flags is set. */ - do { - if (!*p2) goto no_more_coalesc; - p2 += _dirty_bytes_per_line; - } while (--h != 0); - - /* Wohoo, can combine it one step to the right! - * Do that, and clear the bits. */ - right += DIRTY_BLOCK_WIDTH; - - h = h2; - p2 = p; - do { - *p2 = 0; - p2 += _dirty_bytes_per_line; - } while (--h != 0); - } - no_more_coalesc: - - left = x; - top = y; - - if (left < _invalid_rect.left ) left = _invalid_rect.left; - if (top < _invalid_rect.top ) top = _invalid_rect.top; - if (right > _invalid_rect.right ) right = _invalid_rect.right; - if (bottom > _invalid_rect.bottom) bottom = _invalid_rect.bottom; - - if (left < right && top < bottom) { - RedrawScreenRect(left, top, right, bottom); - } - - } - } while (b++, (x += DIRTY_BLOCK_WIDTH) != w); - } while (b += -(int)(w / DIRTY_BLOCK_WIDTH) + _dirty_bytes_per_line, (y += DIRTY_BLOCK_HEIGHT) != h); - - ++_dirty_block_colour; - _invalid_rect.left = w; - _invalid_rect.top = h; - _invalid_rect.right = 0; - _invalid_rect.bottom = 0; -} - -/** - * This function extends the internal _invalid_rect rectangle as it - * now contains the rectangle defined by the given parameters. Note - * the point (0,0) is top left. - * - * @param left The left edge of the rectangle - * @param top The top edge of the rectangle - * @param right The right edge of the rectangle - * @param bottom The bottom edge of the rectangle - * @see DrawDirtyBlocks - * - * @todo The name of the function should be called like @c AddDirtyBlock as - * it neither set a dirty rect nor add several dirty rects although - * the function name is in plural. (Progman) - */ -void SetDirtyBlocks(int left, int top, int right, int bottom) -{ - byte *b; - int width; - int height; - - if (left < 0) left = 0; - if (top < 0) top = 0; - if (right > _screen.width) right = _screen.width; - if (bottom > _screen.height) bottom = _screen.height; - - if (left >= right || top >= bottom) return; - - if (left < _invalid_rect.left ) _invalid_rect.left = left; - if (top < _invalid_rect.top ) _invalid_rect.top = top; - if (right > _invalid_rect.right ) _invalid_rect.right = right; - if (bottom > _invalid_rect.bottom) _invalid_rect.bottom = bottom; - - left /= DIRTY_BLOCK_WIDTH; - top /= DIRTY_BLOCK_HEIGHT; - - b = _dirty_blocks + top * _dirty_bytes_per_line + left; - - width = ((right - 1) / DIRTY_BLOCK_WIDTH) - left + 1; - height = ((bottom - 1) / DIRTY_BLOCK_HEIGHT) - top + 1; - - assert(width > 0 && height > 0); - - do { - int i = width; - - do b[--i] = 0xFF; while (i != 0); - - b += _dirty_bytes_per_line; - } while (--height != 0); -} - -/** - * This function mark the whole screen as dirty. This results in repainting - * the whole screen. Use this with care as this function will break the - * idea about marking only parts of the screen as 'dirty'. - * @ingroup dirty - */ -void MarkWholeScreenDirty() -{ - SetDirtyBlocks(0, 0, _screen.width, _screen.height); -} - -/** - * Set up a clipping area for only drawing into a certain area. To do this, - * Fill a DrawPixelInfo object with the supplied relative rectangle, backup - * the original (calling) _cur_dpi and assign the just returned DrawPixelInfo - * _cur_dpi. When you are done, give restore _cur_dpi's original value - * @param *n the DrawPixelInfo that will be the clipping rectangle box allowed - * for drawing - * @param left,top,width,height the relative coordinates of the clipping - * rectangle relative to the current _cur_dpi. This will most likely be the - * offset from the calling window coordinates - * @return return false if the requested rectangle is not possible with the - * current dpi pointer. Only continue of the return value is true, or you'll - * get some nasty results - */ -bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int height) -{ - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - const DrawPixelInfo *o = _cur_dpi; - - n->zoom = ZOOM_LVL_NORMAL; - - assert(width > 0); - assert(height > 0); - - if ((left -= o->left) < 0) { - width += left; - if (width <= 0) return false; - n->left = -left; - left = 0; - } else { - n->left = 0; - } - - if (width > o->width - left) { - width = o->width - left; - if (width <= 0) return false; - } - n->width = width; - - if ((top -= o->top) < 0) { - height += top; - if (height <= 0) return false; - n->top = -top; - top = 0; - } else { - n->top = 0; - } - - n->dst_ptr = blitter->MoveTo(o->dst_ptr, left, top); - n->pitch = o->pitch; - - if (height > o->height - top) { - height = o->height - top; - if (height <= 0) return false; - } - n->height = height; - - return true; -} - -/** - * Update cursor dimension. - * Called when changing cursor sprite resp. reloading grfs. - */ -void UpdateCursorSize() -{ - CursorVars *cv = &_cursor; - const Sprite *p = GetSprite(GB(cv->sprite, 0, SPRITE_WIDTH), ST_NORMAL); - - cv->size.y = UnScaleByZoom(p->height, ZOOM_LVL_GUI); - cv->size.x = UnScaleByZoom(p->width, ZOOM_LVL_GUI); - cv->offs.x = UnScaleByZoom(p->x_offs, ZOOM_LVL_GUI); - cv->offs.y = UnScaleByZoom(p->y_offs, ZOOM_LVL_GUI); - - cv->dirty = true; -} - -/** - * Switch cursor to different sprite. - * @param cursor Sprite to draw for the cursor. - * @param pal Palette to use for recolouring. - */ -static void SetCursorSprite(CursorID cursor, PaletteID pal) -{ - CursorVars *cv = &_cursor; - if (cv->sprite == cursor) return; - - cv->sprite = cursor; - cv->pal = pal; - UpdateCursorSize(); - - cv->short_vehicle_offset = 0; -} - -static void SwitchAnimatedCursor() -{ - const AnimCursor *cur = _cursor.animate_cur; - - if (cur == NULL || cur->sprite == AnimCursor::LAST) cur = _cursor.animate_list; - - SetCursorSprite(cur->sprite, _cursor.pal); - - _cursor.animate_timeout = cur->display_time; - _cursor.animate_cur = cur + 1; -} - -void CursorTick() -{ - if (_cursor.animate_timeout != 0 && --_cursor.animate_timeout == 0) { - SwitchAnimatedCursor(); - } -} - -/** - * Assign a single non-animated sprite to the cursor. - * @param sprite Sprite to draw for the cursor. - * @param pal Palette to use for recolouring. - * @see SetAnimatedMouseCursor - */ -void SetMouseCursor(CursorID sprite, PaletteID pal) -{ - /* Turn off animation */ - _cursor.animate_timeout = 0; - /* Set cursor */ - SetCursorSprite(sprite, pal); -} - -/** - * Assign an animation to the cursor. - * @param table Array of animation states. - * @see SetMouseCursor - */ -void SetAnimatedMouseCursor(const AnimCursor *table) -{ - _cursor.animate_list = table; - _cursor.animate_cur = NULL; - _cursor.pal = PAL_NONE; - SwitchAnimatedCursor(); -} - -bool ChangeResInGame(int width, int height) -{ - return (_screen.width == width && _screen.height == height) || _video_driver->ChangeResolution(width, height); -} - -bool ToggleFullScreen(bool fs) -{ - bool result = _video_driver->ToggleFullscreen(fs); - if (_fullscreen != fs && _num_resolutions == 0) { - DEBUG(driver, 0, "Could not find a suitable fullscreen resolution"); - } - return result; -} - -static int CDECL compare_res(const Dimension *pa, const Dimension *pb) -{ - int x = pa->width - pb->width; - if (x != 0) return x; - return pa->height - pb->height; -} - -void SortResolutions(int count) -{ - QSortT(_resolutions, count, &compare_res); -} - - -/** - * Returns the initial value for a margin, after telling where are the left and right margins and where we want to draw/write (begining/end of line) - * @param left is the left margin of the horizontal space we want to draw to - * @param right: right margin - * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end - * @return the margin we asked - */ -int InitTempMargin(int left, int right, bool to_end_line) -{ - return to_end_line ^ (_current_text_dir == TD_RTL) ? right :left; -} - -/** - * Consumes a space in an horizontal margin - * @param space: amount of space used - * @param here: the margin where to add the space - * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end - */ -void AddSpace(int space, int &here, bool to_end_line) -{ - here += to_end_line ^ (_current_text_dir == TD_RTL) ? -space : space; -} - -/** - * After drawing something, update a margin - * @param end is where we ended drawing (usually the return value of a DrawString function) - * @param margin is the margin we want to update - * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end - */ -void UpdateMarginEnd(int end, int &margin, bool to_end_line) -{ - margin = to_end_line ^ (_current_text_dir == TD_RTL) ? min(end, margin) : max(end, margin); -} - -/** - * After drawing something, horizontal margins are updated - * @param end: last position drawn - * @param left is the left margin of the horizontal space drawn - * @param right: right margin - * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end - */ -void UpdateMarginsEnd(int end, int &left, int &right, bool to_end_line) -{ - if (to_end_line ^ (_current_text_dir == TD_RTL)) { - right = end; - } else { - left = end; - } -} - -/** - * After drawing something of a certain width, update margins - * @param width: used space - * @param initial left margin - * @param initial right margin - * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end - */ -void UpdateMarginsWidth(int width, int &left, int &right, bool to_end_line) -{ - if (to_end_line ^ (_current_text_dir == TD_RTL)) { - right -= width; - } else { - left += width; - } -} - -/** - * Draws a string in a delimited space; temporal margin gets updated - * @param left is the left margin of the horizontal space we want to draw to - * @param right: right margin of the horizontal space we want to draw to - * @param top: vertical position - * @param margin keeps the most extreme limit used of the line (this should be previously initialized with InitTempLimit) - * @param string to draw - * @param colour for the string - * @param alignment of the string (only left or right alignment) - * @param underline - */ -void DrawString2(int left, int right, int top, int &margin, StringID str, TextColour colour, StringAlignment align, bool underline) -{ - int end = DrawString(left, right, top, str, colour, align, underline); - UpdateMarginEnd(end, margin, align == SA_RIGHT); -} - -/** - * Draws a sprite in a delimited space; temporal margin gets updated - * @param width of the sprite - * @param left is the left margin of the horizontal space we want to draw to - * @param right: right margin of the horizontal space - * @param top: vertical position - * @param margin keeps the most extreme limit used of the line (this should be previously initialized with InitTempLimit) - * @param sprite - * @param palette - * @param to_end_line: 0 if working at the begining of the line, 1 if working at the end - */ -void DrawSprite2(int width, int left, int right, int top, int &margin, SpriteID img, PaletteID pal, bool to_end_line, SubSprite *sub) -{ - DrawSprite(img, pal, to_end_line ^ (_current_text_dir == TD_RTL) ? right - width : left, top, sub); - margin = to_end_line ^ (_current_text_dir == TD_RTL) ? min(right - width, margin): max(margin, left + width); -} diff --git a/src/gfx_func.h.orig b/src/gfx_func.h.orig deleted file mode 100644 index 33b13c1fd8..0000000000 --- a/src/gfx_func.h.orig +++ /dev/null @@ -1,226 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file gfx_func.h Functions related to the gfx engine. */ - -/** - * @defgroup dirty Dirty - * - * Handles the repaint of some part of the screen. - * - * Some places in the code are called functions which makes something "dirty". - * This has nothing to do with making a Tile or Window darker or less visible. - * This term comes from memory caching and is used to define an object must - * be repaint. If some data of an object (like a Tile, Window, Vehicle, whatever) - * are changed which are so extensive the object must be repaint its marked - * as "dirty". The video driver repaint this object instead of the whole screen - * (this is btw. also possible if needed). This is used to avoid a - * flickering of the screen by the video driver constantly repainting it. - * - * This whole mechanism is controlled by an rectangle defined in #_invalid_rect. This - * rectangle defines the area on the screen which must be repaint. If a new object - * needs to be repainted this rectangle is extended to 'catch' the object on the - * screen. At some point (which is normally uninteresting for patch writers) this - * rectangle is send to the video drivers method - * VideoDriver::MakeDirty and it is truncated back to an empty rectangle. At some - * later point (which is uninteresting, too) the video driver - * repaints all these saved rectangle instead of the whole screen and drop the - * rectangle informations. Then a new round begins by marking objects "dirty". - * - * @see VideoDriver::MakeDirty - * @see _invalid_rect - * @see _screen - */ - - -#ifndef GFX_FUNC_H -#define GFX_FUNC_H - -#include "gfx_type.h" -#include "strings_type.h" -#include "string_type.h" - -void GameLoop(); - -void CreateConsole(); - -extern byte _dirkeys; ///< 1 = left, 2 = up, 4 = right, 8 = down -extern bool _fullscreen; -extern CursorVars _cursor; -extern bool _ctrl_pressed; ///< Is Ctrl pressed? -extern bool _shift_pressed; ///< Is Shift pressed? -extern byte _fast_forward; - -extern bool _left_button_down; -extern bool _left_button_clicked; -extern bool _right_button_down; -extern bool _right_button_clicked; - -extern DrawPixelInfo _screen; -extern bool _screen_disable_anim; ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot) - -extern int _num_resolutions; -extern Dimension _resolutions[32]; -extern Dimension _cur_resolution; -extern Palette _cur_palette; ///< Current palette - -void HandleKeypress(uint keycode, WChar key); -void HandleTextInput(const char *str, bool marked = false, const char *caret = NULL, const char *insert_location = NULL, const char *replacement_end = NULL); -void HandleCtrlChanged(); -void HandleMouseEvents(); -void CSleep(int milliseconds); -void UpdateWindows(); - -void DrawMouseCursor(); -void ScreenSizeChanged(); -void GameSizeChanged(); -void UndrawMouseCursor(); - -/** Size of the buffer used for drawing strings. */ -static const int DRAW_STRING_BUFFER = 2048; - -void RedrawScreenRect(int left, int top, int right, int bottom); -void GfxScroll(int left, int top, int width, int height, int xo, int yo); - -Dimension GetSpriteSize(SpriteID sprid, Point *offset = NULL, ZoomLevel zoom = ZOOM_LVL_GUI); -void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = NULL); -void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = NULL, ZoomLevel zoom = ZOOM_LVL_GUI); - -/** How to align the to-be drawn text. */ -enum StringAlignment { - SA_LEFT = 0 << 0, ///< Left align the text. - SA_HOR_CENTER = 1 << 0, ///< Horizontally center the text. - SA_RIGHT = 2 << 0, ///< Right align the text (must be a single bit). - SA_HOR_MASK = 3 << 0, ///< Mask for horizontal alignment. - - SA_TOP = 0 << 2, ///< Top align the text. - SA_VERT_CENTER = 1 << 2, ///< Vertically center the text. - SA_BOTTOM = 2 << 2, ///< Bottom align the text. - SA_VERT_MASK = 3 << 2, ///< Mask for vertical alignment. - - SA_CENTER = SA_HOR_CENTER | SA_VERT_CENTER, ///< Center both horizontally and vertically. - - SA_FORCE = 1 << 4, ///< Force the alignment, i.e. don't swap for RTL languages. -}; -DECLARE_ENUM_AS_BIT_SET(StringAlignment) - -int DrawString(int left, int right, int top, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL); -int DrawString(int left, int right, int top, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL); -int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); -int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); - -void DrawCharCentered(uint32 c, int x, int y, TextColour colour); - -void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode = FILLRECT_OPAQUE); -void GfxDrawLine(int left, int top, int right, int bottom, int colour, int width = 1, int dash = 0); -void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3); - -Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize = FS_NORMAL); -Dimension GetStringBoundingBox(StringID strid); -int GetStringHeight(const char *str, int maxw, FontSize fontsize = FS_NORMAL); -int GetStringHeight(StringID str, int maxw); -int GetStringLineCount(StringID str, int maxw); -Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion); -Dimension GetStringMultiLineBoundingBox(const char *str, const Dimension &suggestion); -void LoadStringWidthTable(bool monospace = false); -Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsize = FS_NORMAL); -const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize = FS_NORMAL); - -void DrawDirtyBlocks(); -void SetDirtyBlocks(int left, int top, int right, int bottom); -void MarkWholeScreenDirty(); - -void GfxInitPalettes(); -void CheckBlitter(); - -bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int height); - -/* window.cpp */ -void DrawOverlappedWindowForAll(int left, int top, int right, int bottom); - -void SetMouseCursor(CursorID cursor, PaletteID pal); -void SetAnimatedMouseCursor(const AnimCursor *table); -void CursorTick(); -void UpdateCursorSize(); -bool ChangeResInGame(int w, int h); -void SortResolutions(int count); -bool ToggleFullScreen(bool fs); - -/* gfx.cpp */ -byte GetCharacterWidth(FontSize size, uint32 key); -byte GetDigitWidth(FontSize size = FS_NORMAL); -void GetBroadestDigit(uint *front, uint *next, FontSize size = FS_NORMAL); - -int GetCharacterHeight(FontSize size); - -/** Height of characters in the small (#FS_SMALL) font. */ -#define FONT_HEIGHT_SMALL (GetCharacterHeight(FS_SMALL)) - -/** Height of characters in the normal (#FS_NORMAL) font. */ -#define FONT_HEIGHT_NORMAL (GetCharacterHeight(FS_NORMAL)) - -/** Height of characters in the large (#FS_LARGE) font. */ -#define FONT_HEIGHT_LARGE (GetCharacterHeight(FS_LARGE)) - -/** Height of characters in the large (#FS_MONO) font. */ -#define FONT_HEIGHT_MONO (GetCharacterHeight(FS_MONO)) - -int InitTempMargin(int left, int right, bool to_end_line); -void AddSpace(int space, int &here, bool to_end_line); - -void UpdateMarginEnd(int end, int &margin, bool to_end_line); -void UpdateMarginWidth(int adding, int &margin, bool to_end_line); -void UpdateMarginsEnd(int end, int &left, int &right, bool to_end_line); -void UpdateMarginsWidth(int width, int &left, int &right, bool to_end_line); - -void DrawString2(int left, int right, int top, int &margin, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false); -void DrawSprite2(int width, int left, int right, int top, int &margin, SpriteID img, PaletteID pal, bool to_end_line = false, SubSprite *sub = NULL); - -extern DrawPixelInfo *_cur_dpi; - -TextColour GetContrastColour(uint8 background); - -/** - * All 16 colour gradients - * 8 colours per gradient from darkest (0) to lightest (7) - */ -extern byte _colour_gradient[COLOUR_END][8]; - -extern bool _palette_remap_grf[]; - -/** - * Return the colour for a particular greyscale level. - * @param level Intensity, 0 = black, 15 = white - * @return colour - */ -#define GREY_SCALE(level) (level) - -static const uint8 PC_BLACK = GREY_SCALE(1); ///< Black palette colour. -static const uint8 PC_DARK_GREY = GREY_SCALE(6); ///< Dark grey palette colour. -static const uint8 PC_GREY = GREY_SCALE(10); ///< Grey palette colour. -static const uint8 PC_WHITE = GREY_SCALE(15); ///< White palette colour. - -static const uint8 PC_VERY_DARK_RED = 0xB2; ///< Almost-black red palette colour. -static const uint8 PC_DARK_RED = 0xB4; ///< Dark red palette colour. -static const uint8 PC_RED = 0xB8; ///< Red palette colour. - -static const uint8 PC_VERY_DARK_BROWN = 0x56; ///< Almost-black brown palette colour. - -static const uint8 PC_ORANGE = 0xC2; ///< Orange palette colour. - -static const uint8 PC_YELLOW = 0xBF; ///< Yellow palette colour. -static const uint8 PC_LIGHT_YELLOW = 0x44; ///< Light yellow palette colour. -static const uint8 PC_VERY_LIGHT_YELLOW = 0x45; ///< Almost-white yellow palette colour. - -static const uint8 PC_GREEN = 0xD0; ///< Green palette colour. - -static const uint8 PC_DARK_BLUE = 0x9D; ///< Dark blue palette colour. -static const uint8 PC_LIGHT_BLUE = 0x98; ///< Light blue palette colour. - -#endif /* GFX_FUNC_H */ diff --git a/src/group_gui.cpp.orig b/src/group_gui.cpp.orig deleted file mode 100644 index 93349a3f5d..0000000000 --- a/src/group_gui.cpp.orig +++ /dev/null @@ -1,891 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file group_gui.cpp GUI for the group window. */ - -#include "stdafx.h" -#include "textbuf_gui.h" -#include "command_func.h" -#include "vehicle_gui.h" -#include "vehicle_base.h" -#include "string_func.h" -#include "strings_func.h" -#include "window_func.h" -#include "vehicle_func.h" -#include "autoreplace_gui.h" -#include "company_func.h" -#include "widgets/dropdown_func.h" -#include "tilehighlight_func.h" -#include "vehicle_gui_base.h" -#include "core/geometry_func.hpp" -#include "company_base.h" - -#include "widgets/group_widget.h" - -#include "table/sprites.h" - -typedef GUIList GUIGroupList; - -static const NWidgetPart _nested_group_widgets[] = { - NWidget(NWID_HORIZONTAL), // Window header - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, WID_GL_CAPTION), - NWidget(WWT_SHADEBOX, COLOUR_GREY), - NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), - NWidget(WWT_STICKYBOX, COLOUR_GREY), - EndContainer(), - NWidget(NWID_HORIZONTAL), - /* left part */ - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalTextLines(1, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM), SetFill(1, 0), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_ALL_VEHICLES), SetFill(1, 0), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_DEFAULT_VEHICLES), SetFill(1, 0), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_GL_LIST_GROUP), SetMatrixDataTip(1, 0, STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP), - SetFill(1, 0), SetResize(0, 1), SetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_GL_LIST_GROUP_SCROLLBAR), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_CREATE_GROUP), SetFill(0, 1), - SetDataTip(SPR_GROUP_CREATE_TRAIN, STR_GROUP_CREATE_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_DELETE_GROUP), SetFill(0, 1), - SetDataTip(SPR_GROUP_DELETE_TRAIN, STR_GROUP_DELETE_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_RENAME_GROUP), SetFill(0, 1), - SetDataTip(SPR_GROUP_RENAME_TRAIN, STR_GROUP_RENAME_TOOLTIP), - NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), EndContainer(), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_REPLACE_PROTECTION), SetFill(0, 1), - SetDataTip(SPR_GROUP_REPLACE_OFF_TRAIN, STR_GROUP_REPLACE_PROTECTION_TOOLTIP), - EndContainer(), - EndContainer(), - /* right part */ - NWidget(NWID_VERTICAL), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_SORT_BY_ORDER), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_SORT_BY_DROPDOWN), SetMinimalSize(167, 12), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetResize(1, 0), EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_GL_LIST_VEHICLE), SetMinimalSize(248, 0), SetMatrixDataTip(1, 0, STR_NULL), SetResize(1, 1), SetFill(1, 0), SetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_GL_LIST_VEHICLE_SCROLLBAR), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(1, 0), SetFill(1, 1), SetResize(1, 0), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_AVAILABLE_VEHICLES), SetMinimalSize(106, 12), SetFill(0, 1), - SetDataTip(STR_BLACK_STRING, STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 1), SetResize(1, 0), EndContainer(), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_MANAGE_VEHICLES_DROPDOWN), SetMinimalSize(118, 12), SetFill(0, 1), - SetDataTip(STR_VEHICLE_LIST_MANAGE_LIST, STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_STOP_ALL), SetMinimalSize(12, 12), SetFill(0, 1), - SetDataTip(SPR_FLAG_VEH_STOPPED, STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_START_ALL), SetMinimalSize(12, 12), SetFill(0, 1), - SetDataTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), - EndContainer(), - EndContainer(), - EndContainer(), -}; - -class VehicleGroupWindow : public BaseVehicleListWindow { -private: - /* Columns in the group list */ - enum ListColumns { - VGC_NAME, ///< Group name. - VGC_PROTECT, ///< Autoreplace protect icon. - VGC_AUTOREPLACE, ///< Autoreplace active icon. - VGC_PROFIT, ///< Profit icon. - VGC_NUMBER, ///< Number of vehicles in the group. - - VGC_END - }; - - VehicleID vehicle_sel; ///< Selected vehicle - GroupID group_rename; ///< Group being renamed, INVALID_GROUP if none - GroupID group_over; ///< Group over which a vehicle is dragged, INVALID_GROUP if none - GUIGroupList groups; ///< List of groups - uint tiny_step_height; ///< Step height for the group list - Scrollbar *group_sb; - - Dimension column_size[VGC_END]; ///< Size of the columns in the group list. - - /** - * (Re)Build the group list. - * - * @param owner The owner of the window - */ - void BuildGroupList(Owner owner) - { - if (!this->groups.NeedRebuild()) return; - - this->groups.Clear(); - - const Group *g; - FOR_ALL_GROUPS(g) { - if (g->owner == owner && g->vehicle_type == this->vli.vtype) { - *this->groups.Append() = g; - } - } - - this->groups.Compact(); - this->groups.RebuildDone(); - } - - /** Sort the groups by their name */ - static int CDECL GroupNameSorter(const Group * const *a, const Group * const *b) - { - static const Group *last_group[2] = { NULL, NULL }; - static char last_name[2][64] = { "", "" }; - - if (*a != last_group[0]) { - last_group[0] = *a; - SetDParam(0, (*a)->index); - GetString(last_name[0], STR_GROUP_NAME, lastof(last_name[0])); - } - - if (*b != last_group[1]) { - last_group[1] = *b; - SetDParam(0, (*b)->index); - GetString(last_name[1], STR_GROUP_NAME, lastof(last_name[1])); - } - - int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). - if (r == 0) return (*a)->index - (*b)->index; - return r; - } - - /** - * Compute tiny_step_height and column_size - * @return Total width required for the group list. - */ - uint ComputeGroupInfoSize() - { - this->column_size[VGC_NAME] = maxdim(GetStringBoundingBox(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype), GetStringBoundingBox(STR_GROUP_ALL_TRAINS + this->vli.vtype)); -/* We consider the max average length of characters to be the one of "a" */ - this->column_size[VGC_NAME].width = max(GetCharacterWidth(FS_NORMAL, 97) * (MAX_LENGTH_GROUP_NAME_CHARS - 4), this->column_size[VGC_NAME].width); - this->tiny_step_height = this->column_size[VGC_NAME].height; - - this->column_size[VGC_PROTECT] = GetSpriteSize(SPR_GROUP_REPLACE_PROTECT); - this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_PROTECT].height); - - this->column_size[VGC_AUTOREPLACE] = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE); - this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_AUTOREPLACE].height); - - this->column_size[VGC_PROFIT].width = 0; - this->column_size[VGC_PROFIT].height = 0; - static const SpriteID profit_sprites[] = {SPR_PROFIT_NA, SPR_PROFIT_NEGATIVE, SPR_PROFIT_SOME, SPR_PROFIT_LOT}; - for (uint i = 0; i < lengthof(profit_sprites); i++) { - Dimension d = GetSpriteSize(profit_sprites[i]); - this->column_size[VGC_PROFIT] = maxdim(this->column_size[VGC_PROFIT], d); - } - this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_PROFIT].height); - - SetDParamMaxValue(0, GroupStatistics::Get(this->vli.company, ALL_GROUP, this->vli.vtype).num_vehicle, 3, FS_SMALL); - this->column_size[VGC_NUMBER] = GetStringBoundingBox(STR_TINY_COMMA); - this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_NUMBER].height); - - this->tiny_step_height += WD_MATRIX_TOP; - - return WD_FRAMERECT_LEFT + 8 + - this->column_size[VGC_NAME].width + 2 + - this->column_size[VGC_PROTECT].width + 2 + - this->column_size[VGC_AUTOREPLACE].width + 2 + - this->column_size[VGC_PROFIT].width + 2 + - this->column_size[VGC_NUMBER].width + 2 + - WD_FRAMERECT_RIGHT; - } - - /** - * Draw a row in the group list. - * @param y Top of the row. - * @param left Left of the row. - * @param right Right of the row. - * @param g_id Group to list. - * @param protection Whether autoreplace protection is set. - */ - void DrawGroupInfo(int y, int left, int right, GroupID g_id, bool protection = false) const - { - /* Highlight the group if a vehicle is dragged over it */ - if (g_id == this->group_over) { - GfxFillRect(left + WD_FRAMERECT_LEFT, y + WD_FRAMERECT_TOP + WD_MATRIX_TOP, right - WD_FRAMERECT_RIGHT, y + this->tiny_step_height - WD_FRAMERECT_BOTTOM - WD_MATRIX_TOP, _colour_gradient[COLOUR_GREY][7]); - } - - if (g_id == NEW_GROUP) return; - - /* draw the selected group in white, else we draw it in black */ - TextColour colour = g_id == this->vli.index ? TC_WHITE : TC_BLACK; - const GroupStatistics &stats = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype); - bool rtl = _current_text_dir == TD_RTL; - - /* draw group name */ - int longer_name = 0; - StringID str; - if (IsAllGroupID(g_id)) { - str = STR_GROUP_ALL_TRAINS + this->vli.vtype; - } else if (IsDefaultGroupID(g_id)) { - str = STR_GROUP_DEFAULT_TRAINS + this->vli.vtype; - } else { - SetDParam(0, g_id); - str = STR_GROUP_NAME; - if (!protection) { - longer_name += this->column_size[VGC_PROTECT].width + 2; - if (!stats.autoreplace_defined) longer_name += this->column_size[VGC_AUTOREPLACE].width + 2; - } - } - int x = rtl ? right - WD_FRAMERECT_RIGHT - 8 - this->column_size[VGC_NAME].width - longer_name + 1 : left + WD_FRAMERECT_LEFT + 8; - DrawString(x, x + this->column_size[VGC_NAME].width + longer_name - 1, y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour); - - /* draw autoreplace protection */ - x = rtl ? x - 2 - this->column_size[VGC_PROTECT].width : x + 2 + this->column_size[VGC_NAME].width; - if (protection) DrawSprite(SPR_GROUP_REPLACE_PROTECT, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROTECT].height) / 2); - - /* draw autoreplace status */ - x = rtl ? x - 2 - this->column_size[VGC_AUTOREPLACE].width : x + 2 + this->column_size[VGC_PROTECT].width; - if (stats.autoreplace_defined) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, stats.autoreplace_finished ? PALETTE_CRASH : PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_AUTOREPLACE].height) / 2); - - /* draw the profit icon */ - x = rtl ? x - 2 - this->column_size[VGC_PROFIT].width : x + 2 + this->column_size[VGC_AUTOREPLACE].width; - SpriteID spr; - if (stats.num_profit_vehicle == 0) { - spr = SPR_PROFIT_NA; - } else if (stats.profit_last_year < 0) { - spr = SPR_PROFIT_NEGATIVE; - } else if (stats.profit_last_year < 10000 * stats.num_profit_vehicle) { // TODO magic number - spr = SPR_PROFIT_SOME; - } else { - spr = SPR_PROFIT_LOT; - } - DrawSprite(spr, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROFIT].height) / 2); - - /* draw the number of vehicles of the group */ - x = rtl ? x - 2 - this->column_size[VGC_NUMBER].width : x + 2 + this->column_size[VGC_PROFIT].width; - SetDParam(0, stats.num_vehicle); - DrawString(x, x + this->column_size[VGC_NUMBER].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NUMBER].height) / 2, STR_TINY_COMMA, colour, SA_RIGHT | SA_FORCE); - } - - /** - * Mark the widget containing the currently highlighted group as dirty. - */ - void DirtyHighlightedGroupWidget() - { - if (this->group_over == INVALID_GROUP) return; - - if (IsAllGroupID(this->group_over)) { - this->SetWidgetDirty(WID_GL_ALL_VEHICLES); - } else if (IsDefaultGroupID(this->group_over)) { - this->SetWidgetDirty(WID_GL_DEFAULT_VEHICLES); - } else { - this->SetWidgetDirty(WID_GL_LIST_GROUP); - } - } - -public: - VehicleGroupWindow(WindowDesc *desc, WindowNumber window_number) : BaseVehicleListWindow(desc, window_number) - { - this->CreateNestedTree(); - - this->vscroll = this->GetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR); - this->group_sb = this->GetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR); - - switch (this->vli.vtype) { - default: NOT_REACHED(); - case VEH_TRAIN: this->sorting = &_sorting.train; break; - case VEH_ROAD: this->sorting = &_sorting.roadveh; break; - case VEH_SHIP: this->sorting = &_sorting.ship; break; - case VEH_AIRCRAFT: this->sorting = &_sorting.aircraft; break; - } - - this->vli.index = ALL_GROUP; - this->vehicle_sel = INVALID_VEHICLE; - this->group_rename = INVALID_GROUP; - this->group_over = INVALID_GROUP; - - this->vehicles.SetListing(*this->sorting); - this->vehicles.ForceRebuild(); - this->vehicles.NeedResort(); - - this->BuildVehicleList(); - this->SortVehicleList(); - - this->groups.ForceRebuild(); - this->groups.NeedResort(); - this->BuildGroupList(vli.company); - this->groups.Sort(&GroupNameSorter); - - this->GetWidget(WID_GL_CAPTION)->widget_data = STR_VEHICLE_LIST_TRAIN_CAPTION + this->vli.vtype; - this->GetWidget(WID_GL_LIST_VEHICLE)->tool_tip = STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vli.vtype; - - this->GetWidget(WID_GL_CREATE_GROUP)->widget_data += this->vli.vtype; - this->GetWidget(WID_GL_RENAME_GROUP)->widget_data += this->vli.vtype; - this->GetWidget(WID_GL_DELETE_GROUP)->widget_data += this->vli.vtype; - this->GetWidget(WID_GL_REPLACE_PROTECTION)->widget_data += this->vli.vtype; - - this->FinishInitNested(window_number); - this->owner = vli.company; - } - - ~VehicleGroupWindow() - { - *this->sorting = this->vehicles.GetListing(); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_GL_LIST_GROUP: { - size->width = this->ComputeGroupInfoSize(); - resize->height = this->tiny_step_height; - - /* Minimum height is the height of the list widget minus all and default vehicles... */ - size->height = 4 * GetVehicleListHeight(this->vli.vtype, this->tiny_step_height) - 2 * this->tiny_step_height; - - /* ... minus the buttons at the bottom ... */ - uint max_icon_height = GetSpriteSize(this->GetWidget(WID_GL_CREATE_GROUP)->widget_data).height; - max_icon_height = max(max_icon_height, GetSpriteSize(this->GetWidget(WID_GL_RENAME_GROUP)->widget_data).height); - max_icon_height = max(max_icon_height, GetSpriteSize(this->GetWidget(WID_GL_DELETE_GROUP)->widget_data).height); - max_icon_height = max(max_icon_height, GetSpriteSize(this->GetWidget(WID_GL_REPLACE_PROTECTION)->widget_data).height); - - /* Get a multiple of tiny_step_height of that amount */ - size->height = Ceil(size->height - max_icon_height, tiny_step_height); - break; - } - - case WID_GL_ALL_VEHICLES: - case WID_GL_DEFAULT_VEHICLES: - size->width = this->ComputeGroupInfoSize(); - size->height = this->tiny_step_height; - break; - - case WID_GL_SORT_BY_ORDER: { - Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); - d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - - case WID_GL_LIST_VEHICLE: - this->ComputeGroupInfoSize(); - resize->height = GetVehicleListHeight(this->vli.vtype, this->tiny_step_height); - size->height = 4 * resize->height; - break; - - case WID_GL_MANAGE_VEHICLES_DROPDOWN: { - Dimension d = this->GetActionDropdownSize(true, true); - d.height += padding.height; - d.width += padding.width; - *size = maxdim(*size, d); - break; - } - } - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (data == 0) { - /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ - this->vehicles.ForceRebuild(); - this->groups.ForceRebuild(); - } else { - this->vehicles.ForceResort(); - this->groups.ForceResort(); - } - - /* Process ID-invalidation in command-scope as well */ - if (this->group_rename != INVALID_GROUP && !Group::IsValidID(this->group_rename)) { - DeleteWindowByClass(WC_QUERY_STRING); - this->group_rename = INVALID_GROUP; - } - - if (!(IsAllGroupID(this->vli.index) || IsDefaultGroupID(this->vli.index) || Group::IsValidID(this->vli.index))) { - this->vli.index = ALL_GROUP; - HideDropDownMenu(this); - } - this->SetDirty(); - } - - virtual void SetStringParameters(int widget) const - { - switch (widget) { - case WID_GL_AVAILABLE_VEHICLES: - SetDParam(0, STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vli.vtype); - break; - - case WID_GL_CAPTION: - /* If selected_group == DEFAULT_GROUP || ALL_GROUP, draw the standard caption - * We list all vehicles or ungrouped vehicles */ - if (IsDefaultGroupID(this->vli.index) || IsAllGroupID(this->vli.index)) { - SetDParam(0, STR_COMPANY_NAME); - SetDParam(1, this->vli.company); - SetDParam(2, this->vehicles.Length()); - SetDParam(3, this->vehicles.Length()); - } else { - const Group *g = Group::Get(this->vli.index); - - SetDParam(0, STR_GROUP_NAME); - SetDParam(1, g->index); - SetDParam(2, g->statistics.num_vehicle); - SetDParam(3, g->statistics.num_vehicle); - } - break; - } - } - - virtual void OnPaint() - { - /* If we select the all vehicles, this->list will contain all vehicles of the owner - * else this->list will contain all vehicles which belong to the selected group */ - this->BuildVehicleList(); - this->SortVehicleList(); - - this->BuildGroupList(this->owner); - this->groups.Sort(&GroupNameSorter); - - this->group_sb->SetCount(this->groups.Length()); - this->vscroll->SetCount(this->vehicles.Length()); - - /* The drop down menu is out, *but* it may not be used, retract it. */ - if (this->vehicles.Length() == 0 && this->IsWidgetLowered(WID_GL_MANAGE_VEHICLES_DROPDOWN)) { - this->RaiseWidget(WID_GL_MANAGE_VEHICLES_DROPDOWN); - HideDropDownMenu(this); - } - - /* Disable all lists management button when the list is empty */ - this->SetWidgetsDisabledState(this->vehicles.Length() == 0 || _local_company != this->vli.company, - WID_GL_STOP_ALL, - WID_GL_START_ALL, - WID_GL_MANAGE_VEHICLES_DROPDOWN, - WIDGET_LIST_END); - - /* Disable the group specific function when we select the default group or all vehicles */ - this->SetWidgetsDisabledState(IsDefaultGroupID(this->vli.index) || IsAllGroupID(this->vli.index) || _local_company != this->vli.company, - WID_GL_DELETE_GROUP, - WID_GL_RENAME_GROUP, - WID_GL_REPLACE_PROTECTION, - WIDGET_LIST_END); - - /* Disable remaining buttons for non-local companies - * Needed while changing _local_company, eg. by cheats - * All procedures (eg. move vehicle to another group) - * verify, whether you are the owner of the vehicle, - * so it doesn't have to be disabled - */ - this->SetWidgetsDisabledState(_local_company != this->vli.company, - WID_GL_CREATE_GROUP, - WID_GL_AVAILABLE_VEHICLES, - WIDGET_LIST_END); - - /* If not a default group and the group has replace protection, show an enabled replace sprite. */ - uint16 protect_sprite = SPR_GROUP_REPLACE_OFF_TRAIN; - if (!IsDefaultGroupID(this->vli.index) && !IsAllGroupID(this->vli.index) && Group::Get(this->vli.index)->replace_protection) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN; - this->GetWidget(WID_GL_REPLACE_PROTECTION)->widget_data = protect_sprite + this->vli.vtype; - - /* Set text of sort by dropdown */ - this->GetWidget(WID_GL_SORT_BY_DROPDOWN)->widget_data = this->vehicle_sorter_names[this->vehicles.SortType()]; - - this->DrawWidgets(); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_GL_ALL_VEHICLES: - DrawGroupInfo(r.top, r.left, r.right, ALL_GROUP); - break; - - case WID_GL_DEFAULT_VEHICLES: - DrawGroupInfo(r.top, r.left, r.right, DEFAULT_GROUP); - break; - - case WID_GL_LIST_GROUP: { - int y1 = r.top; - int max = min(this->group_sb->GetPosition() + this->group_sb->GetCapacity(), this->groups.Length()); - for (int i = this->group_sb->GetPosition(); i < max; ++i) { - const Group *g = this->groups[i]; - - assert(g->owner == this->owner); - - DrawGroupInfo(y1, r.left, r.right, g->index, g->replace_protection); - - y1 += this->tiny_step_height; - } - if ((uint)this->group_sb->GetPosition() + this->group_sb->GetCapacity() > this->groups.Length()) { - DrawGroupInfo(y1, r.left, r.right, NEW_GROUP); - } - break; - } - - case WID_GL_SORT_BY_ORDER: - this->DrawSortButtonState(WID_GL_SORT_BY_ORDER, this->vehicles.IsDescSortOrder() ? SBS_DOWN : SBS_UP); - break; - - case WID_GL_LIST_VEHICLE: - this->DrawVehicleListItems(this->vehicle_sel, this->resize.step_height, r); - break; - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_GL_SORT_BY_ORDER: // Flip sorting method ascending/descending - this->vehicles.ToggleSortOrder(); - this->SetDirty(); - break; - - case WID_GL_SORT_BY_DROPDOWN: // Select sorting criteria dropdown menu - ShowDropDownMenu(this, this->vehicle_sorter_names, this->vehicles.SortType(), WID_GL_SORT_BY_DROPDOWN, 0, (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10)); - return; - - case WID_GL_ALL_VEHICLES: // All vehicles button - if (!IsAllGroupID(this->vli.index)) { - this->vli.index = ALL_GROUP; - this->vehicles.ForceRebuild(); - this->SetDirty(); - } - break; - - case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles button - if (!IsDefaultGroupID(this->vli.index)) { - this->vli.index = DEFAULT_GROUP; - this->vehicles.ForceRebuild(); - this->SetDirty(); - } - break; - - case WID_GL_LIST_GROUP: { // Matrix Group - uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); - if (id_g >= this->groups.Length()) return; - - this->vli.index = this->groups[id_g]->index; - - this->vehicles.ForceRebuild(); - this->SetDirty(); - break; - } - - case WID_GL_LIST_VEHICLE: { // Matrix Vehicle - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE); - if (id_v >= this->vehicles.Length()) return; // click out of list bound - - const Vehicle *v = this->vehicles[id_v]; - if (VehicleClicked(v)) break; - - this->vehicle_sel = v->index; - - int image = v->GetImage(_current_text_dir == TD_RTL ? DIR_E : DIR_W, EIT_IN_LIST); - SetObjectToPlaceWnd(image, GetVehiclePalette(v), HT_DRAG, this); - _cursor.vehchain = true; - - this->SetDirty(); - break; - } - - case WID_GL_CREATE_GROUP: { // Create a new group - DoCommandP(0, this->vli.vtype, 0, CMD_CREATE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_CREATE), CcCreateGroup); - break; - } - - case WID_GL_DELETE_GROUP: { // Delete the selected group - GroupID group = this->vli.index; - this->vli.index = ALL_GROUP; - - DoCommandP(0, group, 0, CMD_DELETE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_DELETE)); - break; - } - - case WID_GL_RENAME_GROUP: // Rename the selected roup - this->ShowRenameGroupWindow(this->vli.index, false); - break; - - case WID_GL_AVAILABLE_VEHICLES: - ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype); - break; - - case WID_GL_MANAGE_VEHICLES_DROPDOWN: { - DropDownList *list = this->BuildActionDropdownList(true, Group::IsValidID(this->vli.index)); - ShowDropDownList(this, list, 0, WID_GL_MANAGE_VEHICLES_DROPDOWN); - break; - } - - case WID_GL_START_ALL: - case WID_GL_STOP_ALL: { // Start/stop all vehicles of the list - DoCommandP(0, (1 << 1) | (widget == WID_GL_START_ALL ? (1 << 0) : 0), this->vli.Pack(), CMD_MASS_START_STOP); - break; - } - - case WID_GL_REPLACE_PROTECTION: { - const Group *g = Group::GetIfValid(this->vli.index); - if (g != NULL) { - DoCommandP(0, this->vli.index, !g->replace_protection, CMD_SET_GROUP_REPLACE_PROTECTION); - } - break; - } - } - } - - virtual void OnDragDrop(Point pt, int widget) - { - switch (widget) { - case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles - DoCommandP(0, DEFAULT_GROUP, this->vehicle_sel | (_ctrl_pressed ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE)); - - this->vehicle_sel = INVALID_VEHICLE; - this->group_over = INVALID_GROUP; - - this->SetDirty(); - break; - - case WID_GL_LIST_GROUP: { // Matrix group - const VehicleID vindex = this->vehicle_sel; - this->vehicle_sel = INVALID_VEHICLE; - this->group_over = INVALID_GROUP; - this->SetDirty(); - - uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); - GroupID new_g = id_g >= this->groups.Length() ? NEW_GROUP : this->groups[id_g]->index; - - DoCommandP(0, new_g, vindex | (_ctrl_pressed ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE), new_g == NEW_GROUP ? CcAddVehicleNewGroup : NULL); - break; - } - - case WID_GL_LIST_VEHICLE: { // Matrix vehicle - const VehicleID vindex = this->vehicle_sel; - this->vehicle_sel = INVALID_VEHICLE; - this->group_over = INVALID_GROUP; - this->SetDirty(); - - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE); - if (id_v >= this->vehicles.Length()) return; // click out of list bound - - const Vehicle *v = this->vehicles[id_v]; - if (!VehicleClicked(v) && vindex == v->index) { - ShowVehicleViewWindow(v); - } - break; - } - } - _cursor.vehchain = false; - } - - virtual void OnQueryTextFinished(char *str) - { - if (str != NULL) DoCommandP(0, this->group_rename, 0, CMD_RENAME_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_RENAME), NULL, str); - this->group_rename = INVALID_GROUP; - } - - virtual void OnResize() - { - this->group_sb->SetCapacityFromWidget(this, WID_GL_LIST_GROUP); - this->vscroll->SetCapacityFromWidget(this, WID_GL_LIST_VEHICLE); - } - - virtual void OnDropdownSelect(int widget, int index) - { - switch (widget) { - case WID_GL_SORT_BY_DROPDOWN: - this->vehicles.SetSortType(index); - break; - - case WID_GL_MANAGE_VEHICLES_DROPDOWN: - assert(this->vehicles.Length() != 0); - - switch (index) { - case ADI_REPLACE: // Replace window - ShowReplaceGroupVehicleWindow(this->vli.index, this->vli.vtype); - break; - case ADI_SERVICE: // Send for servicing - case ADI_DEPOT: { // Send to Depots - DoCommandP(0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : 0U), this->vli.Pack(), GetCmdSendToDepot(this->vli.vtype)); - break; - } - - case ADI_ADD_SHARED: // Add shared Vehicles - assert(Group::IsValidID(this->vli.index)); - - DoCommandP(0, this->vli.index, this->vli.vtype, CMD_ADD_SHARED_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE)); - break; - case ADI_REMOVE_ALL: // Remove all Vehicles from the selected group - assert(Group::IsValidID(this->vli.index)); - - DoCommandP(0, this->vli.index, 0, CMD_REMOVE_ALL_VEHICLES_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES)); - break; - default: NOT_REACHED(); - } - break; - - default: NOT_REACHED(); - } - - this->SetDirty(); - } - - virtual void OnTick() - { - if (_pause_mode != PM_UNPAUSED) return; - if (this->groups.NeedResort() || this->vehicles.NeedResort()) { - this->SetDirty(); - } - } - - virtual void OnPlaceObjectAbort() - { - /* abort drag & drop */ - this->vehicle_sel = INVALID_VEHICLE; - this->DirtyHighlightedGroupWidget(); - this->group_over = INVALID_GROUP; - this->SetWidgetDirty(WID_GL_LIST_VEHICLE); - } - - virtual void OnMouseDrag(Point pt, int widget) - { - if (this->vehicle_sel == INVALID_VEHICLE) return; - - /* A vehicle is dragged over... */ - GroupID new_group_over = INVALID_GROUP; - switch (widget) { - case WID_GL_DEFAULT_VEHICLES: // ... the 'default' group. - new_group_over = DEFAULT_GROUP; - break; - - case WID_GL_LIST_GROUP: { // ... the list of custom groups. - uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); - new_group_over = id_g >= this->groups.Length() ? NEW_GROUP : this->groups[id_g]->index; - break; - } - } - - /* Do not highlight when dragging over the current group */ - if (Vehicle::Get(vehicle_sel)->group_id == new_group_over) new_group_over = INVALID_GROUP; - - /* Mark widgets as dirty if the group changed. */ - if (new_group_over != this->group_over) { - this->DirtyHighlightedGroupWidget(); - this->group_over = new_group_over; - this->DirtyHighlightedGroupWidget(); - } - } - - void ShowRenameGroupWindow(GroupID group, bool empty) - { - assert(Group::IsValidID(group)); - this->group_rename = group; - /* Show empty query for new groups */ - StringID str = STR_EMPTY; - if (!empty) { - SetDParam(0, group); - str = STR_GROUP_NAME; - } - ShowQueryString(str, STR_GROUP_RENAME_CAPTION, MAX_LENGTH_GROUP_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); - } - - /** - * Tests whether a given vehicle is selected in the window, and unselects it if necessary. - * Called when the vehicle is deleted. - * @param vehicle Vehicle that is going to be deleted - */ - void UnselectVehicle(VehicleID vehicle) - { - if (this->vehicle_sel == vehicle) ResetObjectToPlace(); - } -}; - - -static WindowDesc _other_group_desc( - WDP_AUTO, "list_groups", 460, 246, - WC_INVALID, WC_NONE, - 0, - _nested_group_widgets, lengthof(_nested_group_widgets) -); - -static WindowDesc _train_group_desc( - WDP_AUTO, "list_groups_train", 525, 246, - WC_TRAINS_LIST, WC_NONE, - 0, - _nested_group_widgets, lengthof(_nested_group_widgets) -); - -/** - * Show the group window for the given company and vehicle type. - * @param company The company to show the window for. - * @param vehicle_type The type of vehicle to show it for. - */ -void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type) -{ - if (!Company::IsValidID(company)) return; - - WindowNumber num = VehicleListIdentifier(VL_GROUP_LIST, vehicle_type, company).Pack(); - if (vehicle_type == VEH_TRAIN) { - AllocateWindowDescFront(&_train_group_desc, num); - } else { - _other_group_desc.cls = GetWindowClassForVehicleType(vehicle_type); - AllocateWindowDescFront(&_other_group_desc, num); - } -} - -/** - * Finds a group list window determined by vehicle type and owner - * @param vt vehicle type - * @param owner owner of groups - * @return pointer to VehicleGroupWindow, NULL if not found - */ -static inline VehicleGroupWindow *FindVehicleGroupWindow(VehicleType vt, Owner owner) -{ - return (VehicleGroupWindow *)FindWindowById(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, owner).Pack()); -} - -/** - * Opens a 'Rename group' window for newly created group - * @param success did command succeed? - * @param tile unused - * @param p1 vehicle type - * @param p2 unused - * @see CmdCreateGroup - */ -void CcCreateGroup(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Failed()) return; - assert(p1 <= VEH_AIRCRAFT); - - VehicleGroupWindow *w = FindVehicleGroupWindow((VehicleType)p1, _current_company); - if (w != NULL) w->ShowRenameGroupWindow(_new_group_id, true); -} - -/** - * Open rename window after adding a vehicle to a new group via drag and drop. - * @param success Did command succeed? - * @param tile Unused. - * @param p1 Unused. - * @param p2 Bit 0-19: Vehicle ID. - */ -void CcAddVehicleNewGroup(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Failed()) return; - assert(Vehicle::IsValidID(GB(p2, 0, 20))); - - CcCreateGroup(result, 0, Vehicle::Get(GB(p2, 0, 20))->type, 0); -} - -/** - * Removes the highlight of a vehicle in a group window - * @param *v Vehicle to remove all highlights from - */ -void DeleteGroupHighlightOfVehicle(const Vehicle *v) -{ - /* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any group windows either - * If that is the case, we can skip looping though the windows and save time - */ - if (_special_mouse_mode != WSM_DRAGDROP) return; - - VehicleGroupWindow *w = FindVehicleGroupWindow(v->type, v->owner); - if (w != NULL) w->UnselectVehicle(v->index); -} diff --git a/src/industry_gui.cpp.orig b/src/industry_gui.cpp.orig deleted file mode 100644 index ca39e8f1cb..0000000000 --- a/src/industry_gui.cpp.orig +++ /dev/null @@ -1,2715 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file industry_gui.cpp GUIs related to industries. */ - -#include "stdafx.h" -#include "error.h" -#include "gui.h" -#include "settings_gui.h" -#include "sound_func.h" -#include "window_func.h" -#include "textbuf_gui.h" -#include "command_func.h" -#include "viewport_func.h" -#include "industry.h" -#include "town.h" -#include "cheat_type.h" -#include "newgrf_industries.h" -#include "newgrf_text.h" -#include "newgrf_debug.h" -#include "strings_func.h" -#include "company_func.h" -#include "tilehighlight_func.h" -#include "string_func.h" -#include "sortlist_type.h" -#include "widgets/dropdown_func.h" -#include "company_base.h" -#include "core/geometry_func.hpp" -#include "core/random_func.hpp" -#include "core/backup_type.hpp" -#include "genworld.h" -#include "smallmap_gui.h" -#include "widgets/dropdown_type.h" -#include "widgets/industry_widget.h" - -#include "table/strings.h" - -bool _ignore_restrictions; -uint64 _displayed_industries; ///< Communication from the industry chain window to the smallmap window about what industries to display. - -assert_compile(NUM_INDUSTRYTYPES <= 64); // Make sure all industry types fit in _displayed_industries. - -/** Cargo suffix type (for which window is it requested) */ -enum CargoSuffixType { - CST_FUND, ///< Fund-industry window - CST_VIEW, ///< View-industry window - CST_DIR, ///< Industry-directory window -}; - -static void ShowIndustryCargoesWindow(IndustryType id); - -/** - * Gets the string to display after the cargo name (using callback 37) - * @param cargo the cargo for which the suffix is requested - * - 00 - first accepted cargo type - * - 01 - second accepted cargo type - * - 02 - third accepted cargo type - * - 03 - first produced cargo type - * - 04 - second produced cargo type - * @param cst the cargo suffix type (for which window is it requested). @see CargoSuffixType - * @param ind the industry (NULL if in fund window) - * @param ind_type the industry type - * @param indspec the industry spec - * @param suffix is filled with the string to display - * @param suffix_last lastof(suffix) - */ -static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, char *suffix, const char *suffix_last) -{ - suffix[0] = '\0'; - if (HasBit(indspec->callback_mask, CBM_IND_CARGO_SUFFIX)) { - uint16 callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, (cst << 8) | cargo, const_cast(ind), ind_type, (cst != CST_FUND) ? ind->location.tile : INVALID_TILE); - if (callback == CALLBACK_FAILED || callback == 0x400) return; - if (callback > 0x400) { - ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_CARGO_SUFFIX, callback); - } else if (indspec->grf_prop.grffile->grf_version >= 8 || GB(callback, 0, 8) != 0xFF) { - StartTextRefStackUsage(indspec->grf_prop.grffile, 6); - GetString(suffix, GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback), suffix_last); - StopTextRefStackUsage(); - } - } -} - -/** - * Gets all strings to display after the cargoes of industries (using callback 37) - * @param cb_offset The offset for the cargo used in cb37, 0 for accepted cargoes, 3 for produced cargoes - * @param cst the cargo suffix type (for which window is it requested). @see CargoSuffixType - * @param ind the industry (NULL if in fund window) - * @param ind_type the industry type - * @param indspec the industry spec - * @param cargoes array with cargotypes. for CT_INVALID no suffix will be determined - * @param suffixes is filled with the suffixes - */ -template -static inline void GetAllCargoSuffixes(uint cb_offset, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, const TC &cargoes, TS &suffixes) -{ - assert_compile(lengthof(cargoes) <= lengthof(suffixes)); - for (uint j = 0; j < lengthof(cargoes); j++) { - if (cargoes[j] != CT_INVALID) { - GetCargoSuffix(cb_offset + j, cst, ind, ind_type, indspec, suffixes[j], lastof(suffixes[j])); - } else { - suffixes[j][0] = '\0'; - } - } -} - -IndustryType _sorted_industry_types[NUM_INDUSTRYTYPES]; ///< Industry types sorted by name. - -/** Sort industry types by their name. */ -static int CDECL IndustryTypeNameSorter(const IndustryType *a, const IndustryType *b) -{ - static char industry_name[2][64]; - - const IndustrySpec *indsp1 = GetIndustrySpec(*a); - SetDParam(0, indsp1->name); - GetString(industry_name[0], STR_JUST_STRING, lastof(industry_name[0])); - - const IndustrySpec *indsp2 = GetIndustrySpec(*b); - SetDParam(0, indsp2->name); - GetString(industry_name[1], STR_JUST_STRING, lastof(industry_name[1])); - - int r = strnatcmp(industry_name[0], industry_name[1]); // Sort by name (natural sorting). - - /* If the names are equal, sort by industry type. */ - return (r != 0) ? r : (*a - *b); -} - -/** - * Initialize the list of sorted industry types. - */ -void SortIndustryTypes() -{ - /* Add each industry type to the list. */ - for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) { - _sorted_industry_types[i] = i; - } - - /* Sort industry types by name. */ - QSortT(_sorted_industry_types, NUM_INDUSTRYTYPES, &IndustryTypeNameSorter); -} - -/** - * Command callback. In case of failure to build an industry, show an error message. - * @param result Result of the command. - * @param tile Tile where the industry is placed. - * @param p1 Additional data of the #CMD_BUILD_INDUSTRY command. - * @param p2 Additional data of the #CMD_BUILD_INDUSTRY command. - */ -void CcBuildIndustry(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Succeeded()) return; - - uint8 indtype = GB(p1, 0, 8); - if (indtype < NUM_INDUSTRYTYPES) { - const IndustrySpec *indsp = GetIndustrySpec(indtype); - if (indsp->enabled) { - SetDParam(0, indsp->name); - ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HERE, result.GetErrorMessage(), WL_INFO, TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE); - } - } -} - -static const NWidgetPart _nested_build_industry_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_FUND_INDUSTRY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_DARK_GREEN, WID_DPI_MATRIX_WIDGET), SetMatrixDataTip(1, 0, STR_FUND_INDUSTRY_SELECTION_TOOLTIP), SetFill(1, 0), SetResize(1, 1), SetScrollbar(WID_DPI_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_DPI_SCROLLBAR), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_DPI_INFOPANEL), SetResize(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_DARK_GREEN, WID_DPI_DISPLAY_WIDGET), SetFill(1, 0), SetResize(1, 0), - SetDataTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_DARK_GREEN, WID_DPI_FUND_WIDGET), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_JUST_STRING, STR_NULL), - NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), - EndContainer(), -}; - -/** Window definition of the dynamic place industries gui */ -static WindowDesc _build_industry_desc( - WDP_AUTO, "build_industry", 170, 212, - WC_BUILD_INDUSTRY, WC_NONE, - WDF_CONSTRUCTION, - _nested_build_industry_widgets, lengthof(_nested_build_industry_widgets) -); - -/** Build (fund or prospect) a new industry, */ -class BuildIndustryWindow : public Window { - int selected_index; ///< index of the element in the matrix - IndustryType selected_type; ///< industry corresponding to the above index - uint16 callback_timer; ///< timer counter for callback eventual verification - bool timer_enabled; ///< timer can be used - uint16 count; ///< How many industries are loaded - IndustryType index[NUM_INDUSTRYTYPES + 1]; ///< Type of industry, in the order it was loaded - bool enabled[NUM_INDUSTRYTYPES + 1]; ///< availability state, coming from CBID_INDUSTRY_PROBABILITY (if ever) - Scrollbar *vscroll; - - /** The offset for the text in the matrix. */ - static const int MATRIX_TEXT_OFFSET = 17; - - void SetupArrays() - { - this->count = 0; - - for (uint i = 0; i < lengthof(this->index); i++) { - this->index[i] = INVALID_INDUSTRYTYPE; - this->enabled[i] = false; - } - - if (_game_mode == GM_EDITOR) { // give room for the Many Random "button" - this->index[this->count] = INVALID_INDUSTRYTYPE; - this->enabled[this->count] = true; - this->count++; - this->timer_enabled = false; - } - /* Fill the arrays with industries. - * The tests performed after the enabled allow to load the industries - * In the same way they are inserted by grf (if any) - */ - for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) { - IndustryType ind = _sorted_industry_types[i]; - const IndustrySpec *indsp = GetIndustrySpec(ind); - if (indsp->enabled) { - /* Rule is that editor mode loads all industries. - * In game mode, all non raw industries are loaded too - * and raw ones are loaded only when setting allows it */ - if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _settings_game.construction.raw_industry_construction == 0) { - /* Unselect if the industry is no longer in the list */ - if (this->selected_type == ind) this->selected_index = -1; - continue; - } - this->index[this->count] = ind; - this->enabled[this->count] = (_game_mode == GM_EDITOR) || GetIndustryProbabilityCallback(ind, IACT_USERCREATION, 1) > 0; - /* Keep the selection to the correct line */ - if (this->selected_type == ind) this->selected_index = this->count; - this->count++; - } - } - - /* first industry type is selected if the current selection is invalid. - * I'll be damned if there are none available ;) */ - if (this->selected_index == -1) { - this->selected_index = 0; - this->selected_type = this->index[0]; - } - - this->vscroll->SetCount(this->count); - } - - /** Update status of the fund and display-chain widgets. */ - void SetButtons() - { - this->SetWidgetDisabledState(WID_DPI_FUND_WIDGET, this->selected_type != INVALID_INDUSTRYTYPE && !this->enabled[this->selected_index]); - this->SetWidgetDisabledState(WID_DPI_DISPLAY_WIDGET, this->selected_type == INVALID_INDUSTRYTYPE && this->enabled[this->selected_index]); - } - -public: - BuildIndustryWindow() : Window(&_build_industry_desc) - { - this->timer_enabled = _loaded_newgrf_features.has_newindustries; - - this->selected_index = -1; - this->selected_type = INVALID_INDUSTRYTYPE; - - this->callback_timer = DAY_TICKS; - - this->CreateNestedTree(); - this->vscroll = this->GetScrollbar(WID_DPI_SCROLLBAR); - this->FinishInitNested(0); - - this->SetButtons(); - } - - virtual void OnInit() - { - this->SetupArrays(); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_DPI_MATRIX_WIDGET: { - Dimension d = GetStringBoundingBox(STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES); - for (byte i = 0; i < this->count; i++) { - if (this->index[i] == INVALID_INDUSTRYTYPE) continue; - d = maxdim(d, GetStringBoundingBox(GetIndustrySpec(this->index[i])->name)); - } - resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); - d.width += MATRIX_TEXT_OFFSET + padding.width; - d.height = 5 * resize->height; - *size = maxdim(*size, d); - break; - } - - case WID_DPI_INFOPANEL: { - /* Extra line for cost outside of editor + extra lines for 'extra' information for NewGRFs. */ - int height = 2 + (_game_mode == GM_EDITOR ? 0 : 1) + (_loaded_newgrf_features.has_newindustries ? 4 : 0); - Dimension d = {0, 0}; - for (byte i = 0; i < this->count; i++) { - if (this->index[i] == INVALID_INDUSTRYTYPE) continue; - - const IndustrySpec *indsp = GetIndustrySpec(this->index[i]); - - char cargo_suffix[3][512]; - GetAllCargoSuffixes(0, CST_FUND, NULL, this->index[i], indsp, indsp->accepts_cargo, cargo_suffix); - StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO; - byte p = 0; - SetDParam(0, STR_JUST_NOTHING); - SetDParamStr(1, ""); - for (byte j = 0; j < lengthof(indsp->accepts_cargo); j++) { - if (indsp->accepts_cargo[j] == CT_INVALID) continue; - if (p > 0) str++; - SetDParam(p++, CargoSpec::Get(indsp->accepts_cargo[j])->name); - SetDParamStr(p++, cargo_suffix[j]); - } - d = maxdim(d, GetStringBoundingBox(str)); - - /* Draw the produced cargoes, if any. Otherwise, will print "Nothing". */ - GetAllCargoSuffixes(3, CST_FUND, NULL, this->index[i], indsp, indsp->produced_cargo, cargo_suffix); - str = STR_INDUSTRY_VIEW_PRODUCES_CARGO; - p = 0; - SetDParam(0, STR_JUST_NOTHING); - SetDParamStr(1, ""); - for (byte j = 0; j < lengthof(indsp->produced_cargo); j++) { - if (indsp->produced_cargo[j] == CT_INVALID) continue; - if (p > 0) str++; - SetDParam(p++, CargoSpec::Get(indsp->produced_cargo[j])->name); - SetDParamStr(p++, cargo_suffix[j]); - } - d = maxdim(d, GetStringBoundingBox(str)); - } - - /* Set it to something more sane :) */ - size->height = height * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - size->width = d.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - break; - } - - case WID_DPI_FUND_WIDGET: { - Dimension d = GetStringBoundingBox(STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY); - d = maxdim(d, GetStringBoundingBox(STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY)); - d = maxdim(d, GetStringBoundingBox(STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY)); - d.width += padding.width; - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - } - } - - virtual void SetStringParameters(int widget) const - { - switch (widget) { - case WID_DPI_FUND_WIDGET: - /* Raw industries might be prospected. Show this fact by changing the string - * In Editor, you just build, while ingame, or you fund or you prospect */ - if (_game_mode == GM_EDITOR) { - /* We've chosen many random industries but no industries have been specified */ - SetDParam(0, STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY); - } else { - const IndustrySpec *indsp = GetIndustrySpec(this->index[this->selected_index]); - SetDParam(0, (_settings_game.construction.raw_industry_construction == 2 && indsp->IsRawIndustry()) ? STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY : STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY); - } - break; - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_DPI_MATRIX_WIDGET: { - uint text_left, text_right, icon_left, icon_right; - if (_current_text_dir == TD_RTL) { - icon_right = r.right - WD_MATRIX_RIGHT; - icon_left = icon_right - 10; - text_right = icon_right - BuildIndustryWindow::MATRIX_TEXT_OFFSET; - text_left = r.left + WD_MATRIX_LEFT; - } else { - icon_left = r.left + WD_MATRIX_LEFT; - icon_right = icon_left + 10; - text_left = icon_left + BuildIndustryWindow::MATRIX_TEXT_OFFSET; - text_right = r.right - WD_MATRIX_RIGHT; - } - - for (byte i = 0; i < this->vscroll->GetCapacity() && i + this->vscroll->GetPosition() < this->count; i++) { - int y = r.top + WD_MATRIX_TOP + i * this->resize.step_height; - bool selected = this->selected_index == i + this->vscroll->GetPosition(); - - if (this->index[i + this->vscroll->GetPosition()] == INVALID_INDUSTRYTYPE) { - DrawString(text_left, text_right, y, STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES, selected ? TC_WHITE : TC_ORANGE); - continue; - } - const IndustrySpec *indsp = GetIndustrySpec(this->index[i + this->vscroll->GetPosition()]); - - /* Draw the name of the industry in white is selected, otherwise, in orange */ - DrawString(text_left, text_right, y, indsp->name, selected ? TC_WHITE : TC_ORANGE); - GfxFillRect(icon_left, y + 1, icon_right, y + 7, selected ? PC_WHITE : PC_BLACK); - GfxFillRect(icon_left + 1, y + 2, icon_right - 1, y + 6, indsp->map_colour); - } - break; - } - - case WID_DPI_INFOPANEL: { - int y = r.top + WD_FRAMERECT_TOP; - int bottom = r.bottom - WD_FRAMERECT_BOTTOM; - int left = r.left + WD_FRAMERECT_LEFT; - int right = r.right - WD_FRAMERECT_RIGHT; - - if (this->selected_type == INVALID_INDUSTRYTYPE) { - DrawStringMultiLine(left, right, y, bottom, STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP); - break; - } - - const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); - - if (_game_mode != GM_EDITOR) { - SetDParam(0, indsp->GetConstructionCost()); - DrawString(left, right, y, STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST); - y += FONT_HEIGHT_NORMAL; - } - - /* Draw the accepted cargoes, if any. Otherwise, will print "Nothing". */ - char cargo_suffix[3][512]; - GetAllCargoSuffixes(0, CST_FUND, NULL, this->selected_type, indsp, indsp->accepts_cargo, cargo_suffix); - StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO; - byte p = 0; - SetDParam(0, STR_JUST_NOTHING); - SetDParamStr(1, ""); - for (byte j = 0; j < lengthof(indsp->accepts_cargo); j++) { - if (indsp->accepts_cargo[j] == CT_INVALID) continue; - if (p > 0) str++; - SetDParam(p++, CargoSpec::Get(indsp->accepts_cargo[j])->name); - SetDParamStr(p++, cargo_suffix[j]); - } - DrawString(left, right, y, str); - y += FONT_HEIGHT_NORMAL; - - /* Draw the produced cargoes, if any. Otherwise, will print "Nothing". */ - GetAllCargoSuffixes(3, CST_FUND, NULL, this->selected_type, indsp, indsp->produced_cargo, cargo_suffix); - str = STR_INDUSTRY_VIEW_PRODUCES_CARGO; - p = 0; - SetDParam(0, STR_JUST_NOTHING); - SetDParamStr(1, ""); - for (byte j = 0; j < lengthof(indsp->produced_cargo); j++) { - if (indsp->produced_cargo[j] == CT_INVALID) continue; - if (p > 0) str++; - SetDParam(p++, CargoSpec::Get(indsp->produced_cargo[j])->name); - SetDParamStr(p++, cargo_suffix[j]); - } - DrawString(left, right, y, str); - y += FONT_HEIGHT_NORMAL; - - /* Get the additional purchase info text, if it has not already been queried. */ - str = STR_NULL; - if (HasBit(indsp->callback_mask, CBM_IND_FUND_MORE_TEXT)) { - uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, NULL, this->selected_type, INVALID_TILE); - if (callback_res != CALLBACK_FAILED && callback_res != 0x400) { - if (callback_res > 0x400) { - ErrorUnknownCallbackResult(indsp->grf_prop.grffile->grfid, CBID_INDUSTRY_FUND_MORE_TEXT, callback_res); - } else { - str = GetGRFStringID(indsp->grf_prop.grffile->grfid, 0xD000 + callback_res); // No. here's the new string - if (str != STR_UNDEFINED) { - StartTextRefStackUsage(indsp->grf_prop.grffile, 6); - DrawStringMultiLine(left, right, y, bottom, str, TC_YELLOW); - StopTextRefStackUsage(); - } - } - } - } - break; - } - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_DPI_MATRIX_WIDGET: { - int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_DPI_MATRIX_WIDGET); - if (y < this->count) { // Is it within the boundaries of available data? - this->selected_index = y; - this->selected_type = this->index[y]; - const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); - - this->SetDirty(); - - if (_thd.GetCallbackWnd() == this && - ((_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && indsp != NULL && indsp->IsRawIndustry()) || - this->selected_type == INVALID_INDUSTRYTYPE || - !this->enabled[this->selected_index])) { - /* Reset the button state if going to prospecting or "build many industries" */ - this->RaiseButtons(); - ResetObjectToPlace(); - } - - this->SetButtons(); - if (this->enabled[this->selected_index] && click_count > 1) this->OnClick(pt, WID_DPI_FUND_WIDGET, 1); - } - break; - } - - case WID_DPI_DISPLAY_WIDGET: - if (this->selected_type != INVALID_INDUSTRYTYPE) ShowIndustryCargoesWindow(this->selected_type); - break; - - case WID_DPI_FUND_WIDGET: { - if (this->selected_type == INVALID_INDUSTRYTYPE) { - this->HandleButtonClick(WID_DPI_FUND_WIDGET); - - if (Town::GetNumItems() == 0) { - ShowErrorMessage(STR_ERROR_CAN_T_GENERATE_INDUSTRIES, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO); - } else { - extern void GenerateIndustries(); - _generating_world = true; - GenerateIndustries(); - _generating_world = false; - } - } else if (_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && GetIndustrySpec(this->selected_type)->IsRawIndustry()) { - DoCommandP(0, this->selected_type, InteractiveRandom(), CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY)); - this->HandleButtonClick(WID_DPI_FUND_WIDGET); - } else { - HandlePlacePushButton(this, WID_DPI_FUND_WIDGET, SPR_CURSOR_INDUSTRY, HT_RECT); - } - break; - } - } - } - - virtual void OnResize() - { - /* Adjust the number of items in the matrix depending of the resize */ - this->vscroll->SetCapacityFromWidget(this, WID_DPI_MATRIX_WIDGET); - } - - virtual void OnPlaceObject(Point pt, TileIndex tile) - { - bool success = true; - /* We do not need to protect ourselves against "Random Many Industries" in this mode */ - const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); - uint32 seed = InteractiveRandom(); - - if (_game_mode == GM_EDITOR) { - /* Show error if no town exists at all */ - if (Town::GetNumItems() == 0) { - SetDParam(0, indsp->name); - ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HERE, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO, pt.x, pt.y); - return; - } - - Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); - _generating_world = true; - _ignore_restrictions = true; - - DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, - CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY), &CcBuildIndustry); - - cur_company.Restore(); - _ignore_restrictions = false; - _generating_world = false; - } else { - success = DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY)); - } - - /* If an industry has been built, just reset the cursor and the system */ - if (success && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - } - - virtual void OnTick() - { - if (_pause_mode != PM_UNPAUSED) return; - if (!this->timer_enabled) return; - if (--this->callback_timer == 0) { - /* We have just passed another day. - * See if we need to update availability of currently selected industry */ - this->callback_timer = DAY_TICKS; // restart counter - - const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); - - if (indsp->enabled) { - bool call_back_result = GetIndustryProbabilityCallback(this->selected_type, IACT_USERCREATION, 1) > 0; - - /* Only if result does match the previous state would it require a redraw. */ - if (call_back_result != this->enabled[this->selected_index]) { - this->enabled[this->selected_index] = call_back_result; - this->SetButtons(); - this->SetDirty(); - } - } - } - } - - virtual void OnTimeout() - { - this->RaiseButtons(); - } - - virtual void OnPlaceObjectAbort() - { - this->RaiseButtons(); - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - this->SetupArrays(); - - const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); - if (indsp == NULL) this->enabled[this->selected_index] = _settings_game.difficulty.industry_density != ID_FUND_ONLY; - this->SetButtons(); - } -}; - -void ShowBuildIndustryWindow() -{ - if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return; - if (BringWindowToFrontById(WC_BUILD_INDUSTRY, 0)) return; - new BuildIndustryWindow(); -} - -static void UpdateIndustryProduction(Industry *i); - -static inline bool IsProductionAlterable(const Industry *i) -{ - const IndustrySpec *is = GetIndustrySpec(i->type); - return ((_game_mode == GM_EDITOR || _cheats.setup_prod.value) && - (is->production_rate[0] != 0 || is->production_rate[1] != 0 || is->IsRawIndustry())); -} - -class IndustryViewWindow : public Window -{ - /** Modes for changing production */ - enum Editability { - EA_NONE, ///< Not alterable - EA_MULTIPLIER, ///< Allow changing the production multiplier - EA_RATE, ///< Allow changing the production rates - }; - - /** Specific lines in the info panel */ - enum InfoLine { - IL_NONE, ///< No line - IL_MULTIPLIER, ///< Production multiplier - IL_RATE1, ///< Production rate of cargo 1 - IL_RATE2, ///< Production rate of cargo 2 - }; - - Editability editable; ///< Mode for changing production - InfoLine editbox_line; ///< The line clicked to open the edit box - InfoLine clicked_line; ///< The line of the button that has been clicked - byte clicked_button; ///< The button that has been clicked (to raise) - int production_offset_y; ///< The offset of the production texts/buttons - int info_height; ///< Height needed for the #WID_IV_INFO panel - -public: - IndustryViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) - { - this->flags |= WF_DISABLE_VP_SCROLL; - this->editbox_line = IL_NONE; - this->clicked_line = IL_NONE; - this->clicked_button = 0; - this->info_height = WD_FRAMERECT_TOP + 2 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM + 1; // Info panel has at least two lines text. - - this->InitNested(window_number); - NWidgetViewport *nvp = this->GetWidget(WID_IV_VIEWPORT); - nvp->InitializeViewport(this, Industry::Get(window_number)->location.GetCenterTile(), ZOOM_LVL_INDUSTRY); - - this->InvalidateData(); - } - - virtual void OnPaint() - { - this->DrawWidgets(); - - if (this->IsShaded()) return; // Don't draw anything when the window is shaded. - - NWidgetBase *nwi = this->GetWidget(WID_IV_INFO); - uint expected = this->DrawInfo(nwi->pos_x, nwi->pos_x + nwi->current_x - 1, nwi->pos_y) - nwi->pos_y; - if (expected > nwi->current_y - 1) { - this->info_height = expected + 1; - this->ReInit(); - return; - } - } - - /** - * Draw the text in the #WID_IV_INFO panel. - * @param left Left edge of the panel. - * @param right Right edge of the panel. - * @param top Top edge of the panel. - * @return Expected position of the bottom edge of the panel. - */ - int DrawInfo(uint left, uint right, uint top) - { - Industry *i = Industry::Get(this->window_number); - const IndustrySpec *ind = GetIndustrySpec(i->type); - int y = top + WD_FRAMERECT_TOP; - bool first = true; - bool has_accept = false; - char cargo_suffix[3][512]; - - if (i->prod_level == PRODLEVEL_CLOSURE) { - DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE); - y += 2 * FONT_HEIGHT_NORMAL; - } - - if (HasBit(ind->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) { - GetAllCargoSuffixes(0, CST_VIEW, i, i->type, ind, i->accepts_cargo, cargo_suffix); - for (byte j = 0; j < lengthof(i->accepts_cargo); j++) { - if (i->accepts_cargo[j] == CT_INVALID) continue; - has_accept = true; - if (first) { - DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING); - y += FONT_HEIGHT_NORMAL; - first = false; - } - SetDParam(0, i->accepts_cargo[j]); - SetDParam(1, i->incoming_cargo_waiting[j]); - SetDParamStr(2, cargo_suffix[j]); - DrawString(left + WD_FRAMETEXT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO); - y += FONT_HEIGHT_NORMAL; - } - } else { - GetAllCargoSuffixes(0, CST_VIEW, i, i->type, ind, i->accepts_cargo, cargo_suffix); - StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO; - byte p = 0; - for (byte j = 0; j < lengthof(i->accepts_cargo); j++) { - if (i->accepts_cargo[j] == CT_INVALID) continue; - has_accept = true; - if (p > 0) str++; - SetDParam(p++, CargoSpec::Get(i->accepts_cargo[j])->name); - SetDParamStr(p++, cargo_suffix[j]); - } - if (has_accept) { - DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, str); - y += FONT_HEIGHT_NORMAL; - } - } - - GetAllCargoSuffixes(3, CST_VIEW, i, i->type, ind, i->produced_cargo, cargo_suffix); - first = true; - for (byte j = 0; j < lengthof(i->produced_cargo); j++) { - if (i->produced_cargo[j] == CT_INVALID) continue; - if (first) { - if (has_accept) y += WD_PAR_VSEP_WIDE; - DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE); - y += FONT_HEIGHT_NORMAL; - if (this->editable == EA_RATE) this->production_offset_y = y; - first = false; - } - - SetDParam(0, i->produced_cargo[j]); - SetDParam(1, i->last_month_production[j]); - SetDParamStr(2, cargo_suffix[j]); - SetDParam(3, ToPercent8(i->last_month_pct_transported[j])); - uint x = left + WD_FRAMETEXT_LEFT + (this->editable == EA_RATE ? SETTING_BUTTON_WIDTH + 10 : 0); - DrawString(x, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_TRANSPORTED); - /* Let's put out those buttons.. */ - if (this->editable == EA_RATE) { - DrawArrowButtons(left + WD_FRAMETEXT_LEFT, y, COLOUR_YELLOW, (this->clicked_line == IL_RATE1 + j) ? this->clicked_button : 0, - i->production_rate[j] > 0, i->production_rate[j] < 255); - } - y += FONT_HEIGHT_NORMAL; - } - - /* Display production multiplier if editable */ - if (this->editable == EA_MULTIPLIER) { - y += WD_PAR_VSEP_WIDE; - this->production_offset_y = y; - SetDParam(0, RoundDivSU(i->prod_level * 100, PRODLEVEL_DEFAULT)); - uint x = left + WD_FRAMETEXT_LEFT + SETTING_BUTTON_WIDTH + 10; - DrawString(x, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_PRODUCTION_LEVEL); - DrawArrowButtons(left + WD_FRAMETEXT_LEFT, y, COLOUR_YELLOW, (this->clicked_line == IL_MULTIPLIER) ? this->clicked_button : 0, - i->prod_level > PRODLEVEL_MINIMUM, i->prod_level < PRODLEVEL_MAXIMUM); - y += FONT_HEIGHT_NORMAL; - } - - /* Get the extra message for the GUI */ - if (HasBit(ind->callback_mask, CBM_IND_WINDOW_MORE_TEXT)) { - uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_WINDOW_MORE_TEXT, 0, 0, i, i->type, i->location.tile); - if (callback_res != CALLBACK_FAILED && callback_res != 0x400) { - if (callback_res > 0x400) { - ErrorUnknownCallbackResult(ind->grf_prop.grffile->grfid, CBID_INDUSTRY_WINDOW_MORE_TEXT, callback_res); - } else { - StringID message = GetGRFStringID(ind->grf_prop.grffile->grfid, 0xD000 + callback_res); - if (message != STR_NULL && message != STR_UNDEFINED) { - y += WD_PAR_VSEP_WIDE; - - StartTextRefStackUsage(ind->grf_prop.grffile, 6); - /* Use all the available space left from where we stand up to the - * end of the window. We ALSO enlarge the window if needed, so we - * can 'go' wild with the bottom of the window. */ - y = DrawStringMultiLine(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, UINT16_MAX, message, TC_BLACK); - StopTextRefStackUsage(); - } - } - } - } - return y + WD_FRAMERECT_BOTTOM; - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_IV_CAPTION) SetDParam(0, this->window_number); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - if (widget == WID_IV_INFO) size->height = this->info_height; - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_IV_INFO: { - Industry *i = Industry::Get(this->window_number); - InfoLine line = IL_NONE; - - switch (this->editable) { - case EA_NONE: break; - - case EA_MULTIPLIER: - if (IsInsideBS(pt.y, this->production_offset_y, FONT_HEIGHT_NORMAL)) line = IL_MULTIPLIER; - break; - - case EA_RATE: - if (pt.y >= this->production_offset_y) { - int row = (pt.y - this->production_offset_y) / FONT_HEIGHT_NORMAL; - for (uint j = 0; j < lengthof(i->produced_cargo); j++) { - if (i->produced_cargo[j] == CT_INVALID) continue; - row--; - if (row < 0) { - line = (InfoLine)(IL_RATE1 + j); - break; - } - } - } - break; - } - if (line == IL_NONE) return; - - NWidgetBase *nwi = this->GetWidget(widget); - int left = nwi->pos_x + WD_FRAMETEXT_LEFT; - int right = nwi->pos_x + nwi->current_x - 1 - WD_FRAMERECT_RIGHT; - if (IsInsideMM(pt.x, left, left + SETTING_BUTTON_WIDTH)) { - /* Clicked buttons, decrease or increase production */ - byte button = (pt.x < left + SETTING_BUTTON_WIDTH / 2) ? 1 : 2; - switch (this->editable) { - case EA_MULTIPLIER: - if (button == 1) { - if (i->prod_level <= PRODLEVEL_MINIMUM) return; - i->prod_level = max(i->prod_level / 2, PRODLEVEL_MINIMUM); - } else { - if (i->prod_level >= PRODLEVEL_MAXIMUM) return; - i->prod_level = minu(i->prod_level * 2, PRODLEVEL_MAXIMUM); - } - break; - - case EA_RATE: - if (button == 1) { - if (i->production_rate[line - IL_RATE1] <= 0) return; - i->production_rate[line - IL_RATE1] = max(i->production_rate[line - IL_RATE1] / 2, 0); - } else { - if (i->production_rate[line - IL_RATE1] >= 255) return; - /* a zero production industry is unlikely to give anything but zero, so push it a little bit */ - int new_prod = i->production_rate[line - IL_RATE1] == 0 ? 1 : i->production_rate[line - IL_RATE1] * 2; - i->production_rate[line - IL_RATE1] = minu(new_prod, 255); - } - break; - - default: NOT_REACHED(); - } - - UpdateIndustryProduction(i); - this->SetDirty(); - this->SetTimeout(); - this->clicked_line = line; - this->clicked_button = button; - } else if (IsInsideMM(pt.x, left + SETTING_BUTTON_WIDTH + 10, right)) { - /* clicked the text */ - this->editbox_line = line; - switch (this->editable) { - case EA_MULTIPLIER: - SetDParam(0, RoundDivSU(i->prod_level * 100, PRODLEVEL_DEFAULT)); - ShowQueryString(STR_JUST_INT, STR_CONFIG_GAME_PRODUCTION_LEVEL, 10, this, CS_ALPHANUMERAL, QSF_NONE); - break; - - case EA_RATE: - SetDParam(0, i->production_rate[line - IL_RATE1] * 8); - ShowQueryString(STR_JUST_INT, STR_CONFIG_GAME_PRODUCTION, 10, this, CS_ALPHANUMERAL, QSF_NONE); - break; - - default: NOT_REACHED(); - } - } - break; - } - - case WID_IV_GOTO: { - Industry *i = Industry::Get(this->window_number); - if (_ctrl_pressed) { - ShowExtraViewPortWindow(i->location.GetCenterTile()); - } else { - ScrollMainWindowToTile(i->location.GetCenterTile()); - } - break; - } - - case WID_IV_DISPLAY: { - Industry *i = Industry::Get(this->window_number); - ShowIndustryCargoesWindow(i->type); - break; - } - } - } - - virtual void OnTimeout() - { - this->clicked_line = IL_NONE; - this->clicked_button = 0; - this->SetDirty(); - } - - virtual void OnResize() - { - if (this->viewport != NULL) { - NWidgetViewport *nvp = this->GetWidget(WID_IV_VIEWPORT); - nvp->UpdateViewportCoordinates(this); - - ScrollWindowToTile(Industry::Get(this->window_number)->location.GetCenterTile(), this, true); // Re-center viewport. - } - } - - virtual void OnQueryTextFinished(char *str) - { - if (StrEmpty(str)) return; - - Industry *i = Industry::Get(this->window_number); - uint value = atoi(str); - switch (this->editbox_line) { - case IL_NONE: NOT_REACHED(); - - case IL_MULTIPLIER: - i->prod_level = ClampU(RoundDivSU(value * PRODLEVEL_DEFAULT, 100), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM); - break; - - default: - i->production_rate[this->editbox_line - IL_RATE1] = ClampU(RoundDivSU(value, 8), 0, 255); - break; - } - UpdateIndustryProduction(i); - this->SetDirty(); - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - const Industry *i = Industry::Get(this->window_number); - if (IsProductionAlterable(i)) { - const IndustrySpec *ind = GetIndustrySpec(i->type); - this->editable = ind->UsesSmoothEconomy() ? EA_RATE : EA_MULTIPLIER; - } else { - this->editable = EA_NONE; - } - } - - virtual bool IsNewGRFInspectable() const - { - return ::IsNewGRFInspectable(GSF_INDUSTRIES, this->window_number); - } - - virtual void ShowNewGRFInspectWindow() const - { - ::ShowNewGRFInspectWindow(GSF_INDUSTRIES, this->window_number); - } -}; - -static void UpdateIndustryProduction(Industry *i) -{ - const IndustrySpec *indspec = GetIndustrySpec(i->type); - if (!indspec->UsesSmoothEconomy()) i->RecomputeProductionMultipliers(); - - for (byte j = 0; j < lengthof(i->produced_cargo); j++) { - if (i->produced_cargo[j] != CT_INVALID) { - i->last_month_production[j] = 8 * i->production_rate[j]; - } - } -} - -/** Widget definition of the view industry gui */ -static const NWidgetPart _nested_industry_view_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_CREAM), - NWidget(WWT_CAPTION, COLOUR_CREAM, WID_IV_CAPTION), SetDataTip(STR_INDUSTRY_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_DEBUGBOX, COLOUR_CREAM), - NWidget(WWT_SHADEBOX, COLOUR_CREAM), - NWidget(WWT_DEFSIZEBOX, COLOUR_CREAM), - NWidget(WWT_STICKYBOX, COLOUR_CREAM), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_CREAM), - NWidget(WWT_INSET, COLOUR_CREAM), SetPadding(2, 2, 2, 2), - NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_IV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 0), SetPadding(1, 1, 1, 1), SetResize(1, 1), - EndContainer(), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_CREAM, WID_IV_INFO), SetMinimalSize(260, 2), SetResize(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_GOTO), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_INDUSTRY_VIEW_LOCATION_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_DISPLAY), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP), - NWidget(WWT_RESIZEBOX, COLOUR_CREAM), - EndContainer(), -}; - -/** Window definition of the view industry gui */ -static WindowDesc _industry_view_desc( - WDP_AUTO, "view_industry", 260, 120, - WC_INDUSTRY_VIEW, WC_NONE, - 0, - _nested_industry_view_widgets, lengthof(_nested_industry_view_widgets) -); - -void ShowIndustryViewWindow(int industry) -{ - AllocateWindowDescFront(&_industry_view_desc, industry); -} - -/** Widget definition of the industry directory gui */ -static const NWidgetPart _nested_industry_directory_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_BROWN), - NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_INDUSTRY_DIRECTORY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_BROWN), - NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), - NWidget(WWT_STICKYBOX, COLOUR_BROWN), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_VERTICAL), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), - NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_ID_INDUSTRY_LIST), SetDataTip(0x0, STR_INDUSTRY_DIRECTORY_LIST_CAPTION), SetResize(1, 1), SetScrollbar(WID_ID_SCROLLBAR), EndContainer(), - EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_ID_SCROLLBAR), - NWidget(WWT_RESIZEBOX, COLOUR_BROWN), - EndContainer(), - EndContainer(), -}; - -typedef GUIList GUIIndustryList; - - -/** - * The list of industries. - */ -class IndustryDirectoryWindow : public Window { -protected: - /* Runtime saved values */ - static Listing last_sorting; - static const Industry *last_industry; - - /* Constants for sorting stations */ - static const StringID sorter_names[]; - static GUIIndustryList::SortFunction * const sorter_funcs[]; - - GUIIndustryList industries; - Scrollbar *vscroll; - - /** (Re)Build industries list */ - void BuildSortIndustriesList() - { - if (this->industries.NeedRebuild()) { - this->industries.Clear(); - - const Industry *i; - FOR_ALL_INDUSTRIES(i) { - *this->industries.Append() = i; - } - - this->industries.Compact(); - this->industries.RebuildDone(); - this->vscroll->SetCount(this->industries.Length()); // Update scrollbar as well. - } - - if (!this->industries.Sort()) return; - IndustryDirectoryWindow::last_industry = NULL; // Reset name sorter sort cache - this->SetWidgetDirty(WID_ID_INDUSTRY_LIST); // Set the modified widget dirty - } - - /** - * Returns percents of cargo transported if industry produces this cargo, else -1 - * - * @param i industry to check - * @param id cargo slot - * @return percents of cargo transported, or -1 if industry doesn't use this cargo slot - */ - static inline int GetCargoTransportedPercentsIfValid(const Industry *i, uint id) - { - assert(id < lengthof(i->produced_cargo)); - - if (i->produced_cargo[id] == CT_INVALID) return 101; - return ToPercent8(i->last_month_pct_transported[id]); - } - - /** - * Returns value representing industry's transported cargo - * percentage for industry sorting - * - * @param i industry to check - * @return value used for sorting - */ - static int GetCargoTransportedSortValue(const Industry *i) - { - int p1 = GetCargoTransportedPercentsIfValid(i, 0); - int p2 = GetCargoTransportedPercentsIfValid(i, 1); - - if (p1 > p2) Swap(p1, p2); // lower value has higher priority - - return (p1 << 8) + p2; - } - - /** Sort industries by name */ - static int CDECL IndustryNameSorter(const Industry * const *a, const Industry * const *b) - { - static char buf_cache[96]; - static char buf[96]; - - SetDParam(0, (*a)->index); - GetString(buf, STR_INDUSTRY_NAME, lastof(buf)); - - if (*b != last_industry) { - last_industry = *b; - SetDParam(0, (*b)->index); - GetString(buf_cache, STR_INDUSTRY_NAME, lastof(buf_cache)); - } - - return strnatcmp(buf, buf_cache); // Sort by name (natural sorting). - } - - /** Sort industries by type and name */ - static int CDECL IndustryTypeSorter(const Industry * const *a, const Industry * const *b) - { - int it_a = 0; - while (it_a != NUM_INDUSTRYTYPES && (*a)->type != _sorted_industry_types[it_a]) it_a++; - int it_b = 0; - while (it_b != NUM_INDUSTRYTYPES && (*b)->type != _sorted_industry_types[it_b]) it_b++; - int r = it_a - it_b; - return (r == 0) ? IndustryNameSorter(a, b) : r; - } - - /** Sort industries by production and name */ - static int CDECL IndustryProductionSorter(const Industry * const *a, const Industry * const *b) - { - uint prod_a = 0, prod_b = 0; - for (uint i = 0; i < lengthof((*a)->produced_cargo); i++) { - if ((*a)->produced_cargo[i] != CT_INVALID) prod_a += (*a)->last_month_production[i]; - if ((*b)->produced_cargo[i] != CT_INVALID) prod_b += (*b)->last_month_production[i]; - } - int r = prod_a - prod_b; - - return (r == 0) ? IndustryTypeSorter(a, b) : r; - } - - /** Sort industries by transported cargo and name */ - static int CDECL IndustryTransportedCargoSorter(const Industry * const *a, const Industry * const *b) - { - int r = GetCargoTransportedSortValue(*a) - GetCargoTransportedSortValue(*b); - return (r == 0) ? IndustryNameSorter(a, b) : r; - } - - /** - * Get the StringID to draw and set the appropriate DParams. - * @param i the industry to get the StringID of. - * @return the StringID. - */ - StringID GetIndustryString(const Industry *i) const - { - const IndustrySpec *indsp = GetIndustrySpec(i->type); - byte p = 0; - - /* Industry name */ - SetDParam(p++, i->index); - - static char cargo_suffix[lengthof(i->produced_cargo)][512]; - GetAllCargoSuffixes(3, CST_DIR, i, i->type, indsp, i->produced_cargo, cargo_suffix); - - /* Industry productions */ - for (byte j = 0; j < lengthof(i->produced_cargo); j++) { - if (i->produced_cargo[j] == CT_INVALID) continue; - SetDParam(p++, i->produced_cargo[j]); - SetDParam(p++, i->last_month_production[j]); - SetDParamStr(p++, cargo_suffix[j]); - } - - /* Transported productions */ - for (byte j = 0; j < lengthof(i->produced_cargo); j++) { - if (i->produced_cargo[j] == CT_INVALID) continue; - SetDParam(p++, ToPercent8(i->last_month_pct_transported[j])); - } - - /* Drawing the right string */ - switch (p) { - case 1: return STR_INDUSTRY_DIRECTORY_ITEM_NOPROD; - case 5: return STR_INDUSTRY_DIRECTORY_ITEM; - default: return STR_INDUSTRY_DIRECTORY_ITEM_TWO; - } - } - -public: - IndustryDirectoryWindow(WindowDesc *desc, WindowNumber number) : Window(desc) - { - this->CreateNestedTree(); - this->vscroll = this->GetScrollbar(WID_ID_SCROLLBAR); - - this->industries.SetListing(this->last_sorting); - this->industries.SetSortFuncs(IndustryDirectoryWindow::sorter_funcs); - this->industries.ForceRebuild(); - this->BuildSortIndustriesList(); - - this->FinishInitNested(0); - } - - ~IndustryDirectoryWindow() - { - this->last_sorting = this->industries.GetListing(); - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_ID_DROPDOWN_CRITERIA) SetDParam(0, IndustryDirectoryWindow::sorter_names[this->industries.SortType()]); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_ID_DROPDOWN_ORDER: - this->DrawSortButtonState(widget, this->industries.IsDescSortOrder() ? SBS_DOWN : SBS_UP); - break; - - case WID_ID_INDUSTRY_LIST: { - int n = 0; - int y = Center(r.top, this->resize.step_height); - if (this->industries.Length() == 0) { - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_DIRECTORY_NONE); - break; - } - for (uint i = this->vscroll->GetPosition(); i < this->industries.Length(); i++) { - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, this->GetIndustryString(this->industries[i])); - - y += this->resize.step_height; - if (++n == this->vscroll->GetCapacity()) break; // max number of industries in 1 window - } - break; - } - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_ID_DROPDOWN_ORDER: { - Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); - d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - - case WID_ID_DROPDOWN_CRITERIA: { - Dimension d = {0, 0}; - for (uint i = 0; IndustryDirectoryWindow::sorter_names[i] != INVALID_STRING_ID; i++) { - d = maxdim(d, GetStringBoundingBox(IndustryDirectoryWindow::sorter_names[i])); - } - d.width += padding.width; - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - - case WID_ID_INDUSTRY_LIST: { - Dimension d = GetStringBoundingBox(STR_INDUSTRY_DIRECTORY_NONE); - for (uint i = 0; i < this->industries.Length(); i++) { - d = maxdim(d, GetStringBoundingBox(this->GetIndustryString(this->industries[i]))); - } - resize->height = d.height = GetMinSizing(NWST_STEP, d.height); - d.height *= 5; - d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - *size = maxdim(*size, d); - break; - } - } - } - - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_ID_DROPDOWN_ORDER: - this->industries.ToggleSortOrder(); - this->SetDirty(); - break; - - case WID_ID_DROPDOWN_CRITERIA: - ShowDropDownMenu(this, IndustryDirectoryWindow::sorter_names, this->industries.SortType(), WID_ID_DROPDOWN_CRITERIA, 0, 0); - break; - - case WID_ID_INDUSTRY_LIST: { - uint p = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_ID_INDUSTRY_LIST, WD_FRAMERECT_TOP); - if (p < this->industries.Length()) { - if (_ctrl_pressed) { - ShowExtraViewPortWindow(this->industries[p]->location.tile); - } else { - ScrollMainWindowToTile(this->industries[p]->location.tile); - } - } - break; - } - } - } - - virtual void OnDropdownSelect(int widget, int index) - { - if (this->industries.SortType() != index) { - this->industries.SetSortType(index); - this->BuildSortIndustriesList(); - } - } - - virtual void OnResize() - { - this->vscroll->SetCapacityFromWidget(this, WID_ID_INDUSTRY_LIST); - } - - virtual void OnPaint() - { - if (this->industries.NeedRebuild()) this->BuildSortIndustriesList(); - this->DrawWidgets(); - } - - virtual void OnHundredthTick() - { - this->industries.ForceResort(); - this->BuildSortIndustriesList(); - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (data == 0) { - /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ - this->industries.ForceRebuild(); - } else { - this->industries.ForceResort(); - } - } -}; - -Listing IndustryDirectoryWindow::last_sorting = {false, 0}; -const Industry *IndustryDirectoryWindow::last_industry = NULL; - -/* Available station sorting functions. */ -GUIIndustryList::SortFunction * const IndustryDirectoryWindow::sorter_funcs[] = { - &IndustryNameSorter, - &IndustryTypeSorter, - &IndustryProductionSorter, - &IndustryTransportedCargoSorter -}; - -/* Names of the sorting functions */ -const StringID IndustryDirectoryWindow::sorter_names[] = { - STR_SORT_BY_NAME, - STR_SORT_BY_TYPE, - STR_SORT_BY_PRODUCTION, - STR_SORT_BY_TRANSPORTED, - INVALID_STRING_ID -}; - - -/** Window definition of the industry directory gui */ -static WindowDesc _industry_directory_desc( - WDP_AUTO, "list_industries", 428, 190, - WC_INDUSTRY_DIRECTORY, WC_NONE, - 0, - _nested_industry_directory_widgets, lengthof(_nested_industry_directory_widgets) -); - -void ShowIndustryDirectory() -{ - AllocateWindowDescFront(&_industry_directory_desc, 0); -} - -/** Widgets of the industry cargoes window. */ -static const NWidgetPart _nested_industry_cargoes_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_BROWN), - NWidget(WWT_CAPTION, COLOUR_BROWN, WID_IC_CAPTION), SetDataTip(STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_BROWN), - NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), - NWidget(WWT_STICKYBOX, COLOUR_BROWN), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_IC_PANEL), SetResize(1, 10), SetMinimalSize(200, 90), SetScrollbar(WID_IC_SCROLLBAR), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_IC_NOTIFY), - SetDataTip(STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP, STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP), - NWidget(WWT_PANEL, COLOUR_BROWN), SetFill(1, 0), SetResize(0, 0), EndContainer(), - NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_IC_IND_DROPDOWN), SetFill(0, 0), SetResize(0, 0), - SetDataTip(STR_INDUSTRY_CARGOES_SELECT_INDUSTRY, STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP), - NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_IC_CARGO_DROPDOWN), SetFill(0, 0), SetResize(0, 0), - SetDataTip(STR_INDUSTRY_CARGOES_SELECT_CARGO, STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP), - EndContainer(), - EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_IC_SCROLLBAR), - NWidget(WWT_RESIZEBOX, COLOUR_BROWN), - EndContainer(), - EndContainer(), -}; - -/** Window description for the industry cargoes window. */ -static WindowDesc _industry_cargoes_desc( - WDP_AUTO, "industry_cargoes", 300, 210, - WC_INDUSTRY_CARGOES, WC_NONE, - 0, - _nested_industry_cargoes_widgets, lengthof(_nested_industry_cargoes_widgets) -); - -/** Available types of field. */ -enum CargoesFieldType { - CFT_EMPTY, ///< Empty field. - CFT_SMALL_EMPTY, ///< Empty small field (for the header). - CFT_INDUSTRY, ///< Display industry. - CFT_CARGO, ///< Display cargo connections. - CFT_CARGO_LABEL, ///< Display cargo labels. - CFT_HEADER, ///< Header text. -}; - -static const uint MAX_CARGOES = 3; ///< Maximum number of cargoes carried in a #CFT_CARGO field in #CargoesField. - -/** Data about a single field in the #IndustryCargoesWindow panel. */ -struct CargoesField { - static const int VERT_INTER_INDUSTRY_SPACE; - static const int HOR_CARGO_BORDER_SPACE; - static const int CARGO_STUB_WIDTH; - static const int HOR_CARGO_WIDTH, HOR_CARGO_SPACE; - static const int CARGO_FIELD_WIDTH; - static const int VERT_CARGO_SPACE, VERT_CARGO_EDGE; - static const int BLOB_DISTANCE, BLOB_WIDTH, BLOB_HEIGHT; - - static const int INDUSTRY_LINE_COLOUR; - static const int CARGO_LINE_COLOUR; - - static int small_height, normal_height; - static int industry_width; - - CargoesFieldType type; ///< Type of field. - union { - struct { - IndustryType ind_type; ///< Industry type (#NUM_INDUSTRYTYPES means 'houses'). - CargoID other_produced[MAX_CARGOES]; ///< Cargoes produced but not used in this figure. - CargoID other_accepted[MAX_CARGOES]; ///< Cargoes accepted but not used in this figure. - } industry; ///< Industry data (for #CFT_INDUSTRY). - struct { - CargoID vertical_cargoes[MAX_CARGOES]; ///< Cargoes running from top to bottom (cargo ID or #INVALID_CARGO). - byte num_cargoes; ///< Number of cargoes. - CargoID supp_cargoes[MAX_CARGOES]; ///< Cargoes entering from the left (index in #vertical_cargoes, or #INVALID_CARGO). - byte top_end; ///< Stop at the top of the vertical cargoes. - CargoID cust_cargoes[MAX_CARGOES]; ///< Cargoes leaving to the right (index in #vertical_cargoes, or #INVALID_CARGO). - byte bottom_end; ///< Stop at the bottom of the vertical cargoes. - } cargo; ///< Cargo data (for #CFT_CARGO). - struct { - CargoID cargoes[MAX_CARGOES]; ///< Cargoes to display (or #INVALID_CARGO). - bool left_align; ///< Align all cargo texts to the left (else align to the right). - } cargo_label; ///< Label data (for #CFT_CARGO_LABEL). - StringID header; ///< Header text (for #CFT_HEADER). - } u; // Data for each type. - - /** - * Make one of the empty fields (#CFT_EMPTY or #CFT_SMALL_EMPTY). - * @param type Type of empty field. - */ - void MakeEmpty(CargoesFieldType type) - { - this->type = type; - } - - /** - * Make an industry type field. - * @param ind_type Industry type (#NUM_INDUSTRYTYPES means 'houses'). - * @note #other_accepted and #other_produced should be filled later. - */ - void MakeIndustry(IndustryType ind_type) - { - this->type = CFT_INDUSTRY; - this->u.industry.ind_type = ind_type; - MemSetT(this->u.industry.other_accepted, INVALID_CARGO, MAX_CARGOES); - MemSetT(this->u.industry.other_produced, INVALID_CARGO, MAX_CARGOES); - } - - /** - * Connect a cargo from an industry to the #CFT_CARGO column. - * @param cargo Cargo to connect. - * @param produced Cargo is produced (if \c false, cargo is assumed to be accepted). - * @return Horizontal connection index, or \c -1 if not accepted at all. - */ - int ConnectCargo(CargoID cargo, bool producer) - { - assert(this->type == CFT_CARGO); - if (cargo == INVALID_CARGO) return -1; - - /* Find the vertical cargo column carrying the cargo. */ - int column = -1; - for (int i = 0; i < this->u.cargo.num_cargoes; i++) { - if (cargo == this->u.cargo.vertical_cargoes[i]) { - column = i; - break; - } - } - if (column < 0) return -1; - - if (producer) { - assert(this->u.cargo.supp_cargoes[column] == INVALID_CARGO); - this->u.cargo.supp_cargoes[column] = column; - } else { - assert(this->u.cargo.cust_cargoes[column] == INVALID_CARGO); - this->u.cargo.cust_cargoes[column] = column; - } - return column; - } - - /** - * Does this #CFT_CARGO field have a horizontal connection? - * @return \c true if a horizontal connection exists, \c false otherwise. - */ - bool HasConnection() - { - assert(this->type == CFT_CARGO); - - for (uint i = 0; i < MAX_CARGOES; i++) { - if (this->u.cargo.supp_cargoes[i] != INVALID_CARGO) return true; - if (this->u.cargo.cust_cargoes[i] != INVALID_CARGO) return true; - } - return false; - } - - /** - * Make a piece of cargo column. - * @param cargoes Array of #CargoID (may contain #INVALID_CARGO). - * @param length Number of cargoes in \a cargoes. - * @param count Number of cargoes to display (should be at least the number of valid cargoes, or \c -1 to let the method compute it). - * @param top_end This is the first cargo field of this column. - * @param bottom_end This is the last cargo field of this column. - * @note #supp_cargoes and #cust_cargoes should be filled in later. - */ - void MakeCargo(const CargoID *cargoes, uint length, int count = -1, bool top_end = false, bool bottom_end = false) - { - this->type = CFT_CARGO; - uint i; - uint num = 0; - for (i = 0; i < MAX_CARGOES && i < length; i++) { - if (cargoes[i] != INVALID_CARGO) { - this->u.cargo.vertical_cargoes[num] = cargoes[i]; - num++; - } - } - this->u.cargo.num_cargoes = (count < 0) ? num : count; - for (; num < MAX_CARGOES; num++) this->u.cargo.vertical_cargoes[num] = INVALID_CARGO; - this->u.cargo.top_end = top_end; - this->u.cargo.bottom_end = bottom_end; - MemSetT(this->u.cargo.supp_cargoes, INVALID_CARGO, MAX_CARGOES); - MemSetT(this->u.cargo.cust_cargoes, INVALID_CARGO, MAX_CARGOES); - } - - /** - * Make a field displaying cargo type names. - * @param cargoes Array of #CargoID (may contain #INVALID_CARGO). - * @param length Number of cargoes in \a cargoes. - * @param left_align ALign texts to the left (else to the right). - */ - void MakeCargoLabel(const CargoID *cargoes, uint length, bool left_align) - { - this->type = CFT_CARGO_LABEL; - uint i; - for (i = 0; i < MAX_CARGOES && i < length; i++) this->u.cargo_label.cargoes[i] = cargoes[i]; - for (; i < MAX_CARGOES; i++) this->u.cargo_label.cargoes[i] = INVALID_CARGO; - this->u.cargo_label.left_align = left_align; - } - - /** - * Make a header above an industry column. - * @param textid Text to display. - */ - void MakeHeader(StringID textid) - { - this->type = CFT_HEADER; - this->u.header = textid; - } - - /** - * For a #CFT_CARGO, compute the left position of the left-most vertical cargo connection. - * @param xpos Left position of the field. - * @return Left position of the left-most vertical cargo column. - */ - int GetCargoBase(int xpos) const - { - assert(this->type == CFT_CARGO); - - switch (this->u.cargo.num_cargoes) { - case 0: return xpos + CARGO_FIELD_WIDTH / 2; - case 1: return xpos + CARGO_FIELD_WIDTH / 2 - HOR_CARGO_WIDTH / 2; - case 2: return xpos + CARGO_FIELD_WIDTH / 2 - HOR_CARGO_WIDTH - HOR_CARGO_SPACE / 2; - case 3: return xpos + CARGO_FIELD_WIDTH / 2 - HOR_CARGO_WIDTH - HOR_CARGO_SPACE - HOR_CARGO_WIDTH / 2; - default: NOT_REACHED(); - } - } - - /** - * Draw the field. - * @param xpos Position of the left edge. - * @param vpos Position of the top edge. - */ - void Draw(int xpos, int ypos) const - { - switch (this->type) { - case CFT_EMPTY: - case CFT_SMALL_EMPTY: - break; - - case CFT_HEADER: - ypos += (small_height - FONT_HEIGHT_NORMAL) / 2; - DrawString(xpos, xpos + industry_width, ypos, this->u.header, TC_WHITE, SA_HOR_CENTER); - break; - - case CFT_INDUSTRY: { - int ypos1 = ypos + VERT_INTER_INDUSTRY_SPACE / 2; - int ypos2 = ypos + normal_height - 1 - VERT_INTER_INDUSTRY_SPACE / 2; - int xpos2 = xpos + industry_width - 1; - GfxDrawLine(xpos, ypos1, xpos2, ypos1, INDUSTRY_LINE_COLOUR); - GfxDrawLine(xpos, ypos1, xpos, ypos2, INDUSTRY_LINE_COLOUR); - GfxDrawLine(xpos, ypos2, xpos2, ypos2, INDUSTRY_LINE_COLOUR); - GfxDrawLine(xpos2, ypos1, xpos2, ypos2, INDUSTRY_LINE_COLOUR); - ypos += (normal_height - FONT_HEIGHT_NORMAL) / 2; - if (this->u.industry.ind_type < NUM_INDUSTRYTYPES) { - const IndustrySpec *indsp = GetIndustrySpec(this->u.industry.ind_type); - SetDParam(0, indsp->name); - DrawString(xpos, xpos2, ypos, STR_JUST_STRING, TC_WHITE, SA_HOR_CENTER); - - /* Draw the industry legend. */ - int blob_left, blob_right; - if (_current_text_dir == TD_RTL) { - blob_right = xpos2 - BLOB_DISTANCE; - blob_left = blob_right - BLOB_WIDTH; - } else { - blob_left = xpos + BLOB_DISTANCE; - blob_right = blob_left + BLOB_WIDTH; - } - GfxFillRect(blob_left, ypos2 - BLOB_DISTANCE - BLOB_HEIGHT, blob_right, ypos2 - BLOB_DISTANCE, PC_BLACK); // Border - GfxFillRect(blob_left + 1, ypos2 - BLOB_DISTANCE - BLOB_HEIGHT + 1, blob_right - 1, ypos2 - BLOB_DISTANCE - 1, indsp->map_colour); - } else { - DrawString(xpos, xpos2, ypos, STR_INDUSTRY_CARGOES_HOUSES, TC_FROMSTRING, SA_HOR_CENTER); - } - - /* Draw the other_produced/other_accepted cargoes. */ - const CargoID *other_right, *other_left; - if (_current_text_dir == TD_RTL) { - other_right = this->u.industry.other_accepted; - other_left = this->u.industry.other_produced; - } else { - other_right = this->u.industry.other_produced; - other_left = this->u.industry.other_accepted; - } - ypos1 += VERT_CARGO_EDGE; - for (uint i = 0; i < MAX_CARGOES; i++) { - if (other_right[i] != INVALID_CARGO) { - const CargoSpec *csp = CargoSpec::Get(other_right[i]); - int xp = xpos + industry_width + CARGO_STUB_WIDTH; - DrawHorConnection(xpos + industry_width, xp - 1, ypos1, csp); - GfxDrawLine(xp, ypos1, xp, ypos1 + FONT_HEIGHT_NORMAL - 1, CARGO_LINE_COLOUR); - } - if (other_left[i] != INVALID_CARGO) { - const CargoSpec *csp = CargoSpec::Get(other_left[i]); - int xp = xpos - CARGO_STUB_WIDTH; - DrawHorConnection(xp + 1, xpos - 1, ypos1, csp); - GfxDrawLine(xp, ypos1, xp, ypos1 + FONT_HEIGHT_NORMAL - 1, CARGO_LINE_COLOUR); - } - ypos1 += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; - } - break; - } - - case CFT_CARGO: { - int cargo_base = this->GetCargoBase(xpos); - int top = ypos + (this->u.cargo.top_end ? VERT_INTER_INDUSTRY_SPACE / 2 + 1 : 0); - int bot = ypos - (this->u.cargo.bottom_end ? VERT_INTER_INDUSTRY_SPACE / 2 + 1 : 0) + normal_height - 1; - int colpos = cargo_base; - for (int i = 0; i < this->u.cargo.num_cargoes; i++) { - if (this->u.cargo.top_end) GfxDrawLine(colpos, top - 1, colpos + HOR_CARGO_WIDTH - 1, top - 1, CARGO_LINE_COLOUR); - if (this->u.cargo.bottom_end) GfxDrawLine(colpos, bot + 1, colpos + HOR_CARGO_WIDTH - 1, bot + 1, CARGO_LINE_COLOUR); - GfxDrawLine(colpos, top, colpos, bot, CARGO_LINE_COLOUR); - colpos++; - const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[i]); - GfxFillRect(colpos, top, colpos + HOR_CARGO_WIDTH - 2, bot, csp->legend_colour, FILLRECT_OPAQUE); - colpos += HOR_CARGO_WIDTH - 2; - GfxDrawLine(colpos, top, colpos, bot, CARGO_LINE_COLOUR); - colpos += 1 + HOR_CARGO_SPACE; - } - - const CargoID *hor_left, *hor_right; - if (_current_text_dir == TD_RTL) { - hor_left = this->u.cargo.cust_cargoes; - hor_right = this->u.cargo.supp_cargoes; - } else { - hor_left = this->u.cargo.supp_cargoes; - hor_right = this->u.cargo.cust_cargoes; - } - ypos += VERT_CARGO_EDGE + VERT_INTER_INDUSTRY_SPACE / 2; - for (uint i = 0; i < MAX_CARGOES; i++) { - if (hor_left[i] != INVALID_CARGO) { - int col = hor_left[i]; - int dx = 0; - const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[col]); - for (; col > 0; col--) { - int lf = cargo_base + col * HOR_CARGO_WIDTH + (col - 1) * HOR_CARGO_SPACE; - DrawHorConnection(lf, lf + HOR_CARGO_SPACE - dx, ypos, csp); - dx = 1; - } - DrawHorConnection(xpos, cargo_base - dx, ypos, csp); - } - if (hor_right[i] != INVALID_CARGO) { - int col = hor_right[i]; - int dx = 0; - const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[col]); - for (; col < this->u.cargo.num_cargoes - 1; col++) { - int lf = cargo_base + (col + 1) * HOR_CARGO_WIDTH + col * HOR_CARGO_SPACE; - DrawHorConnection(lf + dx - 1, lf + HOR_CARGO_SPACE - 1, ypos, csp); - dx = 1; - } - DrawHorConnection(cargo_base + col * HOR_CARGO_SPACE + (col + 1) * HOR_CARGO_WIDTH - 1 + dx, xpos + CARGO_FIELD_WIDTH - 1, ypos, csp); - } - ypos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; - } - break; - } - - case CFT_CARGO_LABEL: - ypos += VERT_CARGO_EDGE + VERT_INTER_INDUSTRY_SPACE / 2; - for (uint i = 0; i < MAX_CARGOES; i++) { - if (this->u.cargo_label.cargoes[i] != INVALID_CARGO) { - const CargoSpec *csp = CargoSpec::Get(this->u.cargo_label.cargoes[i]); - DrawString(xpos + WD_FRAMERECT_LEFT, xpos + industry_width - 1 - WD_FRAMERECT_RIGHT, ypos, csp->name, TC_WHITE, - (this->u.cargo_label.left_align) ? SA_LEFT : SA_RIGHT); - } - ypos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; - } - break; - - default: - NOT_REACHED(); - } - } - - /** - * Decide which cargo was clicked at in a #CFT_CARGO field. - * @param left Left industry neighbour if available (else \c NULL should be supplied). - * @param right Right industry neighbour if available (else \c NULL should be supplied). - * @param pt Click position in the cargo field. - * @return Cargo clicked at, or #INVALID_CARGO if none. - */ - CargoID CargoClickedAt(const CargoesField *left, const CargoesField *right, Point pt) const - { - assert(this->type == CFT_CARGO); - - /* Vertical matching. */ - int cpos = this->GetCargoBase(0); - uint col; - for (col = 0; col < this->u.cargo.num_cargoes; col++) { - if (pt.x < cpos) break; - if (pt.x < cpos + CargoesField::HOR_CARGO_WIDTH) return this->u.cargo.vertical_cargoes[col]; - cpos += CargoesField::HOR_CARGO_WIDTH + CargoesField::HOR_CARGO_SPACE; - } - /* col = 0 -> left of first col, 1 -> left of 2nd col, ... this->u.cargo.num_cargoes right of last-col. */ - - int vpos = VERT_INTER_INDUSTRY_SPACE / 2 + VERT_CARGO_EDGE; - uint row; - for (row = 0; row < MAX_CARGOES; row++) { - if (pt.y < vpos) return INVALID_CARGO; - if (pt.y < vpos + FONT_HEIGHT_NORMAL) break; - vpos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; - } - if (row == MAX_CARGOES) return INVALID_CARGO; - - /* row = 0 -> at first horizontal row, row = 1 -> second horizontal row, 2 = 3rd horizontal row. */ - if (col == 0) { - if (this->u.cargo.supp_cargoes[row] != INVALID_CARGO) return this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]]; - if (left != NULL) { - if (left->type == CFT_INDUSTRY) return left->u.industry.other_produced[row]; - if (left->type == CFT_CARGO_LABEL && !left->u.cargo_label.left_align) return left->u.cargo_label.cargoes[row]; - } - return INVALID_CARGO; - } - if (col == this->u.cargo.num_cargoes) { - if (this->u.cargo.cust_cargoes[row] != INVALID_CARGO) return this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]]; - if (right != NULL) { - if (right->type == CFT_INDUSTRY) return right->u.industry.other_accepted[row]; - if (right->type == CFT_CARGO_LABEL && right->u.cargo_label.left_align) return right->u.cargo_label.cargoes[row]; - } - return INVALID_CARGO; - } - if (row >= col) { - /* Clicked somewhere in-between vertical cargo connection. - * Since the horizontal connection is made in the same order as the vertical list, the above condition - * ensures we are left-below the main diagonal, thus at the supplying side. - */ - return (this->u.cargo.supp_cargoes[row] != INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]] : INVALID_CARGO; - } else { - /* Clicked at a customer connection. */ - return (this->u.cargo.cust_cargoes[row] != INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]] : INVALID_CARGO; - } - } - - /** - * Decide what cargo the user clicked in the cargo label field. - * @param pt Click position in the cargo label field. - * @return Cargo clicked at, or #INVALID_CARGO if none. - */ - CargoID CargoLabelClickedAt(Point pt) const - { - assert(this->type == CFT_CARGO_LABEL); - - int vpos = VERT_INTER_INDUSTRY_SPACE / 2 + VERT_CARGO_EDGE; - uint row; - for (row = 0; row < MAX_CARGOES; row++) { - if (pt.y < vpos) return INVALID_CARGO; - if (pt.y < vpos + FONT_HEIGHT_NORMAL) break; - vpos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; - } - if (row == MAX_CARGOES) return INVALID_CARGO; - return this->u.cargo_label.cargoes[row]; - } - -private: - /** - * Draw a horizontal cargo connection. - * @param left Left-most coordinate to draw. - * @param right Right-most coordinate to draw. - * @param top Top coordinate of the cargo connection. - * @param csp Cargo to draw. - */ - static void DrawHorConnection(int left, int right, int top, const CargoSpec *csp) - { - GfxDrawLine(left, top, right, top, CARGO_LINE_COLOUR); - GfxFillRect(left, top + 1, right, top + FONT_HEIGHT_NORMAL - 2, csp->legend_colour, FILLRECT_OPAQUE); - GfxDrawLine(left, top + FONT_HEIGHT_NORMAL - 1, right, top + FONT_HEIGHT_NORMAL - 1, CARGO_LINE_COLOUR); - } -}; - -assert_compile(MAX_CARGOES >= cpp_lengthof(IndustrySpec, produced_cargo)); -assert_compile(MAX_CARGOES >= cpp_lengthof(IndustrySpec, accepts_cargo)); - -int CargoesField::small_height; ///< Height of the header row. -int CargoesField::normal_height; ///< Height of the non-header rows. -int CargoesField::industry_width; ///< Width of an industry field. -const int CargoesField::VERT_INTER_INDUSTRY_SPACE = 6; ///< Amount of space between two industries in a column. - -const int CargoesField::HOR_CARGO_BORDER_SPACE = 15; ///< Amount of space between the left/right edge of a #CFT_CARGO field, and the left/right most vertical cargo. -const int CargoesField::CARGO_STUB_WIDTH = 10; ///< Width of a cargo not carried in the column (should be less than #HOR_CARGO_BORDER_SPACE). -const int CargoesField::HOR_CARGO_WIDTH = 15; ///< Width of a vertical cargo column (inclusive the border line). -const int CargoesField::HOR_CARGO_SPACE = 5; ///< Amount of horizontal space between two vertical cargoes. -const int CargoesField::VERT_CARGO_EDGE = 4; ///< Amount of vertical space between top/bottom and the top/bottom connected cargo at an industry. -const int CargoesField::VERT_CARGO_SPACE = 4; ///< Amount of vertical space between two connected cargoes at an industry. - -const int CargoesField::BLOB_DISTANCE = 5; ///< Distance of the industry legend colour from the edge of the industry box. -const int CargoesField::BLOB_WIDTH = 12; ///< Width of the industry legend colour, including border. -const int CargoesField::BLOB_HEIGHT = 9; ///< Height of the industry legend colour, including border - -/** Width of a #CFT_CARGO field. */ -const int CargoesField::CARGO_FIELD_WIDTH = HOR_CARGO_BORDER_SPACE * 2 + HOR_CARGO_WIDTH * MAX_CARGOES + HOR_CARGO_SPACE * (MAX_CARGOES - 1); - -const int CargoesField::INDUSTRY_LINE_COLOUR = PC_YELLOW; ///< Line colour of the industry type box. -const int CargoesField::CARGO_LINE_COLOUR = PC_YELLOW; ///< Line colour around the cargo. - -/** A single row of #CargoesField. */ -struct CargoesRow { - CargoesField columns[5]; ///< One row of fields. - - /** - * Connect industry production cargoes to the cargo column after it. - * @param column Column of the industry. - */ - void ConnectIndustryProduced(int column) - { - CargoesField *ind_fld = this->columns + column; - CargoesField *cargo_fld = this->columns + column + 1; - assert(ind_fld->type == CFT_INDUSTRY && cargo_fld->type == CFT_CARGO); - - MemSetT(ind_fld->u.industry.other_produced, INVALID_CARGO, MAX_CARGOES); - - if (ind_fld->u.industry.ind_type < NUM_INDUSTRYTYPES) { - CargoID others[MAX_CARGOES]; // Produced cargoes not carried in the cargo column. - int other_count = 0; - - const IndustrySpec *indsp = GetIndustrySpec(ind_fld->u.industry.ind_type); - for (uint i = 0; i < lengthof(indsp->produced_cargo); i++) { - int col = cargo_fld->ConnectCargo(indsp->produced_cargo[i], true); - if (col < 0) others[other_count++] = indsp->produced_cargo[i]; - } - - /* Allocate other cargoes in the empty holes of the horizontal cargo connections. */ - for (uint i = 0; i < MAX_CARGOES && other_count > 0; i++) { - if (cargo_fld->u.cargo.supp_cargoes[i] == INVALID_CARGO) ind_fld->u.industry.other_produced[i] = others[--other_count]; - } - } else { - /* Houses only display what is demanded. */ - for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) { - CargoID cid = cargo_fld->u.cargo.vertical_cargoes[i]; - if (cid == CT_PASSENGERS || cid == CT_MAIL) cargo_fld->ConnectCargo(cid, true); - } - } - } - - /** - * Construct a #CFT_CARGO_LABEL field. - * @param column Column to create the new field. - * @param accepting Display accepted cargo (if \c false, display produced cargo). - */ - void MakeCargoLabel(int column, bool accepting) - { - CargoID cargoes[MAX_CARGOES]; - MemSetT(cargoes, INVALID_CARGO, lengthof(cargoes)); - - CargoesField *label_fld = this->columns + column; - CargoesField *cargo_fld = this->columns + (accepting ? column - 1 : column + 1); - - assert(cargo_fld->type == CFT_CARGO && label_fld->type == CFT_EMPTY); - for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) { - int col = cargo_fld->ConnectCargo(cargo_fld->u.cargo.vertical_cargoes[i], !accepting); - if (col >= 0) cargoes[col] = cargo_fld->u.cargo.vertical_cargoes[i]; - } - label_fld->MakeCargoLabel(cargoes, lengthof(cargoes), accepting); - } - - - /** - * Connect industry accepted cargoes to the cargo column before it. - * @param column Column of the industry. - */ - void ConnectIndustryAccepted(int column) - { - CargoesField *ind_fld = this->columns + column; - CargoesField *cargo_fld = this->columns + column - 1; - assert(ind_fld->type == CFT_INDUSTRY && cargo_fld->type == CFT_CARGO); - - MemSetT(ind_fld->u.industry.other_accepted, INVALID_CARGO, MAX_CARGOES); - - if (ind_fld->u.industry.ind_type < NUM_INDUSTRYTYPES) { - CargoID others[MAX_CARGOES]; // Accepted cargoes not carried in the cargo column. - int other_count = 0; - - const IndustrySpec *indsp = GetIndustrySpec(ind_fld->u.industry.ind_type); - for (uint i = 0; i < lengthof(indsp->accepts_cargo); i++) { - int col = cargo_fld->ConnectCargo(indsp->accepts_cargo[i], false); - if (col < 0) others[other_count++] = indsp->accepts_cargo[i]; - } - - /* Allocate other cargoes in the empty holes of the horizontal cargo connections. */ - for (uint i = 0; i < MAX_CARGOES && other_count > 0; i++) { - if (cargo_fld->u.cargo.cust_cargoes[i] == INVALID_CARGO) ind_fld->u.industry.other_accepted[i] = others[--other_count]; - } - } else { - /* Houses only display what is demanded. */ - for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) { - for (uint h = 0; h < NUM_HOUSES; h++) { - HouseSpec *hs = HouseSpec::Get(h); - if (!hs->enabled) continue; - - for (uint j = 0; j < lengthof(hs->accepts_cargo); j++) { - if (cargo_fld->u.cargo.vertical_cargoes[i] == hs->accepts_cargo[j]) { - cargo_fld->ConnectCargo(cargo_fld->u.cargo.vertical_cargoes[i], false); - goto next_cargo; - } - } - } -next_cargo: ; - } - } - } -}; - - -/** - * Window displaying the cargo connections around an industry (or cargo). - * - * The main display is constructed from 'fields', rectangles that contain an industry, piece of the cargo connection, cargo labels, or headers. - * For a nice display, the following should be kept in mind: - * - A #CFT_HEADER is always at the top of an column of #CFT_INDUSTRY fields. - * - A #CFT_CARGO_LABEL field is also always put in a column of #CFT_INDUSTRY fields. - * - The top row contains #CFT_HEADER and #CFT_SMALL_EMPTY fields. - * - Cargo connections have a column of their own (#CFT_CARGO fields). - * - Cargo accepted or produced by an industry, but not carried in a cargo connection, is drawn in the space of a cargo column attached to the industry. - * The information however is part of the industry. - * - * This results in the following invariants: - * - Width of a #CFT_INDUSTRY column is large enough to hold all industry type labels, all cargo labels, and all header texts. - * - Height of a #CFT_INDUSTRY is large enough to hold a header line, or a industry type line, \c N cargo labels - * (where \c N is the maximum number of cargoes connected between industries), \c N connections of cargo types, and space - * between two industry types (1/2 above it, and 1/2 underneath it). - * - Width of a cargo field (#CFT_CARGO) is large enough to hold \c N vertical columns (one for each type of cargo). - * Also, space is needed between an industry and the leftmost/rightmost column to draw the non-carried cargoes. - * - Height of a #CFT_CARGO field is equally high as the height of the #CFT_INDUSTRY. - * - A field at the top (#CFT_HEADER or #CFT_SMALL_EMPTY) match the width of the fields below them (#CFT_INDUSTRY respectively - * #CFT_CARGO), the height should be sufficient to display the header text. - * - * When displaying the cargoes around an industry type, five columns are needed (supplying industries, accepted cargoes, the industry, - * produced cargoes, customer industries). Displaying the industries around a cargo needs three columns (supplying industries, the cargo, - * customer industries). The remaining two columns are set to #CFT_EMPTY with a width equal to the average of a cargo and an industry column. - */ -struct IndustryCargoesWindow : public Window { - static const int HOR_TEXT_PADDING, VERT_TEXT_PADDING; - - typedef SmallVector Fields; - - Fields fields; ///< Fields to display in the #WID_IC_PANEL. - uint ind_cargo; ///< If less than #NUM_INDUSTRYTYPES, an industry type, else a cargo id + NUM_INDUSTRYTYPES. - Dimension cargo_textsize; ///< Size to hold any cargo text, as well as STR_INDUSTRY_CARGOES_SELECT_CARGO. - Dimension ind_textsize; ///< Size to hold any industry type text, as well as STR_INDUSTRY_CARGOES_SELECT_INDUSTRY. - Scrollbar *vscroll; - - IndustryCargoesWindow(int id) : Window(&_industry_cargoes_desc) - { - this->OnInit(); - this->CreateNestedTree(); - this->vscroll = this->GetScrollbar(WID_IC_SCROLLBAR); - this->FinishInitNested(0); - this->OnInvalidateData(id); - } - - virtual void OnInit() - { - /* Initialize static CargoesField size variables. */ - Dimension d = GetStringBoundingBox(STR_INDUSTRY_CARGOES_PRODUCERS); - d = maxdim(d, GetStringBoundingBox(STR_INDUSTRY_CARGOES_CUSTOMERS)); - d.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; - d.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM; - CargoesField::small_height = d.height; - - /* Decide about the size of the box holding the text of an industry type. */ - this->ind_textsize.width = 0; - this->ind_textsize.height = 0; - for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { - const IndustrySpec *indsp = GetIndustrySpec(it); - if (!indsp->enabled) continue; - this->ind_textsize = maxdim(this->ind_textsize, GetStringBoundingBox(indsp->name)); - } - d.width = max(d.width, this->ind_textsize.width); - d.height = this->ind_textsize.height; - this->ind_textsize = maxdim(this->ind_textsize, GetStringBoundingBox(STR_INDUSTRY_CARGOES_SELECT_INDUSTRY)); - - /* Compute max size of the cargo texts. */ - this->cargo_textsize.width = 0; - this->cargo_textsize.height = 0; - for (uint i = 0; i < NUM_CARGO; i++) { - const CargoSpec *csp = CargoSpec::Get(i); - if (!csp->IsValid()) continue; - this->cargo_textsize = maxdim(this->cargo_textsize, GetStringBoundingBox(csp->name)); - } - d = maxdim(d, this->cargo_textsize); // Box must also be wide enough to hold any cargo label. - this->cargo_textsize = maxdim(this->cargo_textsize, GetStringBoundingBox(STR_INDUSTRY_CARGOES_SELECT_CARGO)); - - d.width += 2 * HOR_TEXT_PADDING; - /* Ensure the height is enough for the industry type text, for the horizontal connections, and for the cargo labels. */ - uint min_ind_height = CargoesField::VERT_CARGO_EDGE * 2 + MAX_CARGOES * FONT_HEIGHT_NORMAL + (MAX_CARGOES - 1) * CargoesField::VERT_CARGO_SPACE; - d.height = max(d.height + 2 * VERT_TEXT_PADDING, min_ind_height); - - CargoesField::industry_width = d.width; - CargoesField::normal_height = d.height + CargoesField::VERT_INTER_INDUSTRY_SPACE; - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_IC_PANEL: - size->width = WD_FRAMETEXT_LEFT + CargoesField::industry_width * 3 + CargoesField::CARGO_FIELD_WIDTH * 2 + WD_FRAMETEXT_RIGHT; - break; - - case WID_IC_IND_DROPDOWN: - size->width = max(size->width, this->ind_textsize.width + padding.width); - break; - - case WID_IC_CARGO_DROPDOWN: - size->width = max(size->width, this->cargo_textsize.width + padding.width); - break; - } - } - - - CargoesFieldType type; ///< Type of field. - virtual void SetStringParameters (int widget) const - { - if (widget != WID_IC_CAPTION) return; - - if (this->ind_cargo < NUM_INDUSTRYTYPES) { - const IndustrySpec *indsp = GetIndustrySpec(this->ind_cargo); - SetDParam(0, indsp->name); - } else { - const CargoSpec *csp = CargoSpec::Get(this->ind_cargo - NUM_INDUSTRYTYPES); - SetDParam(0, csp->name); - } - } - - /** - * Do the two sets of cargoes have a valid cargo in common? - * @param cargoes1 Base address of the first cargo array. - * @param length1 Number of cargoes in the first cargo array. - * @param cargoes2 Base address of the second cargo array. - * @param length2 Number of cargoes in the second cargo array. - * @return Arrays have at least one valid cargo in common. - */ - static bool HasCommonValidCargo(const CargoID *cargoes1, uint length1, const CargoID *cargoes2, uint length2) - { - while (length1 > 0) { - if (*cargoes1 != INVALID_CARGO) { - for (uint i = 0; i < length2; i++) if (*cargoes1 == cargoes2[i]) return true; - } - cargoes1++; - length1--; - } - return false; - } - - /** - * Can houses be used to supply one of the cargoes? - * @param cargoes Base address of the cargo array. - * @param length Number of cargoes in the array. - * @return Houses can supply at least one of the cargoes. - */ - static bool HousesCanSupply(const CargoID *cargoes, uint length) - { - for (uint i = 0; i < length; i++) { - if (cargoes[i] == INVALID_CARGO) continue; - if (cargoes[i] == CT_PASSENGERS || cargoes[i] == CT_MAIL) return true; - } - return false; - } - - /** - * Can houses be used as customers of the produced cargoes? - * @param cargoes Base address of the cargo array. - * @param length Number of cargoes in the array. - * @return Houses can accept at least one of the cargoes. - */ - static bool HousesCanAccept(const CargoID *cargoes, uint length) - { - HouseZones climate_mask; - switch (_settings_game.game_creation.landscape) { - case LT_TEMPERATE: climate_mask = HZ_TEMP; break; - case LT_ARCTIC: climate_mask = HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW; break; - case LT_TROPIC: climate_mask = HZ_SUBTROPIC; break; - case LT_TOYLAND: climate_mask = HZ_TOYLND; break; - default: NOT_REACHED(); - } - for (uint i = 0; i < length; i++) { - if (cargoes[i] == INVALID_CARGO) continue; - - for (uint h = 0; h < NUM_HOUSES; h++) { - HouseSpec *hs = HouseSpec::Get(h); - if (!hs->enabled || !(hs->building_availability & climate_mask)) continue; - - for (uint j = 0; j < lengthof(hs->accepts_cargo); j++) { - if (cargoes[i] == hs->accepts_cargo[j]) return true; - } - } - } - return false; - } - - /** - * Count how many industries have accepted cargoes in common with one of the supplied set. - * @param cargoes Cargoes to search. - * @param length Number of cargoes in \a cargoes. - * @return Number of industries that have an accepted cargo in common with the supplied set. - */ - static int CountMatchingAcceptingIndustries(const CargoID *cargoes, uint length) - { - int count = 0; - for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { - const IndustrySpec *indsp = GetIndustrySpec(it); - if (!indsp->enabled) continue; - - if (HasCommonValidCargo(cargoes, length, indsp->accepts_cargo, lengthof(indsp->accepts_cargo))) count++; - } - return count; - } - - /** - * Count how many industries have produced cargoes in common with one of the supplied set. - * @param cargoes Cargoes to search. - * @param length Number of cargoes in \a cargoes. - * @return Number of industries that have a produced cargo in common with the supplied set. - */ - static int CountMatchingProducingIndustries(const CargoID *cargoes, uint length) - { - int count = 0; - for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { - const IndustrySpec *indsp = GetIndustrySpec(it); - if (!indsp->enabled) continue; - - if (HasCommonValidCargo(cargoes, length, indsp->produced_cargo, lengthof(indsp->produced_cargo))) count++; - } - return count; - } - - /** - * Shorten the cargo column to just the part between industries. - * @param column Column number of the cargo column. - * @param top Current top row. - * @param bottom Current bottom row. - */ - void ShortenCargoColumn(int column, int top, int bottom) - { - while (top < bottom && !this->fields[top].columns[column].HasConnection()) { - this->fields[top].columns[column].MakeEmpty(CFT_EMPTY); - top++; - } - this->fields[top].columns[column].u.cargo.top_end = true; - - while (bottom > top && !this->fields[bottom].columns[column].HasConnection()) { - this->fields[bottom].columns[column].MakeEmpty(CFT_EMPTY); - bottom--; - } - this->fields[bottom].columns[column].u.cargo.bottom_end = true; - } - - /** - * Place an industry in the fields. - * @param row Row of the new industry. - * @param col Column of the new industry. - * @param it Industry to place. - */ - void PlaceIndustry(int row, int col, IndustryType it) - { - assert(this->fields[row].columns[col].type == CFT_EMPTY); - this->fields[row].columns[col].MakeIndustry(it); - if (col == 0) { - this->fields[row].ConnectIndustryProduced(col); - } else { - this->fields[row].ConnectIndustryAccepted(col); - } - } - - /** - * Notify smallmap that new displayed industries have been selected (in #_displayed_industries). - */ - void NotifySmallmap() - { - if (!this->IsWidgetLowered(WID_IC_NOTIFY)) return; - - /* Only notify the smallmap window if it exists. In particular, do not - * bring it to the front to prevent messing up any nice layout of the user. */ - InvalidateWindowClassesData(WC_SMALLMAP, 0); - } - - /** - * Compute what and where to display for industry type \a it. - * @param it Industry type to display. - */ - void ComputeIndustryDisplay(IndustryType it) - { - this->GetWidget(WID_IC_CAPTION)->widget_data = STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION; - this->ind_cargo = it; - _displayed_industries = 1ULL << it; - - this->fields.Clear(); - CargoesRow *row = this->fields.Append(); - row->columns[0].MakeHeader(STR_INDUSTRY_CARGOES_PRODUCERS); - row->columns[1].MakeEmpty(CFT_SMALL_EMPTY); - row->columns[2].MakeEmpty(CFT_SMALL_EMPTY); - row->columns[3].MakeEmpty(CFT_SMALL_EMPTY); - row->columns[4].MakeHeader(STR_INDUSTRY_CARGOES_CUSTOMERS); - - const IndustrySpec *central_sp = GetIndustrySpec(it); - bool houses_supply = HousesCanSupply(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo)); - bool houses_accept = HousesCanAccept(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)); - /* Make a field consisting of two cargo columns. */ - int num_supp = CountMatchingProducingIndustries(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo)) + houses_supply; - int num_cust = CountMatchingAcceptingIndustries(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)) + houses_accept; - int num_indrows = max(3, max(num_supp, num_cust)); // One is needed for the 'it' industry, and 2 for the cargo labels. - for (int i = 0; i < num_indrows; i++) { - CargoesRow *row = this->fields.Append(); - row->columns[0].MakeEmpty(CFT_EMPTY); - row->columns[1].MakeCargo(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo)); - row->columns[2].MakeEmpty(CFT_EMPTY); - row->columns[3].MakeCargo(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)); - row->columns[4].MakeEmpty(CFT_EMPTY); - } - /* Add central industry. */ - int central_row = 1 + num_indrows / 2; - this->fields[central_row].columns[2].MakeIndustry(it); - this->fields[central_row].ConnectIndustryProduced(2); - this->fields[central_row].ConnectIndustryAccepted(2); - - /* Add cargo labels. */ - this->fields[central_row - 1].MakeCargoLabel(2, true); - this->fields[central_row + 1].MakeCargoLabel(2, false); - - /* Add suppliers and customers of the 'it' industry. */ - int supp_count = 0; - int cust_count = 0; - for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { - const IndustrySpec *indsp = GetIndustrySpec(it); - if (!indsp->enabled) continue; - - if (HasCommonValidCargo(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo), indsp->produced_cargo, lengthof(indsp->produced_cargo))) { - this->PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, it); - SetBit(_displayed_industries, it); - supp_count++; - } - if (HasCommonValidCargo(central_sp->produced_cargo, lengthof(central_sp->produced_cargo), indsp->accepts_cargo, lengthof(indsp->accepts_cargo))) { - this->PlaceIndustry(1 + cust_count * num_indrows / num_cust, 4, it); - SetBit(_displayed_industries, it); - cust_count++; - } - } - if (houses_supply) { - this->PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, NUM_INDUSTRYTYPES); - supp_count++; - } - if (houses_accept) { - this->PlaceIndustry(1 + cust_count * num_indrows / num_cust, 4, NUM_INDUSTRYTYPES); - cust_count++; - } - - this->ShortenCargoColumn(1, 1, num_indrows); - this->ShortenCargoColumn(3, 1, num_indrows); - const NWidgetBase *nwp = this->GetWidget(WID_IC_PANEL); - this->vscroll->SetCount(CeilDiv(WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + CargoesField::small_height + num_indrows * CargoesField::normal_height, nwp->resize_y)); - this->SetDirty(); - this->NotifySmallmap(); - } - - /** - * Compute what and where to display for cargo id \a cid. - * @param cid Cargo id to display. - */ - void ComputeCargoDisplay(CargoID cid) - { - this->GetWidget(WID_IC_CAPTION)->widget_data = STR_INDUSTRY_CARGOES_CARGO_CAPTION; - this->ind_cargo = cid + NUM_INDUSTRYTYPES; - _displayed_industries = 0; - - this->fields.Clear(); - CargoesRow *row = this->fields.Append(); - row->columns[0].MakeHeader(STR_INDUSTRY_CARGOES_PRODUCERS); - row->columns[1].MakeEmpty(CFT_SMALL_EMPTY); - row->columns[2].MakeHeader(STR_INDUSTRY_CARGOES_CUSTOMERS); - row->columns[3].MakeEmpty(CFT_SMALL_EMPTY); - row->columns[4].MakeEmpty(CFT_SMALL_EMPTY); - - bool houses_supply = HousesCanSupply(&cid, 1); - bool houses_accept = HousesCanAccept(&cid, 1); - int num_supp = CountMatchingProducingIndustries(&cid, 1) + houses_supply + 1; // Ensure room for the cargo label. - int num_cust = CountMatchingAcceptingIndustries(&cid, 1) + houses_accept; - int num_indrows = max(num_supp, num_cust); - for (int i = 0; i < num_indrows; i++) { - CargoesRow *row = this->fields.Append(); - row->columns[0].MakeEmpty(CFT_EMPTY); - row->columns[1].MakeCargo(&cid, 1); - row->columns[2].MakeEmpty(CFT_EMPTY); - row->columns[3].MakeEmpty(CFT_EMPTY); - row->columns[4].MakeEmpty(CFT_EMPTY); - } - - this->fields[num_indrows].MakeCargoLabel(0, false); // Add cargo labels at the left bottom. - - /* Add suppliers and customers of the cargo. */ - int supp_count = 0; - int cust_count = 0; - for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { - const IndustrySpec *indsp = GetIndustrySpec(it); - if (!indsp->enabled) continue; - - if (HasCommonValidCargo(&cid, 1, indsp->produced_cargo, lengthof(indsp->produced_cargo))) { - this->PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, it); - SetBit(_displayed_industries, it); - supp_count++; - } - if (HasCommonValidCargo(&cid, 1, indsp->accepts_cargo, lengthof(indsp->accepts_cargo))) { - this->PlaceIndustry(1 + cust_count * num_indrows / num_cust, 2, it); - SetBit(_displayed_industries, it); - cust_count++; - } - } - if (houses_supply) { - this->PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, NUM_INDUSTRYTYPES); - supp_count++; - } - if (houses_accept) { - this->PlaceIndustry(1 + cust_count * num_indrows / num_cust, 2, NUM_INDUSTRYTYPES); - cust_count++; - } - - this->ShortenCargoColumn(1, 1, num_indrows); - const NWidgetBase *nwp = this->GetWidget(WID_IC_PANEL); - this->vscroll->SetCount(CeilDiv(WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + CargoesField::small_height + num_indrows * CargoesField::normal_height, nwp->resize_y)); - this->SetDirty(); - this->NotifySmallmap(); - } - - /** - * Some data on this window has become invalid. - * @param data Information about the changed data. - * - data = 0 .. NUM_INDUSTRYTYPES - 1: Display the chain around the given industry. - * - data = NUM_INDUSTRYTYPES: Stop sending updates to the smallmap window. - * @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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - if (data == NUM_INDUSTRYTYPES) { - if (this->IsWidgetLowered(WID_IC_NOTIFY)) { - this->RaiseWidget(WID_IC_NOTIFY); - this->SetWidgetDirty(WID_IC_NOTIFY); - } - return; - } - - assert(data >= 0 && data < NUM_INDUSTRYTYPES); - this->ComputeIndustryDisplay(data); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (widget != WID_IC_PANEL) return; - - DrawPixelInfo tmp_dpi, *old_dpi; - int width = r.right - r.left + 1; - int height = r.bottom - r.top + 1 - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM; - if (!FillDrawPixelInfo(&tmp_dpi, r.left + WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, width, height)) return; - old_dpi = _cur_dpi; - _cur_dpi = &tmp_dpi; - - int left_pos = WD_FRAMERECT_LEFT; - if (this->ind_cargo >= NUM_INDUSTRYTYPES) left_pos += (CargoesField::industry_width + CargoesField::CARGO_FIELD_WIDTH) / 2; - int last_column = (this->ind_cargo < NUM_INDUSTRYTYPES) ? 4 : 2; - - const NWidgetBase *nwp = this->GetWidget(WID_IC_PANEL); - int vpos = -this->vscroll->GetPosition() * nwp->resize_y; - for (uint i = 0; i < this->fields.Length(); i++) { - int row_height = (i == 0) ? CargoesField::small_height : CargoesField::normal_height; - if (vpos + row_height >= 0) { - int xpos = left_pos; - int col, dir; - if (_current_text_dir == TD_RTL) { - col = last_column; - dir = -1; - } else { - col = 0; - dir = 1; - } - while (col >= 0 && col <= last_column) { - this->fields[i].columns[col].Draw(xpos, vpos); - xpos += (col & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width; - col += dir; - } - } - vpos += row_height; - if (vpos >= height) break; - } - - _cur_dpi = old_dpi; - } - - /** - * Calculate in which field was clicked, and within the field, at what position. - * @param pt Clicked position in the #WID_IC_PANEL widget. - * @param fieldxy If \c true is returned, field x/y coordinate of \a pt. - * @param xy If \c true is returned, x/y coordinate with in the field. - * @return Clicked at a valid position. - */ - bool CalculatePositionInWidget(Point pt, Point *fieldxy, Point *xy) - { - const NWidgetBase *nw = this->GetWidget(WID_IC_PANEL); - pt.x -= nw->pos_x; - pt.y -= nw->pos_y; - - int vpos = WD_FRAMERECT_TOP + CargoesField::small_height - this->vscroll->GetPosition() * nw->resize_y; - if (pt.y < vpos) return false; - - int row = (pt.y - vpos) / CargoesField::normal_height; // row is relative to row 1. - if (row + 1 >= (int)this->fields.Length()) return false; - vpos = pt.y - vpos - row * CargoesField::normal_height; // Position in the row + 1 field - row++; // rebase row to match index of this->fields. - - int xpos = 2 * WD_FRAMERECT_LEFT + ((this->ind_cargo < NUM_INDUSTRYTYPES) ? 0 : (CargoesField::industry_width + CargoesField::CARGO_FIELD_WIDTH) / 2); - if (pt.x < xpos) return false; - int column; - for (column = 0; column <= 5; column++) { - int width = (column & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width; - if (pt.x < xpos + width) break; - xpos += width; - } - int num_columns = (this->ind_cargo < NUM_INDUSTRYTYPES) ? 4 : 2; - if (column > num_columns) return false; - xpos = pt.x - xpos; - - /* Return both positions, compensating for RTL languages (which works due to the equal symmetry in both displays). */ - fieldxy->y = row; - xy->y = vpos; - if (_current_text_dir == TD_RTL) { - fieldxy->x = num_columns - column; - xy->x = ((column & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width) - xpos; - } else { - fieldxy->x = column; - xy->x = xpos; - } - return true; - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_IC_PANEL: { - Point fieldxy, xy; - if (!CalculatePositionInWidget(pt, &fieldxy, &xy)) return; - - const CargoesField *fld = this->fields[fieldxy.y].columns + fieldxy.x; - switch (fld->type) { - case CFT_INDUSTRY: - if (fld->u.industry.ind_type < NUM_INDUSTRYTYPES) this->ComputeIndustryDisplay(fld->u.industry.ind_type); - break; - - case CFT_CARGO: { - CargoesField *lft = (fieldxy.x > 0) ? this->fields[fieldxy.y].columns + fieldxy.x - 1 : NULL; - CargoesField *rgt = (fieldxy.x < 4) ? this->fields[fieldxy.y].columns + fieldxy.x + 1 : NULL; - CargoID cid = fld->CargoClickedAt(lft, rgt, xy); - if (cid != INVALID_CARGO) this->ComputeCargoDisplay(cid); - break; - } - - case CFT_CARGO_LABEL: { - CargoID cid = fld->CargoLabelClickedAt(xy); - if (cid != INVALID_CARGO) this->ComputeCargoDisplay(cid); - break; - } - - default: - break; - } - break; - } - - case WID_IC_NOTIFY: - this->ToggleWidgetLoweredState(WID_IC_NOTIFY); - this->SetWidgetDirty(WID_IC_NOTIFY); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - - if (this->IsWidgetLowered(WID_IC_NOTIFY)) { - if (FindWindowByClass(WC_SMALLMAP) == NULL) ShowSmallMap(); - this->NotifySmallmap(); - } - break; - - case WID_IC_CARGO_DROPDOWN: { - DropDownList *lst = new DropDownList; - const CargoSpec *cs; - FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { - *lst->Append() = new DropDownListStringItem(cs->name, cs->Index(), false); - } - if (lst->Length() == 0) { - delete lst; - break; - } - int selected = (this->ind_cargo >= NUM_INDUSTRYTYPES) ? (int)(this->ind_cargo - NUM_INDUSTRYTYPES) : -1; - ShowDropDownList(this, lst, selected, WID_IC_CARGO_DROPDOWN, 0, true); - break; - } - - case WID_IC_IND_DROPDOWN: { - DropDownList *lst = new DropDownList; - for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) { - IndustryType ind = _sorted_industry_types[i]; - const IndustrySpec *indsp = GetIndustrySpec(ind); - if (!indsp->enabled) continue; - *lst->Append() = new DropDownListStringItem(indsp->name, ind, false); - } - if (lst->Length() == 0) { - delete lst; - break; - } - int selected = (this->ind_cargo < NUM_INDUSTRYTYPES) ? (int)this->ind_cargo : -1; - ShowDropDownList(this, lst, selected, WID_IC_IND_DROPDOWN, 0, true); - break; - } - } - } - - virtual void OnDropdownSelect(int widget, int index) - { - if (index < 0) return; - - switch (widget) { - case WID_IC_CARGO_DROPDOWN: - this->ComputeCargoDisplay(index); - break; - - case WID_IC_IND_DROPDOWN: - this->ComputeIndustryDisplay(index); - break; - } - } - - virtual void OnHover(Point pt, int widget) - { - if (widget != WID_IC_PANEL) return; - - Point fieldxy, xy; - if (!CalculatePositionInWidget(pt, &fieldxy, &xy)) return; - - const CargoesField *fld = this->fields[fieldxy.y].columns + fieldxy.x; - CargoID cid = INVALID_CARGO; - switch (fld->type) { - case CFT_CARGO: { - CargoesField *lft = (fieldxy.x > 0) ? this->fields[fieldxy.y].columns + fieldxy.x - 1 : NULL; - CargoesField *rgt = (fieldxy.x < 4) ? this->fields[fieldxy.y].columns + fieldxy.x + 1 : NULL; - cid = fld->CargoClickedAt(lft, rgt, xy); - break; - } - - case CFT_CARGO_LABEL: { - cid = fld->CargoLabelClickedAt(xy); - break; - } - - case CFT_INDUSTRY: - if (fld->u.industry.ind_type < NUM_INDUSTRYTYPES && (this->ind_cargo >= NUM_INDUSTRYTYPES || fieldxy.x != 2)) { - GuiShowTooltips(this, STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP, 0, NULL, TCC_HOVER); - } - return; - - default: - break; - } - if (cid != INVALID_CARGO && (this->ind_cargo < NUM_INDUSTRYTYPES || cid != this->ind_cargo - NUM_INDUSTRYTYPES)) { - const CargoSpec *csp = CargoSpec::Get(cid); - uint64 params[5]; - params[0] = csp->name; - GuiShowTooltips(this, STR_INDUSTRY_CARGOES_CARGO_TOOLTIP, 1, params, TCC_HOVER); - } - } - - virtual void OnResize() - { - this->vscroll->SetCapacityFromWidget(this, WID_IC_PANEL); - } -}; - -const int IndustryCargoesWindow::HOR_TEXT_PADDING = 5; ///< Horizontal padding around the industry type text. -const int IndustryCargoesWindow::VERT_TEXT_PADDING = 5; ///< Vertical padding around the industry type text. - -/** - * Open the industry and cargoes window. - * @param id Industry type to display, \c NUM_INDUSTRYTYPES selects a default industry type. - */ -static void ShowIndustryCargoesWindow(IndustryType id) -{ - if (id >= NUM_INDUSTRYTYPES) { - for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) { - const IndustrySpec *indsp = GetIndustrySpec(_sorted_industry_types[i]); - if (indsp->enabled) { - id = _sorted_industry_types[i]; - break; - } - } - if (id >= NUM_INDUSTRYTYPES) return; - } - - Window *w = BringWindowToFrontById(WC_INDUSTRY_CARGOES, 0); - if (w != NULL) { - w->InvalidateData(id); - return; - } - new IndustryCargoesWindow(id); -} - -/** Open the industry and cargoes window with an industry. */ -void ShowIndustryCargoesWindow() -{ - ShowIndustryCargoesWindow(NUM_INDUSTRYTYPES); -} diff --git a/src/lang/english.txt.orig b/src/lang/english.txt.orig deleted file mode 100644 index fb21d3fded..0000000000 --- a/src/lang/english.txt.orig +++ /dev/null @@ -1,4887 +0,0 @@ -##name English (UK) -##ownname English (UK) -##isocode en_GB -##plural 0 -##textdir ltr -##digitsep , -##digitsepcur , -##decimalsep . -##winlangid 0x0809 -##grflangid 0x01 - - -# $Id$ - -# 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 . - - -##id 0x0000 -STR_NULL : -STR_EMPTY : -STR_UNDEFINED :(undefined string) -STR_JUST_NOTHING :Nothing - -# Cargo related strings -# Plural cargo name -STR_CARGO_PLURAL_NOTHING : -STR_CARGO_PLURAL_PASSENGERS :Passengers -STR_CARGO_PLURAL_COAL :Coal -STR_CARGO_PLURAL_MAIL :Mail -STR_CARGO_PLURAL_OIL :Oil -STR_CARGO_PLURAL_LIVESTOCK :Livestock -STR_CARGO_PLURAL_GOODS :Goods -STR_CARGO_PLURAL_GRAIN :Grain -STR_CARGO_PLURAL_WOOD :Wood -STR_CARGO_PLURAL_IRON_ORE :Iron Ore -STR_CARGO_PLURAL_STEEL :Steel -STR_CARGO_PLURAL_VALUABLES :Valuables -STR_CARGO_PLURAL_COPPER_ORE :Copper Ore -STR_CARGO_PLURAL_MAIZE :Maize -STR_CARGO_PLURAL_FRUIT :Fruit -STR_CARGO_PLURAL_DIAMONDS :Diamonds -STR_CARGO_PLURAL_FOOD :Food -STR_CARGO_PLURAL_PAPER :Paper -STR_CARGO_PLURAL_GOLD :Gold -STR_CARGO_PLURAL_WATER :Water -STR_CARGO_PLURAL_WHEAT :Wheat -STR_CARGO_PLURAL_RUBBER :Rubber -STR_CARGO_PLURAL_SUGAR :Sugar -STR_CARGO_PLURAL_TOYS :Toys -STR_CARGO_PLURAL_CANDY :Sweets -STR_CARGO_PLURAL_COLA :Cola -STR_CARGO_PLURAL_COTTON_CANDY :Candyfloss -STR_CARGO_PLURAL_BUBBLES :Bubbles -STR_CARGO_PLURAL_TOFFEE :Toffee -STR_CARGO_PLURAL_BATTERIES :Batteries -STR_CARGO_PLURAL_PLASTIC :Plastic -STR_CARGO_PLURAL_FIZZY_DRINKS :Fizzy Drinks - -# Singular cargo name -STR_CARGO_SINGULAR_NOTHING : -STR_CARGO_SINGULAR_PASSENGER :Passenger -STR_CARGO_SINGULAR_COAL :Coal -STR_CARGO_SINGULAR_MAIL :Mail -STR_CARGO_SINGULAR_OIL :Oil -STR_CARGO_SINGULAR_LIVESTOCK :Livestock -STR_CARGO_SINGULAR_GOODS :Goods -STR_CARGO_SINGULAR_GRAIN :Grain -STR_CARGO_SINGULAR_WOOD :Wood -STR_CARGO_SINGULAR_IRON_ORE :Iron Ore -STR_CARGO_SINGULAR_STEEL :Steel -STR_CARGO_SINGULAR_VALUABLES :Valuables -STR_CARGO_SINGULAR_COPPER_ORE :Copper Ore -STR_CARGO_SINGULAR_MAIZE :Maize -STR_CARGO_SINGULAR_FRUIT :Fruit -STR_CARGO_SINGULAR_DIAMOND :Diamond -STR_CARGO_SINGULAR_FOOD :Food -STR_CARGO_SINGULAR_PAPER :Paper -STR_CARGO_SINGULAR_GOLD :Gold -STR_CARGO_SINGULAR_WATER :Water -STR_CARGO_SINGULAR_WHEAT :Wheat -STR_CARGO_SINGULAR_RUBBER :Rubber -STR_CARGO_SINGULAR_SUGAR :Sugar -STR_CARGO_SINGULAR_TOY :Toy -STR_CARGO_SINGULAR_CANDY :Sweet -STR_CARGO_SINGULAR_COLA :Cola -STR_CARGO_SINGULAR_COTTON_CANDY :Candyfloss -STR_CARGO_SINGULAR_BUBBLE :Bubble -STR_CARGO_SINGULAR_TOFFEE :Toffee -STR_CARGO_SINGULAR_BATTERY :Battery -STR_CARGO_SINGULAR_PLASTIC :Plastic -STR_CARGO_SINGULAR_FIZZY_DRINK :Fizzy Drink - -# Quantity of cargo -STR_QUANTITY_NOTHING : -STR_QUANTITY_PASSENGERS :{COMMA} passenger{P "" s} -STR_QUANTITY_COAL :{WEIGHT_LONG} of coal -STR_QUANTITY_MAIL :{COMMA} bag{P "" s} of mail -STR_QUANTITY_OIL :{VOLUME_LONG} of oil -STR_QUANTITY_LIVESTOCK :{COMMA} item{P "" s} of livestock -STR_QUANTITY_GOODS :{COMMA} crate{P "" s} of goods -STR_QUANTITY_GRAIN :{WEIGHT_LONG} of grain -STR_QUANTITY_WOOD :{WEIGHT_LONG} of wood -STR_QUANTITY_IRON_ORE :{WEIGHT_LONG} of iron ore -STR_QUANTITY_STEEL :{WEIGHT_LONG} of steel -STR_QUANTITY_VALUABLES :{COMMA} bag{P "" s} of valuables -STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} of copper ore -STR_QUANTITY_MAIZE :{WEIGHT_LONG} of maize -STR_QUANTITY_FRUIT :{WEIGHT_LONG} of fruit -STR_QUANTITY_DIAMONDS :{COMMA} bag{P "" s} of diamonds -STR_QUANTITY_FOOD :{WEIGHT_LONG} of food -STR_QUANTITY_PAPER :{WEIGHT_LONG} of paper -STR_QUANTITY_GOLD :{COMMA} bag{P "" s} of gold -STR_QUANTITY_WATER :{VOLUME_LONG} of water -STR_QUANTITY_WHEAT :{WEIGHT_LONG} of wheat -STR_QUANTITY_RUBBER :{VOLUME_LONG} of rubber -STR_QUANTITY_SUGAR :{WEIGHT_LONG} of sugar -STR_QUANTITY_TOYS :{COMMA} toy{P "" s} -STR_QUANTITY_SWEETS :{COMMA} bag{P "" s} of sweets -STR_QUANTITY_COLA :{VOLUME_LONG} of cola -STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} of candyfloss -STR_QUANTITY_BUBBLES :{COMMA} bubble{P "" s} -STR_QUANTITY_TOFFEE :{WEIGHT_LONG} of toffee -STR_QUANTITY_BATTERIES :{COMMA} batter{P y ies} -STR_QUANTITY_PLASTIC :{VOLUME_LONG} of plastic -STR_QUANTITY_FIZZY_DRINKS :{COMMA} fizzy drink{P "" s} -STR_QUANTITY_N_A :N/A - -# Two letter abbreviation of cargo name -STR_ABBREV_NOTHING : -STR_ABBREV_PASSENGERS :{TINY_FONT}PS -STR_ABBREV_COAL :{TINY_FONT}CL -STR_ABBREV_MAIL :{TINY_FONT}ML -STR_ABBREV_OIL :{TINY_FONT}OL -STR_ABBREV_LIVESTOCK :{TINY_FONT}LV -STR_ABBREV_GOODS :{TINY_FONT}GD -STR_ABBREV_GRAIN :{TINY_FONT}GR -STR_ABBREV_WOOD :{TINY_FONT}WD -STR_ABBREV_IRON_ORE :{TINY_FONT}OR -STR_ABBREV_STEEL :{TINY_FONT}ST -STR_ABBREV_VALUABLES :{TINY_FONT}VL -STR_ABBREV_COPPER_ORE :{TINY_FONT}CO -STR_ABBREV_MAIZE :{TINY_FONT}MZ -STR_ABBREV_FRUIT :{TINY_FONT}FT -STR_ABBREV_DIAMONDS :{TINY_FONT}DM -STR_ABBREV_FOOD :{TINY_FONT}FD -STR_ABBREV_PAPER :{TINY_FONT}PR -STR_ABBREV_GOLD :{TINY_FONT}GD -STR_ABBREV_WATER :{TINY_FONT}WR -STR_ABBREV_WHEAT :{TINY_FONT}WH -STR_ABBREV_RUBBER :{TINY_FONT}RB -STR_ABBREV_SUGAR :{TINY_FONT}SG -STR_ABBREV_TOYS :{TINY_FONT}TY -STR_ABBREV_SWEETS :{TINY_FONT}SW -STR_ABBREV_COLA :{TINY_FONT}CL -STR_ABBREV_CANDYFLOSS :{TINY_FONT}CF -STR_ABBREV_BUBBLES :{TINY_FONT}BU -STR_ABBREV_TOFFEE :{TINY_FONT}TF -STR_ABBREV_BATTERIES :{TINY_FONT}BA -STR_ABBREV_PLASTIC :{TINY_FONT}PL -STR_ABBREV_FIZZY_DRINKS :{TINY_FONT}FZ -STR_ABBREV_NONE :{TINY_FONT}NO -STR_ABBREV_ALL :{TINY_FONT}ALL - -# 'Mode' of transport for cargoes -STR_PASSENGERS :{COMMA} passenger{P "" s} -STR_BAGS :{COMMA} bag{P "" s} -STR_TONS :{COMMA} tonne{P "" s} -STR_LITERS :{COMMA} litre{P "" s} -STR_ITEMS :{COMMA} item{P "" s} -STR_CRATES :{COMMA} crate{P "" s} - -# Colours, do not shuffle -STR_COLOUR_DARK_BLUE :Dark Blue -STR_COLOUR_PALE_GREEN :Pale Green -STR_COLOUR_PINK :Pink -STR_COLOUR_YELLOW :Yellow -STR_COLOUR_RED :Red -STR_COLOUR_LIGHT_BLUE :Light Blue -STR_COLOUR_GREEN :Green -STR_COLOUR_DARK_GREEN :Dark Green -STR_COLOUR_BLUE :Blue -STR_COLOUR_CREAM :Cream -STR_COLOUR_MAUVE :Mauve -STR_COLOUR_PURPLE :Purple -STR_COLOUR_ORANGE :Orange -STR_COLOUR_BROWN :Brown -STR_COLOUR_GREY :Grey -STR_COLOUR_WHITE :White - -# Units used in OpenTTD -STR_UNITS_VELOCITY_IMPERIAL :{COMMA} mph -STR_UNITS_VELOCITY_METRIC :{COMMA} km/h -STR_UNITS_VELOCITY_SI :{COMMA} m/s - -STR_UNITS_POWER_IMPERIAL :{COMMA}hp -STR_UNITS_POWER_METRIC :{COMMA}hp -STR_UNITS_POWER_SI :{COMMA}kW - -STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}t -STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}t -STR_UNITS_WEIGHT_SHORT_SI :{COMMA}kg - -STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA} ton{P "" s} -STR_UNITS_WEIGHT_LONG_METRIC :{COMMA} tonne{P "" s} -STR_UNITS_WEIGHT_LONG_SI :{COMMA} kg - -STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}gal -STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}l -STR_UNITS_VOLUME_SHORT_SI :{COMMA}m³ - -STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA} gallon{P "" s} -STR_UNITS_VOLUME_LONG_METRIC :{COMMA} litre{P "" s} -STR_UNITS_VOLUME_LONG_SI :{COMMA} m³ - -STR_UNITS_FORCE_IMPERIAL :{COMMA} lbf -STR_UNITS_FORCE_METRIC :{COMMA} kgf -STR_UNITS_FORCE_SI :{COMMA} kN - -STR_UNITS_HEIGHT_IMPERIAL :{COMMA} ft -STR_UNITS_HEIGHT_METRIC :{COMMA} m -STR_UNITS_HEIGHT_SI :{COMMA} m - -# Common window strings -STR_LIST_FILTER_TITLE :{BLACK}Filter string: -STR_LIST_FILTER_OSKTITLE :{BLACK}Enter filter string -STR_LIST_FILTER_TOOLTIP :{BLACK}Enter a keyword to filter the list for - -STR_TOOLTIP_GROUP_ORDER :{BLACK}Select grouping order -STR_TOOLTIP_SORT_ORDER :{BLACK}Select sorting order (descending/ascending) -STR_TOOLTIP_SORT_CRITERIA :{BLACK}Select sorting criteria -STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Select filtering criteria -STR_BUTTON_SORT_BY :{BLACK}Sort by -STR_BUTTON_LOCATION :{BLACK}Location -STR_BUTTON_RENAME :{BLACK}Rename - -STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Close window -STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Window title - drag this to move window -STR_TOOLTIP_SHADE :{BLACK}Shade window - only show the title bar -STR_TOOLTIP_DEBUG :{BLACK}Show NewGRF debug information -STR_TOOLTIP_DEFSIZE :{BLACK}Resize window to default size. Ctrl+Click to store current size as default -STR_TOOLTIP_STICKY :{BLACK}Mark this window as uncloseable by the 'Close All Windows' key. Ctrl+Click to also save state as default -STR_TOOLTIP_RESIZE :{BLACK}Click and drag to resize this window -STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Toggle large/small window size -STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}Scroll bar - scrolls list up/down -STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST :{BLACK}Scroll bar - scrolls list left/right -STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC :{BLACK}Demolish buildings etc. on a square of land. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate - -# Query window -STR_BUTTON_DEFAULT :{BLACK}Default -STR_BUTTON_CANCEL :{BLACK}Cancel -STR_BUTTON_OK :{BLACK}OK - -# On screen keyboard window -STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . -STR_OSK_KEYBOARD_LAYOUT_CAPS :~!@#$%^&*()_+|QWERTYUIOP{{}}ASDFGHJKL:" ZXCVBNM<>? . - -# Measurement tooltip -STR_MEASURE_LENGTH :{BLACK}Length: {NUM} -STR_MEASURE_AREA :{BLACK}Area: {NUM} x {NUM} -STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}Length: {NUM}{}Height difference: {HEIGHT} -STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}Area: {NUM} x {NUM}{}Height difference: {HEIGHT} - - -# These are used in buttons -STR_SORT_BY_CAPTION_NAME :{BLACK}Name -STR_SORT_BY_CAPTION_DATE :{BLACK}Date -# These are used in dropdowns -STR_SORT_BY_NAME :Name -STR_SORT_BY_PRODUCTION :Production -STR_SORT_BY_TYPE :Type -STR_SORT_BY_TRANSPORTED :Transported -STR_SORT_BY_NUMBER :Number -STR_SORT_BY_PROFIT_LAST_YEAR :Profit last year -STR_SORT_BY_PROFIT_THIS_YEAR :Profit this year -STR_SORT_BY_AGE :Age -STR_SORT_BY_RELIABILITY :Reliability -STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :Total capacity per cargo type -STR_SORT_BY_MAX_SPEED :Maximum speed -STR_SORT_BY_MODEL :Model -STR_SORT_BY_VALUE :Value -STR_SORT_BY_LENGTH :Length -STR_SORT_BY_LIFE_TIME :Remaining lifetime -STR_SORT_BY_TIMETABLE_DELAY :Timetable delay -STR_SORT_BY_FACILITY :Station type -STR_SORT_BY_WAITING_TOTAL :Total waiting cargo -STR_SORT_BY_WAITING_AVAILABLE :Available waiting cargo -STR_SORT_BY_RATING_MAX :Highest cargo rating -STR_SORT_BY_RATING_MIN :Lowest cargo rating -STR_SORT_BY_ENGINE_ID :EngineID (classic sort) -STR_SORT_BY_COST :Cost -STR_SORT_BY_POWER :Power -STR_SORT_BY_TRACTIVE_EFFORT :Tractive effort -STR_SORT_BY_INTRO_DATE :Introduction date -STR_SORT_BY_RUNNING_COST :Running cost -STR_SORT_BY_POWER_VS_RUNNING_COST :Power/Running cost -STR_SORT_BY_CARGO_CAPACITY :Cargo capacity -STR_SORT_BY_RANGE :Range -STR_SORT_BY_POPULATION :Population -STR_SORT_BY_RATING :Rating - -# Tooltips for the main toolbar -STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Pause game -STR_TOOLBAR_TOOLTIP_FORWARD :{BLACK}Fast forward the game -STR_TOOLBAR_TOOLTIP_OPTIONS :{BLACK}Options -STR_TOOLBAR_TOOLTIP_SAVE_GAME_ABANDON_GAME :{BLACK}Save game, abandon game, exit -STR_TOOLBAR_TOOLTIP_DISPLAY_MAP :{BLACK}Display map, extra viewport or list of signs -STR_TOOLBAR_TOOLTIP_DISPLAY_TOWN_DIRECTORY :{BLACK}Display town directory -STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Display subsidies -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Display list of company's stations -STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Display company finances information -STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Display general company information -STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK :{BLACK}Display story book -STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Display goal list -STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Display graphs -STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Display company league table -STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Fund construction of new industry or list all industries -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Display list of company's trains. Ctrl+Click toggles opening the group/vehicle list -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Display list of company's road vehicles. Ctrl+Click toggles opening the group/vehicle list -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Display list of company's ships. Ctrl+Click toggles opening the group/vehicle list -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Display list of company's aircraft. Ctrl+Click toggles opening the group/vehicle list -STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Zoom the view in -STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Zoom the view out -STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Build railway track -STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Build roads -STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Build ship docks -STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Build airports -STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Open the landscaping toolbar to raise/lower land, plant trees, etc. -STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Show sound/music window -STR_TOOLBAR_TOOLTIP_SHOW_LAST_MESSAGE_NEWS :{BLACK}Show last message/news report, show message options -STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION :{BLACK}Land area information, console, script debug, screenshots, about OpenTTD -STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR :{BLACK}Switch toolbars - -# Extra tooltips for the scenario editor toolbar -STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Save scenario, load scenario, abandon scenario editor, exit -STR_SCENEDIT_TOOLBAR_OPENTTD :{YELLOW}OpenTTD -STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR :{YELLOW}Scenario Editor -STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD :{BLACK}Move the starting date backward 1 year -STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD :{BLACK}Move the starting date forward 1 year -STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE :{BLACK}Click to enter the starting year -STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Display map, town directory -STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Landscape generation -STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Town generation -STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Industry generation -STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Road construction -STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plant trees. Shift toggles building/showing cost estimate -STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Place sign -STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Place object. Shift toggles building/showing cost estimate - -############ range for SE file menu starts -STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :Save scenario -STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO :Load scenario -STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP :Save heightmap -STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP :Load heightmap -STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Abandon scenario editor -STR_SCENEDIT_FILE_MENU_SEPARATOR : -STR_SCENEDIT_FILE_MENU_QUIT :Exit -############ range for SE file menu starts - -############ range for settings menu starts -STR_SETTINGS_MENU_GAME_OPTIONS :Game options -STR_SETTINGS_MENU_CONFIG_SETTINGS :Advanced settings -STR_SETTINGS_MENU_SCRIPT_SETTINGS :AI/Game script settings -STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF settings -STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Transparency options -STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Town names displayed -STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Station names displayed -STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Waypoint names displayed -STR_SETTINGS_MENU_SIGNS_DISPLAYED :Signs displayed -STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Competitor signs and names displayed -STR_SETTINGS_MENU_FULL_ANIMATION :Full animation -STR_SETTINGS_MENU_FULL_DETAIL :Full detail -STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :Transparent buildings -STR_SETTINGS_MENU_TRANSPARENT_SIGNS :Transparent signs -############ range ends here - -############ range for file menu starts -STR_FILE_MENU_SAVE_GAME :Save game -STR_FILE_MENU_LOAD_GAME :Load game -STR_FILE_MENU_QUIT_GAME :Abandon game -STR_FILE_MENU_SEPARATOR : -STR_FILE_MENU_EXIT :Exit -############ range ends here - -# map menu -STR_MAP_MENU_MAP_OF_WORLD :Map of world -STR_MAP_MENU_EXTRA_VIEW_PORT :Extra viewport -STR_MAP_MENU_LINGRAPH_LEGEND :Cargo Flow Legend -STR_MAP_MENU_SIGN_LIST :Sign list - -############ range for town menu starts -STR_TOWN_MENU_TOWN_DIRECTORY :Town directory -STR_TOWN_MENU_FOUND_TOWN :Found town -############ range ends here - -############ range for subsidies menu starts -STR_SUBSIDIES_MENU_SUBSIDIES :Subsidies -############ range ends here - -############ range for graph menu starts -STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH :Operating profit graph -STR_GRAPH_MENU_INCOME_GRAPH :Income graph -STR_GRAPH_MENU_DELIVERED_CARGO_GRAPH :Delivered cargo graph -STR_GRAPH_MENU_PERFORMANCE_HISTORY_GRAPH :Performance history graph -STR_GRAPH_MENU_COMPANY_VALUE_GRAPH :Company value graph -STR_GRAPH_MENU_CARGO_PAYMENT_RATES :Cargo payment rates -############ range ends here - -############ range for company league menu starts -STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE :Company league table -STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING :Detailed performance rating -STR_GRAPH_MENU_HIGHSCORE :Highscore table -############ range ends here - -############ range for industry menu starts -STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY :Industry directory -STR_INDUSTRY_MENU_INDUSTRY_CHAIN :Industry chains -STR_INDUSTRY_MENU_FUND_NEW_INDUSTRY :Fund new industry -############ range ends here - -############ range for railway construction menu starts -STR_RAIL_MENU_RAILROAD_CONSTRUCTION :Railway construction -STR_RAIL_MENU_ELRAIL_CONSTRUCTION :Electrified railway construction -STR_RAIL_MENU_MONORAIL_CONSTRUCTION :Monorail construction -STR_RAIL_MENU_MAGLEV_CONSTRUCTION :Maglev construction -############ range ends here - -############ range for road construction menu starts -STR_ROAD_MENU_ROAD_CONSTRUCTION :Road construction -STR_ROAD_MENU_TRAM_CONSTRUCTION :Tramway construction -############ range ends here - -############ range for waterways construction menu starts -STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION :Waterways construction -############ range ends here - -############ range for airport construction menu starts -STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION :Airport construction -############ range ends here - -############ range for landscaping menu starts -STR_LANDSCAPING_MENU_LANDSCAPING :Landscaping -############ range ends here - -############ range for music menu starts -STR_TOOLBAR_SOUND_MUSIC :Sound/music -############ range ends here - -############ range for message menu starts -STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT :Last message/news report -STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Message history -############ range ends here - -############ range for about menu starts -STR_ABOUT_MENU_LAND_BLOCK_INFO :Land area information -STR_ABOUT_MENU_SEPARATOR : -STR_ABOUT_MENU_TOGGLE_CONSOLE :Toggle console -STR_ABOUT_MENU_AI_DEBUG :AI/Game script debug -STR_ABOUT_MENU_SCREENSHOT :Screenshot -STR_ABOUT_MENU_ZOOMIN_SCREENSHOT :Fully zoomed in screenshot -STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :Default zoom screenshot -STR_ABOUT_MENU_GIANT_SCREENSHOT :Whole map screenshot -STR_ABOUT_MENU_ABOUT_OPENTTD :About 'OpenTTD' -STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite aligner -STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Toggle bounding boxes -STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Toggle colouring of dirty blocks -############ range ends here - -############ range for days starts (also used for the place in the highscore window) -STR_ORDINAL_NUMBER_1ST :1st -STR_ORDINAL_NUMBER_2ND :2nd -STR_ORDINAL_NUMBER_3RD :3rd -STR_ORDINAL_NUMBER_4TH :4th -STR_ORDINAL_NUMBER_5TH :5th -STR_ORDINAL_NUMBER_6TH :6th -STR_ORDINAL_NUMBER_7TH :7th -STR_ORDINAL_NUMBER_8TH :8th -STR_ORDINAL_NUMBER_9TH :9th -STR_ORDINAL_NUMBER_10TH :10th -STR_ORDINAL_NUMBER_11TH :11th -STR_ORDINAL_NUMBER_12TH :12th -STR_ORDINAL_NUMBER_13TH :13th -STR_ORDINAL_NUMBER_14TH :14th -STR_ORDINAL_NUMBER_15TH :15th -STR_ORDINAL_NUMBER_16TH :16th -STR_ORDINAL_NUMBER_17TH :17th -STR_ORDINAL_NUMBER_18TH :18th -STR_ORDINAL_NUMBER_19TH :19th -STR_ORDINAL_NUMBER_20TH :20th -STR_ORDINAL_NUMBER_21ST :21st -STR_ORDINAL_NUMBER_22ND :22nd -STR_ORDINAL_NUMBER_23RD :23rd -STR_ORDINAL_NUMBER_24TH :24th -STR_ORDINAL_NUMBER_25TH :25th -STR_ORDINAL_NUMBER_26TH :26th -STR_ORDINAL_NUMBER_27TH :27th -STR_ORDINAL_NUMBER_28TH :28th -STR_ORDINAL_NUMBER_29TH :29th -STR_ORDINAL_NUMBER_30TH :30th -STR_ORDINAL_NUMBER_31ST :31st -############ range for days ends - -############ range for months starts -STR_MONTH_ABBREV_JAN :Jan -STR_MONTH_ABBREV_FEB :Feb -STR_MONTH_ABBREV_MAR :Mar -STR_MONTH_ABBREV_APR :Apr -STR_MONTH_ABBREV_MAY :May -STR_MONTH_ABBREV_JUN :Jun -STR_MONTH_ABBREV_JUL :Jul -STR_MONTH_ABBREV_AUG :Aug -STR_MONTH_ABBREV_SEP :Sep -STR_MONTH_ABBREV_OCT :Oct -STR_MONTH_ABBREV_NOV :Nov -STR_MONTH_ABBREV_DEC :Dec - -STR_MONTH_JAN :January -STR_MONTH_FEB :February -STR_MONTH_MAR :March -STR_MONTH_APR :April -STR_MONTH_MAY :May -STR_MONTH_JUN :June -STR_MONTH_JUL :July -STR_MONTH_AUG :August -STR_MONTH_SEP :September -STR_MONTH_OCT :October -STR_MONTH_NOV :November -STR_MONTH_DEC :December -############ range for months ends - -# Graph window -STR_GRAPH_KEY_BUTTON :{BLACK}Key -STR_GRAPH_KEY_TOOLTIP :{BLACK}Show key to graphs -STR_GRAPH_X_LABEL_MONTH :{TINY_FONT}{STRING}{} {STRING} -STR_GRAPH_X_LABEL_MONTH_YEAR :{TINY_FONT}{STRING}{} {STRING}{}{NUM} -STR_GRAPH_Y_LABEL :{TINY_FONT}{STRING2} -STR_GRAPH_Y_LABEL_NUMBER :{TINY_FONT}{COMMA} - -STR_GRAPH_OPERATING_PROFIT_CAPTION :{WHITE}Operating Profit Graph -STR_GRAPH_INCOME_CAPTION :{WHITE}Income Graph -STR_GRAPH_CARGO_DELIVERED_CAPTION :{WHITE}Units of cargo delivered -STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION :{WHITE}Company performance ratings (maximum rating=1000) -STR_GRAPH_COMPANY_VALUES_CAPTION :{WHITE}Company values - -STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Cargo Payment Rates -STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL :{TINY_FONT}{BLACK}Days in transit -STR_GRAPH_CARGO_PAYMENT_RATES_TITLE :{TINY_FONT}{BLACK}Payment for delivering 10 units (or 10,000 litres) of cargo a distance of 20 squares -STR_GRAPH_CARGO_ENABLE_ALL :{TINY_FONT}{BLACK}Enable all -STR_GRAPH_CARGO_DISABLE_ALL :{TINY_FONT}{BLACK}Disable all -STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL :{BLACK}Display all cargoes on the cargo payment rates graph -STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Display no cargoes on the cargo payment rates graph -STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Toggle graph for cargo type on/off -STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} - -STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Show detailed performance ratings - -# Graph key window -STR_GRAPH_KEY_CAPTION :{WHITE}Key to company graphs -STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Click here to toggle company's entry on graph on/off - -# Company league window -STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Company League Table -STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}' -STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Engineer -STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Traffic Manager -STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR :Transport Coordinator -STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :Route Supervisor -STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR :Director -STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE :Chief Executive -STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :Chairman -STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT :President -STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON :Tycoon - -# Performance detail window -STR_PERFORMANCE_DETAIL :{WHITE}Detailed performance rating -STR_PERFORMANCE_DETAIL_KEY :{BLACK}Detail -STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}({CURRENCY_SHORT}/{CURRENCY_SHORT}) -STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}({COMMA}/{COMMA}) -STR_PERFORMANCE_DETAIL_PERCENT :{WHITE}{NUM}% -STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP :{BLACK}View details about this company -############ Those following lines need to be in this order!! -STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}Vehicles: -STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}Stations: -STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}Min. profit: -STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}Min. income: -STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Max. income: -STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}Delivered: -STR_PERFORMANCE_DETAIL_CARGO :{BLACK}Cargo: -STR_PERFORMANCE_DETAIL_MONEY :{BLACK}Money: -STR_PERFORMANCE_DETAIL_LOAN :{BLACK}Loan: -STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}Total: -############ End of order list -STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP :{BLACK}Number of vehicles that turned a profit last year. This includes road vehicles, trains, ships and aircraft -STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP :{BLACK}Number of recently-serviced stations. Train stations, bus stops, airports and so on are counted separately even if they belong to the same station -STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP :{BLACK}The profit of the vehicle with the lowest income (only vehicles older than two years are considered) -STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP :{BLACK}Amount of cash made in the quarter with the lowest profit of the last 12 quarters -STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP :{BLACK}Amount of cash made in the quarter with the highest profit of the last 12 quarters -STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP :{BLACK}Units of cargo delivered in the last four quarters -STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP :{BLACK}Number of types of cargo delivered in the last quarter -STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP :{BLACK}Amount of money this company has in the bank -STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP :{BLACK}The amount of money this company has taken on loan -STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP :{BLACK}Total points out of possible points - -# Music window -STR_MUSIC_JAZZ_JUKEBOX_CAPTION :{WHITE}Jazz Jukebox -STR_MUSIC_PLAYLIST_ALL :{TINY_FONT}{BLACK}All -STR_MUSIC_PLAYLIST_OLD_STYLE :{TINY_FONT}{BLACK}Old Style -STR_MUSIC_PLAYLIST_NEW_STYLE :{TINY_FONT}{BLACK}New Style -STR_MUSIC_PLAYLIST_EZY_STREET :{TINY_FONT}{BLACK}Ezy Street -STR_MUSIC_PLAYLIST_CUSTOM_1 :{TINY_FONT}{BLACK}Custom 1 -STR_MUSIC_PLAYLIST_CUSTOM_2 :{TINY_FONT}{BLACK}Custom 2 -STR_MUSIC_MUSIC_VOLUME :{TINY_FONT}{BLACK}Music Volume -STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLACK}Effects Volume -STR_MUSIC_RULER_MIN :{TINY_FONT}{BLACK}MIN -STR_MUSIC_RULER_MAX :{TINY_FONT}{BLACK}MAX -STR_MUSIC_RULER_MARKER :{TINY_FONT}{BLACK}' -STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- -STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} -STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ -STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{RAW_STRING}" -STR_MUSIC_TRACK :{TINY_FONT}{BLACK}Track -STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}Title -STR_MUSIC_SHUFFLE :{TINY_FONT}{BLACK}Shuffle -STR_MUSIC_PROGRAM :{TINY_FONT}{BLACK}Programme -STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Skip to previous track in selection -STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Skip to next track in selection -STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC :{BLACK}Stop playing music -STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC :{BLACK}Start playing music -STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Drag sliders to set music and sound effect volumes -STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Select 'all tracks' programme -STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC :{BLACK}Select 'old style music' programme -STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC :{BLACK}Select 'new style music' programme -STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}Select 'Ezy Street style music' programme -STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Select 'Custom 1' (user-defined) programme -STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Select 'Custom 2' (user-defined) programme -STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Toggle programme shuffle on/off -STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Show music track selection window - -STR_ERROR_NO_SONGS :{WHITE}A music set without songs has been selected. No songs will be played - -# Playlist window -STR_PLAYLIST_MUSIC_PROGRAM_SELECTION :{WHITE}Music Programme Selection -STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTBLUE}{ZEROFILL_NUM} "{RAW_STRING}" -STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLACK}Track Index -STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}Programme - '{STRING}' -STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}Clear -STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Clear current programme (Custom1 or Custom2 only) -STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Click on music track to add to current programme (Custom1 or Custom2 only) -STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Click on music track to remove it from current programme (Custom1 or Custom2 only) - -# Highscore window -STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED :{BIG_FONT}{BLACK}Top companies who reached {NUM} -STR_HIGHSCORE_TOP_COMPANIES_NETWORK_GAME :{BIG_FONT}{BLACK}Company League Table in {NUM} -STR_HIGHSCORE_POSITION :{BIG_FONT}{BLACK}{COMMA}. -STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :Businessman -STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR :Entrepreneur -STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST :Industrialist -STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST :Capitalist -STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE :Magnate -STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL :Mogul -STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY :Tycoon of the Century -STR_HIGHSCORE_NAME :{PRESIDENT_NAME}, {COMPANY} -STR_HIGHSCORE_STATS :{BIG_FONT}'{STRING}' ({COMMA}) -STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{BLACK}{COMPANY} achieves '{STRING}' status! -STR_HIGHSCORE_PRESIDENT_OF_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{WHITE}{PRESIDENT_NAME} of {COMPANY} achieves '{STRING}' status! - -# Smallmap window -STR_SMALLMAP_CAPTION :{WHITE}Map - {STRING} - -STR_SMALLMAP_TYPE_CONTOURS :Contours -STR_SMALLMAP_TYPE_VEHICLES :Vehicles -STR_SMALLMAP_TYPE_INDUSTRIES :Industries -STR_SMALLMAP_TYPE_ROUTEMAP :Cargo Flow -STR_SMALLMAP_TYPE_ROUTES :Routes -STR_SMALLMAP_TYPE_VEGETATION :Vegetation -STR_SMALLMAP_TYPE_OWNERS :Owners -STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Show land contours on map -STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP :{BLACK}Show vehicles on map -STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP :{BLACK}Show industries on map -STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP :{BLACK}Show cargo flow on map -STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Show transport routes on map -STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP :{BLACK}Show vegetation on map -STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Show land owners on map -STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}Click on an industry type to toggle displaying it. Ctrl+Click disables all types except the selected one. Ctrl+Click on it again to enable all industry types -STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}Click on a company to toggle displaying its property. Ctrl+Click disables all companies except the selected one. Ctrl+Click on it again to enable all companies -STR_SMALLMAP_TOOLTIP_CARGO_SELECTION :{BLACK}Click on a cargo to toggle displaying its property. Ctrl+Click disables all cargoes except the selected one. Ctrl+Click on it again to enable all cargoes - -STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}Roads -STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}Railways -STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS :{TINY_FONT}{BLACK}Stations/Airports/Docks -STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES :{TINY_FONT}{BLACK}Buildings/Industries -STR_SMALLMAP_LEGENDA_VEHICLES :{TINY_FONT}{BLACK}Vehicles -STR_SMALLMAP_LEGENDA_TRAINS :{TINY_FONT}{BLACK}Trains -STR_SMALLMAP_LEGENDA_ROAD_VEHICLES :{TINY_FONT}{BLACK}Road Vehicles -STR_SMALLMAP_LEGENDA_SHIPS :{TINY_FONT}{BLACK}Ships -STR_SMALLMAP_LEGENDA_AIRCRAFT :{TINY_FONT}{BLACK}Aircraft -STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES :{TINY_FONT}{BLACK}Transport Routes -STR_SMALLMAP_LEGENDA_FOREST :{TINY_FONT}{BLACK}Forest -STR_SMALLMAP_LEGENDA_RAILROAD_STATION :{TINY_FONT}{BLACK}Railway Station -STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Lorry Loading Bay -STR_SMALLMAP_LEGENDA_BUS_STATION :{TINY_FONT}{BLACK}Bus Station -STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT :{TINY_FONT}{BLACK}Airport/Heliport -STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLACK}Dock -STR_SMALLMAP_LEGENDA_ROUGH_LAND :{TINY_FONT}{BLACK}Rough Land -STR_SMALLMAP_LEGENDA_GRASS_LAND :{TINY_FONT}{BLACK}Grass Land -STR_SMALLMAP_LEGENDA_BARE_LAND :{TINY_FONT}{BLACK}Bare Land -STR_SMALLMAP_LEGENDA_FIELDS :{TINY_FONT}{BLACK}Fields -STR_SMALLMAP_LEGENDA_TREES :{TINY_FONT}{BLACK}Trees -STR_SMALLMAP_LEGENDA_ROCKS :{TINY_FONT}{BLACK}Rocks -STR_SMALLMAP_LEGENDA_WATER :{TINY_FONT}{BLACK}Water -STR_SMALLMAP_LEGENDA_NO_OWNER :{TINY_FONT}{BLACK}No Owner -STR_SMALLMAP_LEGENDA_TOWNS :{TINY_FONT}{BLACK}Towns -STR_SMALLMAP_LEGENDA_INDUSTRIES :{TINY_FONT}{BLACK}Industries -STR_SMALLMAP_LEGENDA_DESERT :{TINY_FONT}{BLACK}Desert -STR_SMALLMAP_LEGENDA_SNOW :{TINY_FONT}{BLACK}Snow - -STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Toggle town names on/off on map -STR_SMALLMAP_CENTER :{BLACK}Centre the smallmap on the current position -STR_SMALLMAP_INDUSTRY :{TINY_FONT}{STRING} ({NUM}) -STR_SMALLMAP_LINKSTATS :{TINY_FONT}{STRING} -STR_SMALLMAP_COMPANY :{TINY_FONT}{COMPANY} -STR_SMALLMAP_TOWN :{TINY_FONT}{WHITE}{TOWN} -STR_SMALLMAP_DISABLE_ALL :{BLACK}Disable all -STR_SMALLMAP_ENABLE_ALL :{BLACK}Enable all -STR_SMALLMAP_SHOW_HEIGHT :{BLACK}Show height -STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES :{BLACK}Display no industries on the map -STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES :{BLACK}Display all industries on the map -STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT :{BLACK}Toggle display of heightmap -STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES :{BLACK}Display no company property on the map -STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES :{BLACK}Display all company property on the map -STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS :{BLACK}Display no cargoes on the map -STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Display all cargoes on the map - -# Status bar messages -STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Show last message or news report -STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - -STR_STATUSBAR_PAUSED :{YELLOW}* * PAUSED * * -STR_STATUSBAR_AUTOSAVE :{RED}AUTOSAVE -STR_STATUSBAR_SAVING_GAME :{RED}* * SAVING GAME * * - -# News message history -STR_MESSAGE_HISTORY :{WHITE}Message History -STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}A list of the recent news messages -STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING5} - -STR_NEWS_MESSAGE_CAPTION :{WHITE}Message -STR_NEWS_CUSTOM_ITEM :{BIG_FONT}{BLACK}{RAW_STRING} - -STR_NEWS_FIRST_TRAIN_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First train arrives at {STATION}! -STR_NEWS_FIRST_BUS_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First bus arrives at {STATION}! -STR_NEWS_FIRST_TRUCK_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First truck arrives at {STATION}! -STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First passenger tram arrives at {STATION}! -STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First freight tram arrives at {STATION}! -STR_NEWS_FIRST_SHIP_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First ship arrives at {STATION}! -STR_NEWS_FIRST_AIRCRAFT_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First aircraft arrives at {STATION}! - -STR_NEWS_TRAIN_CRASH :{BIG_FONT}{BLACK}Train Crash!{}{COMMA} die in fireball after collision -STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER :{BIG_FONT}{BLACK}Road Vehicle Crash!{}Driver dies in fireball after collision with train -STR_NEWS_ROAD_VEHICLE_CRASH :{BIG_FONT}{BLACK}Road Vehicle Crash!{}{COMMA} die in fireball after collision with train -STR_NEWS_AIRCRAFT_CRASH :{BIG_FONT}{BLACK}Plane Crash!{}{COMMA} die in fireball at {STATION} -STR_NEWS_PLANE_CRASH_OUT_OF_FUEL :{BIG_FONT}{BLACK}Plane Crash!{}Aircraft ran out of fuel, {COMMA} die in fireball - -STR_NEWS_DISASTER_ZEPPELIN :{BIG_FONT}{BLACK}Zeppelin disaster at {STATION}! -STR_NEWS_DISASTER_SMALL_UFO :{BIG_FONT}{BLACK}Road vehicle destroyed in 'UFO' collision! -STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY :{BIG_FONT}{BLACK}Oil refinery explosion near {TOWN}! -STR_NEWS_DISASTER_HELICOPTER_FACTORY :{BIG_FONT}{BLACK}Factory destroyed in suspicious circumstances near {TOWN}! -STR_NEWS_DISASTER_BIG_UFO :{BIG_FONT}{BLACK}'UFO' lands near {TOWN}! -STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE :{BIG_FONT}{BLACK}Coal mine subsidence leaves trail of destruction near {TOWN}! -STR_NEWS_DISASTER_FLOOD_VEHICLE :{BIG_FONT}{BLACK}Floods!{}At least {COMMA} missing, presumed dead after significant flooding! - -STR_NEWS_COMPANY_IN_TROUBLE_TITLE :{BIG_FONT}{BLACK}Transport company in trouble! -STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION :{BIG_FONT}{BLACK}{RAW_STRING} will be sold off or declared bankrupt unless performance increases soon! -STR_NEWS_COMPANY_MERGER_TITLE :{BIG_FONT}{BLACK}Transport company merger! -STR_NEWS_COMPANY_MERGER_DESCRIPTION :{BIG_FONT}{BLACK}{RAW_STRING} has been sold to {RAW_STRING} for {CURRENCY_LONG}! -STR_NEWS_COMPANY_BANKRUPT_TITLE :{BIG_FONT}{BLACK}Bankrupt! -STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION :{BIG_FONT}{BLACK}{RAW_STRING} has been closed down by creditors and all assets sold off! -STR_NEWS_COMPANY_LAUNCH_TITLE :{BIG_FONT}{BLACK}New transport company launched! -STR_NEWS_COMPANY_LAUNCH_DESCRIPTION :{BIG_FONT}{BLACK}{RAW_STRING} starts construction near {TOWN}! -STR_NEWS_MERGER_TAKEOVER_TITLE :{BIG_FONT}{BLACK}{RAW_STRING} has been taken over by {RAW_STRING}! -STR_PRESIDENT_NAME_MANAGER :{BLACK}{PRESIDENT_NAME}{}(Manager) - -STR_NEWS_NEW_TOWN :{BLACK}{BIG_FONT}{RAW_STRING} sponsored construction of new town {TOWN}! - -STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}New {STRING} under construction near {TOWN}! -STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK}New {STRING} being planted near {TOWN}! - -STR_NEWS_INDUSTRY_CLOSURE_GENERAL :{BIG_FONT}{BLACK}{STRING2} announces imminent closure! -STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS :{BIG_FONT}{BLACK}Supply problems cause {STRING2} to announce imminent closure! -STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES :{BIG_FONT}{BLACK}Lack of nearby trees causes {STRING2} to announce imminent closure! - -STR_NEWS_EURO_INTRODUCTION :{BIG_FONT}{BLACK}European Monetary Union!{}{}The Euro is introduced as the sole currency for everyday transactions in your country! -STR_NEWS_BEGIN_OF_RECESSION :{BIG_FONT}{BLACK}World Recession!{}{}Financial experts fear worst as economy slumps! -STR_NEWS_END_OF_RECESSION :{BIG_FONT}{BLACK}Recession Over!{}{}Upturn in trade gives confidence to industries as economy strengthens! - -STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} increases production! -STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_COAL :{BIG_FONT}{BLACK}New coal seam found at {INDUSTRY}!{}Production is expected to double! -STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL :{BIG_FONT}{BLACK}New oil reserves found at {INDUSTRY}!{}Production is expected to double! -STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM :{BIG_FONT}{BLACK}Improved farming methods at {INDUSTRY} are expected to double production! -STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} production at {INDUSTRY} increases {COMMA}%! -STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} production down by 50% -STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM :{BIG_FONT}{BLACK}Insect infestation causes havoc at {INDUSTRY}!{}Production down by 50% -STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} production at {INDUSTRY} decreases {COMMA}%! - -STR_NEWS_TRAIN_IS_WAITING :{WHITE}{VEHICLE} is waiting in depot -STR_NEWS_ROAD_VEHICLE_IS_WAITING :{WHITE}{VEHICLE} is waiting in depot -STR_NEWS_SHIP_IS_WAITING :{WHITE}{VEHICLE} is waiting in depot -STR_NEWS_AIRCRAFT_IS_WAITING :{WHITE}{VEHICLE} is waiting in the aircraft hangar - -# Start of order review system -# DON'T ADD OR REMOVE LINES HERE -STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS :{WHITE}{VEHICLE} has too few orders in the schedule -STR_NEWS_VEHICLE_HAS_VOID_ORDER :{WHITE}{VEHICLE} has a void order -STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY :{WHITE}{VEHICLE} has duplicate orders -STR_NEWS_VEHICLE_HAS_INVALID_ENTRY :{WHITE}{VEHICLE} has an invalid station in its orders -# end of order system - -STR_NEWS_VEHICLE_IS_GETTING_OLD :{WHITE}{VEHICLE} is getting old -STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD :{WHITE}{VEHICLE} is getting very old -STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND :{WHITE}{VEHICLE} is getting very old and urgently needs replacing -STR_NEWS_TRAIN_IS_STUCK :{WHITE}{VEHICLE} can't find a path to continue -STR_NEWS_VEHICLE_IS_LOST :{WHITE}{VEHICLE} is lost -STR_NEWS_VEHICLE_IS_UNPROFITABLE :{WHITE}{VEHICLE}'s profit last year was {CURRENCY_LONG} -STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} can't get to the next destination because it is out of range - -STR_NEWS_ORDER_REFIT_FAILED :{WHITE}{VEHICLE} stopped because an ordered refit failed -STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Autorenew failed on {VEHICLE}{}{STRING} - -STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE :{BIG_FONT}{BLACK}New {STRING} now available! -STR_NEWS_NEW_VEHICLE_TYPE :{BIG_FONT}{BLACK}{ENGINE} -STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}New {STRING} now available! - {ENGINE} - -STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO :{WHITE}{STATION} no longer accepts {STRING} -STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO :{WHITE}{STATION} no longer accepts {STRING} or {STRING} -STR_NEWS_STATION_NOW_ACCEPTS_CARGO :{WHITE}{STATION} now accepts {STRING} -STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION} now accepts {STRING} and {STRING} - -STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Offer of subsidy expired:{}{}{STRING} from {STRING2} to {STRING2} will now not attract a subsidy -STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subsidy withdrawn:{}{}{STRING} service from {STRING2} to {STRING2} is no longer subsidised -STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Service subsidy offered:{}{}First {STRING} service from {STRING2} to {STRING2} will attract a year's subsidy from the local authority! -STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay 50% extra for the next year! -STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay double rates for the next year! -STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay triple rates for the next year! -STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay quadruple rates for the next year! - -STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Traffic chaos in {TOWN}!{}{}Road rebuilding programme funded by {RAW_STRING} brings 6 months of misery to motorists! -STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Transport monopoly! -STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION :{BIG_FONT}{BLACK}Local authority of {TOWN} signs contract with {RAW_STRING} for one year of exclusive transport rights! - -# Extra view window -STR_EXTRA_VIEW_PORT_TITLE :{WHITE}Viewport {COMMA} -STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}Copy to viewport -STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT :{BLACK}Copy the location of the main view to this viewport -STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}Paste from viewport -STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}Paste the location of this viewport to the main view - -# Game options window -STR_GAME_OPTIONS_CAPTION :{WHITE}Game Options -STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}Currency units -STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}Currency units selection - -############ start of currency region -STR_GAME_OPTIONS_CURRENCY_GBP :British Pound (GBP) -STR_GAME_OPTIONS_CURRENCY_USD :American Dollar (USD) -STR_GAME_OPTIONS_CURRENCY_EUR :Euro (EUR) -STR_GAME_OPTIONS_CURRENCY_JPY :Japanese Yen (JPY) -STR_GAME_OPTIONS_CURRENCY_ATS :Austrian Shilling (ATS) -STR_GAME_OPTIONS_CURRENCY_BEF :Belgian Franc (BEF) -STR_GAME_OPTIONS_CURRENCY_CHF :Swiss Franc (CHF) -STR_GAME_OPTIONS_CURRENCY_CZK :Czech Koruna (CZK) -STR_GAME_OPTIONS_CURRENCY_DEM :Deutschmark (DEM) -STR_GAME_OPTIONS_CURRENCY_DKK :Danish Krone (DKK) -STR_GAME_OPTIONS_CURRENCY_ESP :Spanish Peseta (ESP) -STR_GAME_OPTIONS_CURRENCY_FIM :Finnish Markka (FIM) -STR_GAME_OPTIONS_CURRENCY_FRF :French Franc (FRF) -STR_GAME_OPTIONS_CURRENCY_GRD :Greek Drachma (GRD) -STR_GAME_OPTIONS_CURRENCY_HUF :Hungarian Forint (HUF) -STR_GAME_OPTIONS_CURRENCY_ISK :Icelandic Krona (ISK) -STR_GAME_OPTIONS_CURRENCY_ITL :Italian Lira (ITL) -STR_GAME_OPTIONS_CURRENCY_NLG :Dutch Guilder (NLG) -STR_GAME_OPTIONS_CURRENCY_NOK :Norwegian Krone (NOK) -STR_GAME_OPTIONS_CURRENCY_PLN :Polish Złoty (PLN) -STR_GAME_OPTIONS_CURRENCY_RON :Romanian Leu (RON) -STR_GAME_OPTIONS_CURRENCY_RUR :Russian Rubles (RUR) -STR_GAME_OPTIONS_CURRENCY_SIT :Slovenian Tolar (SIT) -STR_GAME_OPTIONS_CURRENCY_SEK :Swedish Krona (SEK) -STR_GAME_OPTIONS_CURRENCY_TRY :Turkish Lira (TRY) -STR_GAME_OPTIONS_CURRENCY_SKK :Slovak Koruna (SKK) -STR_GAME_OPTIONS_CURRENCY_BRL :Brazilian Real (BRL) -STR_GAME_OPTIONS_CURRENCY_EEK :Estonian Krooni (EEK) -STR_GAME_OPTIONS_CURRENCY_LTL :Lithuanian Litas (LTL) -STR_GAME_OPTIONS_CURRENCY_KRW :South Korean Won (KRW) -STR_GAME_OPTIONS_CURRENCY_ZAR :South African Rand (ZAR) -STR_GAME_OPTIONS_CURRENCY_CUSTOM :Custom... -STR_GAME_OPTIONS_CURRENCY_GEL :Georgian Lari (GEL) -STR_GAME_OPTIONS_CURRENCY_IRR :Iranian Rial (IRR) -############ end of currency region - - -############ start of measuring units region -############ end of measuring units region - -STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Road vehicles -STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP :{BLACK}Select side of road for vehicles to drive on -STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Drive on left -STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Drive on right - -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Town names -STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Select style of town names - -############ start of townname region -STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH :English (Original) -STR_GAME_OPTIONS_TOWN_NAME_FRENCH :French -STR_GAME_OPTIONS_TOWN_NAME_GERMAN :German -STR_GAME_OPTIONS_TOWN_NAME_ADDITIONAL_ENGLISH :English (Additional) -STR_GAME_OPTIONS_TOWN_NAME_LATIN_AMERICAN :Latin-American -STR_GAME_OPTIONS_TOWN_NAME_SILLY :Silly -STR_GAME_OPTIONS_TOWN_NAME_SWEDISH :Swedish -STR_GAME_OPTIONS_TOWN_NAME_DUTCH :Dutch -STR_GAME_OPTIONS_TOWN_NAME_FINNISH :Finnish -STR_GAME_OPTIONS_TOWN_NAME_POLISH :Polish -STR_GAME_OPTIONS_TOWN_NAME_SLOVAK :Slovak -STR_GAME_OPTIONS_TOWN_NAME_NORWEGIAN :Norwegian -STR_GAME_OPTIONS_TOWN_NAME_HUNGARIAN :Hungarian -STR_GAME_OPTIONS_TOWN_NAME_AUSTRIAN :Austrian -STR_GAME_OPTIONS_TOWN_NAME_ROMANIAN :Romanian -STR_GAME_OPTIONS_TOWN_NAME_CZECH :Czech -STR_GAME_OPTIONS_TOWN_NAME_SWISS :Swiss -STR_GAME_OPTIONS_TOWN_NAME_DANISH :Danish -STR_GAME_OPTIONS_TOWN_NAME_TURKISH :Turkish -STR_GAME_OPTIONS_TOWN_NAME_ITALIAN :Italian -STR_GAME_OPTIONS_TOWN_NAME_CATALAN :Catalan -############ end of townname region - -STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Autosave -STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Select interval between automatic game saves - -STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF :Off -STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH :Every month -STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS :Every 3 months -STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS :Every 6 months -STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Every 12 months - -STR_GAME_OPTIONS_LANGUAGE :{BLACK}Language -STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Select the interface language to use - -STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Fullscreen -STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Check this box to play OpenTTD fullscreen mode - -STR_GAME_OPTIONS_RESOLUTION :{BLACK}Screen resolution -STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Select the screen resolution to use -STR_GAME_OPTIONS_RESOLUTION_OTHER :other - -STR_GAME_OPTIONS_SCREENSHOT_FORMAT :{BLACK}Screenshot format -STR_GAME_OPTIONS_SCREENSHOT_FORMAT_TOOLTIP :{BLACK}Select the screenshot format to use - -STR_GAME_OPTIONS_BASE_GRF :{BLACK}Base graphics set -STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Select the base graphics set to use -STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} missing/corrupted file{P "" s} -STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}Additional information about the base graphics set - -STR_GAME_OPTIONS_BASE_SFX :{BLACK}Base sounds set -STR_GAME_OPTIONS_BASE_SFX_TOOLTIP :{BLACK}Select the base sounds set to use -STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP :{BLACK}Additional information about the base sounds set - -STR_GAME_OPTIONS_BASE_MUSIC :{BLACK}Base music set -STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP :{BLACK}Select the base music set to use -STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} corrupted file{P "" s} -STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Additional information about the base music set - -STR_ERROR_FULLSCREEN_FAILED :{WHITE}Fullscreen mode failed -STR_ERROR_RESET_WINDOWS :{WHITE}All windows have been reseted... -STR_ERROR_AUTOMATIC_SIZING :{WHITE}Sizes of buttons and fonts have changed - -# Custom currency window - -STR_CURRENCY_WINDOW :{WHITE}Custom currency -STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}Exchange rate: {ORANGE}{CURRENCY_LONG} = £ {COMMA} -STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Decrease the amount of your currency for one Pound (£) -STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Increase the amount of your currency for one Pound (£) -STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP :{BLACK}Set the exchange rate of your currency for one Pound (£) - -STR_CURRENCY_SEPARATOR :{LTBLUE}Separator: {ORANGE}{RAW_STRING} -STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP :{BLACK}Set the separator for your currency - -STR_CURRENCY_PREFIX :{LTBLUE}Prefix: {ORANGE}{RAW_STRING} -STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP :{BLACK}Set the prefix string for your currency -STR_CURRENCY_SUFFIX :{LTBLUE}Suffix: {ORANGE}{RAW_STRING} -STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP :{BLACK}Set the suffix string for your currency - -STR_CURRENCY_SWITCH_TO_EURO :{LTBLUE}Switch to Euro: {ORANGE}{NUM} -STR_CURRENCY_SWITCH_TO_EURO_NEVER :{LTBLUE}Switch to Euro: {ORANGE}never -STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Set the year to switch to Euro -STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Switch to Euro earlier -STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Switch to Euro later - -STR_CURRENCY_PREVIEW :{LTBLUE}Preview: {ORANGE}{CURRENCY_LONG} -STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP :{BLACK}10000 Pound (£) in your currency -STR_CURRENCY_CHANGE_PARAMETER :{BLACK}Change custom currency parameter - -STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS :{LTBLUE}Maximum no. competitors: {ORANGE}{COMMA} - -STR_NONE :None -STR_FUNDING_ONLY :Funding only -STR_MINIMAL :Minimal -STR_NUM_VERY_LOW :Very Low -STR_NUM_LOW :Low -STR_NUM_NORMAL :Normal -STR_NUM_HIGH :High -STR_NUM_CUSTOM :Custom -STR_NUM_CUSTOM_NUMBER :Custom ({NUM}) - -STR_VARIETY_NONE :None -STR_VARIETY_VERY_LOW :Very Low -STR_VARIETY_LOW :Low -STR_VARIETY_MEDIUM :Medium -STR_VARIETY_HIGH :High -STR_VARIETY_VERY_HIGH :Very High - -STR_AI_SPEED_VERY_SLOW :Very Slow -STR_AI_SPEED_SLOW :Slow -STR_AI_SPEED_MEDIUM :Medium -STR_AI_SPEED_FAST :Fast -STR_AI_SPEED_VERY_FAST :Very Fast - -STR_SEA_LEVEL_VERY_LOW :Very Low -STR_SEA_LEVEL_LOW :Low -STR_SEA_LEVEL_MEDIUM :Medium -STR_SEA_LEVEL_HIGH :High -STR_SEA_LEVEL_CUSTOM :Custom -STR_SEA_LEVEL_CUSTOM_PERCENTAGE :Custom ({NUM}%) - -STR_RIVERS_NONE :None -STR_RIVERS_FEW :Few -STR_RIVERS_MODERATE :Medium -STR_RIVERS_LOT :Many - -STR_DISASTER_NONE :None -STR_DISASTER_REDUCED :Reduced -STR_DISASTER_NORMAL :Normal - -STR_SUBSIDY_X1_5 :x1.5 -STR_SUBSIDY_X2 :x2 -STR_SUBSIDY_X3 :x3 -STR_SUBSIDY_X4 :x4 - -STR_TERRAIN_TYPE_VERY_FLAT :Very Flat -STR_TERRAIN_TYPE_FLAT :Flat -STR_TERRAIN_TYPE_HILLY :Hilly -STR_TERRAIN_TYPE_MOUNTAINOUS :Mountainous - -STR_CITY_APPROVAL_PERMISSIVE :Permissive -STR_CITY_APPROVAL_TOLERANT :Tolerant -STR_CITY_APPROVAL_HOSTILE :Hostile - -STR_WARNING_NO_SUITABLE_AI :{WHITE}No suitable AIs available...{}You can download several AIs via the 'Online Content' system - -# Advanced settings window -STR_CONFIG_SETTING_CAPTION :{WHITE}Advanced Settings -STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filter string: -STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Expand all -STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Collapse all -STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(no explanation available) -STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Default value: {ORANGE}{STRING1} -STR_CONFIG_SETTING_TYPE :{LTBLUE}Setting type: {ORANGE}{STRING} -STR_CONFIG_SETTING_TYPE_CLIENT :Client setting (not stored in saves; affects all games) -STR_CONFIG_SETTING_TYPE_GAME_MENU :Game setting (stored in saves; affects only new games) -STR_CONFIG_SETTING_TYPE_GAME_INGAME :Game setting (stored in save; affects only current game) -STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Company setting (stored in saves; affects only new games) -STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Company setting (stored in save; affects only current company) - -STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Category: -STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Type: -STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}Restricts the list below showing only changed settings -STR_CONFIG_SETTING_RESTRICT_BASIC :Basic settings -STR_CONFIG_SETTING_RESTRICT_ADVANCED :Advanced settings -STR_CONFIG_SETTING_RESTRICT_ALL :Expert settings / all settings -STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT :Settings with a different value than the default -STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW :Settings with a different value than your new-game settings - -STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT :{BLACK}Restricts the list below to certain setting types -STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL :All setting types -STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT :Client settings (not stored in saves; affects all games) -STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU :Game settings (stored in saves; affects only new games) -STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :Game settings (stored in save; affects only current game) -STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU :Company settings (stored in saves; affects only new games) -STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME :Company settings (stored in save; affects only current company) -STR_CONFIG_SETTING_CATEGORY_HIDES :{BLACK}Show all search results by setting{}{SILVER}Category {BLACK}to {WHITE}{STRING} -STR_CONFIG_SETTING_TYPE_HIDES :{BLACK}Show all search results by setting{}{SILVER}Type {BLACK}to {WHITE}All setting types -STR_CONFIG_SETTING_CATEGORY_AND_TYPE_HIDES :{BLACK}Show all search results by setting{}{SILVER}Category {BLACK}to {WHITE}{STRING} {BLACK}and {SILVER}Type {BLACK}to {WHITE}All setting types -STR_CONFIG_SETTINGS_NONE :{WHITE}- None - - -STR_CONFIG_SETTING_OFF :Off -STR_CONFIG_SETTING_ON :On -STR_CONFIG_SETTING_DISABLED :Disabled - -STR_CONFIG_SETTING_COMPANIES_OFF :Off -STR_CONFIG_SETTING_COMPANIES_OWN :Own company -STR_CONFIG_SETTING_COMPANIES_ALL :All companies - -STR_CONFIG_SETTING_NONE :None -STR_CONFIG_SETTING_ORIGINAL :Original -STR_CONFIG_SETTING_REALISTIC :Realistic - -STR_CONFIG_SETTING_HORIZONTAL_POS_LEFT :Left -STR_CONFIG_SETTING_HORIZONTAL_POS_CENTER :Centre -STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :Right - -STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :Maximum initial loan: {STRING2} -STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :Maximum amount a company can loan (without taking inflation into account) -STR_CONFIG_SETTING_INTEREST_RATE :Interest rate: {STRING2} -STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Loan interest rate; also controls inflation, if enabled -STR_CONFIG_SETTING_RUNNING_COSTS :Running costs: {STRING2} -STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Set level of maintainance and running costs of vehicles and infrastructure -STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Construction speed: {STRING2} -STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Limit the amount of construction actions for AIs -STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Vehicle breakdowns: {STRING2} -STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Control how often inadequately serviced vehicles may break down -STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Subsidy multiplier: {STRING2} -STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Set how much is paid for subsidised connections -STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Construction costs: {STRING2} -STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Set level of construction and purchase costs -STR_CONFIG_SETTING_RECESSIONS :Recessions: {STRING2} -STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :If enabled, recessions may occur every few years. During a recession all production is significantly lower (it returns to previous level when the recession is over) -STR_CONFIG_SETTING_TRAIN_REVERSING :Disallow train reversing in stations: {STRING2} -STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :If enabled, trains will not reverse in non-terminus stations, even if there is a shorter path to their next destination when reversing -STR_CONFIG_SETTING_DISASTERS :Disasters: {STRING2} -STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Toggle disasters which may occasionally block or destroy vehicles or infrastructure -STR_CONFIG_SETTING_CITY_APPROVAL :City council's attitude towards area restructuring: {STRING2} -STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Choose how much noise and environmental damage by companies affect their town rating and further construction actions in their area - -STR_CONFIG_SETTING_BUILDONSLOPES :Allow building on slopes and coasts: {STRING2} -STR_CONFIG_SETTING_BUILDONSLOPES_HELPTEXT :If enabled, tracks and stations can be build on most slopes. If disabled, they are only allowed on slopes which match the direction of the track and thus require no foundations -STR_CONFIG_SETTING_AUTOSLOPE :Allow landscaping under buildings, tracks, etc. (autoslope): {STRING2} -STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Allow landscaping under buildings and tracks without removing them -STR_CONFIG_SETTING_CATCHMENT :Allow more realistically sized catchment areas: {STRING2} -STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Have differently sized catchment areas for different types of stations and airports -STR_CONFIG_SETTING_EXTRADYNAMITE :Allow removal of more town-owned roads, bridges and tunnels: {STRING2} -STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Make it easier to remove town-owned infrastructure and buildings -STR_CONFIG_SETTING_TRAIN_LENGTH :Maximum length of trains: {STRING2} -STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT :Set the maximum length of trains -STR_CONFIG_SETTING_TILE_LENGTH :{COMMA} tile{P 0 "" s} -STR_CONFIG_SETTING_SMOKE_AMOUNT :Amount of vehicle smoke/sparks: {STRING2} -STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT :Set how much smoke or how many sparks are emitted by vehicles -STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :Train acceleration model: {STRING2} -STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :Select the physics model for train acceleration. The "original" model penalises slopes equally for all vehicles. The "realistic" model penalises slopes and curves depending on various properties of the consist, like length and tractive effort -STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Road vehicle acceleration model: {STRING2} -STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :Select the physics model for road vehicle acceleration. The "original" model penalises slopes equally for all vehicles. The "realistic" model penalises slopes depending on various properties of the engine, for example 'tractive effort' -STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :Slope steepness for trains: {STRING2} -STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Steepness of a sloped tile for a train. Higher values make it more difficult to climb a hill -STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% -STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Slope steepness for road vehicles: {STRING2} -STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Steepness of a sloped tile for a road vehicle. Higher values make it more difficult to climb a hill -STR_CONFIG_SETTING_FORBID_90_DEG :Forbid trains and ships from making 90° turns: {STRING2} -STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 degree turns occur when a horizontal track is directly followed by a vertical track piece on the adjacent tile, thus making the train turn by 90 degree when traversing the tile edge instead of the usual 45 degrees for other track combinations. This also applies to the turning radius of ships -STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Allow to join stations not directly adjacent: {STRING2} -STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Allow adding parts to a station without directly touching the existing parts. Needs Ctrl+Click while placing the new parts -STR_CONFIG_SETTING_IMPROVEDLOAD :Use improved loading algorithm: {STRING2} -STR_CONFIG_SETTING_IMPROVEDLOAD_HELPTEXT :If enabled, multiple vehicles waiting at a station are loaded sequentially. Loading of the next vehicle only starts when there is enough cargo waiting to completely fill the first vehicle -STR_CONFIG_SETTING_GRADUAL_LOADING :Load vehicles gradually: {STRING2} -STR_CONFIG_SETTING_GRADUAL_LOADING_HELPTEXT :Gradually load vehicles using vehicle specific loading durations, instead of loading everything at once with a fixed time depending only on the amount of cargo loaded -STR_CONFIG_SETTING_INFLATION :Inflation: {STRING2} -STR_CONFIG_SETTING_INFLATION_HELPTEXT :Enable inflation in the economy, where costs are slightly faster rising than payments -STR_CONFIG_SETTING_SELECTGOODS :Deliver cargo to a station only when there is a demand: {STRING2} -STR_CONFIG_SETTING_SELECTGOODS_HELPTEXT :Only deliver cargo to a station that was requested from a loading vehicle. This prevents bad ratings for cargoes that are not serviced at a station -STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :Maximum bridge length: {STRING2} -STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT :Maximum length for building bridges -STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Maximum tunnel length: {STRING2} -STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :Maximum length for building tunnels -STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :Manual primary industry construction method: {STRING2} -STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :Method of funding a primary industry. 'none' means it is not possible to fund any, 'prospecting' means funding is possible, but construction occurs in a random spot on the map and may as well fail, 'as other industries' means raw industries can be constructed by companies like processing industries in any position they like -STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :None -STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :As other industries -STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :Prospecting -STR_CONFIG_SETTING_INDUSTRY_PLATFORM :Flat area around industries: {STRING2} -STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :Amount of flat space around an industry. This ensures empty space will remain available around an industry for building tracks, et cetera -STR_CONFIG_SETTING_MULTIPINDTOWN :Allow multiple similar industries per town: {STRING2} -STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :Normally, a town does not want more than one industry of each type. With this setting, it will allow several industries of the same type in the same town -STR_CONFIG_SETTING_SIGNALSIDE :Show signals: {STRING2} -STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :Select on which side of the track to place signals -STR_CONFIG_SETTING_SIGNALSIDE_LEFT :On the left -STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :On the driving side -STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :On the right -STR_CONFIG_SETTING_SHOWFINANCES :Show finances window at the end of the year: {STRING2} -STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :If enabled, the finances window pops up at the end of each year to allow easy inspection of the financial status of the company -STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :New orders are 'non-stop' by default: {STRING2} -STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Normally, a vehicle will stop at every station it passes. By enabling this setting, it will drive through all station on the way to its final destination without stopping. Note, that this setting only defines a default value for new orders. Individual orders can be set explicitly to either behaviour nevertheless -STR_CONFIG_SETTING_STOP_LOCATION :New train orders stop by default at the {STRING2} of the platform -STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Place where a train will stop at the platform by default. The 'near end' means close to the entry point, 'middle' means in the middle of the platform, and 'far end' means far away from the entry point. Note, that this setting only defines a default value for new orders. Individual orders can be set explicitly to either behaviour nevertheless -STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :near end -STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :middle -STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :far end -STR_CONFIG_SETTING_ROAD_VEHICLE_QUEUEING :Road vehicle queueing (with quantum effects): {STRING2} -STR_CONFIG_SETTING_ROAD_VEHICLE_QUEUEING_HELPTEXT :Make road vehicle wait in front of occupied road stops until they are cleared -STR_CONFIG_SETTING_AUTOSCROLL :Pan window when mouse is at the edge: {STRING2} -STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :When enabled, viewports will start to scroll when the mouse is near the edge of the window -STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :Disabled -STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN :Main viewport, full-screen only -STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT :Main viewport -STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT :Every viewport -STR_CONFIG_SETTING_BRIBE :Allow bribing of the local authority: {STRING2} -STR_CONFIG_SETTING_BRIBE_HELPTEXT :Allow companies to try bribing the local town authority. If the bribe is noticed by an inspector, the company will not be able to act in the town for six months -STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Allow buying exclusive transport rights: {STRING2} -STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :If a company buys exclusive transport rights for a town, opponents' stations (passenger and cargo) won't receive any cargo for a whole year -STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Allow funding buildings: {STRING2} -STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Allow companies to give money to towns for funding new houses -STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Allow funding local road reconstruction: {STRING2} -STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT :Allow companies to give money to towns for road re-construction to sabotage road-based services in the town -STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :Allow sending money to other companies: {STRING2} -STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :Allow transfer of money between companies in multiplayer mode -STR_CONFIG_SETTING_FREIGHT_TRAINS :Weight multiplier for freight to simulate heavy trains: {STRING2} -STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :Set the impact of carrying freight in trains. A higher value makes carrying freight more demanding for trains, especially at hills -STR_CONFIG_SETTING_PLANE_SPEED :Plane speed factor: {STRING2} -STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Set the relative speed of planes compared to other vehicle types, to reduce the amount of income of transport by aircraft -STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} -STR_CONFIG_SETTING_PLANE_CRASHES :Number of plane crashes: {STRING2} -STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Set the chance of an aircraft crash happening -STR_CONFIG_SETTING_PLANE_CRASHES_NONE :None -STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Reduced -STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normal -STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Allow drive-through road stops on town owned roads: {STRING} -STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :Allow construction of drive-through road stops on town-owned roads -STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :Allow drive-through road stops on roads owned by competitors: {STRING2} -STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :Allow construction of drive-through road stops on roads owned by other companies -STR_CONFIG_SETTING_ADJACENT_STATIONS :Allow building adjacent stations: {STRING2} -STR_CONFIG_SETTING_ADJACENT_STATIONS_HELPTEXT :Allow different stations to touch each other -STR_CONFIG_SETTING_DYNAMIC_ENGINES :Enable multiple NewGRF engine sets: {STRING2} -STR_CONFIG_SETTING_DYNAMIC_ENGINES_HELPTEXT :Compatibility option for old NewGRFs. Do not disable this, unless you know exactly what you are doing! -STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Changing this setting is not possible when there are vehicles -STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Infrastructure maintenance: {STRING2} -STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :When enabled, infrastructure causes maintenance costs. The cost grows over-proportional with the network size, thus affecting bigger companies more than smaller ones - -STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Airports never expire: {STRING2} -STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Enabling this setting makes each airport type stay available forever after its introduction - -STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Warn if vehicle is lost: {STRING2} -STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :Trigger messages about vehicles unable to find a path to their ordered destination -STR_CONFIG_SETTING_ORDER_REVIEW :Review vehicles' orders: {STRING2} -STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :When enabled, the orders of the vehicles are periodically checked, and some obvious issues are reported with a news message when detected -STR_CONFIG_SETTING_ORDER_REVIEW_OFF :No -STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :Yes, but exclude stopped vehicles -STR_CONFIG_SETTING_ORDER_REVIEW_ON :Of all vehicles -STR_CONFIG_SETTING_WARN_INCOME_LESS :Warn if a vehicle's income is negative: {STRING2} -STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT :When enabled, a news message gets sent when a vehicle has not made any profit within a calendar year -STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :Vehicles never expire: {STRING2} -STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES_HELPTEXT :When enabled, all vehicle models remain available forever after their introduction -STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Autorenew vehicle when it gets old: {STRING2} -STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :When enabled, a vehicle nearing its end of life gets automatically replaced when the renew conditions are fulfilled -STR_CONFIG_SETTING_AUTORENEW_MONTHS :Autorenew when vehicle is {STRING2} max age -STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Relative age when a vehicle should be considered for auto-renewing -STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} month{P 0 "" s} before -STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} month{P 0 "" s} after -STR_CONFIG_SETTING_AUTORENEW_MONEY :Autorenew minimum needed money for renew: {STRING2} -STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Minimal amount of money that must remain in the bank before considering auto-renewing vehicles -STR_CONFIG_SETTING_ERRMSG_DURATION :Duration of error message: {STRING2} -STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Duration for displaying error messages in a red window. Note that some (critical) error messages are not closed automatically after this time, but must be closed manually -STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} second{P 0 "" s} -STR_CONFIG_SETTING_HOVER_DELAY :Show tooltips: {STRING2} -STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :Delay before tooltips are displayed when hovering the mouse over some interface element. Alternatively tooltips can be bound to the right mouse button -STR_CONFIG_SETTING_HOVER_DELAY_VALUE :Hover for {COMMA} second{P 0 "" s} -STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :Right click -STR_CONFIG_SETTING_POPULATION_IN_LABEL :Show town population in the town name label: {STRING2} -STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Display the population of towns in their label on the map -STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Thickness of lines in graphs: {STRING2} -STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Width of the line in the graphs. A thin line is more precisely readable, a thicker line is easier to see and colours are easier to distinguish - -STR_CONFIG_SETTING_LAND_GENERATOR :Land generator: {STRING2} -STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Original -STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis -STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Max distance from edge for Oil Refineries: {STRING2} -STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Oil refineries are only constructed near the map border, that is at the coast for island maps -STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Snow line height: {STRING2} -STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Roughness of terrain (TerraGenesis only) : {STRING2} -STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Very Smooth -STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Smooth -STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Rough -STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Very Rough -STR_CONFIG_SETTING_TREE_PLACER :Tree placer algorithm: {STRING2} -STR_CONFIG_SETTING_TREE_PLACER_NONE :None -STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Original -STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Improved -STR_CONFIG_SETTING_HEIGHTMAP_ROTATION :Heightmap rotation: {STRING2} -STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :Counter clockwise -STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE :Clockwise -STR_CONFIG_SETTING_SE_FLAT_WORLD_HEIGHT :The height level a flat scenario map gets: {STRING2} -STR_CONFIG_SETTING_ENABLE_FREEFORM_EDGES :Enable landscaping the tiles at the map borders: {STRING2} -STR_CONFIG_SETTING_ENABLE_FREEFORM_EDGES_HELPTEXT :If disabled, the map borders will always be ocean -STR_CONFIG_SETTING_EDGES_NOT_EMPTY :{WHITE}One or more tiles at the northern edge are not empty -STR_CONFIG_SETTING_EDGES_NOT_WATER :{WHITE}One or more tiles at one of the edges is not water - -STR_CONFIG_SETTING_STATION_SPREAD :Max station spread: {STRING2} -STR_CONFIG_SETTING_STATION_SPREAD_HELPTEXT :Maximum area the parts of a single station may be spread out on. Note that high values will slow the game -STR_CONFIG_SETTING_SERVICEATHELIPAD :Service helicopters at helipads automatically: {STRING2} -STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :Service helicopters after every landing, even if there is no depot at the airport -STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Link landscape toolbar to rail/road/water/airport toolbars: {STRING2} -STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :When opening a construction toolbar for a transport type, also open the toolbar for terraforming -STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :Land colour used at the smallmap: {STRING2} -STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Colour of the terrain in the smallmap -STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :Green -STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :Dark green -STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :Violet -STR_CONFIG_SETTING_REVERSE_SCROLLING :Reverse scroll direction: {STRING2} -STR_CONFIG_SETTING_REVERSE_SCROLLING_HELPTEXT :Behaviour when scrolling the map with the right mouse button. When disabled, the mouse moves the camera. When enabled, the mouse moves the map -STR_CONFIG_SETTING_SMOOTH_SCROLLING :Smooth viewport scrolling: {STRING2} -STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Control how the main view scrolls to a specific position when clicking on the smallmap or when issuing a command to scroll to a specific object on the map. If enabled, the viewport scrolls smoothly, if disabled it jumps directly to the targeted spot -STR_CONFIG_SETTING_MEASURE_TOOLTIP :Show a measurement tooltip when using various build-tools: {STRING2} -STR_CONFIG_SETTING_MEASURE_TOOLTIP_HELPTEXT :Display tile-distances and height differences when dragging during construction operations -STR_CONFIG_SETTING_LIVERIES :Show company liveries: {STRING2} -STR_CONFIG_SETTING_LIVERIES_HELPTEXT :Control usage of vehicle-type specific liveries for vehicles (in contrary to company specific) -STR_CONFIG_SETTING_LIVERIES_NONE :None -STR_CONFIG_SETTING_LIVERIES_OWN :Own company -STR_CONFIG_SETTING_LIVERIES_ALL :All companies -STR_CONFIG_SETTING_PREFER_TEAMCHAT :Prefer team chat with : {STRING2} -STR_CONFIG_SETTING_PREFER_TEAMCHAT_HELPTEXT :Switch the binding of company-internal and public chat to resp. -STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING :Function of scrollwheel: {STRING2} -STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING_HELPTEXT :Enable scrolling with two-dimensional mouse-wheels -STR_CONFIG_SETTING_SCROLLWHEEL_ZOOM :Zoom map -STR_CONFIG_SETTING_SCROLLWHEEL_SCROLL :Scroll map -STR_CONFIG_SETTING_SCROLLWHEEL_OFF :Off -STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER :Map scrollwheel speed: {STRING2} -STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER_HELPTEXT :Control the sensitivity of mouse-wheel scrolling -STR_CONFIG_SETTING_OSK_ACTIVATION :On screen keyboard: {STRING2} -STR_CONFIG_SETTING_OSK_ACTIVATION_HELPTEXT :Select the method to open the on screen keyboard for entering text into editboxes only using the pointing device. This is meant for small devices without actual keyboard -STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED :Disabled -STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :Double click -STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :Single click (when focussed) -STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :Single click (immediately) - -STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU :Right-click emulation: {STRING2} -STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_HELPTEXT :Select the method to emulate right mouse-button clicks -STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND :Command+Click -STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_CONTROL :Ctrl+Click -STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_OFF :Off - -STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING :Left-click scrolling: {STRING2} -STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING_HELPTEXT :Enable scrolling the map by dragging it with the left mouse button. This is especially useful when using a touch-screen for scrolling - -STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :Use the {STRING2} date format for savegame names -STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :Format of the date in save game filenames -STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :long (31st Dec 2008) -STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :short (31-12-2008) -STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31) - -STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE :Default palette to assume for NewGRFs not specifying a palette: {STRING2} -STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_HELPTEXT :Default palette to use for NewGRFs that do not specify which one they need -STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_DOS :Default (D) palette -STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_WIN :Legacy (W) palette - -STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Automatically pause when starting a new game: {STRING2} -STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :When enabled, the game will automatically pause when starting a new game, allowing for closer study of the map -STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL :When paused allow: {STRING2} -STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_HELPTEXT :Select what actions may be done while the game is paused -STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS :No actions -STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_CONSTRUCTION :All non-construction actions -STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_LANDSCAPING :All but landscape modifying actions -STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :All actions -STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :Use the advanced vehicle list: {STRING2} -STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS_HELPTEXT :Enable usage of the advanced vehicle lists for grouping vehicles -STR_CONFIG_SETTING_LOADING_INDICATORS :Use loading indicators: {STRING2} -STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :Select whether loading indicators are displayed above loading or unloading vehicles -STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :Show timetable in ticks rather than days: {STRING2} -STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT :Show travel times in time tables in game ticks instead of days -STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Show arrival and departure in timetables: {STRING2} -STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Display anticipated arrival and departure times in timetables -STR_CONFIG_SETTING_QUICKGOTO :Quick creation of vehicle orders: {STRING2} -STR_CONFIG_SETTING_QUICKGOTO_HELPTEXT :Pre-select the 'goto cursor' when opening the orders window -STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE :Default rail type (after new game/game load): {STRING2} -STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_HELPTEXT :Rail type to select after starting or loading a game. 'first available' selects the oldest type of tracks, 'last available' selects the newest type of tracks, and 'most used' selects the type which is currently most in use -STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :First available -STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :Last available -STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :Most used -STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION :Show reserved tracks: {STRING2} -STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT :Give reserved tracks a different colour to assist in problems with trains refusing to enter path-based blocks -STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :Keep building tools active after usage: {STRING2} -STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :Keep the building tools for bridges, tunnels, etc. open after use -STR_CONFIG_SETTING_EXPENSES_LAYOUT :Group expenses in company finance window: {STRING2} -STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :Define the layout for the company expenses window - -STR_CONFIG_SETTING_SOUND_TICKER :News ticker: {STRING2} -STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Play sound for summarised news messages -STR_CONFIG_SETTING_SOUND_NEWS :Newspaper: {STRING2} -STR_CONFIG_SETTING_SOUND_NEWS_HELPTEXT :Play sound upon display of newspapers -STR_CONFIG_SETTING_SOUND_NEW_YEAR :End of year: {STRING2} -STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT :Play sound at the end of a year summarising the company's performance during the year compared to the previous year -STR_CONFIG_SETTING_SOUND_CONFIRM :Construction: {STRING2} -STR_CONFIG_SETTING_SOUND_CONFIRM_HELPTEXT :Play sound on successful constructions or other actions -STR_CONFIG_SETTING_SOUND_CLICK :Button clicks: {STRING2} -STR_CONFIG_SETTING_SOUND_CLICK_HELPTEXT :Beep when clicking buttons -STR_CONFIG_SETTING_SOUND_DISASTER :Disasters/accidents: {STRING2} -STR_CONFIG_SETTING_SOUND_DISASTER_HELPTEXT :Play sound effects of accidents and disasters -STR_CONFIG_SETTING_SOUND_VEHICLE :Vehicles: {STRING2} -STR_CONFIG_SETTING_SOUND_VEHICLE_HELPTEXT :Play sound effects of vehicles -STR_CONFIG_SETTING_SOUND_AMBIENT :Ambient: {STRING2} -STR_CONFIG_SETTING_SOUND_AMBIENT_HELPTEXT :Play ambient sounds of landscape, industries and towns - -STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING :Disable infrastructure building when no suitable vehicles are available: {STRING2} -STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT :When enabled, infrastructure is only available if there are also vehicles available, preventing waste of time and money on unusable infrastructure -STR_CONFIG_SETTING_MAX_TRAINS :Max trains per company: {STRING2} -STR_CONFIG_SETTING_MAX_TRAINS_HELPTEXT :Maximum number of trains that a company can have -STR_CONFIG_SETTING_MAX_ROAD_VEHICLES :Max road vehicles per company: {STRING2} -STR_CONFIG_SETTING_MAX_ROAD_VEHICLES_HELPTEXT :Maximum number of road vehicles that a company can have -STR_CONFIG_SETTING_MAX_AIRCRAFT :Max aircraft per company: {STRING2} -STR_CONFIG_SETTING_MAX_AIRCRAFT_HELPTEXT :Maximum number of aircraft that a company can have -STR_CONFIG_SETTING_MAX_SHIPS :Max ships per company: {STRING2} -STR_CONFIG_SETTING_MAX_SHIPS_HELPTEXT :Maximum number of ships that a company can have - -STR_CONFIG_SETTING_AI_BUILDS_TRAINS :Disable trains for computer: {STRING2} -STR_CONFIG_SETTING_AI_BUILDS_TRAINS_HELPTEXT :Enabling this setting makes building trains impossible for a computer player -STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES :Disable road vehicles for computer: {STRING2} -STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES_HELPTEXT :Enabling this setting makes building road vehicles impossible for a computer player -STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT :Disable aircraft for computer: {STRING2} -STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT_HELPTEXT :Enabling this setting makes building aircraft impossible for a computer player -STR_CONFIG_SETTING_AI_BUILDS_SHIPS :Disable ships for computer: {STRING2} -STR_CONFIG_SETTING_AI_BUILDS_SHIPS_HELPTEXT :Enabling this setting makes building ships impossible for a computer player - -STR_CONFIG_SETTING_AI_PROFILE :Default settings profile: {STRING2} -STR_CONFIG_SETTING_AI_PROFILE_HELPTEXT :Choose which settings profile to use for random AIs or for initial values when adding a new AI or Game Script -STR_CONFIG_SETTING_AI_PROFILE_EASY :Easy -STR_CONFIG_SETTING_AI_PROFILE_MEDIUM :Medium -STR_CONFIG_SETTING_AI_PROFILE_HARD :Hard - -STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Allow AIs in multiplayer: {STRING2} -STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Allow AI computer players to participate in multiplayer games -STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#opcodes before scripts are suspended: {STRING2} -STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Maximum number of computation steps that a script can take in one turn - -STR_CONFIG_SETTING_SERVINT_ISPERCENT :Service intervals are in percents: {STRING2} -STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Choose whether servicing of vehicles is triggered by the time passed since last service or by reliability dropping by a certain percentage of the maximum reliability -STR_CONFIG_SETTING_SERVINT_TRAINS :Default service interval for trains: {STRING2} -STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :Set the default service interval for new rail vehicles, if no explicit service interval is set for the vehicle -STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA} day{P 0 "" s}/% -STR_CONFIG_SETTING_SERVINT_DISABLED :Disabled -STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :Default service interval for road vehicles: {STRING2} -STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :Set the default service interval for new road vehicles, if no explicit service interval is set for the vehicle -STR_CONFIG_SETTING_SERVINT_AIRCRAFT :Default service interval for aircraft: {STRING2} -STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :Set the default service interval for new aircraft, if no explicit service interval is set for the vehicle -STR_CONFIG_SETTING_SERVINT_SHIPS :Default service interval for ships: {STRING2} -STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :Set the default service interval for new ships, if no explicit service interval is set for the vehicle -STR_CONFIG_SETTING_NOSERVICE :Disable servicing when breakdowns set to none: {STRING2} -STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :When enabled, vehicles do not get serviced if they cannot break down -STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Enable wagon speed limits: {STRING2} -STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :When enabled, also use speed limits of wagons for deciding the maximum speed of a train -STR_CONFIG_SETTING_DISABLE_ELRAILS :Disable electric rails: {STRING2} -STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :Enabling this setting disables the requirement to electrify tracks to make electric engines run on them - -STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN :Arrival of first vehicle at player's station: {STRING2} -STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN_HELPTEXT :Display a newspaper when the first vehicle arrives at a new player's station -STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER :Arrival of first vehicle at competitor's station: {STRING2} -STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER_HELPTEXT :Display a newspaper when the first vehicle arrives at a new competitor's station -STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS :Accidents / disasters: {STRING2} -STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS_HELPTEXT :Display a newspaper when accidents or disasters occur -STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION :Company information: {STRING2} -STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION_HELPTEXT :Display a newspaper when a new company starts, or when companies are risking to bankrupt -STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN :Opening of industries: {STRING2} -STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN_HELPTEXT :Display a newspaper when new industries open -STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE :Closing of industries: {STRING2} -STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE_HELPTEXT :Display a newspaper when industries close down -STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES :Economy changes: {STRING2} -STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES_HELPTEXT :Display a newspaper about global changes to economy -STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY :Production changes of industries served by the company: {STRING2} -STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY_HELPTEXT :Display a newspaper when the production level of industries change, which are served by the company -STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER :Production changes of industries served by competitor(s): {STRING2} -STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER_HELPTEXT :Display a newspaper when the production level of industries change, which are served by the competitors -STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED :Other industry production changes: {STRING2} -STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED_HELPTEXT :Display a newspaper when the production level of industries change, which are not served by the company or competitors -STR_CONFIG_SETTING_NEWS_ADVICE :Advice / information on company's vehicles: {STRING2} -STR_CONFIG_SETTING_NEWS_ADVICE_HELPTEXT :Display messages about vehicles needing attention -STR_CONFIG_SETTING_NEWS_NEW_VEHICLES :New vehicles: {STRING2} -STR_CONFIG_SETTING_NEWS_NEW_VEHICLES_HELPTEXT :Display a newspaper when a new vehicle type becomes available -STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE :Changes to cargo acceptance: {STRING2} -STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT :Display messages about stations changing acceptance of some cargoes -STR_CONFIG_SETTING_NEWS_SUBSIDIES :Subsidies: {STRING2} -STR_CONFIG_SETTING_NEWS_SUBSIDIES_HELPTEXT :Display a newspaper about subsidy related events -STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION :General information: {STRING2} -STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT :Display newspaper about general events, such as purchase of exclusive rights or funding of road reconstruction - -STR_CONFIG_SETTING_NEWS_MESSAGES_OFF :Off -STR_CONFIG_SETTING_NEWS_MESSAGES_SUMMARY :Summary -STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :Full - -STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Coloured news appears in: {STRING2} -STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Year that the newspaper announcements get printed in colour. Before this year, it uses monochrome black/white -STR_CONFIG_SETTING_STARTING_YEAR :Starting year: {STRING2} -STR_CONFIG_SETTING_SMOOTH_ECONOMY :Enable smooth economy (more, smaller changes): {STRING2} -STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :When enabled, industry production changes more often, and in smaller steps. This setting has usually no effect, if industry types are provided by a NewGRF -STR_CONFIG_SETTING_ALLOW_SHARES :Allow buying shares from other companies: {STRING2} -STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :When enabled, allow buying and selling of company shares. Shares will only be available for companies reaching a certain age -STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Percentage of leg profit to pay in feeder systems: {STRING2} -STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Percentage of income given to the intermediate legs in feeder systems, giving more control over the income -STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :When dragging, place signals every: {STRING2} -STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Set the distance at which signals will be built on a track up to the next obstacle (signal, junction), if signals are dragged -STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} tile{P 0 "" s} -STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :When dragging, keep fixed distance between signals: {STRING2} -STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :Select the behaviour of signal placement when Ctrl+dragging signals. If disabled, signals are placed around tunnels or bridges to avoid long stretches without signals. If enabled, signals are placed every n tiles, making alignment of signals at parallel tracks easier -STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :Automatically build semaphores before: {STRING2} -STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :Set the year when electric signals will be used for tracks. Before this year, non-electric signals will be used (which have the exact same function, but different looks) -STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :Enable the signal GUI: {STRING2} -STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT :Display a window for choosing signal types to build, instead of only window-less signal-type rotation with Ctrl+clicking on build signals -STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :Signal type to build by default: {STRING2} -STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :Default signal type to use -STR_CONFIG_SETTING_DEFAULT_SIGNAL_NORMAL :Block signals -STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBS :Path signals -STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBSOWAY :One-way path signals -STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES :Cycle through signal types: {STRING2} -STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES_HELPTEXT :Select which signal types to cycle through, when Ctrl+clicking on a build signal with the signal tool -STR_CONFIG_SETTING_CYCLE_SIGNAL_NORMAL :Block signals only -STR_CONFIG_SETTING_CYCLE_SIGNAL_PBS :Path signals only -STR_CONFIG_SETTING_CYCLE_SIGNAL_ALL :All - -STR_CONFIG_SETTING_TOWN_LAYOUT :Road layout for new towns: {STRING2} -STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT :Layout for the road network of towns -STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT :Original -STR_CONFIG_SETTING_TOWN_LAYOUT_BETTER_ROADS :Better roads -STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :2x2 grid -STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :3x3 grid -STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :Random -STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :Towns are allowed to build roads: {STRING2} -STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :Allow towns to build roads for growth. Disable to prevent town authorities from building roads themselves -STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :Towns are allowed to build level crossings: {STRING2} -STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :Enabling this setting allows towns to build level crossings -STR_CONFIG_SETTING_NOISE_LEVEL :Allow town controlled noise level for airports: {STRING2} -STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT :With this setting disabled, there can be two airports in each town. With this setting enabled, the number of airports in a city is limited by the noise acceptance of the town, which depends on population and airport size and distance -STR_CONFIG_SETTING_TOWN_FOUNDING :Founding towns in game: {STRING2} -STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Enabling this setting allows players to found new towns in the game -STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Forbidden -STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Allowed -STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Allowed, custom town layout - -STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :In game placement of trees: {STRING2} -STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Control random appearance of trees during the game. This might affect industries which rely on tree growth, for example lumber mills -STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE :None {RED}(breaks lumber mill) -STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_RAINFOREST :Only in rain forests -STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_ALL :Everywhere - -STR_CONFIG_SETTING_TOOLBAR_POS :Position of main toolbar: {STRING2} -STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Horizontal position of the main toolbar at the top of the screen -STR_CONFIG_SETTING_STATUSBAR_POS :Position of status bar: {STRING2} -STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT :Horizontal position of the status bar at the bottom of the screen -STR_CONFIG_SETTING_SNAP_RADIUS :Window snap radius: {STRING2} -STR_CONFIG_SETTING_SNAP_RADIUS_HELPTEXT :Distance between windows before the window being moved is automatically aligned to nearby windows -STR_CONFIG_SETTING_SNAP_RADIUS_VALUE :{COMMA} pixel{P 0 "" s} -STR_CONFIG_SETTING_SNAP_RADIUS_DISABLED :Disabled -STR_CONFIG_SETTING_SOFT_LIMIT :Maximum number of non-sticky windows: {STRING2} -STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Number of non-sticky open windows before old windows get automatically closed to make room for new windows -STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} -STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :disabled -STR_CONFIG_SETTING_ZOOM_MIN :Maximum zoom in level: {STRING2} -STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :The maximum zoom-in level for viewports. Note that enabling higher zoom-in levels increases memory requirements -STR_CONFIG_SETTING_ZOOM_MAX :Maximum zoom out level: {STRING2} -STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :The maximum zoom-out level for viewports. Higher zoom-out levels might cause lag when used -STR_CONFIG_SETTING_ZOOM_LVL_MIN :4x -STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2x -STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :Normal -STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :2x -STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :4x -STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :8x -STR_CONFIG_SETTING_TOWN_GROWTH :Town growth speed: {STRING2} -STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Speed of town growth -STR_CONFIG_SETTING_TOWN_GROWTH_NONE :None -STR_CONFIG_SETTING_TOWN_GROWTH_SLOW :Slow -STR_CONFIG_SETTING_TOWN_GROWTH_NORMAL :Normal -STR_CONFIG_SETTING_TOWN_GROWTH_FAST :Fast -STR_CONFIG_SETTING_TOWN_GROWTH_VERY_FAST :Very fast -STR_CONFIG_SETTING_LARGER_TOWNS :Proportion of towns that will become cities: {STRING2} -STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Amount of towns which will become a city, thus a town which starts out larger and grows faster -STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 in {COMMA} -STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :None -STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Initial city size multiplier: {STRING2} -STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Average size of cities relative to normal towns at start of the game -STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD :Remove absurd road-elements during the road construction: {STRING2} -STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD_HELPTEXT :Remove dead road ends during funded road reconstruction - -STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Update distribution graph every {STRING2} day{P 0:2 "" s} -STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Time between subsequent recalculations of the link graph. Each recalculation calculates the plans for one component of the graph. That means that a value X for this setting does not mean the whole graph will be updated every X days. Only some component will. The shorter you set it the more CPU time will be necessary to calculate it. The longer you set it the longer it will take until the cargo distribution starts on new routes. -STR_CONFIG_SETTING_LINKGRAPH_TIME :Take {STRING2} day{P 0:2 "" s} for recalculation of distribution graph -STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT :Time taken for each recalculation of a link graph component. When a recalculation is started, a thread is spawned which is allowed to run for this number of days. The shorter you set this the more likely it is that the thread is not finished when it's supposed to. Then the game stops until it is ("lag"). The longer you set it the longer it takes for the distribution to be updated when routes change. -STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manual -STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asymmetric -STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :symmetric -STR_CONFIG_SETTING_DISTRIBUTION_PAX :Distribution mode for passengers: {STRING2} -STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :"symmetric" means that roughly the same number of passengers will go from a station A to a station B as from B to A. "asymmetric" means that arbitrary numbers of passengers can go in either direction. "manual" means that no automatic distribution will take place for passengers. -STR_CONFIG_SETTING_DISTRIBUTION_MAIL :Distribution mode for mail: {STRING2} -STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :"symmetric" means that roughly the same amount of mail will be sent from a station A to a station B as from B to A. "asymmetric" means that arbitrary amounts of mail can be sent in either direction. "manual" means that no automatic distribution will take place for mail. -STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED :Distribution mode for the ARMOURED cargo class: {STRING2} -STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :The ARMOURED cargo class contains valuables in the temperate, diamonds in the subtropical or gold in subarctic climate. NewGRFs may change that. "symmetric" means that roughly the same amount of that cargo will be sent from a station A to a station B as from B to A. "asymmetric" means that arbitrary of that cargo can be sent in either direction. "manual" means that no automatic distribution will take place for that cargo. It is recommended to set this to asymmetric or manual when playing subarctic, as banks won't send any gold back to gold mines. For temperate and subtropical you can also choose symmetric as banks will send valuables back to the origin bank of some load of valuables. -STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Distribution mode for other cargo classes: {STRING2} -STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"asymmetric" means that arbitrary amounts of cargo can be sent in either direction. "manual" means that no automatic distribution will take place for those cargoes. -STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Distribution accuracy: {STRING2} -STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :The higher you set this the more CPU time the calculation of the link graph will take. If it takes too long you may notice lag. If you set it to a low value, however, the distribution will be inaccurate, and you may notice cargo not being sent to the places you expect it to go. -STR_CONFIG_SETTING_DEMAND_DISTANCE :Effect of distance on demands: {STRING2} -STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :If you set this to a value higher than 0, the distance between the origin station A of some cargo and a possible destination B will have an effect on the amount of cargo sent from A to B. The further away B is from A the less cargo will be sent. The higher you set it, the less cargo will be sent to far away stations and the more cargo will be sent to near stations. -STR_CONFIG_SETTING_DEMAND_SIZE :Amount of returning cargo for symmetric mode: {STRING2} -STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Setting this to less than 100% makes the symmetric distribution behave more like the asymmetric one. Less cargo will be forcibly sent back if a certain amount is sent to a station. If you set it to 0% the symmetric distribution behaves just like the asymmetric one. -STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Saturation of short paths before using high-capacity paths: {STRING2} -STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Frequently there are multiple paths between two given stations. Cargodist will saturate the shortest path first, then use the second shortest path until that is saturated and so on. Saturation is determined by an estimation of capacity and planned usage. Once it has saturated all paths, if there is still demand left, it will overload all paths, prefering the ones with high capacity. Most of the time the algorithm will not estimate the capacity accurately, though. This setting allows you to specify up to which percentage a shorter path must be saturated in the first pass before choosing the next longer one. Set it to less than 100% to avoid overcrowded stations in case of overestimated capacity. - -STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Speed units: {STRING2} -STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Whenever a speed is shown in the user interface, show it in the selected units -STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Imperial (mph) -STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metric (km/h) -STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s) - -STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Vehicle power units: {STRING2} -STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Whenever a vehicle's power is shown in the user interface, show it in the selected units -STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :Imperial (hp) -STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :Metric (hp) -STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :SI (kW) - -STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :Weights units: {STRING2} -STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :Whenever weights are shown in the user interface, show it in the selected units -STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :Imperial (short t/ton) -STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :Metric (t/tonne) -STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :SI (kg) - -STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :Volumes units: {STRING2} -STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :Whenever volumes are shown in the user interface, show it in the selected units -STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :Imperial (gal) -STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :Metric (l) -STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :SI (m³) - -STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :Tractive effort units: {STRING2} -STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :Whenever tractive effort, also known as tractive force, is shown in the user interface, show it in the selected units -STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :Imperial (lbf) -STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :Metric (kgf) -STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :SI (kN) - -STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :Heights units: {STRING2} -STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :Whenever heights are shown in the user interface, show it in the selected units -STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :Imperial (ft) -STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :Metric (m) -STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI (m) - -STR_CONFIG_SETTING_GUI :{ORANGE}Interface -STR_CONFIG_SETTING_LOCALISATION :{ORANGE}Localisation -STR_CONFIG_SETTING_CONSTRUCTION :{ORANGE}Construction -STR_CONFIG_SETTING_VEHICLES :{ORANGE}Vehicles -STR_CONFIG_SETTING_STATIONS :{ORANGE}Stations -STR_CONFIG_SETTING_ECONOMY :{ORANGE}Economy -STR_CONFIG_SETTING_LINKGRAPH :{ORANGE}Cargo Distribution -STR_CONFIG_SETTING_AI :{ORANGE}Competitors -STR_CONFIG_SETTING_DISPLAY_OPTIONS :{ORANGE}Display options -STR_CONFIG_SETTING_INTERACTION :{ORANGE}Interaction -STR_CONFIG_SETTING_SOUND :{ORANGE}Sound effects -STR_CONFIG_SETTING_NEWS :{ORANGE}News and messages -STR_CONFIG_SETTING_CONSTRUCTION_SIGNALS :{ORANGE}Signals -STR_CONFIG_SETTING_STATIONS_CARGOHANDLING :{ORANGE}Cargo handling -STR_CONFIG_SETTING_AI_NPC :{ORANGE}Computer players -STR_CONFIG_SETTING_VEHICLES_AUTORENEW :{ORANGE}Autorenew -STR_CONFIG_SETTING_VEHICLES_SERVICING :{ORANGE}Servicing -STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}Routing -STR_CONFIG_SETTING_VEHICLES_TRAINS :{ORANGE}Trains -STR_CONFIG_SETTING_ECONOMY_TOWNS :{ORANGE}Towns -STR_CONFIG_SETTING_ECONOMY_INDUSTRIES :{ORANGE}Industries - -STR_CONFIG_SETTING_PATHFINDER_OPF :Original -STR_CONFIG_SETTING_PATHFINDER_NPF :NPF -STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Recommended) - -STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS :Pathfinder for trains: {STRING2} -STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT :Path finder to use for trains -STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES :Pathfinder for road vehicles: {STRING2} -STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES_HELPTEXT :Path finder to use for road vehicles -STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS :Pathfinder for ships: {STRING2} -STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT :Path finder to use for ships -STR_CONFIG_SETTING_REVERSE_AT_SIGNALS :Automatic reversing at signals: {STRING2} -STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Allow trains to reverse on a signal, if they waited there a long time - -STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Change setting value - -# Config errors -STR_CONFIG_ERROR :{WHITE}Error with the configuration file... -STR_CONFIG_ERROR_ARRAY :{WHITE}... error in array '{RAW_STRING}' -STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... invalid value '{RAW_STRING}' for '{RAW_STRING}' -STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... trailing characters at end of setting '{RAW_STRING}' -STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... ignoring NewGRF '{RAW_STRING}': duplicate GRF ID with '{RAW_STRING}' -STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... ignoring invalid NewGRF '{RAW_STRING}': {STRING} -STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :not found -STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :unsafe for static use -STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :system NewGRF -STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :incompatible to this version of OpenTTD -STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :unknown -STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... compression level '{RAW_STRING}' is not valid -STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... savegame format '{RAW_STRING}' is not available. Reverting to '{RAW_STRING}' -STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... ignoring Base Graphics set '{RAW_STRING}': not found -STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... ignoring Base Sounds set '{RAW_STRING}': not found -STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... ignoring Base Music set '{RAW_STRING}': not found -STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Out of memory -STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}Allocating {BYTES} of spritecache failed. The spritecache was reduced to {BYTES}. This will reduce the performance of OpenTTD. To reduce memory requirements you can try to disable 32bpp graphics and/or zoom-in levels - -# Intro window -STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} - -STR_INTRO_NEW_GAME :{BLACK}New Game -STR_INTRO_LOAD_GAME :{BLACK}Load Game -STR_INTRO_PLAY_SCENARIO :{BLACK}Play Scenario -STR_INTRO_PLAY_HEIGHTMAP :{BLACK}Play Heightmap -STR_INTRO_SCENARIO_EDITOR :{BLACK}Scenario Editor -STR_INTRO_MULTIPLAYER :{BLACK}Multiplayer - -STR_INTRO_GAME_OPTIONS :{BLACK}Game Options -STR_INTRO_HIGHSCORE :{BLACK}Highscore Table -STR_INTRO_ADVANCED_SETTINGS :{BLACK}Advanced Settings -STR_INTRO_NEWGRF_SETTINGS :{BLACK}NewGRF Settings -STR_INTRO_ONLINE_CONTENT :{BLACK}Check Online Content -STR_INTRO_SCRIPT_SETTINGS :{BLACK}AI/Game Script Settings -STR_INTRO_QUIT :{BLACK}Exit - -STR_INTRO_TOOLTIP_NEW_GAME :{BLACK}Start a new game. Ctrl+Click skips map configuration -STR_INTRO_TOOLTIP_LOAD_GAME :{BLACK}Load a saved game -STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP :{BLACK}Start a new game, using a heightmap as landscape -STR_INTRO_TOOLTIP_PLAY_SCENARIO :{BLACK}Start a new game, using a customised scenario -STR_INTRO_TOOLTIP_SCENARIO_EDITOR :{BLACK}Create a customised game world/scenario -STR_INTRO_TOOLTIP_MULTIPLAYER :{BLACK}Start a multiplayer game - -STR_INTRO_TOOLTIP_TEMPERATE :{BLACK}Select 'temperate' landscape style -STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE :{BLACK}Select 'sub-arctic' landscape style -STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE :{BLACK}Select 'sub-tropical' landscape style -STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Select 'toyland' landscape style - -STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Display game options -STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Display highscore table -STR_INTRO_TOOLTIP_ADVANCED_SETTINGS :{BLACK}Display advanced settings -STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Display NewGRF settings -STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Check for new and updated content to download -STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}Display AI/Game script settings -STR_INTRO_TOOLTIP_QUIT :{BLACK}Exit 'OpenTTD' - -STR_INTRO_TRANSLATION :{BLACK}This translation misses {NUM} string{P "" s}. Please help make OpenTTD better by signing up as translator. See readme.txt for details. - -# Quit window -STR_QUIT_CAPTION :{WHITE}Exit -STR_QUIT_ARE_YOU_SURE_YOU_WANT_TO_EXIT_OPENTTD :{YELLOW}Are you sure you want to exit OpenTTD and return to {STRING}? -STR_QUIT_YES :{BLACK}Yes -STR_QUIT_NO :{BLACK}No - -# Supported OSes -STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS -STR_OSNAME_UNIX :Unix -STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS -STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS -STR_OSNAME_OS2 :OS/2 -STR_OSNAME_SUNOS :SunOS - -# Abandon game -STR_ABANDON_GAME_CAPTION :{WHITE}Abandon Game -STR_ABANDON_GAME_QUERY :{YELLOW}Are you sure you want to abandon this game? -STR_ABANDON_SCENARIO_QUERY :{YELLOW}Are you sure you want to abandon this scenario? - -# Cheat window -STR_CHEATS :{WHITE}Cheats -STR_CHEATS_TOOLTIP :{BLACK}Checkboxes indicate if you have used this cheat before -STR_CHEATS_WARNING :{BLACK}Warning! You are about to betray your fellow competitors. Keep in mind that such a disgrace will be remembered for eternity -STR_CHEAT_MONEY :{LTBLUE}Increase money by {CURRENCY_LONG} -STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Playing as company: {ORANGE}{COMMA} -STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Magic bulldozer (remove industries, unmovable objects): {ORANGE}{STRING1} -STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}Tunnels may cross each other: {ORANGE}{STRING1} -STR_CHEAT_NO_JETCRASH :{LTBLUE}Jetplanes will not crash (frequently) on small airports: {ORANGE}{STRING} -STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE :Temperate landscape -STR_CHEAT_SWITCH_CLIMATE_SUB_ARCTIC_LANDSCAPE :Sub-arctic landscape -STR_CHEAT_SWITCH_CLIMATE_SUB_TROPICAL_LANDSCAPE :Sub-tropical landscape -STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE :Toyland landscape -STR_CHEAT_CHANGE_DATE :{LTBLUE}Change date: {ORANGE}{DATE_SHORT} -STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Change current year -STR_CHEAT_SETUP_PROD :{LTBLUE}Enable modifying production values: {ORANGE}{STRING1} - -# Livery window -STR_LIVERY_CAPTION :{WHITE}New Colour Scheme - -STR_LIVERY_GENERAL_TOOLTIP :{BLACK}Show general colour schemes -STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Show train colour schemes -STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Show road vehicle colour schemes -STR_LIVERY_SHIP_TOOLTIP :{BLACK}Show ship colour schemes -STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Show aircraft colour schemes -STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Choose the primary colour for the selected scheme. Ctrl+Click will set this colour for every scheme -STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Choose the secondary colour for the selected scheme. Ctrl+Click will set this colour for every scheme -STR_LIVERY_PANEL_TOOLTIP :{BLACK}Select a colour scheme to change, or multiple schemes with Ctrl+Click. Click on the box to toggle use of the scheme - -STR_LIVERY_DEFAULT :Standard Livery -STR_LIVERY_STEAM :Steam Engine -STR_LIVERY_DIESEL :Diesel Engine -STR_LIVERY_ELECTRIC :Electric Engine -STR_LIVERY_MONORAIL :Monorail Engine -STR_LIVERY_MAGLEV :Maglev Engine -STR_LIVERY_DMU :DMU -STR_LIVERY_EMU :EMU -STR_LIVERY_PASSENGER_WAGON_STEAM :Passenger Coach (Steam) -STR_LIVERY_PASSENGER_WAGON_DIESEL :Passenger Coach (Diesel) -STR_LIVERY_PASSENGER_WAGON_ELECTRIC :Passenger Coach (Electric) -STR_LIVERY_PASSENGER_WAGON_MONORAIL :Passenger Coach (Monorail) -STR_LIVERY_PASSENGER_WAGON_MAGLEV :Passenger Coach (Maglev) -STR_LIVERY_FREIGHT_WAGON :Freight Wagon -STR_LIVERY_BUS :Bus -STR_LIVERY_TRUCK :Lorry -STR_LIVERY_PASSENGER_SHIP :Passenger Ferry -STR_LIVERY_FREIGHT_SHIP :Freight Ship -STR_LIVERY_HELICOPTER :Helicopter -STR_LIVERY_SMALL_PLANE :Small Aeroplane -STR_LIVERY_LARGE_PLANE :Large Aeroplane -STR_LIVERY_PASSENGER_TRAM :Passenger Tram -STR_LIVERY_FREIGHT_TRAM :Freight Tram - -# Face selection window -STR_FACE_CAPTION :{WHITE}Face Selection -STR_FACE_CANCEL_TOOLTIP :{BLACK}Cancel new face selection -STR_FACE_OK_TOOLTIP :{BLACK}Accept new face selection - -STR_FACE_MALE_BUTTON :{BLACK}Male -STR_FACE_MALE_TOOLTIP :{BLACK}Select male faces -STR_FACE_FEMALE_BUTTON :{BLACK}Female -STR_FACE_FEMALE_TOOLTIP :{BLACK}Select female faces -STR_FACE_NEW_FACE_BUTTON :{BLACK}New Face -STR_FACE_NEW_FACE_TOOLTIP :{BLACK}Generate random new face -STR_FACE_ADVANCED :{BLACK}Advanced -STR_FACE_ADVANCED_TOOLTIP :{BLACK}Advanced face selection -STR_FACE_SIMPLE :{BLACK}Simple -STR_FACE_SIMPLE_TOOLTIP :{BLACK}Simple face selection -STR_FACE_LOAD :{BLACK}Load -STR_FACE_LOAD_TOOLTIP :{BLACK}Load favourite face -STR_FACE_LOAD_DONE :{WHITE}Your favourite face has been loaded from the OpenTTD configuration file -STR_FACE_FACECODE :{BLACK}Player face no. -STR_FACE_FACECODE_TOOLTIP :{BLACK}View and/or set face number of the company president -STR_FACE_FACECODE_CAPTION :{WHITE}View and/or set president face number -STR_FACE_FACECODE_SET :{WHITE}New face number code has been set -STR_FACE_FACECODE_ERR :{WHITE}Couldn't set president face number - must be a number between 0 and 4,294,967,295! -STR_FACE_SAVE :{BLACK}Save -STR_FACE_SAVE_TOOLTIP :{BLACK}Save favourite face -STR_FACE_SAVE_DONE :{WHITE}This face will be saved as your favourite in the OpenTTD configuration file -STR_FACE_EUROPEAN :{BLACK}European -STR_FACE_SELECT_EUROPEAN :{BLACK}Select European faces -STR_FACE_AFRICAN :{BLACK}African -STR_FACE_SELECT_AFRICAN :{BLACK}Select African faces -STR_FACE_YES :Yes -STR_FACE_NO :No -STR_FACE_MOUSTACHE_EARRING_TOOLTIP :{BLACK}Enable moustache or earring -STR_FACE_HAIR :Hair: -STR_FACE_HAIR_TOOLTIP :{BLACK}Change hair -STR_FACE_EYEBROWS :Eyebrows: -STR_FACE_EYEBROWS_TOOLTIP :{BLACK}Change eyebrows -STR_FACE_EYECOLOUR :Eye colour: -STR_FACE_EYECOLOUR_TOOLTIP :{BLACK}Change eye colour -STR_FACE_GLASSES :Glasses: -STR_FACE_GLASSES_TOOLTIP :{BLACK}Enable glasses -STR_FACE_GLASSES_TOOLTIP_2 :{BLACK}Change glasses -STR_FACE_NOSE :Nose: -STR_FACE_NOSE_TOOLTIP :{BLACK}Change nose -STR_FACE_LIPS :Lips: -STR_FACE_MOUSTACHE :Moustache: -STR_FACE_LIPS_MOUSTACHE_TOOLTIP :{BLACK}Change lips or moustache -STR_FACE_CHIN :Chin: -STR_FACE_CHIN_TOOLTIP :{BLACK}Change chin -STR_FACE_JACKET :Jacket: -STR_FACE_JACKET_TOOLTIP :{BLACK}Change jacket -STR_FACE_COLLAR :Collar: -STR_FACE_COLLAR_TOOLTIP :{BLACK}Change collar -STR_FACE_TIE :Tie: -STR_FACE_EARRING :Earring: -STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Change tie or earring - -# Network server list -STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer -STR_NETWORK_SERVER_LIST_ADVERTISED :{BLACK}Advertised -STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP :{BLACK}Choose between an advertised (internet) and a not advertised (Local Area Network, LAN) game -STR_NETWORK_SERVER_LIST_ADVERTISED_NO :No -STR_NETWORK_SERVER_LIST_ADVERTISED_YES :Yes -STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Player name: -STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP :{BLACK}This is the name other players will identify you by - -STR_NETWORK_SERVER_LIST_GAME_NAME :{BLACK}Name -STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP :{BLACK}Name of the game -STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} -STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION :{BLACK}Clients -STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP :{BLACK}Clients online / clients max{}Companies online / companies max -STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x{COMMA} -STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION :{BLACK}Map size -STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP :{BLACK}Map size of the game{}Click to sort by area -STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}Date -STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}Current date -STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}Years -STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}Number of years{}the game is running -STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Language, server version, etc. - -STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}Click a game from the list to select it -STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER :{BLACK}The server you joined last time: -STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST :{BLACK}Click to select the server you played last time - -STR_NETWORK_SERVER_LIST_GAME_INFO :{SILVER}GAME INFO -STR_NETWORK_SERVER_LIST_CLIENTS :{SILVER}Clients: {WHITE}{COMMA} / {COMMA} - {COMMA} / {COMMA} -STR_NETWORK_SERVER_LIST_LANGUAGE :{SILVER}Language: {WHITE}{STRING} -STR_NETWORK_SERVER_LIST_LANDSCAPE :{SILVER}Landscape: {WHITE}{STRING} -STR_NETWORK_SERVER_LIST_MAP_SIZE :{SILVER}Map size: {WHITE}{COMMA}x{COMMA} -STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}Server version: {WHITE}{RAW_STRING} -STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Server address: {WHITE}{RAW_STRING} -STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Start date: {WHITE}{DATE_SHORT} -STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Current date: {WHITE}{DATE_SHORT} -STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Password protected! -STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}SERVER OFFLINE -STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}SERVER FULL -STR_NETWORK_SERVER_LIST_VERSION_MISMATCH :{SILVER}VERSION MISMATCH -STR_NETWORK_SERVER_LIST_GRF_MISMATCH :{SILVER}NEWGRF MISMATCH - -STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Join game -STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Refresh server -STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Refresh the server info - -STR_NETWORK_SERVER_LIST_FIND_SERVER :{BLACK}Find server -STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP :{BLACK}Search network for a server -STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Add server -STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Adds a server to the list which will always be checked for running games -STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Start server -STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}Start your own server - -STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Enter your name -STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Enter the address of the host - -# Start new multiplayer server -STR_NETWORK_START_SERVER_CAPTION :{WHITE}Start new multiplayer game - -STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}Game name: -STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}The game name will be displayed to other players in the multiplayer game selection menu -STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Set password -STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protect your game with a password if you don't want it to be publicly accessible - -STR_NETWORK_START_SERVER_UNADVERTISED :No -STR_NETWORK_START_SERVER_ADVERTISED :Yes -STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} client{P "" s} -STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Max clients: -STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Choose the maximum number of clients. Not all slots need to be filled -STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} compan{P y ies} -STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Max companies: -STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}Limit the server to a certain amount of companies -STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} spectator{P "" s} -STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Max spectators: -STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}Limit the server to a certain amount of spectators -STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Language spoken: -STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Other players will know which language is spoken on the server - -STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Enter a name for the network game - -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Any -STR_NETWORK_LANG_ENGLISH :English -STR_NETWORK_LANG_GERMAN :German -STR_NETWORK_LANG_FRENCH :French -STR_NETWORK_LANG_BRAZILIAN :Brazilian -STR_NETWORK_LANG_BULGARIAN :Bulgarian -STR_NETWORK_LANG_CHINESE :Chinese -STR_NETWORK_LANG_CZECH :Czech -STR_NETWORK_LANG_DANISH :Danish -STR_NETWORK_LANG_DUTCH :Dutch -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finnish -STR_NETWORK_LANG_HUNGARIAN :Hungarian -STR_NETWORK_LANG_ICELANDIC :Icelandic -STR_NETWORK_LANG_ITALIAN :Italian -STR_NETWORK_LANG_JAPANESE :Japanese -STR_NETWORK_LANG_KOREAN :Korean -STR_NETWORK_LANG_LITHUANIAN :Lithuanian -STR_NETWORK_LANG_NORWEGIAN :Norwegian -STR_NETWORK_LANG_POLISH :Polish -STR_NETWORK_LANG_PORTUGUESE :Portuguese -STR_NETWORK_LANG_ROMANIAN :Romanian -STR_NETWORK_LANG_RUSSIAN :Russian -STR_NETWORK_LANG_SLOVAK :Slovak -STR_NETWORK_LANG_SLOVENIAN :Slovenian -STR_NETWORK_LANG_SPANISH :Spanish -STR_NETWORK_LANG_SWEDISH :Swedish -STR_NETWORK_LANG_TURKISH :Turkish -STR_NETWORK_LANG_UKRAINIAN :Ukrainian -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Croatian -STR_NETWORK_LANG_CATALAN :Catalan -STR_NETWORK_LANG_ESTONIAN :Estonian -STR_NETWORK_LANG_GALICIAN :Galician -STR_NETWORK_LANG_GREEK :Greek -STR_NETWORK_LANG_LATVIAN :Latvian -############ End of leave-in-this-order - -# Network game lobby -STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Multiplayer game lobby - -STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}Preparing to join: {ORANGE}{RAW_STRING} -STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}A list of all companies currently in this game. You can either join one or start a new one if there is a free company slot - -STR_NETWORK_GAME_LOBBY_COMPANY_INFO :{SILVER}COMPANY INFO -STR_NETWORK_GAME_LOBBY_COMPANY_NAME :{SILVER}Company name: {WHITE}{RAW_STRING} -STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR :{SILVER}Inauguration: {WHITE}{NUM} -STR_NETWORK_GAME_LOBBY_VALUE :{SILVER}Company value: {WHITE}{CURRENCY_LONG} -STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE :{SILVER}Current balance: {WHITE}{CURRENCY_LONG} -STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME :{SILVER}Last year's income: {WHITE}{CURRENCY_LONG} -STR_NETWORK_GAME_LOBBY_PERFORMANCE :{SILVER}Performance: {WHITE}{NUM} - -STR_NETWORK_GAME_LOBBY_VEHICLES :{SILVER}Vehicles: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} -STR_NETWORK_GAME_LOBBY_STATIONS :{SILVER}Stations: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} -STR_NETWORK_GAME_LOBBY_PLAYERS :{SILVER}Players: {WHITE}{RAW_STRING} - -STR_NETWORK_GAME_LOBBY_NEW_COMPANY :{BLACK}New company -STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP :{BLACK}Create a new company -STR_NETWORK_GAME_LOBBY_SPECTATE_GAME :{BLACK}Spectate game -STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP :{BLACK}Watch the game as a spectator -STR_NETWORK_GAME_LOBBY_JOIN_COMPANY :{BLACK}Join company -STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP :{BLACK}Help manage this company - -# Network connecting window -STR_NETWORK_CONNECTING_CAPTION :{WHITE}Connecting... - -############ Leave those lines in this order!! -STR_NETWORK_CONNECTING_1 :{BLACK}(1/6) Connecting... -STR_NETWORK_CONNECTING_2 :{BLACK}(2/6) Authorising... -STR_NETWORK_CONNECTING_3 :{BLACK}(3/6) Waiting... -STR_NETWORK_CONNECTING_4 :{BLACK}(4/6) Downloading map... -STR_NETWORK_CONNECTING_5 :{BLACK}(5/6) Processing data... -STR_NETWORK_CONNECTING_6 :{BLACK}(6/6) Registering... - -STR_NETWORK_CONNECTING_SPECIAL_1 :{BLACK}Fetching game info... -STR_NETWORK_CONNECTING_SPECIAL_2 :{BLACK}Fetching company info... -############ End of leave-in-this-order -STR_NETWORK_CONNECTING_WAITING :{BLACK}{NUM} client{P "" s} in front of you -STR_NETWORK_CONNECTING_DOWNLOADING_1 :{BLACK}{BYTES} downloaded so far -STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} / {BYTES} downloaded so far - -STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Disconnect - -STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server is protected. Enter password -STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Company is protected. Enter password - -# Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}Client list -STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}Spectate -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}New company - -# Network client list -STR_NETWORK_CLIENTLIST_KICK :Kick -STR_NETWORK_CLIENTLIST_BAN :Ban -STR_NETWORK_CLIENTLIST_GIVE_MONEY :Give money -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Speak to all -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Speak to company -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Private message - -STR_NETWORK_SERVER :Server -STR_NETWORK_CLIENT :Client -STR_NETWORK_SPECTATORS :Spectators - -STR_NETWORK_GIVE_MONEY_CAPTION :{WHITE}Enter the amount of money you want to give -STR_NETWORK_TOOLBAR_LIST_SPECTATOR :{BLACK}Spectator - -# Network set password -STR_COMPANY_PASSWORD_CANCEL :{BLACK}Do not save the entered password -STR_COMPANY_PASSWORD_OK :{BLACK}Give the company the new password -STR_COMPANY_PASSWORD_CAPTION :{WHITE}Company password -STR_COMPANY_PASSWORD_MAKE_DEFAULT :{BLACK}Default company password -STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}Use this company password as default for new companies - -# Network company info join/password -STR_COMPANY_VIEW_JOIN :{BLACK}Join -STR_COMPANY_VIEW_JOIN_TOOLTIP :{BLACK}Join and play as this company -STR_COMPANY_VIEW_PASSWORD :{BLACK}Password -STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}Password-protect your company to prevent unauthorised users from joining -STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}Set company password - -# Network chat -STR_NETWORK_CHAT_SEND :{BLACK}Send -STR_NETWORK_CHAT_COMPANY_CAPTION :[Team] : -STR_NETWORK_CHAT_CLIENT_CAPTION :[Private] {RAW_STRING}: -STR_NETWORK_CHAT_ALL_CAPTION :[All] : - -STR_NETWORK_CHAT_COMPANY :[Team] {RAW_STRING}: {WHITE}{RAW_STRING} -STR_NETWORK_CHAT_TO_COMPANY :[Team] To {RAW_STRING}: {WHITE}{RAW_STRING} -STR_NETWORK_CHAT_CLIENT :[Private] {RAW_STRING}: {WHITE}{RAW_STRING} -STR_NETWORK_CHAT_TO_CLIENT :[Private] To {RAW_STRING}: {WHITE}{RAW_STRING} -STR_NETWORK_CHAT_ALL :[All] {RAW_STRING}: {WHITE}{RAW_STRING} -STR_NETWORK_CHAT_OSKTITLE :{BLACK}Enter text for network chat - -# Network messages -STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}No network devices found or compiled without ENABLE_NETWORK -STR_NETWORK_ERROR_NOSERVER :{WHITE}Could not find any network games -STR_NETWORK_ERROR_NOCONNECTION :{WHITE}The server didn't answer the request -STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Could not connect due to NewGRF mismatch -STR_NETWORK_ERROR_DESYNC :{WHITE}Network-Game synchronisation failed -STR_NETWORK_ERROR_LOSTCONNECTION :{WHITE}Network-Game connection lost -STR_NETWORK_ERROR_SAVEGAMEERROR :{WHITE}Could not load savegame -STR_NETWORK_ERROR_SERVER_START :{WHITE}Could not start the server -STR_NETWORK_ERROR_CLIENT_START :{WHITE}Could not connect -STR_NETWORK_ERROR_TIMEOUT :{WHITE}Connection #{NUM} timed out -STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}A protocol error was detected and the connection was closed -STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}The revision of this client does not match the server's revision -STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Wrong password -STR_NETWORK_ERROR_SERVER_FULL :{WHITE}The server is full -STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}You are banned from this server -STR_NETWORK_ERROR_KICKED :{WHITE}You were kicked out of the game -STR_NETWORK_ERROR_CHEATER :{WHITE}Cheating is not allowed on this server -STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}You were sending too many commands to the server -STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}You took too long to enter the password -STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Your computer is too slow to keep up with the server -STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Your computer took too long to download the map -STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Your computer took too long to join the server - -############ Leave those lines in this order!! -STR_NETWORK_ERROR_CLIENT_GENERAL :general error -STR_NETWORK_ERROR_CLIENT_DESYNC :desync error -STR_NETWORK_ERROR_CLIENT_SAVEGAME :could not load map -STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST :connection lost -STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR :protocol error -STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH :NewGRF mismatch -STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED :not authorized -STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED :received invalid or unexpected packet -STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :wrong revision -STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :name already in use -STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :wrong password -STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :wrong company in DoCommand -STR_NETWORK_ERROR_CLIENT_KICKED :kicked by server -STR_NETWORK_ERROR_CLIENT_CHEATER :was trying to use a cheat -STR_NETWORK_ERROR_CLIENT_SERVER_FULL :server full -STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS :was sending too many commands -STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :received no password in time -STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :general timeout -STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :downloading map took too long -STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :processing map took too long -############ End of leave-in-this-order - -STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible connection loss -STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}The last {NUM} second{P "" s} no data has arrived from the server - -# Network related errors -STR_NETWORK_SERVER_MESSAGE :*** {1:RAW_STRING} -############ Leave those lines in this order!! -STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED :Game paused ({STRING}) -STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Game still paused ({STRING}) -STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Game still paused ({STRING}, {STRING}) -STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Game still paused ({STRING}, {STRING}, {STRING}) -STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Game still paused ({STRING}, {STRING}, {STRING}, {STRING}) -STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Game unpaused ({STRING}) -STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :number of players -STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :connecting clients -STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :manual -STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :game script -############ End of leave-in-this-order -STR_NETWORK_MESSAGE_CLIENT_LEAVING :leaving -STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {RAW_STRING} has joined the game -STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {RAW_STRING} has joined the game (Client #{2:NUM}) -STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {RAW_STRING} has joined company #{2:NUM} -STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {RAW_STRING} has joined spectators -STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {RAW_STRING} has started a new company (#{2:NUM}) -STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {RAW_STRING} has left the game ({2:STRING}) -STR_NETWORK_MESSAGE_NAME_CHANGE :*** {RAW_STRING} has changed his/her name to {RAW_STRING} -STR_NETWORK_MESSAGE_GIVE_MONEY :*** {RAW_STRING} gave your company {2:CURRENCY_LONG} -STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** You gave {1:RAW_STRING} {2:CURRENCY_LONG} -STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}The server closed the session -STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}The server is restarting...{}Please wait... - -# Content downloading window -STR_CONTENT_TITLE :{WHITE}Content downloading -STR_CONTENT_TYPE_CAPTION :{BLACK}Type -STR_CONTENT_TYPE_CAPTION_TOOLTIP :{BLACK}Type of the content -STR_CONTENT_NAME_CAPTION :{BLACK}Name -STR_CONTENT_NAME_CAPTION_TOOLTIP :{BLACK}Name of the content -STR_CONTENT_MATRIX_TOOLTIP :{BLACK}Click on a line to see the details{}Click on the checkbox to select it for downloading -STR_CONTENT_SELECT_ALL_CAPTION :{BLACK}Select all -STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP :{BLACK}Mark all content to be downloaded -STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}Select upgrades -STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP :{BLACK}Mark all content that is an upgrade for existing content to be downloaded -STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}Unselect all -STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP :{BLACK}Mark all content to be not downloaded -STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Search external websites -STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}Search content not available on OpenTTD's content service on websites not associated to OpenTTD -STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}You are leaving OpenTTD! -STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}The terms and conditions for downloading content from external websites vary.{}You will have to refer to the external sites for instructions how to install the content into OpenTTD.{}Do you want to continue? -STR_CONTENT_FILTER_TITLE :{BLACK}Tag/name filter: -STR_CONTENT_OPEN_URL :{BLACK}Visit website -STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Visit the website for this content -STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Download -STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}Start downloading the selected content -STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}Total download size: {WHITE}{BYTES} -STR_CONTENT_DETAIL_TITLE :{SILVER}CONTENT INFO -STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}You have not selected this to be downloaded -STR_CONTENT_DETAIL_SUBTITLE_SELECTED :{SILVER}You have selected this to be downloaded -STR_CONTENT_DETAIL_SUBTITLE_AUTOSELECTED :{SILVER}This dependency has been selected to be downloaded -STR_CONTENT_DETAIL_SUBTITLE_ALREADY_HERE :{SILVER}You already have this -STR_CONTENT_DETAIL_SUBTITLE_DOES_NOT_EXIST :{SILVER}This content is unknown and can't be downloaded in OpenTTD -STR_CONTENT_DETAIL_UPDATE :{SILVER}This is a replacement for an existing {STRING} -STR_CONTENT_DETAIL_NAME :{SILVER}Name: {WHITE}{RAW_STRING} -STR_CONTENT_DETAIL_VERSION :{SILVER}Version: {WHITE}{RAW_STRING} -STR_CONTENT_DETAIL_DESCRIPTION :{SILVER}Description: {WHITE}{RAW_STRING} -STR_CONTENT_DETAIL_URL :{SILVER}URL: {WHITE}{RAW_STRING} -STR_CONTENT_DETAIL_TYPE :{SILVER}Type: {WHITE}{STRING} -STR_CONTENT_DETAIL_FILESIZE :{SILVER}Download size: {WHITE}{BYTES} -STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF :{SILVER}Selected because of: {WHITE}{RAW_STRING} -STR_CONTENT_DETAIL_DEPENDENCIES :{SILVER}Dependencies: {WHITE}{RAW_STRING} -STR_CONTENT_DETAIL_TAGS :{SILVER}Tags: {WHITE}{RAW_STRING} -STR_CONTENT_NO_ZLIB :{WHITE}OpenTTD is built without "zlib" support... -STR_CONTENT_NO_ZLIB_SUB :{WHITE}... downloading content is not possible! - -# Order of these is important! -STR_CONTENT_TYPE_BASE_GRAPHICS :Base graphics -STR_CONTENT_TYPE_NEWGRF :NewGRF -STR_CONTENT_TYPE_AI :AI -STR_CONTENT_TYPE_AI_LIBRARY :AI library -STR_CONTENT_TYPE_SCENARIO :Scenario -STR_CONTENT_TYPE_HEIGHTMAP :Heightmap -STR_CONTENT_TYPE_BASE_SOUNDS :Base sounds -STR_CONTENT_TYPE_BASE_MUSIC :Base music -STR_CONTENT_TYPE_GAME_SCRIPT :Game script -STR_CONTENT_TYPE_GS_LIBRARY :GS library - -# Content downloading progress window -STR_CONTENT_DOWNLOAD_TITLE :{WHITE}Downloading content... -STR_CONTENT_DOWNLOAD_INITIALISE :{WHITE}Requesting files... -STR_CONTENT_DOWNLOAD_FILE :{WHITE}Currently downloading {RAW_STRING} ({NUM} of {NUM}) -STR_CONTENT_DOWNLOAD_COMPLETE :{WHITE}Download complete -STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} of {BYTES} downloaded ({NUM} %) - -# Content downloading error messages -STR_CONTENT_ERROR_COULD_NOT_CONNECT :{WHITE}Could not connect to the content server... -STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}Downloading failed... -STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_CONNECTION_LOST :{WHITE}... connection lost -STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... file not writable -STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}Could not decompress the downloaded file - -STR_MISSING_GRAPHICS_SET_CAPTION :{WHITE}Missing graphics -STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}OpenTTD requires graphics to function but none could be found. Do you allow OpenTTD to download and install these graphics? -STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}Yes, download the graphics -STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}No, exit OpenTTD - -# Transparency settings window -STR_TRANSPARENCY_CAPTION :{WHITE}Transparency Options -STR_TRANSPARENT_SIGNS_TOOLTIP :{BLACK}Toggle transparency for signs. Ctrl+Click to lock -STR_TRANSPARENT_TREES_TOOLTIP :{BLACK}Toggle transparency for trees. Ctrl+Click to lock -STR_TRANSPARENT_HOUSES_TOOLTIP :{BLACK}Toggle transparency for houses. Ctrl+Click to lock -STR_TRANSPARENT_INDUSTRIES_TOOLTIP :{BLACK}Toggle transparency for industries. Ctrl+Click to lock -STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Toggle transparency for buildables like stations, depots and waypoints. Ctrl+Click to lock -STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Toggle transparency for bridges. Ctrl+Click to lock -STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Toggle transparency for structures like lighthouses and antennas. Ctrl+Click to lock -STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Toggle transparency for catenary. Ctrl+Click to lock -STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Toggle transparency for loading indicators. Ctrl+Click to lock -STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Set objects invisible instead of transparent - -# Linkgraph legend window -STR_LINKGRAPH_LEGEND_CAPTION :{BLACK}Cargo Flow Legend -STR_LINKGRAPH_LEGEND_ALL :{BLACK}All -STR_LINKGRAPH_LEGEND_NONE :{BLACK}None -STR_LINKGRAPH_LEGEND_SELECT_COMPANIES :{BLACK}Select companies to be displayed - -# Linkgraph legend window and linkgraph legend in smallmap -STR_LINKGRAPH_LEGEND_UNUSED :{TINY_FONT}{BLACK}unused -STR_LINKGRAPH_LEGEND_SATURATED :{TINY_FONT}{BLACK}saturated -STR_LINKGRAPH_LEGEND_OVERLOADED :{TINY_FONT}{BLACK}overloaded - -# Base for station construction window(s) -STR_STATION_BUILD_COVERAGE_AREA_TITLE :{BLACK}Coverage area highlight -STR_STATION_BUILD_COVERAGE_OFF :{BLACK}Off -STR_STATION_BUILD_COVERAGE_ON :{BLACK}On -STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP :{BLACK}Don't highlight coverage area of proposed site -STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP :{BLACK}Highlight coverage area of proposed site -STR_STATION_BUILD_ACCEPTS_CARGO :{BLACK}Accepts: {GOLD}{CARGO_LIST} -STR_STATION_BUILD_SUPPLIES_CARGO :{BLACK}Supplies: {GOLD}{CARGO_LIST} - -# Join station window -STR_JOIN_STATION_CAPTION :{WHITE}Join station -STR_JOIN_STATION_CREATE_SPLITTED_STATION :{YELLOW}Build a separate station - -STR_JOIN_WAYPOINT_CAPTION :{WHITE}Join waypoint -STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT :{YELLOW}Build a separate waypoint - -# Rail construction toolbar -STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION :Railway Construction -STR_RAIL_TOOLBAR_ELRAIL_CONSTRUCTION_CAPTION :Electrified Railway Construction -STR_RAIL_TOOLBAR_MONORAIL_CONSTRUCTION_CAPTION :Monorail Construction -STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :Maglev Construction - -STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Build railway track. Ctrl toggles build/remove for railway construction. Shift toggles building/showing cost estimate -STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}Build railway track using the Autorail mode. Ctrl toggles build/remove for railway construction. Shift toggles building/showing cost estimate -STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Build train depot (for buying and servicing trains). Shift toggles building/showing cost estimate -STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Convert rail to waypoint. Ctrl enables joining waypoints. Shift toggles building/showing cost estimate -STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}Build railway station. Ctrl enables joining stations. Shift toggles building/showing cost estimate -STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Build railway signals. Ctrl toggles semaphore/light signals{}Dragging builds signals along a straight stretch of rail. Ctrl builds signals till the next junction{}Ctrl+Click toggles opening the signal selection window. Shift toggles building/showing cost estimate -STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}Build railway bridge. Shift toggles building/showing cost estimate -STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}Build railway tunnel. Shift toggles building/showing cost estimate -STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Toggle build/remove for railway track, signals, waypoints and stations. Hold Ctrl to also remove the rail of waypoints and stations -STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL :{BLACK}Convert/Upgrade the type of rail. Shift toggles building/showing cost estimate - -STR_RAIL_NAME_RAILROAD :Railway -STR_RAIL_NAME_ELRAIL :Electrified railway -STR_RAIL_NAME_MONORAIL :Monorail -STR_RAIL_NAME_MAGLEV :Maglev - -# Rail depot construction window -STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION :{WHITE}Train Depot Orientation -STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP :{BLACK}Select railway depot orientation - -# Rail waypoint construction window -STR_WAYPOINT_CAPTION :{WHITE}Waypoint -STR_WAYPOINT_GRAPHICS_TOOLTIP :{BLACK}Select waypoint type - -# Rail station construction window -STR_STATION_BUILD_RAIL_CAPTION :{WHITE}Rail Station Selection -STR_STATION_BUILD_ORIENTATION :{BLACK}Orientation -STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP :{BLACK}Select railway station orientation -STR_STATION_BUILD_NUMBER_OF_TRACKS :{BLACK}Number of tracks -STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP :{BLACK}Select number of platforms for railway station -STR_STATION_BUILD_PLATFORM_LENGTH :{BLACK}Platform length -STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP :{BLACK}Select length of railway station -STR_STATION_BUILD_DRAG_DROP :{BLACK}Drag & Drop -STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Build a station using drag & drop - -STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Select a station class to display -STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Select the station type to build - -STR_STATION_CLASS_DFLT :Default station -STR_STATION_CLASS_WAYP :Waypoints - -# Signal window -STR_BUILD_SIGNAL_CAPTION :{WHITE}Signal Selection -STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP :{BLACK}Block Signal (semaphore){}This is the most basic type of signal, allowing only one train to be in the same block at the same time -STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP :{BLACK}Entry Signal (semaphore){}Green as long as there is one or more green exit-signal from the following section of track. Otherwise it shows red -STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP :{BLACK}Exit Signal (semaphore){}Behaves in the same way as a block signal but is necessary to trigger the correct colour on entry & combo pre-signals -STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP :{BLACK}Combo Signal (semaphore){}The combo signal simply acts as both an entry and exit signal. This allows you to build large "trees" of pre-signals -STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP :{BLACK}Path Signal (semaphore){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. Standard path signals can be passed from the back side -STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP :{BLACK}One-way Path Signal (semaphore){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. One-way path signals can't be passed from the back side -STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP :{BLACK}Block Signal (electric){}This is the most basic type of signal, allowing only one train to be in the same block at the same time -STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP :{BLACK}Entry Signal (electric){}Green as long as there is one or more green exit-signal from the following section of track. Otherwise it shows red -STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP :{BLACK}Exit Signal (electric){}Behaves in the same way as a block signal but is necessary to trigger the correct colour on entry & combo pre-signals -STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Combo Signal (electric){}The combo signal simply acts as both an entry and exit signal. This allows you to build large "trees" of pre-signals -STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}Path Signal (electric){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. Standard path signals can be passed from the back side -STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}One-way Path Signal (electric){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. One-way path signals can't be passed from the back side -STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Signal Convert{}When selected, clicking an existing signal will convert it to the selected signal type and variant. Ctrl+Click will toggle the existing variant. Shift+Click shows estimated conversion cost -STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Dragging signal density -STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Decrease dragging signal density -STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Increase dragging signal density - -# Bridge selection window -STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Select Rail Bridge -STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Select Road Bridge -STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Bridge selection - click on your preferred bridge to build it -STR_SELECT_BRIDGE_INFO :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} -STR_SELECT_BRIDGE_SCENEDIT_INFO :{GOLD}{STRING},{} {VELOCITY} -STR_BRIDGE_NAME_SUSPENSION_STEEL :Suspension, Steel -STR_BRIDGE_NAME_GIRDER_STEEL :Girder, Steel -STR_BRIDGE_NAME_CANTILEVER_STEEL :Cantilever, Steel -STR_BRIDGE_NAME_SUSPENSION_CONCRETE :Suspension, Concrete -STR_BRIDGE_NAME_WOODEN :Wooden -STR_BRIDGE_NAME_CONCRETE :Concrete -STR_BRIDGE_NAME_TUBULAR_STEEL :Tubular, Steel -STR_BRIDGE_TUBULAR_SILICON :Tubular, Silicon - - -# Road construction toolbar -STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION :{WHITE}Road Construction -STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}Tramway Construction -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}Build road section. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}Build tramway section. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}Build road section using the Autoroad mode. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Build tramway section using the Autotram mode. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Build road vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Build tram vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}Build bus station. Ctrl enables joining stations. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}Build passenger tram station. Ctrl enables joining stations. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}Build lorry loading bay. Ctrl enables joining stations. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION :{BLACK}Build freight tram station. Ctrl enables joining stations. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD :{BLACK}Activate/Deactivate one way roads -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE :{BLACK}Build road bridge. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE :{BLACK}Build tramway bridge. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Build road tunnel. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Build tramway tunnel. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Toggle build/remove for road construction -STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Toggle build/remove for tramway construction - -# Road depot construction window -STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Road Depot Orientation -STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Select road vehicle depot orientation -STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION :{WHITE}Tram Depot Orientation -STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Select tram vehicle depot orientation - -# Road vehicle station construction window -STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}Bus Station Orientation -STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP :{BLACK}Select bus station orientation -STR_STATION_BUILD_TRUCK_ORIENTATION :{WHITE}Lorry Station Orientation -STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Select lorry loading bay orientation -STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION :{WHITE}Passenger Tram Station Orientation -STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP :{BLACK}Select passenger tram station orientation -STR_STATION_BUILD_CARGO_TRAM_ORIENTATION :{WHITE}Freight Tram Station Orientation -STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP :{BLACK}Select freight tram station orientation - -# Waterways toolbar (last two for SE only) -STR_WATERWAYS_TOOLBAR_CAPTION :{WHITE}Waterways Construction -STR_WATERWAYS_TOOLBAR_CAPTION_SE :{WHITE}Waterways -STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Build canals. Shift toggles building/showing cost estimate -STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}Build locks. Shift toggles building/showing cost estimate -STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}Build ship depot (for buying and servicing ships). Shift toggles building/showing cost estimate -STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Build ship dock. Ctrl enables joining stations. Shift toggles building/showing cost estimate -STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Place a buoy which can be used as a waypoint. Shift toggles building/showing cost estimate -STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Build aqueduct. Shift toggles building/showing cost estimate -STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Define water area.{}Make a canal, unless Ctrl is held down at sea level, when it will flood the surroundings instead -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Place rivers - -# Ship depot construction window -STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Ship Depot Orientation -STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP :{BLACK}Select ship depot orientation - -# Dock construction window -STR_STATION_BUILD_DOCK_CAPTION :{WHITE}Dock - -# Airport toolbar -STR_TOOLBAR_AIRCRAFT_CAPTION :{WHITE}Airports -STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP :{BLACK}Build airport. Ctrl enables joining stations. Shift toggles building/showing cost estimate - -# Airport construction window -STR_STATION_BUILD_AIRPORT_CAPTION :{WHITE}Airport Selection -STR_STATION_BUILD_AIRPORT_TOOLTIP :{BLACK}Select size/type of airport -STR_STATION_BUILD_AIRPORT_CLASS_LABEL :{BLACK}Airport class -STR_STATION_BUILD_AIRPORT_LAYOUT_NAME :{BLACK}Layout {NUM} - -STR_AIRPORT_SMALL :Small -STR_AIRPORT_CITY :City -STR_AIRPORT_METRO :Metropolitan -STR_AIRPORT_INTERNATIONAL :International -STR_AIRPORT_COMMUTER :Commuter -STR_AIRPORT_INTERCONTINENTAL :Intercontinental -STR_AIRPORT_HELIPORT :Heliport -STR_AIRPORT_HELIDEPOT :Helidepot -STR_AIRPORT_HELISTATION :Helistation - -STR_AIRPORT_CLASS_SMALL :Small airports -STR_AIRPORT_CLASS_LARGE :Large airports -STR_AIRPORT_CLASS_HUB :Hub airports -STR_AIRPORT_CLASS_HELIPORTS :Helicopter airports - -STR_STATION_BUILD_NOISE :{BLACK}Noise generated: {GOLD}{COMMA} - -# Landscaping toolbar -STR_LANDSCAPING_TOOLBAR :{WHITE}Landscaping -STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}Lower a corner of land. Dragging lowers the first selected corner and levels the selected area to the new corner height. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate -STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Raise a corner of land. Dragging raises the first selected corner and levels the selected area to the new corner height. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate -STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Level an area of land to the height of the first selected corner. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate -STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Purchase land for future use. Shift toggles building/showing cost estimate - -# Object construction window -STR_OBJECT_BUILD_CAPTION :{WHITE}Object Selection -STR_OBJECT_BUILD_TOOLTIP :{BLACK}Select object to build. Shift toggles building/showing cost estimate -STR_OBJECT_BUILD_CLASS_TOOLTIP :{BLACK}Select class of the object to build -STR_OBJECT_BUILD_PREVIEW_TOOLTIP :{BLACK}Preview of the object -STR_OBJECT_BUILD_SIZE :{BLACK}Size: {GOLD}{NUM} x {NUM} tiles - -STR_OBJECT_CLASS_LTHS :Lighthouses -STR_OBJECT_CLASS_TRNS :Transmitters - -# Tree planting window (last two for SE only) -STR_PLANT_TREE_CAPTION :{WHITE}Trees -STR_PLANT_TREE_TOOLTIP :{BLACK}Select tree type to plant. If the tile already has a tree, this will add more trees of mixed types independent of the selected type -STR_TREES_RANDOM_TYPE :{BLACK}Trees of random type -STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Place trees of random type. Shift toggles building/showing cost estimate -STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Random Trees -STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Plant trees randomly throughout the landscape - -# Land generation window (SE) -STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Land Generation -STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}Place rocky areas on landscape -STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA :{BLACK}Define desert area.{}Hold Ctrl to remove it -STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Increase area of land to lower/raise -STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Decrease area of land to lower/raise -STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND :{BLACK}Generate random land -STR_TERRAFORM_SE_NEW_WORLD :{BLACK}Create new scenario -STR_TERRAFORM_RESET_LANDSCAPE :{BLACK}Reset landscape -STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP :{BLACK}Remove all company-owned property from the map - -STR_QUERY_RESET_LANDSCAPE_CAPTION :{WHITE}Reset Landscape -STR_RESET_LANDSCAPE_CONFIRMATION_TEXT :{WHITE}Are you sure you want to remove all company-owned property? - -# Town generation window (SE) -STR_FOUND_TOWN_CAPTION :{WHITE}Town Generation -STR_FOUND_TOWN_NEW_TOWN_BUTTON :{BLACK}New Town -STR_FOUND_TOWN_NEW_TOWN_TOOLTIP :{BLACK}Found new town. Shift+Click shows only estimated cost -STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Random Town -STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Found town in random location -STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Many random towns -STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Cover the map with randomly placed towns - -STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Town name: -STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Enter town name -STR_FOUND_TOWN_NAME_EDITOR_HELP :{BLACK}Click to enter town name -STR_FOUND_TOWN_NAME_RANDOM_BUTTON :{BLACK}Random name -STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP :{BLACK}Generate new random name - -STR_FOUND_TOWN_INITIAL_SIZE_TITLE :{YELLOW}Town size: -STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON :{BLACK}Small -STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON :{BLACK}Medium -STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON :{BLACK}Large -STR_FOUND_TOWN_SIZE_RANDOM :{BLACK}Random -STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Select town size -STR_FOUND_TOWN_CITY :{BLACK}City -STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Cities grow faster than regular towns{}Depending on settings, they are bigger when founded - -STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Town road layout: -STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT :{BLACK}Select road layout used for this town -STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL :{BLACK}Original -STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS :{BLACK}Better roads -STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID :{BLACK}2x2 grid -STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID :{BLACK}3x3 grid -STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM :{BLACK}Random - -# Fund new industry window -STR_FUND_INDUSTRY_CAPTION :{WHITE}Fund new industry -STR_FUND_INDUSTRY_SELECTION_TOOLTIP :{BLACK}Choose the appropriate industry from this list -STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :Many random industries -STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}Cover the map with randomly placed industries -STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}Cost: {YELLOW}{CURRENCY_LONG} -STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Prospect -STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}Build -STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}Fund - -# Industry cargoes window -STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}Industry chain for {STRING} industry -STR_INDUSTRY_CARGOES_CARGO_CAPTION :{WHITE}Industry chain for {STRING} cargo -STR_INDUSTRY_CARGOES_PRODUCERS :{WHITE}Producing industries -STR_INDUSTRY_CARGOES_CUSTOMERS :{WHITE}Accepting industries -STR_INDUSTRY_CARGOES_HOUSES :{WHITE}Houses -STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP :{BLACK}Click at the industry to see its suppliers and customers -STR_INDUSTRY_CARGOES_CARGO_TOOLTIP :{BLACK}{STRING}{}Click at the cargo to see its suppliers and customers -STR_INDUSTRY_DISPLAY_CHAIN :{BLACK}Display chain -STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP :{BLACK}Display cargo supplying and accepting industries -STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP :{BLACK}Link to smallmap -STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP :{BLACK}Select the displayed industries at the smallmap as well -STR_INDUSTRY_CARGOES_SELECT_CARGO :{BLACK}Select cargo -STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP :{BLACK}Select the cargo you want to display -STR_INDUSTRY_CARGOES_SELECT_INDUSTRY :{BLACK}Select industry -STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}Select the industry you want to display - -# Land area window -STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}Land Area Information -STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Cost to clear: {LTBLUE}N/A -STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Cost to clear: {RED}{CURRENCY_LONG} -STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}Revenue when cleared: {LTBLUE}{CURRENCY_LONG} -STR_LAND_AREA_INFORMATION_OWNER_N_A :N/A -STR_LAND_AREA_INFORMATION_OWNER :{BLACK}Owner: {LTBLUE}{STRING1} -STR_LAND_AREA_INFORMATION_ROAD_OWNER :{BLACK}Road owner: {LTBLUE}{STRING1} -STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tramway owner: {LTBLUE}{STRING1} -STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Railway owner: {LTBLUE}{STRING1} -STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Local authority: {LTBLUE}{STRING1} -STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :None -STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinates: {LTBLUE}{NUM} x {NUM} x {NUM} ({RAW_STRING}) -STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built: {LTBLUE}{DATE_LONG} -STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Station class: {LTBLUE}{STRING} -STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Station type: {LTBLUE}{STRING} -STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Airport class: {LTBLUE}{STRING} -STR_LAND_AREA_INFORMATION_AIRPORT_NAME :{BLACK}Airport name: {LTBLUE}{STRING} -STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}Airport tile name: {LTBLUE}{STRING} -STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: {LTBLUE}{RAW_STRING} -STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Cargo accepted: {LTBLUE} -STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) -STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Rail speed limit: {LTBLUE}{VELOCITY} -STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Road speed limit: {LTBLUE}{VELOCITY} - -# Description of land area of different tiles -STR_LAI_CLEAR_DESCRIPTION_ROCKS :Rocks -STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND :Rough land -STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Bare land -STR_LAI_CLEAR_DESCRIPTION_GRASS :Grass -STR_LAI_CLEAR_DESCRIPTION_FIELDS :Fields -STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND :Snow-covered land -STR_LAI_CLEAR_DESCRIPTION_DESERT :Desert - -STR_LAI_RAIL_DESCRIPTION_TRACK :{STRING} track -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :{STRING} track with block signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS :{STRING} track with pre-signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS :{STRING} track with exit-signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS :{STRING} track with combo-signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS :{STRING} track with path signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS :{STRING} track with one-way path signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS :{STRING} track with block and pre-signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS :{STRING} track with block and exit-signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS :{STRING} track with block and combo-signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS :{STRING} track with block and path signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS :{STRING} track with block and one-way path signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS :{STRING} track with pre- and exit-signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS :{STRING} track with pre- and combo-signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS :{STRING} track with pre- and path signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS :{STRING} track with pre- and one-way path signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS :{STRING} track with exit- and combo-signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS :{STRING} track with exit- and path signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS :{STRING} track with exit- and one-way path signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS :{STRING} track with combo- and path signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :{STRING} track with combo- and one-way path signals -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :{STRING} track with path and one-way path signals -STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :{STRING} train depot - -STR_LAI_ROAD_DESCRIPTION_ROAD :Road -STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Road with street lights -STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Tree-lined road -STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT :Road vehicle depot -STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING :Road/rail level crossing -STR_LAI_ROAD_DESCRIPTION_TRAMWAY :Tramway - -# Houses come directly from their building names -STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION :{STRING} (under construction) - -STR_LAI_TREE_NAME_TREES :Trees -STR_LAI_TREE_NAME_RAINFOREST :Rainforest -STR_LAI_TREE_NAME_CACTUS_PLANTS :Cactus plants - -STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION :Railway station -STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR :Aircraft hangar -STR_LAI_STATION_DESCRIPTION_AIRPORT :Airport -STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Lorry loading area -STR_LAI_STATION_DESCRIPTION_BUS_STATION :Bus station -STR_LAI_STATION_DESCRIPTION_SHIP_DOCK :Ship dock -STR_LAI_STATION_DESCRIPTION_BUOY :Buoy -STR_LAI_STATION_DESCRIPTION_WAYPOINT :Waypoint - -STR_LAI_WATER_DESCRIPTION_WATER :Water -STR_LAI_WATER_DESCRIPTION_CANAL :Canal -STR_LAI_WATER_DESCRIPTION_LOCK :Lock -STR_LAI_WATER_DESCRIPTION_RIVER :River -STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK :Coast or riverbank -STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Ship depot - -# Industries come directly from their industry names - -STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :Railway tunnel -STR_LAI_TUNNEL_DESCRIPTION_ROAD :Road tunnel - -STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Steel suspension rail bridge -STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :Steel girder rail bridge -STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL :Steel cantilever rail bridge -STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE :Reinforced concrete suspension rail bridge -STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN :Wooden rail bridge -STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE :Concrete rail bridge -STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL :Tubular rail bridge - -STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL :Steel suspension road bridge -STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL :Steel girder road bridge -STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL :Steel cantilever road bridge -STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE :Reinforced concrete suspension road bridge -STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN :Wooden road bridge -STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE :Concrete road bridge -STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL :Tubular road bridge - -STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT :Aqueduct - -STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER :Transmitter -STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE :Lighthouse -STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS :Company headquarters -STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :Company-owned land - -# About OpenTTD window -STR_ABOUT_OPENTTD :{WHITE}About OpenTTD -STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Original copyright {COPYRIGHT} 1995 Chris Sawyer, All rights reserved -STR_ABOUT_VERSION :{BLACK}OpenTTD version {REV} -STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT} 2002-2014 The OpenTTD team - -# Save/load game/scenario -STR_SAVELOAD_SAVE_CAPTION :{WHITE}Save Game -STR_SAVELOAD_LOAD_CAPTION :{WHITE}Load Game -STR_SAVELOAD_SAVE_SCENARIO :{WHITE}Save Scenario -STR_SAVELOAD_LOAD_SCENARIO :{WHITE}Load Scenario -STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}Load Heightmap -STR_SAVELOAD_SAVE_HEIGHTMAP :{WHITE}Save Heightmap -STR_SAVELOAD_HOME_BUTTON :{BLACK}Click here to jump to the current default save/load directory -STR_SAVELOAD_BYTES_FREE :{BLACK}{BYTES} free -STR_SAVELOAD_LIST_TOOLTIP :{BLACK}List of drives, directories and saved-game files -STR_SAVELOAD_EDITBOX_TOOLTIP :{BLACK}Currently selected name for saved-game -STR_SAVELOAD_DELETE_BUTTON :{BLACK}Delete -STR_SAVELOAD_DELETE_TOOLTIP :{BLACK}Delete the currently selected saved-game -STR_SAVELOAD_SAVE_BUTTON :{BLACK}Save -STR_SAVELOAD_SAVE_TOOLTIP :{BLACK}Save the current game, using the selected name -STR_SAVELOAD_LOAD_BUTTON :{BLACK}Load -STR_SAVELOAD_LOAD_TOOLTIP :{BLACK}Load the selected game -STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Game Details -STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}No information available -STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING1} -STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} - -STR_SAVELOAD_OSKTITLE :{BLACK}Enter a name for the savegame - -# World generation -STR_MAPGEN_WORLD_GENERATION_CAPTION :{WHITE}World Generation -STR_MAPGEN_MAPSIZE :{BLACK}Map size: -STR_MAPGEN_MAPSIZE_TOOLTIP :{BLACK}Select the size of the map in tiles. The number of available tiles will be slightly smaller -STR_MAPGEN_BY :{BLACK}* -STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}No. of towns: -STR_MAPGEN_DATE :{BLACK}Date: -STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}No. of industries: -STR_MAPGEN_SNOW_LINE_HEIGHT :{BLACK}Snow line height: -STR_MAPGEN_SNOW_LINE_UP :{BLACK}Move the snow line height one up -STR_MAPGEN_SNOW_LINE_DOWN :{BLACK}Move the snow line height one down -STR_MAPGEN_RANDOM_SEED :{BLACK}Random seed: -STR_MAPGEN_RANDOM_SEED_HELP :{BLACK}Click to enter a random seed -STR_MAPGEN_RANDOM :{BLACK}Randomise -STR_MAPGEN_RANDOM_HELP :{BLACK}Change the random seed used for Terrain Generation -STR_MAPGEN_LAND_GENERATOR :{BLACK}Land generator: -STR_MAPGEN_TREE_PLACER :{BLACK}Tree algorithm: -STR_MAPGEN_TERRAIN_TYPE :{BLACK}Terrain type: -STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}Sea level: -STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}Rivers: -STR_MAPGEN_SMOOTHNESS :{BLACK}Smoothness: -STR_MAPGEN_VARIETY :{BLACK}Variety distribution: -STR_MAPGEN_GENERATE :{WHITE}Generate - -# Strings for map borders at game generation -STR_MAPGEN_BORDER_TYPE :{BLACK}Map edges: -STR_MAPGEN_NORTHWEST :{BLACK}Northwest -STR_MAPGEN_NORTHEAST :{BLACK}Northeast -STR_MAPGEN_SOUTHEAST :{BLACK}Southeast -STR_MAPGEN_SOUTHWEST :{BLACK}Southwest -STR_MAPGEN_BORDER_FREEFORM :{BLACK}Freeform -STR_MAPGEN_BORDER_WATER :{BLACK}Water -STR_MAPGEN_BORDER_RANDOM :{BLACK}Random -STR_MAPGEN_BORDER_RANDOMIZE :{BLACK}Random -STR_MAPGEN_BORDER_MANUAL :{BLACK}Manual - -STR_MAPGEN_HEIGHTMAP_ROTATION :{BLACK}Heightmap rotation: -STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}Heightmap name: -STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}Size: -STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} x {NUM} - -STR_MAPGEN_RANDOM_SEED_OSKTITLE :{BLACK}Enter a random seed -STR_MAPGEN_SNOW_LINE_QUERY_CAPT :{WHITE}Change snow line height -STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}Change starting year - -# SE Map generation -STR_SE_MAPGEN_CAPTION :{WHITE}Scenario Type -STR_SE_MAPGEN_FLAT_WORLD :{WHITE}Flat land -STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP :{BLACK}Generate a flat land -STR_SE_MAPGEN_RANDOM_LAND :{WHITE}Random land -STR_SE_MAPGEN_FLAT_WORLD_HEIGHT :{BLACK}Height of flat land: -STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_DOWN :{BLACK}Move the height of flat land one down -STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_UP :{BLACK}Move the height of flat land one up - -STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Change height of flat land - -# Map generation progress -STR_GENERATION_WORLD :{WHITE}Generating World... -STR_GENERATION_ABORT :{BLACK}Abort -STR_GENERATION_ABORT_CAPTION :{WHITE}Abort World Generation -STR_GENERATION_ABORT_MESSAGE :{YELLOW}Do you really want to abort the generation? -STR_GENERATION_PROGRESS :{WHITE}{NUM}% complete -STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM} -STR_GENERATION_WORLD_GENERATION :{BLACK}World generation -STR_GENERATION_RIVER_GENERATION :{BLACK}River generation -STR_GENERATION_TREE_GENERATION :{BLACK}Tree generation -STR_GENERATION_OBJECT_GENERATION :{BLACK}Object generation -STR_GENERATION_CLEARING_TILES :{BLACK}Rough and rocky area generation -STR_GENERATION_SETTINGUP_GAME :{BLACK}Setting up game -STR_GENERATION_PREPARING_TILELOOP :{BLACK}Running tile-loop -STR_GENERATION_PREPARING_SCRIPT :{BLACK}Running script -STR_GENERATION_PREPARING_GAME :{BLACK}Preparing game - -# NewGRF settings -STR_NEWGRF_SETTINGS_CAPTION :{WHITE}NewGRF Settings -STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}Detailed NewGRF information -STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}Active NewGRF files -STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}Inactive NewGRF files -STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}Select preset: -STR_NEWGRF_FILTER_TITLE :{ORANGE}Filter string: -STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}Load the selected preset -STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}Save preset -STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}Save the current list as a preset -STR_NEWGRF_SETTINGS_PRESET_SAVE_QUERY :{BLACK}Enter name for preset -STR_NEWGRF_SETTINGS_PRESET_DELETE :{BLACK}Delete preset -STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP :{BLACK}Delete the currently selected preset -STR_NEWGRF_SETTINGS_ADD :{BLACK}Add -STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP :{BLACK}Add the selected NewGRF file to your configuration -STR_NEWGRF_SETTINGS_RESCAN_FILES :{BLACK}Rescan files -STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP :{BLACK}Update the list of available NewGRF files -STR_NEWGRF_SETTINGS_REMOVE :{BLACK}Remove -STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP :{BLACK}Remove the selected NewGRF file from the list -STR_NEWGRF_SETTINGS_MOVEUP :{BLACK}Move Up -STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP :{BLACK}Move the selected NewGRF file up the list -STR_NEWGRF_SETTINGS_MOVEDOWN :{BLACK}Move Down -STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP :{BLACK}Move the selected NewGRF file down the list -STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}A list of the NewGRF files that are installed - -STR_NEWGRF_SETTINGS_SET_PARAMETERS :{BLACK}Set parameters -STR_NEWGRF_SETTINGS_SHOW_PARAMETERS :{BLACK}Show parameters -STR_NEWGRF_SETTINGS_TOGGLE_PALETTE :{BLACK}Toggle palette -STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP :{BLACK}Toggle the palette of the selected NewGRF.{}Do this when the graphics from this NewGRF look pink in-game -STR_NEWGRF_SETTINGS_APPLY_CHANGES :{BLACK}Apply changes - -STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON :{BLACK}Find missing content online -STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP :{BLACK}Check whether the missing content can be found online - -STR_NEWGRF_SETTINGS_FILENAME :{BLACK}Filename: {SILVER}{RAW_STRING} -STR_NEWGRF_SETTINGS_GRF_ID :{BLACK}GRF ID: {SILVER}{RAW_STRING} -STR_NEWGRF_SETTINGS_VERSION :{BLACK}Version: {SILVER}{NUM} -STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}Min. compatible version: {SILVER}{NUM} -STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{RAW_STRING} -STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Palette: {SILVER}{RAW_STRING} -STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parameters: {SILVER}{STRING1} - -STR_NEWGRF_SETTINGS_NO_INFO :{BLACK}No information available -STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}Matching file not found -STR_NEWGRF_SETTINGS_DISABLED :{RED}Disabled -STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}Incompatible with this version of OpenTTD - -# NewGRF parameters window -STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Change NewGRF parameters -STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Close -STR_NEWGRF_PARAMETERS_RESET :{BLACK}Reset -STR_NEWGRF_PARAMETERS_RESET_TOOLTIP :{BLACK}Set all parameters to their default value -STR_NEWGRF_PARAMETERS_DEFAULT_NAME :Parameter {NUM} -STR_NEWGRF_PARAMETERS_SETTING :{STRING1}: {ORANGE}{STRING1} -STR_NEWGRF_PARAMETERS_NUM_PARAM :{LTBLUE}Number of parameters: {ORANGE}{NUM} - -# NewGRF inspect window -STR_NEWGRF_INSPECT_CAPTION :{WHITE}Inspect - {STRING5} -STR_NEWGRF_INSPECT_PARENT_BUTTON :{BLACK}Parent -STR_NEWGRF_INSPECT_PARENT_TOOLTIP :{BLACK}Inspect the object of the parent scope - -STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING1} at {HEX} -STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT :Object -STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :Rail type - -STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF variable 60+x parameter (hexadecimal) - -# Sprite aligner window -STR_SPRITE_ALIGNER_CAPTION :{WHITE}Aligning sprite {COMMA} ({RAW_STRING}) -STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Next sprite -STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Proceed to the next normal sprite, skipping any pseudo/recolour/font sprites and wrapping around at the end -STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Go to sprite -STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}Go to the given sprite. If the sprite is not a normal sprite, proceed to the next normal sprite -STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Previous sprite -STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Proceed to the previous normal sprite, skipping any pseudo/recolour/font sprites and wrapping around at the begin -STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Representation of the currently selected sprite. The alignment is ignored when drawing this sprite -STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Move the sprite around, changing the X and Y offsets -STR_SPRITE_ALIGNER_OFFSETS :{BLACK}X offset: {NUM}, Y offset: {NUM} -STR_SPRITE_ALIGNER_PICKER_BUTTON :{BLACK}Pick sprite -STR_SPRITE_ALIGNER_PICKER_TOOLTIP :{BLACK}Pick a sprite from anywhere on the screen - -STR_SPRITE_ALIGNER_GOTO_CAPTION :{WHITE}Go to sprite - -# NewGRF (self) generated warnings/errors -STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{RAW_STRING} -STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warning: {SILVER}{RAW_STRING} -STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{RAW_STRING} -STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{RAW_STRING} -STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}A fatal NewGRF error has occurred: {}{STRING5} -STR_NEWGRF_ERROR_VERSION_NUMBER :{1:RAW_STRING} will not work with the TTDPatch version reported by OpenTTD -STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:RAW_STRING} is for the {RAW_STRING} version of TTD -STR_NEWGRF_ERROR_UNSET_SWITCH :{1:RAW_STRING} is designed to be used with {RAW_STRING} -STR_NEWGRF_ERROR_INVALID_PARAMETER :Invalid parameter for {1:RAW_STRING}: parameter {RAW_STRING} ({NUM}) -STR_NEWGRF_ERROR_LOAD_BEFORE :{1:RAW_STRING} must be loaded before {RAW_STRING} -STR_NEWGRF_ERROR_LOAD_AFTER :{1:RAW_STRING} must be loaded after {RAW_STRING} -STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:RAW_STRING} requires OpenTTD version {RAW_STRING} or better -STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :the GRF file it was designed to translate -STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :Too many NewGRFs are loaded -STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Loading {1:RAW_STRING} as static NewGRF with {RAW_STRING} could cause desyncs -STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Unexpected sprite (sprite {3:NUM}) -STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Unknown Action 0 property {4:HEX} (sprite {3:NUM}) -STR_NEWGRF_ERROR_INVALID_ID :Attempt to use invalid ID (sprite {3:NUM}) -STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}{RAW_STRING} contains a corrupt sprite. All corrupt sprites will be shown as a red question mark (?) -STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Contains multiple Action 8 entries (sprite {3:NUM}) -STR_NEWGRF_ERROR_READ_BOUNDS :Read past end of pseudo-sprite (sprite {3:NUM}) -STR_NEWGRF_ERROR_MISSING_SPRITES :{WHITE}The currently used base graphics set is missing a number of sprites.{}Please update the base graphics set -STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE :{WHITE}The currently used base graphics set is missing a number of sprites.{}Please update the base graphics set.{}Since you are playing a {YELLOW}development snapshot of OpenTTD{WHITE}, you might also need a {YELLOW}development snapshot of the base graphics{WHITE} -STR_NEWGRF_ERROR_GRM_FAILED :Requested GRF resources not available (sprite {3:NUM}) -STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:RAW_STRING} was disabled by {2:RAW_STRING} -STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Invalid/unknown sprite layout format (sprite {3:NUM}) - -# NewGRF related 'general' warnings -STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}Caution! -STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}You are about to make changes to a running game. This can crash OpenTTD or break the game state. Do not file bug reports about these issues.{}Are you absolutely sure about this? - -STR_NEWGRF_DUPLICATE_GRFID :{WHITE}Can't add file: duplicate GRF ID -STR_NEWGRF_COMPATIBLE_LOADED :{ORANGE}Matching file not found (compatible GRF loaded) -STR_NEWGRF_TOO_MANY_NEWGRFS :{WHITE}Can't add file: NewGRF file limit reached - -STR_NEWGRF_COMPATIBLE_LOAD_WARNING :{WHITE}Compatible GRF(s) loaded for missing files -STR_NEWGRF_DISABLED_WARNING :{WHITE}Missing GRF file(s) have been disabled -STR_NEWGRF_UNPAUSE_WARNING_TITLE :{YELLOW}Missing GRF file(s) -STR_NEWGRF_UNPAUSE_WARNING :{WHITE}Unpausing can crash OpenTTD. Do not file bug reports for subsequent crashes.{}Do you really want to unpause? - -# NewGRF status -STR_NEWGRF_LIST_NONE :None -STR_NEWGRF_LIST_ALL_FOUND :All files present -STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Found compatible files -STR_NEWGRF_LIST_MISSING :{RED}Missing files - -# NewGRF 'it's broken' warnings -STR_NEWGRF_BROKEN :{WHITE}Behaviour of NewGRF '{0:RAW_STRING}' is likely to cause desyncs and/or crashes -STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}It changed powered-wagon state for '{1:ENGINE}' when not inside a depot -STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}It changed vehicle length for '{1:ENGINE}' when not inside a depot -STR_NEWGRF_BROKEN_CAPACITY :{WHITE}It changed vehicle capacity for '{1:ENGINE}' when not inside a depot or refitting -STR_BROKEN_VEHICLE_LENGTH :{WHITE}Train '{VEHICLE}' belonging to '{COMPANY}' has invalid length. It is probably caused by problems with NewGRFs. Game may desync or crash - -STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:RAW_STRING}' provides incorrect information -STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Cargo/refit information for '{1:ENGINE}' differs from purchase list after construction. This might cause autorenew/-replace to fail refitting correctly -STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' caused an endless loop in the production callback -STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Callback {1:HEX} returned unknown/invalid result {2:HEX} - -# 'User removed essential NewGRFs'-placeholders for stuff without specs -STR_NEWGRF_INVALID_CARGO : -STR_NEWGRF_INVALID_CARGO_ABBREV :?? -STR_NEWGRF_INVALID_CARGO_QUANTITY :{COMMA} of -STR_NEWGRF_INVALID_ENGINE : -STR_NEWGRF_INVALID_INDUSTRYTYPE : - -# Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script). -STR_INVALID_VEHICLE : - -# NewGRF scanning window -STR_NEWGRF_SCAN_CAPTION :{WHITE}Scanning NewGRFs -STR_NEWGRF_SCAN_MESSAGE :{BLACK}Scanning NewGRFs. Depending on the amount this can take a while... -STR_NEWGRF_SCAN_STATUS :{BLACK}{NUM} NewGRF{P "" s} scanned out of an estimated {NUM} NewGRF{P "" s} -STR_NEWGRF_SCAN_ARCHIVES :Scanning for archives - -# Sign list window -STR_SIGN_LIST_CAPTION :{WHITE}Sign List - {COMMA} Sign{P "" s} -STR_SIGN_LIST_MATCH_CASE :{BLACK}Match case -STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}Toggle matching case when comparing sign names against the filter string - -# Sign window -STR_EDIT_SIGN_CAPTION :{WHITE}Edit sign text -STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}Go to next sign -STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}Go to previous sign - -STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}Enter a name for the sign - -# Town directory window -STR_TOWN_DIRECTORY_CAPTION :{WHITE}Towns -STR_TOWN_DIRECTORY_NONE :{ORANGE}- None - -STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ({COMMA}) -STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}Town names - click on name to centre main view on town. Ctrl+Click opens a new viewport on town location -STR_TOWN_POPULATION :{BLACK}World population: {COMMA} - -# Town view window -STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} -STR_TOWN_VIEW_CITY_CAPTION :{WHITE}{TOWN} (City) -STR_TOWN_VIEW_POPULATION_HOUSES :{BLACK}Population: {ORANGE}{COMMA}{BLACK} Houses: {ORANGE}{COMMA} -STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX :{BLACK}Passengers last month: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} -STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX :{BLACK}Mail last month: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} -STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH :{BLACK}Cargo needed for town growth: -STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL :{ORANGE}{STRING}{RED} required -STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER :{ORANGE}{STRING}{BLACK} required in winter -STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL :{ORANGE}{STRING}{GREEN} delivered -STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{RED} (still required) -STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{GREEN} (delivered) -STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}Town grows every {ORANGE}{COMMA}{BLACK} day{P "" s} -STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}Town grows every {ORANGE}{COMMA}{BLACK} day{P "" s} (funded) -STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}Town is {RED}not{BLACK} growing -STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}Noise limit in town: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} -STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Centre the main view on town location. Ctrl+Click opens a new viewport on town location -STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Local authority -STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}Show information on local authority -STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Change town name - -STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Expand -STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Increase size of town -STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Delete -STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Delete this town completely - -STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Rename Town - -# Town local authority window -STR_LOCAL_AUTHORITY_CAPTION :{WHITE}{TOWN} local authority -STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Transport company ratings: -STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} -STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Actions available: -STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP :{BLACK}List of things to do at this town - click on item for more details -STR_LOCAL_AUTHORITY_DO_IT_BUTTON :{BLACK}Do it -STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP :{BLACK}Carry out the highlighted action in the list above - -STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN :Small advertising campaign -STR_LOCAL_AUTHORITY_ACTION_MEDIUM_ADVERTISING_CAMPAIGN :Medium advertising campaign -STR_LOCAL_AUTHORITY_ACTION_LARGE_ADVERTISING_CAMPAIGN :Large advertising campaign -STR_LOCAL_AUTHORITY_ACTION_ROAD_RECONSTRUCTION :Fund local road reconstruction -STR_LOCAL_AUTHORITY_ACTION_STATUE_OF_COMPANY :Build statue of company owner -STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :Fund new buildings -STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :Buy exclusive transport rights -STR_LOCAL_AUTHORITY_ACTION_BRIBE :Bribe the local authority - -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Initiate a small local advertising campaign, to attract more passengers and cargo to your transport services.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Initiate a medium local advertising campaign, to attract more passengers and cargo to your transport services.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Initiate a large local advertising campaign, to attract more passengers and cargo to your transport services.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}Fund the reconstruction of the urban road network. Causes considerable disruption to road traffic for up to 6 months.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}Build a statue in honour of your company.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}Fund the construction of new commercial buildings in the town.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Buy 1 year's exclusive transport rights in town. Town authority will only allow passengers and cargo to use your company's stations.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Bribe the local authority to increase your rating, at the risk of a severe penalty if caught.{}Cost: {CURRENCY_LONG} - -# Goal window -STR_GOALS_CAPTION :{WHITE}{COMPANY} Goals -STR_GOALS_SPECTATOR_CAPTION :{WHITE}Global Goals -STR_GOALS_GLOBAL_TITLE :{BLACK}Global goals: -STR_GOALS_TEXT :{ORANGE}{RAW_STRING} -STR_GOALS_NONE :{ORANGE}- None - -STR_GOALS_SPECTATOR_NONE :{ORANGE}- Not applicable - -STR_GOALS_PROGRESS :{ORANGE}{RAW_STRING} -STR_GOALS_PROGRESS_COMPLETE :{GREEN}{RAW_STRING} -STR_GOALS_COMPANY_TITLE :{BLACK}Company goals: -STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Click on goal to centre main view on industry/town/tile. Ctrl+Click opens a new viewport on industry/town/tile location - -# Goal question window -STR_GOAL_QUESTION_CAPTION_QUESTION :Question -STR_GOAL_QUESTION_CAPTION_INFORMATION :Information -STR_GOAL_QUESTION_CAPTION_WARNING :Warning -STR_GOAL_QUESTION_CAPTION_ERROR :Error - -### Start of Goal Question button list -STR_GOAL_QUESTION_BUTTON_CANCEL :Cancel -STR_GOAL_QUESTION_BUTTON_OK :OK -STR_GOAL_QUESTION_BUTTON_NO :No -STR_GOAL_QUESTION_BUTTON_YES :Yes -STR_GOAL_QUESTION_BUTTON_DECLINE :Decline -STR_GOAL_QUESTION_BUTTON_ACCEPT :Accept -STR_GOAL_QUESTION_BUTTON_IGNORE :Ignore -STR_GOAL_QUESTION_BUTTON_RETRY :Retry -STR_GOAL_QUESTION_BUTTON_PREVIOUS :Previous -STR_GOAL_QUESTION_BUTTON_NEXT :Next -STR_GOAL_QUESTION_BUTTON_STOP :Stop -STR_GOAL_QUESTION_BUTTON_START :Start -STR_GOAL_QUESTION_BUTTON_GO :Go -STR_GOAL_QUESTION_BUTTON_CONTINUE :Continue -STR_GOAL_QUESTION_BUTTON_RESTART :Restart -STR_GOAL_QUESTION_BUTTON_POSTPONE :Postpone -STR_GOAL_QUESTION_BUTTON_SURRENDER :Surrender -STR_GOAL_QUESTION_BUTTON_CLOSE :Close - -# Subsidies window -STR_SUBSIDIES_CAPTION :{WHITE}Subsidies -STR_SUBSIDIES_OFFERED_TITLE :{BLACK}Subsidies on offer for services taking: -STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING} from {STRING2} to {STRING2}{YELLOW} (by {DATE_SHORT}) -STR_SUBSIDIES_NONE :{ORANGE}- None - -STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Services already subsidised: -STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} from {STRING2} to {STRING2}{YELLOW} ({COMPANY}{YELLOW}, until {DATE_SHORT}) -STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Click on service to centre main view on industry/town. Ctrl+Click opens a new viewport on industry/town location - -# Story book window -STR_STORY_BOOK_CAPTION :{WHITE}{COMPANY} Story Book -STR_STORY_BOOK_SPECTATOR_CAPTION :{WHITE}Global Story Book -STR_STORY_BOOK_TITLE :{YELLOW}{RAW_STRING} -STR_STORY_BOOK_GENERIC_PAGE_ITEM :Page {NUM} -STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}Jump to a specific page by selecting it in this drop down list. -STR_STORY_BOOK_PREV_PAGE :{BLACK}Previous -STR_STORY_BOOK_PREV_PAGE_TOOLTIP :{BLACK}Go to previous page -STR_STORY_BOOK_NEXT_PAGE :{BLACK}Next -STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}Go to next page -STR_STORY_BOOK_INVALID_GOAL_REF :{RED}Invalid goal reference - -# Station list window -STR_STATION_LIST_TOOLTIP :{BLACK}Station names - click on name to centre main view on station. Ctrl+Click opens a new viewport on station location -STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE :{BLACK}Hold Ctrl to select more than one item -STR_STATION_LIST_CAPTION :{WHITE}{COMPANY} - {COMMA} Station{P "" s} -STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATION_FEATURES} -STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT} -STR_STATION_LIST_NONE :{YELLOW}- None - -STR_STATION_LIST_SELECT_ALL_FACILITIES :{BLACK}Select all facilities -STR_STATION_LIST_SELECT_ALL_TYPES :{BLACK}Select all cargo types (including no waiting cargo) -STR_STATION_LIST_NO_WAITING_CARGO :{BLACK}No cargo of any type is waiting - -# Station view window -STR_STATION_VIEW_CAPTION :{WHITE}{STATION} {STATION_FEATURES} -STR_STATION_VIEW_WAITING_TITLE :{BLACK}Waiting: {WHITE}{STRING} -STR_STATION_VIEW_WAITING_CARGO :{WHITE}{CARGO_LONG} -STR_STATION_VIEW_EN_ROUTE_FROM :{YELLOW}({CARGO_SHORT} from {STATION}) -STR_STATION_VIEW_RESERVED :{YELLOW}({CARGO_SHORT} reserved for loading) - -STR_STATION_VIEW_ACCEPTS_BUTTON :{BLACK}Accepts -STR_STATION_VIEW_ACCEPTS_TOOLTIP :{BLACK}Show list of accepted cargo -STR_STATION_VIEW_ACCEPTS_CARGO :{BLACK}Accepts: {WHITE}{CARGO_LIST} - -STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF :{BLACK}This station has exclusive transport rights in this town. -STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY :{YELLOW}{COMPANY}{BLACK} bought exclusive transport rights in this town. - -STR_STATION_VIEW_RATINGS_BUTTON :{BLACK}Ratings -STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Show station ratings -STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}Monthly supply and local rating: -STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%) - -STR_STATION_VIEW_GROUP :{BLACK}Group by -STR_STATION_VIEW_WAITING_STATION :Station: Waiting -STR_STATION_VIEW_WAITING_AMOUNT :Amount: Waiting -STR_STATION_VIEW_PLANNED_STATION :Station: Planned -STR_STATION_VIEW_PLANNED_AMOUNT :Amount: Planned -STR_STATION_VIEW_FROM :{YELLOW}{CARGO_SHORT} from {STATION} -STR_STATION_VIEW_VIA :{YELLOW}{CARGO_SHORT} via {STATION} -STR_STATION_VIEW_TO :{YELLOW}{CARGO_SHORT} to {STATION} -STR_STATION_VIEW_FROM_ANY :{RED}{CARGO_SHORT} from unknown station -STR_STATION_VIEW_TO_ANY :{RED}{CARGO_SHORT} to any station -STR_STATION_VIEW_VIA_ANY :{RED}{CARGO_SHORT} via any station -STR_STATION_VIEW_FROM_HERE :{GREEN}{CARGO_SHORT} from this station -STR_STATION_VIEW_VIA_HERE :{GREEN}{CARGO_SHORT} stopping at this station -STR_STATION_VIEW_TO_HERE :{GREEN}{CARGO_SHORT} to this station -STR_STATION_VIEW_NONSTOP :{YELLOW}{CARGO_SHORT} non-stop - -STR_STATION_VIEW_GROUP_S_V_D :Source-Via-Destination -STR_STATION_VIEW_GROUP_S_D_V :Source-Destination-Via -STR_STATION_VIEW_GROUP_V_S_D :Via-Source-Destination -STR_STATION_VIEW_GROUP_V_D_S :Via-Destination-Source -STR_STATION_VIEW_GROUP_D_S_V :Destination-Source-Via -STR_STATION_VIEW_GROUP_D_V_S :Destination-Via-Source - -############ range for rating starts -STR_CARGO_RATING_APPALLING :Appalling -STR_CARGO_RATING_VERY_POOR :Very Poor -STR_CARGO_RATING_POOR :Poor -STR_CARGO_RATING_MEDIOCRE :Mediocre -STR_CARGO_RATING_GOOD :Good -STR_CARGO_RATING_VERY_GOOD :Very Good -STR_CARGO_RATING_EXCELLENT :Excellent -STR_CARGO_RATING_OUTSTANDING :Outstanding -############ range for rating ends - -STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}Centre main view on station location. Ctrl+Click opens a new viewport on station location -STR_STATION_VIEW_RENAME_TOOLTIP :{BLACK}Change name of station - -STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP :{BLACK}Show all trains which have this station on their schedule -STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP :{BLACK}Show all road vehicles which have this station on their schedule -STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP :{BLACK}Show all aircraft which have this station on their schedule -STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP :{BLACK}Show all ships which have this station on their schedule - -STR_STATION_VIEW_RENAME_STATION_CAPTION :Rename station/loading area - -STR_STATION_VIEW_CLOSE_AIRPORT :{BLACK}Close airport -STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}Prevent aircraft from landing on this airport - -# Waypoint/buoy view window -STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT} -STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Centre main view on waypoint location. Ctrl+Click opens a new viewport on waypoint location -STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}Change waypoint name -STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}Centre main view on buoy location. Ctrl+Click opens a new viewport on buoy location -STR_BUOY_VIEW_CHANGE_BUOY_NAME :{BLACK}Change buoy name - -STR_EDIT_WAYPOINT_NAME :{WHITE}Edit waypoint name - -# Finances window -STR_FINANCES_CAPTION :{WHITE}{COMPANY} Finances {BLACK}{COMPANY_NUM} -STR_FINANCES_EXPENDITURE_INCOME_TITLE :{WHITE}Expenditure/Income -STR_FINANCES_YEAR :{WHITE}{NUM} -STR_FINANCES_SECTION_CONSTRUCTION :{GOLD}Construction -STR_FINANCES_SECTION_NEW_VEHICLES :{GOLD}New Vehicles -STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS :{GOLD}Train Running Costs -STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS :{GOLD}Road Vehicle Running Costs -STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS :{GOLD}Aircraft Running Costs -STR_FINANCES_SECTION_SHIP_RUNNING_COSTS :{GOLD}Ship Running Costs -STR_FINANCES_SECTION_PROPERTY_MAINTENANCE :{GOLD}Property Maintenance -STR_FINANCES_SECTION_TRAIN_INCOME :{GOLD}Train Income -STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME :{GOLD}Road Vehicle Income -STR_FINANCES_SECTION_AIRCRAFT_INCOME :{GOLD}Aircraft Income -STR_FINANCES_SECTION_SHIP_INCOME :{GOLD}Ship Income -STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Loan Interest -STR_FINANCES_SECTION_OTHER :{GOLD}Other -STR_FINANCES_NEGATIVE_INCOME :{BLACK}-{CURRENCY_LONG} -STR_FINANCES_POSITIVE_INCOME :{BLACK}+{CURRENCY_LONG} -STR_FINANCES_TOTAL_CAPTION :{WHITE}Total: -STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Bank Balance -STR_FINANCES_LOAN_TITLE :{WHITE}Loan -STR_FINANCES_MAX_LOAN :{WHITE}Max Loan: {BLACK}{CURRENCY_LONG} -STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} -STR_FINANCES_BORROW_BUTTON :{BLACK}Borrow {CURRENCY_LONG} -STR_FINANCES_BORROW_TOOLTIP :{BLACK}Increase size of loan. Ctrl+Click borrows as much as possible -STR_FINANCES_REPAY_BUTTON :{BLACK}Repay {CURRENCY_LONG} -STR_FINANCES_REPAY_TOOLTIP :{BLACK}Repay part of loan. Ctrl+Click repays as much loan as possible -STR_FINANCES_INFRASTRUCTURE_BUTTON :{BLACK}Infrastructure - -# Company view -STR_COMPANY_VIEW_CAPTION :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM} -STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE :{WHITE}{PRESIDENT_NAME}{}{GOLD}(Manager) - -STR_COMPANY_VIEW_INAUGURATED_TITLE :{GOLD}Inaugurated: {WHITE}{NUM} -STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE :{GOLD}Colour Scheme: -STR_COMPANY_VIEW_VEHICLES_TITLE :{GOLD}Vehicles: -STR_COMPANY_VIEW_TRAINS :{WHITE}{COMMA} train{P "" s} -STR_COMPANY_VIEW_ROAD_VEHICLES :{WHITE}{COMMA} road vehicle{P "" s} -STR_COMPANY_VIEW_AIRCRAFT :{WHITE}{COMMA} aircraft -STR_COMPANY_VIEW_SHIPS :{WHITE}{COMMA} ship{P "" s} -STR_COMPANY_VIEW_VEHICLES_NONE :{WHITE}None -STR_COMPANY_VIEW_COMPANY_VALUE :{GOLD}Company value: {WHITE}{CURRENCY_LONG} -STR_COMPANY_VIEW_SHARES_OWNED_BY :{WHITE}({COMMA}% owned by {COMPANY}) -STR_COMPANY_VIEW_INFRASTRUCTURE :{GOLD}Infrastructure: -STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL :{WHITE}{COMMA} rail piece{P "" s} -STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD :{WHITE}{COMMA} road piece{P "" s} -STR_COMPANY_VIEW_INFRASTRUCTURE_WATER :{WHITE}{COMMA} water tile{P "" s} -STR_COMPANY_VIEW_INFRASTRUCTURE_STATION :{WHITE}{COMMA} station tile{P "" s} -STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT :{WHITE}{COMMA} airport{P "" s} -STR_COMPANY_VIEW_INFRASTRUCTURE_NONE :{WHITE}None - -STR_COMPANY_VIEW_BUILD_HQ_BUTTON :{BLACK}Build HQ -STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP :{BLACK}Build company headquarters -STR_COMPANY_VIEW_VIEW_HQ_BUTTON :{BLACK}View HQ -STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP :{BLACK}View company headquarters -STR_COMPANY_VIEW_RELOCATE_HQ :{BLACK}Relocate HQ -STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}Rebuild company headquarters elsewhere for 1% cost of company value. Shift+Click shows estimated cost without relocating HQ -STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}Details -STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}View detailed infrastructure counts - -STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}New Face -STR_COMPANY_VIEW_NEW_FACE_TOOLTIP :{BLACK}Select new face for manager -STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON :{BLACK}Colour Scheme -STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP :{BLACK}Change the company vehicle livery -STR_COMPANY_VIEW_COMPANY_NAME_BUTTON :{BLACK}Company Name -STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP :{BLACK}Change the company name -STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON :{BLACK}Manager Name -STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP :{BLACK}Change the manager's name - -STR_COMPANY_VIEW_BUY_SHARE_BUTTON :{BLACK}Buy 25% share in company -STR_COMPANY_VIEW_SELL_SHARE_BUTTON :{BLACK}Sell 25% share in company -STR_COMPANY_VIEW_BUY_SHARE_TOOLTIP :{BLACK}Buy 25% share in this company. Shift+Click shows estimated cost without purchasing any share -STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP :{BLACK}Sell 25% share in this company. Shift+Click shows estimated income without selling any share - -STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION :Company Name -STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION :Manager's Name - -STR_BUY_COMPANY_MESSAGE :{WHITE}We are looking for a transport company to take-over our company.{}{}Do you want to purchase {COMPANY} for {CURRENCY_LONG}? - -# Company infrastructure window -STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastructure of {COMPANY} -STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Rail pieces: -STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signals -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Road pieces: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Road -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramway -STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Water tiles: -STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canals -STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations: -STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Station tiles -STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}Airports -STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG}/yr - -# Industry directory -STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Industries -STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- None - -STR_INDUSTRY_DIRECTORY_ITEM :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{RAW_STRING}){YELLOW} ({COMMA}% transported) -STR_INDUSTRY_DIRECTORY_ITEM_TWO :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{RAW_STRING}/{CARGO_LONG}{RAW_STRING}){YELLOW} ({COMMA}%/{COMMA}% transported) -STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} -STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Industry names - click on name to centre main view on industry. Ctrl+Click opens a new viewport on industry location - -# Industry view -STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} -STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Production last month: -STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{RAW_STRING}{BLACK} ({COMMA}% transported) -STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Centre the main view on industry location. Ctrl+Click opens a new viewport on industry location -STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Production level: {YELLOW}{COMMA}% -STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}The industry has announced imminent closure! - -############ range for requires starts -STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}Requires: {YELLOW}{STRING}{RAW_STRING} -STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO :{BLACK}Requires: {YELLOW}{STRING}{RAW_STRING}, {STRING}{RAW_STRING} -STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO_CARGO :{BLACK}Requires: {YELLOW}{STRING}{RAW_STRING}, {STRING}{RAW_STRING}, {STRING}{RAW_STRING} -############ range for requires ends - -############ range for produces starts -STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING :{BLACK}Cargo waiting to be processed: -STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO :{YELLOW}{CARGO_LONG}{RAW_STRING}{BLACK} -STR_INDUSTRY_VIEW_PRODUCES_CARGO :{BLACK}Produces: {YELLOW}{STRING}{RAW_STRING} -STR_INDUSTRY_VIEW_PRODUCES_CARGO_CARGO :{BLACK}Produces: {YELLOW}{STRING}{RAW_STRING}, {STRING}{RAW_STRING} -############ range for produces ends - -STR_CONFIG_GAME_PRODUCTION :{WHITE}Change production (multiple of 8, up to 2040) -STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Change production level (percentage, up to 800%) - -# Vehicle lists -STR_VEHICLE_LIST_TRAIN_CAPTION :{WHITE}{STRING2} - {COMMA} Train{P "" s} -STR_VEHICLE_LIST_ROAD_VEHICLE_CAPTION :{WHITE}{STRING2} - {COMMA} Road Vehicle{P "" s} -STR_VEHICLE_LIST_SHIP_CAPTION :{WHITE}{STRING2} - {COMMA} Ship{P "" s} -STR_VEHICLE_LIST_AIRCRAFT_CAPTION :{WHITE}{STRING2} - {COMMA} Aircraft - -STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP :{BLACK}Trains - click on train for information -STR_VEHICLE_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Road vehicles - click on vehicle for information -STR_VEHICLE_LIST_SHIP_TOOLTIP :{BLACK}Ships - click on ship for information -STR_VEHICLE_LIST_AIRCRAFT_TOOLTIP :{BLACK}Aircraft - click on aircraft for information - -STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}Profit this year: {CURRENCY_LONG} (last year: {CURRENCY_LONG}) - -STR_VEHICLE_LIST_AVAILABLE_TRAINS :Available Trains -STR_VEHICLE_LIST_AVAILABLE_ROAD_VEHICLES :Available Vehicles -STR_VEHICLE_LIST_AVAILABLE_SHIPS :Available Ships -STR_VEHICLE_LIST_AVAILABLE_AIRCRAFT :Available Aircraft -STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP :{BLACK}See a list of available engine designs for this vehicle type - -STR_VEHICLE_LIST_MANAGE_LIST :{BLACK}Manage list -STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}Send instructions to all vehicles in this list -STR_VEHICLE_LIST_REPLACE_VEHICLES :Replace vehicles -STR_VEHICLE_LIST_SEND_FOR_SERVICING :Send for Servicing - -STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :Send to Depot -STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :Send to Depot -STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT :Send to Depot -STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR :Send to Hangar - -STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP :{BLACK}Click to stop all the vehicles in the list -STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP :{BLACK}Click to start all the vehicles in the list - -STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION :{WHITE}Shared orders of {COMMA} Vehicle{P "" s} - -# Group window -STR_GROUP_ALL_TRAINS :All trains -STR_GROUP_ALL_ROAD_VEHICLES :All road vehicles -STR_GROUP_ALL_SHIPS :All ships -STR_GROUP_ALL_AIRCRAFTS :All aircraft - -STR_GROUP_DEFAULT_TRAINS :Ungrouped trains -STR_GROUP_DEFAULT_ROAD_VEHICLES :Ungrouped road vehicles -STR_GROUP_DEFAULT_SHIPS :Ungrouped ships -STR_GROUP_DEFAULT_AIRCRAFTS :Ungrouped aircraft - -STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Groups - click on a group to list all vehicles of this group -STR_GROUP_CREATE_TOOLTIP :{BLACK}Click to create a group -STR_GROUP_DELETE_TOOLTIP :{BLACK}Delete the selected group -STR_GROUP_RENAME_TOOLTIP :{BLACK}Rename the selected group -STR_GROUP_REPLACE_PROTECTION_TOOLTIP :{BLACK}Click to protect this group from global autoreplace - -STR_GROUP_ADD_SHARED_VEHICLE :Add shared vehicles -STR_GROUP_REMOVE_ALL_VEHICLES :Remove all vehicles - -STR_GROUP_RENAME_CAPTION :{BLACK}Rename a group - -# Build vehicle window -STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION :New Rail Vehicles -STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :New Electric Rail Vehicles -STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :New Monorail Vehicles -STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :New Maglev Vehicles - -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :New Rail Vehicles -STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :New Road Vehicles -STR_BUY_VEHICLE_SHIP_CAPTION :New Ships -STR_BUY_VEHICLE_AIRCRAFT_CAPTION :New Aircraft - -STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Weight: {GOLD}{WEIGHT_SHORT} -STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Speed: {GOLD}{VELOCITY}{BLACK} Power: {GOLD}{POWER} -STR_PURCHASE_INFO_SPEED :{BLACK}Speed: {GOLD}{VELOCITY} -STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Speed on ocean: {GOLD}{VELOCITY} -STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}Speed on canal/river: {GOLD}{VELOCITY} -STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Running Cost: {GOLD}{CURRENCY_LONG}/yr -STR_PURCHASE_INFO_CAPACITY :{BLACK}Capacity: {GOLD}{CARGO_LONG} {STRING} -STR_PURCHASE_INFO_REFITTABLE :(refittable) -STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Designed: {GOLD}{NUM}{BLACK} Life: {GOLD}{COMMA} year{P "" s} -STR_PURCHASE_INFO_RELIABILITY :{BLACK}Max. Reliability: {GOLD}{COMMA}% -STR_PURCHASE_INFO_COST :{BLACK}Cost: {GOLD}{CURRENCY_LONG} -STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Weight: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) -STR_PURCHASE_INFO_COST_SPEED :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Speed: {GOLD}{VELOCITY} -STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Capacity: {GOLD}{CARGO_LONG}, {CARGO_LONG} -STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Powered Wagons: {GOLD}+{POWER}{BLACK} Weight: {GOLD}+{WEIGHT_SHORT} -STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Refittable to: {GOLD}{STRING2} -STR_PURCHASE_INFO_ALL_TYPES :All cargo types -STR_PURCHASE_INFO_ALL_BUT :All but {CARGO_LIST} -STR_PURCHASE_INFO_MAX_TE :{BLACK}Max. Tractive Effort: {GOLD}{FORCE} -STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Range: {GOLD}{COMMA} tiles - -STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}Train vehicle selection list - click on vehicle for information -STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Road vehicle selection list - click on vehicle for information -STR_BUY_VEHICLE_SHIP_LIST_TOOLTIP :{BLACK}Ship selection list - click on ship for information -STR_BUY_VEHICLE_AIRCRAFT_LIST_TOOLTIP :{BLACK}Aircraft selection list - click on aircraft for information - -STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON :{BLACK}Buy Vehicle -STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Buy Vehicle -STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Buy Ship -STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Buy Aircraft - -STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted train vehicle. Shift+Click shows estimated cost without purchase -STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted road vehicle. Shift+Click shows estimated cost without purchase -STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted ship. Shift+Click shows estimated cost without purchase -STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted aircraft. Shift+Click shows estimated cost without purchase - -STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Rename -STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Rename -STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Rename -STR_BUY_VEHICLE_AIRCRAFT_RENAME_BUTTON :{BLACK}Rename - -STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP :{BLACK}Rename train vehicle type -STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}Rename road vehicle type -STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}Rename ship type -STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}Rename aircraft type - -STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}Rename train vehicle type -STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}Rename road vehicle type -STR_QUERY_RENAME_SHIP_TYPE_CAPTION :{WHITE}Rename ship type -STR_QUERY_RENAME_AIRCRAFT_TYPE_CAPTION :{WHITE}Rename aircraft type - -# Depot window -STR_DEPOT_CAPTION :{WHITE}{DEPOT} - -STR_DEPOT_RENAME_TOOLTIP :{BLACK}Change name of depot -STR_DEPOT_RENAME_DEPOT_CAPTION :Rename depot - -STR_DEPOT_NO_ENGINE :{BLACK}- -STR_DEPOT_VEHICLE_TOOLTIP :{BLACK}{ENGINE}{RAW_STRING} -STR_DEPOT_VEHICLE_TOOLTIP_CHAIN :{BLACK}{NUM} vehicle{P "" s}{RAW_STRING} -STR_DEPOT_VEHICLE_TOOLTIP_CARGO :{}{CARGO_LONG} ({CARGO_SHORT}) - -STR_DEPOT_TRAIN_LIST_TOOLTIP :{BLACK}Trains - drag vehicle with left-click to add/remove from train, right-click for information. Hold Ctrl to make both functions apply to the following chain -STR_DEPOT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Vehicles - right-click on vehicle for information -STR_DEPOT_SHIP_LIST_TOOLTIP :{BLACK}Ships - right-click on ship for information -STR_DEPOT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Aircraft - right-click on aircraft for information - -STR_DEPOT_TRAIN_SELL_TOOLTIP :{BLACK}Drag train vehicle to here to sell it -STR_DEPOT_ROAD_VEHICLE_SELL_TOOLTIP :{BLACK}Drag road vehicle to here to sell it -STR_DEPOT_SHIP_SELL_TOOLTIP :{BLACK}Drag ship to here to sell it -STR_DEPOT_AIRCRAFT_SELL_TOOLTIP :{BLACK}Drag aircraft to here to sell it - -STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP :{BLACK}Drag train engine here to sell the whole train - -STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TOOLTIP :{BLACK}Sell all trains in the depot -STR_DEPOT_SELL_ALL_BUTTON_ROAD_VEHICLE_TOOLTIP :{BLACK}Sell all road vehicles in the depot -STR_DEPOT_SELL_ALL_BUTTON_SHIP_TOOLTIP :{BLACK}Sell all ships in the depot -STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TOOLTIP :{BLACK}Sell all aircraft in the hangar - -STR_DEPOT_AUTOREPLACE_TRAIN_TOOLTIP :{BLACK}Autoreplace all trains in the depot -STR_DEPOT_AUTOREPLACE_ROAD_VEHICLE_TOOLTIP :{BLACK}Autoreplace all road vehicles in the depot -STR_DEPOT_AUTOREPLACE_SHIP_TOOLTIP :{BLACK}Autoreplace all ships in the depot -STR_DEPOT_AUTOREPLACE_AIRCRAFT_TOOLTIP :{BLACK}Autoreplace all aircraft in the hangar - -STR_DEPOT_TRAIN_NEW_VEHICLES_BUTTON :{BLACK}New Vehicles -STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_BUTTON :{BLACK}New Vehicles -STR_DEPOT_SHIP_NEW_VEHICLES_BUTTON :{BLACK}New Ships -STR_DEPOT_AIRCRAFT_NEW_VEHICLES_BUTTON :{BLACK}New Aircraft - -STR_DEPOT_TRAIN_NEW_VEHICLES_TOOLTIP :{BLACK}Buy new train vehicle -STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_TOOLTIP :{BLACK}Buy new road vehicle -STR_DEPOT_SHIP_NEW_VEHICLES_TOOLTIP :{BLACK}Buy new ship -STR_DEPOT_AIRCRAFT_NEW_VEHICLES_TOOLTIP :{BLACK}Buy new aircraft - -STR_DEPOT_CLONE_TRAIN :{BLACK}Clone Train -STR_DEPOT_CLONE_ROAD_VEHICLE :{BLACK}Clone Vehicle -STR_DEPOT_CLONE_SHIP :{BLACK}Clone Ship -STR_DEPOT_CLONE_AIRCRAFT :{BLACK}Clone Aircraft - -STR_DEPOT_CLONE_TRAIN_DEPOT_INFO :{BLACK}This will buy a copy of a train including all cars. Click this button and then on a train inside or outside the depot. Ctrl+Click share the orders. Shift+Click shows estimated cost without purchase -STR_DEPOT_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}This will buy a copy of a road vehicle. Click this button and then on a road vehicle inside or outside the depot. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase -STR_DEPOT_CLONE_SHIP_DEPOT_INFO :{BLACK}This will buy a copy of a ship. Click this button and then on a ship inside or outside the depot. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase -STR_DEPOT_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}This will buy a copy of an aircraft. Click this button and then on an aircraft inside or outside the hangar. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase - -STR_DEPOT_TRAIN_LOCATION_TOOLTIP :{BLACK}Centre main view on train depot location. Ctrl+Click opens a new viewport on train depot location -STR_DEPOT_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Centre main view on road vehicle depot location. Ctrl+Click opens a new viewport on road depot location -STR_DEPOT_SHIP_LOCATION_TOOLTIP :{BLACK}Centre main view on ship depot location. Ctrl+Click opens a new viewport on ship depot location -STR_DEPOT_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Centre main view on hangar location. Ctrl+Click opens a new viewport on hangar location - -STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TOOLTIP :{BLACK}Get a list of all trains with the current depot in their orders -STR_DEPOT_VEHICLE_ORDER_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Get a list of all road vehicles with the current depot in their orders -STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TOOLTIP :{BLACK}Get a list of all ships with the current depot in their orders -STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TOOLTIP :{BLACK}Get a list of all aircraft with any hangar at this airport in their orders - -STR_DEPOT_MASS_STOP_DEPOT_TRAIN_TOOLTIP :{BLACK}Click to stop all the trains inside the depot -STR_DEPOT_MASS_STOP_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Click to stop all the road vehicles inside the depot -STR_DEPOT_MASS_STOP_DEPOT_SHIP_TOOLTIP :{BLACK}Click to stop all the ships inside the depot -STR_DEPOT_MASS_STOP_HANGAR_TOOLTIP :{BLACK}Click to stop all the aircraft inside the hangar - -STR_DEPOT_MASS_START_DEPOT_TRAIN_TOOLTIP :{BLACK}Click to start all the trains inside the depot -STR_DEPOT_MASS_START_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Click to start all the road vehicles inside the depot -STR_DEPOT_MASS_START_DEPOT_SHIP_TOOLTIP :{BLACK}Click to start all the ships inside the depot -STR_DEPOT_MASS_START_HANGAR_TOOLTIP :{BLACK}Click to start all the aircraft inside the hangar - -STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}You are about to sell all the vehicles in the depot. Are you sure? - -# Engine preview window -STR_ENGINE_PREVIEW_CAPTION :{WHITE}Message from vehicle manufacturer -STR_ENGINE_PREVIEW_MESSAGE :{GOLD}We have just designed a new {STRING} - would you be interested in a year's exclusive use of this vehicle, so we can see how it performs before making it universally available? -STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :railway locomotive -STR_ENGINE_PREVIEW_ROAD_VEHICLE :road vehicle -STR_ENGINE_PREVIEW_AIRCRAFT :aircraft -STR_ENGINE_PREVIEW_SHIP :ship -STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monorail locomotive -STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev locomotive - -STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER}{}Running Cost: {CURRENCY_LONG}/yr{}Capacity: {CARGO_LONG} -STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER} Max. T.E.: {6:FORCE}{}Running Cost: {4:CURRENCY_LONG}/yr{}Capacity: {5:CARGO_LONG} -STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY}{}Capacity: {CARGO_LONG}, {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr -STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY}{}Capacity: {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr -STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST:{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY} Range: {COMMA} tiles{}Capacity: {CARGO_LONG}, {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr -STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY} Range: {COMMA} tiles{}Capacity: {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr - -# Autoreplace window -STR_REPLACE_VEHICLES_WHITE :{WHITE}Replace {STRING} - {STRING1} -STR_REPLACE_VEHICLE_TRAIN :Train -STR_REPLACE_VEHICLE_ROAD_VEHICLE :Road Vehicle -STR_REPLACE_VEHICLE_SHIP :Ship -STR_REPLACE_VEHICLE_AIRCRAFT :Aircraft - -STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Select the engine type to replace -STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Select the new engine type you would like to use in place of the left selected engine type - -STR_REPLACE_VEHICLES_START :{BLACK}Start Replacing Vehicles -STR_REPLACE_VEHICLES_NOW :Replace all vehicles now -STR_REPLACE_VEHICLES_WHEN_OLD :Replace only old vehicles -STR_REPLACE_HELP_START_BUTTON :{BLACK}Press to begin replacement of the left selected engine type with the right selected engine type -STR_REPLACE_NOT_REPLACING :{BLACK}Not replacing -STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}No vehicle selected -STR_REPLACE_REPLACING_WHEN_OLD :{ENGINE} when old -STR_REPLACE_VEHICLES_STOP :{BLACK}Stop Replacing Vehicles -STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Press to stop the replacement of the engine type selected on the left - -STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Replacing: {ORANGE}{STRING} -STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Switch between engine and wagon replacement windows -STR_REPLACE_ENGINES :Engines -STR_REPLACE_WAGONS :Wagons - -STR_REPLACE_HELP_RAILTYPE :{BLACK}Choose the rail type you want to replace engines for -STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Displays which engine the left selected engine is being replaced with, if any -STR_REPLACE_RAIL_VEHICLES :Rail Vehicles -STR_REPLACE_ELRAIL_VEHICLES :Electrified Rail Vehicles -STR_REPLACE_MONORAIL_VEHICLES :Monorail Vehicles -STR_REPLACE_MAGLEV_VEHICLES :Maglev Vehicles - -STR_REPLACE_REMOVE_WAGON :{BLACK}Wagon removal: {ORANGE}{STRING} -STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Make autoreplace keep the length of a train the same by removing wagons (starting at the front), if replacing the engine would make the train longer - -# Vehicle view -STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} - -STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP :{BLACK}Centre main view on train's location. Ctrl+Click will follow train in main view -STR_VEHICLE_VIEW_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Centre main view on vehicle's location. Ctrl+Click will follow vehicle in main view -STR_VEHICLE_VIEW_SHIP_LOCATION_TOOLTIP :{BLACK}Centre main view on ship's location. Ctrl+Click will follow ship in main view -STR_VEHICLE_VIEW_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Centre main view on aircraft's location. Ctrl+Click will follow aircraft in main view - -STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send train to depot. Ctrl+Click will only service -STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send vehicle to depot. Ctrl+Click will only service -STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send ship to depot. Ctrl+Click will only service -STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send aircraft to hangar. Ctrl+Click will only service - -STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}This will buy a copy of the train including all cars. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase -STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}This will buy a copy of the road vehicle. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase -STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}This will buy a copy of the ship. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase -STR_VEHICLE_VIEW_CLONE_AIRCRAFT_INFO :{BLACK}This will buy a copy of the aircraft. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase - -STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP :{BLACK}Force train to proceed without waiting for signal to clear it - -STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP :{BLACK}Refit train to carry a different cargo type -STR_VEHICLE_VIEW_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Refit road vehicle to carry a different cargo type -STR_VEHICLE_VIEW_SHIP_REFIT_TOOLTIP :{BLACK}Refit ship to carry a different cargo type -STR_VEHICLE_VIEW_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Refit aircraft to carry a different cargo type - -STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP :{BLACK}Reverse direction of train -STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP :{BLACK}Force vehicle to turn around - -STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP :{BLACK}Show train's orders. Ctrl+Click to show train's timetable -STR_VEHICLE_VIEW_ROAD_VEHICLE_ORDERS_TOOLTIP :{BLACK}Show vehicle's orders. Ctrl+Click to show vehicle's timetable -STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Show ship's orders. Ctrl+Click to show ship's timetable -STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Show aircraft's orders. Ctrl+Click to show aircraft's timetable - -STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Show train details -STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Show road vehicle details -STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Show ship details -STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Show aircraft details - -STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP :{BLACK}Current train action - click to stop/start train. Ctrl+Click to scroll to destination -STR_VEHICLE_VIEW_ROAD_VEHICLE_STATE_START_STOP_TOOLTIP :{BLACK}Current vehicle action - click to stop/start vehicle. Ctrl+Click to scroll to destination -STR_VEHICLE_VIEW_SHIP_STATE_START_STOP_TOOLTIP :{BLACK}Current ship action - click to stop/start ship. Ctrl+Click to scroll to destination -STR_VEHICLE_VIEW_AIRCRAFT_STATE_START_STOP_TOOLTIP :{BLACK}Current aircraft action - click to stop/start aircraft. Ctrl+Click to scroll to destination - -# Messages in the start stop button in the vehicle view -STR_VEHICLE_STATUS_LOADING_UNLOADING :{LTBLUE}Loading / Unloading -STR_VEHICLE_STATUS_LEAVING :{LTBLUE}Leaving -STR_VEHICLE_STATUS_CRASHED :{RED}Crashed! -STR_VEHICLE_STATUS_BROKEN_DOWN :{RED}Broken down -STR_VEHICLE_STATUS_STOPPED :{RED}Stopped -STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}Stopping, {VELOCITY} -STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}No power -STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}Waiting for free path -STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}Too far to next destination - -STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL :{LTBLUE}Heading for {STATION}, {VELOCITY} -STR_VEHICLE_STATUS_NO_ORDERS_VEL :{LTBLUE}No orders, {VELOCITY} -STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL :{LTBLUE}Heading for {WAYPOINT}, {VELOCITY} -STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL :{ORANGE}Heading for {DEPOT}, {VELOCITY} -STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL :{LTBLUE}Service at {DEPOT}, {VELOCITY} - -# Vehicle stopped/started animations -STR_VEHICLE_COMMAND_STOPPED_SMALL :{TINY_FONT}{RED}Stopped -STR_VEHICLE_COMMAND_STOPPED :{RED}Stopped -STR_VEHICLE_COMMAND_STARTED_SMALL :{TINY_FONT}{GREEN}Started -STR_VEHICLE_COMMAND_STARTED :{GREEN}Started - -# Vehicle details -STR_VEHICLE_DETAILS_CAPTION :{WHITE}{VEHICLE} (Details) -STR_VEHICLE_NAME_BUTTON :{BLACK}Name - -STR_VEHICLE_DETAILS_TRAIN_RENAME :{BLACK}Name train -STR_VEHICLE_DETAILS_ROAD_VEHICLE_RENAME :{BLACK}Name road vehicle -STR_VEHICLE_DETAILS_SHIP_RENAME :{BLACK}Name ship -STR_VEHICLE_DETAILS_AIRCRAFT_RENAME :{BLACK}Name aircraft - -STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}Age: {LTBLUE}{STRING2}{BLACK} Running Cost: {LTBLUE}{CURRENCY_LONG}/yr -# The next two need to stay in this order -STR_VEHICLE_INFO_AGE :{COMMA} year{P "" s} ({COMMA}) -STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} year{P "" s} ({COMMA}) - -STR_VEHICLE_INFO_MAX_SPEED :{BLACK}Max. speed: {LTBLUE}{VELOCITY} -STR_VEHICLE_INFO_MAX_SPEED_RANGE :{BLACK}Max. speed: {LTBLUE}{VELOCITY} {BLACK}Range: {LTBLUE}{COMMA} tiles -STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Weight: {LTBLUE}{WEIGHT_SHORT} {BLACK}Power: {LTBLUE}{POWER}{BLACK} Max. speed: {LTBLUE}{VELOCITY} -STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Weight: {LTBLUE}{WEIGHT_SHORT} {BLACK}Power: {LTBLUE}{POWER}{BLACK} Max. speed: {LTBLUE}{VELOCITY} {BLACK}Max. T.E.: {LTBLUE}{FORCE} - -STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Profit this year: {LTBLUE}{CURRENCY_LONG} (last year: {CURRENCY_LONG}) -STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Reliability: {LTBLUE}{COMMA}% {BLACK}Breakdowns since last service: {LTBLUE}{COMMA} - -STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} -STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}Capacity: {LTBLUE}None{STRING} -STR_VEHICLE_INFO_CAPACITY :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}{3:STRING} -STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM}) -STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}, {CARGO_LONG}{STRING} - -STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}Transfer Credits: {LTBLUE}{CURRENCY_LONG} - -STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}Servicing interval: {LTBLUE}{COMMA}days{BLACK} Last service: {LTBLUE}{DATE_LONG} -STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}Servicing interval: {LTBLUE}{COMMA}%{BLACK} Last service: {LTBLUE}{DATE_LONG} -STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Increase servicing interval by 10. Ctrl+Click increases servicing interval by 5 -STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Decrease servicing interval by 10. Ctrl+Click decreases servicing interval by 5 - -STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}Change servicing interval type -STR_VEHICLE_DETAILS_DEFAULT :Default -STR_VEHICLE_DETAILS_DAYS :Days -STR_VEHICLE_DETAILS_PERCENT :Percentage - -STR_QUERY_RENAME_TRAIN_CAPTION :{WHITE}Name train -STR_QUERY_RENAME_ROAD_VEHICLE_CAPTION :{WHITE}Name road vehicle -STR_QUERY_RENAME_SHIP_CAPTION :{WHITE}Name ship -STR_QUERY_RENAME_AIRCRAFT_CAPTION :{WHITE}Name aircraft - -# Extra buttons for train details windows -STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE :{LTBLUE}{ENGINE}{BLACK} Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} -STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE :{LTBLUE}{ENGINE}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} - -STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT :{BLACK}Total cargo capacity of this train: -STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) -STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) (x{NUM}) - -STR_VEHICLE_DETAILS_CARGO_EMPTY :{LTBLUE}Empty -STR_VEHICLE_DETAILS_CARGO_FROM :{LTBLUE}{CARGO_LONG} from {STATION} -STR_VEHICLE_DETAILS_CARGO_FROM_MULT :{LTBLUE}{CARGO_LONG} from {STATION} (x{NUM}) - -STR_VEHICLE_DETAIL_TAB_CARGO :{BLACK}Cargo -STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP :{BLACK}Show details of cargo carried -STR_VEHICLE_DETAIL_TAB_INFORMATION :{BLACK}Information -STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP :{BLACK}Show details of train vehicles -STR_VEHICLE_DETAIL_TAB_CAPACITIES :{BLACK}Capacities -STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP :{BLACK}Show capacities of each vehicle -STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO :{BLACK}Total Cargo -STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP :{BLACK}Show total capacity of train, split by cargo type - -STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}Capacity: {LTBLUE} - -# Vehicle refit -STR_REFIT_CAPTION :{WHITE}{VEHICLE} (Refit) -STR_REFIT_TITLE :{GOLD}Select cargo type to carry: -STR_REFIT_NEW_CAPACITY_COST_OF_REFIT :{BLACK}New capacity: {GOLD}{CARGO_LONG}{}{BLACK}Cost of refit: {RED}{CURRENCY_LONG} -STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT :{BLACK}New capacity: {GOLD}{CARGO_LONG}{}{BLACK}Income from refit: {GREEN}{CURRENCY_LONG} -STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}New capacity: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Cost of refit: {RED}{CURRENCY_LONG} -STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT :{BLACK}New capacity: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Income from refit: {GREEN}{CURRENCY_LONG} -STR_REFIT_SELECT_VEHICLES_TOOLTIP :{BLACK}Select the vehicles to refit. Dragging with the mouse allows to select multiple vehicles. Clicking on an empty space will select the whole vehicle. Ctrl+Click will select a vehicle and the following chain - -STR_REFIT_TRAIN_LIST_TOOLTIP :{BLACK}Select type of cargo for train to carry -STR_REFIT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Select type of cargo for road vehicle to carry -STR_REFIT_SHIP_LIST_TOOLTIP :{BLACK}Select type of cargo for ship to carry -STR_REFIT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Select type of cargo for aircraft to carry - -STR_REFIT_TRAIN_REFIT_BUTTON :{BLACK}Refit train -STR_REFIT_ROAD_VEHICLE_REFIT_BUTTON :{BLACK}Refit road vehicle -STR_REFIT_SHIP_REFIT_BUTTON :{BLACK}Refit ship -STR_REFIT_AIRCRAFT_REFIT_BUTTON :{BLACK}Refit aircraft - -STR_REFIT_TRAIN_REFIT_TOOLTIP :{BLACK}Refit train to carry highlighted cargo type -STR_REFIT_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Refit road vehicle to carry highlighted cargo type -STR_REFIT_SHIP_REFIT_TOOLTIP :{BLACK}Refit ship to carry highlighted cargo type -STR_REFIT_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Refit aircraft to carry highlighted cargo type - -# Order view -STR_ORDERS_CAPTION :{WHITE}{VEHICLE} (Orders) -STR_ORDERS_TIMETABLE_VIEW :{BLACK}Timetable -STR_ORDERS_TIMETABLE_VIEW_TOOLTIP :{BLACK}Switch to the timetable view - -STR_ORDERS_LIST_TOOLTIP :{BLACK}Order list - click on an order to highlight it. Ctrl+Click scrolls to the order's destination -STR_ORDER_INDEX :{COMMA}:{NBSP} -STR_ORDER_TEXT :{STRING4} {STRING2} {STRING} - -STR_ORDERS_END_OF_ORDERS :- - End of Orders - - -STR_ORDERS_END_OF_SHARED_ORDERS :- - End of Shared Orders - - - -# Order bottom buttons -STR_ORDER_NON_STOP :{BLACK}Non-stop -STR_ORDER_GO_TO :Go to -STR_ORDER_GO_NON_STOP_TO :Go non-stop to -STR_ORDER_GO_VIA :Go via -STR_ORDER_GO_NON_STOP_VIA :Go non-stop via -STR_ORDER_TOOLTIP_NON_STOP :{BLACK}Change the stopping behaviour of the highlighted order - -STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}Full load any cargo -STR_ORDER_DROP_LOAD_IF_POSSIBLE :Load if available -STR_ORDER_DROP_FULL_LOAD_ALL :Full load all cargo -STR_ORDER_DROP_FULL_LOAD_ANY :Full load any cargo -STR_ORDER_DROP_NO_LOADING :No loading -STR_ORDER_TOOLTIP_FULL_LOAD :{BLACK}Change the loading behaviour of the highlighted order - -STR_ORDER_TOGGLE_UNLOAD :{BLACK}Unload all -STR_ORDER_DROP_UNLOAD_IF_ACCEPTED :Unload if accepted -STR_ORDER_DROP_UNLOAD :Unload all -STR_ORDER_DROP_TRANSFER :Transfer -STR_ORDER_DROP_NO_UNLOADING :No unloading -STR_ORDER_TOOLTIP_UNLOAD :{BLACK}Change the unloading behaviour of the highlighted order - -STR_ORDER_REFIT :{BLACK}Refit -STR_ORDER_REFIT_TOOLTIP :{BLACK}Select what cargo type to refit to in this order. Ctrl+Click to remove refit instruction -STR_ORDER_REFIT_AUTO :{BLACK}Auto-refit -STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}Select what cargo type to auto-refit to in this order. Ctrl+Click to remove refit instruction. Auto-refitting will only be done if the vehicle allows it -STR_ORDER_DROP_REFIT_AUTO :Fixed cargo -STR_ORDER_DROP_REFIT_AUTO_ANY :Available cargo - -STR_ORDER_SERVICE :{BLACK}Service -STR_ORDER_DROP_GO_ALWAYS_DEPOT :Always go -STR_ORDER_DROP_SERVICE_DEPOT :Service if needed -STR_ORDER_DROP_HALT_DEPOT :Stop -STR_ORDER_SERVICE_TOOLTIP :{BLACK}Skip this order unless a service is needed - -STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP :{BLACK}Vehicle data to base jumping on - -# Conditional order variables, must follow order of OrderConditionVariable enum -STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE :Load percentage -STR_ORDER_CONDITIONAL_RELIABILITY :Reliability -STR_ORDER_CONDITIONAL_MAX_SPEED :Maximum speed -STR_ORDER_CONDITIONAL_AGE :Age (years) -STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :Requires service -STR_ORDER_CONDITIONAL_UNCONDITIONALLY :Always -STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :Remaining lifetime (years) - -STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}How to compare the vehicle data to the given value -STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :is equal to -STR_ORDER_CONDITIONAL_COMPARATOR_NOT_EQUALS :is not equal to -STR_ORDER_CONDITIONAL_COMPARATOR_LESS_THAN :is less than -STR_ORDER_CONDITIONAL_COMPARATOR_LESS_EQUALS :is less or equal to -STR_ORDER_CONDITIONAL_COMPARATOR_MORE_THAN :is more than -STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS :is more or equal to -STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE :is true -STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE :is false - -STR_ORDER_CONDITIONAL_VALUE_TOOLTIP :{BLACK}The value to compare the vehicle data against -STR_ORDER_CONDITIONAL_VALUE_CAPT :{WHITE}Enter value to compare against - -STR_ORDERS_SKIP_BUTTON :{BLACK}Skip -STR_ORDERS_SKIP_TOOLTIP :{BLACK}Skip the current order, and start the next. Ctrl+Click skips to the selected order - -STR_ORDERS_DELETE_BUTTON :{BLACK}Delete -STR_ORDERS_DELETE_TOOLTIP :{BLACK}Delete the highlighted order -STR_ORDERS_DELETE_ALL_TOOLTIP :{BLACK}Delete all orders -STR_ORDERS_STOP_SHARING_BUTTON :{BLACK}Stop sharing -STR_ORDERS_STOP_SHARING_TOOLTIP :{BLACK}Stop sharing the order list. Ctrl+Click additionally deletes all orders for this vehicle - -STR_ORDERS_GO_TO_BUTTON :{BLACK}Go To -STR_ORDER_GO_TO_NEAREST_DEPOT :Go to nearest depot -STR_ORDER_GO_TO_NEAREST_HANGAR :Go to nearest hangar -STR_ORDER_CONDITIONAL :Conditional order jump -STR_ORDER_SHARE :Share orders -STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Insert a new order before the highlighted order, or add to end of list. Ctrl makes station orders 'full load any cargo', waypoint orders 'non-stop' and depot orders 'service'. 'Share orders' or Ctrl lets this vehicle share orders with the selected vehicle. Clicking a vehicle copies the orders from that vehicle. A depot order disables automatic servicing of the vehicle - -STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Show all vehicles that share this schedule - -# String parts to build the order string -STR_ORDER_GO_TO_WAYPOINT :Go via {WAYPOINT} -STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Go non-stop via {WAYPOINT} - -STR_ORDER_SERVICE_AT :Service at -STR_ORDER_SERVICE_NON_STOP_AT :Service non-stop at - -STR_ORDER_NEAREST_DEPOT :the nearest -STR_ORDER_NEAREST_HANGAR :the nearest Hangar -STR_ORDER_TRAIN_DEPOT :Train Depot -STR_ORDER_ROAD_VEHICLE_DEPOT :Road Vehicle Depot -STR_ORDER_SHIP_DEPOT :Ship Depot -STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} {STRING} {STRING} -STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} - -STR_ORDER_REFIT_ORDER :(Refit to {STRING}) -STR_ORDER_REFIT_STOP_ORDER :(Refit to {STRING} and stop) -STR_ORDER_STOP_ORDER :(Stop) - -STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING} - -STR_ORDER_IMPLICIT :(Implicit) - -STR_ORDER_FULL_LOAD :(Full load) -STR_ORDER_FULL_LOAD_ANY :(Full load any cargo) -STR_ORDER_NO_LOAD :(No loading) -STR_ORDER_UNLOAD :(Unload and take cargo) -STR_ORDER_UNLOAD_FULL_LOAD :(Unload and wait for full load) -STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Unload and wait for any full load) -STR_ORDER_UNLOAD_NO_LOAD :(Unload and leave empty) -STR_ORDER_TRANSFER :(Transfer and take cargo) -STR_ORDER_TRANSFER_FULL_LOAD :(Transfer and wait for full load) -STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Transfer and wait for any full load) -STR_ORDER_TRANSFER_NO_LOAD :(Transfer and leave empty) -STR_ORDER_NO_UNLOAD :(No unloading and take cargo) -STR_ORDER_NO_UNLOAD_FULL_LOAD :(No unloading and wait for full load) -STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(No unloading and wait for any full load) -STR_ORDER_NO_UNLOAD_NO_LOAD :(No unloading and no loading) - -STR_ORDER_AUTO_REFIT :(Auto-refit to {STRING}) -STR_ORDER_FULL_LOAD_REFIT :(Full load with auto-refit to {STRING}) -STR_ORDER_FULL_LOAD_ANY_REFIT :(Full load any cargo with auto-refit to {STRING}) -STR_ORDER_UNLOAD_REFIT :(Unload and take cargo with auto-refit to {STRING}) -STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Unload and wait for full load with auto-refit to {STRING}) -STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Unload and wait for any full load with auto-refit to {STRING}) -STR_ORDER_TRANSFER_REFIT :(Transfer and take cargo with auto-refit to {STRING}) -STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Transfer and wait for full load with auto-refit to {STRING}) -STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Transfer and wait for any full load with auto-refit to {STRING}) -STR_ORDER_NO_UNLOAD_REFIT :(No unloading and take cargo with auto-refit to {STRING}) -STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(No unloading and wait for full load with auto-refit to {STRING}) -STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(No unloading and wait for any full load with auto-refit to {STRING}) - -STR_ORDER_AUTO_REFIT_ANY :available cargo - -STR_ORDER_STOP_LOCATION_NEAR_END :[near end] -STR_ORDER_STOP_LOCATION_MIDDLE :[middle] -STR_ORDER_STOP_LOCATION_FAR_END :[far end] - -STR_ORDER_OUT_OF_RANGE :{RED} (Next destination is out of range) - -STR_ORDER_CONDITIONAL_UNCONDITIONAL :Jump to order {COMMA} -STR_ORDER_CONDITIONAL_NUM :Jump to order {COMMA} when {STRING} {STRING} {COMMA} -STR_ORDER_CONDITIONAL_TRUE_FALSE :Jump to order {COMMA} when {STRING} {STRING} - -STR_INVALID_ORDER :{RED} (Invalid Order) - -# Time table window -STR_TIMETABLE_TITLE :{WHITE}{VEHICLE} (Timetable) -STR_TIMETABLE_ORDER_VIEW :{BLACK}Orders -STR_TIMETABLE_ORDER_VIEW_TOOLTIP :{BLACK}Switch to the order view - -STR_TIMETABLE_TOOLTIP :{BLACK}Timetable - click on an order to highlight it - -STR_TIMETABLE_NO_TRAVEL :No travel -STR_TIMETABLE_NOT_TIMETABLEABLE :Travel (automatic; timetabled by next manual order) -STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Travel (not timetabled) -STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Travel with at most {2:VELOCITY} (not timetabled) -STR_TIMETABLE_TRAVEL_FOR :Travel for {STRING1} -STR_TIMETABLE_TRAVEL_FOR_SPEED :Travel for {STRING1} with at most {VELOCITY} -STR_TIMETABLE_STAY_FOR :and stay for {STRING1} -STR_TIMETABLE_AND_TRAVEL_FOR :and travel for {STRING1} -STR_TIMETABLE_DAYS :{COMMA} day{P "" s} -STR_TIMETABLE_TICKS :{COMMA} tick{P "" s} - -STR_TIMETABLE_TOTAL_TIME :{BLACK}This timetable will take {STRING1} to complete -STR_TIMETABLE_TOTAL_TIME_INCOMPLETE :{BLACK}This timetable will take at least {STRING1} to complete (not all timetabled) - -STR_TIMETABLE_STATUS_ON_TIME :{BLACK}This vehicle is currently running on time -STR_TIMETABLE_STATUS_LATE :{BLACK}This vehicle is currently running {STRING1} late -STR_TIMETABLE_STATUS_EARLY :{BLACK}This vehicle is currently running {STRING1} early -STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}This timetable has not yet started -STR_TIMETABLE_STATUS_START_AT :{BLACK}This timetable will start at {STRING1} - -STR_TIMETABLE_STARTING_DATE :{BLACK}Start date -STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Select a date as starting point of this timetable. Ctrl+Click sets the starting point of this timetable and distributes all vehicles sharing this order evenly based on their relative order, if the order is completely timetabled - -STR_TIMETABLE_CHANGE_TIME :{BLACK}Change Time -STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Change the amount of time that the highlighted order should take - -STR_TIMETABLE_CLEAR_TIME :{BLACK}Clear Time -STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Clear the amount of time for the highlighted order - -STR_TIMETABLE_CHANGE_SPEED :{BLACK}Change Speed Limit -STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Change the maximum travel speed of the highlighted order - -STR_TIMETABLE_CLEAR_SPEED :{BLACK}Clear Speed Limit -STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Clear the maximum travel speed of the highlighted order - -STR_TIMETABLE_RESET_LATENESS :{BLACK}Reset Late Counter -STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Reset the lateness counter, so the vehicle will be on time - -STR_TIMETABLE_AUTOFILL :{BLACK}Autofill -STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the timetable automatically with the values from the next journey (Ctrl+Click to try to keep waiting times) - -STR_TIMETABLE_EXPECTED :{BLACK}Expected -STR_TIMETABLE_SCHEDULED :{BLACK}Scheduled -STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Switch between expected and scheduled - -STR_TIMETABLE_ARRIVAL_ABBREVIATION :A: -STR_TIMETABLE_DEPARTURE_ABBREVIATION :D: - - -# Date window (for timetable) -STR_DATE_CAPTION :{WHITE}Set date -STR_DATE_SET_DATE :{BLACK}Set date -STR_DATE_SET_DATE_TOOLTIP :{BLACK}Use the selected date as starting date for the timetable -STR_DATE_DAY_TOOLTIP :{BLACK}Select day -STR_DATE_MONTH_TOOLTIP :{BLACK}Select month -STR_DATE_YEAR_TOOLTIP :{BLACK}Select year - - -# AI debug window -STR_AI_DEBUG :{WHITE}AI/Game Script Debug -STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{RAW_STRING} (v{NUM}) -STR_AI_DEBUG_NAME_TOOLTIP :{BLACK}Name of the script -STR_AI_DEBUG_SETTINGS :{BLACK}Settings -STR_AI_DEBUG_SETTINGS_TOOLTIP :{BLACK}Change the settings of the script -STR_AI_DEBUG_RELOAD :{BLACK}Reload AI -STR_AI_DEBUG_RELOAD_TOOLTIP :{BLACK}Kill the AI, reload the script, and restart the AI -STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK}Enable/disable breaking when an AI log message matches the break string -STR_AI_DEBUG_BREAK_ON_LABEL :{BLACK}Break on: -STR_AI_DEBUG_BREAK_STR_OSKTITLE :{BLACK}Break on -STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}When an AI log message matches this string, the game is paused -STR_AI_DEBUG_MATCH_CASE :{BLACK}Match case -STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Toggle matching case when comparing AI log messages against the break string -STR_AI_DEBUG_CONTINUE :{BLACK}Continue -STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Unpause and continue the AI -STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}View debug output of this AI -STR_AI_GAME_SCRIPT :{BLACK}Game Script -STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Check the Game Script log - -STR_ERROR_AI_NO_AI_FOUND :No suitable AI found to load.{}This AI is a dummy AI and won't do anything.{}You can download several AIs via the 'Online Content' system -STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}One of the running scripts crashed. Please report this to the script author with a screenshot of the AI/Game Script Debug Window -STR_ERROR_AI_DEBUG_SERVER_ONLY :{YELLOW}AI/Game Script Debug window is only available for the server - -# AI configuration window -STR_AI_CONFIG_CAPTION :{WHITE}AI/Game Script Configuration -STR_AI_CONFIG_GAMELIST_TOOLTIP :{BLACK}The Game Script that will be loaded in the next game -STR_AI_CONFIG_AILIST_TOOLTIP :{BLACK}The AIs that will be loaded in the next game -STR_AI_CONFIG_HUMAN_PLAYER :Human player -STR_AI_CONFIG_RANDOM_AI :Random AI -STR_AI_CONFIG_NONE :(none) - -STR_AI_CONFIG_MOVE_UP :{BLACK}Move Up -STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}Move selected AI up in the list -STR_AI_CONFIG_MOVE_DOWN :{BLACK}Move Down -STR_AI_CONFIG_MOVE_DOWN_TOOLTIP :{BLACK}Move selected AI down in the list - -STR_AI_CONFIG_GAMESCRIPT :{SILVER}Game Script -STR_AI_CONFIG_AI :{SILVER}AIs - -STR_AI_CONFIG_CHANGE :{BLACK}Select {STRING} -STR_AI_CONFIG_CHANGE_NONE : -STR_AI_CONFIG_CHANGE_AI :AI -STR_AI_CONFIG_CHANGE_GAMESCRIPT :Game Script -STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}Load another script -STR_AI_CONFIG_CONFIGURE :{BLACK}Configure -STR_AI_CONFIG_CONFIGURE_TOOLTIP :{BLACK}Configure the parameters of the Script - -# Available AIs window -STR_AI_LIST_CAPTION :{WHITE}Available {STRING} -STR_AI_LIST_CAPTION_AI :AIs -STR_AI_LIST_CAPTION_GAMESCRIPT :Game Scripts -STR_AI_LIST_TOOLTIP :{BLACK}Click to select a script - -STR_AI_LIST_AUTHOR :{LTBLUE}Author: {ORANGE}{RAW_STRING} -STR_AI_LIST_VERSION :{LTBLUE}Version: {ORANGE}{NUM} -STR_AI_LIST_URL :{LTBLUE}URL: {ORANGE}{RAW_STRING} - -STR_AI_LIST_ACCEPT :{BLACK}Accept -STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}Select highlighted script -STR_AI_LIST_CANCEL :{BLACK}Cancel -STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Don't change the script - -# AI Parameters -STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parameters -STR_AI_SETTINGS_CAPTION_AI :AI -STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Game Script -STR_AI_SETTINGS_CLOSE :{BLACK}Close -STR_AI_SETTINGS_RESET :{BLACK}Reset -STR_AI_SETTINGS_SETTING :{RAW_STRING}: {ORANGE}{STRING1} -STR_AI_SETTINGS_START_DELAY :Number of days to start this AI after the previous one (give or take): {ORANGE}{STRING1} - - -# Textfile window -STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme of {RAW_STRING} -STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} changelog of {RAW_STRING} -STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licence of {RAW_STRING} -STR_TEXTFILE_WRAP_TEXT :{WHITE}Wrap text -STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Wrap the text of the window so it all fits without having to scroll -STR_TEXTFILE_VIEW_README :{BLACK}View readme -STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Changelog -STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licence - - -# Vehicle loading indicators -STR_PERCENT_UP_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW} -STR_PERCENT_UP :{WHITE}{NUM}%{UP_ARROW} -STR_PERCENT_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{DOWN_ARROW} -STR_PERCENT_DOWN :{WHITE}{NUM}%{DOWN_ARROW} -STR_PERCENT_UP_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} -STR_PERCENT_UP_DOWN :{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} -STR_PERCENT_NONE_SMALL :{TINY_FONT}{WHITE}{NUM}% -STR_PERCENT_NONE :{WHITE}{NUM}% - -# Income 'floats' -STR_INCOME_FLOAT_COST_SMALL :{TINY_FONT}{RED}Cost: {CURRENCY_LONG} -STR_INCOME_FLOAT_COST :{RED}Cost: {CURRENCY_LONG} -STR_INCOME_FLOAT_INCOME_SMALL :{TINY_FONT}{GREEN}Income: {CURRENCY_LONG} -STR_INCOME_FLOAT_INCOME :{GREEN}Income: {CURRENCY_LONG} -STR_FEEDER_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG} -STR_FEEDER :{YELLOW}Transfer: {CURRENCY_LONG} -STR_FEEDER_INCOME_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {GREEN}Income: {CURRENCY_LONG} -STR_FEEDER_INCOME :{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {GREEN}Income: {CURRENCY_LONG} -STR_FEEDER_COST_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {RED}Cost: {CURRENCY_LONG} -STR_FEEDER_COST :{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {RED}Cost: {CURRENCY_LONG} -STR_MESSAGE_ESTIMATED_COST :{WHITE}Estimated Cost: {CURRENCY_LONG} -STR_MESSAGE_ESTIMATED_INCOME :{WHITE}Estimated Income: {CURRENCY_LONG} - -# Saveload messages -STR_ERROR_SAVE_STILL_IN_PROGRESS :{WHITE}Saving still in progress,{}please wait until it is finished! -STR_ERROR_AUTOSAVE_FAILED :{WHITE}Autosave failed -STR_ERROR_UNABLE_TO_READ_DRIVE :{BLACK}Unable to read drive -STR_ERROR_GAME_SAVE_FAILED :{WHITE}Game Save Failed{}{STRING} -STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}Unable to delete file -STR_ERROR_GAME_LOAD_FAILED :{WHITE}Game Load Failed{}{STRING} -STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR :Internal error: {RAW_STRING} -STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Broken savegame - {RAW_STRING} -STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Savegame is made with newer version -STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :File not readable -STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :File not writeable -STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Data integrity check failed -STR_GAME_SAVELOAD_NOT_AVAILABLE : -STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Game was saved in version without tram support. All trams have been removed - -# Map generation messages -STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Map generation aborted...{}... no suitable town locations -STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... there is no town in this scenario - -STR_ERROR_PNGMAP :{WHITE}Can't load landscape from PNG... -STR_ERROR_PNGMAP_FILE_NOT_FOUND :{WHITE}... file not found -STR_ERROR_PNGMAP_IMAGE_TYPE :{WHITE}... could not convert image type. 8 or 24-bit PNG image needed -STR_ERROR_PNGMAP_MISC :{WHITE}... something just went wrong (probably corrupted file) - -STR_ERROR_BMPMAP :{WHITE}Can't load landscape from BMP... -STR_ERROR_BMPMAP_IMAGE_TYPE :{WHITE}... could not convert image type - -STR_ERROR_HEIGHTMAP_TOO_LARGE :{WHITE}... image is too large - -STR_WARNING_HEIGHTMAP_SCALE_CAPTION :{WHITE}Scale warning -STR_WARNING_HEIGHTMAP_SCALE_MESSAGE :{YELLOW}Resizing source map too much is not recommended. Continue with the generation? - -# Soundset messages -STR_WARNING_FALLBACK_SOUNDSET :{WHITE}Only a fallback sound set was found. If you want sounds, install a sound set via the content download system - -# Screenshot related messages -STR_WARNING_SCREENSHOT_SIZE_CAPTION :{WHITE}Huge screenshot -STR_WARNING_SCREENSHOT_SIZE_MESSAGE :{YELLOW}The screenshot will have a resolution of {COMMA} x {COMMA} pixels. Taking the screenshot may take a while. Do you want to continue? - -STR_MESSAGE_SCREENSHOT_SUCCESSFULLY :{WHITE}Screenshot successfully saved as '{RAW_STRING}' -STR_ERROR_SCREENSHOT_FAILED :{WHITE}Screenshot failed! - -# Error message titles -STR_ERROR_MESSAGE_CAPTION :{YELLOW}Message -STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}Message from {STRING1} - -# Generic construction errors -STR_ERROR_OFF_EDGE_OF_MAP :{WHITE}Off edge of map -STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}Too close to edge of map -STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY :{WHITE}Not enough cash - requires {CURRENCY_LONG} -STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Flat land required -STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Land sloped in wrong direction -STR_ERROR_CAN_T_DO_THIS :{WHITE}Can't do this... -STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Building must be demolished first -STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Can't clear this area... -STR_ERROR_SITE_UNSUITABLE :{WHITE}... site unsuitable -STR_ERROR_ALREADY_BUILT :{WHITE}... already built -STR_ERROR_OWNED_BY :{WHITE}... owned by {STRING2} -STR_ERROR_AREA_IS_OWNED_BY_ANOTHER :{WHITE}... area is owned by another company -STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... landscaping limit reached -STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... tile clearing limit reached -STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... tree planting limit reached -STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Name must be unique -STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} in the way -STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Not allowed while paused - -# Local authority errors -STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS :{WHITE}{TOWN} local authority refuses to allow this -STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT :{WHITE}{TOWN} local authority refuses to allow another airport to be built in this town -STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE :{WHITE}{TOWN} local authority refuses permission for airport due to noise concerns -STR_ERROR_BRIBE_FAILED :{WHITE}Your attempted bribe has been discovered by a regional investigator - -# Levelling errors -STR_ERROR_CAN_T_RAISE_LAND_HERE :{WHITE}Can't raise land here... -STR_ERROR_CAN_T_LOWER_LAND_HERE :{WHITE}Can't lower land here... -STR_ERROR_CAN_T_LEVEL_LAND_HERE :{WHITE}Can't level land here... -STR_ERROR_EXCAVATION_WOULD_DAMAGE :{WHITE}Excavation would damage tunnel -STR_ERROR_ALREADY_AT_SEA_LEVEL :{WHITE}... already at sea level -STR_ERROR_TOO_HIGH :{WHITE}... too high -STR_ERROR_ALREADY_LEVELLED :{WHITE}... already flat - -# Company related errors -STR_ERROR_CAN_T_CHANGE_COMPANY_NAME :{WHITE}Can't change company name... -STR_ERROR_CAN_T_CHANGE_PRESIDENT :{WHITE}Can't change manager's name... - -STR_ERROR_MAXIMUM_PERMITTED_LOAN :{WHITE}... maximum permitted loan size is {CURRENCY_LONG} -STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY :{WHITE}Can't borrow any more money... -STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}... no loan to repay -STR_ERROR_CURRENCY_REQUIRED :{WHITE}... {CURRENCY_LONG} required -STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}Can't repay loan... -STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}Can't give away money that is loaned from the bank... -STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}Can't buy company... -STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Can't build company headquarters... -STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Can't buy 25% share in this company... -STR_ERROR_CAN_T_SELL_25_SHARE_IN :{WHITE}Can't sell 25% share in this company... -STR_ERROR_PROTECTED :{WHITE}This company is not old enough to trade shares yet... - -# Town related errors -STR_ERROR_CAN_T_GENERATE_TOWN :{WHITE}Can't build any towns -STR_ERROR_CAN_T_RENAME_TOWN :{WHITE}Can't rename town... -STR_ERROR_CAN_T_FOUND_TOWN_HERE :{WHITE}Can't found town here... -STR_ERROR_CAN_T_EXPAND_TOWN :{WHITE}Can't expand town... -STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB :{WHITE}... too close to edge of map -STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... too close to another town -STR_ERROR_TOO_MANY_TOWNS :{WHITE}... too many towns -STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... there is no more space on the map -STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS :{WHITE}The town will not build roads. You can enable building of roads via Advanced Settings->Economy->Towns -STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Road works in progress -STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Can't delete this town...{}A station or depot is referring to the town or a town owned tile can't be removed -STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... there is no suitable place for a statue in the centre of this town - -# Industry related errors -STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... too many industries -STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Can't generate industries... -STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Can't build {STRING} here... -STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Can't construct this industry type here... -STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... too close to another industry -STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... must found town first -STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... only one allowed per town -STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 :{WHITE}... can only be built in towns with a population of at least 1200 -STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}... can only be built in rainforest areas -STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}... can only be built in desert areas -STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}... can only be built in towns (replacing houses) -STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER :{WHITE}... can only be built near the center of towns -STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS :{WHITE}... can only be built in low areas -STR_ERROR_CAN_ONLY_BE_POSITIONED :{WHITE}... can only be positioned near edges of map -STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... forest can only be planted above snow-line -STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... can only be built above the snow-line -STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... can only be built below the snow-line - -# Station construction related errors -STR_ERROR_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Can't build railway station here... -STR_ERROR_CAN_T_BUILD_BUS_STATION :{WHITE}Can't build bus station... -STR_ERROR_CAN_T_BUILD_TRUCK_STATION :{WHITE}Can't build lorry station... -STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION :{WHITE}Can't build passenger tram station... -STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Can't build freight tram station... -STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}Can't build dock here... -STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Can't build airport here... - -STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Adjoins more than one existing station/loading area -STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}... station too spread out -STR_ERROR_TOO_MANY_STATIONS_LOADING :{WHITE}Too many stations/loading areas -STR_ERROR_TOO_MANY_STATION_SPECS :{WHITE}Too many railway station parts -STR_ERROR_TOO_MANY_BUS_STOPS :{WHITE}Too many bus stops -STR_ERROR_TOO_MANY_TRUCK_STOPS :{WHITE}Too many lorry stations -STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}Too close to another station/loading area -STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Too close to another dock -STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}Too close to another airport -STR_ERROR_CAN_T_RENAME_STATION :{WHITE}Can't rename station... -STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... this is a town owned road -STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... road facing in the wrong direction -STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... drive through stops can't have corners -STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... drive through stops can't have junctions - -# Station destruction related errors -STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Can't remove part of station... -STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}Must remove railway station first -STR_ERROR_CAN_T_REMOVE_BUS_STATION :{WHITE}Can't remove bus station... -STR_ERROR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}Can't remove lorry station... -STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION :{WHITE}Can't remove passenger tram station... -STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION :{WHITE}Can't remove freight tram station... -STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST :{WHITE}Must remove road stop first -STR_ERROR_THERE_IS_NO_STATION :{WHITE}... there is no station here - -STR_ERROR_MUST_DEMOLISH_RAILROAD :{WHITE}Must demolish railway station first -STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST :{WHITE}Must demolish bus station first -STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST :{WHITE}Must demolish lorry station first -STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST :{WHITE}Must demolish passenger tram station first -STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST :{WHITE}Must demolish freight tram station first -STR_ERROR_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Must demolish dock first -STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}Must demolish airport first - -# Waypoint related errors -STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Adjoins more than one existing waypoint -STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT :{WHITE}Too close to another waypoint - -STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT :{WHITE}Can't build train waypoint here... -STR_ERROR_CAN_T_POSITION_BUOY_HERE :{WHITE}Can't place buoy here... -STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME :{WHITE}Can't change waypoint name... - -STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT :{WHITE}Can't remove train waypoint here... -STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST :{WHITE}Must remove rail waypoint first -STR_ERROR_BUOY_IN_THE_WAY :{WHITE}... buoy in the way -STR_ERROR_BUOY_IS_IN_USE :{WHITE}... buoy is in use by another company! - -# Depot related errors -STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}Can't build train depot here... -STR_ERROR_CAN_T_BUILD_ROAD_DEPOT :{WHITE}Can't build road vehicle depot here... -STR_ERROR_CAN_T_BUILD_TRAM_DEPOT :{WHITE}Can't build tram vehicle depot here... -STR_ERROR_CAN_T_BUILD_SHIP_DEPOT :{WHITE}Can't build ship depot here... - -STR_ERROR_CAN_T_RENAME_DEPOT :{WHITE}Can't rename depot... - -STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... must be stopped inside a depot -STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... must be stopped inside a depot -STR_ERROR_SHIP_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... must be stopped inside a depot -STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR :{WHITE}... must be stopped inside a hangar - -STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT :{WHITE}Trains can only be altered when stopped inside a depot -STR_ERROR_TRAIN_TOO_LONG :{WHITE}Train too long -STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE :{WHITE}Can't reverse direction of vehicle... -STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS :{WHITE}... consists of multiple units -STR_ERROR_INCOMPATIBLE_RAIL_TYPES :Incompatible rail types - -STR_ERROR_CAN_T_MOVE_VEHICLE :{WHITE}Can't move vehicle... -STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}The rear engine will always follow its front counterpart -STR_ERROR_UNABLE_TO_FIND_ROUTE_TO :{WHITE}Unable to find route to local depot -STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}Unable to find local depot - -STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :Wrong depot type - -# Autoreplace related errors -STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE} is too long after replacement -STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}No autoreplace/renew rules applied -STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(money limit) - -# Rail construction errors -STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}Impossible track combination -STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Must remove signals first -STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}No suitable railway track -STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Must remove railway track first -STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Road is one way or blocked -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Level crossings not allowed for this rail type -STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Can't build signals here... -STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Can't build railway track here... -STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Can't remove railway track from here... -STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Can't remove signals from here... -STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE :{WHITE}Can't convert signals here... -STR_ERROR_THERE_IS_NO_RAILROAD_TRACK :{WHITE}... there is no railway track -STR_ERROR_THERE_ARE_NO_SIGNALS :{WHITE}... there are no signals - -STR_ERROR_CAN_T_CONVERT_RAIL :{WHITE}Can't convert rail type here... - -# Road construction errors -STR_ERROR_MUST_REMOVE_ROAD_FIRST :{WHITE}Must remove road first -STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... one way roads can't have junctions -STR_ERROR_CAN_T_BUILD_ROAD_HERE :{WHITE}Can't build road here... -STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}Can't build tramway here... -STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Can't remove road from here... -STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Can't remove tramway from here... -STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... there is no road -STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... there is no tramway - -# Waterway construction errors -STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Can't build canals here... -STR_ERROR_CAN_T_BUILD_LOCKS :{WHITE}Can't build locks here... -STR_ERROR_CAN_T_PLACE_RIVERS :{WHITE}Can't place rivers here... -STR_ERROR_MUST_BE_BUILT_ON_WATER :{WHITE}... must be built on water -STR_ERROR_CAN_T_BUILD_ON_WATER :{WHITE}... can't build on water -STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}... can't build on open sea -STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... can't build on canal -STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... can't build on river -STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}Must demolish canal first -STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Can't build aqueduct here... - -# Tree related errors -STR_ERROR_TREE_ALREADY_HERE :{WHITE}... tree already here -STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE :{WHITE}... wrong terrain for tree type -STR_ERROR_CAN_T_PLANT_TREE_HERE :{WHITE}Can't plant tree here... - -# Bridge related errors -STR_ERROR_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Can't build bridge here... -STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST :{WHITE}Must demolish bridge first -STR_ERROR_CAN_T_START_AND_END_ON :{WHITE}Can't start and end in the same spot -STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT :{WHITE}Bridge heads not at the same level -STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN :{WHITE}Bridge is too low for the terrain -STR_ERROR_START_AND_END_MUST_BE_IN :{WHITE}Start and end must be in line -STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}... ends of bridge must both be on land -STR_ERROR_BRIDGE_TOO_LONG :{WHITE}... bridge too long -STR_ERROR_BRIDGE_THROUGH_MAP_BORDER :{WHITE}Bridge would end out of the map - -# Tunnel related errors -STR_ERROR_CAN_T_BUILD_TUNNEL_HERE :{WHITE}Can't build tunnel here... -STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL :{WHITE}Site unsuitable for tunnel entrance -STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST :{WHITE}Must demolish tunnel first -STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY :{WHITE}Another tunnel in the way -STR_ERROR_TUNNEL_THROUGH_MAP_BORDER :{WHITE}Tunnel would end out of the map -STR_ERROR_UNABLE_TO_EXCAVATE_LAND :{WHITE}Unable to excavate land for other end of tunnel -STR_ERROR_TUNNEL_TOO_LONG :{WHITE}... tunnel too long - -# Object related errors -STR_ERROR_TOO_MANY_OBJECTS :{WHITE}... too many objects -STR_ERROR_CAN_T_BUILD_OBJECT :{WHITE}Can't build object... -STR_ERROR_OBJECT_IN_THE_WAY :{WHITE}Object in the way -STR_ERROR_COMPANY_HEADQUARTERS_IN :{WHITE}... company headquarters in the way -STR_ERROR_CAN_T_PURCHASE_THIS_LAND :{WHITE}Can't purchase this land area... -STR_ERROR_YOU_ALREADY_OWN_IT :{WHITE}... you already own it! - -# Group related errors -STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Can't create group... -STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Can't delete this group... -STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Can't rename group... -STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Can't remove all vehicles from this group... -STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Can't add the vehicle to this group... -STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Can't add shared vehicles to group... - -# Generic vehicle errors -STR_ERROR_TRAIN_IN_THE_WAY :{WHITE}Train in the way -STR_ERROR_ROAD_VEHICLE_IN_THE_WAY :{WHITE}Road vehicle in the way -STR_ERROR_SHIP_IN_THE_WAY :{WHITE}Ship in the way -STR_ERROR_AIRCRAFT_IN_THE_WAY :{WHITE}Aircraft in the way - -STR_ERROR_CAN_T_REFIT_TRAIN :{WHITE}Can't refit train... -STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE :{WHITE}Can't refit road vehicle... -STR_ERROR_CAN_T_REFIT_SHIP :{WHITE}Can't refit ship... -STR_ERROR_CAN_T_REFIT_AIRCRAFT :{WHITE}Can't refit aircraft... - -STR_ERROR_CAN_T_RENAME_TRAIN :{WHITE}Can't name train... -STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE :{WHITE}Can't name road vehicle... -STR_ERROR_CAN_T_RENAME_SHIP :{WHITE}Can't name ship... -STR_ERROR_CAN_T_RENAME_AIRCRAFT :{WHITE}Can't name aircraft... - -STR_ERROR_CAN_T_STOP_START_TRAIN :{WHITE}Can't stop/start train... -STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE :{WHITE}Can't stop/start road vehicle... -STR_ERROR_CAN_T_STOP_START_SHIP :{WHITE}Can't stop/start ship... -STR_ERROR_CAN_T_STOP_START_AIRCRAFT :{WHITE}Can't stop/start aircraft... - -STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}Can't send train to depot... -STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT :{WHITE}Can't send road vehicle to depot... -STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT :{WHITE}Can't send ship to depot... -STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR :{WHITE}Can't send aircraft to hangar... - -STR_ERROR_CAN_T_BUY_TRAIN :{WHITE}Can't buy railway vehicle... -STR_ERROR_CAN_T_BUY_ROAD_VEHICLE :{WHITE}Can't buy road vehicle... -STR_ERROR_CAN_T_BUY_SHIP :{WHITE}Can't buy ship... -STR_ERROR_CAN_T_BUY_AIRCRAFT :{WHITE}Can't buy aircraft... - -STR_ERROR_CAN_T_RENAME_TRAIN_TYPE :{WHITE}Can't rename train vehicle type... -STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE_TYPE :{WHITE}Can't rename road vehicle type... -STR_ERROR_CAN_T_RENAME_SHIP_TYPE :{WHITE}Can't rename ship type... -STR_ERROR_CAN_T_RENAME_AIRCRAFT_TYPE :{WHITE}Can't rename aircraft type... - -STR_ERROR_CAN_T_SELL_TRAIN :{WHITE}Can't sell railway vehicle... -STR_ERROR_CAN_T_SELL_ROAD_VEHICLE :{WHITE}Can't sell road vehicle... -STR_ERROR_CAN_T_SELL_SHIP :{WHITE}Can't sell ship... -STR_ERROR_CAN_T_SELL_AIRCRAFT :{WHITE}Can't sell aircraft... - -STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE :{WHITE}Vehicle is not available -STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE :{WHITE}Vehicle is not available -STR_ERROR_SHIP_NOT_AVAILABLE :{WHITE}Ship is not available -STR_ERROR_AIRCRAFT_NOT_AVAILABLE :{WHITE}Aircraft is not available - -STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Too many vehicles in game -STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}Can't change servicing interval... - -STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... vehicle is destroyed - -STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}No vehicles will be available at all -STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Change your NewGRF configuration -STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}No vehicles are available yet -STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Start a new game after {DATE_SHORT} or use a NewGRF that provides early vehicles - -# Specific vehicle errors -STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Can't make train pass signal at danger... -STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Can't reverse direction of train... -STR_ERROR_TRAIN_START_NO_POWER :Train has no power - -STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN :{WHITE}Can't make road vehicle turn around... - -STR_ERROR_AIRCRAFT_IS_IN_FLIGHT :{WHITE}Aircraft is in flight - -# Order related errors -STR_ERROR_NO_MORE_SPACE_FOR_ORDERS :{WHITE}No more space for orders -STR_ERROR_TOO_MANY_ORDERS :{WHITE}Too many orders -STR_ERROR_CAN_T_INSERT_NEW_ORDER :{WHITE}Can't insert new order... -STR_ERROR_CAN_T_DELETE_THIS_ORDER :{WHITE}Can't delete this order... -STR_ERROR_CAN_T_MODIFY_THIS_ORDER :{WHITE}Can't modify this order... -STR_ERROR_CAN_T_MOVE_THIS_ORDER :{WHITE}Can't move this order... -STR_ERROR_CAN_T_SKIP_ORDER :{WHITE}Can't skip current order... -STR_ERROR_CAN_T_SKIP_TO_ORDER :{WHITE}Can't skip to selected order... -STR_ERROR_CAN_T_COPY_SHARE_ORDER :{WHITE}... vehicle can't go to all stations -STR_ERROR_CAN_T_ADD_ORDER :{WHITE}... vehicle can't go to that station -STR_ERROR_CAN_T_ADD_ORDER_SHARED :{WHITE}... a vehicle sharing this order can't go to that station - -STR_ERROR_CAN_T_SHARE_ORDER_LIST :{WHITE}Can't share order list... -STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST :{WHITE}Can't stop sharing order list... -STR_ERROR_CAN_T_COPY_ORDER_LIST :{WHITE}Can't copy order list... -STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION :{WHITE}... too far from previous destination -STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... aircraft has not enough range - -# Timetable related errors -STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Can't timetable vehicle... -STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Vehicles can only wait at stations -STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}This vehicle is not stopping at this station - -# Sign related errors -STR_ERROR_TOO_MANY_SIGNS :{WHITE}... too many signs -STR_ERROR_CAN_T_PLACE_SIGN_HERE :{WHITE}Can't place sign here... -STR_ERROR_CAN_T_CHANGE_SIGN_NAME :{WHITE}Can't change sign name... -STR_ERROR_CAN_T_DELETE_SIGN :{WHITE}Can't delete sign... - -# Translatable comment for OpenTTD's desktop shortcut -STR_DESKTOP_SHORTCUT_COMMENT :A simulation game based on Transport Tycoon Deluxe - -# Translatable descriptions in media/baseset/*.ob* files -STR_BASEGRAPHICS_DOS_DESCRIPTION :Original Transport Tycoon Deluxe DOS edition graphics. -STR_BASEGRAPHICS_DOS_DE_DESCRIPTION :Original Transport Tycoon Deluxe DOS (German) edition graphics. -STR_BASEGRAPHICS_WIN_DESCRIPTION :Original Transport Tycoon Deluxe Windows edition graphics. -STR_BASESOUNDS_DOS_DESCRIPTION :Original Transport Tycoon Deluxe DOS edition sounds. -STR_BASESOUNDS_WIN_DESCRIPTION :Original Transport Tycoon Deluxe Windows edition sounds. -STR_BASESOUNDS_NONE_DESCRIPTION :A sound pack without any sounds. -STR_BASEMUSIC_WIN_DESCRIPTION :Original Transport Tycoon Deluxe Windows edition music. -STR_BASEMUSIC_NONE_DESCRIPTION :A music pack without actual music. - -##id 0x2000 -# Town building names -STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1 :Tall office block -STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1 :Office block -STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1 :Small block of flats -STR_TOWN_BUILDING_NAME_CHURCH_1 :Church -STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1 :Large office block -STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1 :Town houses -STR_TOWN_BUILDING_NAME_HOTEL_1 :Hotel -STR_TOWN_BUILDING_NAME_STATUE_1 :Statue -STR_TOWN_BUILDING_NAME_FOUNTAIN_1 :Fountain -STR_TOWN_BUILDING_NAME_PARK_1 :Park -STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2 :Office block -STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1 :Shops and offices -STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1 :Modern office building -STR_TOWN_BUILDING_NAME_WAREHOUSE_1 :Warehouse -STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3 :Office block -STR_TOWN_BUILDING_NAME_STADIUM_1 :Stadium -STR_TOWN_BUILDING_NAME_OLD_HOUSES_1 :Old houses -STR_TOWN_BUILDING_NAME_COTTAGES_1 :Cottages -STR_TOWN_BUILDING_NAME_HOUSES_1 :Houses -STR_TOWN_BUILDING_NAME_FLATS_1 :Flats -STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2 :Tall office block -STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2 :Shops and offices -STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3 :Shops and offices -STR_TOWN_BUILDING_NAME_THEATER_1 :Theatre -STR_TOWN_BUILDING_NAME_STADIUM_2 :Stadium -STR_TOWN_BUILDING_NAME_OFFICES_1 :Offices -STR_TOWN_BUILDING_NAME_HOUSES_2 :Houses -STR_TOWN_BUILDING_NAME_CINEMA_1 :Cinema -STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1 :Shopping centre -STR_TOWN_BUILDING_NAME_IGLOO_1 :Igloo -STR_TOWN_BUILDING_NAME_TEPEES_1 :Tepees -STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1 :Teapot-House -STR_TOWN_BUILDING_NAME_PIGGY_BANK_1 :Piggy-Bank - -##id 0x4800 -# industry names -STR_INDUSTRY_NAME_COAL_MINE :Coal Mine -STR_INDUSTRY_NAME_POWER_STATION :Power Station -STR_INDUSTRY_NAME_SAWMILL :Sawmill -STR_INDUSTRY_NAME_FOREST :Forest -STR_INDUSTRY_NAME_OIL_REFINERY :Oil Refinery -STR_INDUSTRY_NAME_OIL_RIG :Oil Rig -STR_INDUSTRY_NAME_FACTORY :Factory -STR_INDUSTRY_NAME_PRINTING_WORKS :Printing Works -STR_INDUSTRY_NAME_STEEL_MILL :Steel Mill -STR_INDUSTRY_NAME_FARM :Farm -STR_INDUSTRY_NAME_COPPER_ORE_MINE :Copper Ore Mine -STR_INDUSTRY_NAME_OIL_WELLS :Oil Wells -STR_INDUSTRY_NAME_BANK :Bank -STR_INDUSTRY_NAME_FOOD_PROCESSING_PLANT :Food Processing Plant -STR_INDUSTRY_NAME_PAPER_MILL :Paper Mill -STR_INDUSTRY_NAME_GOLD_MINE :Gold Mine -STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC :Bank -STR_INDUSTRY_NAME_DIAMOND_MINE :Diamond Mine -STR_INDUSTRY_NAME_IRON_ORE_MINE :Iron Ore Mine -STR_INDUSTRY_NAME_FRUIT_PLANTATION :Fruit Plantation -STR_INDUSTRY_NAME_RUBBER_PLANTATION :Rubber Plantation -STR_INDUSTRY_NAME_WATER_SUPPLY :Water Supply -STR_INDUSTRY_NAME_WATER_TOWER :Water Tower -STR_INDUSTRY_NAME_FACTORY_2 :Factory -STR_INDUSTRY_NAME_FARM_2 :Farm -STR_INDUSTRY_NAME_LUMBER_MILL :Lumber Mill -STR_INDUSTRY_NAME_COTTON_CANDY_FOREST :Candyfloss Forest -STR_INDUSTRY_NAME_CANDY_FACTORY :Sweet Factory -STR_INDUSTRY_NAME_BATTERY_FARM :Battery Farm -STR_INDUSTRY_NAME_COLA_WELLS :Cola Wells -STR_INDUSTRY_NAME_TOY_SHOP :Toy Shop -STR_INDUSTRY_NAME_TOY_FACTORY :Toy Factory -STR_INDUSTRY_NAME_PLASTIC_FOUNTAINS :Plastic Fountains -STR_INDUSTRY_NAME_FIZZY_DRINK_FACTORY :Fizzy Drink Factory -STR_INDUSTRY_NAME_BUBBLE_GENERATOR :Bubble Generator -STR_INDUSTRY_NAME_TOFFEE_QUARRY :Toffee Quarry -STR_INDUSTRY_NAME_SUGAR_MINE :Sugar Mine - -############ WARNING, using range 0x6000 for strings that are stored in the savegame -############ These strings may never get a new id, or savegames will break! -##id 0x6000 -STR_SV_EMPTY : -STR_SV_UNNAMED :Unnamed -STR_SV_TRAIN_NAME :Train {COMMA} -STR_SV_ROAD_VEHICLE_NAME :Road Vehicle {COMMA} -STR_SV_SHIP_NAME :Ship {COMMA} -STR_SV_AIRCRAFT_NAME :Aircraft {COMMA} - -STR_SV_STNAME :{STRING1} -STR_SV_STNAME_NORTH :{STRING1} North -STR_SV_STNAME_SOUTH :{STRING1} South -STR_SV_STNAME_EAST :{STRING1} East -STR_SV_STNAME_WEST :{STRING1} West -STR_SV_STNAME_CENTRAL :{STRING1} Central -STR_SV_STNAME_TRANSFER :{STRING1} Transfer -STR_SV_STNAME_HALT :{STRING1} Halt -STR_SV_STNAME_VALLEY :{STRING1} Valley -STR_SV_STNAME_HEIGHTS :{STRING1} Heights -STR_SV_STNAME_WOODS :{STRING1} Woods -STR_SV_STNAME_LAKESIDE :{STRING1} Lakeside -STR_SV_STNAME_EXCHANGE :{STRING1} Exchange -STR_SV_STNAME_AIRPORT :{STRING1} Airport -STR_SV_STNAME_OILFIELD :{STRING1} Oilfield -STR_SV_STNAME_MINES :{STRING1} Mines -STR_SV_STNAME_DOCKS :{STRING1} Docks -STR_SV_STNAME_BUOY :{STRING2} -STR_SV_STNAME_WAYPOINT :{STRING2} -##id 0x6020 -STR_SV_STNAME_ANNEXE :{STRING1} Annexe -STR_SV_STNAME_SIDINGS :{STRING1} Sidings -STR_SV_STNAME_BRANCH :{STRING1} Branch -STR_SV_STNAME_UPPER :Upper {STRING1} -STR_SV_STNAME_LOWER :Lower {STRING1} -STR_SV_STNAME_HELIPORT :{STRING1} Heliport -STR_SV_STNAME_FOREST :{STRING1} Forest -STR_SV_STNAME_FALLBACK :{STRING1} Station #{NUM} -############ end of savegame specific region! - -##id 0x8000 -# Vehicle names -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM :Kirby Paul Tank (Steam) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_250_DIESEL :MJS 250 (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_CHOO_CHOO :Ploddyphut Choo-Choo -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_CHOO_CHOO :Powernaut Choo-Choo -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MIGHTYMOVER_CHOO_CHOO :MightyMover Choo-Choo -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_DIESEL :Ploddyphut Diesel -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_DIESEL :Powernaut Diesel -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_WILLS_2_8_0_STEAM :Wills 2-8-0 (Steam) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CHANEY_JUBILEE_STEAM :Chaney 'Jubilee' (Steam) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_GINZU_A4_STEAM :Ginzu 'A4' (Steam) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_8P_STEAM :SH '8P' (Steam) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MANLEY_MOREL_DMU_DIESEL :Manley-Morel DMU (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_DASH_DIESEL :'Dash' (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_HENDRY_25_DIESEL :SH/Hendry '25' (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_UU_37_DIESEL :UU '37' (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_FLOSS_47_DIESEL :Floss '47' (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_4000_DIESEL :CS 4000 (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_2400_DIESEL :CS 2400 (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CENTENNIAL_DIESEL :Centennial (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KELLING_3100_DIESEL :Kelling 3100 (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_TURNER_TURBO_DIESEL :Turner Turbo (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_1000_DIESEL :MJS 1000 (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_125_DIESEL :SH '125' (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_30_ELECTRIC :SH '30' (Electric) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_40_ELECTRIC :SH '40' (Electric) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_T_I_M_ELECTRIC :'T.I.M.' (Electric) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_ASIASTAR_ELECTRIC :'AsiaStar' (Electric) -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PASSENGER_CAR :Passenger Carriage -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_MAIL_VAN :Mail Van -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COAL_CAR :Coal Truck -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_OIL_TANKER :Oil Tanker -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_LIVESTOCK_VAN :Livestock Van -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GOODS_VAN :Goods Van -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GRAIN_HOPPER :Grain Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WOOD_TRUCK :Wood Truck -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_IRON_ORE_HOPPER :Iron Ore Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_STEEL_TRUCK :Steel Truck -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_ARMORED_VAN :Armoured Van -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FOOD_VAN :Food Van -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PAPER_TRUCK :Paper Truck -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COPPER_ORE_HOPPER :Copper Ore Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WATER_TANKER :Water Tanker -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FRUIT_TRUCK :Fruit Truck -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_RUBBER_TRUCK :Rubber Truck -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_SUGAR_TRUCK :Sugar Truck -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COTTON_CANDY_HOPPER :Candyfloss Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOFFEE_HOPPER :Toffee Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BUBBLE_VAN :Bubble Van -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COLA_TANKER :Cola Tanker -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_CANDY_VAN :Sweet Van -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOY_VAN :Toy Van -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BATTERY_TRUCK :Battery Truck -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FIZZY_DRINK_TRUCK :Fizzy Drink Truck -STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PLASTIC_TRUCK :Plastic Truck -STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_X2001_ELECTRIC :'X2001' (Electric) -STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_MILLENNIUM_Z1_ELECTRIC :'Millennium Z1' (Electric) -STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_WIZZOWOW_Z99 :Wizzowow Z99 -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PASSENGER_CAR :Passenger Carriage -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_MAIL_VAN :Mail Van -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COAL_CAR :Coal Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_OIL_TANKER :Oil Tanker -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_LIVESTOCK_VAN :Livestock Van -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GOODS_VAN :Goods Van -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GRAIN_HOPPER :Grain Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WOOD_TRUCK :Wood Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_IRON_ORE_HOPPER :Iron Ore Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_STEEL_TRUCK :Steel Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_ARMORED_VAN :Armoured Van -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FOOD_VAN :Food Van -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PAPER_TRUCK :Paper Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COPPER_ORE_HOPPER :Copper Ore Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WATER_TANKER :Water Tanker -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FRUIT_TRUCK :Fruit Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_RUBBER_TRUCK :Rubber Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_SUGAR_TRUCK :Sugar Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COTTON_CANDY_HOPPER :Candyfloss Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOFFEE_HOPPER :Toffee Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BUBBLE_VAN :Bubble Van -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COLA_TANKER :Cola Tanker -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_CANDY_VAN :Sweet Van -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOY_VAN :Toy Van -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BATTERY_TRUCK :Battery Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FIZZY_DRINK_TRUCK :Fizzy Drink Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PLASTIC_TRUCK :Plastic Truck -STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV1_LEVIATHAN_ELECTRIC :Lev1 'Leviathan' (Electric) -STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV2_CYCLOPS_ELECTRIC :Lev2 'Cyclops' (Electric) -STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV3_PEGASUS_ELECTRIC :Lev3 'Pegasus' (Electric) -STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV4_CHIMAERA_ELECTRIC :Lev4 'Chimaera' (Electric) -STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_WIZZOWOW_ROCKETEER :Wizzowow Rocketeer -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PASSENGER_CAR :Passenger Carriage -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_MAIL_VAN :Mail Van -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COAL_CAR :Coal Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_OIL_TANKER :Oil Tanker -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_LIVESTOCK_VAN :Livestock Van -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GOODS_VAN :Goods Van -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GRAIN_HOPPER :Grain Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WOOD_TRUCK :Wood Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_IRON_ORE_HOPPER :Iron Ore Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_STEEL_TRUCK :Steel Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_ARMORED_VAN :Armoured Van -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FOOD_VAN :Food Van -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PAPER_TRUCK :Paper Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COPPER_ORE_HOPPER :Copper Ore Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WATER_TANKER :Water Tanker -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FRUIT_TRUCK :Fruit Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_RUBBER_TRUCK :Rubber Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_SUGAR_TRUCK :Sugar Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COTTON_CANDY_HOPPER :Candyfloss Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOFFEE_HOPPER :Toffee Hopper -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BUBBLE_VAN :Bubble Van -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COLA_TANKER :Cola Tanker -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_CANDY_VAN :Sweet Van -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOY_VAN :Toy Van -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BATTERY_TRUCK :Battery Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FIZZY_DRINK_TRUCK :Fizzy Drink Truck -STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PLASTIC_TRUCK :Plastic Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS :MPS Regal Bus -STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_LEOPARD_BUS :Hereford Leopard Bus -STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_BUS :Foster Bus -STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_MKII_SUPERBUS :Foster MkII Superbus -STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKI_BUS :Ploddyphut MkI Bus -STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKII_BUS :Ploddyphut MkII Bus -STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKIII_BUS :Ploddyphut MkIII Bus -STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_COAL_TRUCK :Balogh Coal Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COAL_TRUCK :Uhl Coal Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_DW_COAL_TRUCK :DW Coal Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_MAIL_TRUCK :MPS Mail Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_REYNARD_MAIL_TRUCK :Reynard Mail Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_MAIL_TRUCK :Perry Mail Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_MAIL_TRUCK :MightyMover Mail Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_MAIL_TRUCK :Powernaught Mail Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_MAIL_TRUCK :Wizzowow Mail Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_OIL_TANKER :Witcombe Oil Tanker -STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_OIL_TANKER :Foster Oil Tanker -STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_OIL_TANKER :Perry Oil Tanker -STR_VEHICLE_NAME_ROAD_VEHICLE_TALBOTT_LIVESTOCK_VAN :Talbott Livestock Van -STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_LIVESTOCK_VAN :Uhl Livestock Van -STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_LIVESTOCK_VAN :Foster Livestock Van -STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_GOODS_TRUCK :Balogh Goods Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_CRAIGHEAD_GOODS_TRUCK :Craighead Goods Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GOODS_TRUCK :Goss Goods Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_GRAIN_TRUCK :Hereford Grain Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_THOMAS_GRAIN_TRUCK :Thomas Grain Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GRAIN_TRUCK :Goss Grain Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_WOOD_TRUCK :Witcombe Wood Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_WOOD_TRUCK :Foster Wood Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MORELAND_WOOD_TRUCK :Moreland Wood Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_IRON_ORE_TRUCK :MPS Iron Ore Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_IRON_ORE_TRUCK :Uhl Iron Ore Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_IRON_ORE_TRUCK :Chippy Iron Ore Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_STEEL_TRUCK :Balogh Steel Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_STEEL_TRUCK :Uhl Steel Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_STEEL_TRUCK :Kelling Steel Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_ARMORED_TRUCK :Balogh Armoured Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_ARMORED_TRUCK :Uhl Armoured Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_ARMORED_TRUCK :Foster Armoured Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_FOOD_VAN :Foster Food Van -STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_FOOD_VAN :Perry Food Van -STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_FOOD_VAN :Chippy Food Van -STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_PAPER_TRUCK :Uhl Paper Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_PAPER_TRUCK :Balogh Paper Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_PAPER_TRUCK :MPS Paper Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_COPPER_ORE_TRUCK :MPS Copper Ore Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COPPER_ORE_TRUCK :Uhl Copper Ore Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_COPPER_ORE_TRUCK :Goss Copper Ore Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_WATER_TANKER :Uhl Water Tanker -STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_WATER_TANKER :Balogh Water Tanker -STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_WATER_TANKER :MPS Water Tanker -STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_FRUIT_TRUCK :Balogh Fruit Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_FRUIT_TRUCK :Uhl Fruit Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_FRUIT_TRUCK :Kelling Fruit Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_RUBBER_TRUCK :Balogh Rubber Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_RUBBER_TRUCK :Uhl Rubber Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_RMT_RUBBER_TRUCK :RMT Rubber Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_SUGAR_TRUCK :MightyMover Sugar Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_SUGAR_TRUCK :Powernaught Sugar Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_SUGAR_TRUCK :Wizzowow Sugar Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COLA_TRUCK :MightyMover Cola Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COLA_TRUCK :Powernaught Cola Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COLA_TRUCK :Wizzowow Cola Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COTTON_CANDY :MightyMover Candyfloss Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COTTON_CANDY :Powernaught Candyfloss Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COTTON_CANDY_TRUCK :Wizzowow Candyfloss Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOFFEE_TRUCK :MightyMover Toffee Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOFFEE_TRUCK :Powernaught Toffee Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOFFEE_TRUCK :Wizzowow Toffee Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOY_VAN :MightyMover Toy Van -STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOY_VAN :Powernaught Toy Van -STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOY_VAN :Wizzowow Toy Van -STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_CANDY_TRUCK :MightyMover Sweet Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_CANDY_TRUCK :Powernaught Sweet Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_CANDY_TRUCK :Wizzowow Sweet Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BATTERY_TRUCK :MightyMover Battery Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BATTERY_TRUCK :Powernaught Battery Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BATTERY_TRUCK :Wizzowow Battery Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_FIZZY_DRINK :MightyMover Fizzy Drink Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_FIZZY_DRINK :Powernaught Fizzy Drink Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_FIZZY_DRINK_TRUCK :Wizzowow Fizzy Drink Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_PLASTIC_TRUCK :MightyMover Plastic Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_PLASTIC_TRUCK :Powernaught Plastic Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_PLASTIC_TRUCK :Wizzowow Plastic Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BUBBLE_TRUCK :MightyMover Bubble Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BUBBLE_TRUCK :Powernaught Bubble Truck -STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BUBBLE_TRUCK :Wizzowow Bubble Truck -STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER :MPS Oil Tanker -STR_VEHICLE_NAME_SHIP_CS_INC_OIL_TANKER :CS-Inc. Oil Tanker -STR_VEHICLE_NAME_SHIP_MPS_PASSENGER_FERRY :MPS Passenger Ferry -STR_VEHICLE_NAME_SHIP_FFP_PASSENGER_FERRY :FFP Passenger Ferry -STR_VEHICLE_NAME_SHIP_BAKEWELL_300_HOVERCRAFT :Bakewell 300 Hovercraft -STR_VEHICLE_NAME_SHIP_CHUGGER_CHUG_PASSENGER :Chugger-Chug Passenger Ferry -STR_VEHICLE_NAME_SHIP_SHIVERSHAKE_PASSENGER_FERRY :Shivershake Passenger Ferry -STR_VEHICLE_NAME_SHIP_YATE_CARGO_SHIP :Yate Cargo Ship -STR_VEHICLE_NAME_SHIP_BAKEWELL_CARGO_SHIP :Bakewell Cargo Ship -STR_VEHICLE_NAME_SHIP_MIGHTYMOVER_CARGO_SHIP :MightyMover Cargo Ship -STR_VEHICLE_NAME_SHIP_POWERNAUT_CARGO_SHIP :Powernaut Cargo Ship -STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 :Sampson U52 -STR_VEHICLE_NAME_AIRCRAFT_COLEMAN_COUNT :Coleman Count -STR_VEHICLE_NAME_AIRCRAFT_FFP_DART :FFP Dart -STR_VEHICLE_NAME_AIRCRAFT_YATE_HAUGAN :Yate Haugan -STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_COTSWALD_LB_3 :Bakewell Cotswald LB-3 -STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_8 :Bakewell Luckett LB-8 -STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_9 :Bakewell Luckett LB-9 -STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB80 :Bakewell Luckett LB80 -STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_10 :Bakewell Luckett LB-10 -STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_11 :Bakewell Luckett LB-11 -STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAC_1_11 :Yate Aerospace YAC 1-11 -STR_VEHICLE_NAME_AIRCRAFT_DARWIN_100 :Darwin 100 -STR_VEHICLE_NAME_AIRCRAFT_DARWIN_200 :Darwin 200 -STR_VEHICLE_NAME_AIRCRAFT_DARWIN_300 :Darwin 300 -STR_VEHICLE_NAME_AIRCRAFT_DARWIN_400 :Darwin 400 -STR_VEHICLE_NAME_AIRCRAFT_DARWIN_500 :Darwin 500 -STR_VEHICLE_NAME_AIRCRAFT_DARWIN_600 :Darwin 600 -STR_VEHICLE_NAME_AIRCRAFT_GURU_GALAXY :Guru Galaxy -STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A21 :Airtaxi A21 -STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A31 :Airtaxi A31 -STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A32 :Airtaxi A32 -STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A33 :Airtaxi A33 -STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAE46 :Yate Aerospace YAe46 -STR_VEHICLE_NAME_AIRCRAFT_DINGER_100 :Dinger 100 -STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A34_1000 :AirTaxi A34-1000 -STR_VEHICLE_NAME_AIRCRAFT_YATE_Z_SHUTTLE :Yate Z-Shuttle -STR_VEHICLE_NAME_AIRCRAFT_KELLING_K1 :Kelling K1 -STR_VEHICLE_NAME_AIRCRAFT_KELLING_K6 :Kelling K6 -STR_VEHICLE_NAME_AIRCRAFT_KELLING_K7 :Kelling K7 -STR_VEHICLE_NAME_AIRCRAFT_DARWIN_700 :Darwin 700 -STR_VEHICLE_NAME_AIRCRAFT_FFP_HYPERDART_2 :FFP Hyperdart 2 -STR_VEHICLE_NAME_AIRCRAFT_DINGER_200 :Dinger 200 -STR_VEHICLE_NAME_AIRCRAFT_DINGER_1000 :Dinger 1000 -STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_100 :Ploddyphut 100 -STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_500 :Ploddyphut 500 -STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_X1 :Flashbang X1 -STR_VEHICLE_NAME_AIRCRAFT_JUGGERPLANE_M1 :Juggerplane M1 -STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_WIZZER :Flashbang Wizzer -STR_VEHICLE_NAME_AIRCRAFT_TRICARIO_HELICOPTER :Tricario Helicopter -STR_VEHICLE_NAME_AIRCRAFT_GURU_X2_HELICOPTER :Guru X2 Helicopter -STR_VEHICLE_NAME_AIRCRAFT_POWERNAUT_HELICOPTER :Powernaut Helicopter - -##id 0x8800 -# Formatting of some strings -STR_FORMAT_DATE_TINY :{RAW_STRING}-{RAW_STRING}-{NUM} -STR_FORMAT_DATE_SHORT :{STRING} {NUM} -STR_FORMAT_DATE_LONG :{STRING} {STRING} {NUM} -STR_FORMAT_DATE_ISO :{2:NUM}-{1:RAW_STRING}-{0:RAW_STRING} - -STR_FORMAT_BUOY_NAME :{TOWN} Buoy -STR_FORMAT_BUOY_NAME_SERIAL :{TOWN} Buoy #{COMMA} -STR_FORMAT_COMPANY_NUM :(Company {COMMA}) -STR_FORMAT_GROUP_NAME :Group {COMMA} -STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING} -STR_FORMAT_WAYPOINT_NAME :{TOWN} Waypoint -STR_FORMAT_WAYPOINT_NAME_SERIAL :{TOWN} Waypoint #{COMMA} - -STR_FORMAT_DEPOT_NAME_TRAIN :{TOWN} Train Depot -STR_FORMAT_DEPOT_NAME_TRAIN_SERIAL :{TOWN} Train Depot #{COMMA} -STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE :{TOWN} Road Vehicle Depot -STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE_SERIAL :{TOWN} Road Vehicle Depot #{COMMA} -STR_FORMAT_DEPOT_NAME_SHIP :{TOWN} Ship Depot -STR_FORMAT_DEPOT_NAME_SHIP_SERIAL :{TOWN} Ship Depot #{COMMA} -STR_FORMAT_DEPOT_NAME_AIRCRAFT :{STATION} Hangar - -STR_UNKNOWN_STATION :unknown station -STR_DEFAULT_SIGN_NAME :Sign -STR_COMPANY_SOMEONE :someone - -STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STRING1} -STR_SAVEGAME_NAME_SPECTATOR :Spectator, {1:STRING1} - -# Viewport strings -STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) -STR_VIEWPORT_TOWN :{WHITE}{TOWN} -STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN} -STR_VIEWPORT_TOWN_TINY_WHITE :{TINY_FONT}{WHITE}{TOWN} - -STR_VIEWPORT_SIGN_SMALL_BLACK :{TINY_FONT}{BLACK}{SIGN} -STR_VIEWPORT_SIGN_SMALL_WHITE :{TINY_FONT}{WHITE}{SIGN} - -STR_VIEWPORT_STATION :{STATION} {STATION_FEATURES} -STR_VIEWPORT_STATION_TINY :{TINY_FONT}{STATION} - -STR_VIEWPORT_WAYPOINT :{WAYPOINT} -STR_VIEWPORT_WAYPOINT_TINY :{TINY_FONT}{WAYPOINT} - -# Simple strings to get specific types of data -STR_COMPANY_NAME :{COMPANY} -STR_COMPANY_NAME_COMPANY_NUM :{COMPANY} {COMPANY_NUM} -STR_DEPOT_NAME :{DEPOT} -STR_ENGINE_NAME :{ENGINE} -STR_GROUP_NAME :{GROUP} -STR_INDUSTRY_NAME :{INDUSTRY} -STR_PRESIDENT_NAME :{PRESIDENT_NAME} -STR_SIGN_NAME :{SIGN} -STR_STATION_NAME :{STATION} -STR_TOWN_NAME :{TOWN} -STR_VEHICLE_NAME :{VEHICLE} -STR_WAYPOINT_NAME :{WAYPOINT} - -STR_JUST_CARGO :{CARGO_LONG} -STR_JUST_CHECKMARK :{CHECKMARK} -STR_JUST_COMMA :{COMMA} -STR_JUST_CURRENCY_SHORT :{CURRENCY_SHORT} -STR_JUST_CURRENCY_LONG :{CURRENCY_LONG} -STR_JUST_CARGO_LIST :{CARGO_LIST} -STR_JUST_INT :{NUM} -STR_JUST_DATE_TINY :{DATE_TINY} -STR_JUST_DATE_SHORT :{DATE_SHORT} -STR_JUST_DATE_LONG :{DATE_LONG} -STR_JUST_DATE_ISO :{DATE_ISO} -STR_JUST_STRING :{STRING} -STR_JUST_STRING_STRING :{STRING}{STRING} -STR_JUST_RAW_STRING :{RAW_STRING} -STR_JUST_BIG_RAW_STRING :{BIG_FONT}{RAW_STRING} - -# Slightly 'raw' stringcodes with colour or size -STR_BLACK_COMMA :{BLACK}{COMMA} -STR_TINY_BLACK_COMA :{TINY_FONT}{BLACK}{COMMA} -STR_TINY_COMMA :{TINY_FONT}{COMMA} -STR_BLUE_COMMA :{BLUE}{COMMA} -STR_RED_COMMA :{RED}{COMMA} -STR_WHITE_COMMA :{WHITE}{COMMA} -STR_TINY_BLACK_DECIMAL :{TINY_FONT}{BLACK}{DECIMAL} -STR_COMPANY_MONEY :{WHITE}{CURRENCY_LONG} -STR_BLACK_DATE_LONG :{BLACK}{DATE_LONG} -STR_BLACK_CROSS :{BLACK}{CROSS} -STR_SILVER_CROSS :{SILVER}{CROSS} -STR_WHITE_DATE_LONG :{WHITE}{DATE_LONG} -STR_SHORT_DATE :{WHITE}{DATE_TINY} -STR_DATE_LONG_SMALL :{TINY_FONT}{BLACK}{DATE_LONG} -STR_TINY_GROUP :{TINY_FONT}{GROUP} -STR_BLACK_INT :{BLACK}{NUM} -STR_ORANGE_INT :{ORANGE}{NUM} -STR_WHITE_SIGN :{WHITE}{SIGN} -STR_TINY_BLACK_STATION :{TINY_FONT}{BLACK}{STATION} -STR_BLACK_STRING :{BLACK}{STRING} -STR_BLACK_RAW_STRING :{BLACK}{RAW_STRING} -STR_GREEN_STRING :{GREEN}{STRING} -STR_ORANGE_STRING :{ORANGE}{STRING} -STR_RED_STRING :{RED}{STRING} -STR_LTBLUE_STRING :{LTBLUE}{STRING} -STR_WHITE_STRING :{WHITE}{STRING} -STR_ORANGE_STRING1_WHITE :{ORANGE}{STRING1}{WHITE} -STR_ORANGE_STRING1_LTBLUE :{ORANGE}{STRING1}{LTBLUE} -STR_TINY_BLACK_HEIGHT :{TINY_FONT}{BLACK}{HEIGHT} -STR_TINY_BLACK_VEHICLE :{TINY_FONT}{BLACK}{VEHICLE} -STR_TINY_RIGHT_ARROW :{TINY_FONT}{RIGHT_ARROW} - -STR_BLACK_1 :{BLACK}1 -STR_BLACK_2 :{BLACK}2 -STR_BLACK_3 :{BLACK}3 -STR_BLACK_4 :{BLACK}4 -STR_BLACK_5 :{BLACK}5 -STR_BLACK_6 :{BLACK}6 -STR_BLACK_7 :{BLACK}7 - -STR_TRAIN :{BLACK}{TRAIN} -STR_BUS :{BLACK}{BUS} -STR_LORRY :{BLACK}{LORRY} -STR_PLANE :{BLACK}{PLANE} -STR_SHIP :{BLACK}{SHIP} - -STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) diff --git a/src/misc_gui.cpp.orig b/src/misc_gui.cpp.orig deleted file mode 100644 index 1746573c90..0000000000 --- a/src/misc_gui.cpp.orig +++ /dev/null @@ -1,1210 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file misc_gui.cpp GUIs for a number of misc windows. */ - -#include "stdafx.h" -#include "debug.h" -#include "landscape.h" -#include "error.h" -#include "gui.h" -#include "command_func.h" -#include "company_func.h" -#include "town.h" -#include "string_func.h" -#include "company_base.h" -#include "texteff.hpp" -#include "strings_func.h" -#include "window_func.h" -#include "querystring_gui.h" -#include "core/geometry_func.hpp" -#include "newgrf_debug.h" - -#include "widgets/misc_widget.h" - -#include "table/strings.h" - -/** Method to open the OSK. */ -enum OskActivation { - OSKA_DISABLED, ///< The OSK shall not be activated at all. - OSKA_DOUBLE_CLICK, ///< Double click on the edit box opens OSK. - OSKA_SINGLE_CLICK, ///< Single click after focus click opens OSK. - OSKA_IMMEDIATELY, ///< Focusing click already opens OSK. -}; - - -static const NWidgetPart _nested_land_info_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_LAND_AREA_INFORMATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_DEBUGBOX, COLOUR_GREY), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_LI_BACKGROUND), EndContainer(), -}; - -static WindowDesc _land_info_desc( - WDP_AUTO, "land_info", 0, 0, - WC_LAND_INFO, WC_NONE, - 0, - _nested_land_info_widgets, lengthof(_nested_land_info_widgets) -); - -class LandInfoWindow : public Window { - enum LandInfoLines { - LAND_INFO_CENTERED_LINES = 32, ///< Up to 32 centered lines (arbitrary limit) - LAND_INFO_MULTICENTER_LINE = LAND_INFO_CENTERED_LINES, ///< One multicenter line - LAND_INFO_LINE_END, - }; - - static const uint LAND_INFO_LINE_BUFF_SIZE = 512; - -public: - char landinfo_data[LAND_INFO_LINE_END][LAND_INFO_LINE_BUFF_SIZE]; - TileIndex tile; - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (widget != WID_LI_BACKGROUND) return; - - uint y = r.top + WD_TEXTPANEL_TOP; - for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) { - if (StrEmpty(this->landinfo_data[i])) break; - - DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, this->landinfo_data[i], i == 0 ? TC_LIGHT_BLUE : TC_FROMSTRING, SA_HOR_CENTER); - y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; - if (i == 0) y += 4; - } - - if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) { - SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]); - DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, r.bottom - WD_TEXTPANEL_BOTTOM, STR_JUST_RAW_STRING, TC_FROMSTRING, SA_CENTER); - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - if (widget != WID_LI_BACKGROUND) return; - - size->height = WD_TEXTPANEL_TOP + WD_TEXTPANEL_BOTTOM; - for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) { - if (StrEmpty(this->landinfo_data[i])) break; - - uint width = GetStringBoundingBox(this->landinfo_data[i]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; - size->width = max(size->width, width); - - size->height += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; - if (i == 0) size->height += 4; - } - - if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) { - uint width = GetStringBoundingBox(this->landinfo_data[LAND_INFO_MULTICENTER_LINE]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; - size->width = max(size->width, min(300u, width)); - SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]); - size->height += GetStringHeight(STR_JUST_RAW_STRING, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT); - } - } - - LandInfoWindow(TileIndex tile) : Window(&_land_info_desc), tile(tile) - { - this->InitNested(); - -#if defined(_DEBUG) -# define LANDINFOD_LEVEL 0 -#else -# define LANDINFOD_LEVEL 1 -#endif - DEBUG(misc, LANDINFOD_LEVEL, "TILE: %#x (%i,%i)", tile, TileX(tile), TileY(tile)); - DEBUG(misc, LANDINFOD_LEVEL, "type_height = %#x", _m[tile].type_height); - DEBUG(misc, LANDINFOD_LEVEL, "m1 = %#x", _m[tile].m1); - DEBUG(misc, LANDINFOD_LEVEL, "m2 = %#x", _m[tile].m2); - DEBUG(misc, LANDINFOD_LEVEL, "m3 = %#x", _m[tile].m3); - DEBUG(misc, LANDINFOD_LEVEL, "m4 = %#x", _m[tile].m4); - DEBUG(misc, LANDINFOD_LEVEL, "m5 = %#x", _m[tile].m5); - DEBUG(misc, LANDINFOD_LEVEL, "m6 = %#x", _m[tile].m6); - DEBUG(misc, LANDINFOD_LEVEL, "m7 = %#x", _me[tile].m7); -#undef LANDINFOD_LEVEL - } - - virtual void OnInit() - { - Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); - - /* Because build_date is not set yet in every TileDesc, we make sure it is empty */ - TileDesc td; - - td.build_date = INVALID_DATE; - - /* Most tiles have only one owner, but - * - drivethrough roadstops can be build on town owned roads (up to 2 owners) and - * - roads can have up to four owners (railroad, road, tram, 3rd-roadtype "highway"). - */ - td.owner_type[0] = STR_LAND_AREA_INFORMATION_OWNER; // At least one owner is displayed, though it might be "N/A". - td.owner_type[1] = STR_NULL; // STR_NULL results in skipping the owner - td.owner_type[2] = STR_NULL; - td.owner_type[3] = STR_NULL; - td.owner[0] = OWNER_NONE; - td.owner[1] = OWNER_NONE; - td.owner[2] = OWNER_NONE; - td.owner[3] = OWNER_NONE; - - td.station_class = STR_NULL; - td.station_name = STR_NULL; - td.airport_class = STR_NULL; - td.airport_name = STR_NULL; - td.airport_tile_name = STR_NULL; - td.rail_speed = 0; - td.road_speed = 0; - - td.grf = NULL; - - CargoArray acceptance; - AddAcceptedCargo(tile, acceptance, NULL); - GetTileDesc(tile, &td); - - uint line_nr = 0; - - /* Tiletype */ - SetDParam(0, td.dparam[0]); - GetString(this->landinfo_data[line_nr], td.str, lastof(this->landinfo_data[line_nr])); - line_nr++; - - /* Up to four owners */ - for (uint i = 0; i < 4; i++) { - if (td.owner_type[i] == STR_NULL) continue; - - SetDParam(0, STR_LAND_AREA_INFORMATION_OWNER_N_A); - if (td.owner[i] != OWNER_NONE && td.owner[i] != OWNER_WATER) GetNameOfOwner(td.owner[i], tile); - GetString(this->landinfo_data[line_nr], td.owner_type[i], lastof(this->landinfo_data[line_nr])); - line_nr++; - } - - /* Cost to clear/revenue when cleared */ - StringID str = STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A; - Company *c = Company::GetIfValid(_local_company); - if (c != NULL) { - Money old_money = c->money; - c->money = INT64_MAX; - assert(_current_company == _local_company); - CommandCost costclear = DoCommand(tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR); - c->money = old_money; - if (costclear.Succeeded()) { - Money cost = costclear.GetCost(); - if (cost < 0) { - cost = -cost; // Negate negative cost to a positive revenue - str = STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED; - } else { - str = STR_LAND_AREA_INFORMATION_COST_TO_CLEAR; - } - SetDParam(0, cost); - } - } - GetString(this->landinfo_data[line_nr], str, lastof(this->landinfo_data[line_nr])); - line_nr++; - - /* Location */ - char tmp[16]; - snprintf(tmp, lengthof(tmp), "0x%.4X", tile); - SetDParam(0, TileX(tile)); - SetDParam(1, TileY(tile)); - SetDParam(2, GetTileZ(tile)); - SetDParamStr(3, tmp); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_LANDINFO_COORDS, lastof(this->landinfo_data[line_nr])); - line_nr++; - - /* Local authority */ - SetDParam(0, STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE); - if (t != NULL) { - SetDParam(0, STR_TOWN_NAME); - SetDParam(1, t->index); - } - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY, lastof(this->landinfo_data[line_nr])); - line_nr++; - - /* Build date */ - if (td.build_date != INVALID_DATE) { - SetDParam(0, td.build_date); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_BUILD_DATE, lastof(this->landinfo_data[line_nr])); - line_nr++; - } - - /* Station class */ - if (td.station_class != STR_NULL) { - SetDParam(0, td.station_class); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_STATION_CLASS, lastof(this->landinfo_data[line_nr])); - line_nr++; - } - - /* Station type name */ - if (td.station_name != STR_NULL) { - SetDParam(0, td.station_name); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_STATION_TYPE, lastof(this->landinfo_data[line_nr])); - line_nr++; - } - - /* Airport class */ - if (td.airport_class != STR_NULL) { - SetDParam(0, td.airport_class); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORT_CLASS, lastof(this->landinfo_data[line_nr])); - line_nr++; - } - - /* Airport name */ - if (td.airport_name != STR_NULL) { - SetDParam(0, td.airport_name); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORT_NAME, lastof(this->landinfo_data[line_nr])); - line_nr++; - } - - /* Airport tile name */ - if (td.airport_tile_name != STR_NULL) { - SetDParam(0, td.airport_tile_name); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME, lastof(this->landinfo_data[line_nr])); - line_nr++; - } - - /* Rail speed limit */ - if (td.rail_speed != 0) { - SetDParam(0, td.rail_speed); - GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); - line_nr++; - } - - /* Road speed limit */ - if (td.road_speed != 0) { - SetDParam(0, td.road_speed); - GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); - line_nr++; - } - - /* NewGRF name */ - if (td.grf != NULL) { - SetDParamStr(0, td.grf); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_NEWGRF_NAME, lastof(this->landinfo_data[line_nr])); - line_nr++; - } - - assert(line_nr < LAND_INFO_CENTERED_LINES); - - /* Mark last line empty */ - this->landinfo_data[line_nr][0] = '\0'; - - /* Cargo acceptance is displayed in a extra multiline */ - char *strp = GetString(this->landinfo_data[LAND_INFO_MULTICENTER_LINE], STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); - bool found = false; - - for (CargoID i = 0; i < NUM_CARGO; ++i) { - if (acceptance[i] > 0) { - /* Add a comma between each item. */ - if (found) { - *strp++ = ','; - *strp++ = ' '; - } - found = true; - - /* If the accepted value is less than 8, show it in 1/8:ths */ - if (acceptance[i] < 8) { - SetDParam(0, acceptance[i]); - SetDParam(1, CargoSpec::Get(i)->name); - strp = GetString(strp, STR_LAND_AREA_INFORMATION_CARGO_EIGHTS, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); - } else { - strp = GetString(strp, CargoSpec::Get(i)->name, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); - } - } - } - if (!found) this->landinfo_data[LAND_INFO_MULTICENTER_LINE][0] = '\0'; - } - - virtual bool IsNewGRFInspectable() const - { - return ::IsNewGRFInspectable(GetGrfSpecFeature(this->tile), this->tile); - } - - virtual void ShowNewGRFInspectWindow() const - { - ::ShowNewGRFInspectWindow(GetGrfSpecFeature(this->tile), this->tile); - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - switch (data) { - case 1: - /* ReInit, "debug" sprite might have changed */ - this->ReInit(); - break; - } - } -}; - -/** - * Show land information window. - * @param tile The tile to show information about. - */ -void ShowLandInfo(TileIndex tile) -{ - DeleteWindowById(WC_LAND_INFO, 0); - new LandInfoWindow(tile); -} - -static const NWidgetPart _nested_about_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_ABOUT_OPENTTD, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY), SetPIP(4, 2, 4), - NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_ABOUT_ORIGINAL_COPYRIGHT, STR_NULL), - NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_ABOUT_VERSION, STR_NULL), - NWidget(WWT_FRAME, COLOUR_GREY), SetPadding(0, 5, 1, 5), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_A_SCROLLING_TEXT), - EndContainer(), - NWidget(WWT_LABEL, COLOUR_GREY, WID_A_WEBSITE), SetDataTip(STR_BLACK_RAW_STRING, STR_NULL), - NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_ABOUT_COPYRIGHT_OPENTTD, STR_NULL), - EndContainer(), -}; - -static WindowDesc _about_desc( - WDP_CENTER, NULL, 0, 0, - WC_GAME_OPTIONS, WC_NONE, - 0, - _nested_about_widgets, lengthof(_nested_about_widgets) -); - -static const char * const _credits[] = { - "Original design by Chris Sawyer", - "Original graphics by Simon Foster", - "", - "The OpenTTD team (in alphabetical order):", - " Albert Hofkamp (Alberth) - GUI expert", - " Jean-Fran\xC3\xA7ois Claeys (Belugas) - GUI, newindustries and more", - " Matthijs Kooijman (blathijs) - Pathfinder-guru, pool rework", - " Christoph Elsenhans (frosch) - General coding", - " Ulf Hermann (fonsinchen) - Cargo Distribution", - " Lo\xC3\xAF""c Guilloux (glx) - Windows Expert", - " Michael Lutz (michi_cc) - Path based signals", - " Owen Rudge (orudge) - Forum host, OS/2 port", - " Peter Nelson (peter1138) - Spiritual descendant from NewGRF gods", - " Ingo von Borstel (planetmaker) - Support", - " Remko Bijker (Rubidium) - Lead coder and way more", - " Zden\xC4\x9Bk Sojka (SmatZ) - Bug finder and fixer", - " Jos\xC3\xA9 Soler (Terkhen) - General coding", - " Thijs Marinussen (Yexo) - AI Framework", - " Leif Linse (Zuu) - AI/Game Script", - "", - "Inactive Developers:", - " Bjarni Corfitzen (Bjarni) - MacOSX port, coder and vehicles", - " Victor Fischer (Celestar) - Programming everywhere you need him to", - " Tam\xC3\xA1s Farag\xC3\xB3 (Darkvater) - Ex-Lead coder", - " Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;)", - " Jonathan Coome (Maedhros) - High priest of the NewGRF Temple", - " Attila B\xC3\xA1n (MiHaMiX) - Developer WebTranslator 1 and 2", - " Christoph Mallon (Tron) - Programmer, code correctness police", - "", - "Retired Developers:", - " Ludvig Strigeus (ludde) - OpenTTD author, main coder (0.1 - 0.3.3)", - " Serge Paquet (vurlix) - Assistant project manager, coder (0.1 - 0.3.3)", - " Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3.0 - 0.3.6)", - " Benedikt Br\xC3\xBCggemeier (skidd13) - Bug fixer and code reworker", - " Patric Stout (TrueBrain) - NoProgrammer (0.3 - 1.2), sys op (active)", - "", - "Special thanks go out to:", - " Josef Drexler - For his great work on TTDPatch", - " Marcin Grzegorczyk - Track foundations and for describing TTD internals", - " Petr Baudi\xC5\xA1 (pasky) - Many patches, newGRF support", - " Simon Sasburg (HackyKid) - Many bugfixes he has blessed us with", - " Stefan Mei\xC3\x9Fner (sign_de) - For his work on the console", - " Mike Ragsdale - OpenTTD installer", - " Cian Duffy (MYOB) - BeOS port / manual writing", - " Christian Rosentreter (tokai) - MorphOS / AmigaOS port", - " Richard Kempton (richK) - additional airports, initial TGP implementation", - "", - " Alberto Demichelis - Squirrel scripting language \xC2\xA9 2003-2008", - " L. Peter Deutsch - MD5 implementation \xC2\xA9 1999, 2000, 2002", - " Michael Blunck - Pre-signals and semaphores \xC2\xA9 2003", - " George - Canal/Lock graphics \xC2\xA9 2003-2004", - " Andrew Parkhouse (andythenorth) - River graphics", - " David Dallaston (Pikka) - Tram tracks", - " All Translators - Who made OpenTTD a truly international game", - " Bug Reporters - Without whom OpenTTD would still be full of bugs!", - "", - "", - "And last but not least:", - " Chris Sawyer - For an amazing game!" -}; - -struct AboutWindow : public Window { - int text_position; ///< The top of the scrolling text - byte counter; ///< Used to scroll the text every 5 ticks - int line_height; ///< The height of a single line - static const int num_visible_lines = 19; ///< The number of lines visible simultaneously - - AboutWindow() : Window(&_about_desc) - { - this->InitNested(WN_GAME_OPTIONS_ABOUT); - - this->counter = 5; - this->text_position = this->GetWidget(WID_A_SCROLLING_TEXT)->pos_y + this->GetWidget(WID_A_SCROLLING_TEXT)->current_y; - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_A_WEBSITE) SetDParamStr(0, "Website: http://www.openttd.org"); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - if (widget != WID_A_SCROLLING_TEXT) return; - - this->line_height = FONT_HEIGHT_NORMAL; - - Dimension d; - d.height = this->line_height * num_visible_lines; - - d.width = 0; - for (uint i = 0; i < lengthof(_credits); i++) { - d.width = max(d.width, GetStringBoundingBox(_credits[i]).width); - } - *size = maxdim(*size, d); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (widget != WID_A_SCROLLING_TEXT) return; - - int y = this->text_position; - - /* Show all scrolling _credits */ - for (uint i = 0; i < lengthof(_credits); i++) { - if (y >= r.top + 7 && y < r.bottom - this->line_height) { - DrawString(r.left, r.right, y, _credits[i], TC_BLACK, SA_LEFT | SA_FORCE); - } - y += this->line_height; - } - } - - virtual void OnTick() - { - if (--this->counter == 0) { - this->counter = 5; - this->text_position--; - /* If the last text has scrolled start a new from the start */ - if (this->text_position < (int)(this->GetWidget(WID_A_SCROLLING_TEXT)->pos_y - lengthof(_credits) * this->line_height)) { - this->text_position = this->GetWidget(WID_A_SCROLLING_TEXT)->pos_y + this->GetWidget(WID_A_SCROLLING_TEXT)->current_y; - } - this->SetDirty(); - } - } -}; - -void ShowAboutWindow() -{ - DeleteWindowByClass(WC_GAME_OPTIONS); - new AboutWindow(); -} - -/** - * Display estimated costs. - * @param cost Estimated cost (or income if negative). - * @param x X position of the notification window. - * @param y Y position of the notification window. - */ -void ShowEstimatedCostOrIncome(Money cost, int x, int y) -{ - StringID msg = STR_MESSAGE_ESTIMATED_COST; - - if (cost < 0) { - cost = -cost; - msg = STR_MESSAGE_ESTIMATED_INCOME; - } - SetDParam(0, cost); - ShowErrorMessage(msg, INVALID_STRING_ID, WL_INFO, x, y); -} - -/** - * Display animated income or costs on the map. - * @param x World X position of the animation location. - * @param y World Y position of the animation location. - * @param z World Z position of the animation location. - * @param cost Estimated cost (or income if negative). - */ -void ShowCostOrIncomeAnimation(int x, int y, int z, Money cost) -{ - Point pt = RemapCoords(x, y, z); - StringID msg = STR_INCOME_FLOAT_COST; - - if (cost < 0) { - cost = -cost; - msg = STR_INCOME_FLOAT_INCOME; - } - SetDParam(0, cost); - AddTextEffect(msg, pt.x, pt.y, DAY_TICKS, TE_RISING); -} - -/** - * Display animated feeder income. - * @param x World X position of the animation location. - * @param y World Y position of the animation location. - * @param z World Z position of the animation location. - * @param transfer Estimated feeder income. - * @param income Real income from goods being delivered to their final destination. - */ -void ShowFeederIncomeAnimation(int x, int y, int z, Money transfer, Money income) -{ - Point pt = RemapCoords(x, y, z); - - SetDParam(0, transfer); - if (income == 0) { - AddTextEffect(STR_FEEDER, pt.x, pt.y, DAY_TICKS, TE_RISING); - } else { - StringID msg = STR_FEEDER_COST; - if (income < 0) { - income = -income; - msg = STR_FEEDER_INCOME; - } - SetDParam(1, income); - AddTextEffect(msg, pt.x, pt.y, DAY_TICKS, TE_RISING); - } -} - -/** - * Display vehicle loading indicators. - * @param x World X position of the animation location. - * @param y World Y position of the animation location. - * @param z World Z position of the animation location. - * @param percent Estimated feeder income. - * @param string String which is drawn on the map. - * @return TextEffectID to be used for future updates of the loading indicators. - */ -TextEffectID ShowFillingPercent(int x, int y, int z, uint8 percent, StringID string) -{ - Point pt = RemapCoords(x, y, z); - - assert(string != STR_NULL); - - SetDParam(0, percent); - return AddTextEffect(string, pt.x, pt.y, 0, TE_STATIC); -} - -/** - * Update vehicle loading indicators. - * @param te_id TextEffectID to be updated. - * @param string String wich is printed. - */ -void UpdateFillingPercent(TextEffectID te_id, uint8 percent, StringID string) -{ - assert(string != STR_NULL); - - SetDParam(0, percent); - UpdateTextEffect(te_id, string); -} - -/** - * Hide vehicle loading indicators. - * @param *te_id TextEffectID which is supposed to be hidden. - */ -void HideFillingPercent(TextEffectID *te_id) -{ - if (*te_id == INVALID_TE_ID) return; - - RemoveTextEffect(*te_id); - *te_id = INVALID_TE_ID; -} - -static const NWidgetPart _nested_tooltips_widgets[] = { - NWidget(WWT_PANEL, COLOUR_GREY, WID_TT_BACKGROUND), SetMinimalSize(200, 32), EndContainer(), -}; - -static WindowDesc _tool_tips_desc( - WDP_MANUAL, NULL, 0, 0, // Coordinates and sizes are not used, - WC_TOOLTIPS, WC_NONE, - 0, - _nested_tooltips_widgets, lengthof(_nested_tooltips_widgets) -); - -/** Window for displaying a tooltip. */ -struct TooltipsWindow : public Window -{ - StringID string_id; ///< String to display as tooltip. - byte paramcount; ///< Number of string parameters in #string_id. - uint64 params[5]; ///< The string parameters. - TooltipCloseCondition close_cond; ///< Condition for closing the window. - - TooltipsWindow(Window *parent, StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_tooltip) : Window(&_tool_tips_desc) - { - this->parent = parent; - this->string_id = str; - assert_compile(sizeof(this->params[0]) == sizeof(params[0])); - assert(paramcount <= lengthof(this->params)); - memcpy(this->params, params, sizeof(this->params[0]) * paramcount); - this->paramcount = paramcount; - this->close_cond = close_tooltip; - - this->InitNested(); - - CLRBITS(this->flags, WF_WHITE_BORDER); - } - - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) - { - /* Find the free screen space between the main toolbar at the top, and the statusbar at the bottom. - * Add a fixed distance 2 so the tooltip floats free from both bars. - */ - int scr_top = GetMainViewTop() + 2; - int scr_bot = GetMainViewBottom() - 2; - - Point pt; - - /* Correctly position the tooltip position, watch out for window and cursor size - * Clamp value to below main toolbar and above statusbar. If tooltip would - * go below window, flip it so it is shown above the cursor */ - pt.y = Clamp(_cursor.pos.y + _cursor.size.y + _cursor.offs.y + 5, scr_top, scr_bot); - if (pt.y + sm_height > scr_bot) pt.y = min(_cursor.pos.y + _cursor.offs.y - 5, scr_bot) - sm_height; - pt.x = sm_width >= _screen.width ? 0 : Clamp(_cursor.pos.x - (sm_width >> 1), 0, _screen.width - sm_width); - - return pt; - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - /* There is only one widget. */ - for (uint i = 0; i != this->paramcount; i++) SetDParam(i, this->params[i]); - - size->width = min(GetStringBoundingBox(this->string_id).width, 194); - size->height = GetStringHeight(this->string_id, size->width); - - /* Increase slightly to have some space around the box. */ - size->width += 2 + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - size->height += 2 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - /* There is only one widget. */ - GfxFillRect(r.left, r.top, r.right, r.bottom, PC_BLACK); - GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_LIGHT_YELLOW); - - for (uint arg = 0; arg < this->paramcount; arg++) { - SetDParam(arg, this->params[arg]); - } - DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, this->string_id, TC_FROMSTRING, SA_CENTER); - } - - virtual void OnMouseLoop() - { - /* Always close tooltips when the cursor is not in our window. */ - if (!_cursor.in_window) { - delete this; - return; - } - - /* We can show tooltips while dragging tools. These are shown as long as - * we are dragging the tool. Normal tooltips work with hover or rmb. */ - switch (this->close_cond) { - case TCC_RIGHT_CLICK: if (!_right_button_down) delete this; break; - case TCC_LEFT_CLICK: if (!_left_button_down) delete this; break; - case TCC_HOVER: if (!_mouse_hovering) delete this; break; - } - } -}; - -/** - * Shows a tooltip - * @param parent The window this tooltip is related to. - * @param str String to be displayed - * @param paramcount number of params to deal with - * @param params (optional) up to 5 pieces of additional information that may be added to a tooltip - * @param use_left_mouse_button close the tooltip when the left (true) or right (false) mouse button is released - */ -void GuiShowTooltips(Window *parent, StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_tooltip) -{ - DeleteWindowById(WC_TOOLTIPS, 0); - - if (str == STR_NULL) return; - - new TooltipsWindow(parent, str, paramcount, params, close_tooltip); -} - -void QueryString::HandleEditBox(Window *w, int wid) -{ - if (w->IsWidgetGloballyFocused(wid) && this->text.HandleCaret()) { - w->SetWidgetDirty(wid); - - /* For the OSK also invalidate the parent window */ - if (w->window_class == WC_OSK) w->InvalidateData(); - } -} - -void QueryString::DrawEditBox(const Window *w, int wid) const -{ - const NWidgetLeaf *wi = w->GetWidget(wid); - - assert((wi->type & WWT_MASK) == WWT_EDITBOX); - - bool rtl = _current_text_dir == TD_RTL; - Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); - int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; - - int clearbtn_left = wi->pos_x + (rtl ? 0 : wi->current_x - clearbtn_width); - int clearbtn_right = wi->pos_x + (rtl ? clearbtn_width : wi->current_x) - 1; - int left = wi->pos_x + (rtl ? clearbtn_width : 0); - int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; - - int top = wi->pos_y; - int bottom = wi->pos_y + wi->current_y - 1; - - DrawFrameRect(clearbtn_left, top, clearbtn_right, bottom, wi->colour, wi->IsLowered() ? FR_LOWERED : FR_NONE); - DrawSprite(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT, PAL_NONE, clearbtn_left + WD_IMGBTN_LEFT + (wi->IsLowered() ? 1 : 0), (top + bottom - sprite_size.height) / 2 + (wi->IsLowered() ? 1 : 0)); - if (this->text.bytes == 1) GfxFillRect(clearbtn_left + 1, top + 1, clearbtn_right - 1, bottom - 1, _colour_gradient[wi->colour & 0xF][2], FILLRECT_CHECKER); - - DrawFrameRect(left, top, right, bottom, wi->colour, FR_LOWERED | FR_DARKENED); - GfxFillRect(left + 1, top + 1, right - 1, bottom - 1, PC_BLACK); - - /* Limit the drawing of the string inside the widget boundaries */ - DrawPixelInfo dpi; - if (!FillDrawPixelInfo(&dpi, left + WD_FRAMERECT_LEFT, top + WD_FRAMERECT_TOP, right - left - WD_FRAMERECT_RIGHT, bottom - top - WD_FRAMERECT_BOTTOM)) return; - - DrawPixelInfo *old_dpi = _cur_dpi; - _cur_dpi = &dpi; - - /* We will take the current widget length as maximum width, with a small - * space reserved at the end for the caret to show */ - const Textbuf *tb = &this->text; - int delta = min(0, (right - left) - tb->pixels - 10); - - if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; - - /* If we have a marked area, draw a background highlight. */ - if (tb->marklength != 0) GfxFillRect(delta + tb->markxoffs, 0, delta + tb->markxoffs + tb->marklength - 1, bottom - top, PC_GREY); - - DrawString(delta, tb->pixels, Center(0, bottom - top), tb->buf, TC_YELLOW); - - bool focussed = w->IsWidgetGloballyFocused(wid) || IsOSKOpenedFor(w, wid); - if (focussed && tb->caret) { - int caret_width = GetStringBoundingBox("_").width; - DrawString(tb->caretxoffs + delta, tb->caretxoffs + delta + caret_width, Center(0, bottom - top), "_", TC_WHITE); - } - - _cur_dpi = old_dpi; -} - -/** - * Get the current caret position. - * @param w Window the edit box is in. - * @param wid Widget index. - * @return Top-left location of the caret, relative to the window. - */ -Point QueryString::GetCaretPosition(const Window *w, int wid) const -{ - const NWidgetLeaf *wi = w->GetWidget(wid); - - assert((wi->type & WWT_MASK) == WWT_EDITBOX); - - bool rtl = _current_text_dir == TD_RTL; - Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); - int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; - - int left = wi->pos_x + (rtl ? clearbtn_width : 0); - int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; - - /* Clamp caret position to be inside out current width. */ - const Textbuf *tb = &this->text; - int delta = min(0, (right - left) - tb->pixels - 10); - if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; - - Point pt = {left + WD_FRAMERECT_LEFT + tb->caretxoffs + delta, wi->pos_y + WD_FRAMERECT_TOP}; - return pt; -} - -/** - * Get the bounding rectangle for a range of the query string. - * @param w Window the edit box is in. - * @param wid Widget index. - * @param from Start of the string range. - * @param to End of the string range. - * @return Rectangle encompassing the string range, relative to the window. - */ -Rect QueryString::GetBoundingRect(const Window *w, int wid, const char *from, const char *to) const -{ - const NWidgetLeaf *wi = w->GetWidget(wid); - - assert((wi->type & WWT_MASK) == WWT_EDITBOX); - - bool rtl = _current_text_dir == TD_RTL; - Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); - int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; - - int left = wi->pos_x + (rtl ? clearbtn_width : 0); - int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; - - int top = wi->pos_y + WD_FRAMERECT_TOP; - int bottom = wi->pos_y + wi->current_y - 1 - WD_FRAMERECT_BOTTOM; - - /* Clamp caret position to be inside our current width. */ - const Textbuf *tb = &this->text; - int delta = min(0, (right - left) - tb->pixels - 10); - if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; - - /* Get location of first and last character. */ - Point p1 = GetCharPosInString(tb->buf, from, FS_NORMAL); - Point p2 = from != to ? GetCharPosInString(tb->buf, to, FS_NORMAL) : p1; - - Rect r = { Clamp(left + p1.x + delta + WD_FRAMERECT_LEFT, left, right), top, Clamp(left + p2.x + delta + WD_FRAMERECT_LEFT, left, right - WD_FRAMERECT_RIGHT), bottom }; - - return r; -} - -/** - * Get the character that is rendered at a position. - * @param w Window the edit box is in. - * @param wid Widget index. - * @param pt Position to test. - * @return Pointer to the character at the position or NULL if no character is at the position. - */ -const char *QueryString::GetCharAtPosition(const Window *w, int wid, const Point &pt) const -{ - const NWidgetLeaf *wi = w->GetWidget(wid); - - assert((wi->type & WWT_MASK) == WWT_EDITBOX); - - bool rtl = _current_text_dir == TD_RTL; - Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); - int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; - - int left = wi->pos_x + (rtl ? clearbtn_width : 0); - int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; - - int top = wi->pos_y + WD_FRAMERECT_TOP; - int bottom = wi->pos_y + wi->current_y - 1 - WD_FRAMERECT_BOTTOM; - - if (!IsInsideMM(pt.y, top, bottom)) return NULL; - - /* Clamp caret position to be inside our current width. */ - const Textbuf *tb = &this->text; - int delta = min(0, (right - left) - tb->pixels - 10); - if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; - - return ::GetCharAtPosition(tb->buf, pt.x - delta - left); -} - -void QueryString::ClickEditBox(Window *w, Point pt, int wid, int click_count, bool focus_changed) -{ - const NWidgetLeaf *wi = w->GetWidget(wid); - - assert((wi->type & WWT_MASK) == WWT_EDITBOX); - - bool rtl = _current_text_dir == TD_RTL; - int clearbtn_width = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT).width; - - int clearbtn_left = wi->pos_x + (rtl ? 0 : wi->current_x - clearbtn_width); - - if (IsInsideBS(pt.x, clearbtn_left, clearbtn_width)) { - if (this->text.bytes > 1) { - this->text.DeleteAll(); - w->HandleButtonClick(wid); - w->OnEditboxChanged(wid); - } - return; - } - - if (w->window_class != WC_OSK && _settings_client.gui.osk_activation != OSKA_DISABLED && - (!focus_changed || _settings_client.gui.osk_activation == OSKA_IMMEDIATELY) && - (click_count == 2 || _settings_client.gui.osk_activation != OSKA_DOUBLE_CLICK)) { - /* Open the OSK window */ - ShowOnScreenKeyboard(w, wid); - } -} - -/** Class for the string query window. */ -struct QueryStringWindow : public Window -{ - QueryString editbox; ///< Editbox. - QueryStringFlags flags; ///< Flags controlling behaviour of the window. - - QueryStringWindow(StringID str, StringID caption, uint max_bytes, uint max_chars, WindowDesc *desc, Window *parent, CharSetFilter afilter, QueryStringFlags flags) : - Window(desc), editbox(max_bytes, max_chars) - { - char *last_of = &this->editbox.text.buf[this->editbox.text.max_bytes - 1]; - GetString(this->editbox.text.buf, str, last_of); - str_validate(this->editbox.text.buf, last_of, SVS_NONE); - - /* Make sure the name isn't too long for the text buffer in the number of - * characters (not bytes). max_chars also counts the '\0' characters. */ - while (Utf8StringLength(this->editbox.text.buf) + 1 > this->editbox.text.max_chars) { - *Utf8PrevChar(this->editbox.text.buf + strlen(this->editbox.text.buf)) = '\0'; - } - - this->editbox.text.UpdateSize(); - - if ((flags & QSF_ACCEPT_UNCHANGED) == 0) this->editbox.orig = strdup(this->editbox.text.buf); - - this->querystrings[WID_QS_TEXT] = &this->editbox; - this->editbox.caption = caption; - this->editbox.cancel_button = WID_QS_CANCEL; - this->editbox.ok_button = WID_QS_OK; - this->editbox.text.afilter = afilter; - this->flags = flags; - - this->InitNested(WN_QUERY_STRING); - - this->parent = parent; - - this->SetFocusedWidget(WID_QS_TEXT); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - if (widget == WID_QS_DEFAULT && (this->flags & QSF_ENABLE_DEFAULT) == 0) { - /* We don't want this widget to show! */ - fill->width = 0; - resize->width = 0; - size->width = 0; - } - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_QS_CAPTION) SetDParam(0, this->editbox.caption); - } - - void OnOk() - { - if (this->editbox.orig == NULL || strcmp(this->editbox.text.buf, this->editbox.orig) != 0) { - /* If the parent is NULL, the editbox is handled by general function - * HandleOnEditText */ - if (this->parent != NULL) { - this->parent->OnQueryTextFinished(this->editbox.text.buf); - } else { - HandleOnEditText(this->editbox.text.buf); - } - this->editbox.handled = true; - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_QS_DEFAULT: - this->editbox.text.DeleteAll(); - /* FALL THROUGH */ - case WID_QS_OK: - this->OnOk(); - /* FALL THROUGH */ - case WID_QS_CANCEL: - delete this; - break; - } - } - - ~QueryStringWindow() - { - if (!this->editbox.handled && this->parent != NULL) { - Window *parent = this->parent; - this->parent = NULL; // so parent doesn't try to delete us again - parent->OnQueryTextFinished(NULL); - } - } -}; - -static const NWidgetPart _nested_query_string_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, WID_QS_CAPTION), SetDataTip(STR_WHITE_STRING, STR_NULL), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY), - NWidget(WWT_EDITBOX, COLOUR_GREY, WID_QS_TEXT), SetMinimalSize(256, 12), SetFill(1, 1), SetPadding(2, 2, 2, 2), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_DEFAULT), SetMinimalSize(87, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_DEFAULT, STR_NULL), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_CANCEL), SetMinimalSize(86, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_OK), SetMinimalSize(87, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_OK, STR_NULL), - EndContainer(), -}; - -static WindowDesc _query_string_desc( - WDP_CENTER, "query_string", 0, 0, - WC_QUERY_STRING, WC_NONE, - 0, - _nested_query_string_widgets, lengthof(_nested_query_string_widgets) -); - -/** - * Show a query popup window with a textbox in it. - * @param str StringID for the text shown in the textbox - * @param caption StringID of text shown in caption of querywindow - * @param maxsize maximum size in bytes or characters (including terminating '\0') depending on flags - * @param parent pointer to a Window that will handle the events (ok/cancel) of this - * window. If NULL, results are handled by global function HandleOnEditText - * @param afilter filters out unwanted character input - * @param flags various flags, @see QueryStringFlags - */ -void ShowQueryString(StringID str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags) -{ - DeleteWindowByClass(WC_QUERY_STRING); - new QueryStringWindow(str, caption, ((flags & QSF_LEN_IN_CHARS) ? MAX_CHAR_LENGTH : 1) * maxsize, maxsize, &_query_string_desc, parent, afilter, flags); -} - -/** - * Window used for asking the user a YES/NO question. - */ -struct QueryWindow : public Window { - QueryCallbackProc *proc; ///< callback function executed on closing of popup. Window* points to parent, bool is true if 'yes' clicked, false otherwise - uint64 params[10]; ///< local copy of _decode_parameters - StringID message; ///< message shown for query window - StringID caption; ///< title of window - - QueryWindow(WindowDesc *desc, StringID caption, StringID message, Window *parent, QueryCallbackProc *callback) : Window(desc) - { - /* Create a backup of the variadic arguments to strings because it will be - * overridden pretty often. We will copy these back for drawing */ - CopyOutDParam(this->params, 0, lengthof(this->params)); - this->caption = caption; - this->message = message; - this->proc = callback; - - this->InitNested(WN_CONFIRM_POPUP_QUERY); - - this->parent = parent; - this->left = parent->left + (parent->width / 2) - (this->width / 2); - this->top = parent->top + (parent->height / 2) - (this->height / 2); - } - - ~QueryWindow() - { - if (this->proc != NULL) this->proc(this->parent, false); - } - - virtual void SetStringParameters(int widget) const - { - switch (widget) { - case WID_Q_CAPTION: - CopyInDParam(1, this->params, lengthof(this->params)); - SetDParam(0, this->caption); - break; - - case WID_Q_TEXT: - CopyInDParam(0, this->params, lengthof(this->params)); - break; - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - if (widget != WID_Q_TEXT) return; - - Dimension d = GetStringMultiLineBoundingBox(this->message, *size); - d.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; - d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - *size = d; - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (widget != WID_Q_TEXT) return; - - DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, - this->message, TC_FROMSTRING, SA_CENTER); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_Q_YES: { - /* in the Generate New World window, clicking 'Yes' causes - * DeleteNonVitalWindows() to be called - we shouldn't be in a window then */ - QueryCallbackProc *proc = this->proc; - Window *parent = this->parent; - /* Prevent the destructor calling the callback function */ - this->proc = NULL; - delete this; - if (proc != NULL) { - proc(parent, true); - proc = NULL; - } - break; - } - case WID_Q_NO: - delete this; - break; - } - } - - virtual EventState OnKeyPress(WChar key, uint16 keycode) - { - /* ESC closes the window, Enter confirms the action */ - switch (keycode) { - case WKC_RETURN: - case WKC_NUM_ENTER: - if (this->proc != NULL) { - this->proc(this->parent, true); - this->proc = NULL; - } - /* FALL THROUGH */ - case WKC_ESC: - delete this; - return ES_HANDLED; - } - return ES_NOT_HANDLED; - } -}; - -static const NWidgetPart _nested_query_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_RED), - NWidget(WWT_CAPTION, COLOUR_RED, WID_Q_CAPTION), SetDataTip(STR_JUST_STRING, STR_NULL), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_RED), SetPIP(8, 15, 8), - NWidget(WWT_TEXT, COLOUR_RED, WID_Q_TEXT), SetMinimalSize(200, 12), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY), SetFill(1, 1), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(20, 29, 20), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_Q_NO), SetMinimalSize(71, 12), SetDataTip(STR_QUIT_NO, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_Q_YES), SetMinimalSize(71, 12), SetDataTip(STR_QUIT_YES, STR_NULL), - EndContainer(), - NWidget(WWT_EMPTY), SetFill(1, 1), - EndContainer(), - EndContainer(), -}; - -static WindowDesc _query_desc( - WDP_CENTER, NULL, 0, 0, - WC_CONFIRM_POPUP_QUERY, WC_NONE, - WDF_MODAL, - _nested_query_widgets, lengthof(_nested_query_widgets) -); - -/** - * Show a modal confirmation window with standard 'yes' and 'no' buttons - * The window is aligned to the centre of its parent. - * @param caption string shown as window caption - * @param message string that will be shown for the window - * @param parent pointer to parent window, if this pointer is NULL the parent becomes - * the main window WC_MAIN_WINDOW - * @param callback callback function pointer to set in the window descriptor - */ -void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallbackProc *callback) -{ - if (parent == NULL) parent = FindWindowById(WC_MAIN_WINDOW, 0); - - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class != WC_CONFIRM_POPUP_QUERY) continue; - - const QueryWindow *qw = (const QueryWindow *)w; - if (qw->parent != parent || qw->proc != callback) continue; - - delete qw; - break; - } - - new QueryWindow(&_query_desc, caption, message, parent, callback); -} diff --git a/src/osk_gui.cpp.orig b/src/osk_gui.cpp.orig deleted file mode 100644 index d8d70e70c8..0000000000 --- a/src/osk_gui.cpp.orig +++ /dev/null @@ -1,459 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file osk_gui.cpp The On Screen Keyboard GUI */ - -#include "stdafx.h" -#include "string_func.h" -#include "strings_func.h" -#include "debug.h" -#include "window_func.h" -#include "gfx_func.h" -#include "querystring_gui.h" -#include "video/video_driver.hpp" - -#include "widgets/osk_widget.h" - -#include "table/sprites.h" -#include "table/strings.h" -#ifdef __ANDROID__ -#include -#endif - -char _keyboard_opt[2][OSK_KEYBOARD_ENTRIES * 4 + 1]; -static WChar _keyboard[2][OSK_KEYBOARD_ENTRIES]; - -enum KeyStateBits { - KEYS_NONE, - KEYS_SHIFT, - KEYS_CAPS -}; -static byte _keystate = KEYS_NONE; - -struct OskWindow : public Window { - StringID caption; ///< the caption for this window. - QueryString *qs; ///< text-input - int text_btn; ///< widget number of parent's text field - Textbuf *text; ///< pointer to parent's textbuffer (to update caret position) - char *orig_str_buf; ///< Original string. - bool shift; ///< Is the shift effectively pressed? - - OskWindow(WindowDesc *desc, Window *parent, int button) : Window(desc) - { - this->parent = parent; - assert(parent != NULL); - - NWidgetCore *par_wid = parent->GetWidget(button); - assert(par_wid != NULL); - - assert(parent->querystrings.Contains(button)); - this->qs = parent->querystrings.Find(button)->second; - this->caption = (par_wid->widget_data != STR_NULL) ? par_wid->widget_data : this->qs->caption; - this->text_btn = button; - this->text = &this->qs->text; - this->querystrings[WID_OSK_TEXT] = this->qs; - - /* make a copy in case we need to reset later */ - this->orig_str_buf = strdup(this->qs->text.buf); - - this->InitNested(0); - this->SetFocusedWidget(WID_OSK_TEXT); - - /* Not needed by default. */ - this->DisableWidget(WID_OSK_SPECIAL); - - this->UpdateOskState(); - } - - ~OskWindow() - { - free(this->orig_str_buf); - } - - /** - * Only show valid characters; do not show characters that would - * only insert a space when we have a spacebar to do that or - * characters that are not allowed to be entered. - */ - void UpdateOskState() - { - this->shift = HasBit(_keystate, KEYS_CAPS) ^ HasBit(_keystate, KEYS_SHIFT); - - for (uint i = 0; i < OSK_KEYBOARD_ENTRIES; i++) { - this->SetWidgetDisabledState(WID_OSK_LETTERS + i, - !IsValidChar(_keyboard[this->shift][i], this->qs->text.afilter) || _keyboard[this->shift][i] == ' '); - } - this->SetWidgetDisabledState(WID_OSK_SPACE, !IsValidChar(' ', this->qs->text.afilter)); - - this->SetWidgetLoweredState(WID_OSK_SHIFT, HasBit(_keystate, KEYS_SHIFT)); - this->SetWidgetLoweredState(WID_OSK_CAPS, HasBit(_keystate, KEYS_CAPS)); - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_OSK_CAPTION) SetDParam(0, this->caption); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (widget < WID_OSK_LETTERS) return; - - widget -= WID_OSK_LETTERS; - DrawCharCentered(_keyboard[this->shift][widget], - r.left + 8, - r.top + 3, - TC_BLACK); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - /* clicked a letter */ - if (widget >= WID_OSK_LETTERS) { - WChar c = _keyboard[this->shift][widget - WID_OSK_LETTERS]; - - if (!IsValidChar(c, this->qs->text.afilter)) return; - - if (this->qs->text.InsertChar(c)) this->OnEditboxChanged(WID_OSK_TEXT); - - if (HasBit(_keystate, KEYS_SHIFT)) { - ToggleBit(_keystate, KEYS_SHIFT); - this->UpdateOskState(); - this->SetDirty(); - } - return; - } - - switch (widget) { - case WID_OSK_BACKSPACE: - if (this->qs->text.DeleteChar(WKC_BACKSPACE)) this->OnEditboxChanged(WID_OSK_TEXT); - break; - - case WID_OSK_SPECIAL: - /* - * Anything device specific can go here. - * The button itself is hidden by default, and when you need it you - * can not hide it in the create event. - */ - break; - - case WID_OSK_CAPS: - ToggleBit(_keystate, KEYS_CAPS); - this->UpdateOskState(); - this->SetDirty(); - break; - - case WID_OSK_SHIFT: - ToggleBit(_keystate, KEYS_SHIFT); - this->UpdateOskState(); - this->SetDirty(); - break; - - case WID_OSK_SPACE: - if (this->qs->text.InsertChar(' ')) this->OnEditboxChanged(WID_OSK_TEXT); - break; - - case WID_OSK_LEFT: - if (this->qs->text.MovePos(WKC_LEFT)) this->InvalidateData(); - break; - - case WID_OSK_RIGHT: - if (this->qs->text.MovePos(WKC_RIGHT)) this->InvalidateData(); - break; - - case WID_OSK_OK: - if (this->qs->orig == NULL || strcmp(this->qs->text.buf, this->qs->orig) != 0) { - /* pass information by simulating a button press on parent window */ - if (this->qs->ok_button >= 0) { - this->parent->OnClick(pt, this->qs->ok_button, 1); - /* Window gets deleted when the parent window removes itself. */ - return; - } - } - delete this; - break; - - case WID_OSK_CANCEL: - if (this->qs->cancel_button >= 0) { // pass a cancel event to the parent window - this->parent->OnClick(pt, this->qs->cancel_button, 1); - /* Window gets deleted when the parent window removes itself. */ - return; - } else { // or reset to original string - qs->text.Assign(this->orig_str_buf); - qs->text.MovePos(WKC_END); - this->OnEditboxChanged(WID_OSK_TEXT); - delete this; - } - break; - } - } - - virtual void OnEditboxChanged(int widget) - { - this->SetWidgetDirty(WID_OSK_TEXT); - this->parent->OnEditboxChanged(this->text_btn); - this->parent->SetWidgetDirty(this->text_btn); - } - - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - this->SetWidgetDirty(WID_OSK_TEXT); - this->parent->SetWidgetDirty(this->text_btn); - } - - virtual void OnFocusLost() - { - _video_driver->EditBoxLostFocus(); - delete this; - } -}; - -static const int HALF_KEY_WIDTH = 7; // Width of 1/2 key in pixels. -static const int INTER_KEY_SPACE = 2; // Number of pixels between two keys. - -/** - * Add a key widget to a row of the keyboard. - * @param hor Row container to add key widget to. - * @param height Height of the key (all keys in a row should have equal height). - * @param num_half Number of 1/2 key widths that this key has. - * @param widtype Widget type of the key. Must be either \c NWID_SPACER for an invisible key, or a \c WWT_* widget. - * @param widnum Widget number of the key. - * @param widdata Data value of the key widget. - * @param biggest_index Collected biggest widget index so far. - * @note Key width is measured in 1/2 keys to allow for 1/2 key shifting between rows. - */ -static void AddKey(NWidgetHorizontal *hor, int height, int num_half, WidgetType widtype, int widnum, uint16 widdata, int *biggest_index) -{ - int key_width = HALF_KEY_WIDTH + (INTER_KEY_SPACE + HALF_KEY_WIDTH) * (num_half - 1); - - if (widtype == NWID_SPACER) { - if (!hor->IsEmpty()) key_width += INTER_KEY_SPACE; - NWidgetSpacer *spc = new NWidgetSpacer(key_width, height); - hor->Add(spc); - } else { - if (!hor->IsEmpty()) { - NWidgetSpacer *spc = new NWidgetSpacer(INTER_KEY_SPACE, height); - hor->Add(spc); - } - NWidgetLeaf *leaf = new NWidgetLeaf(widtype, COLOUR_GREY, widnum, widdata, STR_NULL); - leaf->SetMinimalSize(key_width, height); - hor->Add(leaf); - } - - *biggest_index = max(*biggest_index, widnum); -} - -/** Construct the top row keys (cancel, ok, backspace). */ -static NWidgetBase *MakeTopKeys(int *biggest_index) -{ - NWidgetHorizontal *hor = new NWidgetHorizontal(); - int key_height = FONT_HEIGHT_NORMAL + 2; - - AddKey(hor, key_height, 6 * 2, WWT_TEXTBTN, WID_OSK_CANCEL, STR_BUTTON_CANCEL, biggest_index); - AddKey(hor, key_height, 6 * 2, WWT_TEXTBTN, WID_OSK_OK, STR_BUTTON_OK, biggest_index); - AddKey(hor, key_height, 2 * 2, WWT_PUSHIMGBTN, WID_OSK_BACKSPACE, SPR_OSK_BACKSPACE, biggest_index); - return hor; -} - -/** Construct the row containing the digit keys. */ -static NWidgetBase *MakeNumberKeys(int *biggest_index) -{ - NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); - int key_height = FONT_HEIGHT_NORMAL + 6; - - for (int widnum = WID_OSK_NUMBERS_FIRST; widnum <= WID_OSK_NUMBERS_LAST; widnum++) { - AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); - } - return hor; -} - -/** Construct the qwerty row keys. */ -static NWidgetBase *MakeQwertyKeys(int *biggest_index) -{ - NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); - int key_height = FONT_HEIGHT_NORMAL + 6; - - AddKey(hor, key_height, 3, WWT_PUSHIMGBTN, WID_OSK_SPECIAL, SPR_OSK_SPECIAL, biggest_index); - for (int widnum = WID_OSK_QWERTY_FIRST; widnum <= WID_OSK_QWERTY_LAST; widnum++) { - AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); - } - AddKey(hor, key_height, 1, NWID_SPACER, 0, 0, biggest_index); - return hor; -} - -/** Construct the asdfg row keys. */ -static NWidgetBase *MakeAsdfgKeys(int *biggest_index) -{ - NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); - int key_height = FONT_HEIGHT_NORMAL + 6; - - AddKey(hor, key_height, 4, WWT_IMGBTN, WID_OSK_CAPS, SPR_OSK_CAPS, biggest_index); - for (int widnum = WID_OSK_ASDFG_FIRST; widnum <= WID_OSK_ASDFG_LAST; widnum++) { - AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); - } - return hor; -} - -/** Construct the zxcvb row keys. */ -static NWidgetBase *MakeZxcvbKeys(int *biggest_index) -{ - NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); - int key_height = FONT_HEIGHT_NORMAL + 6; - - AddKey(hor, key_height, 3, WWT_IMGBTN, WID_OSK_SHIFT, SPR_OSK_SHIFT, biggest_index); - for (int widnum = WID_OSK_ZXCVB_FIRST; widnum <= WID_OSK_ZXCVB_LAST; widnum++) { - AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); - } - AddKey(hor, key_height, 1, NWID_SPACER, 0, 0, biggest_index); - return hor; -} - -/** Construct the spacebar row keys. */ -static NWidgetBase *MakeSpacebarKeys(int *biggest_index) -{ - NWidgetHorizontal *hor = new NWidgetHorizontal(); - int key_height = FONT_HEIGHT_NORMAL + 6; - - AddKey(hor, key_height, 8, NWID_SPACER, 0, 0, biggest_index); - AddKey(hor, key_height, 13, WWT_PUSHTXTBTN, WID_OSK_SPACE, STR_EMPTY, biggest_index); - AddKey(hor, key_height, 3, NWID_SPACER, 0, 0, biggest_index); - AddKey(hor, key_height, 2, WWT_PUSHIMGBTN, WID_OSK_LEFT, SPR_OSK_LEFT, biggest_index); - AddKey(hor, key_height, 2, WWT_PUSHIMGBTN, WID_OSK_RIGHT, SPR_OSK_RIGHT, biggest_index); - return hor; -} - - -static const NWidgetPart _nested_osk_widgets[] = { - NWidget(WWT_CAPTION, COLOUR_GREY, WID_OSK_CAPTION), SetDataTip(STR_WHITE_STRING, STR_NULL), - NWidget(WWT_PANEL, COLOUR_GREY), - NWidget(WWT_EDITBOX, COLOUR_GREY, WID_OSK_TEXT), SetMinimalSize(252, 12), SetPadding(2, 2, 2, 2), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY), SetPIP(5, 2, 3), - NWidgetFunction(MakeTopKeys), SetPadding(0, 3, 0, 3), - NWidgetFunction(MakeNumberKeys), SetPadding(0, 3, 0, 3), - NWidgetFunction(MakeQwertyKeys), SetPadding(0, 3, 0, 3), - NWidgetFunction(MakeAsdfgKeys), SetPadding(0, 3, 0, 3), - NWidgetFunction(MakeZxcvbKeys), SetPadding(0, 3, 0, 3), - NWidgetFunction(MakeSpacebarKeys), SetPadding(0, 3, 0, 3), - EndContainer(), -}; - -static WindowDesc _osk_desc( - WDP_CENTER, "query_osk", 0, 0, - WC_OSK, WC_NONE, - 0, - _nested_osk_widgets, lengthof(_nested_osk_widgets) -); - -/** - * Retrieve keyboard layout from language string or (if set) config file. - * Also check for invalid characters. - */ -void GetKeyboardLayout() -{ - char keyboard[2][OSK_KEYBOARD_ENTRIES * 4 + 1]; - char errormark[2][OSK_KEYBOARD_ENTRIES + 1]; // used for marking invalid chars - bool has_error = false; // true when an invalid char is detected - - if (StrEmpty(_keyboard_opt[0])) { - GetString(keyboard[0], STR_OSK_KEYBOARD_LAYOUT, lastof(keyboard[0])); - } else { - strecpy(keyboard[0], _keyboard_opt[0], lastof(keyboard[0])); - } - - if (StrEmpty(_keyboard_opt[1])) { - GetString(keyboard[1], STR_OSK_KEYBOARD_LAYOUT_CAPS, lastof(keyboard[1])); - } else { - strecpy(keyboard[1], _keyboard_opt[1], lastof(keyboard[1])); - } - - for (uint j = 0; j < 2; j++) { - const char *kbd = keyboard[j]; - bool ended = false; - for (uint i = 0; i < OSK_KEYBOARD_ENTRIES; i++) { - _keyboard[j][i] = Utf8Consume(&kbd); - - /* Be lenient when the last characters are missing (is quite normal) */ - if (_keyboard[j][i] == '\0' || ended) { - ended = true; - _keyboard[j][i] = ' '; - continue; - } - - if (IsPrintable(_keyboard[j][i])) { - errormark[j][i] = ' '; - } else { - has_error = true; - errormark[j][i] = '^'; - _keyboard[j][i] = ' '; - } - } - } - - if (has_error) { - ShowInfoF("The keyboard layout you selected contains invalid chars. Please check those chars marked with ^."); - ShowInfoF("Normal keyboard: %s", keyboard[0]); - ShowInfoF(" %s", errormark[0]); - ShowInfoF("Caps Lock: %s", keyboard[1]); - ShowInfoF(" %s", errormark[1]); - } -} - -/** - * Show the on-screen keyboard (osk) associated with a given textbox - * @param parent pointer to the Window where this keyboard originated from - * @param button widget number of parent's textbox - */ -void ShowOnScreenKeyboard(Window *parent, int button) -{ - DeleteWindowById(WC_OSK, 0); - - GetKeyboardLayout(); - new OskWindow(&_osk_desc, parent, button); -#ifdef __ANDROID__ - char text[256]; - SDL_ANDROID_GetScreenKeyboardTextInput(text, sizeof(text) - 1); /* Invoke Android built-in screen keyboard */ - OskWindow *osk = dynamic_cast(FindWindowById(WC_OSK, 0)); - osk->qs->text.Assign(text); - free(osk->orig_str_buf); - osk->orig_str_buf = strdup(osk->qs->text.buf); - - osk->SetDirty(); -#endif -} - -/** - * Updates the original text of the OSK so when the 'parent' changes the - * original and you press on cancel you won't get the 'old' original text - * but the updated one. - * @param parent window that just updated its orignal text - * @param button widget number of parent's textbox to update - */ -void UpdateOSKOriginalText(const Window *parent, int button) -{ - OskWindow *osk = dynamic_cast(FindWindowById(WC_OSK, 0)); - if (osk == NULL || osk->parent != parent || osk->text_btn != button) return; - - free(osk->orig_str_buf); - osk->orig_str_buf = strdup(osk->qs->text.buf); - - osk->SetDirty(); -} - -/** - * Check whether the OSK is opened for a specific editbox. - * @parent w Window to check for - * @param button Editbox of \a w to check for - * @return true if the OSK is oppened for \a button. - */ -bool IsOSKOpenedFor(const Window *w, int button) -{ - OskWindow *osk = dynamic_cast(FindWindowById(WC_OSK, 0)); - return osk != NULL && osk->parent == w && osk->text_btn == button; -} diff --git a/src/rail_gui.cpp.orig b/src/rail_gui.cpp.orig deleted file mode 100644 index cb4f16f12f..0000000000 --- a/src/rail_gui.cpp.orig +++ /dev/null @@ -1,1991 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file rail_gui.cpp %File for dealing with rail construction user interface */ - -#include "stdafx.h" -#include "gui.h" -#include "window_gui.h" -#include "station_gui.h" -#include "terraform_gui.h" -#include "viewport_func.h" -#include "command_func.h" -#include "waypoint_func.h" -#include "newgrf_station.h" -#include "company_base.h" -#include "strings_func.h" -#include "window_func.h" -#include "date_func.h" -#include "sound_func.h" -#include "company_func.h" -#include "widgets/dropdown_type.h" -#include "tunnelbridge.h" -#include "tilehighlight_func.h" -#include "spritecache.h" -#include "core/geometry_func.hpp" -#include "hotkeys.h" -#include "engine_base.h" -#include "vehicle_func.h" -#include "zoom_func.h" -#include "rail_gui.h" - -#include "station_map.h" -#include "tunnelbridge_map.h" - -#include "widgets/rail_widget.h" - - -static RailType _cur_railtype; ///< Rail type of the current build-rail toolbar. -static bool _remove_button_clicked; ///< Flag whether 'remove' toggle-button is currently enabled -static DiagDirection _build_depot_direction; ///< Currently selected depot direction -static byte _waypoint_count = 1; ///< Number of waypoint types -static byte _cur_waypoint_type; ///< Currently selected waypoint type -static bool _convert_signal_button; ///< convert signal button in the signal GUI pressed -static SignalVariant _cur_signal_variant; ///< set the signal variant (for signal GUI) -static SignalType _cur_signal_type; ///< set the signal type (for signal GUI) - -/* Map the setting: default_signal_type to the corresponding signal type */ -static const SignalType _default_signal_type[] = {SIGTYPE_NORMAL, SIGTYPE_PBS, SIGTYPE_PBS_ONEWAY}; - -struct RailStationGUISettings { - Axis orientation; ///< Currently selected rail station orientation - - bool newstations; ///< Are custom station definitions available? - StationClassID station_class; ///< Currently selected custom station class (if newstations is \c true ) - byte station_type; ///< %Station type within the currently selected custom station class (if newstations is \c true ) - byte station_count; ///< Number of custom stations (if newstations is \c true ) -}; -static RailStationGUISettings _railstation; ///< Settings of the station builder GUI - - -static void HandleStationPlacement(TileIndex start, TileIndex end); -static void ShowBuildTrainDepotPicker(Window *parent); -static void ShowBuildWaypointPicker(Window *parent); -static void ShowStationBuilder(Window *parent); -static void ShowSignalBuilder(Window *parent); - -/** - * Check whether a station type can be build. - * @return true if building is allowed. - */ -static bool IsStationAvailable(const StationSpec *statspec) -{ - if (statspec == NULL || !HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) return true; - - uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE); - if (cb_res == CALLBACK_FAILED) return true; - - return Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res); -} - -void CcPlaySound1E(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_2, tile); -} - -static void GenericPlaceRail(TileIndex tile, int cmd) -{ - DoCommandP(tile, _cur_railtype, cmd, - _remove_button_clicked ? - CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) : - CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), - CcPlaySound1E); -} - -/** - * Try to add an additional rail-track at the entrance of a depot - * @param tile Tile to use for adding the rail-track - * @param dir Direction to check for already present tracks - * @param track Track to add - * @see CcRailDepot() - */ -static void PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Track track) -{ - if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return; - if ((GetTrackBits(tile) & DiagdirReachesTracks(dir)) == 0) return; - - DoCommandP(tile, _cur_railtype, track, CMD_BUILD_SINGLE_RAIL); -} - -/** Additional pieces of track to add at the entrance of a depot. */ -static const Track _place_depot_extra_track[12] = { - TRACK_LEFT, TRACK_UPPER, TRACK_UPPER, TRACK_RIGHT, // First additional track for directions 0..3 - TRACK_X, TRACK_Y, TRACK_X, TRACK_Y, // Second additional track - TRACK_LOWER, TRACK_LEFT, TRACK_RIGHT, TRACK_LOWER, // Third additional track -}; - -/** Direction to check for existing track pieces. */ -static const DiagDirection _place_depot_extra_dir[12] = { - DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE, DIAGDIR_SW, - DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_SE, - DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_NW, DIAGDIR_NE, -}; - -void CcRailDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Failed()) return; - - DiagDirection dir = (DiagDirection)p2; - - if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_2, tile); - if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - - tile += TileOffsByDiagDir(dir); - - if (IsTileType(tile, MP_RAILWAY)) { - PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]); - PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 4], _place_depot_extra_track[dir + 4]); - PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 8], _place_depot_extra_track[dir + 8]); - } -} - -/** - * Place a rail waypoint. - * @param tile Position to start dragging a waypoint. - */ -static void PlaceRail_Waypoint(TileIndex tile) -{ - if (_remove_button_clicked) { - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_STATION); - return; - } - - Axis axis = GetAxisForNewWaypoint(tile); - if (IsValidAxis(axis)) { - /* Valid tile for waypoints */ - VpStartPlaceSizing(tile, axis == AXIS_X ? VPM_FIX_X : VPM_FIX_Y, DDSP_BUILD_STATION); - } else { - /* Tile where we can't build rail waypoints. This is always going to fail, - * but provides the user with a proper error message. */ - DoCommandP(tile, 1 << 8 | 1 << 16, STAT_CLASS_WAYP | INVALID_STATION << 16, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT)); - } -} - -void CcStation(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Failed()) return; - - if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_2, tile); - /* Only close the station builder window if the default station and non persistent building is chosen. */ - if (_railstation.station_class == STAT_CLASS_DFLT && _railstation.station_type == 0 && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); -} - -/** - * Place a rail station. - * @param tile Position to place or start dragging a station. - */ -static void PlaceRail_Station(TileIndex tile) -{ - if (_remove_button_clicked) { - VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_REMOVE_STATION); - VpSetPlaceSizingLimit(-1); - } else if (_settings_client.gui.station_dragdrop) { - VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_STATION); - VpSetPlaceSizingLimit(_settings_game.station.station_spread); - } else { - uint32 p1 = _cur_railtype | _railstation.orientation << 4 | _settings_client.gui.station_numtracks << 8 | _settings_client.gui.station_platlength << 16 | _ctrl_pressed << 24; - uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16; - - int w = _settings_client.gui.station_numtracks; - int h = _settings_client.gui.station_platlength; - if (!_railstation.orientation) Swap(w, h); - - CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" }; - ShowSelectStationIfNeeded(cmdcont, TileArea(tile, w, h)); - } -} - -/** - * Build a new signal or edit/remove a present signal, use CmdBuildSingleSignal() or CmdRemoveSingleSignal() in rail_cmd.cpp - * - * @param tile The tile where the signal will build or edit - */ -static void GenericPlaceSignals(TileIndex tile) -{ - TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)); - - if (trackbits & TRACK_BIT_VERT) { // N-S direction - trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT; - } - - if (trackbits & TRACK_BIT_HORZ) { // E-W direction - trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER; - } - - Track track = FindFirstTrack(trackbits); - - if (_remove_button_clicked) { - DoCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E); - } else { - const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); - - /* Map the setting cycle_signal_types to the lower and upper allowed signal type. */ - static const uint cycle_bounds[] = {SIGTYPE_NORMAL | (SIGTYPE_LAST_NOPBS << 3), SIGTYPE_PBS | (SIGTYPE_LAST << 3), SIGTYPE_NORMAL | (SIGTYPE_LAST << 3)}; - - /* various bitstuffed elements for CmdBuildSingleSignal() */ - uint32 p1 = track; - - if (w != NULL) { - /* signal GUI is used */ - SB(p1, 3, 1, _ctrl_pressed); - SB(p1, 4, 1, _cur_signal_variant); - SB(p1, 5, 3, _cur_signal_type); - SB(p1, 8, 1, _convert_signal_button); - SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]); - } else { - SB(p1, 3, 1, _ctrl_pressed); - SB(p1, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC)); - SB(p1, 5, 3, _default_signal_type[_settings_client.gui.default_signal_type]); - SB(p1, 8, 1, 0); - SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]); - } - - DoCommandP(tile, p1, 0, CMD_BUILD_SIGNALS | - CMD_MSG((w != NULL && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), - CcPlaySound1E); - } -} - -/** - * Start placing a rail bridge. - * @param tile Position of the first tile of the bridge. - * @param w Rail toolbar window. - */ -static void PlaceRail_Bridge(TileIndex tile, Window *w) -{ - if (IsBridgeTile(tile)) { - TileIndex other_tile = GetOtherTunnelBridgeEnd(tile); - Point pt = {0, 0}; - w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile); - } else { - VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE); - } -} - -/** Command callback for building a tunnel */ -void CcBuildRailTunnel(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Succeeded()) { - if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_2, tile); - if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - } else { - SetRedErrorSquare(_build_tunnel_endtile); - } -} - -/** - * Toggles state of the Remove button of Build rail toolbar - * @param w window the button belongs to - */ -static void ToggleRailButton_Remove(Window *w) -{ - DeleteWindowById(WC_SELECT_STATION, 0); - w->ToggleWidgetLoweredState(WID_RAT_REMOVE); - w->SetWidgetDirty(WID_RAT_REMOVE); - _remove_button_clicked = w->IsWidgetLowered(WID_RAT_REMOVE); - SetSelectionRed(_remove_button_clicked); -} - -/** - * Updates the Remove button because of Ctrl state change - * @param w window the button belongs to - * @return true iff the remove button was changed - */ -static bool RailToolbar_CtrlChanged(Window *w) -{ - if (w->IsWidgetDisabled(WID_RAT_REMOVE)) return false; - - /* allow ctrl to switch remove mode only for these widgets */ - for (uint i = WID_RAT_BUILD_NS; i <= WID_RAT_BUILD_STATION; i++) { - if ((i <= WID_RAT_AUTORAIL || i >= WID_RAT_BUILD_WAYPOINT) && w->IsWidgetLowered(i)) { - ToggleRailButton_Remove(w); - return true; - } - } - - return false; -} - - -/** - * The "remove"-button click proc of the build-rail toolbar. - * @param w Build-rail toolbar window - * @see BuildRailToolbarWindow::OnClick() - */ -static void BuildRailClick_Remove(Window *w) -{ - if (w->IsWidgetDisabled(WID_RAT_REMOVE)) return; - ToggleRailButton_Remove(w); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - - /* handle station builder */ - if (w->IsWidgetLowered(WID_RAT_BUILD_STATION)) { - if (_remove_button_clicked) { - /* starting drag & drop remove */ - if (!_settings_client.gui.station_dragdrop) { - SetTileSelectSize(1, 1); - } else { - VpSetPlaceSizingLimit(-1); - } - } else { - /* starting station build mode */ - if (!_settings_client.gui.station_dragdrop) { - int x = _settings_client.gui.station_numtracks; - int y = _settings_client.gui.station_platlength; - if (_railstation.orientation == 0) Swap(x, y); - SetTileSelectSize(x, y); - } else { - VpSetPlaceSizingLimit(_settings_game.station.station_spread); - } - } - } -} - -static void DoRailroadTrack(int mode) -{ - DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), - _remove_button_clicked ? - CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) : - CMD_BUILD_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), - CcPlaySound1E); -} - -static void HandleAutodirPlacement() -{ - int trackstat = _thd.drawstyle & HT_DIR_MASK; // 0..5 - - if (_thd.drawstyle & HT_RAIL) { // one tile case - GenericPlaceRail(TileVirtXY(_thd.selend.x, _thd.selend.y), trackstat); - return; - } - - DoRailroadTrack(trackstat); -} - -/** - * Build new signals or remove signals or (if only one tile marked) edit a signal. - * - * If one tile marked abort and use GenericPlaceSignals() - * else use CmdBuildSingleSignal() or CmdRemoveSingleSignal() in rail_cmd.cpp to build many signals - */ -static void HandleAutoSignalPlacement() -{ - uint32 p2 = GB(_thd.drawstyle, 0, 3); // 0..5 - - if ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT) { // one tile case - GenericPlaceSignals(TileVirtXY(_thd.selend.x, _thd.selend.y)); - return; - } - - const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); - - if (w != NULL) { - /* signal GUI is used */ - SB(p2, 3, 1, 0); - SB(p2, 4, 1, _cur_signal_variant); - SB(p2, 6, 1, _ctrl_pressed); - SB(p2, 7, 3, _cur_signal_type); - SB(p2, 24, 8, _settings_client.gui.drag_signals_density); - SB(p2, 10, 1, !_settings_client.gui.drag_signals_fixed_distance); - } else { - SB(p2, 3, 1, 0); - SB(p2, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC)); - SB(p2, 6, 1, _ctrl_pressed); - SB(p2, 7, 3, _default_signal_type[_settings_client.gui.default_signal_type]); - SB(p2, 24, 8, _settings_client.gui.drag_signals_density); - SB(p2, 10, 1, !_settings_client.gui.drag_signals_fixed_distance); - } - - /* _settings_client.gui.drag_signals_density is given as a parameter such that each user - * in a network game can specify his/her own signal density */ - DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, - _remove_button_clicked ? - CMD_REMOVE_SIGNAL_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM) : - CMD_BUILD_SIGNAL_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), - CcPlaySound1E); -} - - -/** Rail toolbar management class. */ -struct BuildRailToolbarWindow : Window { - RailType railtype; ///< Rail type to build. - int last_user_action; ///< Last started user action. - - BuildRailToolbarWindow(WindowDesc *desc, RailType railtype) : Window(desc) - { - this->InitNested(TRANSPORT_RAIL); - this->SetupRailToolbar(railtype); - this->DisableWidget(WID_RAT_REMOVE); - this->last_user_action = WIDGET_LIST_END; - - if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); - } - - ~BuildRailToolbarWindow() - { - if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); - } - - /** - * Configures the rail toolbar for railtype given - * @param railtype the railtype to display - */ - void SetupRailToolbar(RailType railtype) - { - this->railtype = railtype; - const RailtypeInfo *rti = GetRailTypeInfo(railtype); - - assert(railtype < RAILTYPE_END); - this->GetWidget(WID_RAT_BUILD_NS)->widget_data = rti->gui_sprites.build_ns_rail; - this->GetWidget(WID_RAT_BUILD_X)->widget_data = rti->gui_sprites.build_x_rail; - this->GetWidget(WID_RAT_BUILD_EW)->widget_data = rti->gui_sprites.build_ew_rail; - this->GetWidget(WID_RAT_BUILD_Y)->widget_data = rti->gui_sprites.build_y_rail; - this->GetWidget(WID_RAT_AUTORAIL)->widget_data = rti->gui_sprites.auto_rail; - this->GetWidget(WID_RAT_BUILD_DEPOT)->widget_data = rti->gui_sprites.build_depot; - this->GetWidget(WID_RAT_CONVERT_RAIL)->widget_data = rti->gui_sprites.convert_rail; - this->GetWidget(WID_RAT_BUILD_TUNNEL)->widget_data = rti->gui_sprites.build_tunnel; - } - - /** - * Switch to another rail type. - * @param railtype New rail type. - */ - void ModifyRailType(RailType railtype) - { - this->SetupRailToolbar(railtype); - this->ReInit(); - } - - void UpdateRemoveWidgetStatus(int clicked_widget) - { - switch (clicked_widget) { - case WID_RAT_REMOVE: - /* If it is the removal button that has been clicked, do nothing, - * as it is up to the other buttons to drive removal status */ - return; - - case WID_RAT_BUILD_NS: - case WID_RAT_BUILD_X: - case WID_RAT_BUILD_EW: - case WID_RAT_BUILD_Y: - case WID_RAT_AUTORAIL: - case WID_RAT_BUILD_WAYPOINT: - case WID_RAT_BUILD_STATION: - case WID_RAT_BUILD_SIGNALS: - /* Removal button is enabled only if the rail/signal/waypoint/station - * button is still lowered. Once raised, it has to be disabled */ - this->SetWidgetDisabledState(WID_RAT_REMOVE, !this->IsWidgetLowered(clicked_widget)); - break; - - default: - /* When any other buttons than rail/signal/waypoint/station, raise and - * disable the removal button */ - this->DisableWidget(WID_RAT_REMOVE); - this->RaiseWidget(WID_RAT_REMOVE); - break; - } - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_RAT_CAPTION) { - const RailtypeInfo *rti = GetRailTypeInfo(this->railtype); - if (rti->max_speed > 0) { - SetDParam(0, STR_TOOLBAR_RAILTYPE_VELOCITY); - SetDParam(1, rti->strings.toolbar_caption); - SetDParam(2, rti->max_speed); - } else { - SetDParam(0, rti->strings.toolbar_caption); - } - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - if (widget < WID_RAT_BUILD_NS) return; - - _remove_button_clicked = false; - switch (widget) { - case WID_RAT_BUILD_NS: - HandlePlacePushButton(this, WID_RAT_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, HT_LINE | HT_DIR_VL); - this->last_user_action = widget; - break; - - case WID_RAT_BUILD_X: - HandlePlacePushButton(this, WID_RAT_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, HT_LINE | HT_DIR_X); - this->last_user_action = widget; - break; - - case WID_RAT_BUILD_EW: - HandlePlacePushButton(this, WID_RAT_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, HT_LINE | HT_DIR_HL); - this->last_user_action = widget; - break; - - case WID_RAT_BUILD_Y: - HandlePlacePushButton(this, WID_RAT_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, HT_LINE | HT_DIR_Y); - this->last_user_action = widget; - break; - - case WID_RAT_AUTORAIL: - HandlePlacePushButton(this, WID_RAT_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, HT_RAIL); - this->last_user_action = widget; - break; - - case WID_RAT_DEMOLISH: - HandlePlacePushButton(this, WID_RAT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); - this->last_user_action = widget; - break; - - case WID_RAT_BUILD_DEPOT: - if (HandlePlacePushButton(this, WID_RAT_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, HT_RECT)) { - ShowBuildTrainDepotPicker(this); - this->last_user_action = widget; - } - break; - - case WID_RAT_BUILD_WAYPOINT: - this->last_user_action = widget; - _waypoint_count = StationClass::Get(STAT_CLASS_WAYP)->GetSpecCount(); - if (HandlePlacePushButton(this, WID_RAT_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, HT_RECT) && _waypoint_count > 1) { - ShowBuildWaypointPicker(this); - } - break; - - case WID_RAT_BUILD_STATION: - if (HandlePlacePushButton(this, WID_RAT_BUILD_STATION, SPR_CURSOR_RAIL_STATION, HT_RECT)) { - ShowStationBuilder(this); - this->last_user_action = widget; - } - break; - - case WID_RAT_BUILD_SIGNALS: { - this->last_user_action = widget; - bool started = HandlePlacePushButton(this, WID_RAT_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, HT_RECT); - if (started && _settings_client.gui.enable_signal_gui != _ctrl_pressed) { - ShowSignalBuilder(this); - } - break; - } - - case WID_RAT_BUILD_BRIDGE: - HandlePlacePushButton(this, WID_RAT_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT); - this->last_user_action = widget; - break; - - case WID_RAT_BUILD_TUNNEL: - HandlePlacePushButton(this, WID_RAT_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, HT_SPECIAL); - this->last_user_action = widget; - break; - - case WID_RAT_REMOVE: - BuildRailClick_Remove(this); - break; - - case WID_RAT_CONVERT_RAIL: - HandlePlacePushButton(this, WID_RAT_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, HT_RECT | HT_DIAGONAL); - this->last_user_action = widget; - break; - - default: NOT_REACHED(); - } - this->UpdateRemoveWidgetStatus(widget); - if (_ctrl_pressed) RailToolbar_CtrlChanged(this); - } - - virtual EventState OnHotkey(int hotkey) - { - MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection - return Window::OnHotkey(hotkey); - } - - virtual void OnPlaceObject(Point pt, TileIndex tile) - { - switch (this->last_user_action) { - case WID_RAT_BUILD_NS: - VpStartPlaceSizing(tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL); - break; - - case WID_RAT_BUILD_X: - VpStartPlaceSizing(tile, VPM_FIX_Y | VPM_RAILDIRS, DDSP_PLACE_RAIL); - break; - - case WID_RAT_BUILD_EW: - VpStartPlaceSizing(tile, VPM_FIX_HORIZONTAL | VPM_RAILDIRS, DDSP_PLACE_RAIL); - break; - - case WID_RAT_BUILD_Y: - VpStartPlaceSizing(tile, VPM_FIX_X | VPM_RAILDIRS, DDSP_PLACE_RAIL); - break; - - case WID_RAT_AUTORAIL: - VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_RAIL); - break; - - case WID_RAT_DEMOLISH: - PlaceProc_DemolishArea(tile); - break; - - case WID_RAT_BUILD_DEPOT: - DoCommandP(tile, _cur_railtype, _build_depot_direction, - CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT), - CcRailDepot); - break; - - case WID_RAT_BUILD_WAYPOINT: - PlaceRail_Waypoint(tile); - break; - - case WID_RAT_BUILD_STATION: - PlaceRail_Station(tile); - break; - - case WID_RAT_BUILD_SIGNALS: - VpStartPlaceSizing(tile, VPM_SIGNALDIRS, DDSP_BUILD_SIGNALS); - break; - - case WID_RAT_BUILD_BRIDGE: - PlaceRail_Bridge(tile, this); - break; - - case WID_RAT_BUILD_TUNNEL: - DoCommandP(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel); - break; - - case WID_RAT_CONVERT_RAIL: - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_RAIL); - break; - - default: NOT_REACHED(); - } - } - - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) - { - /* no dragging if you have pressed the convert button */ - if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && this->IsWidgetLowered(WID_RAT_BUILD_SIGNALS)) return; - - VpSelectTilesWithMethod(pt.x, pt.y, select_method); - } - - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) - { - if (pt.x != -1) { - switch (select_proc) { - default: NOT_REACHED(); - case DDSP_BUILD_BRIDGE: - if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype); - break; - - case DDSP_PLACE_RAIL: - HandleAutodirPlacement(); - break; - - case DDSP_BUILD_SIGNALS: - HandleAutoSignalPlacement(); - break; - - case DDSP_DEMOLISH_AREA: - GUIPlaceProcDragXY(select_proc, start_tile, end_tile); - break; - - case DDSP_CONVERT_RAIL: - DoCommandP(end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 0x10 : 0), CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound10); - break; - - case DDSP_REMOVE_STATION: - case DDSP_BUILD_STATION: - if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) { - /* Station */ - if (_remove_button_clicked) { - DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION), CcPlaySound1E); - } else { - HandleStationPlacement(start_tile, end_tile); - } - } else { - /* Waypoint */ - if (_remove_button_clicked) { - DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT), CcPlaySound1E); - } else { - TileArea ta(start_tile, end_tile); - uint32 p1 = _cur_railtype | (select_method == VPM_FIX_X ? AXIS_X : AXIS_Y) << 4 | ta.w << 8 | ta.h << 16 | _ctrl_pressed << 24; - uint32 p2 = STAT_CLASS_WAYP | _cur_waypoint_type << 8 | INVALID_STATION << 16; - - CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT), CcPlaySound1E, "" }; - ShowSelectWaypointIfNeeded(cmdcont, ta); - } - } - break; - } - } - } - - virtual void OnPlaceObjectAbort() - { - this->RaiseButtons(); - this->DisableWidget(WID_RAT_REMOVE); - this->SetWidgetDirty(WID_RAT_REMOVE); - - DeleteWindowById(WC_BUILD_SIGNAL, TRANSPORT_RAIL); - DeleteWindowById(WC_BUILD_STATION, TRANSPORT_RAIL); - DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_RAIL); - DeleteWindowById(WC_BUILD_WAYPOINT, TRANSPORT_RAIL); - DeleteWindowById(WC_SELECT_STATION, 0); - DeleteWindowByClass(WC_BUILD_BRIDGE); - } - - virtual void OnPlacePresize(Point pt, TileIndex tile) - { - DoCommand(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); - VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); - } - - virtual EventState OnCTRLStateChange() - { - /* do not toggle Remove button by Ctrl when placing station */ - if (!this->IsWidgetLowered(WID_RAT_BUILD_STATION) && !this->IsWidgetLowered(WID_RAT_BUILD_WAYPOINT) && RailToolbar_CtrlChanged(this)) return ES_HANDLED; - return ES_NOT_HANDLED; - } - - static HotkeyList hotkeys; -}; - -/** - * Handler for global hotkeys of the BuildRailToolbarWindow. - * @param hotkey Hotkey - * @return ES_HANDLED if hotkey was accepted. - */ -static EventState RailToolbarGlobalHotkeys(int hotkey) -{ - if (_game_mode != GM_NORMAL || !CanBuildVehicleInfrastructure(VEH_TRAIN)) return ES_NOT_HANDLED; - extern RailType _last_built_railtype; - Window *w = ShowBuildRailToolbar(_last_built_railtype); - if (w == NULL) return ES_NOT_HANDLED; - return w->OnHotkey(hotkey); -} - -const uint16 _railtoolbar_autorail_keys[] = {'5', 'A' | WKC_GLOBAL_HOTKEY, 0}; - -static Hotkey railtoolbar_hotkeys[] = { - Hotkey('1', "build_ns", WID_RAT_BUILD_NS), - Hotkey('2', "build_x", WID_RAT_BUILD_X), - Hotkey('3', "build_ew", WID_RAT_BUILD_EW), - Hotkey('4', "build_y", WID_RAT_BUILD_Y), - Hotkey(_railtoolbar_autorail_keys, "autorail", WID_RAT_AUTORAIL), - Hotkey('6', "demolish", WID_RAT_DEMOLISH), - Hotkey('7', "depot", WID_RAT_BUILD_DEPOT), - Hotkey('8', "waypoint", WID_RAT_BUILD_WAYPOINT), - Hotkey('9', "station", WID_RAT_BUILD_STATION), - Hotkey('S', "signal", WID_RAT_BUILD_SIGNALS), - Hotkey('B', "bridge", WID_RAT_BUILD_BRIDGE), - Hotkey('T', "tunnel", WID_RAT_BUILD_TUNNEL), - Hotkey('R', "remove", WID_RAT_REMOVE), - Hotkey('C', "convert", WID_RAT_CONVERT_RAIL), - HOTKEY_LIST_END -}; -HotkeyList BuildRailToolbarWindow::hotkeys("railtoolbar", railtoolbar_hotkeys, RailToolbarGlobalHotkeys); - -static const NWidgetPart _nested_build_rail_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_RAT_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_NS), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NS, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_X), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NE, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_EW), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_EW, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_Y), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NW, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_AUTORAIL), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTORAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL), - - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetDataTip(0x0, STR_NULL), EndContainer(), - - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_DEMOLISH), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_DEPOT), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DEPOT_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_WAYPOINT), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_WAYPOINT, STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_STATION), - SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_RAIL_STATION, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_SIGNALS), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_SIGNALS, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_BRIDGE), - SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_BRIDGE, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_TUNNEL), - SetFill(0, 1), SetMinimalSize(20, 22), SetDataTip(SPR_IMG_TUNNEL_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_REMOVE), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_CONVERT_RAIL), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL), - EndContainer(), -}; - -static WindowDesc _build_rail_desc( - WDP_ALIGN_TOOLBAR, "toolbar_rail", 0, 0, - WC_BUILD_TOOLBAR, WC_NONE, - WDF_CONSTRUCTION, - _nested_build_rail_widgets, lengthof(_nested_build_rail_widgets), - &BuildRailToolbarWindow::hotkeys -); - - -/** - * Open the build rail toolbar window for a specific rail type. - * - * If the terraform toolbar is linked to the toolbar, that window is also opened. - * - * @param railtype Rail type to open the window for - * @return newly opened rail toolbar, or NULL if the toolbar could not be opened. - */ -Window *ShowBuildRailToolbar(RailType railtype) -{ - if (!Company::IsValidID(_local_company)) return NULL; - if (!ValParamRailtype(railtype)) return NULL; - - DeleteWindowByClass(WC_BUILD_TOOLBAR); - _cur_railtype = railtype; - _remove_button_clicked = false; - return new BuildRailToolbarWindow(&_build_rail_desc, railtype); -} - -/* TODO: For custom stations, respect their allowed platforms/lengths bitmasks! - * --pasky */ - -static void HandleStationPlacement(TileIndex start, TileIndex end) -{ - TileArea ta(start, end); - uint numtracks = ta.w; - uint platlength = ta.h; - - if (_railstation.orientation == AXIS_X) Swap(numtracks, platlength); - - uint32 p1 = _cur_railtype | _railstation.orientation << 4 | numtracks << 8 | platlength << 16 | _ctrl_pressed << 24; - uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16; - - CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" }; - ShowSelectStationIfNeeded(cmdcont, ta); -} - -struct BuildRailStationWindow : public PickerWindowBase { -private: - uint line_height; ///< Height of a single line in the newstation selection matrix (#WID_BRAS_NEWST_LIST widget). - uint coverage_height; ///< Height of the coverage texts. - Scrollbar *vscroll; ///< Vertical scrollbar of the new station list. - Scrollbar *vscroll2; ///< Vertical scrollbar of the matrix with new stations. - - /** - * Verify whether the currently selected station size is allowed after selecting a new station class/type. - * If not, change the station size variables ( _settings_client.gui.station_numtracks and _settings_client.gui.station_platlength ). - * @param statspec Specification of the new station class/type - */ - void CheckSelectedSize(const StationSpec *statspec) - { - if (statspec == NULL || _settings_client.gui.station_dragdrop) return; - - /* If current number of tracks is not allowed, make it as big as possible */ - if (HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { - this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); - _settings_client.gui.station_numtracks = 1; - if (statspec->disallowed_platforms != UINT8_MAX) { - while (HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { - _settings_client.gui.station_numtracks++; - } - this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); - } - } - - if (HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { - this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); - _settings_client.gui.station_platlength = 1; - if (statspec->disallowed_lengths != UINT8_MAX) { - while (HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { - _settings_client.gui.station_platlength++; - } - this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); - } - } - } - -public: - BuildRailStationWindow(WindowDesc *desc, Window *parent, bool newstation) : PickerWindowBase(desc, parent) - { - this->coverage_height = 2 * FONT_HEIGHT_NORMAL + 3 * WD_PAR_VSEP_NORMAL; - this->vscroll = NULL; - _railstation.newstations = newstation; - - this->CreateNestedTree(); - NWidgetStacked *newst_additions = this->GetWidget(WID_BRAS_SHOW_NEWST_ADDITIONS); - newst_additions->SetDisplayedPlane(newstation ? 0 : SZSP_NONE); - newst_additions = this->GetWidget(WID_BRAS_SHOW_NEWST_MATRIX); - newst_additions->SetDisplayedPlane(newstation ? 0 : SZSP_NONE); - newst_additions = this->GetWidget(WID_BRAS_SHOW_NEWST_DEFSIZE); - newst_additions->SetDisplayedPlane(newstation ? 0 : SZSP_NONE); - newst_additions = this->GetWidget(WID_BRAS_SHOW_NEWST_RESIZE); - newst_additions->SetDisplayedPlane(newstation ? 0 : SZSP_NONE); - if (newstation) { - this->vscroll = this->GetScrollbar(WID_BRAS_NEWST_SCROLL); - this->vscroll2 = this->GetScrollbar(WID_BRAS_MATRIX_SCROLL); - } - this->FinishInitNested(TRANSPORT_RAIL); - - this->LowerWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X); - if (_settings_client.gui.station_dragdrop) { - this->LowerWidget(WID_BRAS_PLATFORM_DRAG_N_DROP); - } else { - this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); - this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); - } - this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_OFF, !_settings_client.gui.station_show_coverage); - this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_ON, _settings_client.gui.station_show_coverage); - - if (!newstation || _railstation.station_class >= (int)StationClass::GetClassCount()) { - /* New stations are not available or changed, so ensure the default station - * type is 'selected'. */ - _railstation.station_class = STAT_CLASS_DFLT; - _railstation.station_type = 0; - this->vscroll2 = NULL; - } - if (newstation) { - _railstation.station_count = StationClass::Get(_railstation.station_class)->GetSpecCount(); - _railstation.station_type = min(_railstation.station_type, _railstation.station_count - 1); - - int count = 0; - for (uint i = 0; i < StationClass::GetClassCount(); i++) { - if (i == STAT_CLASS_WAYP) continue; - count++; - } - this->vscroll->SetCount(count); - this->vscroll->SetPosition(Clamp(_railstation.station_class - 2, 0, max(this->vscroll->GetCount() - this->vscroll->GetCapacity(), 0))); - - NWidgetMatrix *matrix = this->GetWidget(WID_BRAS_MATRIX); - matrix->SetScrollbar(this->vscroll2); - matrix->SetCount(_railstation.station_count); - matrix->SetClicked(_railstation.station_type); - } - } - - virtual ~BuildRailStationWindow() - { - DeleteWindowById(WC_SELECT_STATION, 0); - } - - virtual void OnPaint() - { - bool newstations = _railstation.newstations; - const StationSpec *statspec = newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; - - if (_settings_client.gui.station_dragdrop) { - SetTileSelectSize(1, 1); - } else { - int x = _settings_client.gui.station_numtracks; - int y = _settings_client.gui.station_platlength; - if (_railstation.orientation == AXIS_X) Swap(x, y); - if (!_remove_button_clicked) { - SetTileSelectSize(x, y); - } - } - - int rad = (_settings_game.station.modified_catchment) ? CA_TRAIN : CA_UNMODIFIED; - - if (_settings_client.gui.station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); - - for (uint bits = 0; bits < 7; bits++) { - bool disable = bits >= _settings_game.station.station_spread; - if (statspec == NULL) { - this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_NUM_1, disable); - this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_LEN_1, disable); - } else { - this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_NUM_1, HasBit(statspec->disallowed_platforms, bits) || disable); - this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_LEN_1, HasBit(statspec->disallowed_lengths, bits) || disable); - } - } - - this->DrawWidgets(); - - /* 'Accepts' and 'Supplies' texts. */ - NWidgetBase *cov = this->GetWidget(WID_BRAS_COVERAGE_TEXTS); - int top = cov->pos_y + WD_PAR_VSEP_NORMAL; - int left = cov->pos_x + WD_FRAMERECT_LEFT; - int right = cov->pos_x + cov->current_x - WD_FRAMERECT_RIGHT; - int bottom = cov->pos_y + cov->current_y; - top = DrawStationCoverageAreaText(left, right, top, SCT_ALL, rad, false) + WD_PAR_VSEP_NORMAL; - top = DrawStationCoverageAreaText(left, right, top, SCT_ALL, rad, true) + WD_PAR_VSEP_NORMAL; - /* Resize background if the window is too small. - * Never make the window smaller to avoid oscillating if the size change affects the acceptance. - * (This is the case, if making the window bigger moves the mouse into the window.) */ - if (top > bottom) { - this->coverage_height += top - bottom; - this->ReInit(); - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_BRAS_NEWST_LIST: { - Dimension d = {0, 0}; - for (uint i = 0; i < StationClass::GetClassCount(); i++) { - if (i == STAT_CLASS_WAYP) continue; - SetDParam(0, StationClass::Get((StationClassID)i)->name); - d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING)); - } - size->width = max(size->width, d.width + padding.width); - this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; - size->height = 5 * this->line_height; - resize->height = this->line_height; - break; - } - - case WID_BRAS_SHOW_NEWST_TYPE: { - if (!_railstation.newstations) { - size->width = 0; - size->height = 0; - break; - } - - /* If newstations exist, compute the non-zero minimal size. */ - Dimension d = {0, 0}; - StringID str = this->GetWidget(widget)->widget_data; - for (StationClassID statclass = STAT_CLASS_BEGIN; statclass < (StationClassID)StationClass::GetClassCount(); statclass++) { - if (statclass == STAT_CLASS_WAYP) continue; - StationClass *stclass = StationClass::Get(statclass); - for (uint16 j = 0; j < stclass->GetSpecCount(); j++) { - const StationSpec *statspec = stclass->GetSpec(j); - SetDParam(0, (statspec != NULL && statspec->name != 0) ? statspec->name : STR_STATION_CLASS_DFLT); - d = maxdim(d, GetStringBoundingBox(str)); - } - } - size->width = max(size->width, d.width + padding.width); - break; - } - - case WID_BRAS_COVERAGE_TEXTS: - size->height = this->coverage_height; - break; - - case WID_BRAS_MATRIX: - fill->height = 1; - resize->height = 1; - break; - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - DrawPixelInfo tmp_dpi; - - switch (GB(widget, 0, 16)) { - case WID_BRAS_PLATFORM_DIR_X: - /* Set up a clipping area for the '/' station preview */ - if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { - DrawPixelInfo *old_dpi = _cur_dpi; - _cur_dpi = &tmp_dpi; - if (!DrawStationTile(32, 28, _cur_railtype, AXIS_X, _railstation.station_class, _railstation.station_type)) { - StationPickerDrawSprite(32, 28, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2); - } - _cur_dpi = old_dpi; - } - break; - - case WID_BRAS_PLATFORM_DIR_Y: - /* Set up a clipping area for the '\' station preview */ - if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { - DrawPixelInfo *old_dpi = _cur_dpi; - _cur_dpi = &tmp_dpi; - if (!DrawStationTile(32, 28, _cur_railtype, AXIS_Y, _railstation.station_class, _railstation.station_type)) { - StationPickerDrawSprite(32, 28, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 3); - } - _cur_dpi = old_dpi; - } - break; - - case WID_BRAS_NEWST_LIST: { - uint statclass = 0; - uint row = 0; - for (uint i = 0; i < StationClass::GetClassCount(); i++) { - if (i == STAT_CLASS_WAYP) continue; - if (this->vscroll->IsVisible(statclass)) { - SetDParam(0, StationClass::Get((StationClassID)i)->name); - DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, row * this->line_height + r.top + WD_MATRIX_TOP, STR_JUST_STRING, - (StationClassID)i == _railstation.station_class ? TC_WHITE : TC_BLACK); - row++; - } - statclass++; - } - break; - } - - case WID_BRAS_IMAGE: { - byte type = GB(widget, 16, 16); - assert(type < _railstation.station_count); - /* Check station availability callback */ - const StationSpec *statspec = StationClass::Get(_railstation.station_class)->GetSpec(type); - if (!IsStationAvailable(statspec)) { - GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER); - } - - /* Set up a clipping area for the station preview. */ - if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { - DrawPixelInfo *old_dpi = _cur_dpi; - _cur_dpi = &tmp_dpi; - if (!DrawStationTile(32, 28, _cur_railtype, _railstation.orientation, _railstation.station_class, type)) { - StationPickerDrawSprite(32, 28, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2 + _railstation.orientation); - } - _cur_dpi = old_dpi; - } - break; - } - } - } - - virtual void OnResize() - { - if (this->vscroll != NULL) { // New stations available. - this->vscroll->SetCapacityFromWidget(this, WID_BRAS_NEWST_LIST); - } - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_BRAS_SHOW_NEWST_TYPE) { - const StationSpec *statspec = StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type); - SetDParam(0, (statspec != NULL && statspec->name != 0) ? statspec->name : STR_STATION_CLASS_DFLT); - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (GB(widget, 0, 16)) { - case WID_BRAS_PLATFORM_DIR_X: - case WID_BRAS_PLATFORM_DIR_Y: - this->RaiseWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X); - _railstation.orientation = (Axis)(widget - WID_BRAS_PLATFORM_DIR_X); - this->LowerWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - DeleteWindowById(WC_SELECT_STATION, 0); - break; - - case WID_BRAS_PLATFORM_NUM_1: - case WID_BRAS_PLATFORM_NUM_2: - case WID_BRAS_PLATFORM_NUM_3: - case WID_BRAS_PLATFORM_NUM_4: - case WID_BRAS_PLATFORM_NUM_5: - case WID_BRAS_PLATFORM_NUM_6: - case WID_BRAS_PLATFORM_NUM_7: { - this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); - this->RaiseWidget(WID_BRAS_PLATFORM_DRAG_N_DROP); - - _settings_client.gui.station_numtracks = widget - WID_BRAS_PLATFORM_NUM_BEGIN; - _settings_client.gui.station_dragdrop = false; - - _settings_client.gui.station_dragdrop = false; - - const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; - if (statspec != NULL && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { - /* The previously selected number of platforms in invalid */ - for (uint i = 0; i < 7; i++) { - if (!HasBit(statspec->disallowed_lengths, i)) { - this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); - _settings_client.gui.station_platlength = i + 1; - break; - } - } - } - - this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); - this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - DeleteWindowById(WC_SELECT_STATION, 0); - break; - } - - case WID_BRAS_PLATFORM_LEN_1: - case WID_BRAS_PLATFORM_LEN_2: - case WID_BRAS_PLATFORM_LEN_3: - case WID_BRAS_PLATFORM_LEN_4: - case WID_BRAS_PLATFORM_LEN_5: - case WID_BRAS_PLATFORM_LEN_6: - case WID_BRAS_PLATFORM_LEN_7: { - this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); - this->RaiseWidget(WID_BRAS_PLATFORM_DRAG_N_DROP); - - _settings_client.gui.station_platlength = widget - WID_BRAS_PLATFORM_LEN_BEGIN; - _settings_client.gui.station_dragdrop = false; - - _settings_client.gui.station_dragdrop = false; - - const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; - if (statspec != NULL && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { - /* The previously selected number of tracks in invalid */ - for (uint i = 0; i < 7; i++) { - if (!HasBit(statspec->disallowed_platforms, i)) { - this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); - _settings_client.gui.station_numtracks = i + 1; - break; - } - } - } - - this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); - this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - DeleteWindowById(WC_SELECT_STATION, 0); - break; - } - - case WID_BRAS_PLATFORM_DRAG_N_DROP: { - _settings_client.gui.station_dragdrop ^= true; - - this->ToggleWidgetLoweredState(WID_BRAS_PLATFORM_DRAG_N_DROP); - - /* get the first allowed length/number of platforms */ - const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; - if (statspec != NULL && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { - for (uint i = 0; i < 7; i++) { - if (!HasBit(statspec->disallowed_lengths, i)) { - this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); - _settings_client.gui.station_platlength = i + 1; - break; - } - } - } - if (statspec != NULL && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { - for (uint i = 0; i < 7; i++) { - if (!HasBit(statspec->disallowed_platforms, i)) { - this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); - _settings_client.gui.station_numtracks = i + 1; - break; - } - } - } - - this->SetWidgetLoweredState(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN, !_settings_client.gui.station_dragdrop); - this->SetWidgetLoweredState(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN, !_settings_client.gui.station_dragdrop); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - DeleteWindowById(WC_SELECT_STATION, 0); - break; - } - - case WID_BRAS_HIGHLIGHT_OFF: - case WID_BRAS_HIGHLIGHT_ON: - _settings_client.gui.station_show_coverage = (widget != WID_BRAS_HIGHLIGHT_OFF); - - this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_OFF, !_settings_client.gui.station_show_coverage); - this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_ON, _settings_client.gui.station_show_coverage); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - break; - - case WID_BRAS_NEWST_LIST: { - int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BRAS_NEWST_LIST, 0, this->line_height); - if (y >= (int)StationClass::GetClassCount()) return; - for (uint i = 0; i < StationClass::GetClassCount(); i++) { - if (i == STAT_CLASS_WAYP) continue; - if (y == 0) { - if (_railstation.station_class != (StationClassID)i) { - _railstation.station_class = (StationClassID)i; - StationClass *stclass = StationClass::Get(_railstation.station_class); - _railstation.station_count = stclass->GetSpecCount(); - _railstation.station_type = min((int)_railstation.station_type, max(0, (int)_railstation.station_count - 1)); - - this->CheckSelectedSize(stclass->GetSpec(_railstation.station_type)); - - NWidgetMatrix *matrix = this->GetWidget(WID_BRAS_MATRIX); - matrix->SetCount(_railstation.station_count); - matrix->SetClicked(_railstation.station_type); - } - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - DeleteWindowById(WC_SELECT_STATION, 0); - break; - } - y--; - } - break; - } - - case WID_BRAS_IMAGE: { - int y = GB(widget, 16, 16); - if (y >= _railstation.station_count) return; - - /* Check station availability callback */ - const StationSpec *statspec = StationClass::Get(_railstation.station_class)->GetSpec(y); - if (!IsStationAvailable(statspec)) return; - - _railstation.station_type = y; - - this->CheckSelectedSize(statspec); - this->GetWidget(WID_BRAS_MATRIX)->SetClicked(_railstation.station_type); - - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - DeleteWindowById(WC_SELECT_STATION, 0); - break; - } - } - } - - virtual void OnTick() - { - CheckRedrawStationCoverage(this); - } -}; - -static const NWidgetPart _nested_station_builder_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_RAIL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_DEFSIZE), - NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), - EndContainer(), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_VERTICAL), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_ADDITIONS), - NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7), SetPadding(2, 0, 1, 0), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_BRAS_NEWST_LIST), SetMinimalSize(122, 71), SetFill(1, 0), - SetMatrixDataTip(1, 0, STR_STATION_BUILD_STATION_CLASS_TOOLTIP), SetScrollbar(WID_BRAS_NEWST_SCROLL), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BRAS_NEWST_SCROLL), - EndContainer(), - EndContainer(), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetPadding(1, 2, 0, 2), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_X), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_Y), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0), - EndContainer(), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BRAS_SHOW_NEWST_TYPE), SetMinimalSize(144, 11), SetDataTip(STR_ORANGE_STRING, STR_NULL), SetPadding(1, 2, 4, 2), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_NUMBER_OF_TRACKS, STR_NULL), SetPadding(0, 2, 0, 2), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_PLATFORM_LENGTH, STR_NULL), SetPadding(2, 2, 0, 2), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_DRAG_N_DROP), SetMinimalSize(75, 12), SetDataTip(STR_STATION_BUILD_DRAG_DROP, STR_STATION_BUILD_DRAG_DROP_TOOLTIP), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), - EndContainer(), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetPadding(3, 2, 0, 2), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_HIGHLIGHT_OFF), SetMinimalSize(60, 12), - SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_HIGHLIGHT_ON), SetMinimalSize(60, 12), - SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), - EndContainer(), - EndContainer(), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_MATRIX), - /* We need an additional background for the matrix, as the matrix cannot handle the scrollbar due to not being an NWidgetCore. */ - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BRAS_MATRIX_SCROLL), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BRAS_MATRIX), SetScrollbar(WID_BRAS_MATRIX_SCROLL), SetPIP(0, 2, 0), SetPadding(2, 0, 0, 0), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BRAS_IMAGE), SetMinimalSize(66, 60), - SetFill(0, 0), SetResize(0, 0), SetDataTip(0x0, STR_STATION_BUILD_STATION_TYPE_TOOLTIP), SetScrollbar(WID_BRAS_MATRIX_SCROLL), - EndContainer(), - EndContainer(), - NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_BRAS_MATRIX_SCROLL), - EndContainer(), - EndContainer(), - EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BRAS_COVERAGE_TEXTS), SetFill(1, 1), SetResize(1, 0), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_RESIZE), - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(0, 1), EndContainer(), - NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), - EndContainer(), - EndContainer(), - EndContainer(), - EndContainer(), -}; - -/** High level window description of the station-build window (default & newGRF) */ -static WindowDesc _station_builder_desc( - WDP_AUTO, "build_station_rail", 350, 0, - WC_BUILD_STATION, WC_BUILD_TOOLBAR, - WDF_CONSTRUCTION, - _nested_station_builder_widgets, lengthof(_nested_station_builder_widgets) -); - -/** Open station build window */ -static void ShowStationBuilder(Window *parent) -{ - bool newstations = StationClass::GetClassCount() > 2 || StationClass::Get(STAT_CLASS_DFLT)->GetSpecCount() != 1; - new BuildRailStationWindow(&_station_builder_desc, parent, newstations); -} - -struct BuildSignalWindow : public PickerWindowBase { -private: - Dimension sig_sprite_size; ///< Maximum size of signal GUI sprites. - int sig_sprite_bottom_offset; ///< Maximum extent of signal GUI sprite from reference point towards bottom. - - /** - * Draw dynamic a signal-sprite in a button in the signal GUI - * Draw the sprite +1px to the right and down if the button is lowered - * - * @param widget_index index of this widget in the window - * @param image the sprite to draw - */ - void DrawSignalSprite(byte widget_index, SpriteID image) const - { - Point offset; - Dimension sprite_size = GetSpriteSize(image, &offset); - const NWidgetBase *widget = this->GetWidget(widget_index); - int x = widget->pos_x - offset.x + - (widget->current_x - sprite_size.width + offset.x) / 2; // centered - int y = widget->pos_y - sig_sprite_bottom_offset + WD_IMGBTN_TOP + - (widget->current_y - WD_IMGBTN_TOP - WD_IMGBTN_BOTTOM + sig_sprite_size.height) / 2; // aligned to bottom - - DrawSprite(image, PAL_NONE, - x + this->IsWidgetLowered(widget_index), - y + this->IsWidgetLowered(widget_index)); - } - -public: - BuildSignalWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) - { - this->InitNested(TRANSPORT_RAIL); - this->OnInvalidateData(); - } - - ~BuildSignalWindow() - { - _convert_signal_button = false; - } - - virtual void OnInit() - { - /* Calculate maximum signal sprite size. */ - this->sig_sprite_size.width = 0; - this->sig_sprite_size.height = 0; - this->sig_sprite_bottom_offset = 0; - const RailtypeInfo *rti = GetRailTypeInfo(_cur_railtype); - for (uint type = SIGTYPE_NORMAL; type < SIGTYPE_END; type++) { - for (uint variant = SIG_ELECTRIC; variant <= SIG_SEMAPHORE; variant++) { - for (uint lowered = 0; lowered < 2; lowered++) { - Point offset; - Dimension sprite_size = GetSpriteSize(rti->gui_sprites.signals[type][variant][lowered], &offset); - this->sig_sprite_bottom_offset = max(this->sig_sprite_bottom_offset, sprite_size.height); - this->sig_sprite_size.width = max(this->sig_sprite_size.width, sprite_size.width - offset.x); - this->sig_sprite_size.height = max(this->sig_sprite_size.height, sprite_size.height - offset.y); - } - } - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - if (widget == WID_BS_DRAG_SIGNALS_DENSITY_LABEL) { - /* Two digits for signals density. */ - size->width = max(size->width, 2 * GetDigitWidth() + padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT); - } else if (IsInsideMM(widget, WID_BS_SEMAPHORE_NORM, WID_BS_ELECTRIC_PBS_OWAY + 1)) { - size->width = max(size->width, this->sig_sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT); - size->height = max(size->height, this->sig_sprite_size.height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM); - } - } - - virtual void SetStringParameters(int widget) const - { - switch (widget) { - case WID_BS_DRAG_SIGNALS_DENSITY_LABEL: - SetDParam(0, _settings_client.gui.drag_signals_density); - break; - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (IsInsideMM(widget, WID_BS_SEMAPHORE_NORM, WID_BS_ELECTRIC_PBS_OWAY + 1)) { - /* Extract signal from widget number. */ - int type = (widget - WID_BS_SEMAPHORE_NORM) % SIGTYPE_END; - int var = SIG_SEMAPHORE - (widget - WID_BS_SEMAPHORE_NORM) / SIGTYPE_END; // SignalVariant order is reversed compared to the widgets. - SpriteID sprite = GetRailTypeInfo(_cur_railtype)->gui_sprites.signals[type][var][this->IsWidgetLowered(widget)]; - - this->DrawSignalSprite(widget, sprite); - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_BS_SEMAPHORE_NORM: - case WID_BS_SEMAPHORE_ENTRY: - case WID_BS_SEMAPHORE_EXIT: - case WID_BS_SEMAPHORE_COMBO: - case WID_BS_SEMAPHORE_PBS: - case WID_BS_SEMAPHORE_PBS_OWAY: - case WID_BS_ELECTRIC_NORM: - case WID_BS_ELECTRIC_ENTRY: - case WID_BS_ELECTRIC_EXIT: - case WID_BS_ELECTRIC_COMBO: - case WID_BS_ELECTRIC_PBS: - case WID_BS_ELECTRIC_PBS_OWAY: - this->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type); - - _cur_signal_type = (SignalType)((uint)((widget - WID_BS_SEMAPHORE_NORM) % (SIGTYPE_LAST + 1))); - _cur_signal_variant = widget >= WID_BS_ELECTRIC_NORM ? SIG_ELECTRIC : SIG_SEMAPHORE; - - /* If 'remove' button of rail build toolbar is active, disable it. */ - if (_remove_button_clicked) { - Window *w = FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL); - if (w != NULL) ToggleRailButton_Remove(w); - } - - break; - - case WID_BS_CONVERT: - _convert_signal_button = !_convert_signal_button; - break; - - case WID_BS_DRAG_SIGNALS_DENSITY_DECREASE: - if (_settings_client.gui.drag_signals_density > 1) { - _settings_client.gui.drag_signals_density--; - SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_SETTINGS); - } - break; - - case WID_BS_DRAG_SIGNALS_DENSITY_INCREASE: - if (_settings_client.gui.drag_signals_density < 20) { - _settings_client.gui.drag_signals_density++; - SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_SETTINGS); - } - break; - - default: break; - } - - this->InvalidateData(); - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - this->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type); - - this->SetWidgetLoweredState(WID_BS_CONVERT, _convert_signal_button); - - this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, _settings_client.gui.drag_signals_density == 1); - this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, _settings_client.gui.drag_signals_density == 20); - } -}; - -/** Nested widget definition of the build signal window */ -static const NWidgetPart _nested_signal_builder_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_BUILD_SIGNAL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - EndContainer(), - NWidget(NWID_VERTICAL, NC_EQUALSIZE), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_CONVERT), SetDataTip(SPR_IMG_SIGNAL_CONVERT, STR_BUILD_SIGNAL_CONVERT_TOOLTIP), SetFill(1, 1), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BS_DRAG_SIGNALS_DENSITY_LABEL), SetDataTip(STR_ORANGE_INT, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), - NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_DECREASE), SetSizingType(NWST_STEP), SetMinimalSize(9, 12), SetDataTip(AWV_DECREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_INCREASE), SetSizingType(NWST_STEP), SetMinimalSize(9, 12), SetDataTip(AWV_INCREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0), - EndContainer(), - EndContainer(), - EndContainer(), -}; - -/** Signal selection window description */ -static WindowDesc _signal_builder_desc( - WDP_AUTO, "build_signal", 0, 0, - WC_BUILD_SIGNAL, WC_BUILD_TOOLBAR, - WDF_CONSTRUCTION, - _nested_signal_builder_widgets, lengthof(_nested_signal_builder_widgets) -); - -/** - * Open the signal selection window - */ -static void ShowSignalBuilder(Window *parent) -{ - new BuildSignalWindow(&_signal_builder_desc, parent); -} - -struct BuildRailDepotWindow : public PickerWindowBase { - BuildRailDepotWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) - { - this->InitNested(TRANSPORT_RAIL); - this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (!IsInsideMM(widget, WID_BRAD_DEPOT_NE, WID_BRAD_DEPOT_NW + 1)) return; - - DrawTrainDepotSprite(r.left - 1, r.top, widget - WID_BRAD_DEPOT_NE + DIAGDIR_NE, _cur_railtype); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_BRAD_DEPOT_NE: - case WID_BRAD_DEPOT_SE: - case WID_BRAD_DEPOT_SW: - case WID_BRAD_DEPOT_NW: - this->RaiseWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); - _build_depot_direction = (DiagDirection)(widget - WID_BRAD_DEPOT_NE); - this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - break; - } - } -}; - -/** Nested widget definition of the build rail depot window */ -static const NWidgetPart _nested_build_depot_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), - NWidget(NWID_SPACER), SetMinimalSize(0, 3), - NWidget(NWID_HORIZONTAL_LTR), - NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), - EndContainer(), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), - EndContainer(), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 3), - EndContainer(), -}; - -static WindowDesc _build_depot_desc( - WDP_AUTO, NULL, 0, 0, - WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, - WDF_CONSTRUCTION, - _nested_build_depot_widgets, lengthof(_nested_build_depot_widgets) -); - -static void ShowBuildTrainDepotPicker(Window *parent) -{ - new BuildRailDepotWindow(&_build_depot_desc, parent); -} - -struct BuildRailWaypointWindow : PickerWindowBase { - BuildRailWaypointWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) - { - this->CreateNestedTree(); - - NWidgetMatrix *matrix = this->GetWidget(WID_BRW_WAYPOINT_MATRIX); - matrix->SetScrollbar(this->GetScrollbar(WID_BRW_SCROLL)); - - this->FinishInitNested(TRANSPORT_RAIL); - - matrix->SetCount(_waypoint_count); - matrix->SetClicked(_cur_waypoint_type); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_BRW_WAYPOINT_MATRIX: - /* Three blobs high and wide. */ - size->width += resize->width * 2; - size->height += resize->height * 2; - - /* Resizing in X direction only at blob size, but at pixel level in Y. */ - resize->height = 1; - break; - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (GB(widget, 0, 16)) { - case WID_BRW_WAYPOINT: { - byte type = GB(widget, 16, 16); - const StationSpec *statspec = StationClass::Get(STAT_CLASS_WAYP)->GetSpec(type); - DrawWaypointSprite(r.left + TILE_PIXELS, r.bottom - TILE_PIXELS, type, _cur_railtype); - - if (!IsStationAvailable(statspec)) { - GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER); - } - } - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (GB(widget, 0, 16)) { - case WID_BRW_WAYPOINT: { - byte type = GB(widget, 16, 16); - this->GetWidget(WID_BRW_WAYPOINT_MATRIX)->SetClicked(_cur_waypoint_type); - - /* Check station availability callback */ - const StationSpec *statspec = StationClass::Get(STAT_CLASS_WAYP)->GetSpec(type); - if (!IsStationAvailable(statspec)) return; - - _cur_waypoint_type = type; - this->GetWidget(WID_BRW_WAYPOINT_MATRIX)->SetClicked(_cur_waypoint_type); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - break; - } - } - } -}; - -/** Nested widget definition for the build NewGRF rail waypoint window */ -static const NWidgetPart _nested_build_waypoint_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_WAYPOINT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BRW_WAYPOINT_MATRIX), SetPIP(3, 2, 3), SetScrollbar(WID_BRW_SCROLL), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BRW_WAYPOINT), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), SetScrollbar(WID_BRW_SCROLL), EndContainer(), - EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_BRW_SCROLL), - NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), - EndContainer(), - EndContainer(), -}; - -static WindowDesc _build_waypoint_desc( - WDP_AUTO, "build_waypoint", 0, 0, - WC_BUILD_WAYPOINT, WC_BUILD_TOOLBAR, - WDF_CONSTRUCTION, - _nested_build_waypoint_widgets, lengthof(_nested_build_waypoint_widgets) -); - -static void ShowBuildWaypointPicker(Window *parent) -{ - new BuildRailWaypointWindow(&_build_waypoint_desc, parent); -} - -/** - * Initialize rail building GUI settings - */ -void InitializeRailGui() -{ - _build_depot_direction = DIAGDIR_NW; -} - -/** - * Re-initialize rail-build toolbar after toggling support for electric trains - * @param disable Boolean whether electric trains are disabled (removed from the game) - */ -void ReinitGuiAfterToggleElrail(bool disable) -{ - extern RailType _last_built_railtype; - if (disable && _last_built_railtype == RAILTYPE_ELECTRIC) { - _last_built_railtype = _cur_railtype = RAILTYPE_RAIL; - BuildRailToolbarWindow *w = dynamic_cast(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL)); - if (w != NULL) w->ModifyRailType(_cur_railtype); - } - MarkWholeScreenDirty(); -} - -/** Set the initial (default) railtype to use */ -static void SetDefaultRailGui() -{ - if (_local_company == COMPANY_SPECTATOR || !Company::IsValidID(_local_company)) return; - - extern RailType _last_built_railtype; - RailType rt = (RailType)(_settings_client.gui.default_rail_type + RAILTYPE_END); - if (rt == DEF_RAILTYPE_MOST_USED) { - /* Find the most used rail type */ - RailType count[RAILTYPE_END]; - memset(count, 0, sizeof(count)); - for (TileIndex t = 0; t < MapSize(); t++) { - if (IsTileType(t, MP_RAILWAY) || IsLevelCrossingTile(t) || HasStationTileRail(t) || - (IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL)) { - count[GetRailType(t)]++; - } - } - - rt = RAILTYPE_RAIL; - for (RailType r = RAILTYPE_ELECTRIC; r < RAILTYPE_END; r++) { - if (count[r] >= count[rt]) rt = r; - } - - /* No rail, just get the first available one */ - if (count[rt] == 0) rt = DEF_RAILTYPE_FIRST; - } - switch (rt) { - case DEF_RAILTYPE_FIRST: - rt = RAILTYPE_RAIL; - while (rt < RAILTYPE_END && !HasRailtypeAvail(_local_company, rt)) rt++; - break; - - case DEF_RAILTYPE_LAST: - rt = GetBestRailtype(_local_company); - break; - - default: - break; - } - - _last_built_railtype = _cur_railtype = rt; - BuildRailToolbarWindow *w = dynamic_cast(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL)); - if (w != NULL) w->ModifyRailType(_cur_railtype); -} - -/** - * Updates the current signal variant used in the signal GUI - * to the one adequate to current year. - * @param p needed to be called when a setting changes - * @return success, needed for settings - */ -bool ResetSignalVariant(int32 p) -{ - SignalVariant new_variant = (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC); - - if (new_variant != _cur_signal_variant) { - Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); - if (w != NULL) { - w->SetDirty(); - w->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type); - } - _cur_signal_variant = new_variant; - } - - return true; -} - -/** - * Resets the rail GUI - sets default railtype to build - * and resets the signal GUI - */ -void InitializeRailGUI() -{ - SetDefaultRailGui(); - - _convert_signal_button = false; - _cur_signal_type = _default_signal_type[_settings_client.gui.default_signal_type]; - ResetSignalVariant(); -} - -/** - * Compare railtypes based on their sorting order. - * @param first The railtype to compare to. - * @param second The railtype to compare. - * @return True iff the first should be sorted before the second. - */ -static int CDECL CompareRailTypes(const DropDownListItem * const *first, const DropDownListItem * const *second) -{ - return GetRailTypeInfo((RailType)(*first)->result)->sorting_order - GetRailTypeInfo((RailType)(*second)->result)->sorting_order; -} - -/** - * Create a drop down list for all the rail types of the local company. - * @param for_replacement Whether this list is for the replacement window. - * @return The populated and sorted #DropDownList. - */ -DropDownList *GetRailTypeDropDownList(bool for_replacement) -{ - RailTypes used_railtypes = RAILTYPES_NONE; - - /* Find the used railtypes. */ - Engine *e; - FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { - if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; - - used_railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes; - } - - /* Get the date introduced railtypes as well. */ - used_railtypes = AddDateIntroducedRailTypes(used_railtypes, MAX_DAY); - - const Company *c = Company::Get(_local_company); - DropDownList *list = new DropDownList(); - for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { - /* If it's not used ever, don't show it to the user. */ - if (!HasBit(used_railtypes, rt)) continue; - - const RailtypeInfo *rti = GetRailTypeInfo(rt); - /* Skip rail type if it has no label */ - if (rti->label == 0) continue; - - StringID str = for_replacement ? rti->strings.replace_text : (rti->max_speed > 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY : STR_JUST_STRING); - DropDownListParamStringItem *item = new DropDownListParamStringItem(str, rt, !HasBit(c->avail_railtypes, rt)); - item->SetParam(0, rti->strings.menu_text); - item->SetParam(1, rti->max_speed); - *list->Append() = item; - } - QSortT(list->Begin(), list->Length(), CompareRailTypes); - return list; -} diff --git a/src/road_gui.cpp.orig b/src/road_gui.cpp.orig deleted file mode 100644 index 04387cbb7d..0000000000 --- a/src/road_gui.cpp.orig +++ /dev/null @@ -1,1092 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file road_gui.cpp GUI for building roads. */ - -#include "stdafx.h" -#include "gui.h" -#include "window_gui.h" -#include "station_gui.h" -#include "terraform_gui.h" -#include "viewport_func.h" -#include "command_func.h" -#include "road_cmd.h" -#include "station_func.h" -#include "window_func.h" -#include "vehicle_func.h" -#include "sound_func.h" -#include "company_func.h" -#include "tunnelbridge.h" -#include "tunnelbridge_map.h" -#include "tilehighlight_func.h" -#include "company_base.h" -#include "hotkeys.h" -#include "road_gui.h" - -#include "widgets/road_widget.h" - -#include "table/strings.h" - -static void ShowRVStationPicker(Window *parent, RoadStopType rs); -static void ShowRoadDepotPicker(Window *parent); - -static bool _remove_button_clicked; -static bool _one_way_button_clicked; - -/** - * Define the values of the RoadFlags - * @see CmdBuildLongRoad - */ -enum RoadFlags { - RF_NONE = 0x00, - RF_START_HALFROAD_Y = 0x01, // The start tile in Y-dir should have only a half road - RF_END_HALFROAD_Y = 0x02, // The end tile in Y-dir should have only a half road - RF_DIR_Y = 0x04, // The direction is Y-dir - RF_DIR_X = RF_NONE, // Dummy; Dir X is set when RF_DIR_Y is not set - RF_START_HALFROAD_X = 0x08, // The start tile in X-dir should have only a half road - RF_END_HALFROAD_X = 0x10, // The end tile in X-dir should have only a half road -}; -DECLARE_ENUM_AS_BIT_SET(RoadFlags) - -static RoadFlags _place_road_flag; - -static RoadType _cur_roadtype; - -static DiagDirection _road_depot_orientation; -static DiagDirection _road_station_picker_orientation; - -void CcPlaySound1D(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); -} - -/** - * Callback to start placing a bridge. - * @param tile Start tile of the bridge. - */ -static void PlaceRoad_Bridge(TileIndex tile, Window *w) -{ - if (IsBridgeTile(tile)) { - TileIndex other_tile = GetOtherTunnelBridgeEnd(tile); - Point pt = {0, 0}; - w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile); - } else { - VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE); - } -} - -/** - * Callback executed after a build road tunnel command has been called. - * - * @param result Whether the build succeeded. - * @param start_tile Starting tile of the tunnel. - * @param p1 bit 0-3 railtype or roadtypes - * bit 8-9 transport type - * @param p2 unused - */ -void CcBuildRoadTunnel(const CommandCost &result, TileIndex start_tile, uint32 p1, uint32 p2) -{ - if (result.Succeeded()) { - if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_2, start_tile); - if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - - DiagDirection start_direction = ReverseDiagDir(GetTunnelBridgeDirection(start_tile)); - ConnectRoadToStructure(start_tile, start_direction); - - TileIndex end_tile = GetOtherTunnelBridgeEnd(start_tile); - DiagDirection end_direction = ReverseDiagDir(GetTunnelBridgeDirection(end_tile)); - ConnectRoadToStructure(end_tile, end_direction); - } else { - SetRedErrorSquare(_build_tunnel_endtile); - } -} - -/** Structure holding information per roadtype for several functions */ -struct RoadTypeInfo { - StringID err_build_road; ///< Building a normal piece of road - StringID err_remove_road; ///< Removing a normal piece of road - StringID err_depot; ///< Building a depot - StringID err_build_station[2]; ///< Building a bus or truck station - StringID err_remove_station[2]; ///< Removing of a bus or truck station - - StringID picker_title[2]; ///< Title for the station picker for bus or truck stations - StringID picker_tooltip[2]; ///< Tooltip for the station picker for bus or truck stations - - SpriteID cursor_nesw; ///< Cursor for building NE and SW bits - SpriteID cursor_nwse; ///< Cursor for building NW and SE bits - SpriteID cursor_autoroad; ///< Cursor for building autoroad -}; - -/** What errors/cursors must be shown for several types of roads */ -static const RoadTypeInfo _road_type_infos[] = { - { - STR_ERROR_CAN_T_BUILD_ROAD_HERE, - STR_ERROR_CAN_T_REMOVE_ROAD_FROM, - STR_ERROR_CAN_T_BUILD_ROAD_DEPOT, - { STR_ERROR_CAN_T_BUILD_BUS_STATION, STR_ERROR_CAN_T_BUILD_TRUCK_STATION }, - { STR_ERROR_CAN_T_REMOVE_BUS_STATION, STR_ERROR_CAN_T_REMOVE_TRUCK_STATION }, - { STR_STATION_BUILD_BUS_ORIENTATION, STR_STATION_BUILD_TRUCK_ORIENTATION }, - { STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP, STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP }, - - SPR_CURSOR_ROAD_NESW, - SPR_CURSOR_ROAD_NWSE, - SPR_CURSOR_AUTOROAD, - }, - { - STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE, - STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM, - STR_ERROR_CAN_T_BUILD_TRAM_DEPOT, - { STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION }, - { STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION }, - { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION }, - { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP }, - - SPR_CURSOR_TRAMWAY_NESW, - SPR_CURSOR_TRAMWAY_NWSE, - SPR_CURSOR_AUTOTRAM, - }, -}; - -/** - * If required, connects a new structure to an existing road or tram by building the missing roadbit. - * @param tile Tile containing the structure to connect. - * @param direction Direction to check. - */ -void ConnectRoadToStructure(TileIndex tile, DiagDirection direction) -{ - tile += TileOffsByDiagDir(direction); - /* if there is a roadpiece just outside of the station entrance, build a connecting route */ - if (IsNormalRoadTile(tile)) { - if (GetRoadBits(tile, _cur_roadtype) != ROAD_NONE) { - DoCommandP(tile, _cur_roadtype << 4 | DiagDirToRoadBits(ReverseDiagDir(direction)), 0, CMD_BUILD_ROAD); - } - } -} - -void CcRoadDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Failed()) return; - - DiagDirection dir = (DiagDirection)GB(p1, 0, 2); - if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); - if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - ConnectRoadToStructure(tile, dir); -} - -/** - * Command callback for building road stops. - * @param result Result of the build road stop command. - * @param tile Start tile. - * @param p1 bit 0..7: Width of the road stop. - * bit 8..15: Length of the road stop. - * @param p2 bit 0: 0 For bus stops, 1 for truck stops. - * bit 1: 0 For normal stops, 1 for drive-through. - * bit 2..3: The roadtypes. - * bit 5: Allow stations directly adjacent to other stations. - * bit 6..7: Entrance direction (#DiagDirection). - * bit 16..31: Station ID to join (NEW_STATION if build new one). - * @see CmdBuildRoadStop - */ -void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Failed()) return; - - DiagDirection dir = (DiagDirection)GB(p2, 6, 2); - if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); - if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - TileArea roadstop_area(tile, GB(p1, 0, 8), GB(p1, 8, 8)); - TILE_AREA_LOOP(cur_tile, roadstop_area) { - ConnectRoadToStructure(cur_tile, dir); - /* For a drive-through road stop build connecting road for other entrance. */ - if (HasBit(p2, 1)) ConnectRoadToStructure(cur_tile, ReverseDiagDir(dir)); - } -} - -/** - * Place a new road stop. - * @param start_tile First tile of the area. - * @param end_tile Last tile of the area. - * @param p2 bit 0: 0 For bus stops, 1 for truck stops. - * bit 2..3: The roadtypes. - * bit 5: Allow stations directly adjacent to other stations. - * @param cmd Command to use. - * @see CcRoadStop() - */ -static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, uint32 cmd) -{ - uint8 ddir = _road_station_picker_orientation; - SB(p2, 16, 16, INVALID_STATION); // no station to join - - if (ddir >= DIAGDIR_END) { - SetBit(p2, 1); // It's a drive-through stop. - ddir -= DIAGDIR_END; // Adjust picker result to actual direction. - } - p2 |= ddir << 6; // Set the DiagDirecion into p2 bits 6 and 7. - - TileArea ta(start_tile, end_tile); - CommandContainer cmdcont = { ta.tile, ta.w | ta.h << 8, p2, cmd, CcRoadStop, "" }; - ShowSelectStationIfNeeded(cmdcont, ta); -} - -/** - * Callback for placing a bus station. - * @param tile Position to place the station. - */ -static void PlaceRoad_BusStation(TileIndex tile) -{ - if (_remove_button_clicked) { - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_BUSSTOP); - } else { - if (_road_station_picker_orientation < DIAGDIR_END) { // Not a drive-through stop. - VpStartPlaceSizing(tile, (DiagDirToAxis(_road_station_picker_orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_BUSSTOP); - } else { - VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_BUSSTOP); - } - VpSetPlaceSizingLimit(_settings_game.station.station_spread); - } -} - -/** - * Callback for placing a truck station. - * @param tile Position to place the station. - */ -static void PlaceRoad_TruckStation(TileIndex tile) -{ - if (_remove_button_clicked) { - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_TRUCKSTOP); - } else { - if (_road_station_picker_orientation < DIAGDIR_END) { // Not a drive-through stop. - VpStartPlaceSizing(tile, (DiagDirToAxis(_road_station_picker_orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_TRUCKSTOP); - } else { - VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_TRUCKSTOP); - } - VpSetPlaceSizingLimit(_settings_game.station.station_spread); - } -} - -typedef void OnButtonClick(Window *w); - -/** - * Toggles state of the Remove button of Build road toolbar - * @param w window the button belongs to - */ -static void ToggleRoadButton_Remove(Window *w) -{ - w->ToggleWidgetLoweredState(WID_ROT_REMOVE); - w->SetWidgetDirty(WID_ROT_REMOVE); - _remove_button_clicked = w->IsWidgetLowered(WID_ROT_REMOVE); - SetSelectionRed(_remove_button_clicked); -} - -/** - * Updates the Remove button because of Ctrl state change - * @param w window the button belongs to - * @return true iff the remove button was changed - */ -static bool RoadToolbar_CtrlChanged(Window *w) -{ - if (w->IsWidgetDisabled(WID_ROT_REMOVE)) return false; - - /* allow ctrl to switch remove mode only for these widgets */ - for (uint i = WID_ROT_ROAD_X; i <= WID_ROT_AUTOROAD; i++) { - if (w->IsWidgetLowered(i)) { - ToggleRoadButton_Remove(w); - return true; - } - } - - return false; -} - -/** Road toolbar window handler. */ -struct BuildRoadToolbarWindow : Window { - int last_started_action; ///< Last started user action. - - BuildRoadToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) - { - this->InitNested(window_number); - this->SetWidgetsDisabledState(true, - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); - - this->OnInvalidateData(); - this->last_started_action = WIDGET_LIST_END; - - if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); - } - - ~BuildRoadToolbarWindow() - { - if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_ROAD), - WID_ROT_DEPOT, - WID_ROT_BUS_STATION, - WID_ROT_TRUCK_STATION, - WIDGET_LIST_END); - } - - /** - * Update the remove button lowered state of the road toolbar - * - * @param clicked_widget The widget which the client clicked just now - */ - void UpdateOptionWidgetStatus(RoadToolbarWidgets clicked_widget) - { - /* The remove and the one way button state is driven - * by the other buttons so they don't act on themselves. - * Both are only valid if they are able to apply as options. */ - switch (clicked_widget) { - case WID_ROT_REMOVE: - this->RaiseWidget(WID_ROT_ONE_WAY); - this->SetWidgetDirty(WID_ROT_ONE_WAY); - break; - - case WID_ROT_ONE_WAY: - this->RaiseWidget(WID_ROT_REMOVE); - this->SetWidgetDirty(WID_ROT_REMOVE); - break; - - case WID_ROT_BUS_STATION: - case WID_ROT_TRUCK_STATION: - this->DisableWidget(WID_ROT_ONE_WAY); - this->SetWidgetDisabledState(WID_ROT_REMOVE, !this->IsWidgetLowered(clicked_widget)); - break; - - case WID_ROT_ROAD_X: - case WID_ROT_ROAD_Y: - case WID_ROT_AUTOROAD: - this->SetWidgetsDisabledState(!this->IsWidgetLowered(clicked_widget), - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); - break; - - default: - /* When any other buttons than road/station, raise and - * disable the removal button */ - this->SetWidgetsDisabledState(true, - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); - this->SetWidgetsLoweredState(false, - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); - break; - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - _remove_button_clicked = false; - _one_way_button_clicked = false; - switch (widget) { - case WID_ROT_ROAD_X: - HandlePlacePushButton(this, WID_ROT_ROAD_X, _road_type_infos[_cur_roadtype].cursor_nwse, HT_RECT); - this->last_started_action = widget; - break; - - case WID_ROT_ROAD_Y: - HandlePlacePushButton(this, WID_ROT_ROAD_Y, _road_type_infos[_cur_roadtype].cursor_nesw, HT_RECT); - this->last_started_action = widget; - break; - - case WID_ROT_AUTOROAD: - HandlePlacePushButton(this, WID_ROT_AUTOROAD, _road_type_infos[_cur_roadtype].cursor_autoroad, HT_RECT); - this->last_started_action = widget; - break; - - case WID_ROT_DEMOLISH: - HandlePlacePushButton(this, WID_ROT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); - this->last_started_action = widget; - break; - - case WID_ROT_DEPOT: - if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; - if (HandlePlacePushButton(this, WID_ROT_DEPOT, SPR_CURSOR_ROAD_DEPOT, HT_RECT)) { - ShowRoadDepotPicker(this); - this->last_started_action = widget; - } - break; - - case WID_ROT_BUS_STATION: - if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; - if (HandlePlacePushButton(this, WID_ROT_BUS_STATION, SPR_CURSOR_BUS_STATION, HT_RECT)) { - ShowRVStationPicker(this, ROADSTOP_BUS); - this->last_started_action = widget; - } - break; - - case WID_ROT_TRUCK_STATION: - if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; - if (HandlePlacePushButton(this, WID_ROT_TRUCK_STATION, SPR_CURSOR_TRUCK_STATION, HT_RECT)) { - ShowRVStationPicker(this, ROADSTOP_TRUCK); - this->last_started_action = widget; - } - break; - - case WID_ROT_ONE_WAY: - if (this->IsWidgetDisabled(WID_ROT_ONE_WAY)) return; - this->SetDirty(); - this->ToggleWidgetLoweredState(WID_ROT_ONE_WAY); - SetSelectionRed(false); - break; - - case WID_ROT_BUILD_BRIDGE: - HandlePlacePushButton(this, WID_ROT_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT); - this->last_started_action = widget; - break; - - case WID_ROT_BUILD_TUNNEL: - HandlePlacePushButton(this, WID_ROT_BUILD_TUNNEL, SPR_CURSOR_ROAD_TUNNEL, HT_SPECIAL); - this->last_started_action = widget; - break; - - case WID_ROT_REMOVE: - if (this->IsWidgetDisabled(WID_ROT_REMOVE)) return; - - DeleteWindowById(WC_SELECT_STATION, 0); - ToggleRoadButton_Remove(this); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - break; - - default: NOT_REACHED(); - } - this->UpdateOptionWidgetStatus((RoadToolbarWidgets)widget); - if (_ctrl_pressed) RoadToolbar_CtrlChanged(this); - } - - virtual EventState OnHotkey(int hotkey) - { - MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection - return Window::OnHotkey(hotkey); - } - - virtual void OnPlaceObject(Point pt, TileIndex tile) - { - _remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE); - _one_way_button_clicked = this->IsWidgetLowered(WID_ROT_ONE_WAY); - switch (this->last_started_action) { - case WID_ROT_ROAD_X: - _place_road_flag = RF_DIR_X; - if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X; - VpStartPlaceSizing(tile, VPM_FIX_Y, DDSP_PLACE_ROAD_X_DIR); - break; - - case WID_ROT_ROAD_Y: - _place_road_flag = RF_DIR_Y; - if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y; - VpStartPlaceSizing(tile, VPM_FIX_X, DDSP_PLACE_ROAD_Y_DIR); - break; - - case WID_ROT_AUTOROAD: - _place_road_flag = RF_NONE; - if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X; - if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y; - VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_AUTOROAD); - break; - - case WID_ROT_DEMOLISH: - PlaceProc_DemolishArea(tile); - break; - - case WID_ROT_DEPOT: - DoCommandP(tile, _cur_roadtype << 2 | _road_depot_orientation, 0, - CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot); - break; - - case WID_ROT_BUS_STATION: - PlaceRoad_BusStation(tile); - break; - - case WID_ROT_TRUCK_STATION: - PlaceRoad_TruckStation(tile); - break; - - case WID_ROT_BUILD_BRIDGE: - PlaceRoad_Bridge(tile, this); - break; - - case WID_ROT_BUILD_TUNNEL: - DoCommandP(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, - CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRoadTunnel); - break; - - default: NOT_REACHED(); - } - } - - virtual void OnPlaceObjectAbort() - { - this->RaiseButtons(); - this->SetWidgetsDisabledState(true, - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); - this->SetWidgetDirty(WID_ROT_REMOVE); - this->SetWidgetDirty(WID_ROT_ONE_WAY); - - DeleteWindowById(WC_BUS_STATION, TRANSPORT_ROAD); - DeleteWindowById(WC_TRUCK_STATION, TRANSPORT_ROAD); - DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_ROAD); - DeleteWindowById(WC_SELECT_STATION, 0); - DeleteWindowByClass(WC_BUILD_BRIDGE); - } - - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) - { - /* Here we update the end tile flags - * of the road placement actions. - * At first we reset the end halfroad - * bits and if needed we set them again. */ - switch (select_proc) { - case DDSP_PLACE_ROAD_X_DIR: - _place_road_flag &= ~RF_END_HALFROAD_X; - if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X; - break; - - case DDSP_PLACE_ROAD_Y_DIR: - _place_road_flag &= ~RF_END_HALFROAD_Y; - if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y; - break; - - case DDSP_PLACE_AUTOROAD: - _place_road_flag &= ~(RF_END_HALFROAD_Y | RF_END_HALFROAD_X); - if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y; - if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X; - - /* For autoroad we need to update the - * direction of the road */ - if (_thd.size.x > _thd.size.y || (_thd.size.x == _thd.size.y && - ( (_tile_fract_coords.x < _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) < 16) || - (_tile_fract_coords.x > _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) > 16) ))) { - /* Set dir = X */ - _place_road_flag &= ~RF_DIR_Y; - } else { - /* Set dir = Y */ - _place_road_flag |= RF_DIR_Y; - } - - break; - - default: - break; - } - - VpSelectTilesWithMethod(pt.x, pt.y, select_method); - } - - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) - { - if (pt.x != -1) { - switch (select_proc) { - default: NOT_REACHED(); - case DDSP_BUILD_BRIDGE: - if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype)); - break; - - case DDSP_DEMOLISH_AREA: - GUIPlaceProcDragXY(select_proc, start_tile, end_tile); - break; - - case DDSP_PLACE_ROAD_X_DIR: - case DDSP_PLACE_ROAD_Y_DIR: - case DDSP_PLACE_AUTOROAD: - /* Flag description: - * Use the first three bits (0x07) if dir == Y - * else use the last 2 bits (X dir has - * not the 3rd bit set) */ - _place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3)); - - DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), - _remove_button_clicked ? - CMD_REMOVE_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) : - CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound1D); - break; - - case DDSP_BUILD_BUSSTOP: - PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_BUS])); - break; - - case DDSP_BUILD_TRUCKSTOP: - PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_TRUCK, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_TRUCK])); - break; - - case DDSP_REMOVE_BUSSTOP: { - TileArea ta(start_tile, end_tile); - DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound1D); - break; - } - - case DDSP_REMOVE_TRUCKSTOP: { - TileArea ta(start_tile, end_tile); - DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound1D); - break; - } - } - } - } - - virtual void OnPlacePresize(Point pt, TileIndex tile) - { - DoCommand(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); - VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); - } - - virtual EventState OnCTRLStateChange() - { - if (RoadToolbar_CtrlChanged(this)) return ES_HANDLED; - return ES_NOT_HANDLED; - } - - static HotkeyList hotkeys; -}; - -/** - * Handler for global hotkeys of the BuildRoadToolbarWindow. - * @param hotkey Hotkey - * @return ES_HANDLED if hotkey was accepted. - */ -static EventState RoadToolbarGlobalHotkeys(int hotkey) -{ - Window *w = NULL; - switch (_game_mode) { - case GM_NORMAL: { - extern RoadType _last_built_roadtype; - w = ShowBuildRoadToolbar(_last_built_roadtype); - break; - } - - case GM_EDITOR: - w = ShowBuildRoadScenToolbar(); - break; - - default: - break; - } - - if (w == NULL) return ES_NOT_HANDLED; - return w->OnHotkey(hotkey); -} - -static Hotkey roadtoolbar_hotkeys[] = { - Hotkey('1', "build_x", WID_ROT_ROAD_X), - Hotkey('2', "build_y", WID_ROT_ROAD_Y), - Hotkey('3', "autoroad", WID_ROT_AUTOROAD), - Hotkey('4', "demolish", WID_ROT_DEMOLISH), - Hotkey('5', "depot", WID_ROT_DEPOT), - Hotkey('6', "bus_station", WID_ROT_BUS_STATION), - Hotkey('7', "truck_station", WID_ROT_TRUCK_STATION), - Hotkey('8', "oneway", WID_ROT_ONE_WAY), - Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE), - Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL), - Hotkey('R', "remove", WID_ROT_REMOVE), - HOTKEY_LIST_END -}; -HotkeyList BuildRoadToolbarWindow::hotkeys("roadtoolbar", roadtoolbar_hotkeys, RoadToolbarGlobalHotkeys); - - -static const NWidgetPart _nested_build_road_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), - SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD), - EndContainer(), -}; - -static WindowDesc _build_road_desc( - WDP_ALIGN_TOOLBAR, "toolbar_road", 0, 0, - WC_BUILD_TOOLBAR, WC_NONE, - WDF_CONSTRUCTION, - _nested_build_road_widgets, lengthof(_nested_build_road_widgets), - &BuildRoadToolbarWindow::hotkeys -); - -static const NWidgetPart _nested_build_tramway_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOTRAM, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), - NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), SetMinimalSize(0, 0), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), - SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS), - EndContainer(), -}; - -static WindowDesc _build_tramway_desc( - WDP_ALIGN_TOOLBAR, "toolbar_tramway", 0, 0, - WC_BUILD_TOOLBAR, WC_NONE, - WDF_CONSTRUCTION, - _nested_build_tramway_widgets, lengthof(_nested_build_tramway_widgets), - &BuildRoadToolbarWindow::hotkeys -); - -/** - * Open the build road toolbar window - * - * If the terraform toolbar is linked to the toolbar, that window is also opened. - * - * @return newly opened road toolbar, or NULL if the toolbar could not be opened. - */ -Window *ShowBuildRoadToolbar(RoadType roadtype) -{ - if (!Company::IsValidID(_local_company)) return NULL; - _cur_roadtype = roadtype; - - DeleteWindowByClass(WC_BUILD_TOOLBAR); - return AllocateWindowDescFront(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD); -} - -static const NWidgetPart _nested_build_road_scen_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), - SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD), - EndContainer(), -}; - -static WindowDesc _build_road_scen_desc( - WDP_AUTO, "toolbar_road_scen", 0, 0, - WC_SCEN_BUILD_TOOLBAR, WC_NONE, - WDF_CONSTRUCTION, - _nested_build_road_scen_widgets, lengthof(_nested_build_road_scen_widgets), - &BuildRoadToolbarWindow::hotkeys -); - -/** - * Show the road building toolbar in the scenario editor. - * @return The just opened toolbar. - */ -Window *ShowBuildRoadScenToolbar() -{ - _cur_roadtype = ROADTYPE_ROAD; - return AllocateWindowDescFront(&_build_road_scen_desc, TRANSPORT_ROAD); -} - -struct BuildRoadDepotWindow : public PickerWindowBase { - BuildRoadDepotWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) - { - this->CreateNestedTree(); - - this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); - if ( _cur_roadtype == ROADTYPE_TRAM) { - this->GetWidget(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION; - for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_NW; i++) this->GetWidget(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP; - } - - this->FinishInitNested(TRANSPORT_ROAD); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (!IsInsideMM(widget, WID_BROD_DEPOT_NE, WID_BROD_DEPOT_NW + 1)) return; - - DrawRoadDepotSprite(r.left - 1, r.top, (DiagDirection)(widget - WID_BROD_DEPOT_NE + DIAGDIR_NE), _cur_roadtype); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_BROD_DEPOT_NW: - case WID_BROD_DEPOT_NE: - case WID_BROD_DEPOT_SW: - case WID_BROD_DEPOT_SE: - this->RaiseWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); - _road_depot_orientation = (DiagDirection)(widget - WID_BROD_DEPOT_NE); - this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - break; - - default: - break; - } - } -}; - -static const NWidgetPart _nested_build_road_depot_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROD_CAPTION), SetDataTip(STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), - NWidget(NWID_SPACER), SetMinimalSize(0, 3), - NWidget(NWID_HORIZONTAL_LTR), - NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), - EndContainer(), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), - EndContainer(), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 3), - EndContainer(), -}; - -static WindowDesc _build_road_depot_desc( - WDP_AUTO, NULL, 0, 0, - WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, - WDF_CONSTRUCTION, - _nested_build_road_depot_widgets, lengthof(_nested_build_road_depot_widgets) -); - -static void ShowRoadDepotPicker(Window *parent) -{ - new BuildRoadDepotWindow(&_build_road_depot_desc, parent); -} - -struct BuildRoadStationWindow : public PickerWindowBase { - BuildRoadStationWindow(WindowDesc *desc, Window *parent, RoadStopType rs) : PickerWindowBase(desc, parent) - { - this->CreateNestedTree(); - - /* Trams don't have non-drivethrough stations */ - if (_cur_roadtype == ROADTYPE_TRAM && _road_station_picker_orientation < DIAGDIR_END) { - _road_station_picker_orientation = DIAGDIR_END; - } - this->SetWidgetsDisabledState(_cur_roadtype == ROADTYPE_TRAM, - WID_BROS_STATION_NE, - WID_BROS_STATION_SE, - WID_BROS_STATION_SW, - WID_BROS_STATION_NW, - WIDGET_LIST_END); - - this->GetWidget(WID_BROS_CAPTION)->widget_data = _road_type_infos[_cur_roadtype].picker_title[rs]; - for (uint i = WID_BROS_STATION_NE; i < WID_BROS_LT_OFF; i++) this->GetWidget(i)->tool_tip = _road_type_infos[_cur_roadtype].picker_tooltip[rs]; - - this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); - this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF); - - this->FinishInitNested(TRANSPORT_ROAD); - - this->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION; - } - - virtual ~BuildRoadStationWindow() - { - DeleteWindowById(WC_SELECT_STATION, 0); - } - - virtual void OnPaint() - { - this->DrawWidgets(); - - int rad = _settings_game.station.modified_catchment ? ((this->window_class == WC_BUS_STATION) ? CA_BUS : CA_TRUCK) : CA_UNMODIFIED; - if (_settings_client.gui.station_show_coverage) { - SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); - } else { - SetTileSelectSize(1, 1); - } - - /* 'Accepts' and 'Supplies' texts. */ - StationCoverageType sct = (this->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY; - int top = this->GetWidget(WID_BROS_LT_ON)->pos_y + this->GetWidget(WID_BROS_LT_ON)->current_y + WD_PAR_VSEP_NORMAL; - NWidgetBase *back_nwi = this->GetWidget(WID_BROS_BACKGROUND); - int right = back_nwi->pos_x + back_nwi->current_x; - int bottom = back_nwi->pos_y + back_nwi->current_y; - top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, false) + WD_PAR_VSEP_NORMAL; - top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, true) + WD_PAR_VSEP_NORMAL; - /* Resize background if the window is too small. - * Never make the window smaller to avoid oscillating if the size change affects the acceptance. - * (This is the case, if making the window bigger moves the mouse into the window.) */ - if (top > bottom) { - ResizeWindow(this, 0, top - bottom); - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return; - - StationType st = (this->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK; - StationPickerDrawSprite(r.left + TILE_PIXELS, r.bottom - TILE_PIXELS, st, INVALID_RAILTYPE, widget < WID_BROS_STATION_X ? ROADTYPE_ROAD : _cur_roadtype, widget - WID_BROS_STATION_NE); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_BROS_STATION_NE: - case WID_BROS_STATION_SE: - case WID_BROS_STATION_SW: - case WID_BROS_STATION_NW: - case WID_BROS_STATION_X: - case WID_BROS_STATION_Y: - this->RaiseWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); - _road_station_picker_orientation = (DiagDirection)(widget - WID_BROS_STATION_NE); - this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - DeleteWindowById(WC_SELECT_STATION, 0); - break; - - case WID_BROS_LT_OFF: - case WID_BROS_LT_ON: - this->RaiseWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF); - _settings_client.gui.station_show_coverage = (widget != WID_BROS_LT_OFF); - this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - break; - - default: - break; - } - } - - virtual void OnTick() - { - CheckRedrawStationCoverage(this); - } -}; - -/** Widget definition of the build road station window */ -static const NWidgetPart _nested_rv_station_picker_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROS_CAPTION), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_BACKGROUND), - NWidget(NWID_SPACER), SetMinimalSize(0, 3), - NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SW), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SE), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 50), EndContainer(), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 1), - NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_INFO), SetMinimalSize(140, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_OFF), SetMinimalSize(60, 12), - SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_ON), SetMinimalSize(60, 12), - SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1), - EndContainer(), -}; - -static WindowDesc _rv_station_picker_desc( - WDP_AUTO, NULL, 0, 0, - WC_BUS_STATION, WC_BUILD_TOOLBAR, - WDF_CONSTRUCTION, - _nested_rv_station_picker_widgets, lengthof(_nested_rv_station_picker_widgets) -); - -static void ShowRVStationPicker(Window *parent, RoadStopType rs) -{ - new BuildRoadStationWindow(&_rv_station_picker_desc, parent, rs); -} - -void InitializeRoadGui() -{ - _road_depot_orientation = DIAGDIR_NW; - _road_station_picker_orientation = DIAGDIR_NW; -} diff --git a/src/script/api/game/game_window.hpp.sq.orig b/src/script/api/game/game_window.hpp.sq.orig deleted file mode 100644 index 280bf1e532..0000000000 --- a/src/script/api/game/game_window.hpp.sq.orig +++ /dev/null @@ -1,1328 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ - -#include "../script_window.hpp" -#include "../template/template_window.hpp.sq" - - -template <> const char *GetClassName() { return "GSWindow"; } - -void SQGSWindow_Register(Squirrel *engine) -{ - DefSQClass SQGSWindow("GSWindow"); - SQGSWindow.PreRegister(engine); - SQGSWindow.AddConstructor(engine, "x"); - - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_AI, "WN_GAME_OPTIONS_AI"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_ABOUT, "WN_GAME_OPTIONS_ABOUT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_NEWGRF_STATE, "WN_GAME_OPTIONS_NEWGRF_STATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_GAME_OPTIONS, "WN_GAME_OPTIONS_GAME_OPTIONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_GAME_SETTINGS, "WN_GAME_OPTIONS_GAME_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_QUERY_STRING, "WN_QUERY_STRING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_QUERY_STRING_SIGN, "WN_QUERY_STRING_SIGN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_CONFIRM_POPUP_QUERY, "WN_CONFIRM_POPUP_QUERY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_CONFIRM_POPUP_QUERY_BOOTSTRAP, "WN_CONFIRM_POPUP_QUERY_BOOTSTRAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_GAME, "WN_NETWORK_WINDOW_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_LOBBY, "WN_NETWORK_WINDOW_LOBBY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_CONTENT_LIST, "WN_NETWORK_WINDOW_CONTENT_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_START, "WN_NETWORK_WINDOW_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_STATUS_WINDOW_JOIN, "WN_NETWORK_STATUS_WINDOW_JOIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD, "WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NONE, "WC_NONE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_WINDOW, "WC_MAIN_WINDOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_TOOLBAR, "WC_MAIN_TOOLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATUS_BAR, "WC_STATUS_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TOOLBAR, "WC_BUILD_TOOLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_BUILD_TOOLBAR, "WC_SCEN_BUILD_TOOLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TREES, "WC_BUILD_TREES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRANSPARENCY_TOOLBAR, "WC_TRANSPARENCY_TOOLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_SIGNAL, "WC_BUILD_SIGNAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SMALLMAP, "WC_SMALLMAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ERRMSG, "WC_ERRMSG"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOOLTIPS, "WC_TOOLTIPS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_QUERY_STRING, "WC_QUERY_STRING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CONFIRM_POPUP_QUERY, "WC_CONFIRM_POPUP_QUERY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GOAL_QUESTION, "WC_GOAL_QUESTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SAVELOAD, "WC_SAVELOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_LAND_INFO, "WC_LAND_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_DROPDOWN_MENU, "WC_DROPDOWN_MENU"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_OSK, "WC_OSK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SET_DATE, "WC_SET_DATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_SETTINGS, "WC_AI_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GRF_PARAMETERS, "WC_GRF_PARAMETERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TEXTFILE, "WC_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_AUTHORITY, "WC_TOWN_AUTHORITY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_DETAILS, "WC_VEHICLE_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_REFIT, "WC_VEHICLE_REFIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_ORDERS, "WC_VEHICLE_ORDERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_REPLACE_VEHICLE, "WC_REPLACE_VEHICLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_TIMETABLE, "WC_VEHICLE_TIMETABLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_COLOUR, "WC_COMPANY_COLOUR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_MANAGER_FACE, "WC_COMPANY_MANAGER_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_STATION, "WC_SELECT_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NEWS_WINDOW, "WC_NEWS_WINDOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_DIRECTORY, "WC_TOWN_DIRECTORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SUBSIDIES_LIST, "WC_SUBSIDIES_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_DIRECTORY, "WC_INDUSTRY_DIRECTORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MESSAGE_HISTORY, "WC_MESSAGE_HISTORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SIGN_LIST, "WC_SIGN_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_LIST, "WC_AI_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GOALS_LIST, "WC_GOALS_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STORY_BOOK, "WC_STORY_BOOK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATION_LIST, "WC_STATION_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRAINS_LIST, "WC_TRAINS_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ROADVEH_LIST, "WC_ROADVEH_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SHIPS_LIST, "WC_SHIPS_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AIRCRAFT_LIST, "WC_AIRCRAFT_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_VIEW, "WC_TOWN_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_VIEW, "WC_VEHICLE_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATION_VIEW, "WC_STATION_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_DEPOT, "WC_VEHICLE_DEPOT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_WAYPOINT_VIEW, "WC_WAYPOINT_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_VIEW, "WC_INDUSTRY_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY, "WC_COMPANY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_OBJECT, "WC_BUILD_OBJECT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_VEHICLE, "WC_BUILD_VEHICLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_BRIDGE, "WC_BUILD_BRIDGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_STATION, "WC_BUILD_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUS_STATION, "WC_BUS_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRUCK_STATION, "WC_TRUCK_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_DEPOT, "WC_BUILD_DEPOT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_WAYPOINT, "WC_BUILD_WAYPOINT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_FOUND_TOWN, "WC_FOUND_TOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_INDUSTRY, "WC_BUILD_INDUSTRY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_GAME, "WC_SELECT_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_LAND_GEN, "WC_SCEN_LAND_GEN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GENERATE_LANDSCAPE, "WC_GENERATE_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MODAL_PROGRESS, "WC_MODAL_PROGRESS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NETWORK_WINDOW, "WC_NETWORK_WINDOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CLIENT_LIST, "WC_CLIENT_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CLIENT_LIST_POPUP, "WC_CLIENT_LIST_POPUP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NETWORK_STATUS_WINDOW, "WC_NETWORK_STATUS_WINDOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SEND_NETWORK_MSG, "WC_SEND_NETWORK_MSG"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_PASSWORD_WINDOW, "WC_COMPANY_PASSWORD_WINDOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_CARGOES, "WC_INDUSTRY_CARGOES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GRAPH_LEGEND, "WC_GRAPH_LEGEND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_FINANCES, "WC_FINANCES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INCOME_GRAPH, "WC_INCOME_GRAPH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_OPERATING_PROFIT, "WC_OPERATING_PROFIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_DELIVERED_CARGO, "WC_DELIVERED_CARGO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PERFORMANCE_HISTORY, "WC_PERFORMANCE_HISTORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_VALUE, "WC_COMPANY_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_LEAGUE, "WC_COMPANY_LEAGUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PAYMENT_RATES, "WC_PAYMENT_RATES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PERFORMANCE_DETAIL, "WC_PERFORMANCE_DETAIL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_INFRASTRUCTURE, "WC_COMPANY_INFRASTRUCTURE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUY_COMPANY, "WC_BUY_COMPANY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ENGINE_PREVIEW, "WC_ENGINE_PREVIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MUSIC_WINDOW, "WC_MUSIC_WINDOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MUSIC_TRACK_SELECTION, "WC_MUSIC_TRACK_SELECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GAME_OPTIONS, "WC_GAME_OPTIONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CUSTOM_CURRENCY, "WC_CUSTOM_CURRENCY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CHEATS, "WC_CHEATS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_EXTRA_VIEW_PORT, "WC_EXTRA_VIEW_PORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CONSOLE, "WC_CONSOLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BOOTSTRAP, "WC_BOOTSTRAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_HIGHSCORE, "WC_HIGHSCORE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ENDSCREEN, "WC_ENDSCREEN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_DEBUG, "WC_AI_DEBUG"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NEWGRF_INSPECT, "WC_NEWGRF_INSPECT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SPRITE_ALIGNER, "WC_SPRITE_ALIGNER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_LINKGRAPH_LEGEND, "WC_LINKGRAPH_LEGEND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INVALID, "WC_INVALID"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BLUE, "TC_BLUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_SILVER, "TC_SILVER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GOLD, "TC_GOLD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_RED, "TC_RED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_PURPLE, "TC_PURPLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_LIGHT_BROWN, "TC_LIGHT_BROWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_ORANGE, "TC_ORANGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GREEN, "TC_GREEN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_YELLOW, "TC_YELLOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_DARK_GREEN, "TC_DARK_GREEN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_CREAM, "TC_CREAM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BROWN, "TC_BROWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_WHITE, "TC_WHITE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_LIGHT_BLUE, "TC_LIGHT_BLUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GREY, "TC_GREY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_DARK_BLUE, "TC_DARK_BLUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BLACK, "TC_BLACK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_INVALID, "TC_INVALID"); - SQGSWindow.DefSQConst(engine, ScriptWindow::NUMBER_ALL, "NUMBER_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WIDGET_ALL, "WIDGET_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_CAPTION, "WID_AIL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_LIST, "WID_AIL_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_SCROLLBAR, "WID_AIL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_INFO_BG, "WID_AIL_INFO_BG"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_ACCEPT, "WID_AIL_ACCEPT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_CANCEL, "WID_AIL_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_CAPTION, "WID_AIS_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_BACKGROUND, "WID_AIS_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_SCROLLBAR, "WID_AIS_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_ACCEPT, "WID_AIS_ACCEPT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_RESET, "WID_AIS_RESET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_BACKGROUND, "WID_AIC_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_DECREASE, "WID_AIC_DECREASE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_INCREASE, "WID_AIC_INCREASE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_NUMBER, "WID_AIC_NUMBER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_GAMELIST, "WID_AIC_GAMELIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_LIST, "WID_AIC_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_SCROLLBAR, "WID_AIC_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_MOVE_UP, "WID_AIC_MOVE_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_MOVE_DOWN, "WID_AIC_MOVE_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CHANGE, "WID_AIC_CHANGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CONFIGURE, "WID_AIC_CONFIGURE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CLOSE, "WID_AIC_CLOSE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_TEXTFILE, "WID_AIC_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CONTENT_DOWNLOAD, "WID_AIC_CONTENT_DOWNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_VIEW, "WID_AID_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_NAME_TEXT, "WID_AID_NAME_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SETTINGS, "WID_AID_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SCRIPT_GAME, "WID_AID_SCRIPT_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_RELOAD_TOGGLE, "WID_AID_RELOAD_TOGGLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_LOG_PANEL, "WID_AID_LOG_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SCROLLBAR, "WID_AID_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_COMPANY_BUTTON_START, "WID_AID_COMPANY_BUTTON_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_COMPANY_BUTTON_END, "WID_AID_COMPANY_BUTTON_END"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STRING_WIDGETS, "WID_AID_BREAK_STRING_WIDGETS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STR_ON_OFF_BTN, "WID_AID_BREAK_STR_ON_OFF_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STR_EDIT_BOX, "WID_AID_BREAK_STR_EDIT_BOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_MATCH_CASE_BTN, "WID_AID_MATCH_CASE_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_CONTINUE_BTN, "WID_AID_CONTINUE_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AT_AIRPORT, "WID_AT_AIRPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AT_DEMOLISH, "WID_AT_DEMOLISH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_CLASS_DROPDOWN, "WID_AP_CLASS_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_AIRPORT_LIST, "WID_AP_AIRPORT_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_SCROLLBAR, "WID_AP_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_NUM, "WID_AP_LAYOUT_NUM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_DECREASE, "WID_AP_LAYOUT_DECREASE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_INCREASE, "WID_AP_LAYOUT_INCREASE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_AIRPORT_SPRITE, "WID_AP_AIRPORT_SPRITE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_EXTRA_TEXT, "WID_AP_EXTRA_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BOTTOMPANEL, "WID_AP_BOTTOMPANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_COVERAGE_LABEL, "WID_AP_COVERAGE_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BTN_DONTHILIGHT, "WID_AP_BTN_DONTHILIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BTN_DOHILIGHT, "WID_AP_BTN_DOHILIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_CAPTION, "WID_RV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_MATRIX, "WID_RV_LEFT_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_SCROLLBAR, "WID_RV_LEFT_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_MATRIX, "WID_RV_RIGHT_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_SCROLLBAR, "WID_RV_RIGHT_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_DETAILS, "WID_RV_LEFT_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_DETAILS, "WID_RV_RIGHT_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_START_REPLACE, "WID_RV_START_REPLACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_INFO_TAB, "WID_RV_INFO_TAB"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_STOP_REPLACE, "WID_RV_STOP_REPLACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_ENGINEWAGON_TOGGLE, "WID_RV_TRAIN_ENGINEWAGON_TOGGLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_FLUFF_LEFT, "WID_RV_TRAIN_FLUFF_LEFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_RAILTYPE_DROPDOWN, "WID_RV_TRAIN_RAILTYPE_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_FLUFF_RIGHT, "WID_RV_TRAIN_FLUFF_RIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_WAGONREMOVE_TOGGLE, "WID_RV_TRAIN_WAGONREMOVE_TOGGLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BB_BACKGROUND, "WID_BB_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_QUESTION, "WID_BAFD_QUESTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_YES, "WID_BAFD_YES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_NO, "WID_BAFD_NO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_CAPTION, "WID_BBS_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_DROPDOWN_ORDER, "WID_BBS_DROPDOWN_ORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_DROPDOWN_CRITERIA, "WID_BBS_DROPDOWN_CRITERIA"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_BRIDGE_LIST, "WID_BBS_BRIDGE_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_SCROLLBAR, "WID_BBS_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_CAPTION, "WID_BV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SORT_ASSENDING_DESCENDING, "WID_BV_SORT_ASSENDING_DESCENDING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SORT_DROPDOWN, "WID_BV_SORT_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_CARGO_FILTER_DROPDOWN, "WID_BV_CARGO_FILTER_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_LIST, "WID_BV_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SCROLLBAR, "WID_BV_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_PANEL, "WID_BV_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_BUILD, "WID_BV_BUILD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_BUILD_SEL, "WID_BV_BUILD_SEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_RENAME, "WID_BV_RENAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_PANEL, "WID_C_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_CAPTION, "WID_C_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_FACE, "WID_C_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_FACE_TITLE, "WID_C_FACE_TITLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INAUGURATION, "WID_C_DESC_INAUGURATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COLOUR_SCHEME, "WID_C_DESC_COLOUR_SCHEME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COLOUR_SCHEME_EXAMPLE, "WID_C_DESC_COLOUR_SCHEME_EXAMPLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_VEHICLE, "WID_C_DESC_VEHICLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_VEHICLE_COUNTS, "WID_C_DESC_VEHICLE_COUNTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COMPANY_VALUE, "WID_C_DESC_COMPANY_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INFRASTRUCTURE, "WID_C_DESC_INFRASTRUCTURE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INFRASTRUCTURE_COUNTS, "WID_C_DESC_INFRASTRUCTURE_COUNTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_DESC_OWNERS, "WID_C_SELECT_DESC_OWNERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_OWNERS, "WID_C_DESC_OWNERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_BUTTONS, "WID_C_SELECT_BUTTONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_NEW_FACE, "WID_C_NEW_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COLOUR_SCHEME, "WID_C_COLOUR_SCHEME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_PRESIDENT_NAME, "WID_C_PRESIDENT_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_NAME, "WID_C_COMPANY_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BUY_SHARE, "WID_C_BUY_SHARE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELL_SHARE, "WID_C_SELL_SHARE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_VIEW_BUILD_HQ, "WID_C_SELECT_VIEW_BUILD_HQ"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_VIEW_HQ, "WID_C_VIEW_HQ"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BUILD_HQ, "WID_C_BUILD_HQ"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_RELOCATE, "WID_C_SELECT_RELOCATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_RELOCATE_HQ, "WID_C_RELOCATE_HQ"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_VIEW_INFRASTRUCTURE, "WID_C_VIEW_INFRASTRUCTURE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_HAS_PASSWORD, "WID_C_HAS_PASSWORD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_MULTIPLAYER, "WID_C_SELECT_MULTIPLAYER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_PASSWORD, "WID_C_COMPANY_PASSWORD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_JOIN, "WID_C_COMPANY_JOIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_CAPTION, "WID_CF_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOGGLE_SIZE, "WID_CF_TOGGLE_SIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_PANEL, "WID_CF_SEL_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_CATEGORY, "WID_CF_EXPS_CATEGORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE1, "WID_CF_EXPS_PRICE1"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE2, "WID_CF_EXPS_PRICE2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE3, "WID_CF_EXPS_PRICE3"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOTAL_PANEL, "WID_CF_TOTAL_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_MAXLOAN, "WID_CF_SEL_MAXLOAN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_BALANCE_VALUE, "WID_CF_BALANCE_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_LOAN_VALUE, "WID_CF_LOAN_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_LOAN_LINE, "WID_CF_LOAN_LINE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOTAL_VALUE, "WID_CF_TOTAL_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_MAXLOAN_GAP, "WID_CF_MAXLOAN_GAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_MAXLOAN_VALUE, "WID_CF_MAXLOAN_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_BUTTONS, "WID_CF_SEL_BUTTONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_INCREASE_LOAN, "WID_CF_INCREASE_LOAN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_REPAY_LOAN, "WID_CF_REPAY_LOAN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_INFRASTRUCTURE, "WID_CF_INFRASTRUCTURE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CAPTION, "WID_SCL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_GENERAL, "WID_SCL_CLASS_GENERAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_RAIL, "WID_SCL_CLASS_RAIL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_ROAD, "WID_SCL_CLASS_ROAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_SHIP, "WID_SCL_CLASS_SHIP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_AIRCRAFT, "WID_SCL_CLASS_AIRCRAFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_SPACER_DROPDOWN, "WID_SCL_SPACER_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_PRI_COL_DROPDOWN, "WID_SCL_PRI_COL_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_SEC_COL_DROPDOWN, "WID_SCL_SEC_COL_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_MATRIX, "WID_SCL_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CAPTION, "WID_SCMF_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TOGGLE_LARGE_SMALL, "WID_SCMF_TOGGLE_LARGE_SMALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SELECT_FACE, "WID_SCMF_SELECT_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CANCEL, "WID_SCMF_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ACCEPT, "WID_SCMF_ACCEPT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_MALE, "WID_SCMF_MALE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FEMALE, "WID_SCMF_FEMALE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_MALE2, "WID_SCMF_MALE2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FEMALE2, "WID_SCMF_FEMALE2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_LOADSAVE, "WID_SCMF_SEL_LOADSAVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_MALEFEMALE, "WID_SCMF_SEL_MALEFEMALE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_PARTS, "WID_SCMF_SEL_PARTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_RANDOM_NEW_FACE, "WID_SCMF_RANDOM_NEW_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON, "WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FACE, "WID_SCMF_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LOAD, "WID_SCMF_LOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FACECODE, "WID_SCMF_FACECODE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SAVE, "WID_SCMF_SAVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT, "WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_TEXT, "WID_SCMF_TIE_EARRING_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_TEXT, "WID_SCMF_LIPS_MOUSTACHE_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_GLASSES_TEXT, "WID_SCMF_HAS_GLASSES_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_TEXT, "WID_SCMF_HAIR_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_TEXT, "WID_SCMF_EYEBROWS_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_TEXT, "WID_SCMF_EYECOLOUR_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_TEXT, "WID_SCMF_GLASSES_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_TEXT, "WID_SCMF_NOSE_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_TEXT, "WID_SCMF_CHIN_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_TEXT, "WID_SCMF_JACKET_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_TEXT, "WID_SCMF_COLLAR_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ETHNICITY_EUR, "WID_SCMF_ETHNICITY_EUR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ETHNICITY_AFR, "WID_SCMF_ETHNICITY_AFR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_MOUSTACHE_EARRING, "WID_SCMF_HAS_MOUSTACHE_EARRING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_GLASSES, "WID_SCMF_HAS_GLASSES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_L, "WID_SCMF_EYECOLOUR_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR, "WID_SCMF_EYECOLOUR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_R, "WID_SCMF_EYECOLOUR_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_L, "WID_SCMF_CHIN_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN, "WID_SCMF_CHIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_R, "WID_SCMF_CHIN_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_L, "WID_SCMF_EYEBROWS_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS, "WID_SCMF_EYEBROWS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_R, "WID_SCMF_EYEBROWS_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_L, "WID_SCMF_LIPS_MOUSTACHE_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE, "WID_SCMF_LIPS_MOUSTACHE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_R, "WID_SCMF_LIPS_MOUSTACHE_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_L, "WID_SCMF_NOSE_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE, "WID_SCMF_NOSE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_R, "WID_SCMF_NOSE_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_L, "WID_SCMF_HAIR_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR, "WID_SCMF_HAIR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_R, "WID_SCMF_HAIR_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_L, "WID_SCMF_JACKET_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET, "WID_SCMF_JACKET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_R, "WID_SCMF_JACKET_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_L, "WID_SCMF_COLLAR_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR, "WID_SCMF_COLLAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_R, "WID_SCMF_COLLAR_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_L, "WID_SCMF_TIE_EARRING_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING, "WID_SCMF_TIE_EARRING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_R, "WID_SCMF_TIE_EARRING_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_L, "WID_SCMF_GLASSES_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES, "WID_SCMF_GLASSES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_R, "WID_SCMF_GLASSES_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_CAPTION, "WID_CI_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_RAIL_DESC, "WID_CI_RAIL_DESC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_RAIL_COUNT, "WID_CI_RAIL_COUNT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_DESC, "WID_CI_ROAD_DESC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_COUNT, "WID_CI_ROAD_COUNT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_DESC, "WID_CI_WATER_DESC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_COUNT, "WID_CI_WATER_COUNT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_STATION_DESC, "WID_CI_STATION_DESC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_STATION_COUNT, "WID_CI_STATION_COUNT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TOTAL_DESC, "WID_CI_TOTAL_DESC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TOTAL, "WID_CI_TOTAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_CAPTION, "WID_BC_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_FACE, "WID_BC_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_QUESTION, "WID_BC_QUESTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_NO, "WID_BC_NO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_YES, "WID_BC_YES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BACKGROUND, "WID_C_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_DAY, "WID_SD_DAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_MONTH, "WID_SD_MONTH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_YEAR, "WID_SD_YEAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_SET_DATE, "WID_SD_SET_DATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_CAPTION, "WID_D_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL, "WID_D_SELL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_SELL_CHAIN, "WID_D_SHOW_SELL_CHAIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL_CHAIN, "WID_D_SELL_CHAIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL_ALL, "WID_D_SELL_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_AUTOREPLACE, "WID_D_AUTOREPLACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_MATRIX, "WID_D_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_V_SCROLL, "WID_D_V_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_H_SCROLL, "WID_D_SHOW_H_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_H_SCROLL, "WID_D_H_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_BUILD, "WID_D_BUILD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_CLONE, "WID_D_CLONE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_LOCATION, "WID_D_LOCATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_RENAME, "WID_D_SHOW_RENAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_RENAME, "WID_D_RENAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_VEHICLE_LIST, "WID_D_VEHICLE_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_STOP_ALL, "WID_D_STOP_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_START_ALL, "WID_D_START_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_BACKGROUND, "WID_BDD_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_X, "WID_BDD_X"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_Y, "WID_BDD_Y"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_CANAL, "WID_DT_CANAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_LOCK, "WID_DT_LOCK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_DEMOLISH, "WID_DT_DEMOLISH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_DEPOT, "WID_DT_DEPOT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_STATION, "WID_DT_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_BUOY, "WID_DT_BUOY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_RIVER, "WID_DT_RIVER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_BUILD_AQUEDUCT, "WID_DT_BUILD_AQUEDUCT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_INVALID, "WID_DT_INVALID"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_ITEMS, "WID_DM_ITEMS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_SHOW_SCROLL, "WID_DM_SHOW_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_SCROLL, "WID_DM_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_QUESTION, "WID_EP_QUESTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_NO, "WID_EP_NO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_YES, "WID_EP_YES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_CAPTION, "WID_EM_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_FACE, "WID_EM_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_MESSAGE, "WID_EM_MESSAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CAPTION, "WID_SL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SORT_BYNAME, "WID_SL_SORT_BYNAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SORT_BYDATE, "WID_SL_SORT_BYDATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_BACKGROUND, "WID_SL_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_FILE_BACKGROUND, "WID_SL_FILE_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_HOME_BUTTON, "WID_SL_HOME_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DRIVES_DIRECTORIES_LIST, "WID_SL_DRIVES_DIRECTORIES_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SCROLLBAR, "WID_SL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CONTENT_DOWNLOAD, "WID_SL_CONTENT_DOWNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SAVE_OSK_TITLE, "WID_SL_SAVE_OSK_TITLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DELETE_SELECTION, "WID_SL_DELETE_SELECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SAVE_GAME, "WID_SL_SAVE_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CONTENT_DOWNLOAD_SEL, "WID_SL_CONTENT_DOWNLOAD_SEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DETAILS, "WID_SL_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_NEWGRF_INFO, "WID_SL_NEWGRF_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_LOAD_BUTTON, "WID_SL_LOAD_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_MISSING_NEWGRFS, "WID_SL_MISSING_NEWGRFS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TEMPERATE, "WID_GL_TEMPERATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_ARCTIC, "WID_GL_ARCTIC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TROPICAL, "WID_GL_TROPICAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TOYLAND, "WID_GL_TOYLAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAPSIZE_X_PULLDOWN, "WID_GL_MAPSIZE_X_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAPSIZE_Y_PULLDOWN, "WID_GL_MAPSIZE_Y_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TOWN_PULLDOWN, "WID_GL_TOWN_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_INDUSTRY_PULLDOWN, "WID_GL_INDUSTRY_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RANDOM_EDITBOX, "WID_GL_RANDOM_EDITBOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RANDOM_BUTTON, "WID_GL_RANDOM_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_GENERATE_BUTTON, "WID_GL_GENERATE_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_DOWN, "WID_GL_START_DATE_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_TEXT, "WID_GL_START_DATE_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_UP, "WID_GL_START_DATE_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_DOWN, "WID_GL_SNOW_LEVEL_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_TEXT, "WID_GL_SNOW_LEVEL_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_UP, "WID_GL_SNOW_LEVEL_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TREE_PULLDOWN, "WID_GL_TREE_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LANDSCAPE_PULLDOWN, "WID_GL_LANDSCAPE_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_NAME_TEXT, "WID_GL_HEIGHTMAP_NAME_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_SIZE_TEXT, "WID_GL_HEIGHTMAP_SIZE_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_ROTATION_PULLDOWN, "WID_GL_HEIGHTMAP_ROTATION_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TERRAIN_PULLDOWN, "WID_GL_TERRAIN_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_PULLDOWN, "WID_GL_WATER_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RIVER_PULLDOWN, "WID_GL_RIVER_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SMOOTHNESS_PULLDOWN, "WID_GL_SMOOTHNESS_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_VARIETY_PULLDOWN, "WID_GL_VARIETY_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_BORDERS_RANDOM, "WID_GL_BORDERS_RANDOM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_NW, "WID_GL_WATER_NW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_NE, "WID_GL_WATER_NE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_SE, "WID_GL_WATER_SE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_SW, "WID_GL_WATER_SW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TEMPERATE, "WID_CS_TEMPERATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_ARCTIC, "WID_CS_ARCTIC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TROPICAL, "WID_CS_TROPICAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TOYLAND, "WID_CS_TOYLAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_EMPTY_WORLD, "WID_CS_EMPTY_WORLD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_RANDOM_WORLD, "WID_CS_RANDOM_WORLD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_MAPSIZE_X_PULLDOWN, "WID_CS_MAPSIZE_X_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_MAPSIZE_Y_PULLDOWN, "WID_CS_MAPSIZE_Y_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_DOWN, "WID_CS_START_DATE_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_TEXT, "WID_CS_START_DATE_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_UP, "WID_CS_START_DATE_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_DOWN, "WID_CS_FLAT_LAND_HEIGHT_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_TEXT, "WID_CS_FLAT_LAND_HEIGHT_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_UP, "WID_CS_FLAT_LAND_HEIGHT_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_PROGRESS_BAR, "WID_GP_PROGRESS_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_PROGRESS_TEXT, "WID_GP_PROGRESS_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_ABORT, "WID_GP_ABORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_CAPTION, "WID_GOAL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_LIST, "WID_GOAL_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_SCROLLBAR, "WID_GOAL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_CAPTION, "WID_GQ_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_QUESTION, "WID_GQ_QUESTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTONS, "WID_GQ_BUTTONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_1, "WID_GQ_BUTTON_1"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_2, "WID_GQ_BUTTON_2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_3, "WID_GQ_BUTTON_3"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_BACKGROUND, "WID_GL_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_FIRST_COMPANY, "WID_GL_FIRST_COMPANY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LAST_COMPANY, "WID_GL_LAST_COMPANY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_KEY_BUTTON, "WID_CV_KEY_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_BACKGROUND, "WID_CV_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_GRAPH, "WID_CV_GRAPH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_RESIZE, "WID_CV_RESIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_KEY, "WID_PHG_KEY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_DETAILED_PERFORMANCE, "WID_PHG_DETAILED_PERFORMANCE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_BACKGROUND, "WID_PHG_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_GRAPH, "WID_PHG_GRAPH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_RESIZE, "WID_PHG_RESIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_BACKGROUND, "WID_CPR_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_HEADER, "WID_CPR_HEADER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_GRAPH, "WID_CPR_GRAPH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_RESIZE, "WID_CPR_RESIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_FOOTER, "WID_CPR_FOOTER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_ENABLE_CARGOES, "WID_CPR_ENABLE_CARGOES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_DISABLE_CARGOES, "WID_CPR_DISABLE_CARGOES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_CARGO_FIRST, "WID_CPR_CARGO_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CL_BACKGROUND, "WID_CL_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_SCORE_FIRST, "WID_PRD_SCORE_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_SCORE_LAST, "WID_PRD_SCORE_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_COMPANY_FIRST, "WID_PRD_COMPANY_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_COMPANY_LAST, "WID_PRD_COMPANY_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_CAPTION, "WID_GL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SORT_BY_ORDER, "WID_GL_SORT_BY_ORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SORT_BY_DROPDOWN, "WID_GL_SORT_BY_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_VEHICLE, "WID_GL_LIST_VEHICLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_VEHICLE_SCROLLBAR, "WID_GL_LIST_VEHICLE_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_AVAILABLE_VEHICLES, "WID_GL_AVAILABLE_VEHICLES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MANAGE_VEHICLES_DROPDOWN, "WID_GL_MANAGE_VEHICLES_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_STOP_ALL, "WID_GL_STOP_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_ALL, "WID_GL_START_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_ALL_VEHICLES, "WID_GL_ALL_VEHICLES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_DEFAULT_VEHICLES, "WID_GL_DEFAULT_VEHICLES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_GROUP, "WID_GL_LIST_GROUP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_GROUP_SCROLLBAR, "WID_GL_LIST_GROUP_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_CREATE_GROUP, "WID_GL_CREATE_GROUP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_DELETE_GROUP, "WID_GL_DELETE_GROUP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RENAME_GROUP, "WID_GL_RENAME_GROUP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_REPLACE_PROTECTION, "WID_GL_REPLACE_PROTECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_H_BACKGROUND, "WID_H_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_MATRIX_WIDGET, "WID_DPI_MATRIX_WIDGET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_SCROLLBAR, "WID_DPI_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_INFOPANEL, "WID_DPI_INFOPANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_DISPLAY_WIDGET, "WID_DPI_DISPLAY_WIDGET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_FUND_WIDGET, "WID_DPI_FUND_WIDGET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_CAPTION, "WID_IV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_VIEWPORT, "WID_IV_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_INFO, "WID_IV_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_GOTO, "WID_IV_GOTO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_DISPLAY, "WID_IV_DISPLAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_DROPDOWN_ORDER, "WID_ID_DROPDOWN_ORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_DROPDOWN_CRITERIA, "WID_ID_DROPDOWN_CRITERIA"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_INDUSTRY_LIST, "WID_ID_INDUSTRY_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_SCROLLBAR, "WID_ID_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_CAPTION, "WID_IC_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_NOTIFY, "WID_IC_NOTIFY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_PANEL, "WID_IC_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_SCROLLBAR, "WID_IC_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_CARGO_DROPDOWN, "WID_IC_CARGO_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_IND_DROPDOWN, "WID_IC_IND_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_GENERATE_GAME, "WID_SGI_GENERATE_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_LOAD_GAME, "WID_SGI_LOAD_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_SCENARIO, "WID_SGI_PLAY_SCENARIO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_HEIGHTMAP, "WID_SGI_PLAY_HEIGHTMAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_EDIT_SCENARIO, "WID_SGI_EDIT_SCENARIO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_NETWORK, "WID_SGI_PLAY_NETWORK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TEMPERATE_LANDSCAPE, "WID_SGI_TEMPERATE_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_ARCTIC_LANDSCAPE, "WID_SGI_ARCTIC_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TROPIC_LANDSCAPE, "WID_SGI_TROPIC_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TOYLAND_LANDSCAPE, "WID_SGI_TOYLAND_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TRANSLATION_SELECTION, "WID_SGI_TRANSLATION_SELECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TRANSLATION, "WID_SGI_TRANSLATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_OPTIONS, "WID_SGI_OPTIONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_HIGHSCORE, "WID_SGI_HIGHSCORE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_SETTINGS_OPTIONS, "WID_SGI_SETTINGS_OPTIONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_GRF_SETTINGS, "WID_SGI_GRF_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_CONTENT_DOWNLOAD, "WID_SGI_CONTENT_DOWNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_AI_SETTINGS, "WID_SGI_AI_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_EXIT, "WID_SGI_EXIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CAPTION, "WID_LGL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION, "WID_LGL_SATURATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION_FIRST, "WID_LGL_SATURATION_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION_LAST, "WID_LGL_SATURATION_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES, "WID_LGL_COMPANIES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANY_FIRST, "WID_LGL_COMPANY_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANY_LAST, "WID_LGL_COMPANY_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES_ALL, "WID_LGL_COMPANIES_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES_NONE, "WID_LGL_COMPANIES_NONE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES, "WID_LGL_CARGOES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGO_FIRST, "WID_LGL_CARGO_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGO_LAST, "WID_LGL_CARGO_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES_ALL, "WID_LGL_CARGOES_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES_NONE, "WID_LGL_CARGOES_NONE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_VIEWPORT, "WID_M_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LI_BACKGROUND, "WID_LI_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BACKGROUND, "WID_TT_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_A_SCROLLING_TEXT, "WID_A_SCROLLING_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_A_WEBSITE, "WID_A_WEBSITE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_CAPTION, "WID_QS_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_TEXT, "WID_QS_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_DEFAULT, "WID_QS_DEFAULT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_CANCEL, "WID_QS_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_OK, "WID_QS_OK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_CAPTION, "WID_Q_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_TEXT, "WID_Q_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_NO, "WID_Q_NO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_YES, "WID_Q_YES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_CAPTION, "WID_TF_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_WRAPTEXT, "WID_TF_WRAPTEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_BACKGROUND, "WID_TF_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_VSCROLLBAR, "WID_TF_VSCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_HSCROLLBAR, "WID_TF_HSCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LIST_LEFT, "WID_MTS_LIST_LEFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LEFT_SCROLLBAR, "WID_MTS_LEFT_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_PLAYLIST, "WID_MTS_PLAYLIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LIST_RIGHT, "WID_MTS_LIST_RIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_RIGHT_SCROLLBAR, "WID_MTS_RIGHT_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_ALL, "WID_MTS_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_OLD, "WID_MTS_OLD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_NEW, "WID_MTS_NEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_EZY, "WID_MTS_EZY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CUSTOM1, "WID_MTS_CUSTOM1"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CUSTOM2, "WID_MTS_CUSTOM2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CLEAR, "WID_MTS_CLEAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PREV, "WID_M_PREV"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_NEXT, "WID_M_NEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_STOP, "WID_M_STOP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PLAY, "WID_M_PLAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_SLIDERS, "WID_M_SLIDERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_MUSIC_VOL, "WID_M_MUSIC_VOL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_EFFECT_VOL, "WID_M_EFFECT_VOL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_BACKGROUND, "WID_M_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK, "WID_M_TRACK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_NR, "WID_M_TRACK_NR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_TITLE, "WID_M_TRACK_TITLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_NAME, "WID_M_TRACK_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_SHUFFLE, "WID_M_SHUFFLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PROGRAMME, "WID_M_PROGRAMME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_ALL, "WID_M_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_OLD, "WID_M_OLD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_NEW, "WID_M_NEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_EZY, "WID_M_EZY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_CUSTOM1, "WID_M_CUSTOM1"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_CUSTOM2, "WID_M_CUSTOM2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_CLOSE, "WID_NC_CLOSE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_BACKGROUND, "WID_NC_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_DESTINATION, "WID_NC_DESTINATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_TEXTBOX, "WID_NC_TEXTBOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_SENDBUTTON, "WID_NC_SENDBUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCDS_BACKGROUND, "WID_NCDS_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCDS_CANCELOK, "WID_NCDS_CANCELOK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_BACKGROUND, "WID_NCL_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_FILTER_CAPT, "WID_NCL_FILTER_CAPT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_FILTER, "WID_NCL_FILTER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_CHECKBOX, "WID_NCL_CHECKBOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_TYPE, "WID_NCL_TYPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_NAME, "WID_NCL_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_MATRIX, "WID_NCL_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SCROLLBAR, "WID_NCL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_DETAILS, "WID_NCL_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_TEXTFILE, "WID_NCL_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SELECT_ALL, "WID_NCL_SELECT_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SELECT_UPDATE, "WID_NCL_SELECT_UPDATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_UNSELECT, "WID_NCL_UNSELECT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_OPEN_URL, "WID_NCL_OPEN_URL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_CANCEL, "WID_NCL_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_DOWNLOAD, "WID_NCL_DOWNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SEL_ALL_UPDATE, "WID_NCL_SEL_ALL_UPDATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SEARCH_EXTERNAL, "WID_NCL_SEARCH_EXTERNAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MAIN, "WID_NG_MAIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CONNECTION, "WID_NG_CONNECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CONN_BTN, "WID_NG_CONN_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENT_LABEL, "WID_NG_CLIENT_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENT, "WID_NG_CLIENT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FILTER_LABEL, "WID_NG_FILTER_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FILTER, "WID_NG_FILTER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_HEADER, "WID_NG_HEADER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NAME, "WID_NG_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENTS, "WID_NG_CLIENTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MAPSIZE, "WID_NG_MAPSIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DATE, "WID_NG_DATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_YEARS, "WID_NG_YEARS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_INFO, "WID_NG_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MATRIX, "WID_NG_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_SCROLLBAR, "WID_NG_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED_LABEL, "WID_NG_LASTJOINED_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED, "WID_NG_LASTJOINED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED_SPACER, "WID_NG_LASTJOINED_SPACER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DETAILS, "WID_NG_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DETAILS_SPACER, "WID_NG_DETAILS_SPACER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_JOIN, "WID_NG_JOIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_REFRESH, "WID_NG_REFRESH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF, "WID_NG_NEWGRF"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_SEL, "WID_NG_NEWGRF_SEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_MISSING, "WID_NG_NEWGRF_MISSING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_MISSING_SEL, "WID_NG_NEWGRF_MISSING_SEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FIND, "WID_NG_FIND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_ADD, "WID_NG_ADD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_START, "WID_NG_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CANCEL, "WID_NG_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_BACKGROUND, "WID_NSS_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GAMENAME_LABEL, "WID_NSS_GAMENAME_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GAMENAME, "WID_NSS_GAMENAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SETPWD, "WID_NSS_SETPWD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CONNTYPE_LABEL, "WID_NSS_CONNTYPE_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CONNTYPE_BTN, "WID_NSS_CONNTYPE_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_LABEL, "WID_NSS_CLIENTS_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_BTND, "WID_NSS_CLIENTS_BTND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_TXT, "WID_NSS_CLIENTS_TXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_BTNU, "WID_NSS_CLIENTS_BTNU"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_LABEL, "WID_NSS_COMPANIES_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_BTND, "WID_NSS_COMPANIES_BTND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_TXT, "WID_NSS_COMPANIES_TXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_BTNU, "WID_NSS_COMPANIES_BTNU"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_LABEL, "WID_NSS_SPECTATORS_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_BTND, "WID_NSS_SPECTATORS_BTND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_TXT, "WID_NSS_SPECTATORS_TXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_BTNU, "WID_NSS_SPECTATORS_BTNU"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LANGUAGE_LABEL, "WID_NSS_LANGUAGE_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LANGUAGE_BTN, "WID_NSS_LANGUAGE_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GENERATE_GAME, "WID_NSS_GENERATE_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LOAD_GAME, "WID_NSS_LOAD_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_PLAY_SCENARIO, "WID_NSS_PLAY_SCENARIO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_PLAY_HEIGHTMAP, "WID_NSS_PLAY_HEIGHTMAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CANCEL, "WID_NSS_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_BACKGROUND, "WID_NL_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_TEXT, "WID_NL_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_HEADER, "WID_NL_HEADER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_MATRIX, "WID_NL_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_SCROLLBAR, "WID_NL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_DETAILS, "WID_NL_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_JOIN, "WID_NL_JOIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_NEW, "WID_NL_NEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_SPECTATE, "WID_NL_SPECTATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_REFRESH, "WID_NL_REFRESH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_CANCEL, "WID_NL_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CL_PANEL, "WID_CL_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CLP_PANEL, "WID_CLP_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NJS_BACKGROUND, "WID_NJS_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NJS_CANCELOK, "WID_NJS_CANCELOK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_BACKGROUND, "WID_NCP_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_LABEL, "WID_NCP_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_PASSWORD, "WID_NCP_PASSWORD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_SAVE_AS_DEFAULT_PASSWORD, "WID_NCP_SAVE_AS_DEFAULT_PASSWORD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_CANCEL, "WID_NCP_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_OK, "WID_NCP_OK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_CAPTION, "WID_NGRFI_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_PARENT, "WID_NGRFI_PARENT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_PREV, "WID_NGRFI_VEH_PREV"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_NEXT, "WID_NGRFI_VEH_NEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_CHAIN, "WID_NGRFI_VEH_CHAIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_MAINPANEL, "WID_NGRFI_MAINPANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_SCROLLBAR, "WID_NGRFI_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_CAPTION, "WID_SA_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_PREVIOUS, "WID_SA_PREVIOUS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_GOTO, "WID_SA_GOTO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_NEXT, "WID_SA_NEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_UP, "WID_SA_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_LEFT, "WID_SA_LEFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_RIGHT, "WID_SA_RIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_DOWN, "WID_SA_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_SPRITE, "WID_SA_SPRITE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_OFFSETS, "WID_SA_OFFSETS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_PICKER, "WID_SA_PICKER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_LIST, "WID_SA_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_SCROLLBAR, "WID_SA_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SHOW_NUMPAR, "WID_NP_SHOW_NUMPAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_DEC, "WID_NP_NUMPAR_DEC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_INC, "WID_NP_NUMPAR_INC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR, "WID_NP_NUMPAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_TEXT, "WID_NP_NUMPAR_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_BACKGROUND, "WID_NP_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SCROLLBAR, "WID_NP_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_ACCEPT, "WID_NP_ACCEPT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_RESET, "WID_NP_RESET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SHOW_DESCRIPTION, "WID_NP_SHOW_DESCRIPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_DESCRIPTION, "WID_NP_DESCRIPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_LIST, "WID_NS_PRESET_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_SAVE, "WID_NS_PRESET_SAVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_DELETE, "WID_NS_PRESET_DELETE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_ADD, "WID_NS_ADD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_REMOVE, "WID_NS_REMOVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_MOVE_UP, "WID_NS_MOVE_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_MOVE_DOWN, "WID_NS_MOVE_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_FILTER, "WID_NS_FILTER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_FILE_LIST, "WID_NS_FILE_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SCROLLBAR, "WID_NS_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_AVAIL_LIST, "WID_NS_AVAIL_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SCROLL2BAR, "WID_NS_SCROLL2BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_INFO_TITLE, "WID_NS_NEWGRF_INFO_TITLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_INFO, "WID_NS_NEWGRF_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_OPEN_URL, "WID_NS_OPEN_URL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_TEXTFILE, "WID_NS_NEWGRF_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SET_PARAMETERS, "WID_NS_SET_PARAMETERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_VIEW_PARAMETERS, "WID_NS_VIEW_PARAMETERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_TOGGLE_PALETTE, "WID_NS_TOGGLE_PALETTE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_APPLY_CHANGES, "WID_NS_APPLY_CHANGES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_RESCAN_FILES, "WID_NS_RESCAN_FILES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_RESCAN_FILES2, "WID_NS_RESCAN_FILES2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_CONTENT_DOWNLOAD, "WID_NS_CONTENT_DOWNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_CONTENT_DOWNLOAD2, "WID_NS_CONTENT_DOWNLOAD2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SHOW_REMOVE, "WID_NS_SHOW_REMOVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SHOW_APPLY, "WID_NS_SHOW_APPLY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SP_PROGRESS_BAR, "WID_SP_PROGRESS_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SP_PROGRESS_TEXT, "WID_SP_PROGRESS_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_PANEL, "WID_N_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_TITLE, "WID_N_TITLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_HEADLINE, "WID_N_HEADLINE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_CLOSEBOX, "WID_N_CLOSEBOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_DATE, "WID_N_DATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_CAPTION, "WID_N_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_INSET, "WID_N_INSET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VIEWPORT, "WID_N_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_COMPANY_MSG, "WID_N_COMPANY_MSG"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MESSAGE, "WID_N_MESSAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MGR_FACE, "WID_N_MGR_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MGR_NAME, "WID_N_MGR_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_TITLE, "WID_N_VEH_TITLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_BKGND, "WID_N_VEH_BKGND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_NAME, "WID_N_VEH_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_SPR, "WID_N_VEH_SPR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_INFO, "WID_N_VEH_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_STICKYBOX, "WID_MH_STICKYBOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_BACKGROUND, "WID_MH_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_SCROLLBAR, "WID_MH_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_CLASS_LIST, "WID_BO_CLASS_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SCROLLBAR, "WID_BO_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_MATRIX, "WID_BO_OBJECT_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_SPRITE, "WID_BO_OBJECT_SPRITE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_NAME, "WID_BO_OBJECT_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_SIZE, "WID_BO_OBJECT_SIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_INFO, "WID_BO_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_MATRIX, "WID_BO_SELECT_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_IMAGE, "WID_BO_SELECT_IMAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_SCROLL, "WID_BO_SELECT_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_CAPTION, "WID_O_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_TIMETABLE_VIEW, "WID_O_TIMETABLE_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_ORDER_LIST, "WID_O_ORDER_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SCROLLBAR, "WID_O_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SKIP, "WID_O_SKIP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_DELETE, "WID_O_DELETE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_STOP_SHARING, "WID_O_STOP_SHARING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_NON_STOP, "WID_O_NON_STOP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_GOTO, "WID_O_GOTO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_FULL_LOAD, "WID_O_FULL_LOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_UNLOAD, "WID_O_UNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_REFIT, "WID_O_REFIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SERVICE, "WID_O_SERVICE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_EMPTY, "WID_O_EMPTY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_REFIT_DROPDOWN, "WID_O_REFIT_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_VARIABLE, "WID_O_COND_VARIABLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_COMPARATOR, "WID_O_COND_COMPARATOR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_VALUE, "WID_O_COND_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_LEFT, "WID_O_SEL_TOP_LEFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_MIDDLE, "WID_O_SEL_TOP_MIDDLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_RIGHT, "WID_O_SEL_TOP_RIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_ROW_GROUNDVEHICLE, "WID_O_SEL_TOP_ROW_GROUNDVEHICLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_ROW, "WID_O_SEL_TOP_ROW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_BOTTOM_MIDDLE, "WID_O_SEL_BOTTOM_MIDDLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SHARED_ORDER_LIST, "WID_O_SHARED_ORDER_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CAPTION, "WID_OSK_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_TEXT, "WID_OSK_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CANCEL, "WID_OSK_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_OK, "WID_OSK_OK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_BACKSPACE, "WID_OSK_BACKSPACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SPECIAL, "WID_OSK_SPECIAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CAPS, "WID_OSK_CAPS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SHIFT, "WID_OSK_SHIFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SPACE, "WID_OSK_SPACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_LEFT, "WID_OSK_LEFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_RIGHT, "WID_OSK_RIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_LETTERS, "WID_OSK_LETTERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_NUMBERS_FIRST, "WID_OSK_NUMBERS_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_NUMBERS_LAST, "WID_OSK_NUMBERS_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_QWERTY_FIRST, "WID_OSK_QWERTY_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_QWERTY_LAST, "WID_OSK_QWERTY_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ASDFG_FIRST, "WID_OSK_ASDFG_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ASDFG_LAST, "WID_OSK_ASDFG_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ZXCVB_FIRST, "WID_OSK_ZXCVB_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ZXCVB_LAST, "WID_OSK_ZXCVB_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_CAPTION, "WID_RAT_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_NS, "WID_RAT_BUILD_NS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_X, "WID_RAT_BUILD_X"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_EW, "WID_RAT_BUILD_EW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_Y, "WID_RAT_BUILD_Y"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_AUTORAIL, "WID_RAT_AUTORAIL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_DEMOLISH, "WID_RAT_DEMOLISH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_DEPOT, "WID_RAT_BUILD_DEPOT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_WAYPOINT, "WID_RAT_BUILD_WAYPOINT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_STATION, "WID_RAT_BUILD_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_SIGNALS, "WID_RAT_BUILD_SIGNALS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_BRIDGE, "WID_RAT_BUILD_BRIDGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_TUNNEL, "WID_RAT_BUILD_TUNNEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_REMOVE, "WID_RAT_REMOVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_CONVERT_RAIL, "WID_RAT_CONVERT_RAIL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DIR_X, "WID_BRAS_PLATFORM_DIR_X"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DIR_Y, "WID_BRAS_PLATFORM_DIR_Y"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_1, "WID_BRAS_PLATFORM_NUM_1"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_2, "WID_BRAS_PLATFORM_NUM_2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_3, "WID_BRAS_PLATFORM_NUM_3"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_4, "WID_BRAS_PLATFORM_NUM_4"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_5, "WID_BRAS_PLATFORM_NUM_5"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_6, "WID_BRAS_PLATFORM_NUM_6"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_7, "WID_BRAS_PLATFORM_NUM_7"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_1, "WID_BRAS_PLATFORM_LEN_1"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_2, "WID_BRAS_PLATFORM_LEN_2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_3, "WID_BRAS_PLATFORM_LEN_3"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_4, "WID_BRAS_PLATFORM_LEN_4"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_5, "WID_BRAS_PLATFORM_LEN_5"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_6, "WID_BRAS_PLATFORM_LEN_6"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_7, "WID_BRAS_PLATFORM_LEN_7"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DRAG_N_DROP, "WID_BRAS_PLATFORM_DRAG_N_DROP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_HIGHLIGHT_OFF, "WID_BRAS_HIGHLIGHT_OFF"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_HIGHLIGHT_ON, "WID_BRAS_HIGHLIGHT_ON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_COVERAGE_TEXTS, "WID_BRAS_COVERAGE_TEXTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_MATRIX, "WID_BRAS_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_IMAGE, "WID_BRAS_IMAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_MATRIX_SCROLL, "WID_BRAS_MATRIX_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_DEFSIZE, "WID_BRAS_SHOW_NEWST_DEFSIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_ADDITIONS, "WID_BRAS_SHOW_NEWST_ADDITIONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_MATRIX, "WID_BRAS_SHOW_NEWST_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_RESIZE, "WID_BRAS_SHOW_NEWST_RESIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_TYPE, "WID_BRAS_SHOW_NEWST_TYPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_NEWST_LIST, "WID_BRAS_NEWST_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_NEWST_SCROLL, "WID_BRAS_NEWST_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_BEGIN, "WID_BRAS_PLATFORM_NUM_BEGIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_BEGIN, "WID_BRAS_PLATFORM_LEN_BEGIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_NORM, "WID_BS_SEMAPHORE_NORM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_ENTRY, "WID_BS_SEMAPHORE_ENTRY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_EXIT, "WID_BS_SEMAPHORE_EXIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_COMBO, "WID_BS_SEMAPHORE_COMBO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_PBS, "WID_BS_SEMAPHORE_PBS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_PBS_OWAY, "WID_BS_SEMAPHORE_PBS_OWAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_NORM, "WID_BS_ELECTRIC_NORM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_ENTRY, "WID_BS_ELECTRIC_ENTRY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_EXIT, "WID_BS_ELECTRIC_EXIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_COMBO, "WID_BS_ELECTRIC_COMBO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_PBS, "WID_BS_ELECTRIC_PBS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_PBS_OWAY, "WID_BS_ELECTRIC_PBS_OWAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_CONVERT, "WID_BS_CONVERT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_LABEL, "WID_BS_DRAG_SIGNALS_DENSITY_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, "WID_BS_DRAG_SIGNALS_DENSITY_DECREASE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, "WID_BS_DRAG_SIGNALS_DENSITY_INCREASE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_NE, "WID_BRAD_DEPOT_NE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_SE, "WID_BRAD_DEPOT_SE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_SW, "WID_BRAD_DEPOT_SW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_NW, "WID_BRAD_DEPOT_NW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT_MATRIX, "WID_BRW_WAYPOINT_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT, "WID_BRW_WAYPOINT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_SCROLL, "WID_BRW_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_X, "WID_ROT_ROAD_X"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_Y, "WID_ROT_ROAD_Y"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_AUTOROAD, "WID_ROT_AUTOROAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_DEMOLISH, "WID_ROT_DEMOLISH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_DEPOT, "WID_ROT_DEPOT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUS_STATION, "WID_ROT_BUS_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_TRUCK_STATION, "WID_ROT_TRUCK_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ONE_WAY, "WID_ROT_ONE_WAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_BRIDGE, "WID_ROT_BUILD_BRIDGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_TUNNEL, "WID_ROT_BUILD_TUNNEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_REMOVE, "WID_ROT_REMOVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_CAPTION, "WID_BROD_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_NE, "WID_BROD_DEPOT_NE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_SE, "WID_BROD_DEPOT_SE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_SW, "WID_BROD_DEPOT_SW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_NW, "WID_BROD_DEPOT_NW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_CAPTION, "WID_BROS_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_BACKGROUND, "WID_BROS_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_NE, "WID_BROS_STATION_NE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_SE, "WID_BROS_STATION_SE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_SW, "WID_BROS_STATION_SW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_NW, "WID_BROS_STATION_NW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_X, "WID_BROS_STATION_X"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_Y, "WID_BROS_STATION_Y"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_LT_OFF, "WID_BROS_LT_OFF"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_LT_ON, "WID_BROS_LT_ON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_INFO, "WID_BROS_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BACKGROUND, "WID_GO_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_CURRENCY_DROPDOWN, "WID_GO_CURRENCY_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_DISTANCE_DROPDOWN, "WID_GO_DISTANCE_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_ROADSIDE_DROPDOWN, "WID_GO_ROADSIDE_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_TOWNNAME_DROPDOWN, "WID_GO_TOWNNAME_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_AUTOSAVE_DROPDOWN, "WID_GO_AUTOSAVE_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_LANG_DROPDOWN, "WID_GO_LANG_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_RESOLUTION_DROPDOWN, "WID_GO_RESOLUTION_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_FULLSCREEN_BUTTON, "WID_GO_FULLSCREEN_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_SCREENSHOT_DROPDOWN, "WID_GO_SCREENSHOT_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_DROPDOWN, "WID_GO_BASE_GRF_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_STATUS, "WID_GO_BASE_GRF_STATUS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_TEXTFILE, "WID_GO_BASE_GRF_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_DESCRIPTION, "WID_GO_BASE_GRF_DESCRIPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_DROPDOWN, "WID_GO_BASE_SFX_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_TEXTFILE, "WID_GO_BASE_SFX_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_DESCRIPTION, "WID_GO_BASE_SFX_DESCRIPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_DROPDOWN, "WID_GO_BASE_MUSIC_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_STATUS, "WID_GO_BASE_MUSIC_STATUS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_TEXTFILE, "WID_GO_BASE_MUSIC_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_DESCRIPTION, "WID_GO_BASE_MUSIC_DESCRIPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_FILTER, "WID_GS_FILTER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_OPTIONSPANEL, "WID_GS_OPTIONSPANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_SCROLLBAR, "WID_GS_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_HELP_TEXT, "WID_GS_HELP_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_EXPAND_ALL, "WID_GS_EXPAND_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_COLLAPSE_ALL, "WID_GS_COLLAPSE_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_CATEGORY, "WID_GS_RESTRICT_CATEGORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_TYPE, "WID_GS_RESTRICT_TYPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_DROPDOWN, "WID_GS_RESTRICT_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_TYPE_DROPDOWN, "WID_GS_TYPE_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE_DOWN, "WID_CC_RATE_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE_UP, "WID_CC_RATE_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE, "WID_CC_RATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SEPARATOR_EDIT, "WID_CC_SEPARATOR_EDIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SEPARATOR, "WID_CC_SEPARATOR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREFIX_EDIT, "WID_CC_PREFIX_EDIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREFIX, "WID_CC_PREFIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SUFFIX_EDIT, "WID_CC_SUFFIX_EDIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SUFFIX, "WID_CC_SUFFIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR_DOWN, "WID_CC_YEAR_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR_UP, "WID_CC_YEAR_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR, "WID_CC_YEAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREVIEW, "WID_CC_PREVIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_CAPTION, "WID_SIL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_LIST, "WID_SIL_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_SCROLLBAR, "WID_SIL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_TEXT, "WID_SIL_FILTER_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_MATCH_CASE_BTN, "WID_SIL_FILTER_MATCH_CASE_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_ENTER_BTN, "WID_SIL_FILTER_ENTER_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_CAPTION, "WID_QES_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_TEXT, "WID_QES_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_OK, "WID_QES_OK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_CANCEL, "WID_QES_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_DELETE, "WID_QES_DELETE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_PREVIOUS, "WID_QES_PREVIOUS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_NEXT, "WID_QES_NEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CAPTION, "WID_SM_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_MAP_BORDER, "WID_SM_MAP_BORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_MAP, "WID_SM_MAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_LEGEND, "WID_SM_LEGEND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_BLANK, "WID_SM_BLANK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ZOOM_IN, "WID_SM_ZOOM_IN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ZOOM_OUT, "WID_SM_ZOOM_OUT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CONTOUR, "WID_SM_CONTOUR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_VEHICLES, "WID_SM_VEHICLES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_INDUSTRIES, "WID_SM_INDUSTRIES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_LINKSTATS, "WID_SM_LINKSTATS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ROUTES, "WID_SM_ROUTES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_VEGETATION, "WID_SM_VEGETATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_OWNERS, "WID_SM_OWNERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CENTERMAP, "WID_SM_CENTERMAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_TOGGLETOWNNAME, "WID_SM_TOGGLETOWNNAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_SELECT_BUTTONS, "WID_SM_SELECT_BUTTONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ENABLE_ALL, "WID_SM_ENABLE_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_DISABLE_ALL, "WID_SM_DISABLE_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_SHOW_HEIGHT, "WID_SM_SHOW_HEIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_CAPTION, "WID_SV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SORT_ORDER, "WID_SV_SORT_ORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SORT_BY, "WID_SV_SORT_BY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_GROUP, "WID_SV_GROUP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_GROUP_BY, "WID_SV_GROUP_BY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_WAITING, "WID_SV_WAITING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SCROLLBAR, "WID_SV_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ACCEPT_RATING_LIST, "WID_SV_ACCEPT_RATING_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_LOCATION, "WID_SV_LOCATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ACCEPTS_RATINGS, "WID_SV_ACCEPTS_RATINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_RENAME, "WID_SV_RENAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_CLOSE_AIRPORT, "WID_SV_CLOSE_AIRPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_TRAINS, "WID_SV_TRAINS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ROADVEHS, "WID_SV_ROADVEHS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SHIPS, "WID_SV_SHIPS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_PLANES, "WID_SV_PLANES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CAPTION, "WID_STL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_LIST, "WID_STL_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SCROLLBAR, "WID_STL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_TRAIN, "WID_STL_TRAIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_TRUCK, "WID_STL_TRUCK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_BUS, "WID_STL_BUS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_AIRPLANE, "WID_STL_AIRPLANE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SHIP, "WID_STL_SHIP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_FACILALL, "WID_STL_FACILALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_NOCARGOWAITING, "WID_STL_NOCARGOWAITING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CARGOALL, "WID_STL_CARGOALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SORTBY, "WID_STL_SORTBY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SORTDROPBTN, "WID_STL_SORTDROPBTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CARGOSTART, "WID_STL_CARGOSTART"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_CAPTION, "WID_JS_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_PANEL, "WID_JS_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_SCROLLBAR, "WID_JS_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_LEFT, "WID_S_LEFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_MIDDLE, "WID_S_MIDDLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_RIGHT, "WID_S_RIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_CAPTION, "WID_SB_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_SEL_PAGE, "WID_SB_SEL_PAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_PAGE_PANEL, "WID_SB_PAGE_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_SCROLLBAR, "WID_SB_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_PREV_PAGE, "WID_SB_PREV_PAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_NEXT_PAGE, "WID_SB_NEXT_PAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SUL_PANEL, "WID_SUL_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SUL_SCROLLBAR, "WID_SUL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SHOW_PLACE_OBJECT, "WID_TT_SHOW_PLACE_OBJECT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUTTONS_START, "WID_TT_BUTTONS_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LOWER_LAND, "WID_TT_LOWER_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_RAISE_LAND, "WID_TT_RAISE_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LEVEL_LAND, "WID_TT_LEVEL_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_DEMOLISH, "WID_TT_DEMOLISH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUY_LAND, "WID_TT_BUY_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLANT_TREES, "WID_TT_PLANT_TREES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLACE_SIGN, "WID_TT_PLACE_SIGN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLACE_OBJECT, "WID_TT_PLACE_OBJECT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_SHOW_PLACE_DESERT, "WID_ETT_SHOW_PLACE_DESERT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_START, "WID_ETT_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DOTS, "WID_ETT_DOTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_BUTTONS_START, "WID_ETT_BUTTONS_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DEMOLISH, "WID_ETT_DEMOLISH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_LOWER_LAND, "WID_ETT_LOWER_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_RAISE_LAND, "WID_ETT_RAISE_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_LEVEL_LAND, "WID_ETT_LEVEL_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_ROCKS, "WID_ETT_PLACE_ROCKS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_DESERT, "WID_ETT_PLACE_DESERT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_OBJECT, "WID_ETT_PLACE_OBJECT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_BUTTONS_END, "WID_ETT_BUTTONS_END"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_INCREASE_SIZE, "WID_ETT_INCREASE_SIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DECREASE_SIZE, "WID_ETT_DECREASE_SIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_NEW_SCENARIO, "WID_ETT_NEW_SCENARIO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_RESET_LANDSCAPE, "WID_ETT_RESET_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CAPTION, "WID_VT_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ORDER_VIEW, "WID_VT_ORDER_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_TIMETABLE_PANEL, "WID_VT_TIMETABLE_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ARRIVAL_DEPARTURE_PANEL, "WID_VT_ARRIVAL_DEPARTURE_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SCROLLBAR, "WID_VT_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SUMMARY_PANEL, "WID_VT_SUMMARY_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_START_DATE, "WID_VT_START_DATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CHANGE_TIME, "WID_VT_CHANGE_TIME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CLEAR_TIME, "WID_VT_CLEAR_TIME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_RESET_LATENESS, "WID_VT_RESET_LATENESS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_AUTOFILL, "WID_VT_AUTOFILL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_EXPECTED, "WID_VT_EXPECTED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SHARED_ORDER_LIST, "WID_VT_SHARED_ORDER_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ARRIVAL_DEPARTURE_SELECTION, "WID_VT_ARRIVAL_DEPARTURE_SELECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_EXPECTED_SELECTION, "WID_VT_EXPECTED_SELECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CHANGE_SPEED, "WID_VT_CHANGE_SPEED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CLEAR_SPEED, "WID_VT_CLEAR_SPEED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_PAUSE, "WID_TN_PAUSE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_FAST_FORWARD, "WID_TN_FAST_FORWARD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SETTINGS, "WID_TN_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SAVE, "WID_TN_SAVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SMALL_MAP, "WID_TN_SMALL_MAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_TOWNS, "WID_TN_TOWNS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SUBSIDIES, "WID_TN_SUBSIDIES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_STATIONS, "WID_TN_STATIONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_FINANCES, "WID_TN_FINANCES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_COMPANIES, "WID_TN_COMPANIES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_STORY, "WID_TN_STORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_GOAL, "WID_TN_GOAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_GRAPHS, "WID_TN_GRAPHS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_LEAGUE, "WID_TN_LEAGUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_INDUSTRIES, "WID_TN_INDUSTRIES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_VEHICLE_START, "WID_TN_VEHICLE_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_TRAINS, "WID_TN_TRAINS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ROADVEHS, "WID_TN_ROADVEHS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SHIPS, "WID_TN_SHIPS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_AIRCRAFTS, "WID_TN_AIRCRAFTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ZOOM_IN, "WID_TN_ZOOM_IN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ZOOM_OUT, "WID_TN_ZOOM_OUT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_RAILS, "WID_TN_RAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ROADS, "WID_TN_ROADS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_WATER, "WID_TN_WATER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_AIR, "WID_TN_AIR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_LANDSCAPE, "WID_TN_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_MUSIC_SOUND, "WID_TN_MUSIC_SOUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_MESSAGES, "WID_TN_MESSAGES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_HELP, "WID_TN_HELP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SWITCH_BAR, "WID_TN_SWITCH_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_END, "WID_TN_END"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_PAUSE, "WID_TE_PAUSE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_FAST_FORWARD, "WID_TE_FAST_FORWARD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SETTINGS, "WID_TE_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SAVE, "WID_TE_SAVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SPACER, "WID_TE_SPACER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE, "WID_TE_DATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_BACKWARD, "WID_TE_DATE_BACKWARD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_FORWARD, "WID_TE_DATE_FORWARD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SMALL_MAP, "WID_TE_SMALL_MAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ZOOM_IN, "WID_TE_ZOOM_IN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ZOOM_OUT, "WID_TE_ZOOM_OUT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_LAND_GENERATE, "WID_TE_LAND_GENERATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TOWN_GENERATE, "WID_TE_TOWN_GENERATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_INDUSTRY, "WID_TE_INDUSTRY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ROADS, "WID_TE_ROADS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_WATER, "WID_TE_WATER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TREES, "WID_TE_TREES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SIGNS, "WID_TE_SIGNS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_PANEL, "WID_TE_DATE_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_MUSIC_SOUND, "WID_TE_MUSIC_SOUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_HELP, "WID_TE_HELP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SWITCH_BAR, "WID_TE_SWITCH_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_ORDER, "WID_TD_SORT_ORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_CRITERIA, "WID_TD_SORT_CRITERIA"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_LIST, "WID_TD_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SCROLLBAR, "WID_TD_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_WORLD_POPULATION, "WID_TD_WORLD_POPULATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_CAPTION, "WID_TA_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_RATING_INFO, "WID_TA_RATING_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_COMMAND_LIST, "WID_TA_COMMAND_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_SCROLLBAR, "WID_TA_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_ACTION_INFO, "WID_TA_ACTION_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_EXECUTE, "WID_TA_EXECUTE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CAPTION, "WID_TV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_VIEWPORT, "WID_TV_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_INFO, "WID_TV_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CENTER_VIEW, "WID_TV_CENTER_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_SHOW_AUTHORITY, "WID_TV_SHOW_AUTHORITY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CHANGE_NAME, "WID_TV_CHANGE_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_EXPAND, "WID_TV_EXPAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_DELETE, "WID_TV_DELETE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_NEW_TOWN, "WID_TF_NEW_TOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_RANDOM_TOWN, "WID_TF_RANDOM_TOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_MANY_RANDOM_TOWNS, "WID_TF_MANY_RANDOM_TOWNS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_TOWN_NAME_EDITBOX, "WID_TF_TOWN_NAME_EDITBOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_TOWN_NAME_RANDOM, "WID_TF_TOWN_NAME_RANDOM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_SMALL, "WID_TF_SIZE_SMALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_MEDIUM, "WID_TF_SIZE_MEDIUM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_LARGE, "WID_TF_SIZE_LARGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_RANDOM, "WID_TF_SIZE_RANDOM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_CITY, "WID_TF_CITY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_ORIGINAL, "WID_TF_LAYOUT_ORIGINAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_BETTER, "WID_TF_LAYOUT_BETTER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_GRID2, "WID_TF_LAYOUT_GRID2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_GRID3, "WID_TF_LAYOUT_GRID3"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_RANDOM, "WID_TF_LAYOUT_RANDOM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BEGIN, "WID_TT_BEGIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SIGNS, "WID_TT_SIGNS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_TREES, "WID_TT_TREES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_HOUSES, "WID_TT_HOUSES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_INDUSTRIES, "WID_TT_INDUSTRIES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUILDINGS, "WID_TT_BUILDINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BRIDGES, "WID_TT_BRIDGES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_STRUCTURES, "WID_TT_STRUCTURES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_CATENARY, "WID_TT_CATENARY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LOADING, "WID_TT_LOADING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_END, "WID_TT_END"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUTTONS, "WID_TT_BUTTONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_11, "WID_BT_TYPE_11"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_12, "WID_BT_TYPE_12"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_13, "WID_BT_TYPE_13"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_14, "WID_BT_TYPE_14"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_21, "WID_BT_TYPE_21"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_22, "WID_BT_TYPE_22"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_23, "WID_BT_TYPE_23"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_24, "WID_BT_TYPE_24"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_31, "WID_BT_TYPE_31"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_32, "WID_BT_TYPE_32"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_33, "WID_BT_TYPE_33"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_34, "WID_BT_TYPE_34"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_RANDOM, "WID_BT_TYPE_RANDOM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_MANY_RANDOM, "WID_BT_MANY_RANDOM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CAPTION, "WID_VV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_VIEWPORT, "WID_VV_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_START_STOP, "WID_VV_START_STOP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CENTER_MAIN_VIEW, "WID_VV_CENTER_MAIN_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_GOTO_DEPOT, "WID_VV_GOTO_DEPOT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_REFIT, "WID_VV_REFIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SHOW_ORDERS, "WID_VV_SHOW_ORDERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SHOW_DETAILS, "WID_VV_SHOW_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CLONE, "WID_VV_CLONE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SELECT_DEPOT_CLONE, "WID_VV_SELECT_DEPOT_CLONE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SELECT_REFIT_TURN, "WID_VV_SELECT_REFIT_TURN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_TURN_AROUND, "WID_VV_TURN_AROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_FORCE_PROCEED, "WID_VV_FORCE_PROCEED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_CAPTION, "WID_VR_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_VEHICLE_PANEL_DISPLAY, "WID_VR_VEHICLE_PANEL_DISPLAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SHOW_HSCROLLBAR, "WID_VR_SHOW_HSCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_HSCROLLBAR, "WID_VR_HSCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SELECT_HEADER, "WID_VR_SELECT_HEADER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_MATRIX, "WID_VR_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SCROLLBAR, "WID_VR_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_INFO, "WID_VR_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_REFIT, "WID_VR_REFIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_CAPTION, "WID_VD_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_RENAME_VEHICLE, "WID_VD_RENAME_VEHICLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_TOP_DETAILS, "WID_VD_TOP_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_INCREASE_SERVICING_INTERVAL, "WID_VD_INCREASE_SERVICING_INTERVAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DECREASE_SERVICING_INTERVAL, "WID_VD_DECREASE_SERVICING_INTERVAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SERVICE_INTERVAL_DROPDOWN, "WID_VD_SERVICE_INTERVAL_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SERVICING_INTERVAL, "WID_VD_SERVICING_INTERVAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_MIDDLE_DETAILS, "WID_VD_MIDDLE_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_MATRIX, "WID_VD_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SCROLLBAR, "WID_VD_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_CARGO_CARRIED, "WID_VD_DETAILS_CARGO_CARRIED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_TRAIN_VEHICLES, "WID_VD_DETAILS_TRAIN_VEHICLES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_CAPACITY_OF_EACH, "WID_VD_DETAILS_CAPACITY_OF_EACH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_TOTAL_CARGO, "WID_VD_DETAILS_TOTAL_CARGO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_CAPTION, "WID_VL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SORT_ORDER, "WID_VL_SORT_ORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SORT_BY_PULLDOWN, "WID_VL_SORT_BY_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_LIST, "WID_VL_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SCROLLBAR, "WID_VL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_HIDE_BUTTONS, "WID_VL_HIDE_BUTTONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_AVAILABLE_VEHICLES, "WID_VL_AVAILABLE_VEHICLES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_MANAGE_VEHICLES_DROPDOWN, "WID_VL_MANAGE_VEHICLES_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_STOP_ALL, "WID_VL_STOP_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_START_ALL, "WID_VL_START_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_CAPTION, "WID_EV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_VIEWPORT, "WID_EV_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_ZOOM_IN, "WID_EV_ZOOM_IN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_ZOOM_OUT, "WID_EV_ZOOM_OUT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_MAIN_TO_VIEW, "WID_EV_MAIN_TO_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_VIEW_TO_MAIN, "WID_EV_VIEW_TO_MAIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_CAPTION, "WID_W_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_VIEWPORT, "WID_W_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_CENTER_VIEW, "WID_W_CENTER_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_RENAME, "WID_W_RENAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_SHOW_VEHICLES, "WID_W_SHOW_VEHICLES"); - - SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::Close, "Close", 3, ".ii"); - SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::IsOpen, "IsOpen", 3, ".ii"); - SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::Highlight, "Highlight", 5, ".iiii"); - - SQGSWindow.PostRegister(engine); -} diff --git a/src/script/api/script_window.hpp.orig b/src/script/api/script_window.hpp.orig deleted file mode 100644 index f8bb2a3e42..0000000000 --- a/src/script/api/script_window.hpp.orig +++ /dev/null @@ -1,2579 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file script_window.hpp Everything to handle window interaction. */ - -#ifndef SCRIPT_WINDOW_HPP -#define SCRIPT_WINDOW_HPP - -#include "script_object.hpp" -#include "../../window_type.h" -#include "../../gfx_type.h" - -#include "../../widgets/ai_widget.h" -#include "../../widgets/airport_widget.h" -#include "../../widgets/autoreplace_widget.h" -#include "../../widgets/bootstrap_widget.h" -#include "../../widgets/bridge_widget.h" -#include "../../widgets/build_vehicle_widget.h" -#include "../../widgets/cheat_widget.h" -#include "../../widgets/company_widget.h" -#include "../../widgets/console_widget.h" -#include "../../widgets/date_widget.h" -#include "../../widgets/depot_widget.h" -#include "../../widgets/dock_widget.h" -#include "../../widgets/dropdown_widget.h" -#include "../../widgets/engine_widget.h" -#include "../../widgets/error_widget.h" -#include "../../widgets/fios_widget.h" -#include "../../widgets/genworld_widget.h" -#include "../../widgets/goal_widget.h" -#include "../../widgets/graph_widget.h" -#include "../../widgets/group_widget.h" -#include "../../widgets/highscore_widget.h" -#include "../../widgets/industry_widget.h" -#include "../../widgets/intro_widget.h" -#include "../../widgets/main_widget.h" -#include "../../widgets/misc_widget.h" -#include "../../widgets/music_widget.h" -#include "../../widgets/network_chat_widget.h" -#include "../../widgets/network_content_widget.h" -#include "../../widgets/network_widget.h" -#include "../../widgets/newgrf_debug_widget.h" -#include "../../widgets/newgrf_widget.h" -#include "../../widgets/news_widget.h" -#include "../../widgets/object_widget.h" -#include "../../widgets/order_widget.h" -#include "../../widgets/osk_widget.h" -#include "../../widgets/rail_widget.h" -#include "../../widgets/road_widget.h" -#include "../../widgets/settings_widget.h" -#include "../../widgets/sign_widget.h" -#include "../../widgets/smallmap_widget.h" -#include "../../widgets/station_widget.h" -#include "../../widgets/statusbar_widget.h" -#include "../../widgets/subsidy_widget.h" -#include "../../widgets/terraform_widget.h" -#include "../../widgets/timetable_widget.h" -#include "../../widgets/toolbar_widget.h" -#include "../../widgets/town_widget.h" -#include "../../widgets/transparency_widget.h" -#include "../../widgets/tree_widget.h" -#include "../../widgets/vehicle_widget.h" -#include "../../widgets/viewport_widget.h" -#include "../../widgets/waypoint_widget.h" -#include "../../widgets/link_graph_legend_widget.h" -#include "../../widgets/story_widget.h" - -/** - * Class that handles window interaction. A Window in OpenTTD has two imporant - * values. The WindowClass, and a Window number. The first indicates roughly - * which window it is. WC_TOWN_VIEW for example, is the view of a town. - * The Window number is a bit more complex, as it depends mostly on the - * WindowClass. For example for WC_TOWN_VIEW it is the TownID. In general a - * good rule of thumb is: either the number is always 0, or the ID of the - * object in question. - * In the comment at the widget enum, it is mentioned how the number is used. - * - * Note, that the detailed window layout is very version specific. - * Enum values might be added, changed or removed in future versions without notice - * in the changelog, and there won't be any means of compatibility. - * - * @api game - */ -class ScriptWindow : public ScriptObject { -public: - // @enum WindowNumberEnum ../../window_type.h - /* automatically generated from ../../window_type.h */ - /** %Window numbers. */ - enum WindowNumberEnum { - WN_GAME_OPTIONS_AI = ::WN_GAME_OPTIONS_AI, ///< AI settings. - WN_GAME_OPTIONS_ABOUT = ::WN_GAME_OPTIONS_ABOUT, ///< About window. - WN_GAME_OPTIONS_NEWGRF_STATE = ::WN_GAME_OPTIONS_NEWGRF_STATE, ///< NewGRF settings. - WN_GAME_OPTIONS_GAME_OPTIONS = ::WN_GAME_OPTIONS_GAME_OPTIONS, ///< Game options. - WN_GAME_OPTIONS_GAME_SETTINGS = ::WN_GAME_OPTIONS_GAME_SETTINGS, ///< Game settings. - - WN_QUERY_STRING = ::WN_QUERY_STRING, ///< Query string. - WN_QUERY_STRING_SIGN = ::WN_QUERY_STRING_SIGN, ///< Query string for signs. - - WN_CONFIRM_POPUP_QUERY = ::WN_CONFIRM_POPUP_QUERY, ///< Query popup confirm. - WN_CONFIRM_POPUP_QUERY_BOOTSTRAP = ::WN_CONFIRM_POPUP_QUERY_BOOTSTRAP, ///< Query popup confirm for bootstrap. - - WN_NETWORK_WINDOW_GAME = ::WN_NETWORK_WINDOW_GAME, ///< Network game window. - WN_NETWORK_WINDOW_LOBBY = ::WN_NETWORK_WINDOW_LOBBY, ///< Network lobby window. - WN_NETWORK_WINDOW_CONTENT_LIST = ::WN_NETWORK_WINDOW_CONTENT_LIST, ///< Network content list. - WN_NETWORK_WINDOW_START = ::WN_NETWORK_WINDOW_START, ///< Network start server. - - WN_NETWORK_STATUS_WINDOW_JOIN = ::WN_NETWORK_STATUS_WINDOW_JOIN, ///< Network join status. - WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD = ::WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD, ///< Network content download status. - }; - - // @endenum - - // @enum WindowClass ../../window_type.h - /* automatically generated from ../../window_type.h */ - /** %Window classes. */ - enum WindowClass { - WC_NONE = ::WC_NONE, ///< No window, redirects to WC_MAIN_WINDOW. - - /** - * Main window; %Window numbers: - * - 0 = #MainWidgets - */ - WC_MAIN_WINDOW = ::WC_MAIN_WINDOW, - - /** - * Main toolbar (the long bar at the top); %Window numbers: - * - 0 = #ToolbarNormalWidgets - * - 0 = #ToolbarEditorWidgets - */ - WC_MAIN_TOOLBAR = ::WC_MAIN_TOOLBAR, - - /** - * Statusbar (at the bottom of your screen); %Window numbers: - * - 0 = #StatusbarWidgets - */ - WC_STATUS_BAR = ::WC_STATUS_BAR, - - /** - * Build toolbar; %Window numbers: - * - #TRANSPORT_RAIL = #RailToolbarWidgets - * - #TRANSPORT_AIR = #AirportToolbarWidgets - * - #TRANSPORT_WATER = #DockToolbarWidgets - * - #TRANSPORT_ROAD = #RoadToolbarWidgets - */ - WC_BUILD_TOOLBAR = ::WC_BUILD_TOOLBAR, - - /** - * Scenario build toolbar; %Window numbers: - * - #TRANSPORT_WATER = #DockToolbarWidgets - * - #TRANSPORT_ROAD = #RoadToolbarWidgets - */ - WC_SCEN_BUILD_TOOLBAR = ::WC_SCEN_BUILD_TOOLBAR, - - /** - * Build trees toolbar; %Window numbers: - * - 0 = #BuildTreesWidgets - */ - WC_BUILD_TREES = ::WC_BUILD_TREES, - - /** - * Transparency toolbar; %Window numbers: - * - 0 = #TransparencyToolbarWidgets - */ - WC_TRANSPARENCY_TOOLBAR = ::WC_TRANSPARENCY_TOOLBAR, - - /** - * Build signal toolbar; %Window numbers: - * - #TRANSPORT_RAIL = #BuildSignalWidgets - */ - WC_BUILD_SIGNAL = ::WC_BUILD_SIGNAL, - - /** - * Small map; %Window numbers: - * - 0 = #SmallMapWidgets - */ - WC_SMALLMAP = ::WC_SMALLMAP, - - /** - * Error message; %Window numbers: - * - 0 = #ErrorMessageWidgets - */ - WC_ERRMSG = ::WC_ERRMSG, - - /** - * Tooltip window; %Window numbers: - * - 0 = #ToolTipsWidgets - */ - WC_TOOLTIPS = ::WC_TOOLTIPS, - - /** - * Query string window; %Window numbers: - * - #WN_QUERY_STRING = #QueryStringWidgets - * - #WN_QUERY_STRING_SIGN = #QueryEditSignWidgets - */ - WC_QUERY_STRING = ::WC_QUERY_STRING, - - /** - * Popup with confirm question; %Window numbers: - * - #WN_CONFIRM_POPUP_QUERY = #QueryWidgets - * - #WN_CONFIRM_POPUP_QUERY_BOOTSTRAP = #BootstrapAskForDownloadWidgets - */ - WC_CONFIRM_POPUP_QUERY = ::WC_CONFIRM_POPUP_QUERY, - - /** - * Popup with a set of buttons, designed to ask the user a question - * from a GameScript. %Window numbers: - * - uniqueid = #GoalQuestionWidgets - */ - WC_GOAL_QUESTION = ::WC_GOAL_QUESTION, - - - /** - * Saveload window; %Window numbers: - * - 0 = #SaveLoadWidgets - */ - WC_SAVELOAD = ::WC_SAVELOAD, - - /** - * Land info window; %Window numbers: - * - 0 = #LandInfoWidgets - */ - WC_LAND_INFO = ::WC_LAND_INFO, - - /** - * Drop down menu; %Window numbers: - * - 0 = #DropdownMenuWidgets - */ - WC_DROPDOWN_MENU = ::WC_DROPDOWN_MENU, - - /** - * On Screen Keyboard; %Window numbers: - * - 0 = #OnScreenKeyboardWidgets - */ - WC_OSK = ::WC_OSK, - - /** - * Set date; %Window numbers: - * - #VehicleID = #SetDateWidgets - */ - WC_SET_DATE = ::WC_SET_DATE, - - - /** - * AI settings; %Window numbers: - * - 0 = #AISettingsWidgets - */ - WC_AI_SETTINGS = ::WC_AI_SETTINGS, - - /** - * NewGRF parameters; %Window numbers: - * - 0 = #NewGRFParametersWidgets - */ - WC_GRF_PARAMETERS = ::WC_GRF_PARAMETERS, - - /** - * textfile; %Window numbers: - * - 0 = #TextfileWidgets - */ - WC_TEXTFILE = ::WC_TEXTFILE, - - - /** - * Town authority; %Window numbers: - * - #TownID = #TownAuthorityWidgets - */ - WC_TOWN_AUTHORITY = ::WC_TOWN_AUTHORITY, - - /** - * Vehicle details; %Window numbers: - * - #VehicleID = #VehicleDetailsWidgets - */ - WC_VEHICLE_DETAILS = ::WC_VEHICLE_DETAILS, - - /** - * Vehicle refit; %Window numbers: - * - #VehicleID = #VehicleRefitWidgets - */ - WC_VEHICLE_REFIT = ::WC_VEHICLE_REFIT, - - /** - * Vehicle orders; %Window numbers: - * - #VehicleID = #OrderWidgets - */ - WC_VEHICLE_ORDERS = ::WC_VEHICLE_ORDERS, - - /** - * Replace vehicle window; %Window numbers: - * - #VehicleType = #ReplaceVehicleWidgets - */ - WC_REPLACE_VEHICLE = ::WC_REPLACE_VEHICLE, - - /** - * Vehicle timetable; %Window numbers: - * - #VehicleID = #VehicleTimetableWidgets - */ - WC_VEHICLE_TIMETABLE = ::WC_VEHICLE_TIMETABLE, - - /** - * Company colour selection; %Window numbers: - * - #CompanyID = #SelectCompanyLiveryWidgets - */ - WC_COMPANY_COLOUR = ::WC_COMPANY_COLOUR, - - /** - * Alter company face window; %Window numbers: - * - #CompanyID = #SelectCompanyManagerFaceWidgets - */ - WC_COMPANY_MANAGER_FACE = ::WC_COMPANY_MANAGER_FACE, - - /** - * Select station (when joining stations); %Window numbers: - * - 0 = #JoinStationWidgets - */ - WC_SELECT_STATION = ::WC_SELECT_STATION, - - /** - * News window; %Window numbers: - * - 0 = #NewsWidgets - */ - WC_NEWS_WINDOW = ::WC_NEWS_WINDOW, - - /** - * Town directory; %Window numbers: - * - 0 = #TownDirectoryWidgets - */ - WC_TOWN_DIRECTORY = ::WC_TOWN_DIRECTORY, - - /** - * Subsidies list; %Window numbers: - * - 0 = #SubsidyListWidgets - */ - WC_SUBSIDIES_LIST = ::WC_SUBSIDIES_LIST, - - /** - * Industry directory; %Window numbers: - * - 0 = #IndustryDirectoryWidgets - */ - WC_INDUSTRY_DIRECTORY = ::WC_INDUSTRY_DIRECTORY, - - /** - * News history list; %Window numbers: - * - 0 = #MessageHistoryWidgets - */ - WC_MESSAGE_HISTORY = ::WC_MESSAGE_HISTORY, - - /** - * Sign list; %Window numbers: - * - 0 = #SignListWidgets - */ - WC_SIGN_LIST = ::WC_SIGN_LIST, - - /** - * AI list; %Window numbers: - * - 0 = #AIListWidgets - */ - WC_AI_LIST = ::WC_AI_LIST, - - /** - * Goals list; %Window numbers: - * - 0 ; #GoalListWidgets - */ - WC_GOALS_LIST = ::WC_GOALS_LIST, - - /** - * Story book; %Window numbers: - * - CompanyID = #StoryBookWidgets - */ - WC_STORY_BOOK = ::WC_STORY_BOOK, - - /** - * Station list; %Window numbers: - * - #CompanyID = #StationListWidgets - */ - WC_STATION_LIST = ::WC_STATION_LIST, - - /** - * Trains list; %Window numbers: - * - Packed value = #GroupListWidgets / #VehicleListWidgets - */ - WC_TRAINS_LIST = ::WC_TRAINS_LIST, - - /** - * Road vehicle list; %Window numbers: - * - Packed value = #GroupListWidgets / #VehicleListWidgets - */ - WC_ROADVEH_LIST = ::WC_ROADVEH_LIST, - - /** - * Ships list; %Window numbers: - * - Packed value = #GroupListWidgets / #VehicleListWidgets - */ - WC_SHIPS_LIST = ::WC_SHIPS_LIST, - - /** - * Aircraft list; %Window numbers: - * - Packed value = #GroupListWidgets / #VehicleListWidgets - */ - WC_AIRCRAFT_LIST = ::WC_AIRCRAFT_LIST, - - - /** - * Town view; %Window numbers: - * - #TownID = #TownViewWidgets - */ - WC_TOWN_VIEW = ::WC_TOWN_VIEW, - - /** - * Vehicle view; %Window numbers: - * - #VehicleID = #VehicleViewWidgets - */ - WC_VEHICLE_VIEW = ::WC_VEHICLE_VIEW, - - /** - * Station view; %Window numbers: - * - #StationID = #StationViewWidgets - */ - WC_STATION_VIEW = ::WC_STATION_VIEW, - - /** - * Depot view; %Window numbers: - * - #TileIndex = #DepotWidgets - */ - WC_VEHICLE_DEPOT = ::WC_VEHICLE_DEPOT, - - /** - * Waypoint view; %Window numbers: - * - #WaypointID = #WaypointWidgets - */ - WC_WAYPOINT_VIEW = ::WC_WAYPOINT_VIEW, - - /** - * Industry view; %Window numbers: - * - #IndustryID = #IndustryViewWidgets - */ - WC_INDUSTRY_VIEW = ::WC_INDUSTRY_VIEW, - - /** - * Company view; %Window numbers: - * - #CompanyID = #CompanyWidgets - */ - WC_COMPANY = ::WC_COMPANY, - - - /** - * Build object; %Window numbers: - * - 0 = #BuildObjectWidgets - */ - WC_BUILD_OBJECT = ::WC_BUILD_OBJECT, - - /** - * Build vehicle; %Window numbers: - * - #VehicleType = #BuildVehicleWidgets - * - #TileIndex = #BuildVehicleWidgets - */ - WC_BUILD_VEHICLE = ::WC_BUILD_VEHICLE, - - /** - * Build bridge; %Window numbers: - * - #TransportType = #BuildBridgeSelectionWidgets - */ - WC_BUILD_BRIDGE = ::WC_BUILD_BRIDGE, - - /** - * Build station; %Window numbers: - * - #TRANSPORT_AIR = #AirportPickerWidgets - * - #TRANSPORT_WATER = #DockToolbarWidgets - * - #TRANSPORT_RAIL = #BuildRailStationWidgets - */ - WC_BUILD_STATION = ::WC_BUILD_STATION, - - /** - * Build bus station; %Window numbers: - * - #TRANSPORT_ROAD = #BuildRoadStationWidgets - */ - WC_BUS_STATION = ::WC_BUS_STATION, - - /** - * Build truck station; %Window numbers: - * - #TRANSPORT_ROAD = #BuildRoadStationWidgets - */ - WC_TRUCK_STATION = ::WC_TRUCK_STATION, - - /** - * Build depot; %Window numbers: - * - #TRANSPORT_WATER = #BuildDockDepotWidgets - * - #TRANSPORT_RAIL = #BuildRailDepotWidgets - * - #TRANSPORT_ROAD = #BuildRoadDepotWidgets - */ - WC_BUILD_DEPOT = ::WC_BUILD_DEPOT, - - /** - * Build waypoint; %Window numbers: - * - #TRANSPORT_RAIL = #BuildRailWaypointWidgets - */ - WC_BUILD_WAYPOINT = ::WC_BUILD_WAYPOINT, - - /** - * Found a town; %Window numbers: - * - 0 = #TownFoundingWidgets - */ - WC_FOUND_TOWN = ::WC_FOUND_TOWN, - - /** - * Build industry; %Window numbers: - * - 0 = #DynamicPlaceIndustriesWidgets - */ - WC_BUILD_INDUSTRY = ::WC_BUILD_INDUSTRY, - - - /** - * Select game window; %Window numbers: - * - 0 = #SelectGameIntroWidgets - */ - WC_SELECT_GAME = ::WC_SELECT_GAME, - - /** - * Landscape generation (in Scenario Editor); %Window numbers: - * - 0 = #TerraformToolbarWidgets - * - 0 = #EditorTerraformToolbarWidgets - */ - WC_SCEN_LAND_GEN = ::WC_SCEN_LAND_GEN, - - /** - * Generate landscape (newgame); %Window numbers: - * - GLWM_SCENARIO = #CreateScenarioWidgets - * - #GenenerateLandscapeWindowMode = #GenerateLandscapeWidgets - */ - WC_GENERATE_LANDSCAPE = ::WC_GENERATE_LANDSCAPE, - - /** - * Progress report of landscape generation; %Window numbers: - * - 0 = #GenerationProgressWidgets - * - 1 = #ScanProgressWidgets - */ - WC_MODAL_PROGRESS = ::WC_MODAL_PROGRESS, - - - /** - * Network window; %Window numbers: - * - #WN_NETWORK_WINDOW_GAME = #NetworkGameWidgets - * - #WN_NETWORK_WINDOW_LOBBY = #NetworkLobbyWidgets - * - #WN_NETWORK_WINDOW_CONTENT_LIST = #NetworkContentListWidgets - * - #WN_NETWORK_WINDOW_START = #NetworkStartServerWidgets - */ - WC_NETWORK_WINDOW = ::WC_NETWORK_WINDOW, - - /** - * Client list; %Window numbers: - * - 0 = #ClientListWidgets - */ - WC_CLIENT_LIST = ::WC_CLIENT_LIST, - - /** - * Popup for the client list; %Window numbers: - * - #ClientID = #ClientListPopupWidgets - */ - WC_CLIENT_LIST_POPUP = ::WC_CLIENT_LIST_POPUP, - - /** - * Network status window; %Window numbers: - * - #WN_NETWORK_STATUS_WINDOW_JOIN = #NetworkJoinStatusWidgets - * - #WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD = #NetworkContentDownloadStatusWidgets - */ - WC_NETWORK_STATUS_WINDOW = ::WC_NETWORK_STATUS_WINDOW, - - /** - * Chatbox; %Window numbers: - * - #DestType = #NetWorkChatWidgets - */ - WC_SEND_NETWORK_MSG = ::WC_SEND_NETWORK_MSG, - - /** - * Company password query; %Window numbers: - * - 0 = #NetworkCompanyPasswordWidgets - */ - WC_COMPANY_PASSWORD_WINDOW = ::WC_COMPANY_PASSWORD_WINDOW, - - - /** - * Industry cargoes chain; %Window numbers: - * - 0 = #IndustryCargoesWidgets - */ - WC_INDUSTRY_CARGOES = ::WC_INDUSTRY_CARGOES, - - /** - * Legend for graphs; %Window numbers: - * - 0 = #GraphLegendWidgets - */ - WC_GRAPH_LEGEND = ::WC_GRAPH_LEGEND, - - /** - * Finances of a company; %Window numbers: - * - #CompanyID = #CompanyWidgets - */ - WC_FINANCES = ::WC_FINANCES, - - /** - * Income graph; %Window numbers: - * - 0 = #CompanyValueWidgets - */ - WC_INCOME_GRAPH = ::WC_INCOME_GRAPH, - - /** - * Operating profit graph; %Window numbers: - * - 0 = #CompanyValueWidgets - */ - WC_OPERATING_PROFIT = ::WC_OPERATING_PROFIT, - - /** - * Delivered cargo graph; %Window numbers: - * - 0 = #CompanyValueWidgets - */ - WC_DELIVERED_CARGO = ::WC_DELIVERED_CARGO, - - /** - * Performance history graph; %Window numbers: - * - 0 = #PerformanceHistoryGraphWidgets - */ - WC_PERFORMANCE_HISTORY = ::WC_PERFORMANCE_HISTORY, - - /** - * Company value graph; %Window numbers: - * - 0 = #CompanyValueWidgets - */ - WC_COMPANY_VALUE = ::WC_COMPANY_VALUE, - - /** - * Company league window; %Window numbers: - * - 0 = #CompanyLeagueWidgets - */ - WC_COMPANY_LEAGUE = ::WC_COMPANY_LEAGUE, - - /** - * Payment rates graph; %Window numbers: - * - 0 = #CargoPaymentRatesWidgets - */ - WC_PAYMENT_RATES = ::WC_PAYMENT_RATES, - - /** - * Performance detail window; %Window numbers: - * - 0 = #PerformanceRatingDetailsWidgets - */ - WC_PERFORMANCE_DETAIL = ::WC_PERFORMANCE_DETAIL, - - /** - * Company infrastructure overview; %Window numbers: - * - #CompanyID = #CompanyInfrastructureWidgets - */ - WC_COMPANY_INFRASTRUCTURE = ::WC_COMPANY_INFRASTRUCTURE, - - - /** - * Buyout company (merger); %Window numbers: - * - #CompanyID = #BuyCompanyWidgets - */ - WC_BUY_COMPANY = ::WC_BUY_COMPANY, - - /** - * Engine preview window; %Window numbers: - * - #EngineID = #EnginePreviewWidgets - */ - WC_ENGINE_PREVIEW = ::WC_ENGINE_PREVIEW, - - - /** - * Music window; %Window numbers: - * - 0 = #MusicWidgets - */ - WC_MUSIC_WINDOW = ::WC_MUSIC_WINDOW, - - /** - * Music track selection; %Window numbers: - * - 0 = MusicTrackSelectionWidgets - */ - WC_MUSIC_TRACK_SELECTION = ::WC_MUSIC_TRACK_SELECTION, - - /** - * Game options window; %Window numbers: - * - #WN_GAME_OPTIONS_AI = #AIConfigWidgets - * - #WN_GAME_OPTIONS_ABOUT = #AboutWidgets - * - #WN_GAME_OPTIONS_NEWGRF_STATE = #NewGRFStateWidgets - * - #WN_GAME_OPTIONS_GAME_OPTIONS = #GameOptionsWidgets - * - #WN_GAME_OPTIONS_GAME_SETTINGS = #GameSettingsWidgets - */ - WC_GAME_OPTIONS = ::WC_GAME_OPTIONS, - - /** - * Custom currency; %Window numbers: - * - 0 = #CustomCurrencyWidgets - */ - WC_CUSTOM_CURRENCY = ::WC_CUSTOM_CURRENCY, - - /** - * Cheat window; %Window numbers: - * - 0 = #CheatWidgets - */ - WC_CHEATS = ::WC_CHEATS, - - /** - * Extra viewport; %Window numbers: - * - Ascending value = #ExtraViewportWidgets - */ - WC_EXTRA_VIEW_PORT = ::WC_EXTRA_VIEW_PORT, - - - /** - * Console; %Window numbers: - * - 0 = #ConsoleWidgets - */ - WC_CONSOLE = ::WC_CONSOLE, - - /** - * Bootstrap; %Window numbers: - * - 0 = #BootstrapBackgroundWidgets - */ - WC_BOOTSTRAP = ::WC_BOOTSTRAP, - - /** - * Highscore; %Window numbers: - * - 0 = #HighscoreWidgets - */ - WC_HIGHSCORE = ::WC_HIGHSCORE, - - /** - * Endscreen; %Window numbers: - * - 0 = #HighscoreWidgets - */ - WC_ENDSCREEN = ::WC_ENDSCREEN, - - - /** - * AI debug window; %Window numbers: - * - 0 = #AIDebugWidgets - */ - WC_AI_DEBUG = ::WC_AI_DEBUG, - - /** - * NewGRF inspect (debug); %Window numbers: - * - Packed value = #NewGRFInspectWidgets - */ - WC_NEWGRF_INSPECT = ::WC_NEWGRF_INSPECT, - - /** - * Sprite aligner (debug); %Window numbers: - * - 0 = #SpriteAlignerWidgets - */ - WC_SPRITE_ALIGNER = ::WC_SPRITE_ALIGNER, - - /** - * Linkgraph legend; Window numbers: - * - 0 = #LinkGraphWidgets - */ - WC_LINKGRAPH_LEGEND = ::WC_LINKGRAPH_LEGEND, - - WC_INVALID = ::WC_INVALID, ///< Invalid window. - }; - - // @endenum - - /** - * The colours in the game which you can use for text and highlights. - */ - enum TextColour { - /* Note: these values represent part of the in-game TextColour enum */ - TC_BLUE = ::TC_BLUE, ///< Blue colour. - TC_SILVER = ::TC_SILVER, ///< Silver colour. - TC_GOLD = ::TC_GOLD, ///< Gold colour. - TC_RED = ::TC_RED, ///< Red colour. - TC_PURPLE = ::TC_PURPLE, ///< Purple colour. - TC_LIGHT_BROWN = ::TC_LIGHT_BROWN, ///< Light brown colour. - TC_ORANGE = ::TC_ORANGE, ///< Orange colour. - TC_GREEN = ::TC_GREEN, ///< Green colour. - TC_YELLOW = ::TC_YELLOW, ///< Yellow colour. - TC_DARK_GREEN = ::TC_DARK_GREEN, ///< Dark green colour. - TC_CREAM = ::TC_CREAM, ///< Cream colour. - TC_BROWN = ::TC_BROWN, ///< Brown colour. - TC_WHITE = ::TC_WHITE, ///< White colour. - TC_LIGHT_BLUE = ::TC_LIGHT_BLUE, ///< Light blue colour. - TC_GREY = ::TC_GREY, ///< Grey colour. - TC_DARK_BLUE = ::TC_DARK_BLUE, ///< Dark blue colour. - TC_BLACK = ::TC_BLACK, ///< Black colour. - TC_INVALID = ::TC_INVALID, ///< Invalid colour. - }; - - /** - * Special number values. - */ - enum NumberType { - NUMBER_ALL = 0xFFFFFFFF, ///< Value to select all windows of a class. - }; - - /** - * Special widget values. - */ - enum WidgetType { - WIDGET_ALL = 0xFF, ///< Value to select all widgets of a window. - }; - - /** - * Close a window. - * @param window The class of the window to close. - * @param number The number of the window to close, or NUMBER_ALL to close all of this class. - * @pre !ScriptGame::IsMultiplayer(). - */ - static void Close(WindowClass window, uint32 number); - - /** - * Check if a window is open. - * @param window The class of the window to check for. - * @param number The number of the window to check for, or NUMBER_ALL to check for any in the class. - * @pre !ScriptGame::IsMultiplayer(). - * @return True if the window is open. - */ - static bool IsOpen(WindowClass window, uint32 number); - - /** - * Highlight a widget in a window. - * @param window The class of the window to highlight a widget in. - * @param number The number of the window to highlight a widget in. - * @param widget The widget in the window to highlight, or WIDGET_ALL (in combination with TC_INVALID) to disable all widget highlighting on this window. - * @param colour The colour of the highlight, or TC_INVALID for disabling. - * @pre !ScriptGame::IsMultiplayer(). - * @pre number != NUMBER_ALL. - * @pre colour < TC_END || (widget == WIDGET_ALL && colour == TC_INVALID). - * @pre IsOpen(window, number). - */ - static void Highlight(WindowClass window, uint32 number, uint8 widget, TextColour colour); - - // @enum .*Widgets ../../widgets/*_widget.h - /* automatically generated from ../../widgets/ai_widget.h */ - /** Widgets of the #AIListWindow class. */ - enum AIListWidgets { - WID_AIL_CAPTION = ::WID_AIL_CAPTION, ///< Caption of the window. - WID_AIL_LIST = ::WID_AIL_LIST, ///< The matrix with all available AIs. - WID_AIL_SCROLLBAR = ::WID_AIL_SCROLLBAR, ///< Scrollbar next to the AI list. - WID_AIL_INFO_BG = ::WID_AIL_INFO_BG, ///< Panel to draw some AI information on. - WID_AIL_ACCEPT = ::WID_AIL_ACCEPT, ///< Accept button. - WID_AIL_CANCEL = ::WID_AIL_CANCEL, ///< Cancel button. - }; - - /** Widgets of the #AISettingsWindow class. */ - enum AISettingsWidgets { - WID_AIS_CAPTION = ::WID_AIS_CAPTION, ///< Caption of the window. - WID_AIS_BACKGROUND = ::WID_AIS_BACKGROUND, ///< Panel to draw the settings on. - WID_AIS_SCROLLBAR = ::WID_AIS_SCROLLBAR, ///< Scrollbar to scroll through all settings. - WID_AIS_ACCEPT = ::WID_AIS_ACCEPT, ///< Accept button. - WID_AIS_RESET = ::WID_AIS_RESET, ///< Reset button. - }; - - /** Widgets of the #AIConfigWindow class. */ - enum AIConfigWidgets { - WID_AIC_BACKGROUND = ::WID_AIC_BACKGROUND, ///< Window background. - WID_AIC_DECREASE = ::WID_AIC_DECREASE, ///< Decrease the number of AIs. - WID_AIC_INCREASE = ::WID_AIC_INCREASE, ///< Increase the number of AIs. - WID_AIC_NUMBER = ::WID_AIC_NUMBER, ///< Number of AIs. - WID_AIC_GAMELIST = ::WID_AIC_GAMELIST, ///< List with current selected GameScript. - WID_AIC_LIST = ::WID_AIC_LIST, ///< List with currently selected AIs. - WID_AIC_SCROLLBAR = ::WID_AIC_SCROLLBAR, ///< Scrollbar to scroll through the selected AIs. - WID_AIC_MOVE_UP = ::WID_AIC_MOVE_UP, ///< Move up button. - WID_AIC_MOVE_DOWN = ::WID_AIC_MOVE_DOWN, ///< Move down button. - WID_AIC_CHANGE = ::WID_AIC_CHANGE, ///< Select another AI button. - WID_AIC_CONFIGURE = ::WID_AIC_CONFIGURE, ///< Change AI settings button. - WID_AIC_CLOSE = ::WID_AIC_CLOSE, ///< Close window button. - WID_AIC_TEXTFILE = ::WID_AIC_TEXTFILE, ///< Open AI readme, changelog (+1) or license (+2). - WID_AIC_CONTENT_DOWNLOAD = ::WID_AIC_CONTENT_DOWNLOAD, ///< Download content button. - }; - - /** Widgets of the #AIDebugWindow class. */ - enum AIDebugWidgets { - WID_AID_VIEW = ::WID_AID_VIEW, ///< The row of company buttons. - WID_AID_NAME_TEXT = ::WID_AID_NAME_TEXT, ///< Name of the current selected. - WID_AID_SETTINGS = ::WID_AID_SETTINGS, ///< Settings button. - WID_AID_SCRIPT_GAME = ::WID_AID_SCRIPT_GAME, ///< Game Script button. - WID_AID_RELOAD_TOGGLE = ::WID_AID_RELOAD_TOGGLE, ///< Reload button. - WID_AID_LOG_PANEL = ::WID_AID_LOG_PANEL, ///< Panel where the log is in. - WID_AID_SCROLLBAR = ::WID_AID_SCROLLBAR, ///< Scrollbar of the log panel. - WID_AID_COMPANY_BUTTON_START = ::WID_AID_COMPANY_BUTTON_START, ///< Buttons in the VIEW. - WID_AID_COMPANY_BUTTON_END = ::WID_AID_COMPANY_BUTTON_END, ///< Last possible button in the VIEW. - WID_AID_BREAK_STRING_WIDGETS = ::WID_AID_BREAK_STRING_WIDGETS, ///< The panel to handle the breaking on string. - WID_AID_BREAK_STR_ON_OFF_BTN = ::WID_AID_BREAK_STR_ON_OFF_BTN, ///< Enable breaking on string. - WID_AID_BREAK_STR_EDIT_BOX = ::WID_AID_BREAK_STR_EDIT_BOX, ///< Edit box for the string to break on. - WID_AID_MATCH_CASE_BTN = ::WID_AID_MATCH_CASE_BTN, ///< Checkbox to use match caching or not. - WID_AID_CONTINUE_BTN = ::WID_AID_CONTINUE_BTN, ///< Continue button. - }; - - /* automatically generated from ../../widgets/airport_widget.h */ - /** Widgets of the #BuildAirToolbarWindow class. */ - enum AirportToolbarWidgets { - WID_AT_AIRPORT = ::WID_AT_AIRPORT, ///< Build airport button. - WID_AT_DEMOLISH = ::WID_AT_DEMOLISH, ///< Demolish button. - }; - - /** Widgets of the #BuildAirportWindow class. */ - enum AirportPickerWidgets { - WID_AP_CLASS_DROPDOWN = ::WID_AP_CLASS_DROPDOWN, ///< Dropdown of airport classes. - WID_AP_AIRPORT_LIST = ::WID_AP_AIRPORT_LIST, ///< List of airports. - WID_AP_SCROLLBAR = ::WID_AP_SCROLLBAR, ///< Scrollbar of the list. - WID_AP_LAYOUT_NUM = ::WID_AP_LAYOUT_NUM, ///< Current number of the layout. - WID_AP_LAYOUT_DECREASE = ::WID_AP_LAYOUT_DECREASE, ///< Decrease the layout number. - WID_AP_LAYOUT_INCREASE = ::WID_AP_LAYOUT_INCREASE, ///< Increase the layout number. - WID_AP_AIRPORT_SPRITE = ::WID_AP_AIRPORT_SPRITE, ///< A visual display of the airport currently selected. - WID_AP_EXTRA_TEXT = ::WID_AP_EXTRA_TEXT, ///< Additional text about the airport. - WID_AP_BOTTOMPANEL = ::WID_AP_BOTTOMPANEL, ///< Panel at the bottom. - WID_AP_COVERAGE_LABEL = ::WID_AP_COVERAGE_LABEL, ///< Label if you want to see the coverage. - WID_AP_BTN_DONTHILIGHT = ::WID_AP_BTN_DONTHILIGHT, ///< Don't show the coverage button. - WID_AP_BTN_DOHILIGHT = ::WID_AP_BTN_DOHILIGHT, ///< Show the coverage button. - }; - - /* automatically generated from ../../widgets/autoreplace_widget.h */ - /** Widgets of the #ReplaceVehicleWindow class. */ - enum ReplaceVehicleWidgets { - WID_RV_CAPTION = ::WID_RV_CAPTION, ///< Caption of the window. - - /* Left and right matrix + details. */ - WID_RV_LEFT_MATRIX = ::WID_RV_LEFT_MATRIX, ///< The matrix on the left. - WID_RV_LEFT_SCROLLBAR = ::WID_RV_LEFT_SCROLLBAR, ///< The scrollbar for the matrix on the left. - WID_RV_RIGHT_MATRIX = ::WID_RV_RIGHT_MATRIX, ///< The matrix on the right. - WID_RV_RIGHT_SCROLLBAR = ::WID_RV_RIGHT_SCROLLBAR, ///< The scrollbar for the matrix on the right. - WID_RV_LEFT_DETAILS = ::WID_RV_LEFT_DETAILS, ///< Details of the entry on the left. - WID_RV_RIGHT_DETAILS = ::WID_RV_RIGHT_DETAILS, ///< Details of the entry on the right. - - /* Button row. */ - WID_RV_START_REPLACE = ::WID_RV_START_REPLACE, ///< Start Replacing button. - WID_RV_INFO_TAB = ::WID_RV_INFO_TAB, ///< Info tab. - WID_RV_STOP_REPLACE = ::WID_RV_STOP_REPLACE, ///< Stop Replacing button. - - /* Train only widgets. */ - WID_RV_TRAIN_ENGINEWAGON_TOGGLE = ::WID_RV_TRAIN_ENGINEWAGON_TOGGLE, ///< Button to toggle engines and/or wagons. - WID_RV_TRAIN_FLUFF_LEFT = ::WID_RV_TRAIN_FLUFF_LEFT, ///< The fluff on the left. - WID_RV_TRAIN_RAILTYPE_DROPDOWN = ::WID_RV_TRAIN_RAILTYPE_DROPDOWN, ///< Dropdown menu about the railtype. - WID_RV_TRAIN_FLUFF_RIGHT = ::WID_RV_TRAIN_FLUFF_RIGHT, ///< The fluff on the right. - WID_RV_TRAIN_WAGONREMOVE_TOGGLE = ::WID_RV_TRAIN_WAGONREMOVE_TOGGLE, ///< Button to toggle removing wagons. - }; - - /* automatically generated from ../../widgets/bootstrap_widget.h */ - /** Widgets of the #BootstrapBackground class. */ - enum BootstrapBackgroundWidgets { - WID_BB_BACKGROUND = ::WID_BB_BACKGROUND, ///< Background of the window. - }; - - /** Widgets of the #BootstrapContentDownloadStatusWindow class. */ - enum BootstrapAskForDownloadWidgets { - WID_BAFD_QUESTION = ::WID_BAFD_QUESTION, ///< The question whether to download. - WID_BAFD_YES = ::WID_BAFD_YES, ///< An affirmative answer to the question. - WID_BAFD_NO = ::WID_BAFD_NO, ///< An negative answer to the question. - }; - - /* automatically generated from ../../widgets/bridge_widget.h */ - /** Widgets of the #BuildBridgeWindow class. */ - enum BuildBridgeSelectionWidgets { - WID_BBS_CAPTION = ::WID_BBS_CAPTION, ///< Caption of the window. - WID_BBS_DROPDOWN_ORDER = ::WID_BBS_DROPDOWN_ORDER, ///< Direction of sort dropdown. - WID_BBS_DROPDOWN_CRITERIA = ::WID_BBS_DROPDOWN_CRITERIA, ///< Criteria of sort dropdown. - WID_BBS_BRIDGE_LIST = ::WID_BBS_BRIDGE_LIST, ///< List of bridges. - WID_BBS_SCROLLBAR = ::WID_BBS_SCROLLBAR, ///< Scrollbar of the list. - }; - - /* automatically generated from ../../widgets/build_vehicle_widget.h */ - /** Widgets of the #BuildVehicleWindow class. */ - enum BuildVehicleWidgets { - WID_BV_CAPTION = ::WID_BV_CAPTION, ///< Caption of window. - WID_BV_SORT_ASSENDING_DESCENDING = ::WID_BV_SORT_ASSENDING_DESCENDING, ///< Sort direction. - WID_BV_SORT_DROPDOWN = ::WID_BV_SORT_DROPDOWN, ///< Criteria of sorting dropdown. - WID_BV_CARGO_FILTER_DROPDOWN = ::WID_BV_CARGO_FILTER_DROPDOWN, ///< Cargo filter dropdown. - WID_BV_LIST = ::WID_BV_LIST, ///< List of vehicles. - WID_BV_SCROLLBAR = ::WID_BV_SCROLLBAR, ///< Scrollbar of list. - WID_BV_PANEL = ::WID_BV_PANEL, ///< Button panel. - WID_BV_BUILD = ::WID_BV_BUILD, ///< Build panel. - WID_BV_BUILD_SEL = ::WID_BV_BUILD_SEL, ///< Build button. - WID_BV_RENAME = ::WID_BV_RENAME, ///< Rename button. - }; - - /* automatically generated from ../../widgets/cheat_widget.h */ - /** Widgets of the #CheatWindow class.. */ - enum CheatWidgets { - WID_C_PANEL = ::WID_C_PANEL, ///< Panel where all cheats are shown in. - }; - - /* automatically generated from ../../widgets/company_widget.h */ - /** Widgets of the #CompanyWindow class. */ - enum CompanyWidgets { - WID_C_CAPTION = ::WID_C_CAPTION, ///< Caption of the window. - - WID_C_FACE = ::WID_C_FACE, ///< View of the face. - WID_C_FACE_TITLE = ::WID_C_FACE_TITLE, ///< Title for the face. - - WID_C_DESC_INAUGURATION = ::WID_C_DESC_INAUGURATION, ///< Inauguration. - WID_C_DESC_COLOUR_SCHEME = ::WID_C_DESC_COLOUR_SCHEME, ///< Colour scheme. - WID_C_DESC_COLOUR_SCHEME_EXAMPLE = ::WID_C_DESC_COLOUR_SCHEME_EXAMPLE, ///< Colour scheme example. - WID_C_DESC_VEHICLE = ::WID_C_DESC_VEHICLE, ///< Vehicles. - WID_C_DESC_VEHICLE_COUNTS = ::WID_C_DESC_VEHICLE_COUNTS, ///< Vehicle count. - WID_C_DESC_COMPANY_VALUE = ::WID_C_DESC_COMPANY_VALUE, ///< Company value. - WID_C_DESC_INFRASTRUCTURE = ::WID_C_DESC_INFRASTRUCTURE, ///< Infrastructure. - WID_C_DESC_INFRASTRUCTURE_COUNTS = ::WID_C_DESC_INFRASTRUCTURE_COUNTS, ///< Infrastructure count. - - WID_C_SELECT_DESC_OWNERS = ::WID_C_SELECT_DESC_OWNERS, ///< Owners. - WID_C_DESC_OWNERS = ::WID_C_DESC_OWNERS, ///< Owner in Owners. - - WID_C_SELECT_BUTTONS = ::WID_C_SELECT_BUTTONS, ///< Selection widget for the button bar. - WID_C_NEW_FACE = ::WID_C_NEW_FACE, ///< Button to make new face. - WID_C_COLOUR_SCHEME = ::WID_C_COLOUR_SCHEME, ///< Button to change colour scheme. - WID_C_PRESIDENT_NAME = ::WID_C_PRESIDENT_NAME, ///< Button to change president name. - WID_C_COMPANY_NAME = ::WID_C_COMPANY_NAME, ///< Button to change company name. - WID_C_BUY_SHARE = ::WID_C_BUY_SHARE, ///< Button to buy a share. - WID_C_SELL_SHARE = ::WID_C_SELL_SHARE, ///< Button to sell a share. - - WID_C_SELECT_VIEW_BUILD_HQ = ::WID_C_SELECT_VIEW_BUILD_HQ, ///< Panel about HQ. - WID_C_VIEW_HQ = ::WID_C_VIEW_HQ, ///< Button to view the HQ. - WID_C_BUILD_HQ = ::WID_C_BUILD_HQ, ///< Button to build the HQ. - - WID_C_SELECT_RELOCATE = ::WID_C_SELECT_RELOCATE, ///< Panel about 'Relocate HQ'. - WID_C_RELOCATE_HQ = ::WID_C_RELOCATE_HQ, ///< Button to relocate the HQ. - - WID_C_VIEW_INFRASTRUCTURE = ::WID_C_VIEW_INFRASTRUCTURE, ///< Panel about infrastructure. - - WID_C_HAS_PASSWORD = ::WID_C_HAS_PASSWORD, ///< Has company password lock. - WID_C_SELECT_MULTIPLAYER = ::WID_C_SELECT_MULTIPLAYER, ///< Multiplayer selection panel. - WID_C_COMPANY_PASSWORD = ::WID_C_COMPANY_PASSWORD, ///< Button to set company password. - WID_C_COMPANY_JOIN = ::WID_C_COMPANY_JOIN, ///< Button to join company. - }; - - /** Widgets of the #CompanyFinancesWindow class. */ - enum CompanyFinancesWidgets { - WID_CF_CAPTION = ::WID_CF_CAPTION, ///< Caption of the window. - WID_CF_TOGGLE_SIZE = ::WID_CF_TOGGLE_SIZE, ///< Toggle windows size. - WID_CF_SEL_PANEL = ::WID_CF_SEL_PANEL, ///< Select panel or nothing. - WID_CF_EXPS_CATEGORY = ::WID_CF_EXPS_CATEGORY, ///< Column for expenses category strings. - WID_CF_EXPS_PRICE1 = ::WID_CF_EXPS_PRICE1, ///< Column for year Y-2 expenses. - WID_CF_EXPS_PRICE2 = ::WID_CF_EXPS_PRICE2, ///< Column for year Y-1 expenses. - WID_CF_EXPS_PRICE3 = ::WID_CF_EXPS_PRICE3, ///< Column for year Y expenses. - WID_CF_TOTAL_PANEL = ::WID_CF_TOTAL_PANEL, ///< Panel for totals. - WID_CF_SEL_MAXLOAN = ::WID_CF_SEL_MAXLOAN, ///< Selection of maxloan column. - WID_CF_BALANCE_VALUE = ::WID_CF_BALANCE_VALUE, ///< Bank balance value. - WID_CF_LOAN_VALUE = ::WID_CF_LOAN_VALUE, ///< Loan. - WID_CF_LOAN_LINE = ::WID_CF_LOAN_LINE, ///< Line for summing bank balance and loan. - WID_CF_TOTAL_VALUE = ::WID_CF_TOTAL_VALUE, ///< Total. - WID_CF_MAXLOAN_GAP = ::WID_CF_MAXLOAN_GAP, ///< Gap above max loan widget. - WID_CF_MAXLOAN_VALUE = ::WID_CF_MAXLOAN_VALUE, ///< Max loan widget. - WID_CF_SEL_BUTTONS = ::WID_CF_SEL_BUTTONS, ///< Selection of buttons. - WID_CF_INCREASE_LOAN = ::WID_CF_INCREASE_LOAN, ///< Increase loan. - WID_CF_REPAY_LOAN = ::WID_CF_REPAY_LOAN, ///< Decrease loan.. - WID_CF_INFRASTRUCTURE = ::WID_CF_INFRASTRUCTURE, ///< View company infrastructure. - }; - - /** Widgets of the #SelectCompanyLiveryWindow class. */ - enum SelectCompanyLiveryWidgets { - WID_SCL_CAPTION = ::WID_SCL_CAPTION, ///< Caption of window. - WID_SCL_CLASS_GENERAL = ::WID_SCL_CLASS_GENERAL, ///< Class general. - WID_SCL_CLASS_RAIL = ::WID_SCL_CLASS_RAIL, ///< Class rail. - WID_SCL_CLASS_ROAD = ::WID_SCL_CLASS_ROAD, ///< Class road. - WID_SCL_CLASS_SHIP = ::WID_SCL_CLASS_SHIP, ///< Class ship. - WID_SCL_CLASS_AIRCRAFT = ::WID_SCL_CLASS_AIRCRAFT, ///< Class aircraft. - WID_SCL_SPACER_DROPDOWN = ::WID_SCL_SPACER_DROPDOWN, ///< Spacer for dropdown. - WID_SCL_PRI_COL_DROPDOWN = ::WID_SCL_PRI_COL_DROPDOWN, ///< Dropdown for primary colour. - WID_SCL_SEC_COL_DROPDOWN = ::WID_SCL_SEC_COL_DROPDOWN, ///< Dropdown for secondary colour. - WID_SCL_MATRIX = ::WID_SCL_MATRIX, ///< Matrix. - }; - - /** - * Widgets of the #SelectCompanyManagerFaceWindow class. - * Do not change the order of the widgets from WID_SCMF_HAS_MOUSTACHE_EARRING to WID_SCMF_GLASSES_R, - * this order is needed for the WE_CLICK event of DrawFaceStringLabel(). - */ - enum SelectCompanyManagerFaceWidgets { - WID_SCMF_CAPTION = ::WID_SCMF_CAPTION, ///< Caption of window. - WID_SCMF_TOGGLE_LARGE_SMALL = ::WID_SCMF_TOGGLE_LARGE_SMALL, ///< Toggle for large or small. - WID_SCMF_SELECT_FACE = ::WID_SCMF_SELECT_FACE, ///< Select face. - WID_SCMF_CANCEL = ::WID_SCMF_CANCEL, ///< Cancel. - WID_SCMF_ACCEPT = ::WID_SCMF_ACCEPT, ///< Accept. - WID_SCMF_MALE = ::WID_SCMF_MALE, ///< Male button in the simple view. - WID_SCMF_FEMALE = ::WID_SCMF_FEMALE, ///< Female button in the simple view. - WID_SCMF_MALE2 = ::WID_SCMF_MALE2, ///< Male button in the advanced view. - WID_SCMF_FEMALE2 = ::WID_SCMF_FEMALE2, ///< Female button in the advanced view. - WID_SCMF_SEL_LOADSAVE = ::WID_SCMF_SEL_LOADSAVE, ///< Selection to display the load/save/number buttons in the advanced view. - WID_SCMF_SEL_MALEFEMALE = ::WID_SCMF_SEL_MALEFEMALE, ///< Selection to display the male/female buttons in the simple view. - WID_SCMF_SEL_PARTS = ::WID_SCMF_SEL_PARTS, ///< Selection to display the buttons for setting each part of the face in the advanced view. - WID_SCMF_RANDOM_NEW_FACE = ::WID_SCMF_RANDOM_NEW_FACE, ///< Create random new face. - WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON = ::WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON, ///< Toggle for large or small. - WID_SCMF_FACE = ::WID_SCMF_FACE, ///< Current face. - WID_SCMF_LOAD = ::WID_SCMF_LOAD, ///< Load face. - WID_SCMF_FACECODE = ::WID_SCMF_FACECODE, ///< Get the face code. - WID_SCMF_SAVE = ::WID_SCMF_SAVE, ///< Save face. - WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT = ::WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT, ///< Text about moustache and earring. - WID_SCMF_TIE_EARRING_TEXT = ::WID_SCMF_TIE_EARRING_TEXT, ///< Text about tie and earring. - WID_SCMF_LIPS_MOUSTACHE_TEXT = ::WID_SCMF_LIPS_MOUSTACHE_TEXT, ///< Text about lips and moustache. - WID_SCMF_HAS_GLASSES_TEXT = ::WID_SCMF_HAS_GLASSES_TEXT, ///< Text about glasses. - WID_SCMF_HAIR_TEXT = ::WID_SCMF_HAIR_TEXT, ///< Text about hair. - WID_SCMF_EYEBROWS_TEXT = ::WID_SCMF_EYEBROWS_TEXT, ///< Text about eyebrows. - WID_SCMF_EYECOLOUR_TEXT = ::WID_SCMF_EYECOLOUR_TEXT, ///< Text about eyecolour. - WID_SCMF_GLASSES_TEXT = ::WID_SCMF_GLASSES_TEXT, ///< Text about glasses. - WID_SCMF_NOSE_TEXT = ::WID_SCMF_NOSE_TEXT, ///< Text about nose. - WID_SCMF_CHIN_TEXT = ::WID_SCMF_CHIN_TEXT, ///< Text about chin. - WID_SCMF_JACKET_TEXT = ::WID_SCMF_JACKET_TEXT, ///< Text about jacket. - WID_SCMF_COLLAR_TEXT = ::WID_SCMF_COLLAR_TEXT, ///< Text about collar. - WID_SCMF_ETHNICITY_EUR = ::WID_SCMF_ETHNICITY_EUR, ///< Text about ethnicity european. - WID_SCMF_ETHNICITY_AFR = ::WID_SCMF_ETHNICITY_AFR, ///< Text about ethnicity african. - WID_SCMF_HAS_MOUSTACHE_EARRING = ::WID_SCMF_HAS_MOUSTACHE_EARRING, ///< Has moustache or earring. - WID_SCMF_HAS_GLASSES = ::WID_SCMF_HAS_GLASSES, ///< Has glasses. - WID_SCMF_EYECOLOUR_L = ::WID_SCMF_EYECOLOUR_L, ///< Eyecolour left. - WID_SCMF_EYECOLOUR = ::WID_SCMF_EYECOLOUR, ///< Eyecolour. - WID_SCMF_EYECOLOUR_R = ::WID_SCMF_EYECOLOUR_R, ///< Eyecolour right. - WID_SCMF_CHIN_L = ::WID_SCMF_CHIN_L, ///< Chin left. - WID_SCMF_CHIN = ::WID_SCMF_CHIN, ///< Chin. - WID_SCMF_CHIN_R = ::WID_SCMF_CHIN_R, ///< Chin right. - WID_SCMF_EYEBROWS_L = ::WID_SCMF_EYEBROWS_L, ///< Eyebrows left. - WID_SCMF_EYEBROWS = ::WID_SCMF_EYEBROWS, ///< Eyebrows. - WID_SCMF_EYEBROWS_R = ::WID_SCMF_EYEBROWS_R, ///< Eyebrows right. - WID_SCMF_LIPS_MOUSTACHE_L = ::WID_SCMF_LIPS_MOUSTACHE_L, ///< Lips / Moustache left. - WID_SCMF_LIPS_MOUSTACHE = ::WID_SCMF_LIPS_MOUSTACHE, ///< Lips / Moustache. - WID_SCMF_LIPS_MOUSTACHE_R = ::WID_SCMF_LIPS_MOUSTACHE_R, ///< Lips / Moustache right. - WID_SCMF_NOSE_L = ::WID_SCMF_NOSE_L, ///< Nose left. - WID_SCMF_NOSE = ::WID_SCMF_NOSE, ///< Nose. - WID_SCMF_NOSE_R = ::WID_SCMF_NOSE_R, ///< Nose right. - WID_SCMF_HAIR_L = ::WID_SCMF_HAIR_L, ///< Hair left. - WID_SCMF_HAIR = ::WID_SCMF_HAIR, ///< Hair. - WID_SCMF_HAIR_R = ::WID_SCMF_HAIR_R, ///< Hair right. - WID_SCMF_JACKET_L = ::WID_SCMF_JACKET_L, ///< Jacket left. - WID_SCMF_JACKET = ::WID_SCMF_JACKET, ///< Jacket. - WID_SCMF_JACKET_R = ::WID_SCMF_JACKET_R, ///< Jacket right. - WID_SCMF_COLLAR_L = ::WID_SCMF_COLLAR_L, ///< Collar left. - WID_SCMF_COLLAR = ::WID_SCMF_COLLAR, ///< Collar. - WID_SCMF_COLLAR_R = ::WID_SCMF_COLLAR_R, ///< Collar right. - WID_SCMF_TIE_EARRING_L = ::WID_SCMF_TIE_EARRING_L, ///< Tie / Earring left. - WID_SCMF_TIE_EARRING = ::WID_SCMF_TIE_EARRING, ///< Tie / Earring. - WID_SCMF_TIE_EARRING_R = ::WID_SCMF_TIE_EARRING_R, ///< Tie / Earring right. - WID_SCMF_GLASSES_L = ::WID_SCMF_GLASSES_L, ///< Glasses left. - WID_SCMF_GLASSES = ::WID_SCMF_GLASSES, ///< Glasses. - WID_SCMF_GLASSES_R = ::WID_SCMF_GLASSES_R, ///< Glasses right. - }; - - /** Widgets of the #CompanyInfrastructureWindow class. */ - enum CompanyInfrastructureWidgets { - WID_CI_CAPTION = ::WID_CI_CAPTION, ///< Caption of window. - WID_CI_RAIL_DESC = ::WID_CI_RAIL_DESC, ///< Description of rail. - WID_CI_RAIL_COUNT = ::WID_CI_RAIL_COUNT, ///< Count of rail. - WID_CI_ROAD_DESC = ::WID_CI_ROAD_DESC, ///< Description of road. - WID_CI_ROAD_COUNT = ::WID_CI_ROAD_COUNT, ///< Count of road. - WID_CI_WATER_DESC = ::WID_CI_WATER_DESC, ///< Description of water. - WID_CI_WATER_COUNT = ::WID_CI_WATER_COUNT, ///< Count of water. - WID_CI_STATION_DESC = ::WID_CI_STATION_DESC, ///< Description of station. - WID_CI_STATION_COUNT = ::WID_CI_STATION_COUNT, ///< Count of station. - WID_CI_TOTAL_DESC = ::WID_CI_TOTAL_DESC, ///< Description of total. - WID_CI_TOTAL = ::WID_CI_TOTAL, ///< Count of total. - }; - - /** Widgets of the #BuyCompanyWindow class. */ - enum BuyCompanyWidgets { - WID_BC_CAPTION = ::WID_BC_CAPTION, ///< Caption of window. - WID_BC_FACE = ::WID_BC_FACE, ///< Face button. - WID_BC_QUESTION = ::WID_BC_QUESTION, ///< Question text. - WID_BC_NO = ::WID_BC_NO, ///< No button. - WID_BC_YES = ::WID_BC_YES, ///< Yes button. - }; - - /* automatically generated from ../../widgets/console_widget.h */ - /** Widgets of the #IConsoleWindow class. */ - enum ConsoleWidgets { - WID_C_BACKGROUND = ::WID_C_BACKGROUND, ///< Background of the console. - }; - - /* automatically generated from ../../widgets/date_widget.h */ - /** Widgets of the #SetDateWindow class. */ - enum SetDateWidgets { - WID_SD_DAY = ::WID_SD_DAY, ///< Dropdown for the day. - WID_SD_MONTH = ::WID_SD_MONTH, ///< Dropdown for the month. - WID_SD_YEAR = ::WID_SD_YEAR, ///< Dropdown for the year. - WID_SD_SET_DATE = ::WID_SD_SET_DATE, ///< Actually set the date. - }; - - /* automatically generated from ../../widgets/depot_widget.h */ - /** Widgets of the #DepotWindow class. */ - enum DepotWidgets { - WID_D_CAPTION = ::WID_D_CAPTION, ///< Caption of window. - WID_D_SELL = ::WID_D_SELL, ///< Sell button. - WID_D_SHOW_SELL_CHAIN = ::WID_D_SHOW_SELL_CHAIN, ///< Show sell chain panel. - WID_D_SELL_CHAIN = ::WID_D_SELL_CHAIN, ///< Sell chain button. - WID_D_SELL_ALL = ::WID_D_SELL_ALL, ///< Sell all button. - WID_D_AUTOREPLACE = ::WID_D_AUTOREPLACE, ///< Autoreplace button. - WID_D_MATRIX = ::WID_D_MATRIX, ///< Matrix of vehicles. - WID_D_V_SCROLL = ::WID_D_V_SCROLL, ///< Vertical scrollbar. - WID_D_SHOW_H_SCROLL = ::WID_D_SHOW_H_SCROLL, ///< Show horizontal scrollbar panel. - WID_D_H_SCROLL = ::WID_D_H_SCROLL, ///< Horizontal scrollbar. - WID_D_BUILD = ::WID_D_BUILD, ///< Build button. - WID_D_CLONE = ::WID_D_CLONE, ///< Clone button. - WID_D_LOCATION = ::WID_D_LOCATION, ///< Location button. - WID_D_SHOW_RENAME = ::WID_D_SHOW_RENAME, ///< Show rename panel. - WID_D_RENAME = ::WID_D_RENAME, ///< Rename button. - WID_D_VEHICLE_LIST = ::WID_D_VEHICLE_LIST, ///< List of vehicles. - WID_D_STOP_ALL = ::WID_D_STOP_ALL, ///< Stop all button. - WID_D_START_ALL = ::WID_D_START_ALL, ///< Start all button. - }; - - /* automatically generated from ../../widgets/dock_widget.h */ - /** Widgets of the #BuildDocksDepotWindow class. */ - enum BuildDockDepotWidgets { - WID_BDD_BACKGROUND = ::WID_BDD_BACKGROUND, ///< Background of the window. - WID_BDD_X = ::WID_BDD_X, ///< X-direction button. - WID_BDD_Y = ::WID_BDD_Y, ///< Y-direction button. - }; - - /** Widgets of the #BuildDocksToolbarWindow class. */ - enum DockToolbarWidgets { - WID_DT_CANAL = ::WID_DT_CANAL, ///< Build canal button. - WID_DT_LOCK = ::WID_DT_LOCK, ///< Build lock button. - WID_DT_DEMOLISH = ::WID_DT_DEMOLISH, ///< Demolish aka dynamite button. - WID_DT_DEPOT = ::WID_DT_DEPOT, ///< Build depot button. - WID_DT_STATION = ::WID_DT_STATION, ///< Build station button. - WID_DT_BUOY = ::WID_DT_BUOY, ///< Build buoy button. - WID_DT_RIVER = ::WID_DT_RIVER, ///< Build river button (in scenario editor). - WID_DT_BUILD_AQUEDUCT = ::WID_DT_BUILD_AQUEDUCT, ///< Build aqueduct button. - - WID_DT_INVALID = ::WID_DT_INVALID, ///< Used to initialize a variable. - }; - - /* automatically generated from ../../widgets/dropdown_widget.h */ - /** Widgets of the #DropdownWindow class. */ - enum DropdownMenuWidgets { - WID_DM_ITEMS = ::WID_DM_ITEMS, ///< Panel showing the dropdown items. - WID_DM_SHOW_SCROLL = ::WID_DM_SHOW_SCROLL, ///< Hide scrollbar if too few items. - WID_DM_SCROLL = ::WID_DM_SCROLL, ///< Scrollbar. - }; - - /* automatically generated from ../../widgets/engine_widget.h */ - /** Widgets of the #EnginePreviewWindow class. */ - enum EnginePreviewWidgets { - WID_EP_QUESTION = ::WID_EP_QUESTION, ///< The container for the question. - WID_EP_NO = ::WID_EP_NO, ///< No button. - WID_EP_YES = ::WID_EP_YES, ///< Yes button. - }; - - /* automatically generated from ../../widgets/error_widget.h */ - /** Widgets of the #ErrmsgWindow class. */ - enum ErrorMessageWidgets { - WID_EM_CAPTION = ::WID_EM_CAPTION, ///< Caption of the window. - WID_EM_FACE = ::WID_EM_FACE, ///< Error title. - WID_EM_MESSAGE = ::WID_EM_MESSAGE, ///< Error message. - }; - - /* automatically generated from ../../widgets/fios_widget.h */ - /** Widgets of the #SaveLoadWindow class. */ - enum SaveLoadWidgets { - WID_SL_CAPTION = ::WID_SL_CAPTION, ///< Caption of the window. - WID_SL_SORT_BYNAME = ::WID_SL_SORT_BYNAME, ///< Sort by name button. - WID_SL_SORT_BYDATE = ::WID_SL_SORT_BYDATE, ///< Sort by date button. - WID_SL_BACKGROUND = ::WID_SL_BACKGROUND, ///< Background of window. - WID_SL_FILE_BACKGROUND = ::WID_SL_FILE_BACKGROUND, ///< Background of file selection. - WID_SL_HOME_BUTTON = ::WID_SL_HOME_BUTTON, ///< Home button. - WID_SL_DRIVES_DIRECTORIES_LIST = ::WID_SL_DRIVES_DIRECTORIES_LIST, ///< Drives list. - WID_SL_SCROLLBAR = ::WID_SL_SCROLLBAR, ///< Scrollbar of the file list. - WID_SL_CONTENT_DOWNLOAD = ::WID_SL_CONTENT_DOWNLOAD, ///< Content download button, only available for play scenario/heightmap. - WID_SL_SAVE_OSK_TITLE = ::WID_SL_SAVE_OSK_TITLE, ///< Title textbox, only available for save operations. - WID_SL_DELETE_SELECTION = ::WID_SL_DELETE_SELECTION, ///< Delete button, only available for save operations. - WID_SL_SAVE_GAME = ::WID_SL_SAVE_GAME, ///< Save button, only available for save operations. - WID_SL_CONTENT_DOWNLOAD_SEL = ::WID_SL_CONTENT_DOWNLOAD_SEL, ///< Selection 'stack' to 'hide' the content download. - WID_SL_DETAILS = ::WID_SL_DETAILS, ///< Panel with game details. - WID_SL_NEWGRF_INFO = ::WID_SL_NEWGRF_INFO, ///< Button to open NewGgrf configuration. - WID_SL_LOAD_BUTTON = ::WID_SL_LOAD_BUTTON, ///< Button to load game/scenario. - WID_SL_MISSING_NEWGRFS = ::WID_SL_MISSING_NEWGRFS, ///< Button to find missing NewGRFs online. - }; - - /* automatically generated from ../../widgets/genworld_widget.h */ - /** Widgets of the #GenerateLandscapeWindow class. */ - enum GenerateLandscapeWidgets { - WID_GL_TEMPERATE = ::WID_GL_TEMPERATE, ///< Button with icon "Temperate". - WID_GL_ARCTIC = ::WID_GL_ARCTIC, ///< Button with icon "Arctic". - WID_GL_TROPICAL = ::WID_GL_TROPICAL, ///< Button with icon "Tropical". - WID_GL_TOYLAND = ::WID_GL_TOYLAND, ///< Button with icon "Toyland". - - WID_GL_MAPSIZE_X_PULLDOWN = ::WID_GL_MAPSIZE_X_PULLDOWN, ///< Dropdown 'map X size'. - WID_GL_MAPSIZE_Y_PULLDOWN = ::WID_GL_MAPSIZE_Y_PULLDOWN, ///< Dropdown 'map Y size'. - - WID_GL_TOWN_PULLDOWN = ::WID_GL_TOWN_PULLDOWN, ///< Dropdown 'No. of towns'. - WID_GL_INDUSTRY_PULLDOWN = ::WID_GL_INDUSTRY_PULLDOWN, ///< Dropdown 'No. of industries'. - - WID_GL_RANDOM_EDITBOX = ::WID_GL_RANDOM_EDITBOX, ///< 'Random seed' editbox. - WID_GL_RANDOM_BUTTON = ::WID_GL_RANDOM_BUTTON, ///< 'Randomise' button. - - WID_GL_GENERATE_BUTTON = ::WID_GL_GENERATE_BUTTON, ///< 'Generate' button. - - WID_GL_START_DATE_DOWN = ::WID_GL_START_DATE_DOWN, ///< Decrease start year. - WID_GL_START_DATE_TEXT = ::WID_GL_START_DATE_TEXT, ///< Start year. - WID_GL_START_DATE_UP = ::WID_GL_START_DATE_UP, ///< Increase start year. - - WID_GL_SNOW_LEVEL_DOWN = ::WID_GL_SNOW_LEVEL_DOWN, ///< Decrease snow level. - WID_GL_SNOW_LEVEL_TEXT = ::WID_GL_SNOW_LEVEL_TEXT, ///< Snow level. - WID_GL_SNOW_LEVEL_UP = ::WID_GL_SNOW_LEVEL_UP, ///< Increase snow level. - - WID_GL_TREE_PULLDOWN = ::WID_GL_TREE_PULLDOWN, ///< Dropdown 'Tree algorithm'. - WID_GL_LANDSCAPE_PULLDOWN = ::WID_GL_LANDSCAPE_PULLDOWN, ///< Dropdown 'Land generator'. - - WID_GL_HEIGHTMAP_NAME_TEXT = ::WID_GL_HEIGHTMAP_NAME_TEXT, ///< Heightmap name. - WID_GL_HEIGHTMAP_SIZE_TEXT = ::WID_GL_HEIGHTMAP_SIZE_TEXT, ///< Size of heightmap. - WID_GL_HEIGHTMAP_ROTATION_PULLDOWN = ::WID_GL_HEIGHTMAP_ROTATION_PULLDOWN, ///< Dropdown 'Heightmap rotation'. - - WID_GL_TERRAIN_PULLDOWN = ::WID_GL_TERRAIN_PULLDOWN, ///< Dropdown 'Terrain type'. - WID_GL_WATER_PULLDOWN = ::WID_GL_WATER_PULLDOWN, ///< Dropdown 'Sea level'. - WID_GL_RIVER_PULLDOWN = ::WID_GL_RIVER_PULLDOWN, ///< Dropdown 'Rivers'. - WID_GL_SMOOTHNESS_PULLDOWN = ::WID_GL_SMOOTHNESS_PULLDOWN, ///< Dropdown 'Smoothness'. - WID_GL_VARIETY_PULLDOWN = ::WID_GL_VARIETY_PULLDOWN, ///< Dropdown 'Variety distribution'. - - WID_GL_BORDERS_RANDOM = ::WID_GL_BORDERS_RANDOM, ///< 'Random'/'Manual' borders. - WID_GL_WATER_NW = ::WID_GL_WATER_NW, ///< NW 'Water'/'Freeform'. - WID_GL_WATER_NE = ::WID_GL_WATER_NE, ///< NE 'Water'/'Freeform'. - WID_GL_WATER_SE = ::WID_GL_WATER_SE, ///< SE 'Water'/'Freeform'. - WID_GL_WATER_SW = ::WID_GL_WATER_SW, ///< SW 'Water'/'Freeform'. - }; - - /** Widgets of the #CreateScenarioWindow class. */ - enum CreateScenarioWidgets { - WID_CS_TEMPERATE = ::WID_CS_TEMPERATE, ///< Select temperate landscape style. - WID_CS_ARCTIC = ::WID_CS_ARCTIC, ///< Select arctic landscape style. - WID_CS_TROPICAL = ::WID_CS_TROPICAL, ///< Select tropical landscape style. - WID_CS_TOYLAND = ::WID_CS_TOYLAND, ///< Select toy-land landscape style. - WID_CS_EMPTY_WORLD = ::WID_CS_EMPTY_WORLD, ///< Generate an empty flat world. - WID_CS_RANDOM_WORLD = ::WID_CS_RANDOM_WORLD, ///< Generate random land button - WID_CS_MAPSIZE_X_PULLDOWN = ::WID_CS_MAPSIZE_X_PULLDOWN, ///< Pull-down arrow for x map size. - WID_CS_MAPSIZE_Y_PULLDOWN = ::WID_CS_MAPSIZE_Y_PULLDOWN, ///< Pull-down arrow for y map size. - WID_CS_START_DATE_DOWN = ::WID_CS_START_DATE_DOWN, ///< Decrease start year (start earlier). - WID_CS_START_DATE_TEXT = ::WID_CS_START_DATE_TEXT, ///< Clickable start date value. - WID_CS_START_DATE_UP = ::WID_CS_START_DATE_UP, ///< Increase start year (start later). - WID_CS_FLAT_LAND_HEIGHT_DOWN = ::WID_CS_FLAT_LAND_HEIGHT_DOWN, ///< Decrease flat land height. - WID_CS_FLAT_LAND_HEIGHT_TEXT = ::WID_CS_FLAT_LAND_HEIGHT_TEXT, ///< Clickable flat land height value. - WID_CS_FLAT_LAND_HEIGHT_UP = ::WID_CS_FLAT_LAND_HEIGHT_UP, ///< Increase flat land height. - }; - - /** Widgets of the #GenerateProgressWindow class. */ - enum GenerationProgressWidgets { - WID_GP_PROGRESS_BAR = ::WID_GP_PROGRESS_BAR, ///< Progress bar. - WID_GP_PROGRESS_TEXT = ::WID_GP_PROGRESS_TEXT, ///< Text with the progress bar. - WID_GP_ABORT = ::WID_GP_ABORT, ///< Abort button. - }; - - /* automatically generated from ../../widgets/goal_widget.h */ - /** Widgets of the #GoalListWindow class. */ - enum GoalListWidgets { - WID_GOAL_CAPTION = ::WID_GOAL_CAPTION, ///< Caption of the window. - WID_GOAL_LIST = ::WID_GOAL_LIST, ///< Goal list. - WID_GOAL_SCROLLBAR = ::WID_GOAL_SCROLLBAR, ///< Scrollbar of the goal list. - }; - - /** Widgets of the #GoalQuestionWindow class. */ - enum GoalQuestionWidgets { - WID_GQ_CAPTION = ::WID_GQ_CAPTION, ///< Caption of the window. - WID_GQ_QUESTION = ::WID_GQ_QUESTION, ///< Question text. - WID_GQ_BUTTONS = ::WID_GQ_BUTTONS, ///< Buttons selection (between 1, 2 or 3). - WID_GQ_BUTTON_1 = ::WID_GQ_BUTTON_1, ///< First button. - WID_GQ_BUTTON_2 = ::WID_GQ_BUTTON_2, ///< Second button. - WID_GQ_BUTTON_3 = ::WID_GQ_BUTTON_3, ///< Third button. - }; - - /* automatically generated from ../../widgets/graph_widget.h */ - /** Widgets of the #GraphLegendWindow class. */ - enum GraphLegendWidgets { - WID_GL_BACKGROUND = ::WID_GL_BACKGROUND, ///< Background of the window. - - WID_GL_FIRST_COMPANY = ::WID_GL_FIRST_COMPANY, ///< First company in the legend. - WID_GL_LAST_COMPANY = ::WID_GL_LAST_COMPANY, ///< Last company in the legend. - }; - - /** Widgets of the #OperatingProfitGraphWindow class, #IncomeGraphWindow class, #DeliveredCargoGraphWindow class, and #CompanyValueGraphWindow class. */ - enum CompanyValueWidgets { - WID_CV_KEY_BUTTON = ::WID_CV_KEY_BUTTON, ///< Key button. - WID_CV_BACKGROUND = ::WID_CV_BACKGROUND, ///< Background of the window. - WID_CV_GRAPH = ::WID_CV_GRAPH, ///< Graph itself. - WID_CV_RESIZE = ::WID_CV_RESIZE, ///< Resize button. - }; - - /** Widget of the #PerformanceHistoryGraphWindow class. */ - enum PerformanceHistoryGraphWidgets { - WID_PHG_KEY = ::WID_PHG_KEY, ///< Key button. - WID_PHG_DETAILED_PERFORMANCE = ::WID_PHG_DETAILED_PERFORMANCE, ///< Detailed performance. - WID_PHG_BACKGROUND = ::WID_PHG_BACKGROUND, ///< Background of the window. - WID_PHG_GRAPH = ::WID_PHG_GRAPH, ///< Graph itself. - WID_PHG_RESIZE = ::WID_PHG_RESIZE, ///< Resize button. - }; - - /** Widget of the #PaymentRatesGraphWindow class. */ - enum CargoPaymentRatesWidgets { - WID_CPR_BACKGROUND = ::WID_CPR_BACKGROUND, ///< Background of the window. - WID_CPR_HEADER = ::WID_CPR_HEADER, ///< Header. - WID_CPR_GRAPH = ::WID_CPR_GRAPH, ///< Graph itself. - WID_CPR_RESIZE = ::WID_CPR_RESIZE, ///< Resize button. - WID_CPR_FOOTER = ::WID_CPR_FOOTER, ///< Footer. - WID_CPR_ENABLE_CARGOES = ::WID_CPR_ENABLE_CARGOES, ///< Enable cargoes button. - WID_CPR_DISABLE_CARGOES = ::WID_CPR_DISABLE_CARGOES, ///< Disable cargoes button. - WID_CPR_CARGO_FIRST = ::WID_CPR_CARGO_FIRST, ///< First cargo in the list. - }; - - /** Widget of the #CompanyLeagueWindow class. */ - enum CompanyLeagueWidgets { - WID_CL_BACKGROUND = ::WID_CL_BACKGROUND, ///< Background of the window. - }; - - /** Widget of the #PerformanceRatingDetailWindow class. */ - enum PerformanceRatingDetailsWidgets { - WID_PRD_SCORE_FIRST = ::WID_PRD_SCORE_FIRST, ///< First entry in the score list. - WID_PRD_SCORE_LAST = ::WID_PRD_SCORE_LAST, ///< Last entry in the score list. - - WID_PRD_COMPANY_FIRST = ::WID_PRD_COMPANY_FIRST, ///< First company. - WID_PRD_COMPANY_LAST = ::WID_PRD_COMPANY_LAST, ///< Last company. - }; - - /* automatically generated from ../../widgets/group_widget.h */ - /** Widgets of the #VehicleGroupWindow class. */ - enum GroupListWidgets { - WID_GL_CAPTION = ::WID_GL_CAPTION, ///< Caption of the window. - WID_GL_SORT_BY_ORDER = ::WID_GL_SORT_BY_ORDER, ///< Sort order. - WID_GL_SORT_BY_DROPDOWN = ::WID_GL_SORT_BY_DROPDOWN, ///< Sort by dropdown list. - WID_GL_LIST_VEHICLE = ::WID_GL_LIST_VEHICLE, ///< List of the vehicles. - WID_GL_LIST_VEHICLE_SCROLLBAR = ::WID_GL_LIST_VEHICLE_SCROLLBAR, ///< Scrollbar for the list. - WID_GL_AVAILABLE_VEHICLES = ::WID_GL_AVAILABLE_VEHICLES, ///< Available vehicles. - WID_GL_MANAGE_VEHICLES_DROPDOWN = ::WID_GL_MANAGE_VEHICLES_DROPDOWN, ///< Manage vehicles dropdown list. - WID_GL_STOP_ALL = ::WID_GL_STOP_ALL, ///< Stop all button. - WID_GL_START_ALL = ::WID_GL_START_ALL, ///< Start all button. - - WID_GL_ALL_VEHICLES = ::WID_GL_ALL_VEHICLES, ///< All vehicles entry. - WID_GL_DEFAULT_VEHICLES = ::WID_GL_DEFAULT_VEHICLES, ///< Default vehicles entry. - WID_GL_LIST_GROUP = ::WID_GL_LIST_GROUP, ///< List of the groups. - WID_GL_LIST_GROUP_SCROLLBAR = ::WID_GL_LIST_GROUP_SCROLLBAR, ///< Scrollbar for the list. - WID_GL_CREATE_GROUP = ::WID_GL_CREATE_GROUP, ///< Create group button. - WID_GL_DELETE_GROUP = ::WID_GL_DELETE_GROUP, ///< Delete group button. - WID_GL_RENAME_GROUP = ::WID_GL_RENAME_GROUP, ///< Rename group button. - WID_GL_REPLACE_PROTECTION = ::WID_GL_REPLACE_PROTECTION, ///< Replace protection button. - }; - - /* automatically generated from ../../widgets/highscore_widget.h */ - /** Widgets of the #EndGameHighScoreBaseWindow class and #HighScoreWindow class. */ - enum HighscoreWidgets { - WID_H_BACKGROUND = ::WID_H_BACKGROUND, ///< Background of the window. - }; - - /* automatically generated from ../../widgets/industry_widget.h */ - /** Widgets of the #BuildIndustryWindow class. */ - enum DynamicPlaceIndustriesWidgets { - WID_DPI_MATRIX_WIDGET = ::WID_DPI_MATRIX_WIDGET, ///< Matrix of the industries. - WID_DPI_SCROLLBAR = ::WID_DPI_SCROLLBAR, ///< Scrollbar of the matrix. - WID_DPI_INFOPANEL = ::WID_DPI_INFOPANEL, ///< Info panel about the industry. - WID_DPI_DISPLAY_WIDGET = ::WID_DPI_DISPLAY_WIDGET, ///< Display chain button. - WID_DPI_FUND_WIDGET = ::WID_DPI_FUND_WIDGET, ///< Fund button. - }; - - /** Widgets of the #IndustryViewWindow class. */ - enum IndustryViewWidgets { - WID_IV_CAPTION = ::WID_IV_CAPTION, ///< Caption of the window. - WID_IV_VIEWPORT = ::WID_IV_VIEWPORT, ///< Viewport of the industry. - WID_IV_INFO = ::WID_IV_INFO, ///< Info of the industry. - WID_IV_GOTO = ::WID_IV_GOTO, ///< Goto button. - WID_IV_DISPLAY = ::WID_IV_DISPLAY, ///< Display chain button. - }; - - /** Widgets of the #IndustryDirectoryWindow class. */ - enum IndustryDirectoryWidgets { - WID_ID_DROPDOWN_ORDER = ::WID_ID_DROPDOWN_ORDER, ///< Dropdown for the order of the sort. - WID_ID_DROPDOWN_CRITERIA = ::WID_ID_DROPDOWN_CRITERIA, ///< Dropdown for the criteria of the sort. - WID_ID_INDUSTRY_LIST = ::WID_ID_INDUSTRY_LIST, ///< Industry list. - WID_ID_SCROLLBAR = ::WID_ID_SCROLLBAR, ///< Scrollbar of the list. - }; - - /** Widgets of the #IndustryCargoesWindow class */ - enum IndustryCargoesWidgets { - WID_IC_CAPTION = ::WID_IC_CAPTION, ///< Caption of the window. - WID_IC_NOTIFY = ::WID_IC_NOTIFY, ///< Row of buttons at the bottom. - WID_IC_PANEL = ::WID_IC_PANEL, ///< Panel that shows the chain. - WID_IC_SCROLLBAR = ::WID_IC_SCROLLBAR, ///< Scrollbar of the panel. - WID_IC_CARGO_DROPDOWN = ::WID_IC_CARGO_DROPDOWN, ///< Select cargo dropdown. - WID_IC_IND_DROPDOWN = ::WID_IC_IND_DROPDOWN, ///< Select industry dropdown. - }; - - /* automatically generated from ../../widgets/intro_widget.h */ - /** Widgets of the #SelectGameWindow class. */ - enum SelectGameIntroWidgets { - WID_SGI_GENERATE_GAME = ::WID_SGI_GENERATE_GAME, ///< Generate game button. - WID_SGI_LOAD_GAME = ::WID_SGI_LOAD_GAME, ///< Load game button. - WID_SGI_PLAY_SCENARIO = ::WID_SGI_PLAY_SCENARIO, ///< Play scenario button. - WID_SGI_PLAY_HEIGHTMAP = ::WID_SGI_PLAY_HEIGHTMAP, ///< Play heightmap button. - WID_SGI_EDIT_SCENARIO = ::WID_SGI_EDIT_SCENARIO, ///< Edit scenario button. - WID_SGI_PLAY_NETWORK = ::WID_SGI_PLAY_NETWORK, ///< Play network button. - WID_SGI_TEMPERATE_LANDSCAPE = ::WID_SGI_TEMPERATE_LANDSCAPE, ///< Select temperate landscape button. - WID_SGI_ARCTIC_LANDSCAPE = ::WID_SGI_ARCTIC_LANDSCAPE, ///< Select arctic landscape button. - WID_SGI_TROPIC_LANDSCAPE = ::WID_SGI_TROPIC_LANDSCAPE, ///< Select tropic landscape button. - WID_SGI_TOYLAND_LANDSCAPE = ::WID_SGI_TOYLAND_LANDSCAPE, ///< Select toyland landscape button. - WID_SGI_TRANSLATION_SELECTION = ::WID_SGI_TRANSLATION_SELECTION, ///< Translation selection. - WID_SGI_TRANSLATION = ::WID_SGI_TRANSLATION, ///< Translation. - WID_SGI_OPTIONS = ::WID_SGI_OPTIONS, ///< Options button. - WID_SGI_HIGHSCORE = ::WID_SGI_HIGHSCORE, ///< Highscore button. - WID_SGI_SETTINGS_OPTIONS = ::WID_SGI_SETTINGS_OPTIONS, ///< Settings button. - WID_SGI_GRF_SETTINGS = ::WID_SGI_GRF_SETTINGS, ///< NewGRF button. - WID_SGI_CONTENT_DOWNLOAD = ::WID_SGI_CONTENT_DOWNLOAD, ///< Content Download button. - WID_SGI_AI_SETTINGS = ::WID_SGI_AI_SETTINGS, ///< AI button. - WID_SGI_EXIT = ::WID_SGI_EXIT, ///< Exit button. - }; - - /* automatically generated from ../../widgets/link_graph_legend_widget.h */ - /** Widgets of the WC_LINKGRAPH_LEGEND. */ - enum LinkGraphLegendWidgets { - WID_LGL_CAPTION = ::WID_LGL_CAPTION, ///< Caption widget. - WID_LGL_SATURATION = ::WID_LGL_SATURATION, ///< Saturation legend. - WID_LGL_SATURATION_FIRST = ::WID_LGL_SATURATION_FIRST, - WID_LGL_SATURATION_LAST = ::WID_LGL_SATURATION_LAST, - WID_LGL_COMPANIES = ::WID_LGL_COMPANIES, ///< Company selection widget. - WID_LGL_COMPANY_FIRST = ::WID_LGL_COMPANY_FIRST, - WID_LGL_COMPANY_LAST = ::WID_LGL_COMPANY_LAST, - WID_LGL_COMPANIES_ALL = ::WID_LGL_COMPANIES_ALL, - WID_LGL_COMPANIES_NONE = ::WID_LGL_COMPANIES_NONE, - WID_LGL_CARGOES = ::WID_LGL_CARGOES, ///< Cargo selection widget. - WID_LGL_CARGO_FIRST = ::WID_LGL_CARGO_FIRST, - WID_LGL_CARGO_LAST = ::WID_LGL_CARGO_LAST, - WID_LGL_CARGOES_ALL = ::WID_LGL_CARGOES_ALL, - WID_LGL_CARGOES_NONE = ::WID_LGL_CARGOES_NONE, - }; - - /* automatically generated from ../../widgets/main_widget.h */ - /** Widgets of the #MainWindow class. */ - enum MainWidgets { - WID_M_VIEWPORT = ::WID_M_VIEWPORT, ///< Main window viewport. - }; - - /* automatically generated from ../../widgets/misc_widget.h */ - /** Widgets of the #LandInfoWindow class. */ - enum LandInfoWidgets { - WID_LI_BACKGROUND = ::WID_LI_BACKGROUND, ///< Background of the window. - }; - - /** Widgets of the #TooltipsWindow class. */ - enum ToolTipsWidgets { - WID_TT_BACKGROUND = ::WID_TT_BACKGROUND, ///< Background of the window. - }; - - /** Widgets of the #AboutWindow class. */ - enum AboutWidgets { - WID_A_SCROLLING_TEXT = ::WID_A_SCROLLING_TEXT, ///< The actually scrolling text. - WID_A_WEBSITE = ::WID_A_WEBSITE, ///< URL of OpenTTD website. - }; - - /** Widgets of the #QueryStringWindow class. */ - enum QueryStringWidgets { - WID_QS_CAPTION = ::WID_QS_CAPTION, ///< Caption of the window. - WID_QS_TEXT = ::WID_QS_TEXT, ///< Text of the query. - WID_QS_DEFAULT = ::WID_QS_DEFAULT, ///< Default button. - WID_QS_CANCEL = ::WID_QS_CANCEL, ///< Cancel button. - WID_QS_OK = ::WID_QS_OK, ///< OK button. - }; - - /** Widgets of the #QueryWindow class. */ - enum QueryWidgets { - WID_Q_CAPTION = ::WID_Q_CAPTION, ///< Caption of the window. - WID_Q_TEXT = ::WID_Q_TEXT, ///< Text of the query. - WID_Q_NO = ::WID_Q_NO, ///< Yes button. - WID_Q_YES = ::WID_Q_YES, ///< No button. - }; - - /** Widgets of the #TextfileWindow class. */ - enum TextfileWidgets { - WID_TF_CAPTION = ::WID_TF_CAPTION, ///< The caption of the window. - WID_TF_WRAPTEXT = ::WID_TF_WRAPTEXT, ///< Whether or not to wrap the text. - WID_TF_BACKGROUND = ::WID_TF_BACKGROUND, ///< Panel to draw the textfile on. - WID_TF_VSCROLLBAR = ::WID_TF_VSCROLLBAR, ///< Vertical scrollbar to scroll through the textfile up-and-down. - WID_TF_HSCROLLBAR = ::WID_TF_HSCROLLBAR, ///< Horizontal scrollbar to scroll through the textfile left-to-right. - }; - - /* automatically generated from ../../widgets/music_widget.h */ - /** Widgets of the #MusicTrackSelectionWindow class. */ - enum MusicTrackSelectionWidgets { - WID_MTS_LIST_LEFT = ::WID_MTS_LIST_LEFT, ///< Left list. - WID_MTS_LEFT_SCROLLBAR = ::WID_MTS_LEFT_SCROLLBAR, ///< Scrollbar of left list. - WID_MTS_PLAYLIST = ::WID_MTS_PLAYLIST, ///< Playlist name. - WID_MTS_LIST_RIGHT = ::WID_MTS_LIST_RIGHT, ///< Right list. - WID_MTS_RIGHT_SCROLLBAR = ::WID_MTS_RIGHT_SCROLLBAR, ///< Scrollbar of right list. - WID_MTS_ALL = ::WID_MTS_ALL, ///< All button. - WID_MTS_OLD = ::WID_MTS_OLD, ///< Old button. - WID_MTS_NEW = ::WID_MTS_NEW, ///< New button. - WID_MTS_EZY = ::WID_MTS_EZY, ///< Ezy button. - WID_MTS_CUSTOM1 = ::WID_MTS_CUSTOM1, ///< Custom1 button. - WID_MTS_CUSTOM2 = ::WID_MTS_CUSTOM2, ///< Custom2 button. - WID_MTS_CLEAR = ::WID_MTS_CLEAR, ///< Clear button. - }; - - /** Widgets of the #MusicWindow class. */ - enum MusicWidgets { - WID_M_PREV = ::WID_M_PREV, ///< Previous button. - WID_M_NEXT = ::WID_M_NEXT, ///< Next button. - WID_M_STOP = ::WID_M_STOP, ///< Stop button. - WID_M_PLAY = ::WID_M_PLAY, ///< Play button. - WID_M_SLIDERS = ::WID_M_SLIDERS, ///< Sliders. - WID_M_MUSIC_VOL = ::WID_M_MUSIC_VOL, ///< Music volume. - WID_M_EFFECT_VOL = ::WID_M_EFFECT_VOL, ///< Effect volume. - WID_M_BACKGROUND = ::WID_M_BACKGROUND, ///< Background of the window. - WID_M_TRACK = ::WID_M_TRACK, ///< Track playing. - WID_M_TRACK_NR = ::WID_M_TRACK_NR, ///< Track number. - WID_M_TRACK_TITLE = ::WID_M_TRACK_TITLE, ///< Track title. - WID_M_TRACK_NAME = ::WID_M_TRACK_NAME, ///< Track name. - WID_M_SHUFFLE = ::WID_M_SHUFFLE, ///< Shuffle button. - WID_M_PROGRAMME = ::WID_M_PROGRAMME, ///< Program button. - WID_M_ALL = ::WID_M_ALL, ///< All button. - WID_M_OLD = ::WID_M_OLD, ///< Old button. - WID_M_NEW = ::WID_M_NEW, ///< New button. - WID_M_EZY = ::WID_M_EZY, ///< Ezy button. - WID_M_CUSTOM1 = ::WID_M_CUSTOM1, ///< Custom1 button. - WID_M_CUSTOM2 = ::WID_M_CUSTOM2, ///< Custom2 button. - }; - - /* automatically generated from ../../widgets/network_chat_widget.h */ - /** Widgets of the #NetworkChatWindow class. */ - enum NetWorkChatWidgets { - WID_NC_CLOSE = ::WID_NC_CLOSE, ///< Close button. - WID_NC_BACKGROUND = ::WID_NC_BACKGROUND, ///< Background of the window. - WID_NC_DESTINATION = ::WID_NC_DESTINATION, ///< Destination. - WID_NC_TEXTBOX = ::WID_NC_TEXTBOX, ///< Textbox. - WID_NC_SENDBUTTON = ::WID_NC_SENDBUTTON, ///< Send button. - }; - - /* automatically generated from ../../widgets/network_content_widget.h */ - /** Widgets of the #NetworkContentDownloadStatusWindow class. */ - enum NetworkContentDownloadStatusWidgets { - WID_NCDS_BACKGROUND = ::WID_NCDS_BACKGROUND, ///< Background of the window. - WID_NCDS_CANCELOK = ::WID_NCDS_CANCELOK, ///< (Optional) Cancel/OK button. - }; - - /** Widgets of the #NetworkContentListWindow class. */ - enum NetworkContentListWidgets { - WID_NCL_BACKGROUND = ::WID_NCL_BACKGROUND, ///< Resize button. - - WID_NCL_FILTER_CAPT = ::WID_NCL_FILTER_CAPT, ///< Caption for the filter editbox. - WID_NCL_FILTER = ::WID_NCL_FILTER, ///< Filter editbox. - - WID_NCL_CHECKBOX = ::WID_NCL_CHECKBOX, ///< Button above checkboxes. - WID_NCL_TYPE = ::WID_NCL_TYPE, ///< 'Type' button. - WID_NCL_NAME = ::WID_NCL_NAME, ///< 'Name' button. - - WID_NCL_MATRIX = ::WID_NCL_MATRIX, ///< Panel with list of content. - WID_NCL_SCROLLBAR = ::WID_NCL_SCROLLBAR, ///< Scrollbar of matrix. - - WID_NCL_DETAILS = ::WID_NCL_DETAILS, ///< Panel with content details. - WID_NCL_TEXTFILE = ::WID_NCL_TEXTFILE, ///< Open readme, changelog (+1) or license (+2) of a file in the content window. - - WID_NCL_SELECT_ALL = ::WID_NCL_SELECT_ALL, ///< 'Select all' button. - WID_NCL_SELECT_UPDATE = ::WID_NCL_SELECT_UPDATE, ///< 'Select updates' button. - WID_NCL_UNSELECT = ::WID_NCL_UNSELECT, ///< 'Unselect all' button. - WID_NCL_OPEN_URL = ::WID_NCL_OPEN_URL, ///< 'Open url' button. - WID_NCL_CANCEL = ::WID_NCL_CANCEL, ///< 'Cancel' button. - WID_NCL_DOWNLOAD = ::WID_NCL_DOWNLOAD, ///< 'Download' button. - - WID_NCL_SEL_ALL_UPDATE = ::WID_NCL_SEL_ALL_UPDATE, ///< #NWID_SELECTION widget for select all/update buttons.. - WID_NCL_SEARCH_EXTERNAL = ::WID_NCL_SEARCH_EXTERNAL, ///< Search external sites for missing NewGRF. - }; - - /* automatically generated from ../../widgets/network_widget.h */ - /** Widgets of the #NetworkGameWindow class. */ - enum NetworkGameWidgets { - WID_NG_MAIN = ::WID_NG_MAIN, ///< Main panel. - - WID_NG_CONNECTION = ::WID_NG_CONNECTION, ///< Label in front of connection droplist. - WID_NG_CONN_BTN = ::WID_NG_CONN_BTN, ///< 'Connection' droplist button. - WID_NG_CLIENT_LABEL = ::WID_NG_CLIENT_LABEL, ///< Label in front of client name edit box. - WID_NG_CLIENT = ::WID_NG_CLIENT, ///< Panel with editbox to set client name. - WID_NG_FILTER_LABEL = ::WID_NG_FILTER_LABEL, ///< Label in front of the filter/search edit box. - WID_NG_FILTER = ::WID_NG_FILTER, ///< Panel with the edit box to enter the search text. - - WID_NG_HEADER = ::WID_NG_HEADER, ///< Header container of the matrix. - WID_NG_NAME = ::WID_NG_NAME, ///< 'Name' button. - WID_NG_CLIENTS = ::WID_NG_CLIENTS, ///< 'Clients' button. - WID_NG_MAPSIZE = ::WID_NG_MAPSIZE, ///< 'Map size' button. - WID_NG_DATE = ::WID_NG_DATE, ///< 'Date' button. - WID_NG_YEARS = ::WID_NG_YEARS, ///< 'Years' button. - WID_NG_INFO = ::WID_NG_INFO, ///< Third button in the game list panel. - - WID_NG_MATRIX = ::WID_NG_MATRIX, ///< Panel with list of games. - WID_NG_SCROLLBAR = ::WID_NG_SCROLLBAR, ///< Scrollbar of matrix. - - WID_NG_LASTJOINED_LABEL = ::WID_NG_LASTJOINED_LABEL, ///< Label "Last joined server:". - WID_NG_LASTJOINED = ::WID_NG_LASTJOINED, ///< Info about the last joined server. - WID_NG_LASTJOINED_SPACER = ::WID_NG_LASTJOINED_SPACER, ///< Spacer after last joined server panel. - - WID_NG_DETAILS = ::WID_NG_DETAILS, ///< Panel with game details. - WID_NG_DETAILS_SPACER = ::WID_NG_DETAILS_SPACER, ///< Spacer for game actual details. - WID_NG_JOIN = ::WID_NG_JOIN, ///< 'Join game' button. - WID_NG_REFRESH = ::WID_NG_REFRESH, ///< 'Refresh server' button. - WID_NG_NEWGRF = ::WID_NG_NEWGRF, ///< 'NewGRF Settings' button. - WID_NG_NEWGRF_SEL = ::WID_NG_NEWGRF_SEL, ///< Selection 'widget' to hide the NewGRF settings. - WID_NG_NEWGRF_MISSING = ::WID_NG_NEWGRF_MISSING, ///< 'Find missing NewGRF online' button. - WID_NG_NEWGRF_MISSING_SEL = ::WID_NG_NEWGRF_MISSING_SEL, ///< Selection widget for the above button. - - WID_NG_FIND = ::WID_NG_FIND, ///< 'Find server' button. - WID_NG_ADD = ::WID_NG_ADD, ///< 'Add server' button. - WID_NG_START = ::WID_NG_START, ///< 'Start server' button. - WID_NG_CANCEL = ::WID_NG_CANCEL, ///< 'Cancel' button. - }; - - /** Widgets of the #NetworkStartServerWindow class. */ - enum NetworkStartServerWidgets { - WID_NSS_BACKGROUND = ::WID_NSS_BACKGROUND, ///< Background of the window. - WID_NSS_GAMENAME_LABEL = ::WID_NSS_GAMENAME_LABEL, ///< Label for the game name. - WID_NSS_GAMENAME = ::WID_NSS_GAMENAME, ///< Background for editbox to set game name. - WID_NSS_SETPWD = ::WID_NSS_SETPWD, ///< 'Set password' button. - WID_NSS_CONNTYPE_LABEL = ::WID_NSS_CONNTYPE_LABEL, ///< Label for 'connection type'. - WID_NSS_CONNTYPE_BTN = ::WID_NSS_CONNTYPE_BTN, ///< 'Connection type' droplist button. - WID_NSS_CLIENTS_LABEL = ::WID_NSS_CLIENTS_LABEL, ///< Label for 'max clients'. - WID_NSS_CLIENTS_BTND = ::WID_NSS_CLIENTS_BTND, ///< 'Max clients' downarrow. - WID_NSS_CLIENTS_TXT = ::WID_NSS_CLIENTS_TXT, ///< 'Max clients' text. - WID_NSS_CLIENTS_BTNU = ::WID_NSS_CLIENTS_BTNU, ///< 'Max clients' uparrow. - WID_NSS_COMPANIES_LABEL = ::WID_NSS_COMPANIES_LABEL, ///< Label for 'max companies'. - WID_NSS_COMPANIES_BTND = ::WID_NSS_COMPANIES_BTND, ///< 'Max companies' downarrow. - WID_NSS_COMPANIES_TXT = ::WID_NSS_COMPANIES_TXT, ///< 'Max companies' text. - WID_NSS_COMPANIES_BTNU = ::WID_NSS_COMPANIES_BTNU, ///< 'Max companies' uparrow. - WID_NSS_SPECTATORS_LABEL = ::WID_NSS_SPECTATORS_LABEL, ///< Label for 'max spectators'. - WID_NSS_SPECTATORS_BTND = ::WID_NSS_SPECTATORS_BTND, ///< 'Max spectators' downarrow. - WID_NSS_SPECTATORS_TXT = ::WID_NSS_SPECTATORS_TXT, ///< 'Max spectators' text. - WID_NSS_SPECTATORS_BTNU = ::WID_NSS_SPECTATORS_BTNU, ///< 'Max spectators' uparrow. - - WID_NSS_LANGUAGE_LABEL = ::WID_NSS_LANGUAGE_LABEL, ///< Label for 'language spoken'. - WID_NSS_LANGUAGE_BTN = ::WID_NSS_LANGUAGE_BTN, ///< 'Language spoken' droplist button. - - WID_NSS_GENERATE_GAME = ::WID_NSS_GENERATE_GAME, ///< New game button. - WID_NSS_LOAD_GAME = ::WID_NSS_LOAD_GAME, ///< Load game button. - WID_NSS_PLAY_SCENARIO = ::WID_NSS_PLAY_SCENARIO, ///< Play scenario button. - WID_NSS_PLAY_HEIGHTMAP = ::WID_NSS_PLAY_HEIGHTMAP, ///< Play heightmap button. - - WID_NSS_CANCEL = ::WID_NSS_CANCEL, ///< 'Cancel' button. - }; - - /** Widgets of the #NetworkLobbyWindow class. */ - enum NetworkLobbyWidgets { - WID_NL_BACKGROUND = ::WID_NL_BACKGROUND, ///< Background of the window. - WID_NL_TEXT = ::WID_NL_TEXT, ///< Heading text. - WID_NL_HEADER = ::WID_NL_HEADER, ///< Header above list of companies. - WID_NL_MATRIX = ::WID_NL_MATRIX, ///< List of companies. - WID_NL_SCROLLBAR = ::WID_NL_SCROLLBAR, ///< Scroll bar. - WID_NL_DETAILS = ::WID_NL_DETAILS, ///< Company details. - WID_NL_JOIN = ::WID_NL_JOIN, ///< 'Join company' button. - WID_NL_NEW = ::WID_NL_NEW, ///< 'New company' button. - WID_NL_SPECTATE = ::WID_NL_SPECTATE, ///< 'Spectate game' button. - WID_NL_REFRESH = ::WID_NL_REFRESH, ///< 'Refresh server' button. - WID_NL_CANCEL = ::WID_NL_CANCEL, ///< 'Cancel' button. - }; - - /** Widgets of the #NetworkClientListWindow class. */ - enum ClientListWidgets { - WID_CL_PANEL = ::WID_CL_PANEL, ///< Panel of the window. - }; - - /** Widgets of the #NetworkClientListPopupWindow class. */ - enum ClientListPopupWidgets { - WID_CLP_PANEL = ::WID_CLP_PANEL, ///< Panel of the window. - }; - - /** Widgets of the #NetworkJoinStatusWindow class. */ - enum NetworkJoinStatusWidgets { - WID_NJS_BACKGROUND = ::WID_NJS_BACKGROUND, ///< Background of the window. - WID_NJS_CANCELOK = ::WID_NJS_CANCELOK, ///< Cancel / OK button. - }; - - /** Widgets of the #NetworkCompanyPasswordWindow class. */ - enum NetworkCompanyPasswordWidgets { - WID_NCP_BACKGROUND = ::WID_NCP_BACKGROUND, ///< Background of the window. - WID_NCP_LABEL = ::WID_NCP_LABEL, ///< Label in front of the password field. - WID_NCP_PASSWORD = ::WID_NCP_PASSWORD, ///< Input field for the password. - WID_NCP_SAVE_AS_DEFAULT_PASSWORD = ::WID_NCP_SAVE_AS_DEFAULT_PASSWORD, ///< Toggle 'button' for saving the current password as default password. - WID_NCP_CANCEL = ::WID_NCP_CANCEL, ///< Close the window without changing anything. - WID_NCP_OK = ::WID_NCP_OK, ///< Safe the password etc. - }; - - /* automatically generated from ../../widgets/newgrf_debug_widget.h */ - /** Widgets of the #NewGRFInspectWindow class. */ - enum NewGRFInspectWidgets { - WID_NGRFI_CAPTION = ::WID_NGRFI_CAPTION, ///< The caption bar of course. - WID_NGRFI_PARENT = ::WID_NGRFI_PARENT, ///< Inspect the parent. - WID_NGRFI_VEH_PREV = ::WID_NGRFI_VEH_PREV, ///< Go to previous vehicle in chain. - WID_NGRFI_VEH_NEXT = ::WID_NGRFI_VEH_NEXT, ///< Go to next vehicle in chain. - WID_NGRFI_VEH_CHAIN = ::WID_NGRFI_VEH_CHAIN, ///< Display for vehicle chain. - WID_NGRFI_MAINPANEL = ::WID_NGRFI_MAINPANEL, ///< Panel widget containing the actual data. - WID_NGRFI_SCROLLBAR = ::WID_NGRFI_SCROLLBAR, ///< Scrollbar. - }; - - /** Widgets of the #SpriteAlignerWindow class. */ - enum SpriteAlignerWidgets { - WID_SA_CAPTION = ::WID_SA_CAPTION, ///< Caption of the window. - WID_SA_PREVIOUS = ::WID_SA_PREVIOUS, ///< Skip to the previous sprite. - WID_SA_GOTO = ::WID_SA_GOTO, ///< Go to a given sprite. - WID_SA_NEXT = ::WID_SA_NEXT, ///< Skip to the next sprite. - WID_SA_UP = ::WID_SA_UP, ///< Move the sprite up. - WID_SA_LEFT = ::WID_SA_LEFT, ///< Move the sprite to the left. - WID_SA_RIGHT = ::WID_SA_RIGHT, ///< Move the sprite to the right. - WID_SA_DOWN = ::WID_SA_DOWN, ///< Move the sprite down. - WID_SA_SPRITE = ::WID_SA_SPRITE, ///< The actual sprite. - WID_SA_OFFSETS = ::WID_SA_OFFSETS, ///< The sprite offsets. - WID_SA_PICKER = ::WID_SA_PICKER, ///< Sprite picker. - WID_SA_LIST = ::WID_SA_LIST, ///< Queried sprite list. - WID_SA_SCROLLBAR = ::WID_SA_SCROLLBAR, ///< Scrollbar for sprite list. - }; - - /* automatically generated from ../../widgets/newgrf_widget.h */ - /** Widgets of the #NewGRFParametersWindow class. */ - enum NewGRFParametersWidgets { - WID_NP_SHOW_NUMPAR = ::WID_NP_SHOW_NUMPAR, ///< #NWID_SELECTION to optionally display #WID_NP_NUMPAR. - WID_NP_NUMPAR_DEC = ::WID_NP_NUMPAR_DEC, ///< Button to decrease number of parameters. - WID_NP_NUMPAR_INC = ::WID_NP_NUMPAR_INC, ///< Button to increase number of parameters. - WID_NP_NUMPAR = ::WID_NP_NUMPAR, ///< Optional number of parameters. - WID_NP_NUMPAR_TEXT = ::WID_NP_NUMPAR_TEXT, ///< Text description. - WID_NP_BACKGROUND = ::WID_NP_BACKGROUND, ///< Panel to draw the settings on. - WID_NP_SCROLLBAR = ::WID_NP_SCROLLBAR, ///< Scrollbar to scroll through all settings. - WID_NP_ACCEPT = ::WID_NP_ACCEPT, ///< Accept button. - WID_NP_RESET = ::WID_NP_RESET, ///< Reset button. - WID_NP_SHOW_DESCRIPTION = ::WID_NP_SHOW_DESCRIPTION, ///< #NWID_SELECTION to optionally display parameter descriptions. - WID_NP_DESCRIPTION = ::WID_NP_DESCRIPTION, ///< Multi-line description of a parameter. - }; - - /** Widgets of the #NewGRFWindow class. */ - enum NewGRFStateWidgets { - WID_NS_PRESET_LIST = ::WID_NS_PRESET_LIST, ///< Active NewGRF preset. - WID_NS_PRESET_SAVE = ::WID_NS_PRESET_SAVE, ///< Save list of active NewGRFs as presets. - WID_NS_PRESET_DELETE = ::WID_NS_PRESET_DELETE, ///< Delete active preset. - WID_NS_ADD = ::WID_NS_ADD, ///< Add NewGRF to active list. - WID_NS_REMOVE = ::WID_NS_REMOVE, ///< Remove NewGRF from active list. - WID_NS_MOVE_UP = ::WID_NS_MOVE_UP, ///< Move NewGRF up in active list. - WID_NS_MOVE_DOWN = ::WID_NS_MOVE_DOWN, ///< Move NewGRF down in active list. - WID_NS_FILTER = ::WID_NS_FILTER, ///< Filter list of available NewGRFs. - WID_NS_FILE_LIST = ::WID_NS_FILE_LIST, ///< List window of active NewGRFs. - WID_NS_SCROLLBAR = ::WID_NS_SCROLLBAR, ///< Scrollbar for active NewGRF list. - WID_NS_AVAIL_LIST = ::WID_NS_AVAIL_LIST, ///< List window of available NewGRFs. - WID_NS_SCROLL2BAR = ::WID_NS_SCROLL2BAR, ///< Scrollbar for available NewGRF list. - WID_NS_NEWGRF_INFO_TITLE = ::WID_NS_NEWGRF_INFO_TITLE, ///< Title for Info on selected NewGRF. - WID_NS_NEWGRF_INFO = ::WID_NS_NEWGRF_INFO, ///< Panel for Info on selected NewGRF. - WID_NS_OPEN_URL = ::WID_NS_OPEN_URL, ///< Open URL of NewGRF. - WID_NS_NEWGRF_TEXTFILE = ::WID_NS_NEWGRF_TEXTFILE, ///< Open NewGRF readme, changelog (+1) or license (+2). - WID_NS_SET_PARAMETERS = ::WID_NS_SET_PARAMETERS, ///< Open Parameters Window for selected NewGRF for editing parameters. - WID_NS_VIEW_PARAMETERS = ::WID_NS_VIEW_PARAMETERS, ///< Open Parameters Window for selected NewGRF for viewing parameters. - WID_NS_TOGGLE_PALETTE = ::WID_NS_TOGGLE_PALETTE, ///< Toggle Palette of selected, active NewGRF. - WID_NS_APPLY_CHANGES = ::WID_NS_APPLY_CHANGES, ///< Apply changes to NewGRF config. - WID_NS_RESCAN_FILES = ::WID_NS_RESCAN_FILES, ///< Rescan files (available NewGRFs). - WID_NS_RESCAN_FILES2 = ::WID_NS_RESCAN_FILES2, ///< Rescan files (active NewGRFs). - WID_NS_CONTENT_DOWNLOAD = ::WID_NS_CONTENT_DOWNLOAD, ///< Open content download (available NewGRFs). - WID_NS_CONTENT_DOWNLOAD2 = ::WID_NS_CONTENT_DOWNLOAD2, ///< Open content download (active NewGRFs). - WID_NS_SHOW_REMOVE = ::WID_NS_SHOW_REMOVE, ///< Select active list buttons (0, 1 = simple layout). - WID_NS_SHOW_APPLY = ::WID_NS_SHOW_APPLY, ///< Select display of the buttons below the 'details'. - }; - - /** Widgets of the #ScanProgressWindow class. */ - enum ScanProgressWidgets { - WID_SP_PROGRESS_BAR = ::WID_SP_PROGRESS_BAR, ///< Simple progress bar. - WID_SP_PROGRESS_TEXT = ::WID_SP_PROGRESS_TEXT, ///< Text explaining what is happening. - }; - - /* automatically generated from ../../widgets/news_widget.h */ - /** Widgets of the #NewsWindow class. */ - enum NewsWidgets { - WID_N_PANEL = ::WID_N_PANEL, ///< Panel of the window. - WID_N_TITLE = ::WID_N_TITLE, ///< Title of the company news. - WID_N_HEADLINE = ::WID_N_HEADLINE, ///< The news headline. - WID_N_CLOSEBOX = ::WID_N_CLOSEBOX, ///< Close the window. - WID_N_DATE = ::WID_N_DATE, ///< Date of the news item. - WID_N_CAPTION = ::WID_N_CAPTION, ///< Title bar of the window. Only used in small news items. - WID_N_INSET = ::WID_N_INSET, ///< Inset around the viewport in the window. Only used in small news items. - WID_N_VIEWPORT = ::WID_N_VIEWPORT, ///< Viewport in the window. - WID_N_COMPANY_MSG = ::WID_N_COMPANY_MSG, ///< Message in company news items. - WID_N_MESSAGE = ::WID_N_MESSAGE, ///< Space for displaying the message. Only used in small news items. - WID_N_MGR_FACE = ::WID_N_MGR_FACE, ///< Face of the manager. - WID_N_MGR_NAME = ::WID_N_MGR_NAME, ///< Name of the manager. - WID_N_VEH_TITLE = ::WID_N_VEH_TITLE, ///< Vehicle new title. - WID_N_VEH_BKGND = ::WID_N_VEH_BKGND, ///< Dark background of new vehicle news. - WID_N_VEH_NAME = ::WID_N_VEH_NAME, ///< Name of the new vehicle. - WID_N_VEH_SPR = ::WID_N_VEH_SPR, ///< Graphical display of the new vehicle. - WID_N_VEH_INFO = ::WID_N_VEH_INFO, ///< Some technical data of the new vehicle. - }; - - /** Widgets of the #MessageHistoryWindow class. */ - enum MessageHistoryWidgets { - WID_MH_STICKYBOX = ::WID_MH_STICKYBOX, ///< Stickybox. - WID_MH_BACKGROUND = ::WID_MH_BACKGROUND, ///< Background of the window. - WID_MH_SCROLLBAR = ::WID_MH_SCROLLBAR, ///< Scrollbar for the list. - }; - - /* automatically generated from ../../widgets/object_widget.h */ - /** Widgets of the #BuildObjectWindow class. */ - enum BuildObjectWidgets { - WID_BO_CLASS_LIST = ::WID_BO_CLASS_LIST, ///< The list with classes. - WID_BO_SCROLLBAR = ::WID_BO_SCROLLBAR, ///< The scrollbar associated with the list. - WID_BO_OBJECT_MATRIX = ::WID_BO_OBJECT_MATRIX, ///< The matrix with preview sprites. - WID_BO_OBJECT_SPRITE = ::WID_BO_OBJECT_SPRITE, ///< A preview sprite of the object. - WID_BO_OBJECT_NAME = ::WID_BO_OBJECT_NAME, ///< The name of the selected object. - WID_BO_OBJECT_SIZE = ::WID_BO_OBJECT_SIZE, ///< The size of the selected object. - WID_BO_INFO = ::WID_BO_INFO, ///< Other information about the object (from the NewGRF). - - WID_BO_SELECT_MATRIX = ::WID_BO_SELECT_MATRIX, ///< Selection preview matrix of objects of a given class. - WID_BO_SELECT_IMAGE = ::WID_BO_SELECT_IMAGE, ///< Preview image in the #WID_BO_SELECT_MATRIX. - WID_BO_SELECT_SCROLL = ::WID_BO_SELECT_SCROLL, ///< Scrollbar next to the #WID_BO_SELECT_MATRIX. - }; - - /* automatically generated from ../../widgets/order_widget.h */ - /** Widgets of the #OrdersWindow class. */ - enum OrderWidgets { - WID_O_CAPTION = ::WID_O_CAPTION, ///< Caption of the window. - WID_O_TIMETABLE_VIEW = ::WID_O_TIMETABLE_VIEW, ///< Toggle timetable view. - WID_O_ORDER_LIST = ::WID_O_ORDER_LIST, ///< Order list panel. - WID_O_SCROLLBAR = ::WID_O_SCROLLBAR, ///< Order list scrollbar. - WID_O_SKIP = ::WID_O_SKIP, ///< Skip current order. - WID_O_DELETE = ::WID_O_DELETE, ///< Delete selected order. - WID_O_STOP_SHARING = ::WID_O_STOP_SHARING, ///< Stop sharing orders. - WID_O_NON_STOP = ::WID_O_NON_STOP, ///< Goto non-stop to destination. - WID_O_GOTO = ::WID_O_GOTO, ///< Goto destination. - WID_O_FULL_LOAD = ::WID_O_FULL_LOAD, ///< Select full load. - WID_O_UNLOAD = ::WID_O_UNLOAD, ///< Select unload. - WID_O_REFIT = ::WID_O_REFIT, ///< Select refit. - WID_O_SERVICE = ::WID_O_SERVICE, ///< Select service (at depot). - WID_O_EMPTY = ::WID_O_EMPTY, ///< Placeholder for refit dropdown when not owner. - WID_O_REFIT_DROPDOWN = ::WID_O_REFIT_DROPDOWN, ///< Open refit options. - WID_O_COND_VARIABLE = ::WID_O_COND_VARIABLE, ///< Choose condition variable. - WID_O_COND_COMPARATOR = ::WID_O_COND_COMPARATOR, ///< Choose condition type. - WID_O_COND_VALUE = ::WID_O_COND_VALUE, ///< Choose condition value. - WID_O_SEL_TOP_LEFT = ::WID_O_SEL_TOP_LEFT, ///< #NWID_SELECTION widget for left part of the top row of the 'your train' order window. - WID_O_SEL_TOP_MIDDLE = ::WID_O_SEL_TOP_MIDDLE, ///< #NWID_SELECTION widget for middle part of the top row of the 'your train' order window. - WID_O_SEL_TOP_RIGHT = ::WID_O_SEL_TOP_RIGHT, ///< #NWID_SELECTION widget for right part of the top row of the 'your train' order window. - WID_O_SEL_TOP_ROW_GROUNDVEHICLE = ::WID_O_SEL_TOP_ROW_GROUNDVEHICLE, ///< #NWID_SELECTION widget for the top row of the 'your train' order window. - WID_O_SEL_TOP_ROW = ::WID_O_SEL_TOP_ROW, ///< #NWID_SELECTION widget for the top row of the 'your non-trains' order window. - WID_O_SEL_BOTTOM_MIDDLE = ::WID_O_SEL_BOTTOM_MIDDLE, ///< #NWID_SELECTION widget for the middle part of the bottom row of the 'your train' order window. - WID_O_SHARED_ORDER_LIST = ::WID_O_SHARED_ORDER_LIST, ///< Open list of shared vehicles. - }; - - /* automatically generated from ../../widgets/osk_widget.h */ - /** Widgets of the #OskWindow class. */ - enum OnScreenKeyboardWidgets { - WID_OSK_CAPTION = ::WID_OSK_CAPTION, ///< Caption of window. - WID_OSK_TEXT = ::WID_OSK_TEXT, ///< Edit box. - WID_OSK_CANCEL = ::WID_OSK_CANCEL, ///< Cancel key. - WID_OSK_OK = ::WID_OSK_OK, ///< Ok key. - WID_OSK_BACKSPACE = ::WID_OSK_BACKSPACE, ///< Backspace key. - WID_OSK_SPECIAL = ::WID_OSK_SPECIAL, ///< Special key (at keyboards often used for tab key). - WID_OSK_CAPS = ::WID_OSK_CAPS, ///< Capslock key. - WID_OSK_SHIFT = ::WID_OSK_SHIFT, ///< Shift(lock) key. - WID_OSK_SPACE = ::WID_OSK_SPACE, ///< Space bar. - WID_OSK_LEFT = ::WID_OSK_LEFT, ///< Cursor left key. - WID_OSK_RIGHT = ::WID_OSK_RIGHT, ///< Cursor right key. - WID_OSK_LETTERS = ::WID_OSK_LETTERS, ///< First widget of the 'normal' keys. - - WID_OSK_NUMBERS_FIRST = ::WID_OSK_NUMBERS_FIRST, ///< First widget of the numbers row. - WID_OSK_NUMBERS_LAST = ::WID_OSK_NUMBERS_LAST, ///< Last widget of the numbers row. - - WID_OSK_QWERTY_FIRST = ::WID_OSK_QWERTY_FIRST, ///< First widget of the qwerty row. - WID_OSK_QWERTY_LAST = ::WID_OSK_QWERTY_LAST, ///< Last widget of the qwerty row. - - WID_OSK_ASDFG_FIRST = ::WID_OSK_ASDFG_FIRST, ///< First widget of the asdfg row. - WID_OSK_ASDFG_LAST = ::WID_OSK_ASDFG_LAST, ///< Last widget of the asdfg row. - - WID_OSK_ZXCVB_FIRST = ::WID_OSK_ZXCVB_FIRST, ///< First widget of the zxcvb row. - WID_OSK_ZXCVB_LAST = ::WID_OSK_ZXCVB_LAST, ///< Last widget of the zxcvb row. - }; - - /* automatically generated from ../../widgets/rail_widget.h */ - /** Widgets of the #BuildRailToolbarWindow class. */ - enum RailToolbarWidgets { - /* Name starts with RA instead of R, because of collision with RoadToolbarWidgets */ - WID_RAT_CAPTION = ::WID_RAT_CAPTION, ///< Caption of the window. - WID_RAT_BUILD_NS = ::WID_RAT_BUILD_NS, ///< Build rail along the game view Y axis. - WID_RAT_BUILD_X = ::WID_RAT_BUILD_X, ///< Build rail along the game grid X axis. - WID_RAT_BUILD_EW = ::WID_RAT_BUILD_EW, ///< Build rail along the game view X axis. - WID_RAT_BUILD_Y = ::WID_RAT_BUILD_Y, ///< Build rail along the game grid Y axis. - WID_RAT_AUTORAIL = ::WID_RAT_AUTORAIL, ///< Autorail tool. - WID_RAT_DEMOLISH = ::WID_RAT_DEMOLISH, ///< Destroy something with dynamite! - WID_RAT_BUILD_DEPOT = ::WID_RAT_BUILD_DEPOT, ///< Build a depot. - WID_RAT_BUILD_WAYPOINT = ::WID_RAT_BUILD_WAYPOINT, ///< Build a waypoint. - WID_RAT_BUILD_STATION = ::WID_RAT_BUILD_STATION, ///< Build a station. - WID_RAT_BUILD_SIGNALS = ::WID_RAT_BUILD_SIGNALS, ///< Build signals. - WID_RAT_BUILD_BRIDGE = ::WID_RAT_BUILD_BRIDGE, ///< Build a bridge. - WID_RAT_BUILD_TUNNEL = ::WID_RAT_BUILD_TUNNEL, ///< Build a tunnel. - WID_RAT_REMOVE = ::WID_RAT_REMOVE, ///< Bulldozer to remove rail. - WID_RAT_CONVERT_RAIL = ::WID_RAT_CONVERT_RAIL, ///< Convert other rail to this type. - }; - - /** Widgets of the #BuildRailStationWindow class. */ - enum BuildRailStationWidgets { - /* Name starts with BRA instead of BR, because of collision with BuildRoadStationWidgets */ - WID_BRAS_PLATFORM_DIR_X = ::WID_BRAS_PLATFORM_DIR_X, ///< Button to select '/' view. - WID_BRAS_PLATFORM_DIR_Y = ::WID_BRAS_PLATFORM_DIR_Y, ///< Button to select '\' view. - - WID_BRAS_PLATFORM_NUM_1 = ::WID_BRAS_PLATFORM_NUM_1, ///< Button to select stations with a single platform. - WID_BRAS_PLATFORM_NUM_2 = ::WID_BRAS_PLATFORM_NUM_2, ///< Button to select stations with 2 platforms. - WID_BRAS_PLATFORM_NUM_3 = ::WID_BRAS_PLATFORM_NUM_3, ///< Button to select stations with 3 platforms. - WID_BRAS_PLATFORM_NUM_4 = ::WID_BRAS_PLATFORM_NUM_4, ///< Button to select stations with 4 platforms. - WID_BRAS_PLATFORM_NUM_5 = ::WID_BRAS_PLATFORM_NUM_5, ///< Button to select stations with 5 platforms. - WID_BRAS_PLATFORM_NUM_6 = ::WID_BRAS_PLATFORM_NUM_6, ///< Button to select stations with 6 platforms. - WID_BRAS_PLATFORM_NUM_7 = ::WID_BRAS_PLATFORM_NUM_7, ///< Button to select stations with 7 platforms. - - WID_BRAS_PLATFORM_LEN_1 = ::WID_BRAS_PLATFORM_LEN_1, ///< Button to select single tile length station platforms. - WID_BRAS_PLATFORM_LEN_2 = ::WID_BRAS_PLATFORM_LEN_2, ///< Button to select 2 tiles length station platforms. - WID_BRAS_PLATFORM_LEN_3 = ::WID_BRAS_PLATFORM_LEN_3, ///< Button to select 3 tiles length station platforms. - WID_BRAS_PLATFORM_LEN_4 = ::WID_BRAS_PLATFORM_LEN_4, ///< Button to select 4 tiles length station platforms. - WID_BRAS_PLATFORM_LEN_5 = ::WID_BRAS_PLATFORM_LEN_5, ///< Button to select 5 tiles length station platforms. - WID_BRAS_PLATFORM_LEN_6 = ::WID_BRAS_PLATFORM_LEN_6, ///< Button to select 6 tiles length station platforms. - WID_BRAS_PLATFORM_LEN_7 = ::WID_BRAS_PLATFORM_LEN_7, ///< Button to select 7 tiles length station platforms. - - WID_BRAS_PLATFORM_DRAG_N_DROP = ::WID_BRAS_PLATFORM_DRAG_N_DROP, ///< Button to enable drag and drop type station placement. - - WID_BRAS_HIGHLIGHT_OFF = ::WID_BRAS_HIGHLIGHT_OFF, ///< Button for turning coverage highlighting off. - WID_BRAS_HIGHLIGHT_ON = ::WID_BRAS_HIGHLIGHT_ON, ///< Button for turning coverage highlighting on. - WID_BRAS_COVERAGE_TEXTS = ::WID_BRAS_COVERAGE_TEXTS, ///< Empty space for the coverage texts. - - WID_BRAS_MATRIX = ::WID_BRAS_MATRIX, ///< Matrix widget displaying the available stations. - WID_BRAS_IMAGE = ::WID_BRAS_IMAGE, ///< Panel used at each cell of the matrix. - WID_BRAS_MATRIX_SCROLL = ::WID_BRAS_MATRIX_SCROLL, ///< Scrollbar of the matrix widget. - - WID_BRAS_SHOW_NEWST_DEFSIZE = ::WID_BRAS_SHOW_NEWST_DEFSIZE, ///< Selection for default-size button for newstation. - WID_BRAS_SHOW_NEWST_ADDITIONS = ::WID_BRAS_SHOW_NEWST_ADDITIONS, ///< Selection for newstation class selection list. - WID_BRAS_SHOW_NEWST_MATRIX = ::WID_BRAS_SHOW_NEWST_MATRIX, ///< Selection for newstation image matrix. - WID_BRAS_SHOW_NEWST_RESIZE = ::WID_BRAS_SHOW_NEWST_RESIZE, ///< Selection for panel and resize at bottom right for newstation. - WID_BRAS_SHOW_NEWST_TYPE = ::WID_BRAS_SHOW_NEWST_TYPE, ///< Display of selected station type. - WID_BRAS_NEWST_LIST = ::WID_BRAS_NEWST_LIST, ///< List with available newstation classes. - WID_BRAS_NEWST_SCROLL = ::WID_BRAS_NEWST_SCROLL, ///< Scrollbar of the #WID_BRAS_NEWST_LIST. - - WID_BRAS_PLATFORM_NUM_BEGIN = ::WID_BRAS_PLATFORM_NUM_BEGIN, ///< Helper for determining the chosen platform width. - WID_BRAS_PLATFORM_LEN_BEGIN = ::WID_BRAS_PLATFORM_LEN_BEGIN, ///< Helper for determining the chosen platform length. - }; - - /** Widgets of the #BuildSignalWindow class. */ - enum BuildSignalWidgets { - WID_BS_SEMAPHORE_NORM = ::WID_BS_SEMAPHORE_NORM, ///< Build a semaphore normal block signal - WID_BS_SEMAPHORE_ENTRY = ::WID_BS_SEMAPHORE_ENTRY, ///< Build a semaphore entry block signal - WID_BS_SEMAPHORE_EXIT = ::WID_BS_SEMAPHORE_EXIT, ///< Build a semaphore exit block signal - WID_BS_SEMAPHORE_COMBO = ::WID_BS_SEMAPHORE_COMBO, ///< Build a semaphore combo block signal - WID_BS_SEMAPHORE_PBS = ::WID_BS_SEMAPHORE_PBS, ///< Build a semaphore path signal. - WID_BS_SEMAPHORE_PBS_OWAY = ::WID_BS_SEMAPHORE_PBS_OWAY, ///< Build a semaphore one way path signal. - WID_BS_ELECTRIC_NORM = ::WID_BS_ELECTRIC_NORM, ///< Build an electric normal block signal - WID_BS_ELECTRIC_ENTRY = ::WID_BS_ELECTRIC_ENTRY, ///< Build an electric entry block signal - WID_BS_ELECTRIC_EXIT = ::WID_BS_ELECTRIC_EXIT, ///< Build an electric exit block signal - WID_BS_ELECTRIC_COMBO = ::WID_BS_ELECTRIC_COMBO, ///< Build an electric combo block signal - WID_BS_ELECTRIC_PBS = ::WID_BS_ELECTRIC_PBS, ///< Build an electric path signal. - WID_BS_ELECTRIC_PBS_OWAY = ::WID_BS_ELECTRIC_PBS_OWAY, ///< Build an electric one way path signal. - WID_BS_CONVERT = ::WID_BS_CONVERT, ///< Convert the signal. - WID_BS_DRAG_SIGNALS_DENSITY_LABEL = ::WID_BS_DRAG_SIGNALS_DENSITY_LABEL, ///< The current signal density. - WID_BS_DRAG_SIGNALS_DENSITY_DECREASE = ::WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, ///< Decrease the signal density. - WID_BS_DRAG_SIGNALS_DENSITY_INCREASE = ::WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, ///< Increase the signal density. - }; - - /** Widgets of the #BuildRailDepotWindow class. */ - enum BuildRailDepotWidgets { - /* Name starts with BRA instead of BR, because of collision with BuildRoadDepotWidgets */ - WID_BRAD_DEPOT_NE = ::WID_BRAD_DEPOT_NE, ///< Build a depot with the entrance in the north east. - WID_BRAD_DEPOT_SE = ::WID_BRAD_DEPOT_SE, ///< Build a depot with the entrance in the south east. - WID_BRAD_DEPOT_SW = ::WID_BRAD_DEPOT_SW, ///< Build a depot with the entrance in the south west. - WID_BRAD_DEPOT_NW = ::WID_BRAD_DEPOT_NW, ///< Build a depot with the entrance in the north west. - }; - - /** Widgets of the #BuildRailWaypointWindow class. */ - enum BuildRailWaypointWidgets { - WID_BRW_WAYPOINT_MATRIX = ::WID_BRW_WAYPOINT_MATRIX, ///< Matrix with waypoints. - WID_BRW_WAYPOINT = ::WID_BRW_WAYPOINT, ///< A single waypoint. - WID_BRW_SCROLL = ::WID_BRW_SCROLL, ///< Scrollbar for the matrix. - }; - - /* automatically generated from ../../widgets/road_widget.h */ - /** Widgets of the #BuildRoadToolbarWindow class. */ - enum RoadToolbarWidgets { - /* Name starts with RO instead of R, because of collision with RailToolbarWidgets */ - WID_ROT_ROAD_X = ::WID_ROT_ROAD_X, ///< Build road in x-direction. - WID_ROT_ROAD_Y = ::WID_ROT_ROAD_Y, ///< Build road in y-direction. - WID_ROT_AUTOROAD = ::WID_ROT_AUTOROAD, ///< Autorail. - WID_ROT_DEMOLISH = ::WID_ROT_DEMOLISH, ///< Demolish. - WID_ROT_DEPOT = ::WID_ROT_DEPOT, ///< Build depot. - WID_ROT_BUS_STATION = ::WID_ROT_BUS_STATION, ///< Build bus station. - WID_ROT_TRUCK_STATION = ::WID_ROT_TRUCK_STATION, ///< Build truck station. - WID_ROT_ONE_WAY = ::WID_ROT_ONE_WAY, ///< Build one-way road. - WID_ROT_BUILD_BRIDGE = ::WID_ROT_BUILD_BRIDGE, ///< Build bridge. - WID_ROT_BUILD_TUNNEL = ::WID_ROT_BUILD_TUNNEL, ///< Build tunnel. - WID_ROT_REMOVE = ::WID_ROT_REMOVE, ///< Remove road. - }; - - /** Widgets of the #BuildRoadDepotWindow class. */ - enum BuildRoadDepotWidgets { - /* Name starts with BRO instead of BR, because of collision with BuildRailDepotWidgets */ - WID_BROD_CAPTION = ::WID_BROD_CAPTION, ///< Caption of the window. - WID_BROD_DEPOT_NE = ::WID_BROD_DEPOT_NE, ///< Depot with NE entry. - WID_BROD_DEPOT_SE = ::WID_BROD_DEPOT_SE, ///< Depot with SE entry. - WID_BROD_DEPOT_SW = ::WID_BROD_DEPOT_SW, ///< Depot with SW entry. - WID_BROD_DEPOT_NW = ::WID_BROD_DEPOT_NW, ///< Depot with NW entry. - }; - - /** Widgets of the #BuildRoadStationWindow class. */ - enum BuildRoadStationWidgets { - /* Name starts with BRO instead of BR, because of collision with BuildRailStationWidgets */ - WID_BROS_CAPTION = ::WID_BROS_CAPTION, ///< Caption of the window. - WID_BROS_BACKGROUND = ::WID_BROS_BACKGROUND, ///< Background of the window. - WID_BROS_STATION_NE = ::WID_BROS_STATION_NE, ///< Terminal station with NE entry. - WID_BROS_STATION_SE = ::WID_BROS_STATION_SE, ///< Terminal station with SE entry. - WID_BROS_STATION_SW = ::WID_BROS_STATION_SW, ///< Terminal station with SW entry. - WID_BROS_STATION_NW = ::WID_BROS_STATION_NW, ///< Terminal station with NW entry. - WID_BROS_STATION_X = ::WID_BROS_STATION_X, ///< Drive-through station in x-direction. - WID_BROS_STATION_Y = ::WID_BROS_STATION_Y, ///< Drive-through station in y-direction. - WID_BROS_LT_OFF = ::WID_BROS_LT_OFF, ///< Turn off area highlight. - WID_BROS_LT_ON = ::WID_BROS_LT_ON, ///< Turn on area highlight. - WID_BROS_INFO = ::WID_BROS_INFO, ///< Station acceptance info. - }; - - /* automatically generated from ../../widgets/settings_widget.h */ - /** Widgets of the #GameOptionsWindow class. */ - enum GameOptionsWidgets { - WID_GO_BACKGROUND = ::WID_GO_BACKGROUND, ///< Background of the window. - WID_GO_CURRENCY_DROPDOWN = ::WID_GO_CURRENCY_DROPDOWN, ///< Currency dropdown. - WID_GO_DISTANCE_DROPDOWN = ::WID_GO_DISTANCE_DROPDOWN, ///< Measuring unit dropdown. - WID_GO_ROADSIDE_DROPDOWN = ::WID_GO_ROADSIDE_DROPDOWN, ///< Dropdown to select the road side (to set the right side ;)). - WID_GO_TOWNNAME_DROPDOWN = ::WID_GO_TOWNNAME_DROPDOWN, ///< Town name dropdown. - WID_GO_AUTOSAVE_DROPDOWN = ::WID_GO_AUTOSAVE_DROPDOWN, ///< Dropdown to say how often to autosave. - WID_GO_LANG_DROPDOWN = ::WID_GO_LANG_DROPDOWN, ///< Language dropdown. - WID_GO_RESOLUTION_DROPDOWN = ::WID_GO_RESOLUTION_DROPDOWN, ///< Dropdown for the resolution. - WID_GO_FULLSCREEN_BUTTON = ::WID_GO_FULLSCREEN_BUTTON, ///< Toggle fullscreen. - WID_GO_SCREENSHOT_DROPDOWN = ::WID_GO_SCREENSHOT_DROPDOWN, ///< Select the screenshot type... please use PNG!. - WID_GO_BASE_GRF_DROPDOWN = ::WID_GO_BASE_GRF_DROPDOWN, ///< Use to select a base GRF. - WID_GO_BASE_GRF_STATUS = ::WID_GO_BASE_GRF_STATUS, ///< Info about missing files etc. - WID_GO_BASE_GRF_TEXTFILE = ::WID_GO_BASE_GRF_TEXTFILE, ///< Open base GRF readme, changelog (+1) or license (+2). - WID_GO_BASE_GRF_DESCRIPTION = ::WID_GO_BASE_GRF_DESCRIPTION, ///< Description of selected base GRF. - WID_GO_BASE_SFX_DROPDOWN = ::WID_GO_BASE_SFX_DROPDOWN, ///< Use to select a base SFX. - WID_GO_BASE_SFX_TEXTFILE = ::WID_GO_BASE_SFX_TEXTFILE, ///< Open base SFX readme, changelog (+1) or license (+2). - WID_GO_BASE_SFX_DESCRIPTION = ::WID_GO_BASE_SFX_DESCRIPTION, ///< Description of selected base SFX. - WID_GO_BASE_MUSIC_DROPDOWN = ::WID_GO_BASE_MUSIC_DROPDOWN, ///< Use to select a base music set. - WID_GO_BASE_MUSIC_STATUS = ::WID_GO_BASE_MUSIC_STATUS, ///< Info about corrupted files etc. - WID_GO_BASE_MUSIC_TEXTFILE = ::WID_GO_BASE_MUSIC_TEXTFILE, ///< Open base music readme, changelog (+1) or license (+2). - WID_GO_BASE_MUSIC_DESCRIPTION = ::WID_GO_BASE_MUSIC_DESCRIPTION, ///< Description of selected base music set. - }; - - /** Widgets of the #GameSettingsWindow class. */ - enum GameSettingsWidgets { - WID_GS_FILTER = ::WID_GS_FILTER, ///< Text filter. - WID_GS_OPTIONSPANEL = ::WID_GS_OPTIONSPANEL, ///< Panel widget containing the option lists. - WID_GS_SCROLLBAR = ::WID_GS_SCROLLBAR, ///< Scrollbar. - WID_GS_HELP_TEXT = ::WID_GS_HELP_TEXT, ///< Information area to display help text of the selected option. - WID_GS_EXPAND_ALL = ::WID_GS_EXPAND_ALL, ///< Expand all button. - WID_GS_COLLAPSE_ALL = ::WID_GS_COLLAPSE_ALL, ///< Collapse all button. - WID_GS_RESTRICT_CATEGORY = ::WID_GS_RESTRICT_CATEGORY, ///< Label upfront to the category drop-down box to restrict the list of settings to show - WID_GS_RESTRICT_TYPE = ::WID_GS_RESTRICT_TYPE, ///< Label upfront to the type drop-down box to restrict the list of settings to show - WID_GS_RESTRICT_DROPDOWN = ::WID_GS_RESTRICT_DROPDOWN, ///< The drop down box to restrict the list of settings - WID_GS_TYPE_DROPDOWN = ::WID_GS_TYPE_DROPDOWN, ///< The drop down box to choose client/game/company/all settings - }; - - /** Widgets of the #CustomCurrencyWindow class. */ - enum CustomCurrencyWidgets { - WID_CC_RATE_DOWN = ::WID_CC_RATE_DOWN, ///< Down button. - WID_CC_RATE_UP = ::WID_CC_RATE_UP, ///< Up button. - WID_CC_RATE = ::WID_CC_RATE, ///< Rate of currency. - WID_CC_SEPARATOR_EDIT = ::WID_CC_SEPARATOR_EDIT, ///< Separator edit button. - WID_CC_SEPARATOR = ::WID_CC_SEPARATOR, ///< Current separator. - WID_CC_PREFIX_EDIT = ::WID_CC_PREFIX_EDIT, ///< Prefix edit button. - WID_CC_PREFIX = ::WID_CC_PREFIX, ///< Current prefix. - WID_CC_SUFFIX_EDIT = ::WID_CC_SUFFIX_EDIT, ///< Suffix edit button. - WID_CC_SUFFIX = ::WID_CC_SUFFIX, ///< Current suffix. - WID_CC_YEAR_DOWN = ::WID_CC_YEAR_DOWN, ///< Down button. - WID_CC_YEAR_UP = ::WID_CC_YEAR_UP, ///< Up button. - WID_CC_YEAR = ::WID_CC_YEAR, ///< Year of introduction. - WID_CC_PREVIEW = ::WID_CC_PREVIEW, ///< Preview. - }; - - /* automatically generated from ../../widgets/sign_widget.h */ - /** Widgets of the #SignListWindow class. */ - enum SignListWidgets { - /* Name starts with SI instead of S, because of collision with SaveLoadWidgets */ - WID_SIL_CAPTION = ::WID_SIL_CAPTION, ///< Caption of the window. - WID_SIL_LIST = ::WID_SIL_LIST, ///< List of signs. - WID_SIL_SCROLLBAR = ::WID_SIL_SCROLLBAR, ///< Scrollbar of list. - WID_SIL_FILTER_TEXT = ::WID_SIL_FILTER_TEXT, ///< Text box for typing a filter string. - WID_SIL_FILTER_MATCH_CASE_BTN = ::WID_SIL_FILTER_MATCH_CASE_BTN, ///< Button to toggle if case sensitive filtering should be used. - WID_SIL_FILTER_ENTER_BTN = ::WID_SIL_FILTER_ENTER_BTN, ///< Scroll to first sign. - }; - - /** Widgets of the #SignWindow class. */ - enum QueryEditSignWidgets { - WID_QES_CAPTION = ::WID_QES_CAPTION, ///< Caption of the window. - WID_QES_TEXT = ::WID_QES_TEXT, ///< Text of the query. - WID_QES_OK = ::WID_QES_OK, ///< OK button. - WID_QES_CANCEL = ::WID_QES_CANCEL, ///< Cancel button. - WID_QES_DELETE = ::WID_QES_DELETE, ///< Delete button. - WID_QES_PREVIOUS = ::WID_QES_PREVIOUS, ///< Previous button. - WID_QES_NEXT = ::WID_QES_NEXT, ///< Next button. - }; - - /* automatically generated from ../../widgets/smallmap_widget.h */ - /** Widgets of the #SmallMapWindow class. */ - enum SmallMapWidgets { - WID_SM_CAPTION = ::WID_SM_CAPTION, ///< Caption of the window. - WID_SM_MAP_BORDER = ::WID_SM_MAP_BORDER, ///< Border around the smallmap. - WID_SM_MAP = ::WID_SM_MAP, ///< Panel containing the smallmap. - WID_SM_LEGEND = ::WID_SM_LEGEND, ///< Bottom panel to display smallmap legends. - WID_SM_BLANK = ::WID_SM_BLANK, ///< Empty button as placeholder. - WID_SM_ZOOM_IN = ::WID_SM_ZOOM_IN, ///< Button to zoom in one step. - WID_SM_ZOOM_OUT = ::WID_SM_ZOOM_OUT, ///< Button to zoom out one step. - WID_SM_CONTOUR = ::WID_SM_CONTOUR, ///< Button to select the contour view (height map). - WID_SM_VEHICLES = ::WID_SM_VEHICLES, ///< Button to select the vehicles view. - WID_SM_INDUSTRIES = ::WID_SM_INDUSTRIES, ///< Button to select the industries view. - WID_SM_LINKSTATS = ::WID_SM_LINKSTATS, ///< Button to select the link stats view. - WID_SM_ROUTES = ::WID_SM_ROUTES, ///< Button to select the routes view. - WID_SM_VEGETATION = ::WID_SM_VEGETATION, ///< Button to select the vegetation view. - WID_SM_OWNERS = ::WID_SM_OWNERS, ///< Button to select the owners view. - WID_SM_CENTERMAP = ::WID_SM_CENTERMAP, ///< Button to move smallmap center to main window center. - WID_SM_TOGGLETOWNNAME = ::WID_SM_TOGGLETOWNNAME, ///< Toggle button to display town names. - WID_SM_SELECT_BUTTONS = ::WID_SM_SELECT_BUTTONS, ///< Selection widget for the buttons present in some smallmap modes. - WID_SM_ENABLE_ALL = ::WID_SM_ENABLE_ALL, ///< Button to enable display of all legend entries. - WID_SM_DISABLE_ALL = ::WID_SM_DISABLE_ALL, ///< Button to disable display of all legend entries. - WID_SM_SHOW_HEIGHT = ::WID_SM_SHOW_HEIGHT, ///< Show heightmap toggle button. - }; - - /* automatically generated from ../../widgets/station_widget.h */ - /** Widgets of the #StationViewWindow class. */ - enum StationViewWidgets { - WID_SV_CAPTION = ::WID_SV_CAPTION, ///< Caption of the window. - WID_SV_SORT_ORDER = ::WID_SV_SORT_ORDER, ///< 'Sort order' button - WID_SV_SORT_BY = ::WID_SV_SORT_BY, ///< 'Sort by' button - WID_SV_GROUP = ::WID_SV_GROUP, ///< label for "group by" - WID_SV_GROUP_BY = ::WID_SV_GROUP_BY, ///< 'Group by' button - WID_SV_WAITING = ::WID_SV_WAITING, ///< List of waiting cargo. - WID_SV_SCROLLBAR = ::WID_SV_SCROLLBAR, ///< Scrollbar. - WID_SV_ACCEPT_RATING_LIST = ::WID_SV_ACCEPT_RATING_LIST, ///< List of accepted cargoes / rating of cargoes. - WID_SV_LOCATION = ::WID_SV_LOCATION, ///< 'Location' button. - WID_SV_ACCEPTS_RATINGS = ::WID_SV_ACCEPTS_RATINGS, ///< 'Accepts' / 'Ratings' button. - WID_SV_RENAME = ::WID_SV_RENAME, ///< 'Rename' button. - WID_SV_CLOSE_AIRPORT = ::WID_SV_CLOSE_AIRPORT, ///< 'Close airport' button. - WID_SV_TRAINS = ::WID_SV_TRAINS, ///< List of scheduled trains button. - WID_SV_ROADVEHS = ::WID_SV_ROADVEHS, ///< List of scheduled road vehs button. - WID_SV_SHIPS = ::WID_SV_SHIPS, ///< List of scheduled ships button. - WID_SV_PLANES = ::WID_SV_PLANES, ///< List of scheduled planes button. - }; - - /** Widgets of the #CompanyStationsWindow class. */ - enum StationListWidgets { - /* Name starts with ST instead of S, because of collision with SaveLoadWidgets */ - WID_STL_CAPTION = ::WID_STL_CAPTION, ///< Caption of the window. - WID_STL_LIST = ::WID_STL_LIST, ///< The main panel, list of stations. - WID_STL_SCROLLBAR = ::WID_STL_SCROLLBAR, ///< Scrollbar next to the main panel. - - /* Vehicletypes need to be in order of StationFacility due to bit magic */ - WID_STL_TRAIN = ::WID_STL_TRAIN, ///< 'TRAIN' button - list only facilities where is a railroad station. - WID_STL_TRUCK = ::WID_STL_TRUCK, ///< 'TRUCK' button - list only facilities where is a truck stop. - WID_STL_BUS = ::WID_STL_BUS, ///< 'BUS' button - list only facilities where is a bus stop. - WID_STL_AIRPLANE = ::WID_STL_AIRPLANE, ///< 'AIRPLANE' button - list only facilities where is an airport. - WID_STL_SHIP = ::WID_STL_SHIP, ///< 'SHIP' button - list only facilities where is a dock. - WID_STL_FACILALL = ::WID_STL_FACILALL, ///< 'ALL' button - list all facilities. - - WID_STL_NOCARGOWAITING = ::WID_STL_NOCARGOWAITING, ///< 'NO' button - list stations where no cargo is waiting. - WID_STL_CARGOALL = ::WID_STL_CARGOALL, ///< 'ALL' button - list all stations. - - WID_STL_SORTBY = ::WID_STL_SORTBY, ///< 'Sort by' button - reverse sort direction. - WID_STL_SORTDROPBTN = ::WID_STL_SORTDROPBTN, ///< Dropdown button. - - WID_STL_CARGOSTART = ::WID_STL_CARGOSTART, ///< Widget numbers used for list of cargo types (not present in _company_stations_widgets). - }; - - /** Widgets of the #SelectStationWindow class. */ - enum JoinStationWidgets { - WID_JS_CAPTION = ::WID_JS_CAPTION, // Caption of the window. - WID_JS_PANEL = ::WID_JS_PANEL, // Main panel. - WID_JS_SCROLLBAR = ::WID_JS_SCROLLBAR, // Scrollbar of the panel. - }; - - /* automatically generated from ../../widgets/statusbar_widget.h */ - /** Widgets of the #StatusBarWindow class. */ - enum StatusbarWidgets { - WID_S_LEFT = ::WID_S_LEFT, ///< Left part of the statusbar; date is shown there. - WID_S_MIDDLE = ::WID_S_MIDDLE, ///< Middle part; current news or company name or *** SAVING *** or *** PAUSED ***. - WID_S_RIGHT = ::WID_S_RIGHT, ///< Right part; bank balance. - }; - - /* automatically generated from ../../widgets/story_widget.h */ - /** Widgets of the #GoalListWindow class. */ - enum StoryBookWidgets { - WID_SB_CAPTION = ::WID_SB_CAPTION, ///< Caption of the window. - WID_SB_SEL_PAGE = ::WID_SB_SEL_PAGE, ///< Page selector. - WID_SB_PAGE_PANEL = ::WID_SB_PAGE_PANEL, ///< Page body. - WID_SB_SCROLLBAR = ::WID_SB_SCROLLBAR, ///< Scrollbar of the goal list. - WID_SB_PREV_PAGE = ::WID_SB_PREV_PAGE, ///< Prev button. - WID_SB_NEXT_PAGE = ::WID_SB_NEXT_PAGE, ///< Next button. - }; - - /* automatically generated from ../../widgets/subsidy_widget.h */ - /** Widgets of the #SubsidyListWindow class. */ - enum SubsidyListWidgets { - /* Name starts with SU instead of S, because of collision with SaveLoadWidgets. */ - WID_SUL_PANEL = ::WID_SUL_PANEL, ///< Main panel of window. - WID_SUL_SCROLLBAR = ::WID_SUL_SCROLLBAR, ///< Scrollbar of panel. - }; - - /* automatically generated from ../../widgets/terraform_widget.h */ - /** Widgets of the #TerraformToolbarWindow class. */ - enum TerraformToolbarWidgets { - WID_TT_SHOW_PLACE_OBJECT = ::WID_TT_SHOW_PLACE_OBJECT, ///< Should the place object button be shown? - WID_TT_BUTTONS_START = ::WID_TT_BUTTONS_START, ///< Start of pushable buttons. - WID_TT_LOWER_LAND = ::WID_TT_LOWER_LAND, ///< Lower land button. - WID_TT_RAISE_LAND = ::WID_TT_RAISE_LAND, ///< Raise land button. - WID_TT_LEVEL_LAND = ::WID_TT_LEVEL_LAND, ///< Level land button. - WID_TT_DEMOLISH = ::WID_TT_DEMOLISH, ///< Demolish aka dynamite button. - WID_TT_BUY_LAND = ::WID_TT_BUY_LAND, ///< Buy land button. - WID_TT_PLANT_TREES = ::WID_TT_PLANT_TREES, ///< Plant trees button (note: opens separate window, no place-push-button). - WID_TT_PLACE_SIGN = ::WID_TT_PLACE_SIGN, ///< Place sign button. - WID_TT_PLACE_OBJECT = ::WID_TT_PLACE_OBJECT, ///< Place object button. - }; - - /** Widgets of the #ScenarioEditorLandscapeGenerationWindow class. */ - enum EditorTerraformToolbarWidgets { - WID_ETT_SHOW_PLACE_DESERT = ::WID_ETT_SHOW_PLACE_DESERT, ///< Should the place desert button be shown? - WID_ETT_START = ::WID_ETT_START, ///< Used for iterations. - WID_ETT_DOTS = ::WID_ETT_DOTS, ///< Invisible widget for rendering the terraform size on. - WID_ETT_BUTTONS_START = ::WID_ETT_BUTTONS_START, ///< Start of pushable buttons. - WID_ETT_DEMOLISH = ::WID_ETT_DEMOLISH, ///< Demolish aka dynamite button. - WID_ETT_LOWER_LAND = ::WID_ETT_LOWER_LAND, ///< Lower land button. - WID_ETT_RAISE_LAND = ::WID_ETT_RAISE_LAND, ///< Raise land button. - WID_ETT_LEVEL_LAND = ::WID_ETT_LEVEL_LAND, ///< Level land button. - WID_ETT_PLACE_ROCKS = ::WID_ETT_PLACE_ROCKS, ///< Place rocks button. - WID_ETT_PLACE_DESERT = ::WID_ETT_PLACE_DESERT, ///< Place desert button (in tropical climate). - WID_ETT_PLACE_OBJECT = ::WID_ETT_PLACE_OBJECT, ///< Place transmitter button. - WID_ETT_BUTTONS_END = ::WID_ETT_BUTTONS_END, ///< End of pushable buttons. - WID_ETT_INCREASE_SIZE = ::WID_ETT_INCREASE_SIZE, ///< Upwards arrow button to increase terraforming size. - WID_ETT_DECREASE_SIZE = ::WID_ETT_DECREASE_SIZE, ///< Downwards arrow button to decrease terraforming size. - WID_ETT_NEW_SCENARIO = ::WID_ETT_NEW_SCENARIO, ///< Button for generating a new scenario. - WID_ETT_RESET_LANDSCAPE = ::WID_ETT_RESET_LANDSCAPE, ///< Button for removing all company-owned property. - }; - - /* automatically generated from ../../widgets/timetable_widget.h */ - /** Widgets of the #TimetableWindow class. */ - enum VehicleTimetableWidgets { - WID_VT_CAPTION = ::WID_VT_CAPTION, ///< Caption of the window. - WID_VT_ORDER_VIEW = ::WID_VT_ORDER_VIEW, ///< Order view. - WID_VT_TIMETABLE_PANEL = ::WID_VT_TIMETABLE_PANEL, ///< Timetable panel. - WID_VT_ARRIVAL_DEPARTURE_PANEL = ::WID_VT_ARRIVAL_DEPARTURE_PANEL, ///< Panel with the expected/scheduled arrivals. - WID_VT_SCROLLBAR = ::WID_VT_SCROLLBAR, ///< Scrollbar for the panel. - WID_VT_SUMMARY_PANEL = ::WID_VT_SUMMARY_PANEL, ///< Summary panel. - WID_VT_START_DATE = ::WID_VT_START_DATE, ///< Start date button. - WID_VT_CHANGE_TIME = ::WID_VT_CHANGE_TIME, ///< Change time button. - WID_VT_CLEAR_TIME = ::WID_VT_CLEAR_TIME, ///< Clear time button. - WID_VT_RESET_LATENESS = ::WID_VT_RESET_LATENESS, ///< Reset lateness button. - WID_VT_AUTOFILL = ::WID_VT_AUTOFILL, ///< Autofill button. - WID_VT_EXPECTED = ::WID_VT_EXPECTED, ///< Toggle between expected and scheduled arrivals. - WID_VT_SHARED_ORDER_LIST = ::WID_VT_SHARED_ORDER_LIST, ///< Show the shared order list. - WID_VT_ARRIVAL_DEPARTURE_SELECTION = ::WID_VT_ARRIVAL_DEPARTURE_SELECTION, ///< Disable/hide the arrival departure panel. - WID_VT_EXPECTED_SELECTION = ::WID_VT_EXPECTED_SELECTION, ///< Disable/hide the expected selection button. - WID_VT_CHANGE_SPEED = ::WID_VT_CHANGE_SPEED, ///< Change speed limit button. - WID_VT_CLEAR_SPEED = ::WID_VT_CLEAR_SPEED, ///< Clear speed limit button. - }; - - /* automatically generated from ../../widgets/toolbar_widget.h */ - /** Widgets of the #MainToolbarWindow class. */ - enum ToolbarNormalWidgets { - WID_TN_PAUSE = ::WID_TN_PAUSE, ///< Pause the game. - WID_TN_FAST_FORWARD = ::WID_TN_FAST_FORWARD, ///< Fast forward the game. - WID_TN_SETTINGS = ::WID_TN_SETTINGS, ///< Settings menu. - WID_TN_SAVE = ::WID_TN_SAVE, ///< Save menu. - WID_TN_SMALL_MAP = ::WID_TN_SMALL_MAP, ///< Small map menu. - WID_TN_TOWNS = ::WID_TN_TOWNS, ///< Town menu. - WID_TN_SUBSIDIES = ::WID_TN_SUBSIDIES, ///< Subsidy menu. - WID_TN_STATIONS = ::WID_TN_STATIONS, ///< Station menu. - WID_TN_FINANCES = ::WID_TN_FINANCES, ///< Finance menu. - WID_TN_COMPANIES = ::WID_TN_COMPANIES, ///< Company menu. - WID_TN_STORY = ::WID_TN_STORY, ///< Story menu. - WID_TN_GOAL = ::WID_TN_GOAL, ///< Goal menu. - WID_TN_GRAPHS = ::WID_TN_GRAPHS, ///< Graph menu. - WID_TN_LEAGUE = ::WID_TN_LEAGUE, ///< Company league menu. - WID_TN_INDUSTRIES = ::WID_TN_INDUSTRIES, ///< Industry menu. - WID_TN_VEHICLE_START = ::WID_TN_VEHICLE_START, ///< Helper for the offset of the vehicle menus. - WID_TN_TRAINS = ::WID_TN_TRAINS, ///< Train menu. - WID_TN_ROADVEHS = ::WID_TN_ROADVEHS, ///< Road vehicle menu. - WID_TN_SHIPS = ::WID_TN_SHIPS, ///< Ship menu. - WID_TN_AIRCRAFTS = ::WID_TN_AIRCRAFTS, ///< Aircraft menu. - WID_TN_ZOOM_IN = ::WID_TN_ZOOM_IN, ///< Zoom in the main viewport. - WID_TN_ZOOM_OUT = ::WID_TN_ZOOM_OUT, ///< Zoom out the main viewport. - WID_TN_RAILS = ::WID_TN_RAILS, ///< Rail building menu. - WID_TN_ROADS = ::WID_TN_ROADS, ///< Road building menu. - WID_TN_WATER = ::WID_TN_WATER, ///< Water building toolbar. - WID_TN_AIR = ::WID_TN_AIR, ///< Airport building toolbar. - WID_TN_LANDSCAPE = ::WID_TN_LANDSCAPE, ///< Landscaping toolbar. - WID_TN_MUSIC_SOUND = ::WID_TN_MUSIC_SOUND, ///< Music/sound configuration menu. - WID_TN_MESSAGES = ::WID_TN_MESSAGES, ///< Messages menu. - WID_TN_HELP = ::WID_TN_HELP, ///< Help menu. - WID_TN_SWITCH_BAR = ::WID_TN_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. - WID_TN_END = ::WID_TN_END, ///< Helper for knowing the amount of widgets. - }; - - /** Widgets of the #ScenarioEditorToolbarWindow class. */ - enum ToolbarEditorWidgets { - WID_TE_PAUSE = ::WID_TE_PAUSE, ///< Pause the game. - WID_TE_FAST_FORWARD = ::WID_TE_FAST_FORWARD, ///< Fast forward the game. - WID_TE_SETTINGS = ::WID_TE_SETTINGS, ///< Settings menu. - WID_TE_SAVE = ::WID_TE_SAVE, ///< Save menu. - WID_TE_SPACER = ::WID_TE_SPACER, ///< Spacer with "scenario editor" text. - WID_TE_DATE = ::WID_TE_DATE, ///< The date of the scenario. - WID_TE_DATE_BACKWARD = ::WID_TE_DATE_BACKWARD, ///< Reduce the date of the scenario. - WID_TE_DATE_FORWARD = ::WID_TE_DATE_FORWARD, ///< Increase the date of the scenario. - WID_TE_SMALL_MAP = ::WID_TE_SMALL_MAP, ///< Small map menu. - WID_TE_ZOOM_IN = ::WID_TE_ZOOM_IN, ///< Zoom in the main viewport. - WID_TE_ZOOM_OUT = ::WID_TE_ZOOM_OUT, ///< Zoom out the main viewport. - WID_TE_LAND_GENERATE = ::WID_TE_LAND_GENERATE, ///< Land generation. - WID_TE_TOWN_GENERATE = ::WID_TE_TOWN_GENERATE, ///< Town building window. - WID_TE_INDUSTRY = ::WID_TE_INDUSTRY, ///< Industry building window. - WID_TE_ROADS = ::WID_TE_ROADS, ///< Road building menu. - WID_TE_WATER = ::WID_TE_WATER, ///< Water building toolbar. - WID_TE_TREES = ::WID_TE_TREES, ///< Tree building toolbar. - WID_TE_SIGNS = ::WID_TE_SIGNS, ///< Sign building. - WID_TE_DATE_PANEL = ::WID_TE_DATE_PANEL, ///< Container for the date widgets. - /* The following three need to have the same actual widget number as the normal toolbar due to shared code. */ - WID_TE_MUSIC_SOUND = ::WID_TE_MUSIC_SOUND, ///< Music/sound configuration menu. - WID_TE_HELP = ::WID_TE_HELP, ///< Help menu. - WID_TE_SWITCH_BAR = ::WID_TE_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. - }; - - /* automatically generated from ../../widgets/town_widget.h */ - /** Widgets of the #TownDirectoryWindow class. */ - enum TownDirectoryWidgets { - WID_TD_SORT_ORDER = ::WID_TD_SORT_ORDER, ///< Direction of sort dropdown. - WID_TD_SORT_CRITERIA = ::WID_TD_SORT_CRITERIA, ///< Criteria of sort dropdown. - WID_TD_LIST = ::WID_TD_LIST, ///< List of towns. - WID_TD_SCROLLBAR = ::WID_TD_SCROLLBAR, ///< Scrollbar for the town list. - WID_TD_WORLD_POPULATION = ::WID_TD_WORLD_POPULATION, ///< The world's population. - }; - - /** Widgets of the #TownAuthorityWindow class. */ - enum TownAuthorityWidgets { - WID_TA_CAPTION = ::WID_TA_CAPTION, ///< Caption of window. - WID_TA_RATING_INFO = ::WID_TA_RATING_INFO, ///< Overview with ratings for each company. - WID_TA_COMMAND_LIST = ::WID_TA_COMMAND_LIST, ///< List of commands for the player. - WID_TA_SCROLLBAR = ::WID_TA_SCROLLBAR, ///< Scrollbar of the list of commands. - WID_TA_ACTION_INFO = ::WID_TA_ACTION_INFO, ///< Additional information about the action. - WID_TA_EXECUTE = ::WID_TA_EXECUTE, ///< Do-it button. - }; - - /** Widgets of the #TownViewWindow class. */ - enum TownViewWidgets { - WID_TV_CAPTION = ::WID_TV_CAPTION, ///< Caption of window. - WID_TV_VIEWPORT = ::WID_TV_VIEWPORT, ///< View of the center of the town. - WID_TV_INFO = ::WID_TV_INFO, ///< General information about the town. - WID_TV_CENTER_VIEW = ::WID_TV_CENTER_VIEW, ///< Center the main view on this town. - WID_TV_SHOW_AUTHORITY = ::WID_TV_SHOW_AUTHORITY, ///< Show the town authority window. - WID_TV_CHANGE_NAME = ::WID_TV_CHANGE_NAME, ///< Change the name of this town. - WID_TV_EXPAND = ::WID_TV_EXPAND, ///< Expand this town (scenario editor only). - WID_TV_DELETE = ::WID_TV_DELETE, ///< Delete this town (scenario editor only). - }; - - /** Widgets of the #FoundTownWindow class. */ - enum TownFoundingWidgets { - WID_TF_NEW_TOWN = ::WID_TF_NEW_TOWN, ///< Create a new town. - WID_TF_RANDOM_TOWN = ::WID_TF_RANDOM_TOWN, ///< Randomly place a town. - WID_TF_MANY_RANDOM_TOWNS = ::WID_TF_MANY_RANDOM_TOWNS, ///< Randomly place many towns. - WID_TF_TOWN_NAME_EDITBOX = ::WID_TF_TOWN_NAME_EDITBOX, ///< Editor for the town name. - WID_TF_TOWN_NAME_RANDOM = ::WID_TF_TOWN_NAME_RANDOM, ///< Generate a random town name. - WID_TF_SIZE_SMALL = ::WID_TF_SIZE_SMALL, ///< Selection for a small town. - WID_TF_SIZE_MEDIUM = ::WID_TF_SIZE_MEDIUM, ///< Selection for a medium town. - WID_TF_SIZE_LARGE = ::WID_TF_SIZE_LARGE, ///< Selection for a large town. - WID_TF_SIZE_RANDOM = ::WID_TF_SIZE_RANDOM, ///< Selection for a randomly sized town. - WID_TF_CITY = ::WID_TF_CITY, ///< Selection for the town's city state. - WID_TF_LAYOUT_ORIGINAL = ::WID_TF_LAYOUT_ORIGINAL, ///< Selection for the original town layout. - WID_TF_LAYOUT_BETTER = ::WID_TF_LAYOUT_BETTER, ///< Selection for the better town layout. - WID_TF_LAYOUT_GRID2 = ::WID_TF_LAYOUT_GRID2, ///< Selection for the 2x2 grid town layout. - WID_TF_LAYOUT_GRID3 = ::WID_TF_LAYOUT_GRID3, ///< Selection for the 3x3 grid town layout. - WID_TF_LAYOUT_RANDOM = ::WID_TF_LAYOUT_RANDOM, ///< Selection for a randomly chosen town layout. - }; - - /* automatically generated from ../../widgets/transparency_widget.h */ - /** Widgets of the #TransparenciesWindow class. */ - enum TransparencyToolbarWidgets { - /* Button row. */ - WID_TT_BEGIN = ::WID_TT_BEGIN, ///< First toggle button. - WID_TT_SIGNS = ::WID_TT_SIGNS, ///< Signs background transparency toggle button. - WID_TT_TREES = ::WID_TT_TREES, ///< Trees transparency toggle button. - WID_TT_HOUSES = ::WID_TT_HOUSES, ///< Houses transparency toggle button. - WID_TT_INDUSTRIES = ::WID_TT_INDUSTRIES, ///< industries transparency toggle button. - WID_TT_BUILDINGS = ::WID_TT_BUILDINGS, ///< Company buildings and structures transparency toggle button. - WID_TT_BRIDGES = ::WID_TT_BRIDGES, ///< Bridges transparency toggle button. - WID_TT_STRUCTURES = ::WID_TT_STRUCTURES, ///< Object structure transparency toggle button. - WID_TT_CATENARY = ::WID_TT_CATENARY, ///< Catenary transparency toggle button. - WID_TT_LOADING = ::WID_TT_LOADING, ///< Loading indicators transparency toggle button. - WID_TT_END = ::WID_TT_END, ///< End of toggle buttons. - - /* Panel with buttons for invisibility */ - WID_TT_BUTTONS = ::WID_TT_BUTTONS, ///< Panel with 'invisibility' buttons. - }; - - /* automatically generated from ../../widgets/tree_widget.h */ - /** Widgets of the #BuildTreesWindow class. */ - enum BuildTreesWidgets { - WID_BT_TYPE_11 = ::WID_BT_TYPE_11, ///< Tree 1st column 1st row. - WID_BT_TYPE_12 = ::WID_BT_TYPE_12, ///< Tree 1st column 2nd row. - WID_BT_TYPE_13 = ::WID_BT_TYPE_13, ///< Tree 1st column 3rd row. - WID_BT_TYPE_14 = ::WID_BT_TYPE_14, ///< Tree 1st column 4th row. - WID_BT_TYPE_21 = ::WID_BT_TYPE_21, ///< Tree 2st column 1st row. - WID_BT_TYPE_22 = ::WID_BT_TYPE_22, ///< Tree 2st column 2nd row. - WID_BT_TYPE_23 = ::WID_BT_TYPE_23, ///< Tree 2st column 3rd row. - WID_BT_TYPE_24 = ::WID_BT_TYPE_24, ///< Tree 2st column 4th row. - WID_BT_TYPE_31 = ::WID_BT_TYPE_31, ///< Tree 3st column 1st row. - WID_BT_TYPE_32 = ::WID_BT_TYPE_32, ///< Tree 3st column 2nd row. - WID_BT_TYPE_33 = ::WID_BT_TYPE_33, ///< Tree 3st column 3rd row. - WID_BT_TYPE_34 = ::WID_BT_TYPE_34, ///< Tree 3st column 4th row. - WID_BT_TYPE_RANDOM = ::WID_BT_TYPE_RANDOM, ///< Button to build random type of tree. - WID_BT_MANY_RANDOM = ::WID_BT_MANY_RANDOM, ///< Button to build many random trees. - }; - - /* automatically generated from ../../widgets/vehicle_widget.h */ - /** Widgets of the #VehicleViewWindow class. */ - enum VehicleViewWidgets { - WID_VV_CAPTION = ::WID_VV_CAPTION, ///< Caption of window. - WID_VV_VIEWPORT = ::WID_VV_VIEWPORT, ///< Viewport widget. - WID_VV_START_STOP = ::WID_VV_START_STOP, ///< Start or stop this vehicle, and show information about the current state. - WID_VV_CENTER_MAIN_VIEW = ::WID_VV_CENTER_MAIN_VIEW, ///< Center the main view on this vehicle. - WID_VV_GOTO_DEPOT = ::WID_VV_GOTO_DEPOT, ///< Order this vehicle to go to the depot. - WID_VV_REFIT = ::WID_VV_REFIT, ///< Open the refit window. - WID_VV_SHOW_ORDERS = ::WID_VV_SHOW_ORDERS, ///< Show the orders of this vehicle. - WID_VV_SHOW_DETAILS = ::WID_VV_SHOW_DETAILS, ///< Show details of this vehicle. - WID_VV_CLONE = ::WID_VV_CLONE, ///< Clone this vehicle. - WID_VV_SELECT_DEPOT_CLONE = ::WID_VV_SELECT_DEPOT_CLONE, ///< Selection widget between 'goto depot', and 'clone vehicle' buttons. - WID_VV_SELECT_REFIT_TURN = ::WID_VV_SELECT_REFIT_TURN, ///< Selection widget between 'refit' and 'turn around' buttons. - WID_VV_TURN_AROUND = ::WID_VV_TURN_AROUND, ///< Turn this vehicle around. - WID_VV_FORCE_PROCEED = ::WID_VV_FORCE_PROCEED, ///< Force this vehicle to pass a signal at danger. - }; - - /** Widgets of the #RefitWindow class. */ - enum VehicleRefitWidgets { - WID_VR_CAPTION = ::WID_VR_CAPTION, ///< Caption of window. - WID_VR_VEHICLE_PANEL_DISPLAY = ::WID_VR_VEHICLE_PANEL_DISPLAY, ///< Display with a representation of the vehicle to refit. - WID_VR_SHOW_HSCROLLBAR = ::WID_VR_SHOW_HSCROLLBAR, ///< Selection widget for the horizontal scrollbar. - WID_VR_HSCROLLBAR = ::WID_VR_HSCROLLBAR, ///< Horizontal scrollbar or the vehicle display. - WID_VR_SELECT_HEADER = ::WID_VR_SELECT_HEADER, ///< Header with question about the cargo to carry. - WID_VR_MATRIX = ::WID_VR_MATRIX, ///< Options to refit to. - WID_VR_SCROLLBAR = ::WID_VR_SCROLLBAR, ///< Scrollbar for the refit options. - WID_VR_INFO = ::WID_VR_INFO, ///< Information about the currently selected refit option. - WID_VR_REFIT = ::WID_VR_REFIT, ///< Perform the refit. - }; - - /** Widgets of the #VehicleDetailsWindow class. */ - enum VehicleDetailsWidgets { - WID_VD_CAPTION = ::WID_VD_CAPTION, ///< Caption of window. - WID_VD_RENAME_VEHICLE = ::WID_VD_RENAME_VEHICLE, ///< Rename this vehicle. - WID_VD_TOP_DETAILS = ::WID_VD_TOP_DETAILS, ///< Panel with generic details. - WID_VD_INCREASE_SERVICING_INTERVAL = ::WID_VD_INCREASE_SERVICING_INTERVAL, ///< Increase the servicing interval. - WID_VD_DECREASE_SERVICING_INTERVAL = ::WID_VD_DECREASE_SERVICING_INTERVAL, ///< Decrease the servicing interval. - WID_VD_SERVICE_INTERVAL_DROPDOWN = ::WID_VD_SERVICE_INTERVAL_DROPDOWN, ///< Dropdown to select default/days/percent service interval. - WID_VD_SERVICING_INTERVAL = ::WID_VD_SERVICING_INTERVAL, ///< Information about the servicing interval. - WID_VD_MIDDLE_DETAILS = ::WID_VD_MIDDLE_DETAILS, ///< Details for non-trains. - WID_VD_MATRIX = ::WID_VD_MATRIX, ///< List of details for trains. - WID_VD_SCROLLBAR = ::WID_VD_SCROLLBAR, ///< Scrollbar for train details. - WID_VD_DETAILS_CARGO_CARRIED = ::WID_VD_DETAILS_CARGO_CARRIED, ///< Show carried cargo per part of the train. - WID_VD_DETAILS_TRAIN_VEHICLES = ::WID_VD_DETAILS_TRAIN_VEHICLES, ///< Show all parts of the train with their description. - WID_VD_DETAILS_CAPACITY_OF_EACH = ::WID_VD_DETAILS_CAPACITY_OF_EACH, ///< Show the capacity of all train parts. - WID_VD_DETAILS_TOTAL_CARGO = ::WID_VD_DETAILS_TOTAL_CARGO, ///< Show the capacity and carried cargo amounts aggregated per cargo of the train. - }; - - /** Widgets of the #VehicleListWindow class. */ - enum VehicleListWidgets { - WID_VL_CAPTION = ::WID_VL_CAPTION, ///< Caption of window. - WID_VL_SORT_ORDER = ::WID_VL_SORT_ORDER, ///< Sort order. - WID_VL_SORT_BY_PULLDOWN = ::WID_VL_SORT_BY_PULLDOWN, ///< Sort by dropdown list. - WID_VL_LIST = ::WID_VL_LIST, ///< List of the vehicles. - WID_VL_SCROLLBAR = ::WID_VL_SCROLLBAR, ///< Scrollbar for the list. - WID_VL_HIDE_BUTTONS = ::WID_VL_HIDE_BUTTONS, ///< Selection to hide the buttons. - WID_VL_AVAILABLE_VEHICLES = ::WID_VL_AVAILABLE_VEHICLES, ///< Available vehicles. - WID_VL_MANAGE_VEHICLES_DROPDOWN = ::WID_VL_MANAGE_VEHICLES_DROPDOWN, ///< Manage vehicles dropdown list. - WID_VL_STOP_ALL = ::WID_VL_STOP_ALL, ///< Stop all button. - WID_VL_START_ALL = ::WID_VL_START_ALL, ///< Start all button. - }; - - /* automatically generated from ../../widgets/viewport_widget.h */ - /** Widgets of the #ExtraViewportWindow class. */ - enum ExtraViewportWidgets { - WID_EV_CAPTION = ::WID_EV_CAPTION, ///< Caption of window. - WID_EV_VIEWPORT = ::WID_EV_VIEWPORT, ///< The viewport. - WID_EV_ZOOM_IN = ::WID_EV_ZOOM_IN, ///< Zoom in. - WID_EV_ZOOM_OUT = ::WID_EV_ZOOM_OUT, ///< Zoom out. - WID_EV_MAIN_TO_VIEW = ::WID_EV_MAIN_TO_VIEW, ///< Center the view of this viewport on the main view. - WID_EV_VIEW_TO_MAIN = ::WID_EV_VIEW_TO_MAIN, ///< Center the main view on the view of this viewport. - }; - - /* automatically generated from ../../widgets/waypoint_widget.h */ - /** Widgets of the #WaypointWindow class. */ - enum WaypointWidgets { - WID_W_CAPTION = ::WID_W_CAPTION, ///< Caption of window. - WID_W_VIEWPORT = ::WID_W_VIEWPORT, ///< The viewport on this waypoint. - WID_W_CENTER_VIEW = ::WID_W_CENTER_VIEW, ///< Center the main view on this waypoint. - WID_W_RENAME = ::WID_W_RENAME, ///< Rename this waypoint. - WID_W_SHOW_VEHICLES = ::WID_W_SHOW_VEHICLES, ///< Show the vehicles visiting this waypoint. - }; - - // @endenum -}; - -#endif /* SCRIPT_WINDOW_HPP */ diff --git a/src/script/api/template/template_window.hpp.sq.orig b/src/script/api/template/template_window.hpp.sq.orig deleted file mode 100644 index 9f01e42d5a..0000000000 --- a/src/script/api/template/template_window.hpp.sq.orig +++ /dev/null @@ -1,257 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ - -#include "../script_window.hpp" - -namespace SQConvert { - /* Allow enums to be used as Squirrel parameters */ - template <> inline ScriptWindow::WindowNumberEnum GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::WindowNumberEnum)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::WindowNumberEnum res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::WindowClass GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::WindowClass)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::WindowClass res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::TextColour GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TextColour)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TextColour res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NumberType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NumberType)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NumberType res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::WidgetType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::WidgetType)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::WidgetType res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::AIListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AIListWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AIListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::AISettingsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AISettingsWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AISettingsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::AIConfigWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AIConfigWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AIConfigWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::AIDebugWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AIDebugWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AIDebugWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::AirportToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AirportToolbarWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AirportToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::AirportPickerWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AirportPickerWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AirportPickerWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::ReplaceVehicleWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ReplaceVehicleWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ReplaceVehicleWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BootstrapBackgroundWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BootstrapBackgroundWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BootstrapBackgroundWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BootstrapAskForDownloadWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BootstrapAskForDownloadWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BootstrapAskForDownloadWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BuildBridgeSelectionWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildBridgeSelectionWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildBridgeSelectionWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BuildVehicleWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildVehicleWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildVehicleWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::CheatWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CheatWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CheatWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::CompanyWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::CompanyFinancesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyFinancesWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyFinancesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::SelectCompanyLiveryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SelectCompanyLiveryWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SelectCompanyLiveryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::SelectCompanyManagerFaceWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SelectCompanyManagerFaceWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SelectCompanyManagerFaceWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::CompanyInfrastructureWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyInfrastructureWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyInfrastructureWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BuyCompanyWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuyCompanyWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuyCompanyWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::ConsoleWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ConsoleWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ConsoleWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::SetDateWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SetDateWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SetDateWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::DepotWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DepotWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::DepotWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BuildDockDepotWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildDockDepotWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildDockDepotWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::DockToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DockToolbarWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::DockToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::DropdownMenuWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DropdownMenuWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::DropdownMenuWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::EnginePreviewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::EnginePreviewWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::EnginePreviewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::ErrorMessageWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ErrorMessageWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ErrorMessageWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::SaveLoadWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SaveLoadWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SaveLoadWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::GenerateLandscapeWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GenerateLandscapeWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GenerateLandscapeWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::CreateScenarioWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CreateScenarioWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CreateScenarioWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::GenerationProgressWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GenerationProgressWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GenerationProgressWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::GoalListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GoalListWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GoalListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::GoalQuestionWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GoalQuestionWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GoalQuestionWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::GraphLegendWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GraphLegendWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GraphLegendWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::CompanyValueWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyValueWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyValueWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::PerformanceHistoryGraphWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::PerformanceHistoryGraphWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::PerformanceHistoryGraphWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::CargoPaymentRatesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CargoPaymentRatesWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CargoPaymentRatesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::CompanyLeagueWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyLeagueWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyLeagueWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::PerformanceRatingDetailsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::PerformanceRatingDetailsWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::PerformanceRatingDetailsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::GroupListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GroupListWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GroupListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::HighscoreWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::HighscoreWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::HighscoreWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::DynamicPlaceIndustriesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DynamicPlaceIndustriesWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::DynamicPlaceIndustriesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::IndustryViewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::IndustryViewWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::IndustryViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::IndustryDirectoryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::IndustryDirectoryWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::IndustryDirectoryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::IndustryCargoesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::IndustryCargoesWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::IndustryCargoesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::SelectGameIntroWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SelectGameIntroWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SelectGameIntroWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::LinkGraphLegendWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::LinkGraphLegendWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::LinkGraphLegendWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::MainWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MainWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::MainWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::LandInfoWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::LandInfoWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::LandInfoWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::ToolTipsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolTipsWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolTipsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::AboutWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AboutWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AboutWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::QueryStringWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::QueryStringWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::QueryStringWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::QueryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::QueryWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::QueryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::TextfileWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TextfileWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TextfileWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::MusicTrackSelectionWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MusicTrackSelectionWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::MusicTrackSelectionWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::MusicWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MusicWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::MusicWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NetWorkChatWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetWorkChatWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetWorkChatWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NetworkContentDownloadStatusWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkContentDownloadStatusWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkContentDownloadStatusWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NetworkContentListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkContentListWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkContentListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NetworkGameWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkGameWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkGameWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NetworkStartServerWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkStartServerWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkStartServerWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NetworkLobbyWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkLobbyWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkLobbyWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::ClientListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ClientListWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ClientListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::ClientListPopupWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ClientListPopupWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ClientListPopupWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NetworkJoinStatusWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkJoinStatusWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkJoinStatusWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NetworkCompanyPasswordWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkCompanyPasswordWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkCompanyPasswordWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NewGRFInspectWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewGRFInspectWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewGRFInspectWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::SpriteAlignerWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SpriteAlignerWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SpriteAlignerWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NewGRFParametersWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewGRFParametersWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewGRFParametersWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NewGRFStateWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewGRFStateWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewGRFStateWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::ScanProgressWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ScanProgressWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ScanProgressWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NewsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewsWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::MessageHistoryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MessageHistoryWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::MessageHistoryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BuildObjectWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildObjectWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildObjectWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::OrderWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::OrderWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::OrderWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::OnScreenKeyboardWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::OnScreenKeyboardWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::OnScreenKeyboardWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::RailToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::RailToolbarWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::RailToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BuildRailStationWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRailStationWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRailStationWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BuildSignalWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildSignalWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildSignalWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BuildRailDepotWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRailDepotWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRailDepotWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BuildRailWaypointWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRailWaypointWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRailWaypointWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::RoadToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::RoadToolbarWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::RoadToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BuildRoadDepotWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRoadDepotWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRoadDepotWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BuildRoadStationWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRoadStationWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRoadStationWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::GameOptionsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GameOptionsWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GameOptionsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::GameSettingsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GameSettingsWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GameSettingsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::CustomCurrencyWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CustomCurrencyWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CustomCurrencyWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::SignListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SignListWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SignListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::QueryEditSignWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::QueryEditSignWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::QueryEditSignWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::SmallMapWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SmallMapWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SmallMapWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::StationViewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StationViewWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StationViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::StationListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StationListWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StationListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::JoinStationWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::JoinStationWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::JoinStationWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::StatusbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StatusbarWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StatusbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::StoryBookWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StoryBookWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StoryBookWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::SubsidyListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SubsidyListWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SubsidyListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::TerraformToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TerraformToolbarWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TerraformToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::EditorTerraformToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::EditorTerraformToolbarWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::EditorTerraformToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::VehicleTimetableWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleTimetableWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleTimetableWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::ToolbarNormalWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolbarNormalWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolbarNormalWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::ToolbarEditorWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolbarEditorWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolbarEditorWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::TownDirectoryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownDirectoryWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownDirectoryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::TownAuthorityWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownAuthorityWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownAuthorityWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::TownViewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownViewWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::TownFoundingWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownFoundingWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownFoundingWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::TransparencyToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TransparencyToolbarWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TransparencyToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::BuildTreesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildTreesWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildTreesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::VehicleViewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleViewWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::VehicleRefitWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleRefitWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleRefitWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::VehicleDetailsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleDetailsWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleDetailsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::VehicleListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleListWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::ExtraViewportWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ExtraViewportWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ExtraViewportWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::WaypointWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::WaypointWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::WaypointWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - - /* Allow ScriptWindow to be used as Squirrel parameter */ - template <> inline ScriptWindow *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWindow *)instance; } - template <> inline ScriptWindow &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWindow *)instance; } - template <> inline const ScriptWindow *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWindow *)instance; } - template <> inline const ScriptWindow &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWindow *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Window", res, NULL, DefSQDestructorCallback, true); return 1; } -} // namespace SQConvert diff --git a/src/settings.cpp.orig b/src/settings.cpp.orig deleted file mode 100644 index 970c169b4a..0000000000 --- a/src/settings.cpp.orig +++ /dev/null @@ -1,2174 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** - * @file settings.cpp - * All actions handling saving and loading of the settings/configuration goes on in this file. - * The file consists of three parts: - *
    - *
  1. Parsing the configuration file (openttd.cfg). This is achieved with the ini_ functions which - * handle various types, such as normal 'key = value' pairs, lists and value combinations of - * lists, strings, integers, 'bit'-masks and element selections. - *
  2. Handle reading and writing to the setting-structures from inside the game either from - * the console for example or through the gui with CMD_ functions. - *
  3. Handle saving/loading of the PATS chunk inside the savegame. - *
- * @see SettingDesc - * @see SaveLoad - */ - -#include "stdafx.h" -#include "currency.h" -#include "screenshot.h" -#include "network/network.h" -#include "network/network_func.h" -#include "settings_internal.h" -#include "command_func.h" -#include "console_func.h" -#include "pathfinder/pathfinder_type.h" -#include "genworld.h" -#include "train.h" -#include "news_func.h" -#include "window_func.h" -#include "sound_func.h" -#include "company_func.h" -#include "rev.h" -#ifdef WITH_FREETYPE -#include "fontcache.h" -#endif -#include "textbuf_gui.h" -#include "rail_gui.h" -#include "elrail_func.h" -#include "error.h" -#include "town.h" -#include "video/video_driver.hpp" -#include "sound/sound_driver.hpp" -#include "music/music_driver.hpp" -#include "blitter/factory.hpp" -#include "base_media_base.h" -#include "gamelog.h" -#include "settings_func.h" -#include "ini_type.h" -#include "ai/ai_config.hpp" -#include "ai/ai.hpp" -#include "game/game_config.hpp" -#include "game/game.hpp" -#include "ship.h" -#include "smallmap_gui.h" -#include "roadveh.h" -#include "fios.h" -#include "strings_func.h" - -#include "void_map.h" -#include "station_base.h" - -#include "table/strings.h" -#include "table/settings.h" - -ClientSettings _settings_client; -GameSettings _settings_game; ///< Game settings of a running game or the scenario editor. -GameSettings _settings_newgame; ///< Game settings for new games (updated from the intro screen). -VehicleDefaultSettings _old_vds; ///< Used for loading default vehicles settings from old savegames -char *_config_file; ///< Configuration file of OpenTTD - -typedef std::list ErrorList; -static ErrorList _settings_error_list; ///< Errors while loading minimal settings. - - -typedef void SettingDescProc(IniFile *ini, const SettingDesc *desc, const char *grpname, void *object); -typedef void SettingDescProcList(IniFile *ini, const char *grpname, StringList *list); - -static bool IsSignedVarMemType(VarType vt); - -/** - * Groups in openttd.cfg that are actually lists. - */ -static const char * const _list_group_names[] = { - "bans", - "newgrf", - "servers", - "server_bind_addresses", - NULL -}; - -/** - * Find the index value of a ONEofMANY type in a string separated by | - * @param many full domain of values the ONEofMANY setting can have - * @param one the current value of the setting for which a value needs found - * @param onelen force calculation of the *one parameter - * @return the integer index of the full-list, or -1 if not found - */ -static size_t LookupOneOfMany(const char *many, const char *one, size_t onelen = 0) -{ - const char *s; - size_t idx; - - if (onelen == 0) onelen = strlen(one); - - /* check if it's an integer */ - if (*one >= '0' && *one <= '9') return strtoul(one, NULL, 0); - - idx = 0; - for (;;) { - /* find end of item */ - s = many; - while (*s != '|' && *s != 0) s++; - if ((size_t)(s - many) == onelen && !memcmp(one, many, onelen)) return idx; - if (*s == 0) return (size_t)-1; - many = s + 1; - idx++; - } -} - -/** - * Find the set-integer value MANYofMANY type in a string - * @param many full domain of values the MANYofMANY setting can have - * @param str the current string value of the setting, each individual - * of separated by a whitespace,tab or | character - * @return the 'fully' set integer, or -1 if a set is not found - */ -static size_t LookupManyOfMany(const char *many, const char *str) -{ - const char *s; - size_t r; - size_t res = 0; - - for (;;) { - /* skip "whitespace" */ - while (*str == ' ' || *str == '\t' || *str == '|') str++; - if (*str == 0) break; - - s = str; - while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++; - - r = LookupOneOfMany(many, str, s - str); - if (r == (size_t)-1) return r; - - SetBit(res, (uint8)r); // value found, set it - if (*s == 0) break; - str = s + 1; - } - return res; -} - -/** - * Parse an integerlist string and set each found value - * @param p the string to be parsed. Each element in the list is separated by a - * comma or a space character - * @param items pointer to the integerlist-array that will be filled with values - * @param maxitems the maximum number of elements the integerlist-array has - * @return returns the number of items found, or -1 on an error - */ -static int ParseIntList(const char *p, int *items, int maxitems) -{ - int n = 0; // number of items read so far - bool comma = false; // do we accept comma? - - while (*p != '\0') { - switch (*p) { - case ',': - /* Do not accept multiple commas between numbers */ - if (!comma) return -1; - comma = false; - /* FALL THROUGH */ - case ' ': - p++; - break; - - default: { - if (n == maxitems) return -1; // we don't accept that many numbers - char *end; - long v = strtol(p, &end, 0); - if (p == end) return -1; // invalid character (not a number) - if (sizeof(int) < sizeof(long)) v = ClampToI32(v); - items[n++] = v; - p = end; // first non-number - comma = true; // we accept comma now - break; - } - } - } - - /* If we have read comma but no number after it, fail. - * We have read comma when (n != 0) and comma is not allowed */ - if (n != 0 && !comma) return -1; - - return n; -} - -/** - * Load parsed string-values into an integer-array (intlist) - * @param str the string that contains the values (and will be parsed) - * @param array pointer to the integer-arrays that will be filled - * @param nelems the number of elements the array holds. Maximum is 64 elements - * @param type the type of elements the array holds (eg INT8, UINT16, etc.) - * @return return true on success and false on error - */ -static bool LoadIntList(const char *str, void *array, int nelems, VarType type) -{ - int items[64]; - int i, nitems; - - if (str == NULL) { - memset(items, 0, sizeof(items)); - nitems = nelems; - } else { - nitems = ParseIntList(str, items, lengthof(items)); - if (nitems != nelems) return false; - } - - switch (type) { - case SLE_VAR_BL: - case SLE_VAR_I8: - case SLE_VAR_U8: - for (i = 0; i != nitems; i++) ((byte*)array)[i] = items[i]; - break; - - case SLE_VAR_I16: - case SLE_VAR_U16: - for (i = 0; i != nitems; i++) ((uint16*)array)[i] = items[i]; - break; - - case SLE_VAR_I32: - case SLE_VAR_U32: - for (i = 0; i != nitems; i++) ((uint32*)array)[i] = items[i]; - break; - - default: NOT_REACHED(); - } - - return true; -} - -/** - * Convert an integer-array (intlist) to a string representation. Each value - * is separated by a comma or a space character - * @param buf output buffer where the string-representation will be stored - * @param last last item to write to in the output buffer - * @param array pointer to the integer-arrays that is read from - * @param nelems the number of elements the array holds. - * @param type the type of elements the array holds (eg INT8, UINT16, etc.) - */ -static void MakeIntList(char *buf, const char *last, const void *array, int nelems, VarType type) -{ - int i, v = 0; - const byte *p = (const byte *)array; - - for (i = 0; i != nelems; i++) { - switch (type) { - case SLE_VAR_BL: - case SLE_VAR_I8: v = *(const int8 *)p; p += 1; break; - case SLE_VAR_U8: v = *(const uint8 *)p; p += 1; break; - case SLE_VAR_I16: v = *(const int16 *)p; p += 2; break; - case SLE_VAR_U16: v = *(const uint16 *)p; p += 2; break; - case SLE_VAR_I32: v = *(const int32 *)p; p += 4; break; - case SLE_VAR_U32: v = *(const uint32 *)p; p += 4; break; - default: NOT_REACHED(); - } - buf += seprintf(buf, last, (i == 0) ? "%d" : ",%d", v); - } -} - -/** - * Convert a ONEofMANY structure to a string representation. - * @param buf output buffer where the string-representation will be stored - * @param last last item to write to in the output buffer - * @param many the full-domain string of possible values - * @param id the value of the variable and whose string-representation must be found - */ -static void MakeOneOfMany(char *buf, const char *last, const char *many, int id) -{ - int orig_id = id; - - /* Look for the id'th element */ - while (--id >= 0) { - for (; *many != '|'; many++) { - if (*many == '\0') { // not found - seprintf(buf, last, "%d", orig_id); - return; - } - } - many++; // pass the |-character - } - - /* copy string until next item (|) or the end of the list if this is the last one */ - while (*many != '\0' && *many != '|' && buf < last) *buf++ = *many++; - *buf = '\0'; -} - -/** - * Convert a MANYofMANY structure to a string representation. - * @param buf output buffer where the string-representation will be stored - * @param last last item to write to in the output buffer - * @param many the full-domain string of possible values - * @param x the value of the variable and whose string-representation must - * be found in the bitmasked many string - */ -static void MakeManyOfMany(char *buf, const char *last, const char *many, uint32 x) -{ - const char *start; - int i = 0; - bool init = true; - - for (; x != 0; x >>= 1, i++) { - start = many; - while (*many != 0 && *many != '|') many++; // advance to the next element - - if (HasBit(x, 0)) { // item found, copy it - if (!init) buf += seprintf(buf, last, "|"); - init = false; - if (start == many) { - buf += seprintf(buf, last, "%d", i); - } else { - memcpy(buf, start, many - start); - buf += many - start; - } - } - - if (*many == '|') many++; - } - - *buf = '\0'; -} - -/** - * Convert a string representation (external) of a setting to the internal rep. - * @param desc SettingDesc struct that holds all information about the variable - * @param orig_str input string that will be parsed based on the type of desc - * @return return the parsed value of the setting - */ -static const void *StringToVal(const SettingDescBase *desc, const char *orig_str) -{ - const char *str = orig_str == NULL ? "" : orig_str; - - switch (desc->cmd) { - case SDT_NUMX: { - char *end; - size_t val = strtoul(str, &end, 0); - if (end == str) { - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); - msg.SetDParamStr(0, str); - msg.SetDParamStr(1, desc->name); - _settings_error_list.push_back(msg); - return desc->def; - } - if (*end != '\0') { - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_TRAILING_CHARACTERS); - msg.SetDParamStr(0, desc->name); - _settings_error_list.push_back(msg); - } - return (void*)val; - } - - case SDT_ONEOFMANY: { - size_t r = LookupOneOfMany(desc->many, str); - /* if the first attempt of conversion from string to the appropriate value fails, - * look if we have defined a converter from old value to new value. */ - if (r == (size_t)-1 && desc->proc_cnvt != NULL) r = desc->proc_cnvt(str); - if (r != (size_t)-1) return (void*)r; // and here goes converted value - - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); - msg.SetDParamStr(0, str); - msg.SetDParamStr(1, desc->name); - _settings_error_list.push_back(msg); - return desc->def; - } - - case SDT_MANYOFMANY: { - size_t r = LookupManyOfMany(desc->many, str); - if (r != (size_t)-1) return (void*)r; - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); - msg.SetDParamStr(0, str); - msg.SetDParamStr(1, desc->name); - _settings_error_list.push_back(msg); - return desc->def; - } - - case SDT_BOOLX: { - if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return (void*)true; - if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return (void*)false; - - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); - msg.SetDParamStr(0, str); - msg.SetDParamStr(1, desc->name); - _settings_error_list.push_back(msg); - return desc->def; - } - - case SDT_STRING: return orig_str; - case SDT_INTLIST: return str; - default: break; - } - - return NULL; -} - -/** - * Set the value of a setting and if needed clamp the value to - * the preset minimum and maximum. - * @param ptr the variable itself - * @param sd pointer to the 'information'-database of the variable - * @param val signed long version of the new value - * @pre SettingDesc is of type SDT_BOOLX, SDT_NUMX, - * SDT_ONEOFMANY or SDT_MANYOFMANY. Other types are not supported as of now - */ -static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val) -{ - const SettingDescBase *sdb = &sd->desc; - - if (sdb->cmd != SDT_BOOLX && - sdb->cmd != SDT_NUMX && - sdb->cmd != SDT_ONEOFMANY && - sdb->cmd != SDT_MANYOFMANY) { - return; - } - - /* We cannot know the maximum value of a bitset variable, so just have faith */ - if (sdb->cmd != SDT_MANYOFMANY) { - /* We need to take special care of the uint32 type as we receive from the function - * a signed integer. While here also bail out on 64-bit settings as those are not - * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed - * 32-bit variable - * TODO: Support 64-bit settings/variables */ - switch (GetVarMemType(sd->save.conv)) { - case SLE_VAR_NULL: return; - case SLE_VAR_BL: - case SLE_VAR_I8: - case SLE_VAR_U8: - case SLE_VAR_I16: - case SLE_VAR_U16: - case SLE_VAR_I32: { - /* Override the minimum value. No value below sdb->min, except special value 0 */ - if (!(sdb->flags & SGF_0ISDISABLED) || val != 0) val = Clamp(val, sdb->min, sdb->max); - break; - } - case SLE_VAR_U32: { - /* Override the minimum value. No value below sdb->min, except special value 0 */ - uint min = ((sdb->flags & SGF_0ISDISABLED) && (uint)val <= (uint)sdb->min) ? 0 : sdb->min; - WriteValue(ptr, SLE_VAR_U32, (int64)ClampU(val, min, sdb->max)); - return; - } - case SLE_VAR_I64: - case SLE_VAR_U64: - default: NOT_REACHED(); - } - } - - WriteValue(ptr, sd->save.conv, (int64)val); -} - -/** - * Load values from a group of an IniFile structure into the internal representation - * @param ini pointer to IniFile structure that holds administrative information - * @param sd pointer to SettingDesc structure whose internally pointed variables will - * be given values - * @param grpname the group of the IniFile to search in for the new values - * @param object pointer to the object been loaded - */ -static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object) -{ - IniGroup *group; - IniGroup *group_def = ini->GetGroup(grpname); - IniItem *item; - const void *p; - void *ptr; - const char *s; - - for (; sd->save.cmd != SL_END; sd++) { - const SettingDescBase *sdb = &sd->desc; - const SaveLoad *sld = &sd->save; - - if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue; - - /* For settings.xx.yy load the settings from [xx] yy = ? */ - s = strchr(sdb->name, '.'); - if (s != NULL) { - group = ini->GetGroup(sdb->name, s - sdb->name); - s++; - } else { - s = sdb->name; - group = group_def; - } - - item = group->GetItem(s, false); - if (item == NULL && group != group_def) { - /* For settings.xx.yy load the settings from [settingss] yy = ? in case the previous - * did not exist (e.g. loading old config files with a [settings] section */ - item = group_def->GetItem(s, false); - } - if (item == NULL) { - /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous - * did not exist (e.g. loading old config files with a [yapf] section */ - const char *sc = strchr(s, '.'); - if (sc != NULL) item = ini->GetGroup(s, sc - s)->GetItem(sc + 1, false); - } - - p = (item == NULL) ? sdb->def : StringToVal(sdb, item->value); - ptr = GetVariableAddress(object, sld); - - switch (sdb->cmd) { - case SDT_BOOLX: // All four are various types of (integer) numbers - case SDT_NUMX: - case SDT_ONEOFMANY: - case SDT_MANYOFMANY: - Write_ValidateSetting(ptr, sd, (int32)(size_t)p); - break; - - case SDT_STRING: - switch (GetVarMemType(sld->conv)) { - case SLE_VAR_STRB: - case SLE_VAR_STRBQ: - if (p != NULL) ttd_strlcpy((char*)ptr, (const char*)p, sld->length); - break; - - case SLE_VAR_STR: - case SLE_VAR_STRQ: - free(*(char**)ptr); - *(char**)ptr = p == NULL ? NULL : strdup((const char*)p); - break; - - case SLE_VAR_CHAR: if (p != NULL) *(char *)ptr = *(const char *)p; break; - - default: NOT_REACHED(); - } - break; - - case SDT_INTLIST: { - if (!LoadIntList((const char*)p, ptr, sld->length, GetVarMemType(sld->conv))) { - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY); - msg.SetDParamStr(0, sdb->name); - _settings_error_list.push_back(msg); - - /* Use default */ - LoadIntList((const char*)sdb->def, ptr, sld->length, GetVarMemType(sld->conv)); - } else if (sd->desc.proc_cnvt != NULL) { - sd->desc.proc_cnvt((const char*)p); - } - break; - } - default: NOT_REACHED(); - } - } -} - -/** - * Save the values of settings to the inifile. - * @param ini pointer to IniFile structure - * @param sd read-only SettingDesc structure which contains the unmodified, - * loaded values of the configuration file and various information about it - * @param grpname holds the name of the group (eg. [network]) where these will be saved - * @param object pointer to the object been saved - * The function works as follows: for each item in the SettingDesc structure we - * have a look if the value has changed since we started the game (the original - * values are reloaded when saving). If settings indeed have changed, we get - * these and save them. - */ -static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object) -{ - IniGroup *group_def = NULL, *group; - IniItem *item; - char buf[512]; - const char *s; - void *ptr; - - for (; sd->save.cmd != SL_END; sd++) { - const SettingDescBase *sdb = &sd->desc; - const SaveLoad *sld = &sd->save; - - /* If the setting is not saved to the configuration - * file, just continue with the next setting */ - if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue; - if (sld->conv & SLF_NOT_IN_CONFIG) continue; - - /* XXX - wtf is this?? (group override?) */ - s = strchr(sdb->name, '.'); - if (s != NULL) { - group = ini->GetGroup(sdb->name, s - sdb->name); - s++; - } else { - if (group_def == NULL) group_def = ini->GetGroup(grpname); - s = sdb->name; - group = group_def; - } - - item = group->GetItem(s, true); - ptr = GetVariableAddress(object, sld); - - if (item->value != NULL) { - /* check if the value is the same as the old value */ - const void *p = StringToVal(sdb, item->value); - - /* The main type of a variable/setting is in bytes 8-15 - * The subtype (what kind of numbers do we have there) is in 0-7 */ - switch (sdb->cmd) { - case SDT_BOOLX: - case SDT_NUMX: - case SDT_ONEOFMANY: - case SDT_MANYOFMANY: - switch (GetVarMemType(sld->conv)) { - case SLE_VAR_BL: - if (*(bool*)ptr == (p != NULL)) continue; - break; - - case SLE_VAR_I8: - case SLE_VAR_U8: - if (*(byte*)ptr == (byte)(size_t)p) continue; - break; - - case SLE_VAR_I16: - case SLE_VAR_U16: - if (*(uint16*)ptr == (uint16)(size_t)p) continue; - break; - - case SLE_VAR_I32: - case SLE_VAR_U32: - if (*(uint32*)ptr == (uint32)(size_t)p) continue; - break; - - default: NOT_REACHED(); - } - break; - - default: break; // Assume the other types are always changed - } - } - - /* Value has changed, get the new value and put it into a buffer */ - switch (sdb->cmd) { - case SDT_BOOLX: - case SDT_NUMX: - case SDT_ONEOFMANY: - case SDT_MANYOFMANY: { - uint32 i = (uint32)ReadValue(ptr, sld->conv); - - switch (sdb->cmd) { - case SDT_BOOLX: strecpy(buf, (i != 0) ? "true" : "false", lastof(buf)); break; - case SDT_NUMX: seprintf(buf, lastof(buf), IsSignedVarMemType(sld->conv) ? "%d" : "%u", i); break; - case SDT_ONEOFMANY: MakeOneOfMany(buf, lastof(buf), sdb->many, i); break; - case SDT_MANYOFMANY: MakeManyOfMany(buf, lastof(buf), sdb->many, i); break; - default: NOT_REACHED(); - } - break; - } - - case SDT_STRING: - switch (GetVarMemType(sld->conv)) { - case SLE_VAR_STRB: strecpy(buf, (char*)ptr, lastof(buf)); break; - case SLE_VAR_STRBQ:seprintf(buf, lastof(buf), "\"%s\"", (char*)ptr); break; - case SLE_VAR_STR: strecpy(buf, *(char**)ptr, lastof(buf)); break; - - case SLE_VAR_STRQ: - if (*(char**)ptr == NULL) { - buf[0] = '\0'; - } else { - seprintf(buf, lastof(buf), "\"%s\"", *(char**)ptr); - } - break; - - case SLE_VAR_CHAR: buf[0] = *(char*)ptr; buf[1] = '\0'; break; - default: NOT_REACHED(); - } - break; - - case SDT_INTLIST: - MakeIntList(buf, lastof(buf), ptr, sld->length, GetVarMemType(sld->conv)); - break; - - default: NOT_REACHED(); - } - - /* The value is different, that means we have to write it to the ini */ - free(item->value); - item->value = strdup(buf); - } -} - -/** - * Loads all items from a 'grpname' section into a list - * The list parameter can be a NULL pointer, in this case nothing will be - * saved and a callback function should be defined that will take over the - * list-handling and store the data itself somewhere. - * @param ini IniFile handle to the ini file with the source data - * @param grpname character string identifying the section-header of the ini file that will be parsed - * @param list new list with entries of the given section - */ -static void IniLoadSettingList(IniFile *ini, const char *grpname, StringList *list) -{ - IniGroup *group = ini->GetGroup(grpname); - - if (group == NULL || list == NULL) return; - - list->Clear(); - - for (const IniItem *item = group->item; item != NULL; item = item->next) { - if (item->name != NULL) *list->Append() = strdup(item->name); - } -} - -/** - * Saves all items from a list into the 'grpname' section - * The list parameter can be a NULL pointer, in this case a callback function - * should be defined that will provide the source data to be saved. - * @param ini IniFile handle to the ini file where the destination data is saved - * @param grpname character string identifying the section-header of the ini file - * @param list pointer to an string(pointer) array that will be used as the - * source to be saved into the relevant ini section - */ -static void IniSaveSettingList(IniFile *ini, const char *grpname, StringList *list) -{ - IniGroup *group = ini->GetGroup(grpname); - - if (group == NULL || list == NULL) return; - group->Clear(); - - for (char **iter = list->Begin(); iter != list->End(); iter++) { - group->GetItem(*iter, true)->SetValue(""); - } -} - -/** - * Load a WindowDesc from config. - * @param ini IniFile handle to the ini file with the source data - * @param grpname character string identifying the section-header of the ini file that will be parsed - * @param desc Destination WindowDesc - */ -void IniLoadWindowSettings(IniFile *ini, const char *grpname, void *desc) -{ - IniLoadSettings(ini, _window_settings, grpname, desc); -} - -/** - * Save a WindowDesc to config. - * @param ini IniFile handle to the ini file where the destination data is saved - * @param grpname character string identifying the section-header of the ini file - * @param desc Source WindowDesc - */ -void IniSaveWindowSettings(IniFile *ini, const char *grpname, void *desc) -{ - IniSaveSettings(ini, _window_settings, grpname, desc); -} - -/** - * Check whether the setting is editable in the current gamemode. - * @param do_command true if this is about checking a command from the server. - * @return true if editable. - */ -bool SettingDesc::IsEditable(bool do_command) const -{ - if (!do_command && !(this->save.conv & SLF_NO_NETWORK_SYNC) && _networking && !_network_server && !(this->desc.flags & SGF_PER_COMPANY)) return false; - if ((this->desc.flags & SGF_NETWORK_ONLY) && !_networking && _game_mode != GM_MENU) return false; - if ((this->desc.flags & SGF_NO_NETWORK) && _networking) return false; - if ((this->desc.flags & SGF_NEWGAME_ONLY) && - (_game_mode == GM_NORMAL || - (_game_mode == GM_EDITOR && !(this->desc.flags & SGF_SCENEDIT_TOO)))) return false; - return true; -} - -/** - * Return the type of the setting. - * @return type of setting - */ -SettingType SettingDesc::GetType() const -{ - if (this->desc.flags & SGF_PER_COMPANY) return ST_COMPANY; - return (this->save.conv & SLF_NOT_IN_SAVE) ? ST_CLIENT : ST_GAME; -} - -/* Begin - Callback Functions for the various settings. */ - -/** Reposition the main toolbar as the setting changed. */ -static bool v_PositionMainToolbar(int32 p1) -{ - if (_game_mode != GM_MENU) PositionMainToolbar(NULL); - return true; -} - -/** Reposition the statusbar as the setting changed. */ -static bool v_PositionStatusbar(int32 p1) -{ - if (_game_mode != GM_MENU) { - PositionStatusbar(NULL); - PositionNewsMessage(NULL); - PositionNetworkChatWindow(NULL); - } - return true; -} - -static bool PopulationInLabelActive(int32 p1) -{ - UpdateAllTownVirtCoords(); - return true; -} - -static bool RedrawScreen(int32 p1) -{ - MarkWholeScreenDirty(); - return true; -} - -/** - * Redraw the smallmap after a colour scheme change. - * @param p1 Callback parameter. - * @return Always true. - */ -static bool RedrawSmallmap(int32 p1) -{ - BuildLandLegend(); - BuildOwnerLegend(); - SetWindowClassesDirty(WC_SMALLMAP); - return true; -} - -static bool InvalidateDetailsWindow(int32 p1) -{ - SetWindowClassesDirty(WC_VEHICLE_DETAILS); - return true; -} - -static bool StationSpreadChanged(int32 p1) -{ - InvalidateWindowData(WC_SELECT_STATION, 0); - InvalidateWindowData(WC_BUILD_STATION, 0); - return true; -} - -static bool InvalidateBuildIndustryWindow(int32 p1) -{ - InvalidateWindowData(WC_BUILD_INDUSTRY, 0); - return true; -} - -static bool CloseSignalGUI(int32 p1) -{ - if (p1 == 0) { - DeleteWindowByClass(WC_BUILD_SIGNAL); - } - return true; -} - -static bool InvalidateTownViewWindow(int32 p1) -{ - InvalidateWindowClassesData(WC_TOWN_VIEW, p1); - return true; -} - -static bool DeleteSelectStationWindow(int32 p1) -{ - DeleteWindowById(WC_SELECT_STATION, 0); - return true; -} - -static bool UpdateConsists(int32 p1) -{ - Train *t; - FOR_ALL_TRAINS(t) { - /* Update the consist of all trains so the maximum speed is set correctly. */ - if (t->IsFrontEngine() || t->IsFreeWagon()) t->ConsistChanged(CCF_TRACK); - } - InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0); - return true; -} - -/* Check service intervals of vehicles, p1 is value of % or day based servicing */ -static bool CheckInterval(int32 p1) -{ - bool update_vehicles; - VehicleDefaultSettings *vds; - if (_game_mode == GM_MENU || !Company::IsValidID(_current_company)) { - vds = &_settings_client.company.vehicle; - update_vehicles = false; - } else { - vds = &Company::Get(_current_company)->settings.vehicle; - update_vehicles = true; - } - - if (p1 != 0) { - vds->servint_trains = 50; - vds->servint_roadveh = 50; - vds->servint_aircraft = 50; - vds->servint_ships = 50; - } else { - vds->servint_trains = 150; - vds->servint_roadveh = 150; - vds->servint_aircraft = 100; - vds->servint_ships = 360; - } - - if (update_vehicles) { - const Company *c = Company::Get(_current_company); - Vehicle *v; - FOR_ALL_VEHICLES(v) { - if (v->owner == _current_company && v->IsPrimaryVehicle() && !v->ServiceIntervalIsCustom()) { - v->SetServiceInterval(CompanyServiceInterval(c, v->type)); - v->SetServiceIntervalIsPercent(p1 != 0); - } - } - } - - InvalidateDetailsWindow(0); - - return true; -} - -static bool UpdateInterval(VehicleType type, int32 p1) -{ - bool update_vehicles; - VehicleDefaultSettings *vds; - if (_game_mode == GM_MENU || !Company::IsValidID(_current_company)) { - vds = &_settings_client.company.vehicle; - update_vehicles = false; - } else { - vds = &Company::Get(_current_company)->settings.vehicle; - update_vehicles = true; - } - - /* Test if the interval is valid */ - uint16 interval = GetServiceIntervalClamped(p1, vds->servint_ispercent); - if (interval != p1) return false; - - if (update_vehicles) { - Vehicle *v; - FOR_ALL_VEHICLES(v) { - if (v->owner == _current_company && v->type == type && v->IsPrimaryVehicle() && !v->ServiceIntervalIsCustom()) { - v->SetServiceInterval(p1); - } - } - } - - InvalidateDetailsWindow(0); - - return true; -} - -static bool UpdateIntervalTrains(int32 p1) -{ - return UpdateInterval(VEH_TRAIN, p1); -} - -static bool UpdateIntervalRoadVeh(int32 p1) -{ - return UpdateInterval(VEH_ROAD, p1); -} - -static bool UpdateIntervalShips(int32 p1) -{ - return UpdateInterval(VEH_SHIP, p1); -} - -static bool UpdateIntervalAircraft(int32 p1) -{ - return UpdateInterval(VEH_AIRCRAFT, p1); -} - -static bool TrainAccelerationModelChanged(int32 p1) -{ - Train *t; - FOR_ALL_TRAINS(t) { - if (t->IsFrontEngine()) { - t->tcache.cached_max_curve_speed = t->GetCurveSpeedLimit(); - t->UpdateAcceleration(); - } - } - - /* These windows show acceleration values only when realistic acceleration is on. They must be redrawn after a setting change. */ - SetWindowClassesDirty(WC_ENGINE_PREVIEW); - InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0); - SetWindowClassesDirty(WC_VEHICLE_DETAILS); - - return true; -} - -/** - * This function updates the train acceleration cache after a steepness change. - * @param p1 Callback parameter. - * @return Always true. - */ -static bool TrainSlopeSteepnessChanged(int32 p1) -{ - Train *t; - FOR_ALL_TRAINS(t) { - if (t->IsFrontEngine()) t->CargoChanged(); - } - - return true; -} - -/** - * This function updates realistic acceleration caches when the setting "Road vehicle acceleration model" is set. - * @param p1 Callback parameter - * @return Always true - */ -static bool RoadVehAccelerationModelChanged(int32 p1) -{ - if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) { - RoadVehicle *rv; - FOR_ALL_ROADVEHICLES(rv) { - if (rv->IsFrontEngine()) { - rv->CargoChanged(); - } - } - } - - /* These windows show acceleration values only when realistic acceleration is on. They must be redrawn after a setting change. */ - SetWindowClassesDirty(WC_ENGINE_PREVIEW); - InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0); - SetWindowClassesDirty(WC_VEHICLE_DETAILS); - - return true; -} - -/** - * This function updates the road vehicle acceleration cache after a steepness change. - * @param p1 Callback parameter. - * @return Always true. - */ -static bool RoadVehSlopeSteepnessChanged(int32 p1) -{ - RoadVehicle *rv; - FOR_ALL_ROADVEHICLES(rv) { - if (rv->IsFrontEngine()) rv->CargoChanged(); - } - - return true; -} - -static bool DragSignalsDensityChanged(int32) -{ - InvalidateWindowData(WC_BUILD_SIGNAL, 0); - - return true; -} - -static bool TownFoundingChanged(int32 p1) -{ - if (_game_mode != GM_EDITOR && _settings_game.economy.found_town == TF_FORBIDDEN) { - DeleteWindowById(WC_FOUND_TOWN, 0); - return true; - } - InvalidateWindowData(WC_FOUND_TOWN, 0); - return true; -} - -static bool InvalidateVehTimetableWindow(int32 p1) -{ - InvalidateWindowClassesData(WC_VEHICLE_TIMETABLE, VIWD_MODIFY_ORDERS); - return true; -} - -static bool ZoomMinMaxChanged(int32 p1) -{ - extern void ConstrainAllViewportsZoom(); - ConstrainAllViewportsZoom(); - GfxClearSpriteCache(); - return true; -} - -/** - * Update any possible saveload window and delete any newgrf dialogue as - * its widget parts might change. Reinit all windows as it allows access to the - * newgrf debug button. - * @param p1 unused. - * @return Always true. - */ -static bool InvalidateNewGRFChangeWindows(int32 p1) -{ - InvalidateWindowClassesData(WC_SAVELOAD); - DeleteWindowByClass(WC_GAME_OPTIONS); - ReInitAllWindows(); - return true; -} - -static bool InvalidateCompanyLiveryWindow(int32 p1) -{ - InvalidateWindowClassesData(WC_COMPANY_COLOUR); - return RedrawScreen(p1); -} - -static bool InvalidateIndustryViewWindow(int32 p1) -{ - InvalidateWindowClassesData(WC_INDUSTRY_VIEW); - return true; -} - -static bool InvalidateAISettingsWindow(int32 p1) -{ - InvalidateWindowClassesData(WC_AI_SETTINGS); - return true; -} - -/** - * Update the town authority window after a town authority setting change. - * @param p1 Unused. - * @return Always true. - */ -static bool RedrawTownAuthority(int32 p1) -{ - SetWindowClassesDirty(WC_TOWN_AUTHORITY); - return true; -} - -/** - * Invalidate the company infrastructure details window after a infrastructure maintenance setting change. - * @param p1 Unused. - * @return Always true. - */ -static bool InvalidateCompanyInfrastructureWindow(int32 p1) -{ - InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); - return true; -} - -/** - * Invalidate the company details window after the shares setting changed. - * @param p1 Unused. - * @return Always true. - */ -static bool InvalidateCompanyWindow(int32 p1) -{ - InvalidateWindowClassesData(WC_COMPANY); - return true; -} - -/** Checks if any settings are set to incorrect values, and sets them to correct values in that case. */ -static void ValidateSettings() -{ - /* Do not allow a custom sea level with the original land generator. */ - if (_settings_newgame.game_creation.land_generator == 0 && - _settings_newgame.difficulty.quantity_sea_lakes == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) { - _settings_newgame.difficulty.quantity_sea_lakes = CUSTOM_SEA_LEVEL_MIN_PERCENTAGE; - } -} - -static bool DifficultyNoiseChange(int32 i) -{ - if (_game_mode == GM_NORMAL) { - UpdateAirportsNoise(); - if (_settings_game.economy.station_noise_level) { - InvalidateWindowClassesData(WC_TOWN_VIEW, 0); - } - } - - return true; -} - -static bool MaxNoAIsChange(int32 i) -{ - if (GetGameSettings().difficulty.max_no_competitors != 0 && - AI::GetInfoList()->size() == 0 && - (!_networking || _network_server)) { - ShowErrorMessage(STR_WARNING_NO_SUITABLE_AI, INVALID_STRING_ID, WL_CRITICAL); - } - - return true; -} - -/** - * Check whether the road side may be changed. - * @param p1 unused - * @return true if the road side may be changed. - */ -static bool CheckRoadSide(int p1) -{ - extern bool RoadVehiclesAreBuilt(); - return _game_mode == GM_MENU || !RoadVehiclesAreBuilt(); -} - -/** - * Conversion callback for _gameopt_settings_game.landscape - * It converts (or try) between old values and the new ones, - * without losing initial setting of the user - * @param value that was read from config file - * @return the "hopefully" converted value - */ -static size_t ConvertLandscape(const char *value) -{ - /* try with the old values */ - return LookupOneOfMany("normal|hilly|desert|candy", value); -} - -static bool CheckFreeformEdges(int32 p1) -{ - if (_game_mode == GM_MENU) return true; - if (p1 != 0) { - Ship *s; - FOR_ALL_SHIPS(s) { - /* Check if there is a ship on the northern border. */ - if (TileX(s->tile) == 0 || TileY(s->tile) == 0) { - ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, WL_ERROR); - return false; - } - } - BaseStation *st; - FOR_ALL_BASE_STATIONS(st) { - /* Check if there is a non-deleted buoy on the northern border. */ - if (st->IsInUse() && (TileX(st->xy) == 0 || TileY(st->xy) == 0)) { - ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, WL_ERROR); - return false; - } - } - for (uint i = 0; i < MapSizeX(); i++) MakeVoid(TileXY(i, 0)); - for (uint i = 0; i < MapSizeY(); i++) MakeVoid(TileXY(0, i)); - } else { - for (uint i = 0; i < MapMaxX(); i++) { - if (TileHeight(TileXY(i, 1)) != 0) { - ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR); - return false; - } - } - for (uint i = 1; i < MapMaxX(); i++) { - if (!IsTileType(TileXY(i, MapMaxY() - 1), MP_WATER) || TileHeight(TileXY(1, MapMaxY())) != 0) { - ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR); - return false; - } - } - for (uint i = 0; i < MapMaxY(); i++) { - if (TileHeight(TileXY(1, i)) != 0) { - ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR); - return false; - } - } - for (uint i = 1; i < MapMaxY(); i++) { - if (!IsTileType(TileXY(MapMaxX() - 1, i), MP_WATER) || TileHeight(TileXY(MapMaxX(), i)) != 0) { - ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR); - return false; - } - } - /* Make tiles at the border water again. */ - for (uint i = 0; i < MapMaxX(); i++) { - SetTileHeight(TileXY(i, 0), 0); - SetTileType(TileXY(i, 0), MP_WATER); - } - for (uint i = 0; i < MapMaxY(); i++) { - SetTileHeight(TileXY(0, i), 0); - SetTileType(TileXY(0, i), MP_WATER); - } - } - MarkWholeScreenDirty(); - return true; -} - -/** - * Changing the setting "allow multiple NewGRF sets" is not allowed - * if there are vehicles. - */ -static bool ChangeDynamicEngines(int32 p1) -{ - if (_game_mode == GM_MENU) return true; - - if (!EngineOverrideManager::ResetToCurrentNewGRFConfig()) { - ShowErrorMessage(STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES, INVALID_STRING_ID, WL_ERROR); - return false; - } - - return true; -} - -static bool StationCatchmentChanged(int32 p1) -{ - Station::RecomputeIndustriesNearForAll(); - return true; -} - - -#ifdef ENABLE_NETWORK - -static bool UpdateClientName(int32 p1) -{ - NetworkUpdateClientName(); - return true; -} - -static bool UpdateServerPassword(int32 p1) -{ - if (strcmp(_settings_client.network.server_password, "*") == 0) { - _settings_client.network.server_password[0] = '\0'; - } - - return true; -} - -static bool UpdateRconPassword(int32 p1) -{ - if (strcmp(_settings_client.network.rcon_password, "*") == 0) { - _settings_client.network.rcon_password[0] = '\0'; - } - - return true; -} - -static bool UpdateClientConfigValues(int32 p1) -{ - if (_network_server) NetworkServerSendConfigUpdate(); - - return true; -} - -#endif /* ENABLE_NETWORK */ - - -/* End - Callback Functions */ - -/** - * Prepare for reading and old diff_custom by zero-ing the memory. - */ -static void PrepareOldDiffCustom() -{ - memset(_old_diff_custom, 0, sizeof(_old_diff_custom)); -} - -/** - * Reading of the old diff_custom array and transforming it to the new format. - * @param savegame is it read from the config or savegame. In the latter case - * we are sure there is an array; in the former case we have - * to check that. - */ -static void HandleOldDiffCustom(bool savegame) -{ - uint options_to_load = GAME_DIFFICULTY_NUM - ((savegame && IsSavegameVersionBefore(4)) ? 1 : 0); - - if (!savegame) { - /* If we did read to old_diff_custom, then at least one value must be non 0. */ - bool old_diff_custom_used = false; - for (uint i = 0; i < options_to_load && !old_diff_custom_used; i++) { - old_diff_custom_used = (_old_diff_custom[i] != 0); - } - - if (!old_diff_custom_used) return; - } - - for (uint i = 0; i < options_to_load; i++) { - const SettingDesc *sd = &_settings[i]; - /* Skip deprecated options */ - if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; - void *var = GetVariableAddress(savegame ? &_settings_game : &_settings_newgame, &sd->save); - Write_ValidateSetting(var, sd, (int32)((i == 4 ? 1000 : 1) * _old_diff_custom[i])); - } -} - -static void AILoadConfig(IniFile *ini, const char *grpname) -{ - IniGroup *group = ini->GetGroup(grpname); - IniItem *item; - - /* Clean any configured AI */ - for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME)->Change(NULL); - } - - /* If no group exists, return */ - if (group == NULL) return; - - CompanyID c = COMPANY_FIRST; - for (item = group->item; c < MAX_COMPANIES && item != NULL; c++, item = item->next) { - AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME); - - config->Change(item->name); - if (!config->HasScript()) { - if (strcmp(item->name, "none") != 0) { - DEBUG(script, 0, "The AI by the name '%s' was no longer found, and removed from the list.", item->name); - continue; - } - } - if (item->value != NULL) config->StringToSettings(item->value); - } -} - -static void GameLoadConfig(IniFile *ini, const char *grpname) -{ - IniGroup *group = ini->GetGroup(grpname); - IniItem *item; - - /* Clean any configured GameScript */ - GameConfig::GetConfig(GameConfig::SSS_FORCE_NEWGAME)->Change(NULL); - - /* If no group exists, return */ - if (group == NULL) return; - - item = group->item; - if (item == NULL) return; - - GameConfig *config = GameConfig::GetConfig(AIConfig::SSS_FORCE_NEWGAME); - - config->Change(item->name); - if (!config->HasScript()) { - if (strcmp(item->name, "none") != 0) { - DEBUG(script, 0, "The GameScript by the name '%s' was no longer found, and removed from the list.", item->name); - return; - } - } - if (item->value != NULL) config->StringToSettings(item->value); -} - -/** - * Load a GRF configuration - * @param ini The configuration to read from. - * @param grpname Group name containing the configuration of the GRF. - * @param is_static GRF is static. - */ -static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_static) -{ - IniGroup *group = ini->GetGroup(grpname); - IniItem *item; - GRFConfig *first = NULL; - GRFConfig **curr = &first; - - if (group == NULL) return NULL; - - for (item = group->item; item != NULL; item = item->next) { - GRFConfig *c = new GRFConfig(item->name); - - /* Parse parameters */ - if (!StrEmpty(item->value)) { - c->num_params = ParseIntList(item->value, (int*)c->param, lengthof(c->param)); - if (c->num_params == (byte)-1) { - SetDParamStr(0, item->name); - ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL); - c->num_params = 0; - } - } - - /* Check if item is valid */ - if (!FillGRFDetails(c, is_static) || HasBit(c->flags, GCF_INVALID)) { - if (c->status == GCS_NOT_FOUND) { - SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND); - } else if (HasBit(c->flags, GCF_UNSAFE)) { - SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNSAFE); - } else if (HasBit(c->flags, GCF_SYSTEM)) { - SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_SYSTEM); - } else if (HasBit(c->flags, GCF_INVALID)) { - SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE); - } else { - SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN); - } - - SetDParamStr(0, item->name); - ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL); - delete c; - continue; - } - - /* Check for duplicate GRFID (will also check for duplicate filenames) */ - bool duplicate = false; - for (const GRFConfig *gc = first; gc != NULL; gc = gc->next) { - if (gc->ident.grfid == c->ident.grfid) { - SetDParamStr(0, item->name); - SetDParamStr(1, gc->filename); - ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_DUPLICATE_GRFID, WL_CRITICAL); - duplicate = true; - break; - } - } - if (duplicate) { - delete c; - continue; - } - - /* Mark file as static to avoid saving in savegame. */ - if (is_static) SetBit(c->flags, GCF_STATIC); - - /* Add item to list */ - *curr = c; - curr = &c->next; - } - - return first; -} - -static void AISaveConfig(IniFile *ini, const char *grpname) -{ - IniGroup *group = ini->GetGroup(grpname); - - if (group == NULL) return; - group->Clear(); - - for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME); - const char *name; - char value[1024]; - config->SettingsToString(value, lengthof(value)); - - if (config->HasScript()) { - name = config->GetName(); - } else { - name = "none"; - } - - IniItem *item = new IniItem(group, name, strlen(name)); - item->SetValue(value); - } -} - -static void GameSaveConfig(IniFile *ini, const char *grpname) -{ - IniGroup *group = ini->GetGroup(grpname); - - if (group == NULL) return; - group->Clear(); - - GameConfig *config = GameConfig::GetConfig(AIConfig::SSS_FORCE_NEWGAME); - const char *name; - char value[1024]; - config->SettingsToString(value, lengthof(value)); - - if (config->HasScript()) { - name = config->GetName(); - } else { - name = "none"; - } - - IniItem *item = new IniItem(group, name, strlen(name)); - item->SetValue(value); -} - -/** - * Save the version of OpenTTD to the ini file. - * @param ini the ini to write to - */ -static void SaveVersionInConfig(IniFile *ini) -{ - IniGroup *group = ini->GetGroup("version"); - - char version[9]; - snprintf(version, lengthof(version), "%08X", _openttd_newgrf_version); - - const char * const versions[][2] = { - { "version_string", _openttd_revision }, - { "version_number", version } - }; - - for (uint i = 0; i < lengthof(versions); i++) { - group->GetItem(versions[i][0], true)->SetValue(versions[i][1]); - } -} - -/* Save a GRF configuration to the given group name */ -static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *list) -{ - ini->RemoveGroup(grpname); - IniGroup *group = ini->GetGroup(grpname); - const GRFConfig *c; - - for (c = list; c != NULL; c = c->next) { - char params[512]; - GRFBuildParamList(params, c, lastof(params)); - - group->GetItem(c->filename, true)->SetValue(params); - } -} - -/* Common handler for saving/loading variables to the configuration file */ -static void HandleSettingDescs(IniFile *ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool basic_settings = true, bool other_settings = true) -{ - if (basic_settings) { - proc(ini, (const SettingDesc*)_misc_settings, "misc", NULL); -#if defined(WIN32) && !defined(DEDICATED) - proc(ini, (const SettingDesc*)_win32_settings, "win32", NULL); -#endif /* WIN32 */ - } - - if (other_settings) { - proc(ini, _settings, "patches", &_settings_newgame); - proc(ini, _currency_settings,"currency", &_custom_currency); - proc(ini, _company_settings, "company", &_settings_client.company); - -#ifdef ENABLE_NETWORK - proc_list(ini, "server_bind_addresses", &_network_bind_list); - proc_list(ini, "servers", &_network_host_list); - proc_list(ini, "bans", &_network_ban_list); -#endif /* ENABLE_NETWORK */ - } -} - -static IniFile *IniLoadConfig() -{ - IniFile *ini = new IniFile(_list_group_names); - ini->LoadFromDisk(_config_file, BASE_DIR); - return ini; -} - -/** - * Load the values from the configuration files - * @param minimal Load the minimal amount of the configuration to "bootstrap" the blitter and such. - */ -void LoadFromConfig(bool minimal) -{ - IniFile *ini = IniLoadConfig(); - if (!minimal) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one - - /* Load basic settings only during bootstrap, load other settings not during bootstrap */ - HandleSettingDescs(ini, IniLoadSettings, IniLoadSettingList, minimal, !minimal); - - if (!minimal) { - _grfconfig_newgame = GRFLoadConfig(ini, "newgrf", false); - _grfconfig_static = GRFLoadConfig(ini, "newgrf-static", true); - AILoadConfig(ini, "ai_players"); - GameLoadConfig(ini, "game_scripts"); - - PrepareOldDiffCustom(); - IniLoadSettings(ini, _gameopt_settings, "gameopt", &_settings_newgame); - HandleOldDiffCustom(false); - - ValidateSettings(); - - /* Display sheduled errors */ - extern void ScheduleErrorMessage(ErrorList &datas); - ScheduleErrorMessage(_settings_error_list); - if (FindWindowById(WC_ERRMSG, 0) == NULL) ShowFirstError(); - } - - delete ini; -} - -/** Save the values to the configuration file */ -void SaveToConfig() -{ - IniFile *ini = IniLoadConfig(); - - /* Remove some obsolete groups. These have all been loaded into other groups. */ - ini->RemoveGroup("patches"); - ini->RemoveGroup("yapf"); - ini->RemoveGroup("gameopt"); - - HandleSettingDescs(ini, IniSaveSettings, IniSaveSettingList); - GRFSaveConfig(ini, "newgrf", _grfconfig_newgame); - GRFSaveConfig(ini, "newgrf-static", _grfconfig_static); - AISaveConfig(ini, "ai_players"); - GameSaveConfig(ini, "game_scripts"); - SaveVersionInConfig(ini); - ini->SaveToDisk(_config_file); - delete ini; -} - -/** - * Get the list of known NewGrf presets. - * @param list[inout] Pointer to list for storing the preset names. - */ -void GetGRFPresetList(GRFPresetList *list) -{ - list->Clear(); - - IniFile *ini = IniLoadConfig(); - IniGroup *group; - for (group = ini->group; group != NULL; group = group->next) { - if (strncmp(group->name, "preset-", 7) == 0) { - *list->Append() = strdup(group->name + 7); - } - } - - delete ini; -} - -/** - * Load a NewGRF configuration by preset-name. - * @param config_name Name of the preset. - * @return NewGRF configuration. - * @see GetGRFPresetList - */ -GRFConfig *LoadGRFPresetFromConfig(const char *config_name) -{ - char *section = (char*)alloca(strlen(config_name) + 8); - sprintf(section, "preset-%s", config_name); - - IniFile *ini = IniLoadConfig(); - GRFConfig *config = GRFLoadConfig(ini, section, false); - delete ini; - - return config; -} - -/** - * Save a NewGRF configuration with a preset name. - * @param config_name Name of the preset. - * @param config NewGRF configuration to save. - * @see GetGRFPresetList - */ -void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config) -{ - char *section = (char*)alloca(strlen(config_name) + 8); - sprintf(section, "preset-%s", config_name); - - IniFile *ini = IniLoadConfig(); - GRFSaveConfig(ini, section, config); - ini->SaveToDisk(_config_file); - delete ini; -} - -/** - * Delete a NewGRF configuration by preset name. - * @param config_name Name of the preset. - */ -void DeleteGRFPresetFromConfig(const char *config_name) -{ - char *section = (char*)alloca(strlen(config_name) + 8); - sprintf(section, "preset-%s", config_name); - - IniFile *ini = IniLoadConfig(); - ini->RemoveGroup(section); - ini->SaveToDisk(_config_file); - delete ini; -} - -const SettingDesc *GetSettingDescription(uint index) -{ - if (index >= lengthof(_settings)) return NULL; - return &_settings[index]; -} - -/** - * Network-safe changing of settings (server-only). - * @param tile unused - * @param flags operation to perform - * @param p1 the index of the setting in the SettingDesc array which identifies it - * @param p2 the new value for the setting - * The new value is properly clamped to its minimum/maximum when setting - * @param text unused - * @return the cost of this operation or an error - * @see _settings - */ -CommandCost CmdChangeSetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) -{ - const SettingDesc *sd = GetSettingDescription(p1); - - if (sd == NULL) return CMD_ERROR; - if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) return CMD_ERROR; - - if (!sd->IsEditable(true)) return CMD_ERROR; - - if (flags & DC_EXEC) { - void *var = GetVariableAddress(&GetGameSettings(), &sd->save); - - int32 oldval = (int32)ReadValue(var, sd->save.conv); - int32 newval = (int32)p2; - - Write_ValidateSetting(var, sd, newval); - newval = (int32)ReadValue(var, sd->save.conv); - - if (oldval == newval) return CommandCost(); - - if (sd->desc.proc != NULL && !sd->desc.proc(newval)) { - WriteValue(var, sd->save.conv, (int64)oldval); - return CommandCost(); - } - - if (sd->desc.flags & SGF_NO_NETWORK) { - GamelogStartAction(GLAT_SETTING); - GamelogSetting(sd->desc.name, oldval, newval); - GamelogStopAction(); - } - - SetWindowClassesDirty(WC_GAME_OPTIONS); - } - - return CommandCost(); -} - -/** - * Change one of the per-company settings. - * @param tile unused - * @param flags operation to perform - * @param p1 the index of the setting in the _company_settings array which identifies it - * @param p2 the new value for the setting - * The new value is properly clamped to its minimum/maximum when setting - * @param text unused - * @return the cost of this operation or an error - */ -CommandCost CmdChangeCompanySetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) -{ - if (p1 >= lengthof(_company_settings)) return CMD_ERROR; - const SettingDesc *sd = &_company_settings[p1]; - - if (flags & DC_EXEC) { - void *var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save); - - int32 oldval = (int32)ReadValue(var, sd->save.conv); - int32 newval = (int32)p2; - - Write_ValidateSetting(var, sd, newval); - newval = (int32)ReadValue(var, sd->save.conv); - - if (oldval == newval) return CommandCost(); - - if (sd->desc.proc != NULL && !sd->desc.proc(newval)) { - WriteValue(var, sd->save.conv, (int64)oldval); - return CommandCost(); - } - - SetWindowClassesDirty(WC_GAME_OPTIONS); - } - - return CommandCost(); -} - -/** - * Top function to save the new value of an element of the Settings struct - * @param index offset in the SettingDesc array of the Settings struct which - * identifies the setting member we want to change - * @param value new value of the setting - * @param force_newgame force the newgame settings - */ -bool SetSettingValue(uint index, int32 value, bool force_newgame) -{ - const SettingDesc *sd = &_settings[index]; - /* If an item is company-based, we do not send it over the network - * (if any) to change. Also *hack*hack* we update the _newgame version - * of settings because changing a company-based setting in a game also - * changes its defaults. At least that is the convention we have chosen */ - if (sd->save.conv & SLF_NO_NETWORK_SYNC) { - void *var = GetVariableAddress(&GetGameSettings(), &sd->save); - Write_ValidateSetting(var, sd, value); - - if (_game_mode != GM_MENU) { - void *var2 = GetVariableAddress(&_settings_newgame, &sd->save); - Write_ValidateSetting(var2, sd, value); - } - if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv)); - - SetWindowClassesDirty(WC_GAME_OPTIONS); - - return true; - } - - if (force_newgame) { - void *var2 = GetVariableAddress(&_settings_newgame, &sd->save); - Write_ValidateSetting(var2, sd, value); - return true; - } - - /* send non-company-based settings over the network */ - if (!_networking || (_networking && _network_server)) { - return DoCommandP(0, index, value, CMD_CHANGE_SETTING); - } - return false; -} - -/** - * Top function to save the new value of an element of the Settings struct - * @param index offset in the SettingDesc array of the CompanySettings struct - * which identifies the setting member we want to change - * @param value new value of the setting - */ -void SetCompanySetting(uint index, int32 value) -{ - const SettingDesc *sd = &_company_settings[index]; - if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) { - DoCommandP(0, index, value, CMD_CHANGE_COMPANY_SETTING); - } else { - void *var = GetVariableAddress(&_settings_client.company, &sd->save); - Write_ValidateSetting(var, sd, value); - if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv)); - } -} - -/** - * Set the company settings for a new company to their default values. - */ -void SetDefaultCompanySettings(CompanyID cid) -{ - Company *c = Company::Get(cid); - const SettingDesc *sd; - for (sd = _company_settings; sd->save.cmd != SL_END; sd++) { - void *var = GetVariableAddress(&c->settings, &sd->save); - Write_ValidateSetting(var, sd, (int32)(size_t)sd->desc.def); - } -} - -#if defined(ENABLE_NETWORK) -/** - * Sync all company settings in a multiplayer game. - */ -void SyncCompanySettings() -{ - const SettingDesc *sd; - uint i = 0; - for (sd = _company_settings; sd->save.cmd != SL_END; sd++, i++) { - const void *old_var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save); - const void *new_var = GetVariableAddress(&_settings_client.company, &sd->save); - uint32 old_value = (uint32)ReadValue(old_var, sd->save.conv); - uint32 new_value = (uint32)ReadValue(new_var, sd->save.conv); - if (old_value != new_value) NetworkSendCommand(0, i, new_value, CMD_CHANGE_COMPANY_SETTING, NULL, NULL, _local_company); - } -} -#endif /* ENABLE_NETWORK */ - -/** - * Get the index in the _company_settings array of a setting - * @param name The name of the setting - * @return The index in the _company_settings array - */ -uint GetCompanySettingIndex(const char *name) -{ - uint i; - const SettingDesc *sd = GetSettingFromName(name, &i); - assert(sd != NULL && (sd->desc.flags & SGF_PER_COMPANY) != 0); - return i; -} - -/** - * Set a setting value with a string. - * @param index the settings index. - * @param value the value to write - * @param force_newgame force the newgame settings - * @note Strings WILL NOT be synced over the network - */ -bool SetSettingValue(uint index, const char *value, bool force_newgame) -{ - const SettingDesc *sd = &_settings[index]; - assert(sd->save.conv & SLF_NO_NETWORK_SYNC); - - if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ) { - char **var = (char**)GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); - free(*var); - *var = strcmp(value, "(null)") == 0 ? NULL : strdup(value); - } else { - char *var = (char*)GetVariableAddress(NULL, &sd->save); - ttd_strlcpy(var, value, sd->save.length); - } - if (sd->desc.proc != NULL) sd->desc.proc(0); - - return true; -} - -/** - * Given a name of setting, return a setting description of it. - * @param name Name of the setting to return a setting description of - * @param i Pointer to an integer that will contain the index of the setting after the call, if it is successful. - * @return Pointer to the setting description of setting \a name if it can be found, - * \c NULL indicates failure to obtain the description - */ -const SettingDesc *GetSettingFromName(const char *name, uint *i) -{ - const SettingDesc *sd; - - /* First check all full names */ - for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) { - if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; - if (strcmp(sd->desc.name, name) == 0) return sd; - } - - /* Then check the shortcut variant of the name. */ - for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) { - if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; - const char *short_name = strchr(sd->desc.name, '.'); - if (short_name != NULL) { - short_name++; - if (strcmp(short_name, name) == 0) return sd; - } - } - - if (strncmp(name, "company.", 8) == 0) name += 8; - /* And finally the company-based settings */ - for (*i = 0, sd = _company_settings; sd->save.cmd != SL_END; sd++, (*i)++) { - if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; - if (strcmp(sd->desc.name, name) == 0) return sd; - } - - return NULL; -} - -/* Those 2 functions need to be here, else we have to make some stuff non-static - * and besides, it is also better to keep stuff like this at the same place */ -void IConsoleSetSetting(const char *name, const char *value, bool force_newgame) -{ - uint index; - const SettingDesc *sd = GetSettingFromName(name, &index); - - if (sd == NULL) { - IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name); - return; - } - - bool success; - if (sd->desc.cmd == SDT_STRING) { - success = SetSettingValue(index, value, force_newgame); - } else { - uint32 val; - extern bool GetArgumentInteger(uint32 *value, const char *arg); - success = GetArgumentInteger(&val, value); - if (!success) { - IConsolePrintF(CC_ERROR, "'%s' is not an integer.", value); - return; - } - - success = SetSettingValue(index, val, force_newgame); - } - - if (!success) { - if (_network_server) { - IConsoleError("This command/variable is not available during network games."); - } else { - IConsoleError("This command/variable is only available to a network server."); - } - } -} - -void IConsoleSetSetting(const char *name, int value) -{ - uint index; - const SettingDesc *sd = GetSettingFromName(name, &index); - assert(sd != NULL); - SetSettingValue(index, value); -} - -/** - * Output value of a specific setting to the console - * @param name Name of the setting to output its value - * @param force_newgame force the newgame settings - */ -void IConsoleGetSetting(const char *name, bool force_newgame) -{ - char value[20]; - uint index; - const SettingDesc *sd = GetSettingFromName(name, &index); - const void *ptr; - - if (sd == NULL) { - IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name); - return; - } - - ptr = GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); - - if (sd->desc.cmd == SDT_STRING) { - IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s'", name, (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ) ? *(const char * const *)ptr : (const char *)ptr); - } else { - if (sd->desc.cmd == SDT_BOOLX) { - snprintf(value, sizeof(value), (*(const bool*)ptr != 0) ? "on" : "off"); - } else { - snprintf(value, sizeof(value), sd->desc.min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd->save.conv)); - } - - IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s' (min: %s%d, max: %u)", - name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max); - } -} - -/** - * List all settings and their value to the console - * - * @param prefilter If not \c NULL, only list settings with names that begin with \a prefilter prefix - */ -void IConsoleListSettings(const char *prefilter) -{ - IConsolePrintF(CC_WARNING, "All settings with their current value:"); - - for (const SettingDesc *sd = _settings; sd->save.cmd != SL_END; sd++) { - if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; - if (prefilter != NULL && strstr(sd->desc.name, prefilter) == NULL) continue; - char value[80]; - const void *ptr = GetVariableAddress(&GetGameSettings(), &sd->save); - - if (sd->desc.cmd == SDT_BOOLX) { - snprintf(value, lengthof(value), (*(const bool *)ptr != 0) ? "on" : "off"); - } else if (sd->desc.cmd == SDT_STRING) { - snprintf(value, sizeof(value), "%s", (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ) ? *(const char * const *)ptr : (const char *)ptr); - } else { - snprintf(value, lengthof(value), sd->desc.min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd->save.conv)); - } - IConsolePrintF(CC_DEFAULT, "%s = %s", sd->desc.name, value); - } - - IConsolePrintF(CC_WARNING, "Use 'setting' command to change a value"); -} - -/** - * Save and load handler for settings - * @param osd SettingDesc struct containing all information - * @param object can be either NULL in which case we load global variables or - * a pointer to a struct which is getting saved - */ -static void LoadSettings(const SettingDesc *osd, void *object) -{ - for (; osd->save.cmd != SL_END; osd++) { - const SaveLoad *sld = &osd->save; - void *ptr = GetVariableAddress(object, sld); - - if (!SlObjectMember(ptr, sld)) continue; - if (IsNumericType(sld->conv)) Write_ValidateSetting(ptr, osd, ReadValue(ptr, sld->conv)); - } -} - -/** - * Save and load handler for settings - * @param sd SettingDesc struct containing all information - * @param object can be either NULL in which case we load global variables or - * a pointer to a struct which is getting saved - */ -static void SaveSettings(const SettingDesc *sd, void *object) -{ - /* We need to write the CH_RIFF header, but unfortunately can't call - * SlCalcLength() because we have a different format. So do this manually */ - const SettingDesc *i; - size_t length = 0; - for (i = sd; i->save.cmd != SL_END; i++) { - length += SlCalcObjMemberLength(object, &i->save); - } - SlSetLength(length); - - for (i = sd; i->save.cmd != SL_END; i++) { - void *ptr = GetVariableAddress(object, &i->save); - SlObjectMember(ptr, &i->save); - } -} - -static void Load_OPTS() -{ - /* Copy over default setting since some might not get loaded in - * a networking environment. This ensures for example that the local - * autosave-frequency stays when joining a network-server */ - PrepareOldDiffCustom(); - LoadSettings(_gameopt_settings, &_settings_game); - HandleOldDiffCustom(true); -} - -static void Load_PATS() -{ - /* Copy over default setting since some might not get loaded in - * a networking environment. This ensures for example that the local - * currency setting stays when joining a network-server */ - LoadSettings(_settings, &_settings_game); -} - -static void Check_PATS() -{ - LoadSettings(_settings, &_load_check_data.settings); -} - -static void Save_PATS() -{ - SaveSettings(_settings, &_settings_game); -} - -void CheckConfig() -{ - /* - * Increase old default values for pf_maxdepth and pf_maxlength - * to support big networks. - */ - if (_settings_newgame.pf.opf.pf_maxdepth == 16 && _settings_newgame.pf.opf.pf_maxlength == 512) { - _settings_newgame.pf.opf.pf_maxdepth = 48; - _settings_newgame.pf.opf.pf_maxlength = 4096; - } -} - -extern const ChunkHandler _setting_chunk_handlers[] = { - { 'OPTS', NULL, Load_OPTS, NULL, NULL, CH_RIFF}, - { 'PATS', Save_PATS, Load_PATS, NULL, Check_PATS, CH_RIFF | CH_LAST}, -}; - -static bool IsSignedVarMemType(VarType vt) -{ - switch (GetVarMemType(vt)) { - case SLE_VAR_I8: - case SLE_VAR_I16: - case SLE_VAR_I32: - case SLE_VAR_I64: - return true; - } - return false; -} diff --git a/src/settings.cpp.rej b/src/settings.cpp.rej deleted file mode 100644 index 9b84f848c1..0000000000 --- a/src/settings.cpp.rej +++ /dev/null @@ -1,11 +0,0 @@ ---- src/settings.cpp -+++ src/settings.cpp -@@ -1092,7 +1092,7 @@ - - static bool TouchscreenModeChanged(int32 p1) - { -- //ResetTabletWindow(); -+ ResetTabletWindow(); - return true; - } - diff --git a/src/settings_gui.cpp.orig b/src/settings_gui.cpp.orig deleted file mode 100644 index 80f26b5282..0000000000 --- a/src/settings_gui.cpp.orig +++ /dev/null @@ -1,2649 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file settings_gui.cpp GUI for settings. */ - -#include "stdafx.h" -#include "currency.h" -#include "error.h" -#include "settings_gui.h" -#include "textbuf_gui.h" -#include "command_func.h" -#include "screenshot.h" -#include "network/network.h" -#include "town.h" -#include "settings_internal.h" -#include "newgrf_townname.h" -#include "strings_func.h" -#include "window_func.h" -#include "string_func.h" -#include "widgets/dropdown_type.h" -#include "widgets/dropdown_func.h" -#include "highscore.h" -#include "base_media_base.h" -#include "company_base.h" -#include "company_func.h" -#include "viewport_func.h" -#include "core/geometry_func.hpp" -#include "ai/ai.hpp" -#include "blitter/factory.hpp" -#include "language.h" -#include "textfile_gui.h" -#include "stringfilter_type.h" -#include "querystring_gui.h" - - -static const StringID _driveside_dropdown[] = { - STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT, - STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT, - INVALID_STRING_ID -}; - -static const StringID _autosave_dropdown[] = { - STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF, - STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH, - STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS, - STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS, - STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS, - INVALID_STRING_ID, -}; - -int _nb_orig_names = SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1; ///< Number of original town names. -static StringID *_grf_names = NULL; ///< Pointer to town names defined by NewGRFs. -static int _nb_grf_names = 0; ///< Number of town names defined by NewGRFs. - -static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const SettingDesc *sd); - -/** Allocate memory for the NewGRF town names. */ -void InitGRFTownGeneratorNames() -{ - free(_grf_names); - _grf_names = GetGRFTownNameList(); - _nb_grf_names = 0; - for (StringID *s = _grf_names; *s != INVALID_STRING_ID; s++) _nb_grf_names++; -} - -/** - * Get a town name. - * @param town_name Number of the wanted town name. - * @return Name of the town as string ID. - */ -static inline StringID TownName(int town_name) -{ - if (town_name < _nb_orig_names) return STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH + town_name; - town_name -= _nb_orig_names; - if (town_name < _nb_grf_names) return _grf_names[town_name]; - return STR_UNDEFINED; -} - -/** - * Get index of the current screen resolution. - * @return Index of the current screen resolution if it is a known resolution, #_num_resolutions otherwise. - */ -static int GetCurRes() -{ - int i; - - for (i = 0; i != _num_resolutions; i++) { - if ((int)_resolutions[i].width == _screen.width && - (int)_resolutions[i].height == _screen.height) { - break; - } - } - return i; -} - -static void ShowCustCurrency(); - -template -static DropDownList *BuiltSetDropDownList(int *selected_index) -{ - int n = T::GetNumSets(); - *selected_index = T::GetIndexOfUsedSet(); - - DropDownList *list = new DropDownList(); - for (int i = 0; i < n; i++) { - *list->Append() = new DropDownListCharStringItem(T::GetSet(i)->name, i, (_game_mode == GM_MENU) ? false : (*selected_index != i)); - } - - return list; -} - -/** Window for displaying the textfile of a BaseSet. */ -template -struct BaseSetTextfileWindow : public TextfileWindow { - const TBaseSet* baseset; ///< View the textfile of this BaseSet. - StringID content_type; ///< STR_CONTENT_TYPE_xxx for title. - - BaseSetTextfileWindow(TextfileType file_type, const TBaseSet* baseset, StringID content_type) : TextfileWindow(file_type), baseset(baseset), content_type(content_type) - { - const char *textfile = this->baseset->GetTextfile(file_type); - this->LoadTextfile(textfile, BASESET_DIR); - } - - /* virtual */ void SetStringParameters(int widget) const - { - if (widget == WID_TF_CAPTION) { - SetDParam(0, content_type); - SetDParamStr(1, this->baseset->name); - } - } -}; - -/** - * Open the BaseSet version of the textfile window. - * @param file_type The type of textfile to display. - * @param baseset The BaseSet to use. - * @param content_type STR_CONTENT_TYPE_xxx for title. - */ -template -void ShowBaseSetTextfileWindow(TextfileType file_type, const TBaseSet* baseset, StringID content_type) -{ - DeleteWindowByClass(WC_TEXTFILE); - new BaseSetTextfileWindow(file_type, baseset, content_type); -} - -struct GameOptionsWindow : Window { - GameSettings *opt; - bool reload; - - GameOptionsWindow(WindowDesc *desc) : Window(desc) - { - this->opt = &GetGameSettings(); - this->reload = false; - - this->InitNested(WN_GAME_OPTIONS_GAME_OPTIONS); - this->OnInvalidateData(0); - } - - ~GameOptionsWindow() - { - DeleteWindowById(WC_CUSTOM_CURRENCY, 0); - if (this->reload) _switch_mode = SM_MENU; - } - - /** - * Build the dropdown list for a specific widget. - * @param widget Widget to build list for - * @param selected_index Currently selected item - * @return the built dropdown list, or NULL if the widget has no dropdown menu. - */ - DropDownList *BuildDropDownList(int widget, int *selected_index) const - { - DropDownList *list = NULL; - switch (widget) { - case WID_GO_CURRENCY_DROPDOWN: { // Setup currencies dropdown - list = new DropDownList(); - *selected_index = this->opt->locale.currency; - StringID *items = BuildCurrencyDropdown(); - uint64 disabled = _game_mode == GM_MENU ? 0LL : ~GetMaskOfAllowedCurrencies(); - - /* Add non-custom currencies; sorted naturally */ - for (uint i = 0; i < CURRENCY_END; items++, i++) { - if (i == CURRENCY_CUSTOM) continue; - *list->Append() = new DropDownListStringItem(*items, i, HasBit(disabled, i)); - } - QSortT(list->Begin(), list->Length(), DropDownListStringItem::NatSortFunc); - - /* Append custom currency at the end */ - *list->Append() = new DropDownListItem(-1, false); // separator line - *list->Append() = new DropDownListStringItem(STR_GAME_OPTIONS_CURRENCY_CUSTOM, CURRENCY_CUSTOM, HasBit(disabled, CURRENCY_CUSTOM)); - break; - } - - case WID_GO_ROADSIDE_DROPDOWN: { // Setup road-side dropdown - list = new DropDownList(); - *selected_index = this->opt->vehicle.road_side; - const StringID *items = _driveside_dropdown; - uint disabled = 0; - - /* You can only change the drive side if you are in the menu or ingame with - * no vehicles present. In a networking game only the server can change it */ - extern bool RoadVehiclesAreBuilt(); - if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server)) { - disabled = ~(1 << this->opt->vehicle.road_side); // disable the other value - } - - for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) { - *list->Append() = new DropDownListStringItem(*items, i, HasBit(disabled, i)); - } - break; - } - - case WID_GO_TOWNNAME_DROPDOWN: { // Setup townname dropdown - list = new DropDownList(); - *selected_index = this->opt->game_creation.town_name; - - int enabled_item = (_game_mode == GM_MENU || Town::GetNumItems() == 0) ? -1 : *selected_index; - - /* Add and sort newgrf townnames generators */ - for (int i = 0; i < _nb_grf_names; i++) { - int result = _nb_orig_names + i; - *list->Append() = new DropDownListStringItem(_grf_names[i], result, enabled_item != result && enabled_item >= 0); - } - QSortT(list->Begin(), list->Length(), DropDownListStringItem::NatSortFunc); - - int newgrf_size = list->Length(); - /* Insert newgrf_names at the top of the list */ - if (newgrf_size > 0) { - *list->Append() = new DropDownListItem(-1, false); // separator line - newgrf_size++; - } - - /* Add and sort original townnames generators */ - for (int i = 0; i < _nb_orig_names; i++) { - *list->Append() = new DropDownListStringItem(STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH + i, i, enabled_item != i && enabled_item >= 0); - } - QSortT(list->Begin() + newgrf_size, list->Length() - newgrf_size, DropDownListStringItem::NatSortFunc); - break; - } - - case WID_GO_AUTOSAVE_DROPDOWN: { // Setup autosave dropdown - list = new DropDownList(); - *selected_index = _settings_client.gui.autosave; - const StringID *items = _autosave_dropdown; - for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) { - *list->Append() = new DropDownListStringItem(*items, i, false); - } - break; - } - - case WID_GO_LANG_DROPDOWN: { // Setup interface language dropdown - list = new DropDownList(); - for (uint i = 0; i < _languages.Length(); i++) { - if (&_languages[i] == _current_language) *selected_index = i; - *list->Append() = new DropDownListStringItem(SPECSTR_LANGUAGE_START + i, i, false); - } - QSortT(list->Begin(), list->Length(), DropDownListStringItem::NatSortFunc); - break; - } - - case WID_GO_RESOLUTION_DROPDOWN: // Setup resolution dropdown - list = new DropDownList(); - *selected_index = GetCurRes(); - for (int i = 0; i < _num_resolutions; i++) { - *list->Append() = new DropDownListStringItem(SPECSTR_RESOLUTION_START + i, i, false); - } - break; - - case WID_GO_SCREENSHOT_DROPDOWN: // Setup screenshot format dropdown - list = new DropDownList(); - *selected_index = _cur_screenshot_format; - for (uint i = 0; i < _num_screenshot_formats; i++) { - if (!GetScreenshotFormatSupports_32bpp(i) && BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 32) continue; - *list->Append() = new DropDownListStringItem(SPECSTR_SCREENSHOT_START + i, i, false); - } - break; - - case WID_GO_BASE_GRF_DROPDOWN: - list = BuiltSetDropDownList(selected_index); - break; - - case WID_GO_BASE_SFX_DROPDOWN: - list = BuiltSetDropDownList(selected_index); - break; - - case WID_GO_BASE_MUSIC_DROPDOWN: - list = BuiltSetDropDownList(selected_index); - break; - - default: - return NULL; - } - - return list; - } - - virtual void SetStringParameters(int widget) const - { - switch (widget) { - case WID_GO_CURRENCY_DROPDOWN: SetDParam(0, _currency_specs[this->opt->locale.currency].name); break; - case WID_GO_ROADSIDE_DROPDOWN: SetDParam(0, STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT + this->opt->vehicle.road_side); break; - case WID_GO_TOWNNAME_DROPDOWN: SetDParam(0, TownName(this->opt->game_creation.town_name)); break; - case WID_GO_AUTOSAVE_DROPDOWN: SetDParam(0, _autosave_dropdown[_settings_client.gui.autosave]); break; - case WID_GO_LANG_DROPDOWN: SetDParamStr(0, _current_language->own_name); break; - case WID_GO_RESOLUTION_DROPDOWN: SetDParam(0, GetCurRes() == _num_resolutions ? STR_GAME_OPTIONS_RESOLUTION_OTHER : SPECSTR_RESOLUTION_START + GetCurRes()); break; - case WID_GO_SCREENSHOT_DROPDOWN: SetDParam(0, SPECSTR_SCREENSHOT_START + _cur_screenshot_format); break; - case WID_GO_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->name); break; - case WID_GO_BASE_GRF_STATUS: SetDParam(0, BaseGraphics::GetUsedSet()->GetNumInvalid()); break; - case WID_GO_BASE_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->name); break; - case WID_GO_BASE_MUSIC_DROPDOWN: SetDParamStr(0, BaseMusic::GetUsedSet()->name); break; - case WID_GO_BASE_MUSIC_STATUS: SetDParam(0, BaseMusic::GetUsedSet()->GetNumInvalid()); break; - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_GO_BASE_GRF_DESCRIPTION: - SetDParamStr(0, BaseGraphics::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); - DrawString(r.left, r.right, r.top, STR_BLACK_RAW_STRING); - break; - - case WID_GO_BASE_SFX_DESCRIPTION: - SetDParamStr(0, BaseSounds::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); - DrawString(r.left, r.right, r.top, STR_BLACK_RAW_STRING); - break; - - case WID_GO_BASE_MUSIC_DESCRIPTION: - SetDParamStr(0, BaseMusic::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); - DrawString(r.left, r.right, r.top, STR_BLACK_RAW_STRING); - break; - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_GO_BASE_GRF_DESCRIPTION: - /* Find the biggest description for the default size. */ - for (int i = 0; i < BaseGraphics::GetNumSets(); i++) { - SetDParamStr(0, "123"); - size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); - } - break; - - case WID_GO_BASE_GRF_STATUS: - /* Find the biggest description for the default size. */ - for (int i = 0; i < BaseGraphics::GetNumSets(); i++) { - uint invalid_files = BaseGraphics::GetSet(i)->GetNumInvalid(); - if (invalid_files == 0) continue; - - SetDParam(0, invalid_files); - *size = maxdim(*size, GetStringBoundingBox(STR_GAME_OPTIONS_BASE_GRF_STATUS)); - } - break; - - case WID_GO_BASE_SFX_DESCRIPTION: - /* Find the biggest description for the default size. */ - for (int i = 0; i < BaseSounds::GetNumSets(); i++) { - SetDParamStr(0, "123"); - size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); - } - break; - - case WID_GO_BASE_MUSIC_DESCRIPTION: - /* Find the biggest description for the default size. */ - for (int i = 0; i < BaseMusic::GetNumSets(); i++) { - SetDParamStr(0, "123"); - size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); - } - break; - - case WID_GO_BASE_MUSIC_STATUS: - /* Find the biggest description for the default size. */ - for (int i = 0; i < BaseMusic::GetNumSets(); i++) { - uint invalid_files = BaseMusic::GetSet(i)->GetNumInvalid(); - if (invalid_files == 0) continue; - - SetDParam(0, invalid_files); - *size = maxdim(*size, GetStringBoundingBox(STR_GAME_OPTIONS_BASE_MUSIC_STATUS)); - } - break; - - default: { - int selected; - DropDownList *list = this->BuildDropDownList(widget, &selected); - if (list != NULL) { - /* Find the biggest item for the default size. */ - for (const DropDownListItem * const *it = list->Begin(); it != list->End(); it++) { - Dimension string_dim; - int width = (*it)->Width(); - string_dim.width = width + padding.width; - string_dim.height = (*it)->Height(width) + padding.height; - *size = maxdim(*size, string_dim); - } - delete list; - } - } - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - if (widget >= WID_GO_BASE_GRF_TEXTFILE && widget < WID_GO_BASE_GRF_TEXTFILE + TFT_END) { - if (BaseGraphics::GetUsedSet() == NULL) return; - - ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_GRF_TEXTFILE), BaseGraphics::GetUsedSet(), STR_CONTENT_TYPE_BASE_GRAPHICS); - return; - } - if (widget >= WID_GO_BASE_SFX_TEXTFILE && widget < WID_GO_BASE_SFX_TEXTFILE + TFT_END) { - if (BaseSounds::GetUsedSet() == NULL) return; - - ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_SFX_TEXTFILE), BaseSounds::GetUsedSet(), STR_CONTENT_TYPE_BASE_SOUNDS); - return; - } - if (widget >= WID_GO_BASE_MUSIC_TEXTFILE && widget < WID_GO_BASE_MUSIC_TEXTFILE + TFT_END) { - if (BaseMusic::GetUsedSet() == NULL) return; - - ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_MUSIC_TEXTFILE), BaseMusic::GetUsedSet(), STR_CONTENT_TYPE_BASE_MUSIC); - return; - } - switch (widget) { - case WID_GO_FULLSCREEN_BUTTON: // Click fullscreen on/off - /* try to toggle full-screen on/off */ - if (!ToggleFullScreen(!_fullscreen)) { - ShowErrorMessage(STR_ERROR_FULLSCREEN_FAILED, INVALID_STRING_ID, WL_ERROR); - } - this->SetWidgetLoweredState(WID_GO_FULLSCREEN_BUTTON, _fullscreen); - this->SetDirty(); - break; - - default: { - int selected; - DropDownList *list = this->BuildDropDownList(widget, &selected); - if (list != NULL) { - ShowDropDownList(this, list, selected, widget); - } - break; - } - } - } - - /** - * Set the base media set. - * @param index the index of the media set - * @tparam T class of media set - */ - template - void SetMediaSet(int index) - { - if (_game_mode == GM_MENU) { - const char *name = T::GetSet(index)->name; - - free(T::ini_set); - T::ini_set = strdup(name); - - T::SetSet(name); - this->reload = true; - this->InvalidateData(); - } - } - - virtual void OnDropdownSelect(int widget, int index) - { - switch (widget) { - case WID_GO_CURRENCY_DROPDOWN: // Currency - if (index == CURRENCY_CUSTOM) ShowCustCurrency(); - this->opt->locale.currency = index; - ReInitAllWindows(); - break; - - case WID_GO_ROADSIDE_DROPDOWN: // Road side - if (this->opt->vehicle.road_side != index) { // only change if setting changed - uint i; - if (GetSettingFromName("vehicle.road_side", &i) == NULL) NOT_REACHED(); - SetSettingValue(i, index); - MarkWholeScreenDirty(); - } - break; - - case WID_GO_TOWNNAME_DROPDOWN: // Town names - if (_game_mode == GM_MENU || Town::GetNumItems() == 0) { - this->opt->game_creation.town_name = index; - SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_OPTIONS); - } - break; - - case WID_GO_AUTOSAVE_DROPDOWN: // Autosave options - _settings_client.gui.autosave = index; - this->SetDirty(); - break; - - case WID_GO_LANG_DROPDOWN: // Change interface language - ReadLanguagePack(&_languages[index]); - DeleteWindowByClass(WC_QUERY_STRING); - CheckForMissingGlyphs(); - UpdateAllVirtCoords(); - ReInitAllWindows(); - break; - - case WID_GO_RESOLUTION_DROPDOWN: // Change resolution - if (index < _num_resolutions && ChangeResInGame(_resolutions[index].width, _resolutions[index].height)) { - this->SetDirty(); - } - break; - - case WID_GO_SCREENSHOT_DROPDOWN: // Change screenshot format - SetScreenshotFormat(index); - this->SetDirty(); - break; - - case WID_GO_BASE_GRF_DROPDOWN: - this->SetMediaSet(index); - break; - - case WID_GO_BASE_SFX_DROPDOWN: - this->SetMediaSet(index); - break; - - case WID_GO_BASE_MUSIC_DROPDOWN: - this->SetMediaSet(index); - break; - } - } - - /** - * Some data on this window has become invalid. - * @param data Information about the changed data. @see GameOptionsInvalidationData - * @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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - this->SetWidgetLoweredState(WID_GO_FULLSCREEN_BUTTON, _fullscreen); - - bool missing_files = BaseGraphics::GetUsedSet()->GetNumMissing() == 0; - this->GetWidget(WID_GO_BASE_GRF_STATUS)->SetDataTip(missing_files ? STR_EMPTY : STR_GAME_OPTIONS_BASE_GRF_STATUS, STR_NULL); - - for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { - this->SetWidgetDisabledState(WID_GO_BASE_GRF_TEXTFILE + tft, BaseGraphics::GetUsedSet() == NULL || BaseGraphics::GetUsedSet()->GetTextfile(tft) == NULL); - this->SetWidgetDisabledState(WID_GO_BASE_SFX_TEXTFILE + tft, BaseSounds::GetUsedSet() == NULL || BaseSounds::GetUsedSet()->GetTextfile(tft) == NULL); - this->SetWidgetDisabledState(WID_GO_BASE_MUSIC_TEXTFILE + tft, BaseMusic::GetUsedSet() == NULL || BaseMusic::GetUsedSet()->GetTextfile(tft) == NULL); - } - - missing_files = BaseMusic::GetUsedSet()->GetNumInvalid() == 0; - this->GetWidget(WID_GO_BASE_MUSIC_STATUS)->SetDataTip(missing_files ? STR_EMPTY : STR_GAME_OPTIONS_BASE_MUSIC_STATUS, STR_NULL); - } -}; - -static const NWidgetPart _nested_game_options_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_GO_BACKGROUND), SetPIP(6, 6, 10), - NWidget(NWID_HORIZONTAL), SetPIP(10, 10, 10), - NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_CURRENCY_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP), SetFill(1, 0), - EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_ROADSIDE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP), SetFill(1, 0), - EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_AUTOSAVE_FRAME, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_AUTOSAVE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP), SetFill(1, 0), - EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_RESOLUTION, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_RESOLUTION_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_RESOLUTION_TOOLTIP), SetFill(1, 0), SetPadding(0, 0, 3, 0), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_FULLSCREEN, STR_NULL), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_FULLSCREEN_BUTTON), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP), - EndContainer(), - EndContainer(), - EndContainer(), - - NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_TOWN_NAMES_FRAME, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_TOWNNAME_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP), SetFill(1, 0), - EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_LANGUAGE, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_LANG_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_LANGUAGE_TOOLTIP), SetFill(1, 0), - EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_SCREENSHOT_FORMAT, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_SCREENSHOT_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_SCREENSHOT_FORMAT_TOOLTIP), SetFill(1, 0), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 0), SetFill(0, 1), - EndContainer(), - EndContainer(), - - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_GRF, STR_NULL), SetPadding(0, 10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_GRF_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_GRF_TOOLTIP), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), - EndContainer(), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), - EndContainer(), - EndContainer(), - - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_SFX, STR_NULL), SetPadding(0, 10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_SFX_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_SFX_TOOLTIP), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_SFX_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), - EndContainer(), - EndContainer(), - - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_MUSIC, STR_NULL), SetPadding(0, 10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_MUSIC_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), - EndContainer(), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), - EndContainer(), - EndContainer(), - EndContainer(), -}; - -static WindowDesc _game_options_desc( - WDP_CENTER, "settings_game", 0, 0, - WC_GAME_OPTIONS, WC_NONE, - 0, - _nested_game_options_widgets, lengthof(_nested_game_options_widgets) -); - -/** Open the game options window. */ -void ShowGameOptions() -{ - DeleteWindowByClass(WC_GAME_OPTIONS); - new GameOptionsWindow(&_game_options_desc); -} - -static int SETTING_HEIGHT = 11; ///< Height of a single setting in the tree view in pixels -static const int LEVEL_WIDTH = 15; ///< Indenting width of a sub-page in pixels - -/** - * Flags for #SettingEntry - * @note The #SEF_BUTTONS_MASK matches expectations of the formal parameter 'state' of #DrawArrowButtons - */ -enum SettingEntryFlags { - SEF_LEFT_DEPRESSED = 0x01, ///< Of a numeric setting entry, the left button is depressed - SEF_RIGHT_DEPRESSED = 0x02, ///< Of a numeric setting entry, the right button is depressed - SEF_BUTTONS_MASK = (SEF_LEFT_DEPRESSED | SEF_RIGHT_DEPRESSED), ///< Bit-mask for button flags - - SEF_LAST_FIELD = 0x04, ///< This entry is the last one in a (sub-)page - SEF_FILTERED = 0x08, ///< Entry is hidden by the string filter - - /* Entry kind */ - SEF_SETTING_KIND = 0x10, ///< Entry kind: Entry is a setting - SEF_SUBTREE_KIND = 0x20, ///< Entry kind: Entry is a sub-tree - SEF_KIND_MASK = (SEF_SETTING_KIND | SEF_SUBTREE_KIND), ///< Bit-mask for fetching entry kind -}; - -struct SettingsPage; // Forward declaration - -/** Data fields for a sub-page (#SEF_SUBTREE_KIND kind)*/ -struct SettingEntrySubtree { - SettingsPage *page; ///< Pointer to the sub-page - bool folded; ///< Sub-page is folded (not visible except for its title) - StringID title; ///< Title of the sub-page -}; - -/** Data fields for a single setting (#SEF_SETTING_KIND kind) */ -struct SettingEntrySetting { - const char *name; ///< Name of the setting - const SettingDesc *setting; ///< Setting description of the setting - uint index; ///< Index of the setting in the settings table -}; - -/** How the list of advanced settings is filtered. */ -enum RestrictionMode { - RM_BASIC, ///< Display settings associated to the "basic" list. - RM_ADVANCED, ///< Display settings associated to the "advanced" list. - RM_ALL, ///< List all settings regardless of the default/newgame/... values. - RM_CHANGED_AGAINST_DEFAULT, ///< Show only settings which are different compared to default values. - RM_CHANGED_AGAINST_NEW, ///< Show only settings which are different compared to the user's new game setting values. - RM_END, ///< End for iteration. -}; -DECLARE_POSTFIX_INCREMENT(RestrictionMode) - -/** Filter for settings list. */ -struct SettingFilter { - StringFilter string; ///< Filter string. - RestrictionMode min_cat; ///< Minimum category needed to display all filtered strings (#RM_BASIC, #RM_ADVANCED, or #RM_ALL). - bool type_hides; ///< Whether the type hides filtered strings. - RestrictionMode mode; ///< Filter based on category. - SettingType type; ///< Filter based on type. -}; - -/** Data structure describing a single setting in a tab */ -struct SettingEntry { - byte flags; ///< Flags of the setting entry. @see SettingEntryFlags - byte level; ///< Nesting level of this setting entry - union { - SettingEntrySetting entry; ///< Data fields if entry is a setting - SettingEntrySubtree sub; ///< Data fields if entry is a sub-page - } d; ///< Data fields for each kind - - SettingEntry(const char *nm); - SettingEntry(SettingsPage *sub, StringID title); - - void Init(byte level); - void FoldAll(); - void UnFoldAll(); - void SetButtons(byte new_val); - - /** - * Set whether this is the last visible entry of the parent node. - * @param last_field Value to set - */ - void SetLastField(bool last_field) { if (last_field) SETBITS(this->flags, SEF_LAST_FIELD); else CLRBITS(this->flags, SEF_LAST_FIELD); } - - uint Length() const; - void GetFoldingState(bool &all_folded, bool &all_unfolded) const; - bool IsVisible(const SettingEntry *item) const; - SettingEntry *FindEntry(uint row, uint *cur_row); - uint GetMaxHelpHeight(int maxw); - - bool IsFiltered() const; - bool UpdateFilterState(SettingFilter &filter, bool force_visible); - - uint Draw(GameSettings *settings_ptr, int base_x, int base_y, int max_x, uint first_row, uint max_row, uint cur_row, uint parent_last, SettingEntry *selected); - - /** - * Get the help text of a single setting. - * @return The requested help text. - */ - inline StringID GetHelpText() - { - assert((this->flags & SEF_KIND_MASK) == SEF_SETTING_KIND); - return this->d.entry.setting->desc.str_help; - } - - void SetValueDParams(uint first_param, int32 value); - -private: - void DrawSetting(GameSettings *settings_ptr, int x, int y, int max_x, int state, bool highlight); - bool IsVisibleByRestrictionMode(RestrictionMode mode) const; -}; - -/** Data structure describing one page of settings in the settings window. */ -struct SettingsPage { - SettingEntry *entries; ///< Array of setting entries of the page. - byte num; ///< Number of entries on the page (statically filled). - - void Init(byte level = 0); - void FoldAll(); - void UnFoldAll(); - - uint Length() const; - void GetFoldingState(bool &all_folded, bool &all_unfolded) const; - bool IsVisible(const SettingEntry *item) const; - SettingEntry *FindEntry(uint row, uint *cur_row) const; - uint GetMaxHelpHeight(int maxw); - - bool UpdateFilterState(SettingFilter &filter, bool force_visible); - - uint Draw(GameSettings *settings_ptr, int base_x, int base_y, int max_x, uint first_row, uint max_row, SettingEntry *selected, uint cur_row = 0, uint parent_last = 0) const; -}; - - -/* == SettingEntry methods == */ - -/** - * Constructor for a single setting in the 'advanced settings' window - * @param nm Name of the setting in the setting table - */ -SettingEntry::SettingEntry(const char *nm) -{ - this->flags = SEF_SETTING_KIND; - this->level = 0; - this->d.entry.name = nm; - this->d.entry.setting = NULL; - this->d.entry.index = 0; -} - -/** - * Constructor for a sub-page in the 'advanced settings' window - * @param sub Sub-page - * @param title Title of the sub-page - */ -SettingEntry::SettingEntry(SettingsPage *sub, StringID title) -{ - this->flags = SEF_SUBTREE_KIND; - this->level = 0; - this->d.sub.page = sub; - this->d.sub.folded = true; - this->d.sub.title = title; -} - -/** - * Initialization of a setting entry - * @param level Page nesting level of this entry - */ -void SettingEntry::Init(byte level) -{ - this->level = level; - - switch (this->flags & SEF_KIND_MASK) { - case SEF_SETTING_KIND: - this->d.entry.setting = GetSettingFromName(this->d.entry.name, &this->d.entry.index); - assert(this->d.entry.setting != NULL); - break; - case SEF_SUBTREE_KIND: - this->d.sub.page->Init(level + 1); - break; - default: NOT_REACHED(); - } -} - -/** Recursively close all (filtered) folds of sub-pages */ -void SettingEntry::FoldAll() -{ - if (this->IsFiltered()) return; - switch (this->flags & SEF_KIND_MASK) { - case SEF_SETTING_KIND: - break; - - case SEF_SUBTREE_KIND: - this->d.sub.folded = true; - this->d.sub.page->FoldAll(); - break; - - default: NOT_REACHED(); - } -} - -/** Recursively open all (filtered) folds of sub-pages */ -void SettingEntry::UnFoldAll() -{ - if (this->IsFiltered()) return; - switch (this->flags & SEF_KIND_MASK) { - case SEF_SETTING_KIND: - break; - - case SEF_SUBTREE_KIND: - this->d.sub.folded = false; - this->d.sub.page->UnFoldAll(); - break; - - default: NOT_REACHED(); - } -} - -/** - * Recursively accumulate the folding state of the (filtered) tree. - * @param[in,out] all_folded Set to false, if one entry is not folded. - * @param[in,out] all_unfolded Set to false, if one entry is folded. - */ -void SettingEntry::GetFoldingState(bool &all_folded, bool &all_unfolded) const -{ - if (this->IsFiltered()) return; - switch (this->flags & SEF_KIND_MASK) { - case SEF_SETTING_KIND: - break; - - case SEF_SUBTREE_KIND: - if (this->d.sub.folded) { - all_unfolded = false; - } else { - all_folded = false; - } - this->d.sub.page->GetFoldingState(all_folded, all_unfolded); - break; - - default: NOT_REACHED(); - } -} - -/** - * Check whether an entry is visible and not folded or filtered away. - * Note: This does not consider the scrolling range; it might still require scrolling to make the setting really visible. - * @param item Entry to search for. - * @return true if entry is visible. - */ -bool SettingEntry::IsVisible(const SettingEntry *item) const -{ - if (this->IsFiltered()) return false; - if (this == item) return true; - - switch (this->flags & SEF_KIND_MASK) { - case SEF_SETTING_KIND: - return false; - - case SEF_SUBTREE_KIND: - return !this->d.sub.folded && this->d.sub.page->IsVisible(item); - - default: NOT_REACHED(); - } -} - -/** - * Set the button-depressed flags (#SEF_LEFT_DEPRESSED and #SEF_RIGHT_DEPRESSED) to a specified value - * @param new_val New value for the button flags - * @see SettingEntryFlags - */ -void SettingEntry::SetButtons(byte new_val) -{ - assert((new_val & ~SEF_BUTTONS_MASK) == 0); // Should not touch any flags outside the buttons - this->flags = (this->flags & ~SEF_BUTTONS_MASK) | new_val; -} - -/** Return numbers of rows needed to display the (filtered) entry */ -uint SettingEntry::Length() const -{ - if (this->IsFiltered()) return 0; - switch (this->flags & SEF_KIND_MASK) { - case SEF_SETTING_KIND: - return 1; - case SEF_SUBTREE_KIND: - if (this->d.sub.folded) return 1; // Only displaying the title - - return 1 + this->d.sub.page->Length(); // 1 extra row for the title - default: NOT_REACHED(); - } -} - -/** - * Find setting entry at row \a row_num - * @param row_num Index of entry to return - * @param cur_row Current row number - * @return The requested setting entry or \c NULL if it not found (folded or filtered) - */ -SettingEntry *SettingEntry::FindEntry(uint row_num, uint *cur_row) -{ - if (this->IsFiltered()) return NULL; - if (row_num == *cur_row) return this; - - switch (this->flags & SEF_KIND_MASK) { - case SEF_SETTING_KIND: - (*cur_row)++; - break; - case SEF_SUBTREE_KIND: - (*cur_row)++; // add one for row containing the title - if (this->d.sub.folded) { - break; - } - - /* sub-page is visible => search it too */ - return this->d.sub.page->FindEntry(row_num, cur_row); - default: NOT_REACHED(); - } - return NULL; -} - -/** - * Get the biggest height of the help text(s), if the width is at least \a maxw. Help text gets wrapped if needed. - * @param maxw Maximal width of a line help text. - * @return Biggest height needed to display any help text of this node (and its descendants). - */ -uint SettingEntry::GetMaxHelpHeight(int maxw) -{ - switch (this->flags & SEF_KIND_MASK) { - case SEF_SETTING_KIND: return GetStringHeight(this->GetHelpText(), maxw); - case SEF_SUBTREE_KIND: return this->d.sub.page->GetMaxHelpHeight(maxw); - default: NOT_REACHED(); - } -} - -/** - * Check whether an entry is hidden due to filters - * @return true if hidden. - */ -bool SettingEntry::IsFiltered() const -{ - return (this->flags & SEF_FILTERED) != 0; -} - -/** - * Checks whether an entry shall be made visible based on the restriction mode. - * @param mode The current status of the restriction drop down box. - * @return true if the entry shall be visible. - */ -bool SettingEntry::IsVisibleByRestrictionMode(RestrictionMode mode) const -{ - /* There shall not be any restriction, i.e. all settings shall be visible. */ - if (mode == RM_ALL) return true; - - GameSettings *settings_ptr = &GetGameSettings(); - assert((this->flags & SEF_KIND_MASK) == SEF_SETTING_KIND); - const SettingDesc *sd = this->d.entry.setting; - - if (mode == RM_BASIC) return (this->d.entry.setting->desc.cat & SC_BASIC_LIST) != 0; - if (mode == RM_ADVANCED) return (this->d.entry.setting->desc.cat & SC_ADVANCED_LIST) != 0; - - /* Read the current value. */ - const void *var = ResolveVariableAddress(settings_ptr, sd); - int64 current_value = ReadValue(var, sd->save.conv); - - int64 filter_value; - - if (mode == RM_CHANGED_AGAINST_DEFAULT) { - /* This entry shall only be visible, if the value deviates from its default value. */ - - /* Read the default value. */ - filter_value = ReadValue(&sd->desc.def, sd->save.conv); - } else { - assert(mode == RM_CHANGED_AGAINST_NEW); - /* This entry shall only be visible, if the value deviates from - * its value is used when starting a new game. */ - - /* Make sure we're not comparing the new game settings against itself. */ - assert(settings_ptr != &_settings_newgame); - - /* Read the new game's value. */ - var = ResolveVariableAddress(&_settings_newgame, sd); - filter_value = ReadValue(var, sd->save.conv); - } - - return current_value != filter_value; -} - -/** - * Update the filter state. - * @param filter Filter - * @param force_visible Whether to force all items visible, no matter what (due to filter text; not affected by restriction drop down box). - * @return true if item remains visible - */ -bool SettingEntry::UpdateFilterState(SettingFilter &filter, bool force_visible) -{ - CLRBITS(this->flags, SEF_FILTERED); - - bool visible = true; - switch (this->flags & SEF_KIND_MASK) { - case SEF_SETTING_KIND: { - const SettingDesc *sd = this->d.entry.setting; - if (!force_visible && !filter.string.IsEmpty()) { - /* Process the search text filter for this item. */ - filter.string.ResetState(); - - const SettingDescBase *sdb = &sd->desc; - - SetDParam(0, STR_EMPTY); - filter.string.AddLine(sdb->str); - filter.string.AddLine(this->GetHelpText()); - - visible = filter.string.GetState(); - } - if (visible) { - if (filter.type != ST_ALL && sd->GetType() != filter.type) { - filter.type_hides = true; - visible = false; - } - if (!this->IsVisibleByRestrictionMode(filter.mode)) { - while (filter.min_cat < RM_ALL && (filter.min_cat == filter.mode || !this->IsVisibleByRestrictionMode(filter.min_cat))) filter.min_cat++; - visible = false; - } - } - break; - } - case SEF_SUBTREE_KIND: { - if (!force_visible && !filter.string.IsEmpty()) { - filter.string.ResetState(); - filter.string.AddLine(this->d.sub.title); - force_visible = filter.string.GetState(); - } - visible = this->d.sub.page->UpdateFilterState(filter, force_visible); - break; - } - default: NOT_REACHED(); - } - - if (!visible) SETBITS(this->flags, SEF_FILTERED); - return visible; -} - - - -/** - * Draw a row in the settings panel. - * - * See SettingsPage::Draw() for an explanation about how drawing is performed. - * - * The \a parent_last parameter ensures that the vertical lines at the left are - * only drawn when another entry follows, that it prevents output like - * \verbatim - * |-- setting - * |-- (-) - Title - * | |-- setting - * | |-- setting - * \endverbatim - * The left-most vertical line is not wanted. It is prevented by setting the - * appropriate bit in the \a parent_last parameter. - * - * @param settings_ptr Pointer to current values of all settings - * @param left Left-most position in window/panel to start drawing \a first_row - * @param right Right-most x position to draw strings at. - * @param base_y Upper-most position in window/panel to start drawing \a first_row - * @param first_row First row number to draw - * @param max_row Row-number to stop drawing (the row-number of the row below the last row to draw) - * @param cur_row Current row number (internal variable) - * @param parent_last Last-field booleans of parent page level (page level \e i sets bit \e i to 1 if it is its last field) - * @param selected Selected entry by the user. - * @return Row number of the next row to draw - */ -uint SettingEntry::Draw(GameSettings *settings_ptr, int left, int right, int base_y, uint first_row, uint max_row, uint cur_row, uint parent_last, SettingEntry *selected) -{ - if (this->IsFiltered()) return cur_row; - if (cur_row >= max_row) return cur_row; - - bool rtl = _current_text_dir == TD_RTL; - int offset = rtl ? -4 : 4; - int level_width = rtl ? -LEVEL_WIDTH : LEVEL_WIDTH; - - int x = rtl ? right : left; - int y = base_y; - if (cur_row >= first_row) { - int colour = _colour_gradient[COLOUR_ORANGE][4]; - y = base_y + (cur_row - first_row) * SETTING_HEIGHT; // Compute correct y start position - - /* Draw vertical for parent nesting levels */ - for (uint lvl = 0; lvl < this->level; lvl++) { - if (!HasBit(parent_last, lvl)) GfxDrawLine(x + offset, y, x + offset, y + SETTING_HEIGHT - 1, colour); - x += level_width; - } - /* draw own |- prefix */ - int halfway_y = y + SETTING_HEIGHT / 2; - int bottom_y = (flags & SEF_LAST_FIELD) ? halfway_y : y + SETTING_HEIGHT - 1; - GfxDrawLine(x + offset, y, x + offset, bottom_y, colour); - /* Small horizontal line from the last vertical line */ - GfxDrawLine(x + offset, halfway_y, x + level_width - offset, halfway_y, colour); - x += level_width; - } - - switch (this->flags & SEF_KIND_MASK) { - case SEF_SETTING_KIND: - if (cur_row >= first_row) { - this->DrawSetting(settings_ptr, rtl ? left : x, rtl ? x : right, y, this->flags & SEF_BUTTONS_MASK, - this == selected); - } - cur_row++; - break; - case SEF_SUBTREE_KIND: - if (cur_row >= first_row) { - DrawSprite((this->d.sub.folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED), PAL_NONE, rtl ? x - 8 : x, y + (SETTING_HEIGHT - 11) / 2); - DrawString(rtl ? left : x + 12, rtl ? x - 12 : right, Center(y, SETTING_HEIGHT), this->d.sub.title); - } - cur_row++; - if (!this->d.sub.folded) { - if (this->flags & SEF_LAST_FIELD) { - assert(this->level < sizeof(parent_last)); - SetBit(parent_last, this->level); // Add own last-field state - } - - cur_row = this->d.sub.page->Draw(settings_ptr, left, right, base_y, first_row, max_row, selected, cur_row, parent_last); - } - break; - default: NOT_REACHED(); - } - return cur_row; -} - -static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const SettingDesc *sd) -{ - if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { - if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) { - return GetVariableAddress(&Company::Get(_local_company)->settings, &sd->save); - } else { - return GetVariableAddress(&_settings_client.company, &sd->save); - } - } else { - return GetVariableAddress(settings_ptr, &sd->save); - } -} - -/** - * Set the DParams for drawing the value of a setting. - * @param first_param First DParam to use - * @param value Setting value to set params for. - */ -void SettingEntry::SetValueDParams(uint first_param, int32 value) -{ - assert((this->flags & SEF_KIND_MASK) == SEF_SETTING_KIND); - const SettingDescBase *sdb = &this->d.entry.setting->desc; - if (sdb->cmd == SDT_BOOLX) { - SetDParam(first_param++, value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); - } else { - if ((sdb->flags & SGF_MULTISTRING) != 0) { - SetDParam(first_param++, sdb->str_val - sdb->min + value); - } else if ((sdb->flags & SGF_DISPLAY_ABS) != 0) { - SetDParam(first_param++, sdb->str_val + ((value >= 0) ? 1 : 0)); - value = abs(value); - } else { - SetDParam(first_param++, sdb->str_val + ((value == 0 && (sdb->flags & SGF_0ISDISABLED) != 0) ? 1 : 0)); - } - SetDParam(first_param++, value); - } -} - -/** - * Private function to draw setting value (button + text + current value) - * @param settings_ptr Pointer to current values of all settings - * @param left Left-most position in window/panel to start drawing - * @param right Right-most position in window/panel to draw - * @param y Upper-most position in window/panel to start drawing - * @param state State of the left + right arrow buttons to draw for the setting - * @param highlight Highlight entry. - */ -void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, int y, int state, bool highlight) -{ - const SettingDesc *sd = this->d.entry.setting; - const SettingDescBase *sdb = &sd->desc; - const void *var = ResolveVariableAddress(settings_ptr, sd); - - bool rtl = _current_text_dir == TD_RTL; - uint buttons_left = rtl ? right + 1 - SETTING_BUTTON_WIDTH : left; - uint text_left = left + (rtl ? 0 : SETTING_BUTTON_WIDTH + 5); - uint text_right = right - (rtl ? SETTING_BUTTON_WIDTH + 5 : 0); - uint button_y = y + (SETTING_HEIGHT - SETTING_BUTTON_HEIGHT) / 2; - - /* We do not allow changes of some items when we are a client in a networkgame */ - bool editable = sd->IsEditable(); - - SetDParam(0, highlight ? STR_ORANGE_STRING1_WHITE : STR_ORANGE_STRING1_LTBLUE); - int32 value = (int32)ReadValue(var, sd->save.conv); - if (sdb->cmd == SDT_BOOLX) { - /* Draw checkbox for boolean-value either on/off */ - DrawBoolButton(buttons_left, button_y, value != 0, editable); - } else if ((sdb->flags & SGF_MULTISTRING) != 0) { - /* Draw [v] button for settings of an enum-type */ - DrawDropDownButton(buttons_left, button_y, COLOUR_YELLOW, state != 0, editable); - } else { - /* Draw [<][>] boxes for settings of an integer-type */ - DrawArrowButtons(buttons_left, button_y, COLOUR_YELLOW, state, - editable && value != (sdb->flags & SGF_0ISDISABLED ? 0 : sdb->min), editable && (uint32)value != sdb->max); - } - this->SetValueDParams(1, value); - DrawString(text_left, text_right, Center(y, SETTING_HEIGHT), sdb->str, highlight ? TC_WHITE : TC_LIGHT_BLUE); -} - - -/* == SettingsPage methods == */ - -/** - * Initialization of an entire setting page - * @param level Nesting level of this page (internal variable, do not provide a value for it when calling) - */ -void SettingsPage::Init(byte level) -{ - for (uint field = 0; field < this->num; field++) { - this->entries[field].Init(level); - } -} - -/** Recursively close all folds of sub-pages */ -void SettingsPage::FoldAll() -{ - for (uint field = 0; field < this->num; field++) { - this->entries[field].FoldAll(); - } -} - -/** Recursively open all folds of sub-pages */ -void SettingsPage::UnFoldAll() -{ - for (uint field = 0; field < this->num; field++) { - this->entries[field].UnFoldAll(); - } -} - -/** - * Recursively accumulate the folding state of the tree. - * @param[in,out] all_folded Set to false, if one entry is not folded. - * @param[in,out] all_unfolded Set to false, if one entry is folded. - */ -void SettingsPage::GetFoldingState(bool &all_folded, bool &all_unfolded) const -{ - for (uint field = 0; field < this->num; field++) { - this->entries[field].GetFoldingState(all_folded, all_unfolded); - } -} - -/** - * Update the filter state. - * @param filter Filter - * @param force_visible Whether to force all items visible, no matter what - * @return true if item remains visible - */ -bool SettingsPage::UpdateFilterState(SettingFilter &filter, bool force_visible) -{ - bool visible = false; - bool first_visible = true; - for (int field = this->num - 1; field >= 0; field--) { - visible |= this->entries[field].UpdateFilterState(filter, force_visible); - this->entries[field].SetLastField(first_visible); - if (visible && first_visible) first_visible = false; - } - return visible; -} - - -/** - * Check whether an entry is visible and not folded or filtered away. - * Note: This does not consider the scrolling range; it might still require scrolling ot make the setting really visible. - * @param item Entry to search for. - * @return true if entry is visible. - */ -bool SettingsPage::IsVisible(const SettingEntry *item) const -{ - for (uint field = 0; field < this->num; field++) { - if (this->entries[field].IsVisible(item)) return true; - } - return false; -} - -/** Return number of rows needed to display the whole page */ -uint SettingsPage::Length() const -{ - uint length = 0; - for (uint field = 0; field < this->num; field++) { - length += this->entries[field].Length(); - } - return length; -} - -/** - * Find the setting entry at row number \a row_num - * @param row_num Index of entry to return - * @param cur_row Variable used for keeping track of the current row number. Should point to memory initialized to \c 0 when first called. - * @return The requested setting entry or \c NULL if it does not exist - */ -SettingEntry *SettingsPage::FindEntry(uint row_num, uint *cur_row) const -{ - SettingEntry *pe = NULL; - - for (uint field = 0; field < this->num; field++) { - pe = this->entries[field].FindEntry(row_num, cur_row); - if (pe != NULL) { - break; - } - } - return pe; -} - -/** - * Get the biggest height of the help texts, if the width is at least \a maxw. Help text gets wrapped if needed. - * @param maxw Maximal width of a line help text. - * @return Biggest height needed to display any help text of this (sub-)tree. - */ -uint SettingsPage::GetMaxHelpHeight(int maxw) -{ - uint biggest = 0; - for (uint field = 0; field < this->num; field++) { - biggest = max(biggest, this->entries[field].GetMaxHelpHeight(maxw)); - } - return biggest; -} - -/** - * Draw a selected part of the settings page. - * - * The scrollbar uses rows of the page, while the page data structure is a tree of #SettingsPage and #SettingEntry objects. - * As a result, the drawing routing traverses the tree from top to bottom, counting rows in \a cur_row until it reaches \a first_row. - * Then it enables drawing rows while traversing until \a max_row is reached, at which point drawing is terminated. - * - * @param settings_ptr Pointer to current values of all settings - * @param left Left-most position in window/panel to start drawing of each setting row - * @param right Right-most position in window/panel to draw at - * @param base_y Upper-most position in window/panel to start drawing of row number \a first_row - * @param first_row Number of first row to draw - * @param max_row Row-number to stop drawing (the row-number of the row below the last row to draw) - * @param cur_row Current row number (internal variable) - * @param parent_last Last-field booleans of parent page level (page level \e i sets bit \e i to 1 if it is its last field) - * @param selected Selected entry by the user. - * @return Row number of the next row to draw - */ -uint SettingsPage::Draw(GameSettings *settings_ptr, int left, int right, int base_y, uint first_row, uint max_row, SettingEntry *selected, uint cur_row, uint parent_last) const -{ - if (cur_row >= max_row) return cur_row; - - for (uint i = 0; i < this->num; i++) { - cur_row = this->entries[i].Draw(settings_ptr, left, right, base_y, first_row, max_row, cur_row, parent_last, selected); - if (cur_row >= max_row) { - break; - } - } - return cur_row; -} - - -static SettingEntry _settings_ui_localisation[] = { - SettingEntry("locale.units_velocity"), - SettingEntry("locale.units_power"), - SettingEntry("locale.units_weight"), - SettingEntry("locale.units_volume"), - SettingEntry("locale.units_force"), - SettingEntry("locale.units_height"), -}; -/** Localisation options sub-page */ -static SettingsPage _settings_ui_localisation_page = {_settings_ui_localisation, lengthof(_settings_ui_localisation)}; - -static SettingEntry _settings_ui_display[] = { - SettingEntry("gui.date_format_in_default_names"), - SettingEntry("gui.population_in_label"), - SettingEntry("gui.measure_tooltip"), - SettingEntry("gui.loading_indicators"), - SettingEntry("gui.liveries"), - SettingEntry("gui.show_track_reservation"), - SettingEntry("gui.expenses_layout"), - SettingEntry("gui.smallmap_land_colour"), - SettingEntry("gui.zoom_min"), - SettingEntry("gui.zoom_max"), - SettingEntry("gui.graph_line_thickness"), -}; -/** Display options sub-page */ -static SettingsPage _settings_ui_display_page = {_settings_ui_display, lengthof(_settings_ui_display)}; - -static SettingEntry _settings_ui_interaction[] = { - SettingEntry("gui.window_snap_radius"), - SettingEntry("gui.window_soft_limit"), - SettingEntry("gui.link_terraform_toolbar"), - SettingEntry("gui.prefer_teamchat"), - SettingEntry("gui.auto_scrolling"), - SettingEntry("gui.reverse_scroll"), - SettingEntry("gui.smooth_scroll"), - SettingEntry("gui.left_mouse_btn_scrolling"), - /* While the horizontal scrollwheel scrolling is written as general code, only - * the cocoa (OSX) driver generates input for it. - * Since it's also able to completely disable the scrollwheel will we display it on all platforms anyway */ - SettingEntry("gui.scrollwheel_scrolling"), - SettingEntry("gui.scrollwheel_multiplier"), - SettingEntry("gui.osk_activation"), -#ifdef __APPLE__ - /* We might need to emulate a right mouse button on mac */ - SettingEntry("gui.right_mouse_btn_emulation"), -#endif -}; -/** Interaction sub-page */ -static SettingsPage _settings_ui_interaction_page = {_settings_ui_interaction, lengthof(_settings_ui_interaction)}; - -static SettingEntry _settings_ui_sound[] = { - SettingEntry("sound.click_beep"), - SettingEntry("sound.confirm"), - SettingEntry("sound.news_ticker"), - SettingEntry("sound.news_full"), - SettingEntry("sound.new_year"), - SettingEntry("sound.disaster"), - SettingEntry("sound.vehicle"), - SettingEntry("sound.ambient"), -}; -/** Sound effects sub-page */ -static SettingsPage _settings_ui_sound_page = {_settings_ui_sound, lengthof(_settings_ui_sound)}; - -static SettingEntry _settings_ui_news[] = { - SettingEntry("news_display.arrival_player"), - SettingEntry("news_display.arrival_other"), - SettingEntry("news_display.accident"), - SettingEntry("news_display.company_info"), - SettingEntry("news_display.open"), - SettingEntry("news_display.close"), - SettingEntry("news_display.economy"), - SettingEntry("news_display.production_player"), - SettingEntry("news_display.production_other"), - SettingEntry("news_display.production_nobody"), - SettingEntry("news_display.advice"), - SettingEntry("news_display.new_vehicles"), - SettingEntry("news_display.acceptance"), - SettingEntry("news_display.subsidies"), - SettingEntry("news_display.general"), - SettingEntry("gui.coloured_news_year"), -}; -/** News sub-page */ -static SettingsPage _settings_ui_news_page = {_settings_ui_news, lengthof(_settings_ui_news)}; - -static SettingEntry _settings_ui[] = { - SettingEntry(&_settings_ui_localisation_page, STR_CONFIG_SETTING_LOCALISATION), - SettingEntry(&_settings_ui_display_page, STR_CONFIG_SETTING_DISPLAY_OPTIONS), - SettingEntry(&_settings_ui_interaction_page, STR_CONFIG_SETTING_INTERACTION), - SettingEntry(&_settings_ui_sound_page, STR_CONFIG_SETTING_SOUND), - SettingEntry(&_settings_ui_news_page, STR_CONFIG_SETTING_NEWS), - SettingEntry("gui.show_finances"), - SettingEntry("gui.errmsg_duration"), - SettingEntry("gui.hover_delay"), - SettingEntry("gui.toolbar_pos"), - SettingEntry("gui.statusbar_pos"), - SettingEntry("gui.newgrf_default_palette"), - SettingEntry("gui.pause_on_newgame"), - SettingEntry("gui.advanced_vehicle_list"), - SettingEntry("gui.timetable_in_ticks"), - SettingEntry("gui.timetable_arrival_departure"), - SettingEntry("gui.quick_goto"), - SettingEntry("gui.default_rail_type"), - SettingEntry("gui.disable_unsuitable_building"), - SettingEntry("gui.persistent_buildingtools"), -}; -/** Interface subpage */ -static SettingsPage _settings_ui_page = {_settings_ui, lengthof(_settings_ui)}; - -static SettingEntry _settings_construction_signals[] = { - SettingEntry("construction.train_signal_side"), - SettingEntry("gui.enable_signal_gui"), - SettingEntry("gui.drag_signals_fixed_distance"), - SettingEntry("gui.semaphore_build_before"), - SettingEntry("gui.default_signal_type"), - SettingEntry("gui.cycle_signal_types"), -}; -/** Signals subpage */ -static SettingsPage _settings_construction_signals_page = {_settings_construction_signals, lengthof(_settings_construction_signals)}; - -static SettingEntry _settings_construction[] = { - SettingEntry(&_settings_construction_signals_page, STR_CONFIG_SETTING_CONSTRUCTION_SIGNALS), - SettingEntry("construction.build_on_slopes"), - SettingEntry("construction.autoslope"), - SettingEntry("construction.extra_dynamite"), - SettingEntry("construction.max_bridge_length"), - SettingEntry("construction.max_tunnel_length"), - SettingEntry("station.never_expire_airports"), - SettingEntry("construction.freeform_edges"), - SettingEntry("construction.extra_tree_placement"), - SettingEntry("construction.command_pause_level"), -}; -/** Construction sub-page */ -static SettingsPage _settings_construction_page = {_settings_construction, lengthof(_settings_construction)}; - -static SettingEntry _settings_stations_cargo[] = { - SettingEntry("order.improved_load"), - SettingEntry("order.gradual_loading"), - SettingEntry("order.selectgoods"), -}; -/** Cargo handling sub-page */ -static SettingsPage _settings_stations_cargo_page = {_settings_stations_cargo, lengthof(_settings_stations_cargo)}; - -static SettingEntry _settings_stations[] = { - SettingEntry(&_settings_stations_cargo_page, STR_CONFIG_SETTING_STATIONS_CARGOHANDLING), - SettingEntry("station.adjacent_stations"), - SettingEntry("station.distant_join_stations"), - SettingEntry("station.station_spread"), - SettingEntry("economy.station_noise_level"), - SettingEntry("station.modified_catchment"), - SettingEntry("construction.road_stop_on_town_road"), - SettingEntry("construction.road_stop_on_competitor_road"), -}; -/** Stations sub-page */ -static SettingsPage _settings_stations_page = {_settings_stations, lengthof(_settings_stations)}; - -static SettingEntry _settings_economy_towns[] = { - SettingEntry("difficulty.town_council_tolerance"), - SettingEntry("economy.bribe"), - SettingEntry("economy.exclusive_rights"), - SettingEntry("economy.fund_roads"), - SettingEntry("economy.fund_buildings"), - SettingEntry("economy.town_layout"), - SettingEntry("economy.allow_town_roads"), - SettingEntry("economy.allow_town_level_crossings"), - SettingEntry("economy.found_town"), - SettingEntry("economy.mod_road_rebuild"), - SettingEntry("economy.town_growth_rate"), - SettingEntry("economy.larger_towns"), - SettingEntry("economy.initial_city_size"), -}; -/** Towns sub-page */ -static SettingsPage _settings_economy_towns_page = {_settings_economy_towns, lengthof(_settings_economy_towns)}; - -static SettingEntry _settings_economy_industries[] = { - SettingEntry("construction.raw_industry_construction"), - SettingEntry("construction.industry_platform"), - SettingEntry("economy.multiple_industry_per_town"), - SettingEntry("game_creation.oil_refinery_limit"), -}; -/** Industries sub-page */ -static SettingsPage _settings_economy_industries_page = {_settings_economy_industries, lengthof(_settings_economy_industries)}; - - -static SettingEntry _settings_economy[] = { - SettingEntry(&_settings_economy_towns_page, STR_CONFIG_SETTING_ECONOMY_TOWNS), - SettingEntry(&_settings_economy_industries_page, STR_CONFIG_SETTING_ECONOMY_INDUSTRIES), - SettingEntry("economy.inflation"), - SettingEntry("difficulty.initial_interest"), - SettingEntry("difficulty.max_loan"), - SettingEntry("difficulty.subsidy_multiplier"), - SettingEntry("difficulty.economy"), - SettingEntry("economy.smooth_economy"), - SettingEntry("economy.feeder_payment_share"), - SettingEntry("economy.infrastructure_maintenance"), - SettingEntry("difficulty.vehicle_costs"), - SettingEntry("difficulty.construction_cost"), - SettingEntry("difficulty.disasters"), -}; -/** Economy sub-page */ -static SettingsPage _settings_economy_page = {_settings_economy, lengthof(_settings_economy)}; - -static SettingEntry _settings_linkgraph[] = { - SettingEntry("linkgraph.recalc_time"), - SettingEntry("linkgraph.recalc_interval"), - SettingEntry("linkgraph.distribution_pax"), - SettingEntry("linkgraph.distribution_mail"), - SettingEntry("linkgraph.distribution_armoured"), - SettingEntry("linkgraph.distribution_default"), - SettingEntry("linkgraph.accuracy"), - SettingEntry("linkgraph.demand_distance"), - SettingEntry("linkgraph.demand_size"), - SettingEntry("linkgraph.short_path_saturation"), -}; -/** Linkgraph sub-page */ -static SettingsPage _settings_linkgraph_page = {_settings_linkgraph, lengthof(_settings_linkgraph)}; - -static SettingEntry _settings_ai_npc[] = { - SettingEntry("script.settings_profile"), - SettingEntry("script.script_max_opcode_till_suspend"), - SettingEntry("difficulty.competitor_speed"), - SettingEntry("ai.ai_in_multiplayer"), - SettingEntry("ai.ai_disable_veh_train"), - SettingEntry("ai.ai_disable_veh_roadveh"), - SettingEntry("ai.ai_disable_veh_aircraft"), - SettingEntry("ai.ai_disable_veh_ship"), -}; -/** Computer players sub-page */ -static SettingsPage _settings_ai_npc_page = {_settings_ai_npc, lengthof(_settings_ai_npc)}; - -static SettingEntry _settings_ai[] = { - SettingEntry(&_settings_ai_npc_page, STR_CONFIG_SETTING_AI_NPC), - SettingEntry("economy.give_money"), - SettingEntry("economy.allow_shares"), -}; -/** AI sub-page */ -static SettingsPage _settings_ai_page = {_settings_ai, lengthof(_settings_ai)}; - -static SettingEntry _settings_vehicles_routing[] = { - SettingEntry("pf.pathfinder_for_trains"), - SettingEntry("pf.forbid_90_deg"), - SettingEntry("pf.pathfinder_for_roadvehs"), - SettingEntry("pf.roadveh_queue"), - SettingEntry("pf.pathfinder_for_ships"), -}; -/** Autorenew sub-page */ -static SettingsPage _settings_vehicles_routing_page = {_settings_vehicles_routing, lengthof(_settings_vehicles_routing)}; - -static SettingEntry _settings_vehicles_autorenew[] = { - SettingEntry("company.engine_renew"), - SettingEntry("company.engine_renew_months"), - SettingEntry("company.engine_renew_money"), -}; -/** Autorenew sub-page */ -static SettingsPage _settings_vehicles_autorenew_page = {_settings_vehicles_autorenew, lengthof(_settings_vehicles_autorenew)}; - -static SettingEntry _settings_vehicles_servicing[] = { - SettingEntry("vehicle.servint_ispercent"), - SettingEntry("vehicle.servint_trains"), - SettingEntry("vehicle.servint_roadveh"), - SettingEntry("vehicle.servint_ships"), - SettingEntry("vehicle.servint_aircraft"), - SettingEntry("difficulty.vehicle_breakdowns"), - SettingEntry("order.no_servicing_if_no_breakdowns"), - SettingEntry("order.serviceathelipad"), -}; -/** Servicing sub-page */ -static SettingsPage _settings_vehicles_servicing_page = {_settings_vehicles_servicing, lengthof(_settings_vehicles_servicing)}; - -static SettingEntry _settings_vehicles_trains[] = { - SettingEntry("difficulty.line_reverse_mode"), - SettingEntry("pf.reverse_at_signals"), - SettingEntry("vehicle.train_acceleration_model"), - SettingEntry("vehicle.train_slope_steepness"), - SettingEntry("vehicle.max_train_length"), - SettingEntry("vehicle.wagon_speed_limits"), - SettingEntry("vehicle.disable_elrails"), - SettingEntry("vehicle.freight_trains"), - SettingEntry("gui.stop_location"), -}; -/** Trains sub-page */ -static SettingsPage _settings_vehicles_trains_page = {_settings_vehicles_trains, lengthof(_settings_vehicles_trains)}; - -static SettingEntry _settings_vehicles[] = { - SettingEntry(&_settings_vehicles_routing_page, STR_CONFIG_SETTING_VEHICLES_ROUTING), - SettingEntry(&_settings_vehicles_autorenew_page, STR_CONFIG_SETTING_VEHICLES_AUTORENEW), - SettingEntry(&_settings_vehicles_servicing_page, STR_CONFIG_SETTING_VEHICLES_SERVICING), - SettingEntry(&_settings_vehicles_trains_page, STR_CONFIG_SETTING_VEHICLES_TRAINS), - SettingEntry("gui.new_nonstop"), - SettingEntry("gui.order_review_system"), - SettingEntry("gui.vehicle_income_warn"), - SettingEntry("gui.lost_vehicle_warn"), - SettingEntry("vehicle.never_expire_vehicles"), - SettingEntry("vehicle.max_trains"), - SettingEntry("vehicle.max_roadveh"), - SettingEntry("vehicle.max_aircraft"), - SettingEntry("vehicle.max_ships"), - SettingEntry("vehicle.plane_speed"), - SettingEntry("vehicle.plane_crashes"), - SettingEntry("vehicle.dynamic_engines"), - SettingEntry("vehicle.roadveh_acceleration_model"), - SettingEntry("vehicle.roadveh_slope_steepness"), - SettingEntry("vehicle.smoke_amount"), -}; -/** Vehicles sub-page */ -static SettingsPage _settings_vehicles_page = {_settings_vehicles, lengthof(_settings_vehicles)}; - -static SettingEntry _settings_main[] = { - SettingEntry(&_settings_ui_page, STR_CONFIG_SETTING_GUI), - SettingEntry(&_settings_construction_page, STR_CONFIG_SETTING_CONSTRUCTION), - SettingEntry(&_settings_vehicles_page, STR_CONFIG_SETTING_VEHICLES), - SettingEntry(&_settings_stations_page, STR_CONFIG_SETTING_STATIONS), - SettingEntry(&_settings_economy_page, STR_CONFIG_SETTING_ECONOMY), - SettingEntry(&_settings_linkgraph_page, STR_CONFIG_SETTING_LINKGRAPH), - SettingEntry(&_settings_ai_page, STR_CONFIG_SETTING_AI), -}; - -/** Main page, holding all advanced settings */ -static SettingsPage _settings_main_page = {_settings_main, lengthof(_settings_main)}; - -static const StringID _game_settings_restrict_dropdown[] = { - STR_CONFIG_SETTING_RESTRICT_BASIC, // RM_BASIC - STR_CONFIG_SETTING_RESTRICT_ADVANCED, // RM_ADVANCED - STR_CONFIG_SETTING_RESTRICT_ALL, // RM_ALL - STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT, // RM_CHANGED_AGAINST_DEFAULT - STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW, // RM_CHANGED_AGAINST_NEW -}; -assert_compile(lengthof(_game_settings_restrict_dropdown) == RM_END); - -/** Warnings about hidden search results. */ -enum WarnHiddenResult { - WHR_NONE, ///< Nothing was filtering matches away. - WHR_CATEGORY, ///< Category setting filtered matches away. - WHR_TYPE, ///< Type setting filtered matches away. - WHR_CATEGORY_TYPE, ///< Both category and type settings filtered matches away. -}; - -/** Window to edit settings of the game. */ -struct GameSettingsWindow : Window { - static const int SETTINGTREE_LEFT_OFFSET = 5; ///< Position of left edge of setting values - static const int SETTINGTREE_RIGHT_OFFSET = 5; ///< Position of right edge of setting values - static const int SETTINGTREE_TOP_OFFSET = 5; ///< Position of top edge of setting values - static const int SETTINGTREE_BOTTOM_OFFSET = 5; ///< Position of bottom edge of setting values - - static GameSettings *settings_ptr; ///< Pointer to the game settings being displayed and modified. - - SettingEntry *valuewindow_entry; ///< If non-NULL, pointer to setting for which a value-entering window has been opened. - SettingEntry *clicked_entry; ///< If non-NULL, pointer to a clicked numeric setting (with a depressed left or right button). - SettingEntry *last_clicked; ///< If non-NULL, pointer to the last clicked setting. - SettingEntry *valuedropdown_entry; ///< If non-NULL, pointer to the value for which a dropdown window is currently opened. - bool closing_dropdown; ///< True, if the dropdown list is currently closing. - - SettingFilter filter; ///< Filter for the list. - QueryString filter_editbox; ///< Filter editbox; - bool manually_changed_folding; ///< Whether the user expanded/collapsed something manually. - WarnHiddenResult warn_missing; ///< Whether and how to warn about missing search results. - int warn_lines; ///< Number of lines used for warning about missing search results. - - Scrollbar *vscroll; - - GameSettingsWindow(WindowDesc *desc) : Window(desc), filter_editbox(50) - { - static bool first_time = true; - - this->warn_missing = WHR_NONE; - this->warn_lines = 0; - this->filter.mode = (RestrictionMode)_settings_client.gui.settings_restriction_mode; - this->filter.min_cat = RM_ALL; - this->filter.type = ST_ALL; - this->filter.type_hides = false; - this->settings_ptr = &GetGameSettings(); - - /* Build up the dynamic settings-array only once per OpenTTD session */ - if (first_time) { - _settings_main_page.Init(); - first_time = false; - } else { - _settings_main_page.FoldAll(); // Close all sub-pages - } - - this->valuewindow_entry = NULL; // No setting entry for which a entry window is opened - this->clicked_entry = NULL; // No numeric setting buttons are depressed - this->last_clicked = NULL; - this->valuedropdown_entry = NULL; - this->closing_dropdown = false; - this->manually_changed_folding = false; - - this->CreateNestedTree(); - this->vscroll = this->GetScrollbar(WID_GS_SCROLLBAR); - this->FinishInitNested(WN_GAME_OPTIONS_GAME_SETTINGS); - - this->querystrings[WID_GS_FILTER] = &this->filter_editbox; - this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR; - this->SetFocusedWidget(WID_GS_FILTER); - - this->InvalidateData(); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_GS_OPTIONSPANEL: - resize->height = SETTING_HEIGHT = GetMinSizing(NWST_STEP, max(11, FONT_HEIGHT_NORMAL + 1)); - resize->width = 1; - - size->height = 5 * resize->height + SETTINGTREE_TOP_OFFSET + SETTINGTREE_BOTTOM_OFFSET; - break; - - case WID_GS_HELP_TEXT: { - static const StringID setting_types[] = { - STR_CONFIG_SETTING_TYPE_CLIENT, - STR_CONFIG_SETTING_TYPE_COMPANY_MENU, STR_CONFIG_SETTING_TYPE_COMPANY_INGAME, - STR_CONFIG_SETTING_TYPE_GAME_MENU, STR_CONFIG_SETTING_TYPE_GAME_INGAME, - }; - for (uint i = 0; i < lengthof(setting_types); i++) { - SetDParam(0, setting_types[i]); - size->width = max(size->width, GetStringBoundingBox(STR_CONFIG_SETTING_TYPE).width); - } - size->height = 2 * FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL + - max(size->height, _settings_main_page.GetMaxHelpHeight(size->width)); - break; - } - - case WID_GS_RESTRICT_CATEGORY: - case WID_GS_RESTRICT_TYPE: - size->width = max(GetStringBoundingBox(STR_CONFIG_SETTING_RESTRICT_CATEGORY).width, GetStringBoundingBox(STR_CONFIG_SETTING_RESTRICT_TYPE).width); - break; - - default: - break; - } - } - - virtual void OnPaint() - { - if (this->closing_dropdown) { - this->closing_dropdown = false; - assert(this->valuedropdown_entry != NULL); - this->valuedropdown_entry->SetButtons(0); - this->valuedropdown_entry = NULL; - } - - /* Reserve the correct number of lines for the 'some search results are hidden' notice in the central settings display panel. */ - const NWidgetBase *panel = this->GetWidget(WID_GS_OPTIONSPANEL); - StringID warn_str = STR_CONFIG_SETTING_CATEGORY_HIDES - 1 + this->warn_missing; - int new_warn_lines; - if (this->warn_missing == WHR_NONE) { - new_warn_lines = 0; - } else { - SetDParam(0, _game_settings_restrict_dropdown[this->filter.min_cat]); - new_warn_lines = GetStringLineCount(warn_str, panel->current_x); - } - if (this->warn_lines != new_warn_lines) { - this->vscroll->SetCount(this->vscroll->GetCount() - this->warn_lines + new_warn_lines); - this->warn_lines = new_warn_lines; - } - - this->DrawWidgets(); - - /* Draw the 'some search results are hidden' notice. */ - if (this->warn_missing != WHR_NONE) { - const int left = panel->pos_x; - const int right = left + panel->current_x - 1; - const int top = panel->pos_y; - SetDParam(0, _game_settings_restrict_dropdown[this->filter.min_cat]); - if (this->warn_lines == 1) { - /* If the warning fits at one line, center it. */ - DrawString(left + WD_FRAMETEXT_LEFT, right - WD_FRAMETEXT_RIGHT, top + WD_FRAMETEXT_TOP, warn_str, TC_FROMSTRING, SA_HOR_CENTER); - } else { - DrawStringMultiLine(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top + WD_FRAMERECT_TOP, INT32_MAX, warn_str); - } - } - } - - virtual void SetStringParameters(int widget) const - { - switch (widget) { - case WID_GS_RESTRICT_DROPDOWN: - SetDParam(0, _game_settings_restrict_dropdown[this->filter.mode]); - break; - - case WID_GS_TYPE_DROPDOWN: - switch (this->filter.type) { - case ST_GAME: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME); break; - case ST_COMPANY: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME); break; - case ST_CLIENT: SetDParam(0, STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT); break; - default: SetDParam(0, STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL); break; - } - break; - } - } - - DropDownList *BuildDropDownList(int widget) const - { - DropDownList *list = NULL; - switch (widget) { - case WID_GS_RESTRICT_DROPDOWN: - list = new DropDownList(); - - for (int mode = 0; mode != RM_END; mode++) { - /* If we are in adv. settings screen for the new game's settings, - * we don't want to allow comparing with new game's settings. */ - bool disabled = mode == RM_CHANGED_AGAINST_NEW && settings_ptr == &_settings_newgame; - - *list->Append() = new DropDownListStringItem(_game_settings_restrict_dropdown[mode], mode, disabled); - } - break; - - case WID_GS_TYPE_DROPDOWN: - list = new DropDownList(); - *list->Append() = new DropDownListStringItem(STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL, ST_ALL, false); - *list->Append() = new DropDownListStringItem(_game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME, ST_GAME, false); - *list->Append() = new DropDownListStringItem(_game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME, ST_COMPANY, false); - *list->Append() = new DropDownListStringItem(STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT, ST_CLIENT, false); - break; - } - return list; - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_GS_OPTIONSPANEL: { - int top_pos = r.top + SETTINGTREE_TOP_OFFSET + 1 + this->warn_lines * FONT_HEIGHT_NORMAL; - uint last_row = this->vscroll->GetPosition() + this->vscroll->GetCapacity() - this->warn_lines; - int next_row = _settings_main_page.Draw(settings_ptr, r.left + SETTINGTREE_LEFT_OFFSET, r.right - SETTINGTREE_RIGHT_OFFSET, top_pos, - this->vscroll->GetPosition(), last_row, this->last_clicked); - if (next_row == 0) DrawString(r.left + SETTINGTREE_LEFT_OFFSET, r.right - SETTINGTREE_RIGHT_OFFSET, top_pos, STR_CONFIG_SETTINGS_NONE); - break; - } - - case WID_GS_HELP_TEXT: - if (this->last_clicked != NULL) { - const SettingDesc *sd = this->last_clicked->d.entry.setting; - - int y = r.top; - switch (sd->GetType()) { - case ST_COMPANY: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_COMPANY_INGAME); break; - case ST_CLIENT: SetDParam(0, STR_CONFIG_SETTING_TYPE_CLIENT); break; - case ST_GAME: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_GAME_MENU : STR_CONFIG_SETTING_TYPE_GAME_INGAME); break; - default: NOT_REACHED(); - } - DrawString(r.left, r.right, y, STR_CONFIG_SETTING_TYPE); - y += FONT_HEIGHT_NORMAL; - - int32 default_value = ReadValue(&sd->desc.def, sd->save.conv); - this->last_clicked->SetValueDParams(0, default_value); - DrawString(r.left, r.right, y, STR_CONFIG_SETTING_DEFAULT_VALUE); - y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; - - DrawStringMultiLine(r.left, r.right, y, r.bottom, this->last_clicked->GetHelpText(), TC_WHITE); - } - break; - - default: - break; - } - } - - /** - * Set the entry that should have its help text displayed, and mark the window dirty so it gets repainted. - * @param pe Setting to display help text of, use \c NULL to stop displaying help of the currently displayed setting. - */ - void SetDisplayedHelpText(SettingEntry *pe) - { - if (this->last_clicked != pe) this->SetDirty(); - this->last_clicked = pe; - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_GS_EXPAND_ALL: - this->manually_changed_folding = true; - _settings_main_page.UnFoldAll(); - this->InvalidateData(); - break; - - case WID_GS_COLLAPSE_ALL: - this->manually_changed_folding = true; - _settings_main_page.FoldAll(); - this->InvalidateData(); - break; - - case WID_GS_RESTRICT_DROPDOWN: { - DropDownList *list = this->BuildDropDownList(widget); - if (list != NULL) { - ShowDropDownList(this, list, this->filter.mode, widget); - } - break; - } - - case WID_GS_TYPE_DROPDOWN: { - DropDownList *list = this->BuildDropDownList(widget); - if (list != NULL) { - ShowDropDownList(this, list, this->filter.type, widget); - } - break; - } - } - - if (widget != WID_GS_OPTIONSPANEL) return; - - uint btn = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GS_OPTIONSPANEL, SETTINGTREE_TOP_OFFSET); - if (btn == INT_MAX || (int)btn < this->warn_lines) return; - btn -= this->warn_lines; - - uint cur_row = 0; - SettingEntry *pe = _settings_main_page.FindEntry(btn, &cur_row); - - if (pe == NULL) return; // Clicked below the last setting of the page - - int x = (_current_text_dir == TD_RTL ? this->width - 1 - pt.x : pt.x) - SETTINGTREE_LEFT_OFFSET - (pe->level + 1) * LEVEL_WIDTH; // Shift x coordinate - if (x < 0) return; // Clicked left of the entry - - if ((pe->flags & SEF_KIND_MASK) == SEF_SUBTREE_KIND) { - this->SetDisplayedHelpText(NULL); - pe->d.sub.folded = !pe->d.sub.folded; // Flip 'folded'-ness of the sub-page - - this->manually_changed_folding = true; - - this->InvalidateData(); - return; - } - - assert((pe->flags & SEF_KIND_MASK) == SEF_SETTING_KIND); - const SettingDesc *sd = pe->d.entry.setting; - - /* return if action is only active in network, or only settable by server */ - if (!sd->IsEditable()) { - this->SetDisplayedHelpText(pe); - return; - } - - const void *var = ResolveVariableAddress(settings_ptr, sd); - int32 value = (int32)ReadValue(var, sd->save.conv); - - /* clicked on the icon on the left side. Either scroller, bool on/off or dropdown */ - if (x < SETTING_BUTTON_WIDTH && (sd->desc.flags & SGF_MULTISTRING)) { - const SettingDescBase *sdb = &sd->desc; - this->SetDisplayedHelpText(pe); - - if (this->valuedropdown_entry == pe) { - /* unclick the dropdown */ - HideDropDownMenu(this); - this->closing_dropdown = false; - this->valuedropdown_entry->SetButtons(0); - this->valuedropdown_entry = NULL; - } else { - if (this->valuedropdown_entry != NULL) this->valuedropdown_entry->SetButtons(0); - this->closing_dropdown = false; - - const NWidgetBase *wid = this->GetWidget(WID_GS_OPTIONSPANEL); - int rel_y = (pt.y - (int)wid->pos_y - SETTINGTREE_TOP_OFFSET) % wid->resize_y; - - Rect wi_rect; - wi_rect.left = pt.x - (_current_text_dir == TD_RTL ? SETTING_BUTTON_WIDTH - 1 - x : x); - wi_rect.right = wi_rect.left + SETTING_BUTTON_WIDTH - 1; - wi_rect.top = pt.y - rel_y + (SETTING_HEIGHT - SETTING_BUTTON_HEIGHT) / 2; - wi_rect.bottom = wi_rect.top + SETTING_BUTTON_HEIGHT - 1; - - /* For dropdowns we also have to check the y position thoroughly, the mouse may not above the just opening dropdown */ - if (pt.y >= wi_rect.top && pt.y <= wi_rect.bottom) { - this->valuedropdown_entry = pe; - this->valuedropdown_entry->SetButtons(SEF_LEFT_DEPRESSED); - - DropDownList *list = new DropDownList(); - for (int i = sdb->min; i <= (int)sdb->max; i++) { - *list->Append() = new DropDownListStringItem(sdb->str_val + i - sdb->min, i, false); - } - - ShowDropDownListAt(this, list, value, -1, wi_rect, COLOUR_ORANGE, true); - } - } - this->SetDirty(); - } else if (x < SETTING_BUTTON_WIDTH) { - this->SetDisplayedHelpText(pe); - const SettingDescBase *sdb = &sd->desc; - int32 oldvalue = value; - - switch (sdb->cmd) { - case SDT_BOOLX: value ^= 1; break; - case SDT_ONEOFMANY: - case SDT_NUMX: { - /* Add a dynamic step-size to the scroller. In a maximum of - * 50-steps you should be able to get from min to max, - * unless specified otherwise in the 'interval' variable - * of the current setting. */ - uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval; - if (step == 0) step = 1; - - /* don't allow too fast scrolling */ - if ((this->flags & WF_TIMEOUT) && this->timeout_timer > 1) { - _left_button_clicked = false; - return; - } - - /* Increase or decrease the value and clamp it to extremes */ - if (x >= SETTING_BUTTON_WIDTH / 2) { - value += step; - if (sdb->min < 0) { - assert((int32)sdb->max >= 0); - if (value > (int32)sdb->max) value = (int32)sdb->max; - } else { - if ((uint32)value > sdb->max) value = (int32)sdb->max; - } - if (value < sdb->min) value = sdb->min; // skip between "disabled" and minimum - } else { - value -= step; - if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min; - } - - /* Set up scroller timeout for numeric values */ - if (value != oldvalue) { - if (this->clicked_entry != NULL) { // Release previous buttons if any - this->clicked_entry->SetButtons(0); - } - this->clicked_entry = pe; - this->clicked_entry->SetButtons((x >= SETTING_BUTTON_WIDTH / 2) != (_current_text_dir == TD_RTL) ? SEF_RIGHT_DEPRESSED : SEF_LEFT_DEPRESSED); - this->SetTimeout(); - _left_button_clicked = false; - } - break; - } - - default: NOT_REACHED(); - } - - if (value != oldvalue) { - if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { - SetCompanySetting(pe->d.entry.index, value); - } else { - SetSettingValue(pe->d.entry.index, value); - } - this->SetDirty(); - } - } else { - /* Only open editbox if clicked for the second time, and only for types where it is sensible for. */ - if (this->last_clicked == pe && sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) { - /* Show the correct currency-translated value */ - if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate; - - this->valuewindow_entry = pe; - SetDParam(0, value); - ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 10, this, CS_NUMERAL, QSF_ENABLE_DEFAULT); - } - this->SetDisplayedHelpText(pe); - } - } - - virtual void OnTimeout() - { - if (this->clicked_entry != NULL) { // On timeout, release any depressed buttons - this->clicked_entry->SetButtons(0); - this->clicked_entry = NULL; - this->SetDirty(); - } - } - - virtual void OnQueryTextFinished(char *str) - { - /* The user pressed cancel */ - if (str == NULL) return; - - assert(this->valuewindow_entry != NULL); - assert((this->valuewindow_entry->flags & SEF_KIND_MASK) == SEF_SETTING_KIND); - const SettingDesc *sd = this->valuewindow_entry->d.entry.setting; - - int32 value; - if (!StrEmpty(str)) { - value = atoi(str); - - /* Save the correct currency-translated value */ - if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate; - } else { - value = (int32)(size_t)sd->desc.def; - } - - if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { - SetCompanySetting(this->valuewindow_entry->d.entry.index, value); - } else { - SetSettingValue(this->valuewindow_entry->d.entry.index, value); - } - this->SetDirty(); - } - - virtual void OnDropdownSelect(int widget, int index) - { - switch (widget) { - case WID_GS_RESTRICT_DROPDOWN: - this->filter.mode = (RestrictionMode)index; - if (this->filter.mode == RM_CHANGED_AGAINST_DEFAULT || - this->filter.mode == RM_CHANGED_AGAINST_NEW) { - - if (!this->manually_changed_folding) { - /* Expand all when selecting 'changes'. Update the filter state first, in case it becomes less restrictive in some cases. */ - _settings_main_page.UpdateFilterState(this->filter, false); - _settings_main_page.UnFoldAll(); - } - } else { - /* Non-'changes' filter. Save as default. */ - _settings_client.gui.settings_restriction_mode = this->filter.mode; - } - this->InvalidateData(); - break; - - case WID_GS_TYPE_DROPDOWN: - this->filter.type = (SettingType)index; - this->InvalidateData(); - break; - - default: - if (widget < 0) { - /* Deal with drop down boxes on the panel. */ - assert(this->valuedropdown_entry != NULL); - const SettingDesc *sd = this->valuedropdown_entry->d.entry.setting; - assert(sd->desc.flags & SGF_MULTISTRING); - - if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { - SetCompanySetting(this->valuedropdown_entry->d.entry.index, index); - } else { - SetSettingValue(this->valuedropdown_entry->d.entry.index, index); - } - - this->SetDirty(); - } - break; - } - } - - virtual void OnDropdownClose(Point pt, int widget, int index, bool instant_close) - { - if (widget >= 0) { - /* Normally the default implementation of OnDropdownClose() takes care of - * a few things. We want that behaviour here too, but only for - * "normal" dropdown boxes. The special dropdown boxes added for every - * setting that needs one can't have this call. */ - Window::OnDropdownClose(pt, widget, index, instant_close); - } else { - /* We cannot raise the dropdown button just yet. OnClick needs some hint, whether - * the same dropdown button was clicked again, and then not open the dropdown again. - * So, we only remember that it was closed, and process it on the next OnPaint, which is - * after OnClick. */ - assert(this->valuedropdown_entry != NULL); - this->closing_dropdown = true; - this->SetDirty(); - } - } - - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - - /* Update which settings are to be visible. */ - RestrictionMode min_level = (this->filter.mode <= RM_ALL) ? this->filter.mode : RM_BASIC; - this->filter.min_cat = min_level; - this->filter.type_hides = false; - _settings_main_page.UpdateFilterState(this->filter, false); - - if (this->filter.string.IsEmpty()) { - this->warn_missing = WHR_NONE; - } else if (min_level < this->filter.min_cat) { - this->warn_missing = this->filter.type_hides ? WHR_CATEGORY_TYPE : WHR_CATEGORY; - } else { - this->warn_missing = this->filter.type_hides ? WHR_TYPE : WHR_NONE; - } - this->vscroll->SetCount(_settings_main_page.Length() + this->warn_lines); - - if (this->last_clicked != NULL && !_settings_main_page.IsVisible(this->last_clicked)) { - this->SetDisplayedHelpText(NULL); - } - - bool all_folded = true; - bool all_unfolded = true; - _settings_main_page.GetFoldingState(all_folded, all_unfolded); - this->SetWidgetDisabledState(WID_GS_EXPAND_ALL, all_unfolded); - this->SetWidgetDisabledState(WID_GS_COLLAPSE_ALL, all_folded); - } - - virtual void OnEditboxChanged(int wid) - { - if (wid == WID_GS_FILTER) { - this->filter.string.SetFilterTerm(this->filter_editbox.text.buf); - if (!this->filter.string.IsEmpty() && !this->manually_changed_folding) { - /* User never expanded/collapsed single pages and entered a filter term. - * Expand everything, to save weird expand clicks, */ - _settings_main_page.UnFoldAll(); - } - this->InvalidateData(); - } - } - - virtual void OnResize() - { - this->vscroll->SetCapacityFromWidget(this, WID_GS_OPTIONSPANEL, SETTINGTREE_TOP_OFFSET + SETTINGTREE_BOTTOM_OFFSET); - } -}; - -GameSettings *GameSettingsWindow::settings_ptr = NULL; - -static const NWidgetPart _nested_settings_selection_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), - NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_CONFIG_SETTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_MAUVE), - NWidget(NWID_VERTICAL), SetPIP(0, WD_PAR_VSEP_NORMAL, 0), SetPadding(WD_TEXTPANEL_TOP, 0, WD_TEXTPANEL_BOTTOM, 0), - NWidget(NWID_HORIZONTAL), SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_RIGHT), - NWidget(WWT_TEXT, COLOUR_MAUVE, WID_GS_RESTRICT_CATEGORY), SetDataTip(STR_CONFIG_SETTING_RESTRICT_CATEGORY, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_MAUVE, WID_GS_RESTRICT_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_BLACK_STRING, STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT), SetFill(1, 0), SetResize(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_RIGHT), - NWidget(WWT_TEXT, COLOUR_MAUVE, WID_GS_RESTRICT_TYPE), SetDataTip(STR_CONFIG_SETTING_RESTRICT_TYPE, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_MAUVE, WID_GS_TYPE_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_BLACK_STRING, STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT), SetFill(1, 0), SetResize(1, 0), - EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPadding(0, 0, WD_TEXTPANEL_BOTTOM, 0), - SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_RIGHT), - NWidget(WWT_TEXT, COLOUR_MAUVE), SetFill(0, 1), SetDataTip(STR_CONFIG_SETTING_FILTER_TITLE, STR_NULL), - NWidget(WWT_EDITBOX, COLOUR_MAUVE, WID_GS_FILTER), SetFill(1, 0), SetMinimalSize(50, 12), SetResize(1, 0), - SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), - EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_MAUVE, WID_GS_OPTIONSPANEL), SetMinimalSize(400, 174), SetScrollbar(WID_GS_SCROLLBAR), EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_GS_SCROLLBAR), - EndContainer(), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_MAUVE), SetMinimalSize(400, 40), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GS_HELP_TEXT), SetMinimalSize(300, 25), SetFill(1, 1), SetResize(1, 0), - SetPadding(WD_FRAMETEXT_TOP, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_BOTTOM, WD_FRAMETEXT_LEFT), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_MAUVE), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_GS_EXPAND_ALL), SetDataTip(STR_CONFIG_SETTING_EXPAND_ALL, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_GS_COLLAPSE_ALL), SetDataTip(STR_CONFIG_SETTING_COLLAPSE_ALL, STR_NULL), - NWidget(NWID_SPACER, INVALID_COLOUR), SetFill(1, 1), SetResize(1, 0), - EndContainer(), - EndContainer(), - NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), - EndContainer(), - EndContainer(), -}; - -static WindowDesc _settings_selection_desc( - WDP_CENTER, "settings", 510, 450, - WC_GAME_OPTIONS, WC_NONE, - 0, - _nested_settings_selection_widgets, lengthof(_nested_settings_selection_widgets) -); - -/** Open advanced settings window. */ -void ShowGameSettings() -{ - DeleteWindowByClass(WC_GAME_OPTIONS); - new GameSettingsWindow(&_settings_selection_desc); -} - - -/** - * Draw [<][>] boxes. - * @param x the x position to draw - * @param y the y position to draw - * @param button_colour the colour of the button - * @param state 0 = none clicked, 1 = first clicked, 2 = second clicked - * @param clickable_left is the left button clickable? - * @param clickable_right is the right button clickable? - */ -void DrawArrowButtons(int x, int y, Colours button_colour, byte state, bool clickable_left, bool clickable_right) -{ - int colour = _colour_gradient[button_colour][2]; - - DrawFrameRect(x, y, x + SETTING_BUTTON_WIDTH / 2 - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, (state == 1) ? FR_LOWERED : FR_NONE); - DrawFrameRect(x + SETTING_BUTTON_WIDTH / 2, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, (state == 2) ? FR_LOWERED : FR_NONE); - DrawSprite(SPR_ARROW_LEFT, PAL_NONE, x + WD_IMGBTN_LEFT, y + WD_IMGBTN_TOP); - DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, x + WD_IMGBTN_LEFT + SETTING_BUTTON_WIDTH / 2, y + WD_IMGBTN_TOP); - - /* Grey out the buttons that aren't clickable */ - bool rtl = _current_text_dir == TD_RTL; - if (rtl ? !clickable_right : !clickable_left) { - GfxFillRect(x + 1, y, x + SETTING_BUTTON_WIDTH / 2 - 1, y + SETTING_BUTTON_HEIGHT - 2, colour, FILLRECT_CHECKER); - } - if (rtl ? !clickable_left : !clickable_right) { - GfxFillRect(x + SETTING_BUTTON_WIDTH / 2 + 1, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 2, colour, FILLRECT_CHECKER); - } -} - -/** - * Draw a dropdown button. - * @param x the x position to draw - * @param y the y position to draw - * @param button_colour the colour of the button - * @param state true = lowered - * @param clickable is the button clickable? - */ -void DrawDropDownButton(int x, int y, Colours button_colour, bool state, bool clickable) -{ - static const char *DOWNARROW = "\xEE\x8A\xAA"; - - int colour = _colour_gradient[button_colour][2]; - - DrawFrameRect(x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, state ? FR_LOWERED : FR_NONE); - DrawString(x + (state ? 1 : 0), x + SETTING_BUTTON_WIDTH - (state ? 0 : 1), y + (state ? 2 : 1), DOWNARROW, TC_BLACK, SA_HOR_CENTER); - - if (!clickable) { - GfxFillRect(x + 1, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 2, colour, FILLRECT_CHECKER); - } -} - -/** - * Draw a toggle button. - * @param x the x position to draw - * @param y the y position to draw - * @param state true = lowered - * @param clickable is the button clickable? - */ -void DrawBoolButton(int x, int y, bool state, bool clickable) -{ - static const Colours _bool_ctabs[2][2] = {{COLOUR_CREAM, COLOUR_RED}, {COLOUR_DARK_GREEN, COLOUR_GREEN}}; - DrawFrameRect(x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1, _bool_ctabs[state][clickable], state ? FR_LOWERED : FR_NONE); -} - -struct CustomCurrencyWindow : Window { - int query_widget; - - CustomCurrencyWindow(WindowDesc *desc) : Window(desc) - { - this->InitNested(); - - SetButtonState(); - } - - void SetButtonState() - { - this->SetWidgetDisabledState(WID_CC_RATE_DOWN, _custom_currency.rate == 1); - this->SetWidgetDisabledState(WID_CC_RATE_UP, _custom_currency.rate == UINT16_MAX); - this->SetWidgetDisabledState(WID_CC_YEAR_DOWN, _custom_currency.to_euro == CF_NOEURO); - this->SetWidgetDisabledState(WID_CC_YEAR_UP, _custom_currency.to_euro == MAX_YEAR); - } - - virtual void SetStringParameters(int widget) const - { - switch (widget) { - case WID_CC_RATE: SetDParam(0, 1); SetDParam(1, 1); break; - case WID_CC_SEPARATOR: SetDParamStr(0, _custom_currency.separator); break; - case WID_CC_PREFIX: SetDParamStr(0, _custom_currency.prefix); break; - case WID_CC_SUFFIX: SetDParamStr(0, _custom_currency.suffix); break; - case WID_CC_YEAR: - SetDParam(0, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER); - SetDParam(1, _custom_currency.to_euro); - break; - - case WID_CC_PREVIEW: - SetDParam(0, 10000); - break; - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - /* Set the appropriate width for the edit 'buttons' */ - case WID_CC_SEPARATOR_EDIT: - case WID_CC_PREFIX_EDIT: - case WID_CC_SUFFIX_EDIT: - size->width = this->GetWidget(WID_CC_RATE_DOWN)->smallest_x + this->GetWidget(WID_CC_RATE_UP)->smallest_x; - break; - - /* Make sure the window is wide enough for the widest exchange rate */ - case WID_CC_RATE: - SetDParam(0, 1); - SetDParam(1, INT32_MAX); - *size = GetStringBoundingBox(STR_CURRENCY_EXCHANGE_RATE); - break; - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - int line = 0; - int len = 0; - StringID str = 0; - CharSetFilter afilter = CS_ALPHANUMERAL; - - switch (widget) { - case WID_CC_RATE_DOWN: - if (_custom_currency.rate > 1) _custom_currency.rate--; - if (_custom_currency.rate == 1) this->DisableWidget(WID_CC_RATE_DOWN); - this->EnableWidget(WID_CC_RATE_UP); - break; - - case WID_CC_RATE_UP: - if (_custom_currency.rate < UINT16_MAX) _custom_currency.rate++; - if (_custom_currency.rate == UINT16_MAX) this->DisableWidget(WID_CC_RATE_UP); - this->EnableWidget(WID_CC_RATE_DOWN); - break; - - case WID_CC_RATE: - SetDParam(0, _custom_currency.rate); - str = STR_JUST_INT; - len = 5; - line = WID_CC_RATE; - afilter = CS_NUMERAL; - break; - - case WID_CC_SEPARATOR_EDIT: - case WID_CC_SEPARATOR: - SetDParamStr(0, _custom_currency.separator); - str = STR_JUST_RAW_STRING; - len = 1; - line = WID_CC_SEPARATOR; - break; - - case WID_CC_PREFIX_EDIT: - case WID_CC_PREFIX: - SetDParamStr(0, _custom_currency.prefix); - str = STR_JUST_RAW_STRING; - len = 12; - line = WID_CC_PREFIX; - break; - - case WID_CC_SUFFIX_EDIT: - case WID_CC_SUFFIX: - SetDParamStr(0, _custom_currency.suffix); - str = STR_JUST_RAW_STRING; - len = 12; - line = WID_CC_SUFFIX; - break; - - case WID_CC_YEAR_DOWN: - _custom_currency.to_euro = (_custom_currency.to_euro <= 2000) ? CF_NOEURO : _custom_currency.to_euro - 1; - if (_custom_currency.to_euro == CF_NOEURO) this->DisableWidget(WID_CC_YEAR_DOWN); - this->EnableWidget(WID_CC_YEAR_UP); - break; - - case WID_CC_YEAR_UP: - _custom_currency.to_euro = Clamp(_custom_currency.to_euro + 1, 2000, MAX_YEAR); - if (_custom_currency.to_euro == MAX_YEAR) this->DisableWidget(WID_CC_YEAR_UP); - this->EnableWidget(WID_CC_YEAR_DOWN); - break; - - case WID_CC_YEAR: - SetDParam(0, _custom_currency.to_euro); - str = STR_JUST_INT; - len = 7; - line = WID_CC_YEAR; - afilter = CS_NUMERAL; - break; - } - - if (len != 0) { - this->query_widget = line; - ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, this, afilter, QSF_NONE); - } - - this->SetTimeout(); - this->SetDirty(); - } - - virtual void OnQueryTextFinished(char *str) - { - if (str == NULL) return; - - switch (this->query_widget) { - case WID_CC_RATE: - _custom_currency.rate = Clamp(atoi(str), 1, UINT16_MAX); - break; - - case WID_CC_SEPARATOR: // Thousands separator - strecpy(_custom_currency.separator, str, lastof(_custom_currency.separator)); - break; - - case WID_CC_PREFIX: - strecpy(_custom_currency.prefix, str, lastof(_custom_currency.prefix)); - break; - - case WID_CC_SUFFIX: - strecpy(_custom_currency.suffix, str, lastof(_custom_currency.suffix)); - break; - - case WID_CC_YEAR: { // Year to switch to euro - int val = atoi(str); - - _custom_currency.to_euro = (val < 2000 ? CF_NOEURO : min(val, MAX_YEAR)); - break; - } - } - MarkWholeScreenDirty(); - SetButtonState(); - } - - virtual void OnTimeout() - { - this->SetDirty(); - } -}; - -static const NWidgetPart _nested_cust_currency_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CURRENCY_WINDOW, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY), - NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(7, 3, 0), - NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), - NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_RATE_DOWN), SetDataTip(AWV_DECREASE, STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_RATE_UP), SetDataTip(AWV_INCREASE, STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP), - NWidget(NWID_SPACER), SetMinimalSize(5, 0), - NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_RATE), SetDataTip(STR_CURRENCY_EXCHANGE_RATE, STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP), SetFill(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), - NWidget(WWT_PUSHBTN, COLOUR_DARK_BLUE, WID_CC_SEPARATOR_EDIT), SetDataTip(0x0, STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP), SetFill(0, 1), - NWidget(NWID_SPACER), SetMinimalSize(5, 0), - NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_SEPARATOR), SetDataTip(STR_CURRENCY_SEPARATOR, STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP), SetFill(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), - NWidget(WWT_PUSHBTN, COLOUR_DARK_BLUE, WID_CC_PREFIX_EDIT), SetDataTip(0x0, STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP), SetFill(0, 1), - NWidget(NWID_SPACER), SetMinimalSize(5, 0), - NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_PREFIX), SetDataTip(STR_CURRENCY_PREFIX, STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP), SetFill(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), - NWidget(WWT_PUSHBTN, COLOUR_DARK_BLUE, WID_CC_SUFFIX_EDIT), SetDataTip(0x0, STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP), SetFill(0, 1), - NWidget(NWID_SPACER), SetMinimalSize(5, 0), - NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_SUFFIX), SetDataTip(STR_CURRENCY_SUFFIX, STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP), SetFill(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), - NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_YEAR_DOWN), SetDataTip(AWV_DECREASE, STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_YEAR_UP), SetDataTip(AWV_INCREASE, STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP), - NWidget(NWID_SPACER), SetMinimalSize(5, 0), - NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_YEAR), SetDataTip(STR_JUST_STRING, STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP), SetFill(1, 0), - EndContainer(), - EndContainer(), - NWidget(WWT_LABEL, COLOUR_BLUE, WID_CC_PREVIEW), - SetDataTip(STR_CURRENCY_PREVIEW, STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP), SetPadding(15, 1, 18, 2), - EndContainer(), -}; - -static WindowDesc _cust_currency_desc( - WDP_CENTER, NULL, 0, 0, - WC_CUSTOM_CURRENCY, WC_NONE, - 0, - _nested_cust_currency_widgets, lengthof(_nested_cust_currency_widgets) -); - -/** Open custom currency window. */ -static void ShowCustCurrency() -{ - DeleteWindowById(WC_CUSTOM_CURRENCY, 0); - new CustomCurrencyWindow(&_cust_currency_desc); -} diff --git a/src/smallmap_gui.cpp.orig b/src/smallmap_gui.cpp.orig deleted file mode 100644 index b4137038fc..0000000000 --- a/src/smallmap_gui.cpp.orig +++ /dev/null @@ -1,1827 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file smallmap_gui.cpp GUI that shows a small map of the world with metadata like owner or height. */ - -#include "stdafx.h" -#include "clear_map.h" -#include "industry.h" -#include "station_map.h" -#include "landscape.h" -#include "tree_map.h" -#include "viewport_func.h" -#include "town.h" -#include "tunnelbridge_map.h" -#include "core/endian_func.hpp" -#include "vehicle_base.h" -#include "sound_func.h" -#include "window_func.h" -#include "company_base.h" - -#include "smallmap_gui.h" - -#include "table/strings.h" - -static int _smallmap_industry_count; ///< Number of used industries -static int _smallmap_company_count; ///< Number of entries in the owner legend. -static int _smallmap_cargo_count; ///< Number of cargos in the link stats legend. - -/** Link stat colours shown in legenda. */ -static uint8 _linkstat_colours_in_legenda[] = {0, 1, 3, 5, 7, 9, 11}; - -static const int NUM_NO_COMPANY_ENTRIES = 4; ///< Number of entries in the owner legend that are not companies. - -static const uint8 PC_ROUGH_LAND = 0x52; ///< Dark green palette colour for rough land. -static const uint8 PC_GRASS_LAND = 0x54; ///< Dark green palette colour for grass land. -static const uint8 PC_BARE_LAND = 0x37; ///< Brown palette colour for bare land. -static const uint8 PC_FIELDS = 0x25; ///< Light brown palette colour for fields. -static const uint8 PC_TREES = 0x57; ///< Green palette colour for trees. -static const uint8 PC_WATER = 0xCA; ///< Dark blue palette colour for water. - -/** Macro for ordinary entry of LegendAndColour */ -#define MK(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false} - -/** Macro for a height legend entry with configurable colour. */ -#define MC(height) {0, STR_TINY_BLACK_HEIGHT, INVALID_INDUSTRYTYPE, height, INVALID_COMPANY, true, false, false} - -/** Macro for non-company owned property entry of LegendAndColour */ -#define MO(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false} - -/** Macro used for forcing a rebuild of the owner legend the first time it is used. */ -#define MOEND() {0, 0, INVALID_INDUSTRYTYPE, 0, OWNER_NONE, true, true, false} - -/** Macro for end of list marker in arrays of LegendAndColour */ -#define MKEND() {0, STR_NULL, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, true, false} - -/** - * Macro for break marker in arrays of LegendAndColour. - * It will have valid data, though - */ -#define MS(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, true} - -/** Legend text giving the colours to look for on the minimap */ -static LegendAndColour _legend_land_contours[] = { - /* The colours for the following values are set at BuildLandLegend() based on each colour scheme. */ - MC(0), - MC(4), - MC(8), - MC(12), - MC(14), - - MS(PC_BLACK, STR_SMALLMAP_LEGENDA_ROADS), - MK(PC_GREY, STR_SMALLMAP_LEGENDA_RAILROADS), - MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS), - MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES), - MK(PC_WHITE, STR_SMALLMAP_LEGENDA_VEHICLES), - MKEND() -}; - -static const LegendAndColour _legend_vehicles[] = { - MK(PC_RED, STR_SMALLMAP_LEGENDA_TRAINS), - MK(PC_YELLOW, STR_SMALLMAP_LEGENDA_ROAD_VEHICLES), - MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_SHIPS), - MK(PC_WHITE, STR_SMALLMAP_LEGENDA_AIRCRAFT), - - MS(PC_BLACK, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES), - MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES), - MKEND() -}; - -static const LegendAndColour _legend_routes[] = { - MK(PC_BLACK, STR_SMALLMAP_LEGENDA_ROADS), - MK(PC_GREY, STR_SMALLMAP_LEGENDA_RAILROADS), - MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES), - - MS(PC_VERY_DARK_BROWN, STR_SMALLMAP_LEGENDA_RAILROAD_STATION), - MK(PC_ORANGE, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY), - MK(PC_YELLOW, STR_SMALLMAP_LEGENDA_BUS_STATION), - MK(PC_RED, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT), - MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_DOCK), - MKEND() -}; - -static const LegendAndColour _legend_vegetation[] = { - MK(PC_ROUGH_LAND, STR_SMALLMAP_LEGENDA_ROUGH_LAND), - MK(PC_GRASS_LAND, STR_SMALLMAP_LEGENDA_GRASS_LAND), - MK(PC_BARE_LAND, STR_SMALLMAP_LEGENDA_BARE_LAND), - MK(PC_FIELDS, STR_SMALLMAP_LEGENDA_FIELDS), - MK(PC_TREES, STR_SMALLMAP_LEGENDA_TREES), - MK(PC_GREEN, STR_SMALLMAP_LEGENDA_FOREST), - - MS(PC_GREY, STR_SMALLMAP_LEGENDA_ROCKS), - MK(PC_ORANGE, STR_SMALLMAP_LEGENDA_DESERT), - MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_SNOW), - MK(PC_BLACK, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES), - MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES), - MKEND() -}; - -static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = { - MO(PC_WATER, STR_SMALLMAP_LEGENDA_WATER), - MO(0x00, STR_SMALLMAP_LEGENDA_NO_OWNER), // This colour will vary depending on settings. - MO(PC_DARK_RED, STR_SMALLMAP_LEGENDA_TOWNS), - MO(PC_DARK_GREY, STR_SMALLMAP_LEGENDA_INDUSTRIES), - /* The legend will be terminated the first time it is used. */ - MOEND(), -}; - -#undef MK -#undef MC -#undef MS -#undef MO -#undef MOEND -#undef MKEND - -/** Legend entries for the link stats view. */ -static LegendAndColour _legend_linkstats[NUM_CARGO + lengthof(_linkstat_colours_in_legenda) + 1]; -/** - * Allow room for all industries, plus a terminator entry - * This is required in order to have the industry slots all filled up - */ -static LegendAndColour _legend_from_industries[NUM_INDUSTRYTYPES + 1]; -/** For connecting industry type to position in industries list(small map legend) */ -static uint _industry_to_list_pos[NUM_INDUSTRYTYPES]; -/** Show heightmap in industry and owner mode of smallmap window. */ -static bool _smallmap_show_heightmap = false; -/** Highlight a specific industry type */ -static IndustryType _smallmap_industry_highlight = INVALID_INDUSTRYTYPE; -/** State of highlight blinking */ -static bool _smallmap_industry_highlight_state; -/** For connecting company ID to position in owner list (small map legend) */ -static uint _company_to_list_pos[MAX_COMPANIES]; - -/** - * Fills an array for the industries legends. - */ -void BuildIndustriesLegend() -{ - uint j = 0; - - /* Add each name */ - for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) { - IndustryType ind = _sorted_industry_types[i]; - const IndustrySpec *indsp = GetIndustrySpec(ind); - if (indsp->enabled) { - _legend_from_industries[j].legend = indsp->name; - _legend_from_industries[j].colour = indsp->map_colour; - _legend_from_industries[j].type = ind; - _legend_from_industries[j].show_on_map = true; - _legend_from_industries[j].col_break = false; - _legend_from_industries[j].end = false; - - /* Store widget number for this industry type. */ - _industry_to_list_pos[ind] = j; - j++; - } - } - /* Terminate the list */ - _legend_from_industries[j].end = true; - - /* Store number of enabled industries */ - _smallmap_industry_count = j; -} - -/** - * Populate legend table for the link stat view. - */ -void BuildLinkStatsLegend() -{ - /* Clear the legend */ - memset(_legend_linkstats, 0, sizeof(_legend_linkstats)); - - uint i = 0; - for (; i < _sorted_cargo_specs_size; ++i) { - const CargoSpec *cs = _sorted_cargo_specs[i]; - - _legend_linkstats[i].legend = cs->name; - _legend_linkstats[i].colour = cs->legend_colour; - _legend_linkstats[i].type = cs->Index(); - _legend_linkstats[i].show_on_map = true; - } - - _legend_linkstats[i].col_break = true; - _smallmap_cargo_count = i; - - for (; i < _smallmap_cargo_count + lengthof(_linkstat_colours_in_legenda); ++i) { - _legend_linkstats[i].legend = STR_EMPTY; - _legend_linkstats[i].colour = LinkGraphOverlay::LINK_COLOURS[_linkstat_colours_in_legenda[i - _smallmap_cargo_count]]; - _legend_linkstats[i].show_on_map = true; - } - - _legend_linkstats[_smallmap_cargo_count].legend = STR_LINKGRAPH_LEGEND_UNUSED; - _legend_linkstats[i - 1].legend = STR_LINKGRAPH_LEGEND_OVERLOADED; - _legend_linkstats[(_smallmap_cargo_count + i - 1) / 2].legend = STR_LINKGRAPH_LEGEND_SATURATED; - _legend_linkstats[i].end = true; -} - -static const LegendAndColour * const _legend_table[] = { - _legend_land_contours, - _legend_vehicles, - _legend_from_industries, - _legend_linkstats, - _legend_routes, - _legend_vegetation, - _legend_land_owners, -}; - -#define MKCOLOUR(x) TO_LE32X(x) - -#define MKCOLOUR_XXXX(x) (MKCOLOUR(0x01010101) * (uint)(x)) -#define MKCOLOUR_X0X0(x) (MKCOLOUR(0x01000100) * (uint)(x)) -#define MKCOLOUR_0X0X(x) (MKCOLOUR(0x00010001) * (uint)(x)) -#define MKCOLOUR_0XX0(x) (MKCOLOUR(0x00010100) * (uint)(x)) -#define MKCOLOUR_X00X(x) (MKCOLOUR(0x01000001) * (uint)(x)) - -#define MKCOLOUR_XYXY(x, y) (MKCOLOUR_X0X0(x) | MKCOLOUR_0X0X(y)) -#define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y)) - -#define MKCOLOUR_0000 MKCOLOUR_XXXX(0x00) -#define MKCOLOUR_0FF0 MKCOLOUR_0XX0(0xFF) -#define MKCOLOUR_F00F MKCOLOUR_X00X(0xFF) -#define MKCOLOUR_FFFF MKCOLOUR_XXXX(0xFF) - -/** Height map colours for the green colour scheme, ordered by height. */ -static const uint32 _green_map_heights[] = { - MKCOLOUR_XXXX(0x5A), - MKCOLOUR_XYXY(0x5A, 0x5B), - MKCOLOUR_XXXX(0x5B), - MKCOLOUR_XYXY(0x5B, 0x5C), - MKCOLOUR_XXXX(0x5C), - MKCOLOUR_XYXY(0x5C, 0x5D), - MKCOLOUR_XXXX(0x5D), - MKCOLOUR_XYXY(0x5D, 0x5E), - MKCOLOUR_XXXX(0x5E), - MKCOLOUR_XYXY(0x5E, 0x5F), - MKCOLOUR_XXXX(0x5F), - MKCOLOUR_XYXY(0x5F, 0x1F), - MKCOLOUR_XXXX(0x1F), - MKCOLOUR_XYXY(0x1F, 0x27), - MKCOLOUR_XXXX(0x27), - MKCOLOUR_XXXX(0x27), -}; -assert_compile(lengthof(_green_map_heights) == MAX_TILE_HEIGHT + 1); - -/** Height map colours for the dark green colour scheme, ordered by height. */ -static const uint32 _dark_green_map_heights[] = { - MKCOLOUR_XXXX(0x60), - MKCOLOUR_XYXY(0x60, 0x61), - MKCOLOUR_XXXX(0x61), - MKCOLOUR_XYXY(0x61, 0x62), - MKCOLOUR_XXXX(0x62), - MKCOLOUR_XYXY(0x62, 0x63), - MKCOLOUR_XXXX(0x63), - MKCOLOUR_XYXY(0x63, 0x64), - MKCOLOUR_XXXX(0x64), - MKCOLOUR_XYXY(0x64, 0x65), - MKCOLOUR_XXXX(0x65), - MKCOLOUR_XYXY(0x65, 0x66), - MKCOLOUR_XXXX(0x66), - MKCOLOUR_XYXY(0x66, 0x67), - MKCOLOUR_XXXX(0x67), - MKCOLOUR_XXXX(0x67), -}; -assert_compile(lengthof(_dark_green_map_heights) == MAX_TILE_HEIGHT + 1); - -/** Height map colours for the violet colour scheme, ordered by height. */ -static const uint32 _violet_map_heights[] = { - MKCOLOUR_XXXX(0x80), - MKCOLOUR_XYXY(0x80, 0x81), - MKCOLOUR_XXXX(0x81), - MKCOLOUR_XYXY(0x81, 0x82), - MKCOLOUR_XXXX(0x82), - MKCOLOUR_XYXY(0x82, 0x83), - MKCOLOUR_XXXX(0x83), - MKCOLOUR_XYXY(0x83, 0x84), - MKCOLOUR_XXXX(0x84), - MKCOLOUR_XYXY(0x84, 0x85), - MKCOLOUR_XXXX(0x85), - MKCOLOUR_XYXY(0x85, 0x86), - MKCOLOUR_XXXX(0x86), - MKCOLOUR_XYXY(0x86, 0x87), - MKCOLOUR_XXXX(0x87), - MKCOLOUR_XXXX(0x87), -}; -assert_compile(lengthof(_violet_map_heights) == MAX_TILE_HEIGHT + 1); - -/** Colour scheme of the smallmap. */ -struct SmallMapColourScheme { - const uint32 *height_colours; ///< Colour of each level in a heightmap. - uint32 default_colour; ///< Default colour of the land. -}; - -/** Available colour schemes for height maps. */ -static const SmallMapColourScheme _heightmap_schemes[] = { - {_green_map_heights, MKCOLOUR_XXXX(0x54)}, ///< Green colour scheme. - {_dark_green_map_heights, MKCOLOUR_XXXX(0x62)}, ///< Dark green colour scheme. - {_violet_map_heights, MKCOLOUR_XXXX(0x82)}, ///< Violet colour scheme. -}; - -/** - * (Re)build the colour tables for the legends. - */ -void BuildLandLegend() -{ - for (LegendAndColour *lc = _legend_land_contours; lc->legend == STR_TINY_BLACK_HEIGHT; lc++) { - lc->colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[lc->height]; - } -} - -/** - * Completes the array for the owned property legend. - */ -void BuildOwnerLegend() -{ - _legend_land_owners[1].colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour; - - int i = NUM_NO_COMPANY_ENTRIES; - const Company *c; - FOR_ALL_COMPANIES(c) { - _legend_land_owners[i].colour = _colour_gradient[c->colour][5]; - _legend_land_owners[i].company = c->index; - _legend_land_owners[i].show_on_map = true; - _legend_land_owners[i].col_break = false; - _legend_land_owners[i].end = false; - _company_to_list_pos[c->index] = i; - i++; - } - - /* Terminate the list */ - _legend_land_owners[i].end = true; - - /* Store maximum amount of owner legend entries. */ - _smallmap_company_count = i; -} - -struct AndOr { - uint32 mor; - uint32 mand; -}; - -static inline uint32 ApplyMask(uint32 colour, const AndOr *mask) -{ - return (colour & mask->mand) | mask->mor; -} - - -/** Colour masks for "Contour" and "Routes" modes. */ -static const AndOr _smallmap_contours_andor[] = { - {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_CLEAR - {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F}, // MP_RAILWAY - {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_ROAD - {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_HOUSE - {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TREES - {MKCOLOUR_XXXX(PC_LIGHT_BLUE), MKCOLOUR_0000}, // MP_STATION - {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000}, // MP_WATER - {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_VOID - {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000}, // MP_INDUSTRY - {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE - {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_OBJECT - {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F}, -}; - -/** Colour masks for "Vehicles", "Industry", and "Vegetation" modes. */ -static const AndOr _smallmap_vehicles_andor[] = { - {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_CLEAR - {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_RAILWAY - {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_ROAD - {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_HOUSE - {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TREES - {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_STATION - {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000}, // MP_WATER - {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_VOID - {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000}, // MP_INDUSTRY - {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE - {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_OBJECT - {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, -}; - -/** Mapping of tile type to importance of the tile (higher number means more interesting to show). */ -static const byte _tiletype_importance[] = { - 2, // MP_CLEAR - 8, // MP_RAILWAY - 7, // MP_ROAD - 5, // MP_HOUSE - 2, // MP_TREES - 9, // MP_STATION - 2, // MP_WATER - 1, // MP_VOID - 6, // MP_INDUSTRY - 8, // MP_TUNNELBRIDGE - 2, // MP_OBJECT - 0, -}; - - -static inline TileType GetEffectiveTileType(TileIndex tile) -{ - TileType t = GetTileType(tile); - - if (t == MP_TUNNELBRIDGE) { - TransportType tt = GetTunnelBridgeTransportType(tile); - - switch (tt) { - case TRANSPORT_RAIL: t = MP_RAILWAY; break; - case TRANSPORT_ROAD: t = MP_ROAD; break; - default: t = MP_WATER; break; - } - } - return t; -} - -/** - * Return the colour a tile would be displayed with in the small map in mode "Contour". - * @param tile The tile of which we would like to get the colour. - * @param t Effective tile type of the tile (see #GetEffectiveTileType). - * @return The colour of tile in the small map in mode "Contour" - */ -static inline uint32 GetSmallMapContoursPixels(TileIndex tile, TileType t) -{ - const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(cs->height_colours[TileHeight(tile)], &_smallmap_contours_andor[t]); -} - -/** - * Return the colour a tile would be displayed with in the small map in mode "Vehicles". - * - * @param tile The tile of which we would like to get the colour. - * @param t Effective tile type of the tile (see #GetEffectiveTileType). - * @return The colour of tile in the small map in mode "Vehicles" - */ -static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile, TileType t) -{ - const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(cs->default_colour, &_smallmap_vehicles_andor[t]); -} - -/** - * Return the colour a tile would be displayed with in the small map in mode "Industries". - * - * @param tile The tile of which we would like to get the colour. - * @param t Effective tile type of the tile (see #GetEffectiveTileType). - * @return The colour of tile in the small map in mode "Industries" - */ -static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile, TileType t) -{ - if (t == MP_INDUSTRY) { - /* If industry is allowed to be seen, use its colour on the map */ - IndustryType type = Industry::GetByTile(tile)->type; - if (_legend_from_industries[_industry_to_list_pos[type]].show_on_map && - (_smallmap_industry_highlight_state || type != _smallmap_industry_highlight)) { - return (type == _smallmap_industry_highlight ? PC_WHITE : GetIndustrySpec(Industry::GetByTile(tile)->type)->map_colour) * 0x01010101; - } else { - /* Otherwise, return the colour which will make it disappear */ - t = (IsTileOnWater(tile) ? MP_WATER : MP_CLEAR); - } - } - - const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(_smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour, &_smallmap_vehicles_andor[t]); -} - -/** - * Return the colour a tile would be displayed with in the small map in mode "Routes". - * - * @param tile The tile of which we would like to get the colour. - * @param t Effective tile type of the tile (see #GetEffectiveTileType). - * @return The colour of tile in the small map in mode "Routes" - */ -static inline uint32 GetSmallMapRoutesPixels(TileIndex tile, TileType t) -{ - if (t == MP_STATION) { - switch (GetStationType(tile)) { - case STATION_RAIL: return MKCOLOUR_XXXX(PC_VERY_DARK_BROWN); - case STATION_AIRPORT: return MKCOLOUR_XXXX(PC_RED); - case STATION_TRUCK: return MKCOLOUR_XXXX(PC_ORANGE); - case STATION_BUS: return MKCOLOUR_XXXX(PC_YELLOW); - case STATION_DOCK: return MKCOLOUR_XXXX(PC_LIGHT_BLUE); - default: return MKCOLOUR_FFFF; - } - } else if (t == MP_RAILWAY) { - AndOr andor = { - MKCOLOUR_0XX0(GetRailTypeInfo(GetRailType(tile))->map_colour), - _smallmap_contours_andor[t].mand - }; - - const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(cs->default_colour, &andor); - } - - /* Ground colour */ - const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]); -} - -/** - * Return the colour a tile would be displayed with in the small map in mode "link stats". - * - * @param tile The tile of which we would like to get the colour. - * @param t Effective tile type of the tile (see #GetEffectiveTileType). - * @return The colour of tile in the small map in mode "link stats" - */ -static inline uint32 GetSmallMapLinkStatsPixels(TileIndex tile, TileType t) -{ - return _smallmap_show_heightmap ? GetSmallMapContoursPixels(tile, t) : GetSmallMapRoutesPixels(tile, t); -} - -static const uint32 _vegetation_clear_bits[] = { - MKCOLOUR_XXXX(PC_GRASS_LAND), ///< full grass - MKCOLOUR_XXXX(PC_ROUGH_LAND), ///< rough land - MKCOLOUR_XXXX(PC_GREY), ///< rocks - MKCOLOUR_XXXX(PC_FIELDS), ///< fields - MKCOLOUR_XXXX(PC_LIGHT_BLUE), ///< snow - MKCOLOUR_XXXX(PC_ORANGE), ///< desert - MKCOLOUR_XXXX(PC_GRASS_LAND), ///< unused - MKCOLOUR_XXXX(PC_GRASS_LAND), ///< unused -}; - -/** - * Return the colour a tile would be displayed with in the smallmap in mode "Vegetation". - * - * @param tile The tile of which we would like to get the colour. - * @param t Effective tile type of the tile (see #GetEffectiveTileType). - * @return The colour of tile in the smallmap in mode "Vegetation" - */ -static inline uint32 GetSmallMapVegetationPixels(TileIndex tile, TileType t) -{ - switch (t) { - case MP_CLEAR: - return (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) ? MKCOLOUR_XXXX(PC_BARE_LAND) : _vegetation_clear_bits[GetClearGround(tile)]; - - case MP_INDUSTRY: - return IsTileForestIndustry(tile) ? MKCOLOUR_XXXX(PC_GREEN) : MKCOLOUR_XXXX(PC_DARK_RED); - - case MP_TREES: - if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(tile) == TREE_GROUND_ROUGH_SNOW) { - return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR_XYYX(PC_LIGHT_BLUE, PC_TREES) : MKCOLOUR_XYYX(PC_ORANGE, PC_TREES); - } - return MKCOLOUR_XYYX(PC_GRASS_LAND, PC_TREES); - - default: - return ApplyMask(MKCOLOUR_XXXX(PC_GRASS_LAND), &_smallmap_vehicles_andor[t]); - } -} - -/** - * Return the colour a tile would be displayed with in the small map in mode "Owner". - * - * @param tile The tile of which we would like to get the colour. - * @param t Effective tile type of the tile (see #GetEffectiveTileType). - * @return The colour of tile in the small map in mode "Owner" - */ -static inline uint32 GetSmallMapOwnerPixels(TileIndex tile, TileType t) -{ - Owner o; - - switch (t) { - case MP_INDUSTRY: return MKCOLOUR_XXXX(PC_DARK_GREY); - case MP_HOUSE: return MKCOLOUR_XXXX(PC_DARK_RED); - default: o = GetTileOwner(tile); break; - /* FIXME: For MP_ROAD there are multiple owners. - * GetTileOwner returns the rail owner (level crossing) resp. the owner of ROADTYPE_ROAD (normal road), - * even if there are no ROADTYPE_ROAD bits on the tile. - */ - } - - if ((o < MAX_COMPANIES && !_legend_land_owners[_company_to_list_pos[o]].show_on_map) || o == OWNER_NONE || o == OWNER_WATER) { - if (t == MP_WATER) return MKCOLOUR_XXXX(PC_WATER); - const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return _smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour; - } else if (o == OWNER_TOWN) { - return MKCOLOUR_XXXX(PC_DARK_RED); - } - - return MKCOLOUR_XXXX(_legend_land_owners[_company_to_list_pos[o]].colour); -} - -/** Vehicle colours in #SMT_VEHICLES mode. Indexed by #VehicleTypeByte. */ -static const byte _vehicle_type_colours[6] = { - PC_RED, PC_YELLOW, PC_LIGHT_BLUE, PC_WHITE, PC_BLACK, PC_RED -}; - - -inline Point SmallMapWindow::SmallmapRemapCoords(int x, int y) const -{ - Point pt; - pt.x = (y - x) * 2; - pt.y = y + x; - return pt; -} - -/** - * Remap tile to location on this smallmap. - * @param tile_x X coordinate of the tile. - * @param tile_y Y coordinate of the tile. - * @return Position to draw on. - */ -inline Point SmallMapWindow::RemapTile(int tile_x, int tile_y) const -{ - int x_offset = tile_x - this->scroll_x / (int)TILE_SIZE; - int y_offset = tile_y - this->scroll_y / (int)TILE_SIZE; - - if (this->zoom == 1) return SmallmapRemapCoords(x_offset, y_offset); - - /* For negative offsets, round towards -inf. */ - if (x_offset < 0) x_offset -= this->zoom - 1; - if (y_offset < 0) y_offset -= this->zoom - 1; - - return SmallmapRemapCoords(x_offset / this->zoom, y_offset / this->zoom); -} - -/** - * Determine the tile relative to the base tile of the smallmap, and the pixel position at - * that tile for a point in the smallmap. - * @param px Horizontal coordinate of the pixel. - * @param py Vertical coordinate of the pixel. - * @param sub[out] Pixel position at the tile (0..3). - * @param add_sub Add current #subscroll to the position. - * @return Tile being displayed at the given position relative to #scroll_x and #scroll_y. - * @note The #subscroll offset is already accounted for. - */ -inline Point SmallMapWindow::PixelToTile(int px, int py, int *sub, bool add_sub) const -{ - if (add_sub) px += this->subscroll; // Total horizontal offset. - - /* For each two rows down, add a x and a y tile, and - * For each four pixels to the right, move a tile to the right. */ - Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom}; - px &= 3; - - if (py & 1) { // Odd number of rows, handle the 2 pixel shift. - if (px < 2) { - pt.x += this->zoom; - px += 2; - } else { - pt.y += this->zoom; - px -= 2; - } - } - - *sub = px; - return pt; -} - -/** - * Compute base parameters of the smallmap such that tile (\a tx, \a ty) starts at pixel (\a x, \a y). - * @param tx Tile x coordinate. - * @param ty Tile y coordinate. - * @param x Non-negative horizontal position in the display where the tile starts. - * @param y Non-negative vertical position in the display where the tile starts. - * @param sub [out] Value of #subscroll needed. - * @return #scroll_x, #scroll_y values. - */ -Point SmallMapWindow::ComputeScroll(int tx, int ty, int x, int y, int *sub) -{ - assert(x >= 0 && y >= 0); - - int new_sub; - Point tile_xy = PixelToTile(x, y, &new_sub, false); - tx -= tile_xy.x; - ty -= tile_xy.y; - - Point scroll; - if (new_sub == 0) { - *sub = 0; - scroll.x = (tx + this->zoom) * TILE_SIZE; - scroll.y = (ty - this->zoom) * TILE_SIZE; - } else { - *sub = 4 - new_sub; - scroll.x = (tx + 2 * this->zoom) * TILE_SIZE; - scroll.y = (ty - 2 * this->zoom) * TILE_SIZE; - } - return scroll; -} - -/** - * Initialize or change the zoom level. - * @param change Way to change the zoom level. - * @param zoom_pt Position to keep fixed while zooming. - * @pre \c *zoom_pt should contain a point in the smallmap display when zooming in or out. - */ -void SmallMapWindow::SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt) -{ - static const int zoomlevels[] = {1, 2, 4, 6, 8}; // Available zoom levels. Bigger number means more zoom-out (further away). - static const int MIN_ZOOM_INDEX = 0; - static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1; - - int new_index, cur_index, sub; - Point tile; - switch (change) { - case ZLC_INITIALIZE: - cur_index = - 1; // Definitely different from new_index. - new_index = MIN_ZOOM_INDEX; - tile.x = tile.y = 0; - break; - - case ZLC_ZOOM_IN: - case ZLC_ZOOM_OUT: - for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) { - if (this->zoom == zoomlevels[cur_index]) break; - } - assert(cur_index <= MAX_ZOOM_INDEX); - - tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub); - new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX); - break; - - default: NOT_REACHED(); - } - - if (new_index != cur_index) { - this->zoom = zoomlevels[new_index]; - if (cur_index >= 0) { - Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub); - this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE, - this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub); - } else if (this->map_type == SMT_LINKSTATS) { - this->overlay->RebuildCache(); - } - this->SetWidgetDisabledState(WID_SM_ZOOM_IN, this->zoom == zoomlevels[MIN_ZOOM_INDEX]); - this->SetWidgetDisabledState(WID_SM_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]); - this->SetDirty(); - } -} - -/** - * Decide which colours to show to the user for a group of tiles. - * @param ta Tile area to investigate. - * @return Colours to display. - */ -inline uint32 SmallMapWindow::GetTileColours(const TileArea &ta) const -{ - int importance = 0; - TileIndex tile = INVALID_TILE; // Position of the most important tile. - TileType et = MP_VOID; // Effective tile type at that position. - - TILE_AREA_LOOP(ti, ta) { - TileType ttype = GetEffectiveTileType(ti); - if (_tiletype_importance[ttype] > importance) { - importance = _tiletype_importance[ttype]; - tile = ti; - et = ttype; - } - } - - switch (this->map_type) { - case SMT_CONTOUR: - return GetSmallMapContoursPixels(tile, et); - - case SMT_VEHICLES: - return GetSmallMapVehiclesPixels(tile, et); - - case SMT_INDUSTRY: - return GetSmallMapIndustriesPixels(tile, et); - - case SMT_LINKSTATS: - return GetSmallMapLinkStatsPixels(tile, et); - - case SMT_ROUTES: - return GetSmallMapRoutesPixels(tile, et); - - case SMT_VEGETATION: - return GetSmallMapVegetationPixels(tile, et); - - case SMT_OWNER: - return GetSmallMapOwnerPixels(tile, et); - - default: NOT_REACHED(); - } -} - -/** - * Draws one column of tiles of the small map in a certain mode onto the screen buffer, skipping the shifted rows in between. - * - * @param dst Pointer to a part of the screen buffer to write to. - * @param xc The X coordinate of the first tile in the column. - * @param yc The Y coordinate of the first tile in the column - * @param pitch Number of pixels to advance in the screen buffer each time a pixel is written. - * @param reps Number of lines to draw - * @param start_pos Position of first pixel to draw. - * @param end_pos Position of last pixel to draw (exclusive). - * @param blitter current blitter - * @note If pixel position is below \c 0, skip drawing. - */ -void SmallMapWindow::DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const -{ - void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height); - uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0; - - do { - /* Check if the tile (xc,yc) is within the map range */ - if (xc >= MapMaxX() || yc >= MapMaxY()) continue; - - /* Check if the dst pointer points to a pixel inside the screen buffer */ - if (dst < _screen.dst_ptr) continue; - if (dst >= dst_ptr_abs_end) continue; - - /* Construct tilearea covered by (xc, yc, xc + this->zoom, yc + this->zoom) such that it is within min_xy limits. */ - TileArea ta; - if (min_xy == 1 && (xc == 0 || yc == 0)) { - if (this->zoom == 1) continue; // The tile area is empty, don't draw anything. - - ta = TileArea(TileXY(max(min_xy, xc), max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0)); - } else { - ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom); - } - ta.ClampToMap(); // Clamp to map boundaries (may contain MP_VOID tiles!). - - uint32 val = this->GetTileColours(ta); - uint8 *val8 = (uint8 *)&val; - int idx = max(0, -start_pos); - for (int pos = max(0, start_pos); pos < end_pos; pos++) { - blitter->SetPixel(dst, idx, 0, val8[idx]); - idx++; - } - /* Switch to next tile in the column */ - } while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0); -} - -/** - * Adds vehicles to the smallmap. - * @param dpi the part of the smallmap to be drawn into - * @param blitter current blitter - */ -void SmallMapWindow::DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const -{ - const Vehicle *v; - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_EFFECT) continue; - if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue; - - /* Remap into flat coordinates. */ - Point pt = this->RemapTile(v->x_pos / TILE_SIZE, v->y_pos / TILE_SIZE); - - int y = pt.y - dpi->top; - if (!IsInsideMM(y, 0, dpi->height)) continue; // y is out of bounds. - - bool skip = false; // Default is to draw both pixels. - int x = pt.x - this->subscroll - 3 - dpi->left; // Offset X coordinate. - if (x < 0) { - /* if x+1 is 0, that means we're on the very left edge, - * and should thus only draw a single pixel */ - if (++x != 0) continue; - skip = true; - } else if (x >= dpi->width - 1) { - /* Check if we're at the very right edge, and if so draw only a single pixel */ - if (x != dpi->width - 1) continue; - skip = true; - } - - /* Calculate pointer to pixel and the colour */ - byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE; - - /* And draw either one or two pixels depending on clipping */ - blitter->SetPixel(dpi->dst_ptr, x, y, colour); - if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour); - } -} - -/** - * Adds town names to the smallmap. - * @param dpi the part of the smallmap to be drawn into - */ -void SmallMapWindow::DrawTowns(const DrawPixelInfo *dpi) const -{ - const Town *t; - FOR_ALL_TOWNS(t) { - /* Remap the town coordinate */ - Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy)); - int x = pt.x - this->subscroll - (t->cache.sign.width_small >> 1); - int y = pt.y; - - /* Check if the town sign is within bounds */ - if (x + t->cache.sign.width_small > dpi->left && - x < dpi->left + dpi->width && - y + FONT_HEIGHT_SMALL > dpi->top && - y < dpi->top + dpi->height) { - /* And draw it. */ - SetDParam(0, t->index); - DrawString(x, x + t->cache.sign.width_small, y, STR_SMALLMAP_TOWN); - } - } -} - -/** - * Adds map indicators to the smallmap. - */ -void SmallMapWindow::DrawMapIndicators() const -{ - /* Find main viewport. */ - const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; - - Point tile = InverseRemapCoords(vp->virtual_left, vp->virtual_top); - Point tl = this->RemapTile(tile.x >> 4, tile.y >> 4); - tl.x -= this->subscroll; - - tile = InverseRemapCoords(vp->virtual_left + vp->virtual_width, vp->virtual_top + vp->virtual_height); - Point br = this->RemapTile(tile.x >> 4, tile.y >> 4); - br.x -= this->subscroll; - - SmallMapWindow::DrawVertMapIndicator(tl.x, tl.y, br.y); - SmallMapWindow::DrawVertMapIndicator(br.x, tl.y, br.y); - - SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, tl.y); - SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, br.y); -} - -/** - * Draws the small map. - * - * Basically, the small map is draw column of pixels by column of pixels. The pixels - * are drawn directly into the screen buffer. The final map is drawn in multiple passes. - * The passes are: - *
  1. The colours of tiles in the different modes.
  2. - *
  3. Town names (optional)
- * - * @param dpi pointer to pixel to write onto - */ -void SmallMapWindow::DrawSmallMap(DrawPixelInfo *dpi) const -{ - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - DrawPixelInfo *old_dpi; - - old_dpi = _cur_dpi; - _cur_dpi = dpi; - - /* Clear it */ - GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, PC_BLACK); - - /* Which tile is displayed at (dpi->left, dpi->top)? */ - int dx; - Point tile = this->PixelToTile(dpi->left, dpi->top, &dx); - int tile_x = this->scroll_x / (int)TILE_SIZE + tile.x; - int tile_y = this->scroll_y / (int)TILE_SIZE + tile.y; - - void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0); - int x = - dx - 4; - int y = 0; - - for (;;) { - /* Distance from left edge */ - if (x >= -3) { - if (x >= dpi->width) break; // Exit the loop. - - int end_pos = min(dpi->width, x + 4); - int reps = (dpi->height - y + 1) / 2; // Number of lines. - if (reps > 0) { - this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter); - } - } - - if (y == 0) { - tile_y += this->zoom; - y++; - ptr = blitter->MoveTo(ptr, 0, 1); - } else { - tile_x -= this->zoom; - y--; - ptr = blitter->MoveTo(ptr, 0, -1); - } - ptr = blitter->MoveTo(ptr, 2, 0); - x += 2; - } - - /* Draw vehicles */ - if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter); - - /* Draw link stat overlay */ - if (this->map_type == SMT_LINKSTATS) this->overlay->Draw(dpi); - - /* Draw town names */ - if (this->show_towns) this->DrawTowns(dpi); - - /* Draw map indicators */ - this->DrawMapIndicators(); - - _cur_dpi = old_dpi; -} - -/** - * Function to set up widgets depending on the information being shown on the smallmap. - */ -void SmallMapWindow::SetupWidgetData() -{ - StringID legend_tooltip; - StringID enable_all_tooltip; - StringID disable_all_tooltip; - int plane; - switch (this->map_type) { - case SMT_INDUSTRY: - legend_tooltip = STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION; - enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES; - disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES; - plane = 0; - break; - - case SMT_OWNER: - legend_tooltip = STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION; - enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES; - disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES; - plane = 0; - break; - - case SMT_LINKSTATS: - legend_tooltip = STR_SMALLMAP_TOOLTIP_CARGO_SELECTION; - enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS; - disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS; - plane = 0; - break; - - default: - legend_tooltip = STR_NULL; - enable_all_tooltip = STR_NULL; - disable_all_tooltip = STR_NULL; - plane = 1; - break; - } - - this->GetWidget(WID_SM_LEGEND)->SetDataTip(STR_NULL, legend_tooltip); - this->GetWidget(WID_SM_ENABLE_ALL)->SetDataTip(STR_SMALLMAP_ENABLE_ALL, enable_all_tooltip); - this->GetWidget(WID_SM_DISABLE_ALL)->SetDataTip(STR_SMALLMAP_DISABLE_ALL, disable_all_tooltip); - this->GetWidget(WID_SM_SELECT_BUTTONS)->SetDisplayedPlane(plane); -} - -SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : Window(desc), refresh(FORCE_REFRESH_PERIOD) -{ - _smallmap_industry_highlight = INVALID_INDUSTRYTYPE; - this->overlay = new LinkGraphOverlay(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1); - this->InitNested(window_number); - this->LowerWidget(this->map_type + WID_SM_CONTOUR); - - BuildLandLegend(); - this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap); - - this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns); - - this->SetupWidgetData(); - - this->SetZoomLevel(ZLC_INITIALIZE, NULL); - this->SmallMapCenterOnCurrentPos(); - this->SetOverlayCargoMask(); -} - -/* virtual */ void SmallMapWindow::SetStringParameters(int widget) const -{ - switch (widget) { - case WID_SM_CAPTION: - SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type); - break; - } -} - -/* virtual */ void SmallMapWindow::OnInit() -{ - uint min_width = 0; - this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS; - this->min_number_of_fixed_rows = lengthof(_linkstat_colours_in_legenda); - for (uint i = 0; i < lengthof(_legend_table); i++) { - uint height = 0; - uint num_columns = 1; - for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) { - StringID str; - if (i == SMT_INDUSTRY) { - SetDParam(0, tbl->legend); - SetDParam(1, IndustryPool::MAX_SIZE); - str = STR_SMALLMAP_INDUSTRY; - } else if (i == SMT_LINKSTATS) { - SetDParam(0, tbl->legend); - str = STR_SMALLMAP_LINKSTATS; - } else if (i == SMT_OWNER) { - if (tbl->company != INVALID_COMPANY) { - if (!Company::IsValidID(tbl->company)) { - /* Rebuild the owner legend. */ - BuildOwnerLegend(); - this->OnInit(); - return; - } - /* Non-fixed legend entries for the owner view. */ - SetDParam(0, tbl->company); - str = STR_SMALLMAP_COMPANY; - } else { - str = tbl->legend; - } - } else { - if (tbl->col_break) { - this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height); - height = 0; - num_columns++; - } - height++; - str = tbl->legend; - } - min_width = max(GetStringBoundingBox(str).width, min_width); - } - this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height); - this->min_number_of_columns = max(this->min_number_of_columns, num_columns); - } - - /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */ - this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; -} - -/* virtual */ void SmallMapWindow::OnPaint() -{ - if (this->map_type == SMT_OWNER) { - for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) { - if (tbl->company != INVALID_COMPANY && !Company::IsValidID(tbl->company)) { - /* Rebuild the owner legend. */ - BuildOwnerLegend(); - this->InvalidateData(1); - break; - } - } - } - - this->DrawWidgets(); -} - -/* virtual */ void SmallMapWindow::DrawWidget(const Rect &r, int widget) const -{ - switch (widget) { - case WID_SM_MAP: { - DrawPixelInfo new_dpi; - if (!FillDrawPixelInfo(&new_dpi, r.left + 1, r.top + 1, r.right - r.left - 1, r.bottom - r.top - 1)) return; - this->DrawSmallMap(&new_dpi); - break; - } - - case WID_SM_LEGEND: { - uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1); - uint number_of_rows = this->GetNumberRowsLegend(columns); - bool rtl = _current_text_dir == TD_RTL; - uint y_org = r.top + WD_FRAMERECT_TOP; - uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT; - uint y = y_org; - uint i = 0; // Row counter for industry legend. - uint row_height = FONT_HEIGHT_SMALL; - - uint text_left = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT; - uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0); - uint blob_left = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0; - uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH; - - StringID string = STR_NULL; - switch (this->map_type) { - case SMT_INDUSTRY: - string = STR_SMALLMAP_INDUSTRY; - break; - case SMT_LINKSTATS: - string = STR_SMALLMAP_LINKSTATS; - break; - case SMT_OWNER: - string = STR_SMALLMAP_COMPANY; - break; - default: - break; - } - - for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) { - if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER || this->map_type == SMT_LINKSTATS) && i++ >= number_of_rows)) { - /* Column break needed, continue at top, COLUMN_WIDTH pixels - * (one "row") to the right. */ - x += rtl ? -(int)this->column_width : this->column_width; - y = y_org; - i = 1; - } - - uint8 legend_colour = tbl->colour; - - switch (this->map_type) { - case SMT_INDUSTRY: - /* Industry name must be formatted, since it's not in tiny font in the specs. - * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font */ - SetDParam(0, tbl->legend); - SetDParam(1, Industry::GetIndustryTypeCount(tbl->type)); - if (tbl->show_on_map && tbl->type == _smallmap_industry_highlight) { - legend_colour = _smallmap_industry_highlight_state ? PC_WHITE : PC_BLACK; - } - /* FALL THROUGH */ - case SMT_LINKSTATS: - SetDParam(0, tbl->legend); - /* FALL_THROUGH */ - case SMT_OWNER: - if (this->map_type != SMT_OWNER || tbl->company != INVALID_COMPANY) { - if (this->map_type == SMT_OWNER) SetDParam(0, tbl->company); - if (!tbl->show_on_map) { - /* Simply draw the string, not the black border of the legend colour. - * This will enforce the idea of the disabled item */ - DrawString(x + text_left, x + text_right, y, string, TC_GREY); - } else { - DrawString(x + text_left, x + text_right, y, string, TC_BLACK); - GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK); // Outer border of the legend colour - } - break; - } - /* FALL_THROUGH */ - default: - if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP); - /* Anything that is not an industry or a company is using normal process */ - GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK); - DrawString(x + text_left, x + text_right, y, tbl->legend); - break; - } - GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, legend_colour); // Legend colour - - y += row_height; - } - } - } -} - -/** - * Select a new map type. - * @param map_type New map type. - */ -void SmallMapWindow::SwitchMapType(SmallMapType map_type) -{ - this->RaiseWidget(this->map_type + WID_SM_CONTOUR); - this->map_type = map_type; - this->LowerWidget(this->map_type + WID_SM_CONTOUR); - - this->SetupWidgetData(); - - if (map_type == SMT_LINKSTATS) this->overlay->RebuildCache(); - this->SetDirty(); -} - -/** - * Get the number of rows in the legend from the number of columns. Those - * are at least min_number_of_fixed_rows and possibly more if there are so - * many cargoes, industry types or companies that they won't fit in the - * available space. - * @param columns Number of columns in the legend. - * @return Number of rows needed for everything to fit in. - */ -inline uint SmallMapWindow::GetNumberRowsLegend(uint columns) const -{ - /* Reserve one column for link colours */ - uint num_rows_linkstats = CeilDiv(_smallmap_cargo_count, columns - 1); - uint num_rows_others = CeilDiv(max(_smallmap_industry_count, _smallmap_company_count), columns); - return max(this->min_number_of_fixed_rows, max(num_rows_linkstats, num_rows_others)); -} - -/** - * Select and toggle a legend item. When CTRL is pressed, disable all other - * items in the group defined by begin_legend_item and end_legend_item and - * keep the clicked one enabled even if it was already enabled before. If - * the other items in the group are all disabled already and CTRL is pressed - * enable them instead. - * @param click_pos the index of the item being selected - * @param legend the legend from which we select - * @param end_legend_item index one past the last item in the group to be inverted - * @param begin_legend_item index of the first item in the group to be inverted - */ -void SmallMapWindow::SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item) -{ - if (_ctrl_pressed) { - /* Disable all, except the clicked one */ - bool changes = false; - for (int i = begin_legend_item; i != end_legend_item; i++) { - bool new_state = (i == click_pos); - if (legend[i].show_on_map != new_state) { - changes = true; - legend[i].show_on_map = new_state; - } - } - if (!changes) { - /* Nothing changed? Then show all (again). */ - for (int i = begin_legend_item; i != end_legend_item; i++) { - legend[i].show_on_map = true; - } - } - } else { - legend[click_pos].show_on_map = !legend[click_pos].show_on_map; - } -} - -/** - * Set the link graph overlay cargo mask from the legend. - */ -void SmallMapWindow::SetOverlayCargoMask() -{ - uint32 cargo_mask = 0; - for (int i = 0; i != _smallmap_cargo_count; ++i) { - if (_legend_linkstats[i].show_on_map) SetBit(cargo_mask, _legend_linkstats[i].type); - } - this->overlay->SetCargoMask(cargo_mask); -} - -/** - * Determines the mouse position on the legend. - * @param pt Mouse position. - * @return Legend item under the mouse. - */ -int SmallMapWindow::GetPositionOnLegend(Point pt) -{ - const NWidgetBase *wi = this->GetWidget(WID_SM_LEGEND); - uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL; - uint columns = this->GetNumberColumnsLegend(wi->current_x); - uint number_of_rows = this->GetNumberRowsLegend(columns); - if (line >= number_of_rows) return -1; - - bool rtl = _current_text_dir == TD_RTL; - int x = pt.x - wi->pos_x; - if (rtl) x = wi->current_x - x; - uint column = (x - WD_FRAMERECT_LEFT) / this->column_width; - - return (column * number_of_rows) + line; -} - -/* virtual */ void SmallMapWindow::OnMouseOver(Point pt, int widget) -{ - IndustryType new_highlight = INVALID_INDUSTRYTYPE; - if (widget == WID_SM_LEGEND && this->map_type == SMT_INDUSTRY) { - int industry_pos = GetPositionOnLegend(pt); - if (industry_pos >= 0 && industry_pos < _smallmap_industry_count) { - new_highlight = _legend_from_industries[industry_pos].type; - } - } - if (new_highlight != _smallmap_industry_highlight) { - _smallmap_industry_highlight = new_highlight; - this->refresh = _smallmap_industry_highlight != INVALID_INDUSTRYTYPE ? BLINK_PERIOD : FORCE_REFRESH_PERIOD; - _smallmap_industry_highlight_state = true; - this->SetDirty(); - } -} - -/* virtual */ void SmallMapWindow::OnClick(Point pt, int widget, int click_count) -{ - /* User clicked something, notify the industry chain window to stop sending newly selected industries. */ - InvalidateWindowClassesData(WC_INDUSTRY_CARGOES, NUM_INDUSTRYTYPES); - - switch (widget) { - case WID_SM_MAP: { // Map window - /* - * XXX: scrolling with the left mouse button is done by subsequently - * clicking with the left mouse button; clicking once centers the - * large map at the selected point. So by unclicking the left mouse - * button here, it gets reclicked during the next inputloop, which - * would make it look like the mouse is being dragged, while it is - * actually being (virtually) clicked every inputloop. - */ - _left_button_clicked = false; - - const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); - Window *w = FindWindowById(WC_MAIN_WINDOW, 0); - int sub; - pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub); - pt = RemapCoords(this->scroll_x + pt.x * TILE_SIZE + this->zoom * (TILE_SIZE - sub * TILE_SIZE / 4), - this->scroll_y + pt.y * TILE_SIZE + sub * this->zoom * TILE_SIZE / 4, 0); - - w->viewport->follow_vehicle = INVALID_VEHICLE; - w->viewport->dest_scrollpos_x = pt.x - (w->viewport->virtual_width >> 1); - w->viewport->dest_scrollpos_y = pt.y - (w->viewport->virtual_height >> 1); - - this->SetDirty(); - break; - } - - case WID_SM_ZOOM_IN: - case WID_SM_ZOOM_OUT: { - const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); - Point pt = {wid->current_x / 2, wid->current_y / 2}; - this->SetZoomLevel((widget == WID_SM_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - break; - } - - case WID_SM_CONTOUR: // Show land contours - case WID_SM_VEHICLES: // Show vehicles - case WID_SM_INDUSTRIES: // Show industries - case WID_SM_LINKSTATS: // Show route map - case WID_SM_ROUTES: // Show transport routes - case WID_SM_VEGETATION: // Show vegetation - case WID_SM_OWNERS: // Show land owners - this->SwitchMapType((SmallMapType)(widget - WID_SM_CONTOUR)); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - break; - - case WID_SM_CENTERMAP: // Center the smallmap again - this->SmallMapCenterOnCurrentPos(); - this->HandleButtonClick(WID_SM_CENTERMAP); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - break; - - case WID_SM_TOGGLETOWNNAME: // Toggle town names - this->show_towns = !this->show_towns; - this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns); - - this->SetDirty(); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - break; - - case WID_SM_LEGEND: // Legend - if (this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER) { - int click_pos = this->GetPositionOnLegend(pt); - if (click_pos < 0) break; - - /* If industry type small map*/ - if (this->map_type == SMT_INDUSTRY) { - /* If click on industries label, find right industry type and enable/disable it. */ - if (click_pos < _smallmap_industry_count) { - this->SelectLegendItem(click_pos, _legend_from_industries, _smallmap_industry_count); - } - } else if (this->map_type == SMT_LINKSTATS) { - if (click_pos < _smallmap_cargo_count) { - this->SelectLegendItem(click_pos, _legend_linkstats, _smallmap_cargo_count); - this->SetOverlayCargoMask(); - } - } else if (this->map_type == SMT_OWNER) { - if (click_pos < _smallmap_company_count) { - this->SelectLegendItem(click_pos, _legend_land_owners, _smallmap_company_count, NUM_NO_COMPANY_ENTRIES); - } - } - this->SetDirty(); - } - break; - - case WID_SM_ENABLE_ALL: - /* FALL THROUGH */ - case WID_SM_DISABLE_ALL: { - LegendAndColour *tbl = NULL; - switch (this->map_type) { - case SMT_INDUSTRY: - tbl = _legend_from_industries; - break; - case SMT_OWNER: - tbl = &(_legend_land_owners[NUM_NO_COMPANY_ENTRIES]); - break; - case SMT_LINKSTATS: - tbl = _legend_linkstats; - break; - default: - NOT_REACHED(); - } - for (;!tbl->end && tbl->legend != STR_LINKGRAPH_LEGEND_UNUSED; ++tbl) { - tbl->show_on_map = (widget == WID_SM_ENABLE_ALL); - } - if (this->map_type == SMT_LINKSTATS) this->SetOverlayCargoMask(); - this->SetDirty(); - break; - } - - case WID_SM_SHOW_HEIGHT: // Enable/disable showing of heightmap. - _smallmap_show_heightmap = !_smallmap_show_heightmap; - this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap); - this->SetDirty(); - break; - } -} - -/** - * Some data on this window has become invalid. - * @param data Information about the changed data. - * - data = 0: Displayed industries at the industry chain window have changed. - * - data = 1: Companies have changed. - * @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. - */ -/* virtual */ void SmallMapWindow::OnInvalidateData(int data, bool gui_scope) -{ - if (!gui_scope) return; - switch (data) { - case 1: - /* The owner legend has already been rebuilt. */ - this->ReInit(); - break; - - case 0: { - extern uint64 _displayed_industries; - if (this->map_type != SMT_INDUSTRY) this->SwitchMapType(SMT_INDUSTRY); - - for (int i = 0; i != _smallmap_industry_count; i++) { - _legend_from_industries[i].show_on_map = HasBit(_displayed_industries, _legend_from_industries[i].type); - } - break; - } - - default: NOT_REACHED(); - } - this->SetDirty(); -} - -/* virtual */ bool SmallMapWindow::OnRightClick(Point pt, int widget) -{ - if (widget != WID_SM_MAP || _scrolling_viewport) return false; - - _scrolling_viewport = true; - return true; -} - -/* virtual */ void SmallMapWindow::OnMouseWheel(int wheel) -{ - if (_settings_client.gui.scrollwheel_scrolling == 0) { - const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); - int cursor_x = _cursor.pos.x - this->left - wid->pos_x; - int cursor_y = _cursor.pos.y - this->top - wid->pos_y; - if (IsInsideMM(cursor_x, 0, wid->current_x) && IsInsideMM(cursor_y, 0, wid->current_y)) { - Point pt = {cursor_x, cursor_y}; - this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt); - } - } -} - -/* virtual */ void SmallMapWindow::OnTick() -{ - /* Update the window every now and then */ - if (--this->refresh != 0) return; - - if (this->map_type == SMT_LINKSTATS) { - uint32 company_mask = this->GetOverlayCompanyMask(); - if (this->overlay->GetCompanyMask() != company_mask) { - this->overlay->SetCompanyMask(company_mask); - } else { - this->overlay->RebuildCache(); - } - } - _smallmap_industry_highlight_state = !_smallmap_industry_highlight_state; - - this->refresh = _smallmap_industry_highlight != INVALID_INDUSTRYTYPE ? BLINK_PERIOD : FORCE_REFRESH_PERIOD; - this->SetDirty(); -} - -/** - * Set new #scroll_x, #scroll_y, and #subscroll values after limiting them such that the center - * of the smallmap always contains a part of the map. - * @param sx Proposed new #scroll_x - * @param sy Proposed new #scroll_y - * @param sub Proposed new #subscroll - */ -void SmallMapWindow::SetNewScroll(int sx, int sy, int sub) -{ - const NWidgetBase *wi = this->GetWidget(WID_SM_MAP); - Point hv = InverseRemapCoords(wi->current_x * ZOOM_LVL_BASE * TILE_SIZE / 2, wi->current_y * ZOOM_LVL_BASE * TILE_SIZE / 2); - hv.x *= this->zoom; - hv.y *= this->zoom; - - if (sx < -hv.x) { - sx = -hv.x; - sub = 0; - } - if (sx > (int)(MapMaxX() * TILE_SIZE) - hv.x) { - sx = MapMaxX() * TILE_SIZE - hv.x; - sub = 0; - } - if (sy < -hv.y) { - sy = -hv.y; - sub = 0; - } - if (sy > (int)(MapMaxY() * TILE_SIZE) - hv.y) { - sy = MapMaxY() * TILE_SIZE - hv.y; - sub = 0; - } - - this->scroll_x = sx; - this->scroll_y = sy; - this->subscroll = sub; - if (this->map_type == SMT_LINKSTATS) this->overlay->RebuildCache(); -} - -/* virtual */ void SmallMapWindow::OnScroll(Point delta) -{ - _cursor.fix_at = true; - - /* While tile is at (delta.x, delta.y)? */ - int sub; - Point pt = this->PixelToTile(delta.x, delta.y, &sub); - this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub); - - this->SetDirty(); -} - -void SmallMapWindow::SmallMapCenterOnCurrentPos() -{ - const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; - Point pt = InverseRemapCoords(vp->virtual_left + vp->virtual_width / 2, vp->virtual_top + vp->virtual_height / 2); - - int sub; - const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); - Point sxy = this->ComputeScroll(pt.x / TILE_SIZE, pt.y / TILE_SIZE, max(0, (int)wid->current_x / 2 - 2), wid->current_y / 2, &sub); - this->SetNewScroll(sxy.x, sxy.y, sub); - this->SetDirty(); -} - -/** - * Get the center of the given station as point on the screen in the smallmap window. - * @param st Station to find in the smallmap. - * @return Point with coordinates of the station. - */ -Point SmallMapWindow::GetStationMiddle(const Station *st) const -{ - int x = (st->rect.right + st->rect.left + 1) / 2; - int y = (st->rect.bottom + st->rect.top + 1) / 2; - Point ret = this->RemapTile(x, y); - - /* Same magic 3 as in DrawVehicles; that's where I got it from. - * No idea what it is, but without it the result looks bad. - */ - ret.x -= 3 + this->subscroll; - return ret; -} - -SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR; -bool SmallMapWindow::show_towns = true; - -/** - * Custom container class for displaying smallmap with a vertically resizing legend panel. - * The legend panel has a smallest height that depends on its width. Standard containers cannot handle this case. - * - * @note The container assumes it has two children, the first is the display, the second is the bar with legends and selection image buttons. - * Both children should be both horizontally and vertically resizable and horizontally fillable. - * The bar should have a minimal size with a zero-size legends display. Child padding is not supported. - */ -class NWidgetSmallmapDisplay : public NWidgetContainer { - const SmallMapWindow *smallmap_window; ///< Window manager instance. -public: - NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL) - { - this->smallmap_window = NULL; - } - - virtual void SetupSmallestSize(Window *w, bool init_array) - { - NWidgetBase *display = this->head; - NWidgetBase *bar = display->next; - - display->SetupSmallestSize(w, init_array); - bar->SetupSmallestSize(w, init_array); - - this->smallmap_window = dynamic_cast(w); - assert(this->smallmap_window != NULL); - this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth()); - this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetLegendHeight(smallmap_window->min_number_of_columns)); - this->fill_x = max(display->fill_x, bar->fill_x); - this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y); - this->resize_x = max(display->resize_x, bar->resize_x); - this->resize_y = min(display->resize_y, bar->resize_y); - } - - virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) - { - this->pos_x = x; - this->pos_y = y; - this->current_x = given_width; - this->current_y = given_height; - - NWidgetBase *display = this->head; - NWidgetBase *bar = display->next; - - if (sizing == ST_SMALLEST) { - this->smallest_x = given_width; - this->smallest_y = given_height; - /* Make display and bar exactly equal to their minimal size. */ - display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl); - bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl); - } - - uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(this->smallmap_window->GetNumberColumnsLegend(given_width - bar->smallest_x))); - uint display_height = given_height - bar_height; - display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl); - bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl); - } - - virtual NWidgetCore *GetWidgetFromPos(int x, int y) - { - if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y); - if (widget != NULL) return widget; - } - return NULL; - } - - virtual void Draw(const Window *w) - { - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w); - } -}; - -/** Widget parts of the smallmap display. */ -static const NWidgetPart _nested_smallmap_display[] = { - NWidget(WWT_PANEL, COLOUR_BROWN, WID_SM_MAP_BORDER), - NWidget(WWT_INSET, COLOUR_BROWN, WID_SM_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(), - EndContainer(), -}; - -/** Widget parts of the smallmap legend bar + image buttons. */ -static const NWidgetPart _nested_smallmap_bar[] = { - NWidget(WWT_PANEL, COLOUR_BROWN), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SM_LEGEND), SetResize(1, 1), - NWidget(NWID_VERTICAL), - /* Top button row. */ - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_IN), - SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetFill(1, 1), - NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_CENTERMAP), - SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER), SetFill(1, 1), - NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_BLANK), - SetDataTip(SPR_DOT_SMALL, STR_NULL), SetFill(1, 1), - NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_CONTOUR), - SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), SetFill(1, 1), - NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_VEHICLES), - SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), SetFill(1, 1), - NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_INDUSTRIES), - SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), SetFill(1, 1), - EndContainer(), - /* Bottom button row. */ - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_OUT), - SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1), - NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_TOGGLETOWNNAME), - SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), SetFill(1, 1), - NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_LINKSTATS), - SetDataTip(SPR_IMG_CARGOFLOW, STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP), SetFill(1, 1), - NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_ROUTES), - SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON), SetFill(1, 1), - NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_VEGETATION), - SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP), SetFill(1, 1), - NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_OWNERS), - SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP), SetFill(1, 1), - EndContainer(), - NWidget(NWID_SPACER), SetResize(0, 1), - EndContainer(), - EndContainer(), - EndContainer(), -}; - -static NWidgetBase *SmallMapDisplay(int *biggest_index) -{ - NWidgetContainer *map_display = new NWidgetSmallmapDisplay; - - MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display); - MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display); - return map_display; -} - - -static const NWidgetPart _nested_smallmap_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_BROWN), - NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SM_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_BROWN), - NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), - NWidget(WWT_STICKYBOX, COLOUR_BROWN), - EndContainer(), - NWidgetFunction(SmallMapDisplay), // Smallmap display and legend bar + image buttons. - /* Bottom button row and resize box. */ - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_BROWN), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SM_SELECT_BUTTONS), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SM_ENABLE_ALL), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SM_DISABLE_ALL), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_NULL), - NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SM_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT), - EndContainer(), - NWidget(NWID_SPACER), SetFill(1, 1), - EndContainer(), - NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0), - EndContainer(), - EndContainer(), - NWidget(WWT_RESIZEBOX, COLOUR_BROWN), - EndContainer(), -}; - -static WindowDesc _smallmap_desc( - WDP_AUTO, "smallmap", 484, 314, - WC_SMALLMAP, WC_NONE, - 0, - _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets) -); - -/** - * Show the smallmap window. - */ -void ShowSmallMap() -{ - AllocateWindowDescFront(&_smallmap_desc, 0); -} - -/** - * Scrolls the main window to given coordinates. - * @param x x coordinate - * @param y y coordinate - * @param z z coordinate; -1 to scroll to terrain height - * @param instant scroll instantly (meaningful only when smooth_scrolling is active) - * @return did the viewport position change? - */ -bool ScrollMainWindowTo(int x, int y, int z, bool instant) -{ - bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant); - - /* If a user scrolls to a tile (via what way what so ever) and already is on - * that tile (e.g.: pressed twice), move the smallmap to that location, - * so you directly see where you are on the smallmap. */ - - if (res) return res; - - SmallMapWindow *w = dynamic_cast(FindWindowById(WC_SMALLMAP, 0)); - if (w != NULL) w->SmallMapCenterOnCurrentPos(); - - return res; -} diff --git a/src/smallmap_gui.h.orig b/src/smallmap_gui.h.orig deleted file mode 100644 index 6652f83d8c..0000000000 --- a/src/smallmap_gui.h.orig +++ /dev/null @@ -1,192 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file smallmap_gui.h Smallmap GUI functions. */ - -#ifndef SMALLMAP_GUI_H -#define SMALLMAP_GUI_H - -#include "industry_type.h" -#include "company_base.h" -#include "window_gui.h" -#include "strings_func.h" -#include "blitter/factory.hpp" -#include "linkgraph/linkgraph_gui.h" -#include "widgets/smallmap_widget.h" - -/* set up the cargos to be displayed in the smallmap's route legend */ -void BuildLinkStatsLegend(); - -void BuildIndustriesLegend(); -void ShowSmallMap(); -void BuildLandLegend(); -void BuildOwnerLegend(); - -/** Structure for holding relevant data for legends in small map */ -struct LegendAndColour { - uint8 colour; ///< Colour of the item on the map. - StringID legend; ///< String corresponding to the coloured item. - IndustryType type; ///< Type of industry. Only valid for industry entries. - uint8 height; ///< Height in tiles. Only valid for height legend entries. - CompanyID company; ///< Company to display. Only valid for company entries of the owner legend. - bool show_on_map; ///< For filtering industries, if \c true, industry is shown on the map in colour. - bool end; ///< This is the end of the list. - bool col_break; ///< Perform a column break and go further at the next column. -}; - -/** Class managing the smallmap window. */ -class SmallMapWindow : public Window { -protected: - /** Types of legends in the #WID_SM_LEGEND widget. */ - enum SmallMapType { - SMT_CONTOUR, - SMT_VEHICLES, - SMT_INDUSTRY, - SMT_LINKSTATS, - SMT_ROUTES, - SMT_VEGETATION, - SMT_OWNER, - }; - - /** Available kinds of zoomlevel changes. */ - enum ZoomLevelChange { - ZLC_INITIALIZE, ///< Initialize zoom level. - ZLC_ZOOM_OUT, ///< Zoom out. - ZLC_ZOOM_IN, ///< Zoom in. - }; - - static SmallMapType map_type; ///< Currently displayed legends. - static bool show_towns; ///< Display town names in the smallmap. - - static const uint LEGEND_BLOB_WIDTH = 8; ///< Width of the coloured blob in front of a line text in the #WID_SM_LEGEND widget. - static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2; ///< Minimal number of columns in the #WID_SM_LEGEND widget for the #SMT_INDUSTRY legend. - static const uint FORCE_REFRESH_PERIOD = 0x1F; ///< map is redrawn after that many ticks - static const uint BLINK_PERIOD = 0x0F; ///< highlight blinking interval - - uint min_number_of_columns; ///< Minimal number of columns in legends. - uint min_number_of_fixed_rows; ///< Minimal number of rows in the legends for the fixed layouts only (all except #SMT_INDUSTRY). - uint column_width; ///< Width of a column in the #WID_SM_LEGEND widget. - - int32 scroll_x; ///< Horizontal world coordinate of the base tile left of the top-left corner of the smallmap display. - int32 scroll_y; ///< Vertical world coordinate of the base tile left of the top-left corner of the smallmap display. - int32 subscroll; ///< Number of pixels (0..3) between the right end of the base tile and the pixel at the top-left corner of the smallmap display. - int zoom; ///< Zoom level. Bigger number means more zoom-out (further away). - - uint8 refresh; ///< Refresh counter, zeroed every FORCE_REFRESH_PERIOD ticks. - LinkGraphOverlay *overlay; - - Point SmallmapRemapCoords(int x, int y) const; - - /** - * Draws vertical part of map indicator - * @param x X coord of left/right border of main viewport - * @param y Y coord of top border of main viewport - * @param y2 Y coord of bottom border of main viewport - */ - static inline void DrawVertMapIndicator(int x, int y, int y2) - { - GfxFillRect(x, y, x, y + 3, PC_VERY_LIGHT_YELLOW); - GfxFillRect(x, y2 - 3, x, y2, PC_VERY_LIGHT_YELLOW); - } - - /** - * Draws horizontal part of map indicator - * @param x X coord of left border of main viewport - * @param x2 X coord of right border of main viewport - * @param y Y coord of top/bottom border of main viewport - */ - static inline void DrawHorizMapIndicator(int x, int x2, int y) - { - GfxFillRect(x, y, x + 3, y, PC_VERY_LIGHT_YELLOW); - GfxFillRect(x2 - 3, y, x2, y, PC_VERY_LIGHT_YELLOW); - } - - /** - * Compute minimal required width of the legends. - * @return Minimally needed width for displaying the smallmap legends in pixels. - */ - inline uint GetMinLegendWidth() const - { - return WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width; - } - - /** - * Return number of columns that can be displayed in \a width pixels. - * @return Number of columns to display. - */ - inline uint GetNumberColumnsLegend(uint width) const - { - return width / this->column_width; - } - - /** - * Compute height given a number of columns. - * @param num_columns Number of columns. - * @return Needed height for displaying the smallmap legends in pixels. - */ - inline uint GetLegendHeight(uint num_columns) const - { - return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + - this->GetNumberRowsLegend(num_columns) * FONT_HEIGHT_SMALL; - } - - /** - * Get a bitmask for company links to be displayed. Usually this will be - * the _local_company. Spectators get to see all companies' links. - * @return Company mask. - */ - inline uint32 GetOverlayCompanyMask() const - { - return Company::IsValidID(_local_company) ? 1U << _local_company : 0xffffffff; - } - - uint GetNumberRowsLegend(uint columns) const; - void SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item = 0); - void SwitchMapType(SmallMapType map_type); - void SetNewScroll(int sx, int sy, int sub); - - void DrawMapIndicators() const; - void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const; - void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const; - void DrawTowns(const DrawPixelInfo *dpi) const; - void DrawSmallMap(DrawPixelInfo *dpi) const; - - Point RemapTile(int tile_x, int tile_y) const; - Point PixelToTile(int px, int py, int *sub, bool add_sub = true) const; - Point ComputeScroll(int tx, int ty, int x, int y, int *sub); - void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt); - void SetOverlayCargoMask(); - void SetupWidgetData(); - uint32 GetTileColours(const TileArea &ta) const; - - int GetPositionOnLegend(Point pt); - -public: - friend class NWidgetSmallmapDisplay; - - SmallMapWindow(WindowDesc *desc, int window_number); - virtual ~SmallMapWindow() { delete this->overlay; } - - void SmallMapCenterOnCurrentPos(); - Point GetStationMiddle(const Station *st) const; - - virtual void SetStringParameters(int widget) const; - virtual void OnInit(); - virtual void OnPaint(); - virtual void DrawWidget(const Rect &r, int widget) const; - virtual void OnClick(Point pt, int widget, int click_count); - virtual void OnInvalidateData(int data = 0, bool gui_scope = true); - virtual bool OnRightClick(Point pt, int widget); - virtual void OnMouseWheel(int wheel); - virtual void OnTick(); - virtual void OnScroll(Point delta); - virtual void OnMouseOver(Point pt, int widget); -}; - -#endif /* SMALLMAP_GUI_H */ diff --git a/src/station_base.h.orig b/src/station_base.h.orig deleted file mode 100644 index a4ad69547e..0000000000 --- a/src/station_base.h.orig +++ /dev/null @@ -1,534 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file station_base.h Base classes/functions for stations. */ - -#ifndef STATION_BASE_H -#define STATION_BASE_H - -#include "core/random_func.hpp" -#include "base_station_base.h" -#include "newgrf_airport.h" -#include "cargopacket.h" -#include "industry_type.h" -#include "linkgraph/linkgraph_type.h" -#include "newgrf_storage.h" -#include - -typedef Pool StationPool; -extern StationPool _station_pool; - -static const byte INITIAL_STATION_RATING = 175; - -/** - * Flow statistics telling how much flow should be sent along a link. This is - * done by creating "flow shares" and using std::map's upper_bound() method to - * look them up with a random number. A flow share is the difference between a - * key in a map and the previous key. So one key in the map doesn't actually - * mean anything by itself. - */ -class FlowStat { -public: - typedef std::map SharesMap; - - /** - * Invalid constructor. This can't be called as a FlowStat must not be - * empty. However, the constructor must be defined and reachable for - * FlwoStat to be used in a std::map. - */ - inline FlowStat() {NOT_REACHED();} - - /** - * Create a FlowStat with an initial entry. - * @param st Station the initial entry refers to. - * @param flow Amount of flow for the initial entry. - */ - inline FlowStat(StationID st, uint flow) - { - assert(flow > 0); - this->shares[flow] = st; - this->unrestricted = flow; - } - - /** - * Add some flow to the end of the shares map. Only do that if you know - * that the station isn't in the map yet. Anything else may lead to - * inconsistencies. - * @param st Remote station. - * @param flow Amount of flow to be added. - * @param restricted If the flow to be added is restricted. - */ - inline void AppendShare(StationID st, uint flow, bool restricted = false) - { - assert(flow > 0); - this->shares[(--this->shares.end())->first + flow] = st; - if (!restricted) this->unrestricted += flow; - } - - uint GetShare(StationID st) const; - - void ChangeShare(StationID st, int flow); - - void RestrictShare(StationID st); - - void ReleaseShare(StationID st); - - void ScaleToMonthly(uint runtime); - - /** - * Get the actual shares as a const pointer so that they can be iterated - * over. - * @return Actual shares. - */ - inline const SharesMap *GetShares() const { return &this->shares; } - - /** - * Return total amount of unrestricted shares. - * @return Amount of unrestricted shares. - */ - inline uint GetUnrestricted() const { return this->unrestricted; } - - /** - * Swap the shares maps, and thus the content of this FlowStat with the - * other one. - * @param other FlowStat to swap with. - */ - inline void SwapShares(FlowStat &other) - { - this->shares.swap(other.shares); - Swap(this->unrestricted, other.unrestricted); - } - - /** - * Get a station a package can be routed to. This done by drawing a - * random number between 0 and sum_shares and then looking that up in - * the map with lower_bound. So each share gets selected with a - * probability dependent on its flow. Do include restricted flows here. - * @param is_restricted Output if a restricted flow was chosen. - * @return A station ID from the shares map. - */ - inline StationID GetViaWithRestricted(bool &is_restricted) const - { - assert(!this->shares.empty()); - uint rand = RandomRange((--this->shares.end())->first); - is_restricted = rand >= this->unrestricted; - return this->shares.upper_bound(rand)->second; - } - - /** - * Get a station a package can be routed to. This done by drawing a - * random number between 0 and sum_shares and then looking that up in - * the map with lower_bound. So each share gets selected with a - * probability dependent on its flow. Don't include restricted flows. - * @return A station ID from the shares map. - */ - inline StationID GetVia() const - { - assert(!this->shares.empty()); - return this->unrestricted > 0 ? - this->shares.upper_bound(RandomRange(this->unrestricted))->second : - INVALID_STATION; - } - - StationID GetVia(StationID excluded, StationID excluded2 = INVALID_STATION) const; - - void Invalidate(); - -private: - SharesMap shares; ///< Shares of flow to be sent via specified station (or consumed locally). - uint unrestricted; ///< Limit for unrestricted shares. -}; - -/** Flow descriptions by origin stations. */ -class FlowStatMap : public std::map { -public: - void AddFlow(StationID origin, StationID via, uint amount); - void PassOnFlow(StationID origin, StationID via, uint amount); - StationIDStack DeleteFlows(StationID via); - void RestrictFlows(StationID via); - void ReleaseFlows(StationID via); - void FinalizeLocalConsumption(StationID self); -}; - -/** - * Stores station stats for a single cargo. - */ -struct GoodsEntry { - /** Status of this cargo for the station. */ - enum GoodsEntryStatus { - /** - * Set when the station accepts the cargo currently for final deliveries. - * It is updated every STATION_ACCEPTANCE_TICKS ticks by checking surrounding tiles for acceptance >= 8/8. - */ - GES_ACCEPTANCE, - - /** - * Set when the cargo was ever waiting at the station. - * It is set when cargo supplied by surrounding tiles is moved to the station, or when - * arriving vehicles unload/transfer cargo without it being a final delivery. - * This also indicates, whether a cargo has a rating at the station. - * This flag is never cleared. - */ - GES_PICKUP, - - /** - * Set when a vehicle ever delivered cargo to the station for final delivery. - * This flag is never cleared. - */ - GES_EVER_ACCEPTED, - - /** - * Set when cargo was delivered for final delivery last month. - * This flag is set to the value of GES_CURRENT_MONTH at the start of each month. - */ - GES_LAST_MONTH, - - /** - * Set when cargo was delivered for final delivery this month. - * This flag is reset on the beginning of every month. - */ - GES_CURRENT_MONTH, - - /** - * Set when cargo was delivered for final delivery during the current STATION_ACCEPTANCE_TICKS interval. - * This flag is reset every STATION_ACCEPTANCE_TICKS ticks. - */ - GES_ACCEPTED_BIGTICK, - }; - - GoodsEntry() : - acceptance_pickup(0), - time_since_pickup(255), - rating(INITIAL_STATION_RATING), - last_speed(0), - last_age(255), - amount_fract(0), - link_graph(INVALID_LINK_GRAPH), - node(INVALID_NODE), - max_waiting_cargo(0) - {} - - byte acceptance_pickup; ///< Status of this cargo, see #GoodsEntryStatus. - - /** - * Number of rating-intervals (up to 255) since the last vehicle tried to load this cargo. - * The unit used is STATION_RATING_TICKS. - * This does not imply there was any cargo to load. - */ - byte time_since_pickup; - - byte rating; ///< %Station rating for this cargo. - - /** - * Maximum speed (up to 255) of the last vehicle that tried to load this cargo. - * This does not imply there was any cargo to load. - * The unit used is a special vehicle-specific speed unit for station ratings. - * - Trains: km-ish/h - * - RV: km-ish/h - * - Ships: 0.5 * km-ish/h - * - Aircraft: 8 * mph - */ - byte last_speed; - - /** - * Age in years (up to 255) of the last vehicle that tried to load this cargo. - * This does not imply there was any cargo to load. - */ - byte last_age; - - byte amount_fract; ///< Fractional part of the amount in the cargo list - StationCargoList cargo; ///< The cargo packets of cargo waiting in this station - - LinkGraphID link_graph; ///< Link graph this station belongs to. - NodeID node; ///< ID of node in link graph referring to this goods entry. - FlowStatMap flows; ///< Planned flows through this station. - uint max_waiting_cargo; ///< Max cargo from this station waiting at any station. - - /** - * Reports whether a vehicle has ever tried to load the cargo at this station. - * This does not imply that there was cargo available for loading. Refer to GES_PICKUP for that. - * @return true if vehicle tried to load. - */ - bool HasVehicleEverTriedLoading() const { return this->last_speed != 0; } - - /** - * Does this cargo have a rating at this station? - * @return true if the cargo has a rating, i.e. pickup has been attempted. - */ - inline bool HasRating() const - { - return HasBit(this->acceptance_pickup, GES_PICKUP); - } - - uint GetSumFlowVia(StationID via) const; - - /** - * Get the best next hop for a cargo packet from station source. - * @param source Source of the packet. - * @return The chosen next hop or INVALID_STATION if none was found. - */ - inline StationID GetVia(StationID source) const - { - FlowStatMap::const_iterator flow_it(this->flows.find(source)); - return flow_it != this->flows.end() ? flow_it->second.GetVia() : INVALID_STATION; - } - - /** - * Get the best next hop for a cargo packet from station source, optionally - * excluding one or two stations. - * @param source Source of the packet. - * @param excluded If this station would be chosen choose the second best one instead. - * @param excluded2 Second station to be excluded, if != INVALID_STATION. - * @return The chosen next hop or INVALID_STATION if none was found. - */ - inline StationID GetVia(StationID source, StationID excluded, StationID excluded2 = INVALID_STATION) const - { - FlowStatMap::const_iterator flow_it(this->flows.find(source)); - return flow_it != this->flows.end() ? flow_it->second.GetVia(excluded, excluded2) : INVALID_STATION; - } -}; - -/** All airport-related information. Only valid if tile != INVALID_TILE. */ -struct Airport : public TileArea { - Airport() : TileArea(INVALID_TILE, 0, 0) {} - - uint64 flags; ///< stores which blocks on the airport are taken. was 16 bit earlier on, then 32 - byte type; ///< Type of this airport, @see AirportTypes - byte layout; ///< Airport layout number. - Direction rotation; ///< How this airport is rotated. - - PersistentStorage *psa; ///< Persistent storage for NewGRF airports. - - /** - * Get the AirportSpec that from the airport type of this airport. If there - * is no airport (\c tile == INVALID_TILE) then return the dummy AirportSpec. - * @return The AirportSpec for this airport. - */ - const AirportSpec *GetSpec() const - { - if (this->tile == INVALID_TILE) return &AirportSpec::dummy; - return AirportSpec::Get(this->type); - } - - /** - * Get the finite-state machine for this airport or the finite-state machine - * for the dummy airport in case this isn't an airport. - * @pre this->type < NEW_AIRPORT_OFFSET. - * @return The state machine for this airport. - */ - const AirportFTAClass *GetFTA() const - { - return this->GetSpec()->fsm; - } - - /** Check if this airport has at least one hangar. */ - inline bool HasHangar() const - { - return this->GetSpec()->nof_depots > 0; - } - - /** - * Add the tileoffset to the base tile of this airport but rotate it first. - * The base tile is the northernmost tile of this airport. This function - * helps to make sure that getting the tile of a hangar works even for - * rotated airport layouts without requiring a rotated array of hangar tiles. - * @param tidc The tilediff to add to the airport tile. - * @return The tile of this airport plus the rotated offset. - */ - inline TileIndex GetRotatedTileFromOffset(TileIndexDiffC tidc) const - { - const AirportSpec *as = this->GetSpec(); - switch (this->rotation) { - case DIR_N: return this->tile + ToTileIndexDiff(tidc); - - case DIR_E: return this->tile + TileDiffXY(tidc.y, as->size_x - 1 - tidc.x); - - case DIR_S: return this->tile + TileDiffXY(as->size_x - 1 - tidc.x, as->size_y - 1 - tidc.y); - - case DIR_W: return this->tile + TileDiffXY(as->size_y - 1 - tidc.y, tidc.x); - - default: NOT_REACHED(); - } - } - - /** - * Get the first tile of the given hangar. - * @param hangar_num The hangar to get the location of. - * @pre hangar_num < GetNumHangars(). - * @return A tile with the given hangar. - */ - inline TileIndex GetHangarTile(uint hangar_num) const - { - const AirportSpec *as = this->GetSpec(); - for (uint i = 0; i < as->nof_depots; i++) { - if (as->depot_table[i].hangar_num == hangar_num) { - return this->GetRotatedTileFromOffset(as->depot_table[i].ti); - } - } - NOT_REACHED(); - } - - /** - * Get the exit direction of the hangar at a specific tile. - * @param tile The tile to query. - * @pre IsHangarTile(tile). - * @return The exit direction of the hangar, taking airport rotation into account. - */ - inline Direction GetHangarExitDirection(TileIndex tile) const - { - const AirportSpec *as = this->GetSpec(); - const HangarTileTable *htt = GetHangarDataByTile(tile); - return ChangeDir(htt->dir, DirDifference(this->rotation, as->rotation[0])); - } - - /** - * Get the hangar number of the hangar at a specific tile. - * @param tile The tile to query. - * @pre IsHangarTile(tile). - * @return The hangar number of the hangar at the given tile. - */ - inline uint GetHangarNum(TileIndex tile) const - { - const HangarTileTable *htt = GetHangarDataByTile(tile); - return htt->hangar_num; - } - - /** Get the number of hangars on this airport. */ - inline uint GetNumHangars() const - { - uint num = 0; - uint counted = 0; - const AirportSpec *as = this->GetSpec(); - for (uint i = 0; i < as->nof_depots; i++) { - if (!HasBit(counted, as->depot_table[i].hangar_num)) { - num++; - SetBit(counted, as->depot_table[i].hangar_num); - } - } - return num; - } - -private: - /** - * Retrieve hangar information of a hangar at a given tile. - * @param tile %Tile containing the hangar. - * @return The requested hangar information. - * @pre The \a tile must be at a hangar tile at an airport. - */ - inline const HangarTileTable *GetHangarDataByTile(TileIndex tile) const - { - const AirportSpec *as = this->GetSpec(); - for (uint i = 0; i < as->nof_depots; i++) { - if (this->GetRotatedTileFromOffset(as->depot_table[i].ti) == tile) { - return as->depot_table + i; - } - } - NOT_REACHED(); - } -}; - -typedef SmallVector IndustryVector; - -/** Station data structure */ -struct Station FINAL : SpecializedStation { -public: - RoadStop *GetPrimaryRoadStop(RoadStopType type) const - { - return type == ROADSTOP_BUS ? bus_stops : truck_stops; - } - - RoadStop *GetPrimaryRoadStop(const struct RoadVehicle *v) const; - - RoadStop *bus_stops; ///< All the road stops - TileArea bus_station; ///< Tile area the bus 'station' part covers - RoadStop *truck_stops; ///< All the truck stops - TileArea truck_station; ///< Tile area the truck 'station' part covers - - Airport airport; ///< Tile area the airport covers - TileIndex dock_tile; ///< The location of the dock - - IndustryType indtype; ///< Industry type to get the name from - - StationHadVehicleOfTypeByte had_vehicle_of_type; - - byte time_since_load; - byte time_since_unload; - - byte last_vehicle_type; - std::list loading_vehicles; - GoodsEntry goods[NUM_CARGO]; ///< Goods at this station - uint32 always_accepted; ///< Bitmask of always accepted cargo types (by houses, HQs, industry tiles when industry doesn't accept cargo) - - IndustryVector industries_near; ///< Cached list of industries near the station that can accept cargo, @see DeliverGoodsToIndustry() - - Station(TileIndex tile = INVALID_TILE); - ~Station(); - - void AddFacility(StationFacility new_facility_bit, TileIndex facil_xy); - - void MarkTilesDirty(bool cargo_change) const; - - void UpdateVirtCoord(); - - /* virtual */ uint GetPlatformLength(TileIndex tile, DiagDirection dir) const; - /* virtual */ uint GetPlatformLength(TileIndex tile) const; - void RecomputeIndustriesNear(); - static void RecomputeIndustriesNearForAll(); - - uint GetCatchmentRadius() const; - Rect GetCatchmentRect() const; - - /* virtual */ inline bool TileBelongsToRailStation(TileIndex tile) const - { - return IsRailStationTile(tile) && GetStationIndex(tile) == this->index; - } - - inline bool TileBelongsToAirport(TileIndex tile) const - { - return IsAirportTile(tile) && GetStationIndex(tile) == this->index; - } - - /* virtual */ uint32 GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const; - - /* virtual */ void GetTileArea(TileArea *ta, StationType type) const; -}; - -#define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var) - -/** Iterator to iterate over all tiles belonging to an airport. */ -class AirportTileIterator : public OrthogonalTileIterator { -private: - const Station *st; ///< The station the airport is a part of. - -public: - /** - * Construct the iterator. - * @param ta Area, i.e. begin point and width/height of to-be-iterated area. - */ - AirportTileIterator(const Station *st) : OrthogonalTileIterator(st->airport), st(st) - { - if (!st->TileBelongsToAirport(this->tile)) ++(*this); - } - - inline TileIterator& operator ++() - { - (*this).OrthogonalTileIterator::operator++(); - while (this->tile != INVALID_TILE && !st->TileBelongsToAirport(this->tile)) { - (*this).OrthogonalTileIterator::operator++(); - } - return *this; - } - - virtual TileIterator *Clone() const - { - return new AirportTileIterator(*this); - } -}; - -#endif /* STATION_BASE_H */ diff --git a/src/station_gui.cpp.orig b/src/station_gui.cpp.orig deleted file mode 100644 index 5df21155c1..0000000000 --- a/src/station_gui.cpp.orig +++ /dev/null @@ -1,2450 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file station_gui.cpp The GUI for stations. */ - -#include "stdafx.h" -#include "debug.h" -#include "gui.h" -#include "textbuf_gui.h" -#include "company_func.h" -#include "command_func.h" -#include "vehicle_gui.h" -#include "cargotype.h" -#include "station_gui.h" -#include "strings_func.h" -#include "window_func.h" -#include "viewport_func.h" -#include "widgets/dropdown_func.h" -#include "station_base.h" -#include "waypoint_base.h" -#include "tilehighlight_func.h" -#include "company_base.h" -#include "sortlist_type.h" -#include "core/geometry_func.hpp" -#include "vehiclelist.h" -#include "town.h" -#include "linkgraph/linkgraph.h" - -#include "widgets/station_widget.h" - -#include "table/strings.h" - -#include -#include - -/** - * Calculates and draws the accepted or supplied cargo around the selected tile(s) - * @param left x position where the string is to be drawn - * @param right the right most position to draw on - * @param top y position where the string is to be drawn - * @param sct which type of cargo is to be displayed (passengers/non-passengers) - * @param rad radius around selected tile(s) to be searched - * @param supplies if supplied cargoes should be drawn, else accepted cargoes - * @return Returns the y value below the string that was drawn - */ -int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageType sct, int rad, bool supplies) -{ - TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y); - uint32 cargo_mask = 0; - if (_thd.drawstyle == HT_RECT && tile < MapSize()) { - CargoArray cargoes; - if (supplies) { - cargoes = GetProductionAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad); - } else { - cargoes = GetAcceptanceAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad); - } - - /* Convert cargo counts to a set of cargo bits, and draw the result. */ - for (CargoID i = 0; i < NUM_CARGO; i++) { - switch (sct) { - case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(i, CC_PASSENGERS)) continue; break; - case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(i, CC_PASSENGERS)) continue; break; - case SCT_ALL: break; - default: NOT_REACHED(); - } - if (cargoes[i] >= (supplies ? 1U : 8U)) SetBit(cargo_mask, i); - } - } - SetDParam(0, cargo_mask); - return DrawStringMultiLine(left, right, top, INT32_MAX, supplies ? STR_STATION_BUILD_SUPPLIES_CARGO : STR_STATION_BUILD_ACCEPTS_CARGO); -} - -/** - * Check whether we need to redraw the station coverage text. - * If it is needed actually make the window for redrawing. - * @param w the window to check. - */ -void CheckRedrawStationCoverage(const Window *w) -{ - if (_thd.dirty & 1) { - _thd.dirty &= ~1; - w->SetDirty(); - } -} - -/** - * Draw small boxes of cargo amount and ratings data at the given - * coordinates. If amount exceeds 576 units, it is shown 'full', same - * goes for the rating: at above 90% orso (224) it is also 'full' - * - * @param left left most coordinate to draw the box at - * @param right right most coordinate to draw the box at - * @param y coordinate to draw the box at - * @param type Cargo type - * @param amount Cargo amount - * @param rating ratings data for that particular cargo - */ -static void StationsWndShowStationRating(int left, int right, int y, CargoID type, uint amount, byte rating) -{ - static const uint units_full = 1 << 9; ///< Number of units to show station as full. - static const uint rating_full = 224; ///< Rating needed so it is shown as full. - - const CargoSpec *cs = CargoSpec::Get(type); - if (!cs->IsValid()) return; - - y++; ///< Make boxes 1 pixel shorter. - int left_start = left; - int right_start = right; - int height = GetCharacterHeight(FS_SMALL) - 2; - int colour = cs->rating_colour; - - /* Get width of the box to draw. */ - uint width = minu(amount, units_full) * (right - left) / units_full; - - /* Update the end margin, adding the width of the box not to be drawn... */ - if (width != 0) UpdateMarginsWidth(right - left - width, left_start, right_start, true); - /* ... or prepare margins in case width == 0 and amount > 0 (just one pixel bar). */ - else left_start = right_start = _current_text_dir ? right : left; - - /* Draw total cargo (limited) on station */ - if (amount > 0) GfxFillRect(left_start, y, right_start, y + height, colour); - - DrawString(left, right, y, cs->abbrev, GetContrastColour(colour), SA_CENTER); - - /* Draw green/red ratings bar*/ - y += height + 2; - left_start = left + 1; - right_start = right - 1; - if (rating != 0) { - GfxFillRect(left_start, y, right_start, y, PC_GREEN); - width = minu(rating, rating_full) * (right_start - left_start) / rating_full; - UpdateMarginsWidth(width, left_start, right_start, false); - } - GfxFillRect(left_start, y, right_start, y, PC_RED); -} - -/** - * Draw small boxes of cargo accepted. - * @param left Left most coordinate to draw the box at. - * @param right Right most coordinate to draw the box at. - * @param y Coordinate to draw the box at. - * @param type Cargo type. - * @param acceptance_pickup_byte Acceptance byte. - */ -static void StationsWndShowAcceptance(int left, int right, int y, CargoID type) -{ - const CargoSpec *cs = CargoSpec::Get(type); - if (!cs->IsValid()) return; - y++; - GfxFillRect(left, y, right, y + GetCharacterHeight(FS_SMALL), cs->rating_colour, FILLRECT_CHECKER); - DrawString(left, right, y, cs->abbrev, TC_BLACK, SA_CENTER); -} - -/** - * Draw small boxes showing cargo waiting, ratings... for a given station. - * @param st Station to draw statistics of. - * @param x Position to start drawing at. - * @param width Width for each box. - * @param y Height position to draw the box at. - */ -void StationsWndShowStationRating(const Station *st, int left, int right, int x, int width, int y) -{ - bool rtl = _current_text_dir == TD_RTL; - AddSpace(5, x, false); - - /* For RTL we work in exactly the opposite direction. So - * decrement the space needed first, then draw to the left - * instead of drawing to the left and then incrementing - * the space. */ - if (rtl) x -= width + 4; - for (uint j = 0; j < _sorted_standard_cargo_specs_size && ( x > left && x + width < right ); j++) { - CargoID cid = _sorted_cargo_specs[j]->Index(); - if (st->goods[cid].IsSourceStationForCargo()) { - StationsWndShowStationRating(x, x + width, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating); - AddSpace(width + 4, x, false); - } else if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_EVER_ACCEPTED)) { - StationsWndShowAcceptance(x, x + width, y, cid); - AddSpace(width + 4, x, false); - } - } -} - -typedef GUIList GUIStationList; - -/** - * The list of stations per company. - */ -class CompanyStationsWindow : public Window -{ -protected: - /* Runtime saved values */ - static Listing last_sorting; - static byte facilities; // types of stations of interest - static bool include_empty; // whether we should include stations without waiting cargo - static const uint32 cargo_filter_max; - static uint32 cargo_filter; // bitmap of cargo types to include - static const Station *last_station; - - /* Constants for sorting stations */ - static const StringID sorter_names[]; - static GUIStationList::SortFunction * const sorter_funcs[]; - - GUIStationList stations; - Scrollbar *vscroll; - - /** - * (Re)Build station list - * - * @param owner company whose stations are to be in list - */ - void BuildStationsList(const Owner owner) - { - if (!this->stations.NeedRebuild()) return; - - DEBUG(misc, 3, "Building station list for company %d", owner); - - this->stations.Clear(); - - const Station *st; - FOR_ALL_STATIONS(st) { - if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) { - if (this->facilities & st->facilities) { // only stations with selected facilities - int num_waiting_cargo = 0; - for (CargoID j = 0; j < NUM_CARGO; j++) { - if (st->goods[j].HasRating()) { - num_waiting_cargo++; // count number of waiting cargo - if (HasBit(this->cargo_filter, j)) { - *this->stations.Append() = st; - break; - } - } - } - /* stations without waiting cargo */ - if (num_waiting_cargo == 0 && this->include_empty) { - *this->stations.Append() = st; - } - } - } - } - - this->stations.Compact(); - this->stations.RebuildDone(); - - this->vscroll->SetCount(this->stations.Length()); // Update the scrollbar - } - - /** Sort stations by their name */ - static int CDECL StationNameSorter(const Station * const *a, const Station * const *b) - { - static char buf_cache[64]; - char buf[64]; - - SetDParam(0, (*a)->index); - GetString(buf, STR_STATION_NAME, lastof(buf)); - - if (*b != last_station) { - last_station = *b; - SetDParam(0, (*b)->index); - GetString(buf_cache, STR_STATION_NAME, lastof(buf_cache)); - } - - return strcmp(buf, buf_cache); - } - - /** Sort stations by their type */ - static int CDECL StationTypeSorter(const Station * const *a, const Station * const *b) - { - return (*a)->facilities - (*b)->facilities; - } - - /** Sort stations by their waiting cargo */ - static int CDECL StationWaitingTotalSorter(const Station * const *a, const Station * const *b) - { - int diff = 0; - - CargoID j; - FOR_EACH_SET_CARGO_ID(j, cargo_filter) { - diff += (*a)->goods[j].cargo.TotalCount() - (*b)->goods[j].cargo.TotalCount(); - } - - return diff; - } - - /** Sort stations by their available waiting cargo */ - static int CDECL StationWaitingAvailableSorter(const Station * const *a, const Station * const *b) - { - int diff = 0; - - CargoID j; - FOR_EACH_SET_CARGO_ID(j, cargo_filter) { - diff += (*a)->goods[j].cargo.AvailableCount() - (*b)->goods[j].cargo.AvailableCount(); - } - - return diff; - } - - /** Sort stations by their rating */ - static int CDECL StationRatingMaxSorter(const Station * const *a, const Station * const *b) - { - byte maxr1 = 0; - byte maxr2 = 0; - - CargoID j; - FOR_EACH_SET_CARGO_ID(j, cargo_filter) { - if ((*a)->goods[j].HasRating()) maxr1 = max(maxr1, (*a)->goods[j].rating); - if ((*b)->goods[j].HasRating()) maxr2 = max(maxr2, (*b)->goods[j].rating); - } - - return maxr1 - maxr2; - } - - /** Sort stations by their rating */ - static int CDECL StationRatingMinSorter(const Station * const *a, const Station * const *b) - { - byte minr1 = 255; - byte minr2 = 255; - - for (CargoID j = 0; j < NUM_CARGO; j++) { - if (!HasBit(cargo_filter, j)) continue; - if ((*a)->goods[j].HasRating()) minr1 = min(minr1, (*a)->goods[j].rating); - if ((*b)->goods[j].HasRating()) minr2 = min(minr2, (*b)->goods[j].rating); - } - - return -(minr1 - minr2); - } - - /** Sort the stations list */ - void SortStationsList() - { - if (!this->stations.Sort()) return; - - /* Reset name sorter sort cache */ - this->last_station = NULL; - - /* Set the modified widget dirty */ - this->SetWidgetDirty(WID_STL_LIST); - } - -public: - CompanyStationsWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) - { - this->stations.SetListing(this->last_sorting); - this->stations.SetSortFuncs(this->sorter_funcs); - this->stations.ForceRebuild(); - this->stations.NeedResort(); - this->SortStationsList(); - - this->CreateNestedTree(); - this->vscroll = this->GetScrollbar(WID_STL_SCROLLBAR); - this->FinishInitNested(window_number); - this->owner = (Owner)this->window_number; - - const CargoSpec *cs; - FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { - if (!HasBit(this->cargo_filter, cs->Index())) continue; - this->LowerWidget(WID_STL_CARGOSTART + index); - } - - if (this->cargo_filter == this->cargo_filter_max) this->cargo_filter = _cargo_mask; - - for (uint i = 0; i < 5; i++) { - if (HasBit(this->facilities, i)) this->LowerWidget(i + WID_STL_TRAIN); - } - this->SetWidgetLoweredState(WID_STL_NOCARGOWAITING, this->include_empty); - - this->GetWidget(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()]; - } - - ~CompanyStationsWindow() - { - this->last_sorting = this->stations.GetListing(); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_STL_SORTBY: { - Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); - d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - - case WID_STL_SORTDROPBTN: { - Dimension d = {0, 0}; - for (int i = 0; this->sorter_names[i] != INVALID_STRING_ID; i++) { - d = maxdim(d, GetStringBoundingBox(this->sorter_names[i])); - } - d.width += padding.width; - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - - case WID_STL_LIST: - resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; - break; - - case WID_STL_TRAIN: - case WID_STL_TRUCK: - case WID_STL_BUS: - case WID_STL_AIRPLANE: - case WID_STL_SHIP: - size->height = max(FONT_HEIGHT_SMALL, 10) + padding.height; - break; - - case WID_STL_CARGOALL: - case WID_STL_FACILALL: - case WID_STL_NOCARGOWAITING: { - Dimension d = GetStringBoundingBox(widget == WID_STL_NOCARGOWAITING ? STR_ABBREV_NONE : STR_ABBREV_ALL); - d.width += padding.width + 2; - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - - default: - if (widget >= WID_STL_CARGOSTART) { - Dimension d = GetStringBoundingBox(_sorted_cargo_specs[widget - WID_STL_CARGOSTART]->abbrev); - d.width += padding.width + 2; - d.height += padding.height; - *size = maxdim(*size, d); - } - break; - } - } - - virtual void OnPaint() - { - this->BuildStationsList((Owner)this->window_number); - this->SortStationsList(); - - this->DrawWidgets(); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_STL_SORTBY: - /* draw arrow pointing up/down for ascending/descending sorting */ - this->DrawSortButtonState(WID_STL_SORTBY, this->stations.IsDescSortOrder() ? SBS_DOWN : SBS_UP); - break; - - case WID_STL_LIST: { - int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.Length()); - uint line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - int y = Center(r.top + WD_FRAMERECT_TOP, line_height); - for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner - const Station *st = this->stations[i]; - assert(st->xy != INVALID_TILE); - - /* Do not do the complex check HasStationInUse here, it may be even false - * when the order had been removed and the station list hasn't been removed yet */ - assert(st->owner == owner || st->owner == OWNER_NONE); - - SetDParam(0, st->index); - SetDParam(1, st->facilities); - int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION); - - StationsWndShowStationRating(st, r.left, r.right, x, line_height + 2, y); - - y += line_height; - } - - if (this->vscroll->GetCount() == 0) { // company has no stations - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_NONE); - return; - } - break; - } - - case WID_STL_NOCARGOWAITING: { - int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1; - DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_NONE, TC_BLACK, SA_HOR_CENTER); - break; - } - - case WID_STL_CARGOALL: { - int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1; - DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER); - break; - } - - case WID_STL_FACILALL: { - int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1; - DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER); - break; - } - - default: - if (widget >= WID_STL_CARGOSTART) { - const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART]; - int cg_ofst = HasBit(this->cargo_filter, cs->Index()) ? 2 : 1; - GfxFillRect(r.left + cg_ofst, r.top + cg_ofst, r.right - 2 + cg_ofst, r.bottom - 2 + cg_ofst, cs->rating_colour); - TextColour tc = GetContrastColour(cs->rating_colour); - DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, cs->abbrev, tc, SA_HOR_CENTER); - } - break; - } - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_STL_CAPTION) { - SetDParam(0, this->window_number); - SetDParam(1, this->vscroll->GetCount()); - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_STL_LIST: { - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, this->resize.step_height); - if (id_v >= this->stations.Length()) return; // click out of list bound - - const Station *st = this->stations[id_v]; - /* do not check HasStationInUse - it is slow and may be invalid */ - assert(st->owner == (Owner)this->window_number || st->owner == OWNER_NONE); - - if (_ctrl_pressed) { - ShowExtraViewPortWindow(st->xy); - } else { - ScrollMainWindowToTile(st->xy); - } - break; - } - - case WID_STL_TRAIN: - case WID_STL_TRUCK: - case WID_STL_BUS: - case WID_STL_AIRPLANE: - case WID_STL_SHIP: - if (_ctrl_pressed) { - ToggleBit(this->facilities, widget - WID_STL_TRAIN); - this->ToggleWidgetLoweredState(widget); - } else { - uint i; - FOR_EACH_SET_BIT(i, this->facilities) { - this->RaiseWidget(i + WID_STL_TRAIN); - } - this->facilities = 1 << (widget - WID_STL_TRAIN); - this->LowerWidget(widget); - } - this->stations.ForceRebuild(); - this->SetDirty(); - break; - - case WID_STL_FACILALL: - for (uint i = WID_STL_TRAIN; i <= WID_STL_SHIP; i++) { - this->LowerWidget(i); - } - - this->facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK; - this->stations.ForceRebuild(); - this->SetDirty(); - break; - - case WID_STL_CARGOALL: { - for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { - this->LowerWidget(WID_STL_CARGOSTART + i); - } - this->LowerWidget(WID_STL_NOCARGOWAITING); - - this->cargo_filter = _cargo_mask; - this->include_empty = true; - this->stations.ForceRebuild(); - this->SetDirty(); - break; - } - - case WID_STL_SORTBY: // flip sorting method asc/desc - this->stations.ToggleSortOrder(); - this->SetDirty(); - break; - - case WID_STL_SORTDROPBTN: // select sorting criteria dropdown menu - ShowDropDownMenu(this, this->sorter_names, this->stations.SortType(), WID_STL_SORTDROPBTN, 0, 0); - break; - - case WID_STL_NOCARGOWAITING: - if (_ctrl_pressed) { - this->include_empty = !this->include_empty; - this->ToggleWidgetLoweredState(WID_STL_NOCARGOWAITING); - } else { - for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { - this->RaiseWidget(WID_STL_CARGOSTART + i); - } - - this->cargo_filter = 0; - this->include_empty = true; - - this->LowerWidget(WID_STL_NOCARGOWAITING); - } - this->stations.ForceRebuild(); - this->SetDirty(); - break; - - default: - if (widget >= WID_STL_CARGOSTART) { // change cargo_filter - /* Determine the selected cargo type */ - const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART]; - - if (_ctrl_pressed) { - ToggleBit(this->cargo_filter, cs->Index()); - this->ToggleWidgetLoweredState(widget); - } else { - for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { - this->RaiseWidget(WID_STL_CARGOSTART + i); - } - this->RaiseWidget(WID_STL_NOCARGOWAITING); - - this->cargo_filter = 0; - this->include_empty = false; - - SetBit(this->cargo_filter, cs->Index()); - this->LowerWidget(widget); - } - this->stations.ForceRebuild(); - this->SetDirty(); - } - break; - } - } - - virtual void OnDropdownSelect(int widget, int index) - { - if (this->stations.SortType() != index) { - this->stations.SetSortType(index); - - /* Display the current sort variant */ - this->GetWidget(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()]; - - this->SetDirty(); - } - } - - virtual void OnTick() - { - if (_pause_mode != PM_UNPAUSED) return; - if (this->stations.NeedResort()) { - DEBUG(misc, 3, "Periodic rebuild station list company %d", this->window_number); - this->SetDirty(); - } - } - - virtual void OnResize() - { - this->vscroll->SetCapacityFromWidget(this, WID_STL_LIST, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (data == 0) { - /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ - this->stations.ForceRebuild(); - } else { - this->stations.ForceResort(); - } - } -}; - -Listing CompanyStationsWindow::last_sorting = {false, 0}; -byte CompanyStationsWindow::facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK; -bool CompanyStationsWindow::include_empty = true; -const uint32 CompanyStationsWindow::cargo_filter_max = UINT32_MAX; -uint32 CompanyStationsWindow::cargo_filter = UINT32_MAX; -const Station *CompanyStationsWindow::last_station = NULL; - -/* Availible station sorting functions */ -GUIStationList::SortFunction * const CompanyStationsWindow::sorter_funcs[] = { - &StationNameSorter, - &StationTypeSorter, - &StationWaitingTotalSorter, - &StationWaitingAvailableSorter, - &StationRatingMaxSorter, - &StationRatingMinSorter -}; - -/* Names of the sorting functions */ -const StringID CompanyStationsWindow::sorter_names[] = { - STR_SORT_BY_NAME, - STR_SORT_BY_FACILITY, - STR_SORT_BY_WAITING_TOTAL, - STR_SORT_BY_WAITING_AVAILABLE, - STR_SORT_BY_RATING_MAX, - STR_SORT_BY_RATING_MIN, - INVALID_STRING_ID -}; - -/** - * Make a horizontal row of cargo buttons, starting at widget #WID_STL_CARGOSTART. - * @param biggest_index Pointer to store biggest used widget number of the buttons. - * @return Horizontal row. - */ -static NWidgetBase *CargoWidgets(int *biggest_index) -{ - NWidgetHorizontal *container = new NWidgetHorizontal(); - - for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { - NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_STL_CARGOSTART + i); - panel->SetMinimalSize(14, 11); - panel->SetResize(0, 0); - panel->SetFill(0, 1); - panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE); - container->Add(panel); - } - *biggest_index = WID_STL_CARGOSTART + _sorted_standard_cargo_specs_size; - return container; -} - -static const NWidgetPart _nested_company_stations_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, WID_STL_CAPTION), SetDataTip(STR_STATION_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_GREY), - NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), - NWidget(WWT_STICKYBOX, COLOUR_GREY), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRAIN), SetMinimalSize(14, 11), SetDataTip(STR_TRAIN, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRUCK), SetMinimalSize(14, 11), SetDataTip(STR_LORRY, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_BUS), SetMinimalSize(14, 11), SetDataTip(STR_BUS, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_SHIP), SetMinimalSize(14, 11), SetDataTip(STR_SHIP, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetMinimalSize(14, 11), SetDataTip(STR_PLANE, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), - NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetFill(0, 1), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 11), SetFill(0, 1), EndContainer(), - NWidgetFunction(CargoWidgets), - NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_NOCARGOWAITING), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), SetFill(0, 1), EndContainer(), - NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_CARGOALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_TYPES), SetFill(0, 1), - NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_SORTDROPBTN), SetMinimalSize(163, 12), SetDataTip(STR_SORT_BY_NAME, STR_TOOLTIP_SORT_CRITERIA), // widget_data gets overwritten. - NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_LIST), SetMinimalSize(346, 125), SetResize(1, 10), SetDataTip(0x0, STR_STATION_LIST_TOOLTIP), SetScrollbar(WID_STL_SCROLLBAR), EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_STL_SCROLLBAR), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), - EndContainer(), - EndContainer(), -}; - -static WindowDesc _company_stations_desc( - WDP_AUTO, "list_stations", 358, 162, - WC_STATION_LIST, WC_NONE, - 0, - _nested_company_stations_widgets, lengthof(_nested_company_stations_widgets) -); - -/** - * Opens window with list of company's stations - * - * @param company whose stations' list show - */ -void ShowCompanyStations(CompanyID company) -{ - if (!Company::IsValidID(company)) return; - - AllocateWindowDescFront(&_company_stations_desc, company); -} - -static const NWidgetPart _nested_station_view_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, WID_SV_CAPTION), SetDataTip(STR_STATION_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_GREY), - NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), - NWidget(WWT_STICKYBOX, COLOUR_GREY), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(1, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_GROUP), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_STATION_VIEW_GROUP, 0x0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_GROUP_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(1, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_SV_WAITING), SetMinimalSize(237, 44), SetResize(1, 10), SetScrollbar(WID_SV_SCROLLBAR), EndContainer(), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SV_SCROLLBAR), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_SV_ACCEPT_RATING_LIST), SetMinimalSize(249, 23), SetResize(1, 0), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_LOCATION), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1), - SetDataTip(STR_BUTTON_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ACCEPTS_RATINGS), SetMinimalSize(46, 12), SetResize(1, 0), SetFill(1, 1), - SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_RENAME), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1), - SetDataTip(STR_BUTTON_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP), - EndContainer(), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1), - SetDataTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_TRAINS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ROADVEHS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SHIPS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_PLANES), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_PLANE, STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), - EndContainer(), -}; - -/** - * Draws icons of waiting cargo in the StationView window - * - * @param i type of cargo - * @param waiting number of waiting units - * @param left left most coordinate to draw on - * @param right right most coordinate to draw on - * @param y y coordinate - * @param width the width of the view - */ -static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int y) -{ - uint num = min((waiting + 5) / 10, (right - left) / 10); // maximum is width / 10 icons so it won't overflow - if (num == 0) return; - - SpriteID sprite = CargoSpec::Get(i)->GetCargoIcon(); - - int x = _current_text_dir == TD_RTL ? left : right - num * 10; - do { - DrawSprite(sprite, PAL_NONE, x, y); - x += 10; - } while (--num); -} - -enum SortOrder { - SO_DESCENDING, - SO_ASCENDING -}; - -class CargoDataEntry; - -enum CargoSortType { - ST_AS_GROUPING, ///< by the same principle the entries are being grouped - ST_COUNT, ///< by amount of cargo - ST_STATION_STRING, ///< by station name - ST_STATION_ID, ///< by station id - ST_CARGO_ID, ///< by cargo id -}; - -class CargoSorter { -public: - CargoSorter(CargoSortType t = ST_STATION_ID, SortOrder o = SO_ASCENDING) : type(t), order(o) {} - CargoSortType GetSortType() {return this->type;} - bool operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const; - -private: - CargoSortType type; - SortOrder order; - - template - bool SortId(Tid st1, Tid st2) const; - bool SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const; - bool SortStation (StationID st1, StationID st2) const; -}; - -typedef std::set CargoDataSet; - -/** - * A cargo data entry representing one possible row in the station view window's - * top part. Cargo data entries form a tree where each entry can have several - * children. Parents keep track of the sums of their childrens' cargo counts. - */ -class CargoDataEntry { -public: - CargoDataEntry(); - ~CargoDataEntry(); - - /** - * Insert a new child or retrieve an existing child using a station ID as ID. - * @param station ID of the station for which an entry shall be created or retrieved - * @return a child entry associated with the given station. - */ - CargoDataEntry *InsertOrRetrieve(StationID station) - { - return this->InsertOrRetrieve(station); - } - - /** - * Insert a new child or retrieve an existing child using a cargo ID as ID. - * @param cargo ID of the cargo for which an entry shall be created or retrieved - * @return a child entry associated with the given cargo. - */ - CargoDataEntry *InsertOrRetrieve(CargoID cargo) - { - return this->InsertOrRetrieve(cargo); - } - - void Update(uint count); - - /** - * Remove a child associated with the given station. - * @param station ID of the station for which the child should be removed. - */ - void Remove(StationID station) - { - CargoDataEntry t(station); - this->Remove(&t); - } - - /** - * Remove a child associated with the given cargo. - * @param cargo ID of the cargo for which the child should be removed. - */ - void Remove(CargoID cargo) - { - CargoDataEntry t(cargo); - this->Remove(&t); - } - - /** - * Retrieve a child for the given station. Return NULL if it doesn't exist. - * @param station ID of the station the child we're looking for is associated with. - * @return a child entry for the given station or NULL. - */ - CargoDataEntry *Retrieve(StationID station) const - { - CargoDataEntry t(station); - return this->Retrieve(this->children->find(&t)); - } - - /** - * Retrieve a child for the given cargo. Return NULL if it doesn't exist. - * @param cargo ID of the cargo the child we're looking for is associated with. - * @return a child entry for the given cargo or NULL. - */ - CargoDataEntry *Retrieve(CargoID cargo) const - { - CargoDataEntry t(cargo); - return this->Retrieve(this->children->find(&t)); - } - - void Resort(CargoSortType type, SortOrder order); - - /** - * Get the station ID for this entry. - */ - StationID GetStation() const { return this->station; } - - /** - * Get the cargo ID for this entry. - */ - CargoID GetCargo() const { return this->cargo; } - - /** - * Get the cargo count for this entry. - */ - uint GetCount() const { return this->count; } - - /** - * Get the parent entry for this entry. - */ - CargoDataEntry *GetParent() const { return this->parent; } - - /** - * Get the number of children for this entry. - */ - uint GetNumChildren() const { return this->num_children; } - - /** - * Get an iterator pointing to the begin of the set of children. - */ - CargoDataSet::iterator Begin() const { return this->children->begin(); } - - /** - * Get an iterator pointing to the end of the set of children. - */ - CargoDataSet::iterator End() const { return this->children->end(); } - - /** - * Has this entry transfers. - */ - bool HasTransfers() const { return this->transfers; } - - /** - * Set the transfers state. - */ - void SetTransfers(bool value) { this->transfers = value; } - - void Clear(); -private: - - CargoDataEntry(StationID st, uint c, CargoDataEntry *p); - CargoDataEntry(CargoID car, uint c, CargoDataEntry *p); - CargoDataEntry(StationID st); - CargoDataEntry(CargoID car); - - CargoDataEntry *Retrieve(CargoDataSet::iterator i) const; - - template - CargoDataEntry *InsertOrRetrieve(Tid s); - - void Remove(CargoDataEntry *comp); - void IncrementSize(); - - CargoDataEntry *parent; ///< the parent of this entry. - const union { - StationID station; ///< ID of the station this entry is associated with. - struct { - CargoID cargo; ///< ID of the cargo this entry is associated with. - bool transfers; ///< If there are transfers for this cargo. - }; - }; - uint num_children; ///< the number of subentries belonging to this entry. - uint count; ///< sum of counts of all children or amount of cargo for this entry. - CargoDataSet *children; ///< the children of this entry. -}; - -CargoDataEntry::CargoDataEntry() : - parent(NULL), - station(INVALID_STATION), - num_children(0), - count(0), - children(new CargoDataSet(CargoSorter(ST_CARGO_ID))) -{} - -CargoDataEntry::CargoDataEntry(CargoID cargo, uint count, CargoDataEntry *parent) : - parent(parent), - cargo(cargo), - num_children(0), - count(count), - children(new CargoDataSet) -{} - -CargoDataEntry::CargoDataEntry(StationID station, uint count, CargoDataEntry *parent) : - parent(parent), - station(station), - num_children(0), - count(count), - children(new CargoDataSet) -{} - -CargoDataEntry::CargoDataEntry(StationID station) : - parent(NULL), - station(station), - num_children(0), - count(0), - children(NULL) -{} - -CargoDataEntry::CargoDataEntry(CargoID cargo) : - parent(NULL), - cargo(cargo), - num_children(0), - count(0), - children(NULL) -{} - -CargoDataEntry::~CargoDataEntry() -{ - this->Clear(); - delete this->children; -} - -/** - * Delete all subentries, reset count and num_children and adapt parent's count. - */ -void CargoDataEntry::Clear() -{ - if (this->children != NULL) { - for (CargoDataSet::iterator i = this->children->begin(); i != this->children->end(); ++i) { - assert(*i != this); - delete *i; - } - this->children->clear(); - } - if (this->parent != NULL) this->parent->count -= this->count; - this->count = 0; - this->num_children = 0; -} - -/** - * Remove a subentry from this one and delete it. - * @param child the entry to be removed. This may also be a synthetic entry - * which only contains the ID of the entry to be removed. In this case child is - * not deleted. - */ -void CargoDataEntry::Remove(CargoDataEntry *child) -{ - CargoDataSet::iterator i = this->children->find(child); - if (i != this->children->end()) { - delete *i; - this->children->erase(i); - } -} - -/** - * Retrieve a subentry or insert it if it doesn't exist, yet. - * @tparam ID type of ID: either StationID or CargoID - * @param child_id ID of the child to be inserted or retrieved. - * @return the new or retrieved subentry - */ -template -CargoDataEntry *CargoDataEntry::InsertOrRetrieve(Tid child_id) -{ - CargoDataEntry tmp(child_id); - CargoDataSet::iterator i = this->children->find(&tmp); - if (i == this->children->end()) { - IncrementSize(); - return *(this->children->insert(new CargoDataEntry(child_id, 0, this)).first); - } else { - CargoDataEntry *ret = *i; - assert(this->children->value_comp().GetSortType() != ST_COUNT); - return ret; - } -} - -/** - * Update the count for this entry and propagate the change to the parent entry - * if there is one. - * @param count the amount to be added to this entry - */ -void CargoDataEntry::Update(uint count) -{ - this->count += count; - if (this->parent != NULL) this->parent->Update(count); -} - -/** - * Increment - */ -void CargoDataEntry::IncrementSize() -{ - ++this->num_children; - if (this->parent != NULL) this->parent->IncrementSize(); -} - -void CargoDataEntry::Resort(CargoSortType type, SortOrder order) -{ - CargoDataSet *new_subs = new CargoDataSet(this->children->begin(), this->children->end(), CargoSorter(type, order)); - delete this->children; - this->children = new_subs; -} - -CargoDataEntry *CargoDataEntry::Retrieve(CargoDataSet::iterator i) const -{ - if (i == this->children->end()) { - return NULL; - } else { - assert(this->children->value_comp().GetSortType() != ST_COUNT); - return *i; - } -} - -bool CargoSorter::operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const -{ - switch (this->type) { - case ST_STATION_ID: - return this->SortId(cd1->GetStation(), cd2->GetStation()); - case ST_CARGO_ID: - return this->SortId(cd1->GetCargo(), cd2->GetCargo()); - case ST_COUNT: - return this->SortCount(cd1, cd2); - case ST_STATION_STRING: - return this->SortStation(cd1->GetStation(), cd2->GetStation()); - default: - NOT_REACHED(); - } -} - -template -bool CargoSorter::SortId(Tid st1, Tid st2) const -{ - return (this->order == SO_ASCENDING) ? st1 < st2 : st2 < st1; -} - -bool CargoSorter::SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const -{ - uint c1 = cd1->GetCount(); - uint c2 = cd2->GetCount(); - if (c1 == c2) { - return this->SortStation(cd1->GetStation(), cd2->GetStation()); - } else if (this->order == SO_ASCENDING) { - return c1 < c2; - } else { - return c2 < c1; - } -} - -bool CargoSorter::SortStation(StationID st1, StationID st2) const -{ - static char buf1[MAX_LENGTH_STATION_NAME_CHARS]; - static char buf2[MAX_LENGTH_STATION_NAME_CHARS]; - - if (!Station::IsValidID(st1)) { - return Station::IsValidID(st2) ? this->order == SO_ASCENDING : this->SortId(st1, st2); - } else if (!Station::IsValidID(st2)) { - return order == SO_DESCENDING; - } - - SetDParam(0, st1); - GetString(buf1, STR_STATION_NAME, lastof(buf1)); - SetDParam(0, st2); - GetString(buf2, STR_STATION_NAME, lastof(buf2)); - - int res = strcmp(buf1, buf2); - if (res == 0) { - return this->SortId(st1, st2); - } else { - return (this->order == SO_ASCENDING) ? res < 0 : res > 0; - } -} - -/** - * The StationView window - */ -struct StationViewWindow : public Window { - /** - * A row being displayed in the cargo view (as opposed to being "hidden" behind a plus sign). - */ - struct RowDisplay { - RowDisplay(CargoDataEntry *f, StationID n) : filter(f), next_station(n) {} - RowDisplay(CargoDataEntry *f, CargoID n) : filter(f), next_cargo(n) {} - - /** - * Parent of the cargo entry belonging to the row. - */ - CargoDataEntry *filter; - union { - /** - * ID of the station belonging to the entry actually displayed if it's to/from/via. - */ - StationID next_station; - - /** - * ID of the cargo belonging to the entry actually displayed if it's cargo. - */ - CargoID next_cargo; - }; - }; - - typedef std::vector CargoDataVector; - - static const int NUM_COLUMNS = 4; ///< Number of "columns" in the cargo view: cargo, from, via, to - - /** - * Type of data invalidation. - */ - enum Invalidation { - INV_FLOWS = 0x100, ///< The planned flows have been recalculated and everything has to be updated. - INV_CARGO = 0x200 ///< Some cargo has been added or removed. - }; - - /** - * Type of grouping used in each of the "columns". - */ - enum Grouping { - GR_SOURCE, ///< Group by source of cargo ("from"). - GR_NEXT, ///< Group by next station ("via"). - GR_DESTINATION, ///< Group by estimated final destination ("to"). - GR_CARGO, ///< Group by cargo type. - }; - - /** - * Display mode of the cargo view. - */ - enum Mode { - MODE_WAITING, ///< Show cargo waiting at the station. - MODE_PLANNED ///< Show cargo planned to pass through the station. - }; - - uint expand_shrink_width; ///< The width allocated to the expand/shrink 'button' - int rating_lines; ///< Number of lines in the cargo ratings view. - int accepts_lines; ///< Number of lines in the accepted cargo view. - Scrollbar *vscroll; - - /** Height of the #WID_SV_ACCEPT_RATING_LIST widget for different views. */ - enum AcceptListHeight { - ALH_RATING = 13, ///< Height of the cargo ratings view. - ALH_ACCEPTS = 3, ///< Height of the accepted cargo view. - }; - - static const StringID _sort_names[]; ///< Names of the sorting options in the dropdown. - static const StringID _group_names[]; ///< Names of the grouping options in the dropdown. - - /** - * Sort types of the different 'columns'. - * In fact only ST_COUNT and ST_AS_GROUPING are active and you can only - * sort all the columns in the same way. The other options haven't been - * included in the GUI due to lack of space. - */ - CargoSortType sortings[NUM_COLUMNS]; - - /** Sort order (ascending/descending) for the 'columns'. */ - SortOrder sort_orders[NUM_COLUMNS]; - - int scroll_to_row; ///< If set, scroll the main viewport to the station pointed to by this row. - int grouping_index; ///< Currently selected entry in the grouping drop down. - Mode current_mode; ///< Currently selected display mode of cargo view. - Grouping groupings[NUM_COLUMNS]; ///< Grouping modes for the different columns. - - CargoDataEntry expanded_rows; ///< Parent entry of currently expanded rows. - CargoDataEntry cached_destinations; ///< Cache for the flows passing through this station. - CargoDataVector displayed_rows; ///< Parent entry of currently displayed rows (including collapsed ones). - - StationViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), - scroll_to_row(INT_MAX), grouping_index(0) - { - this->rating_lines = ALH_RATING; - this->accepts_lines = ALH_ACCEPTS; - - this->CreateNestedTree(); - this->vscroll = this->GetScrollbar(WID_SV_SCROLLBAR); - /* Nested widget tree creation is done in two steps to ensure that this->GetWidget(WID_SV_ACCEPTS_RATINGS) exists in UpdateWidgetSize(). */ - this->FinishInitNested(window_number); - - this->groupings[0] = GR_CARGO; - this->sortings[0] = ST_AS_GROUPING; - this->SelectGroupBy(_settings_client.gui.station_gui_group_order); - this->SelectSortBy(_settings_client.gui.station_gui_sort_by); - this->sort_orders[0] = SO_ASCENDING; - this->SelectSortOrder((SortOrder)_settings_client.gui.station_gui_sort_order); - Owner owner = Station::Get(window_number)->owner; - if (owner != OWNER_NONE) this->owner = owner; - } - - ~StationViewWindow() - { - Owner owner = Station::Get(this->window_number)->owner; - DeleteWindowById(WC_TRAINS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_TRAIN, owner, this->window_number).Pack(), false); - DeleteWindowById(WC_ROADVEH_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_ROAD, owner, this->window_number).Pack(), false); - DeleteWindowById(WC_SHIPS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_SHIP, owner, this->window_number).Pack(), false); - DeleteWindowById(WC_AIRCRAFT_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_AIRCRAFT, owner, this->window_number).Pack(), false); - } - - /** - * Show a certain cargo entry characterized by source/next/dest station, cargo ID and amount of cargo at the - * right place in the cargo view. I.e. update as many rows as are expanded following that characterization. - * @param data Root entry of the tree. - * @param cargo Cargo ID of the entry to be shown. - * @param source Source station of the entry to be shown. - * @param next Next station the cargo to be shown will visit. - * @param dest Final destination of the cargo to be shown. - * @param count Amount of cargo to be shown. - */ - void ShowCargo(CargoDataEntry *data, CargoID cargo, StationID source, StationID next, StationID dest, uint count) - { - if (count == 0) return; - bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL; - const CargoDataEntry *expand = &this->expanded_rows; - for (int i = 0; i < NUM_COLUMNS && expand != NULL; ++i) { - switch (groupings[i]) { - case GR_CARGO: - assert(i == 0); - data = data->InsertOrRetrieve(cargo); - data->SetTransfers(source != this->window_number); - expand = expand->Retrieve(cargo); - break; - case GR_SOURCE: - if (auto_distributed || source != this->window_number) { - data = data->InsertOrRetrieve(source); - expand = expand->Retrieve(source); - } - break; - case GR_NEXT: - if (auto_distributed) { - data = data->InsertOrRetrieve(next); - expand = expand->Retrieve(next); - } - break; - case GR_DESTINATION: - if (auto_distributed) { - data = data->InsertOrRetrieve(dest); - expand = expand->Retrieve(dest); - } - break; - } - } - data->Update(count); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_SV_WAITING: - resize->height = FONT_HEIGHT_NORMAL; - size->height = WD_FRAMERECT_TOP + 4 * resize->height + WD_FRAMERECT_BOTTOM; - this->expand_shrink_width = max(GetStringBoundingBox("-").width, GetStringBoundingBox("+").width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - break; - - case WID_SV_ACCEPT_RATING_LIST: - size->height = WD_FRAMERECT_TOP + ((this->GetWidget(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) ? this->accepts_lines : this->rating_lines) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; - break; - - case WID_SV_CLOSE_AIRPORT: - if (!(Station::Get(this->window_number)->facilities & FACIL_AIRPORT)) { - /* Hide 'Close Airport' button if no airport present. */ - size->width = 0; - resize->width = 0; - fill->width = 0; - } - break; - - case WID_SV_SORT_ORDER: - case WID_SV_GROUP: - *size = maxdim(GetStringBoundingBox(STR_BUTTON_SORT_BY), GetStringBoundingBox(STR_STATION_VIEW_GROUP)); - size->width += padding.width; - break; - } - } - - virtual void OnPaint() - { - const Station *st = Station::Get(this->window_number); - CargoDataEntry cargo; - BuildCargoList(&cargo, st); - - this->vscroll->SetCount(cargo.GetNumChildren()); // update scrollbar - - /* disable some buttons */ - this->SetWidgetDisabledState(WID_SV_RENAME, st->owner != _local_company); - this->SetWidgetDisabledState(WID_SV_TRAINS, !(st->facilities & FACIL_TRAIN)); - this->SetWidgetDisabledState(WID_SV_ROADVEHS, !(st->facilities & FACIL_TRUCK_STOP) && !(st->facilities & FACIL_BUS_STOP)); - this->SetWidgetDisabledState(WID_SV_SHIPS, !(st->facilities & FACIL_DOCK)); - this->SetWidgetDisabledState(WID_SV_PLANES, !(st->facilities & FACIL_AIRPORT)); - this->SetWidgetDisabledState(WID_SV_CLOSE_AIRPORT, !(st->facilities & FACIL_AIRPORT) || st->owner != _local_company || st->owner == OWNER_NONE); // Also consider SE, where _local_company == OWNER_NONE - this->SetWidgetLoweredState(WID_SV_CLOSE_AIRPORT, (st->facilities & FACIL_AIRPORT) && (st->airport.flags & AIRPORT_CLOSED_block) != 0); - - this->DrawWidgets(); - - if (!this->IsShaded()) { - /* Draw 'accepted cargo' or 'cargo ratings'. */ - const NWidgetBase *wid = this->GetWidget(WID_SV_ACCEPT_RATING_LIST); - const Rect r = {wid->pos_x, wid->pos_y, wid->pos_x + wid->current_x - 1, wid->pos_y + wid->current_y - 1}; - if (this->GetWidget(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) { - int lines = this->DrawAcceptedCargo(r); - if (lines > this->accepts_lines) { // Resize the widget, and perform re-initialization of the window. - this->accepts_lines = lines; - this->ReInit(); - return; - } - } else { - int lines = this->DrawCargoRatings(r); - if (lines > this->rating_lines) { // Resize the widget, and perform re-initialization of the window. - this->rating_lines = lines; - this->ReInit(); - return; - } - } - - /* Draw arrow pointing up/down for ascending/descending sorting */ - this->DrawSortButtonState(WID_SV_SORT_ORDER, sort_orders[1] == SO_ASCENDING ? SBS_UP : SBS_DOWN); - - int pos = this->vscroll->GetPosition(); - - int maxrows = this->vscroll->GetCapacity(); - - displayed_rows.clear(); - - /* Draw waiting cargo. */ - NWidgetBase *nwi = this->GetWidget(WID_SV_WAITING); - Rect waiting_rect = {nwi->pos_x, nwi->pos_y, nwi->pos_x + nwi->current_x - 1, nwi->pos_y + nwi->current_y - 1}; - this->DrawEntries(&cargo, waiting_rect, pos, maxrows, 0); - scroll_to_row = INT_MAX; - } - } - - virtual void SetStringParameters(int widget) const - { - const Station *st = Station::Get(this->window_number); - SetDParam(0, st->index); - SetDParam(1, st->facilities); - } - - /** - * Rebuild the cache for estimated destinations which is used to quickly show the "destination" entries - * even if we actually don't know the destination of a certain packet from just looking at it. - * @param i Cargo to recalculate the cache for. - */ - void RecalcDestinations(CargoID i) - { - const Station *st = Station::Get(this->window_number); - CargoDataEntry *cargo_entry = cached_destinations.InsertOrRetrieve(i); - cargo_entry->Clear(); - - const FlowStatMap &flows = st->goods[i].flows; - for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) { - StationID from = it->first; - CargoDataEntry *source_entry = cargo_entry->InsertOrRetrieve(from); - const FlowStat::SharesMap *shares = it->second.GetShares(); - uint32 prev_count = 0; - for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) { - StationID via = flow_it->second; - CargoDataEntry *via_entry = source_entry->InsertOrRetrieve(via); - if (via == this->window_number) { - via_entry->InsertOrRetrieve(via)->Update(flow_it->first - prev_count); - } else { - EstimateDestinations(i, from, via, flow_it->first - prev_count, via_entry); - } - prev_count = flow_it->first; - } - } - } - - /** - * Estimate the amounts of cargo per final destination for a given cargo, source station and next hop and - * save the result as children of the given CargoDataEntry. - * @param cargo ID of the cargo to estimate destinations for. - * @param source Source station of the given batch of cargo. - * @param next Intermediate hop to start the calculation at ("next hop"). - * @param count Size of the batch of cargo. - * @param dest CargoDataEntry to save the results in. - */ - void EstimateDestinations(CargoID cargo, StationID source, StationID next, uint count, CargoDataEntry *dest) - { - if (Station::IsValidID(next) && Station::IsValidID(source)) { - CargoDataEntry tmp; - const FlowStatMap &flowmap = Station::Get(next)->goods[cargo].flows; - FlowStatMap::const_iterator map_it = flowmap.find(source); - if (map_it != flowmap.end()) { - const FlowStat::SharesMap *shares = map_it->second.GetShares(); - uint32 prev_count = 0; - for (FlowStat::SharesMap::const_iterator i = shares->begin(); i != shares->end(); ++i) { - tmp.InsertOrRetrieve(i->second)->Update(i->first - prev_count); - prev_count = i->first; - } - } - - if (tmp.GetCount() == 0) { - dest->InsertOrRetrieve(INVALID_STATION)->Update(count); - } else { - uint sum_estimated = 0; - while (sum_estimated < count) { - for (CargoDataSet::iterator i = tmp.Begin(); i != tmp.End() && sum_estimated < count; ++i) { - CargoDataEntry *child = *i; - uint estimate = DivideApprox(child->GetCount() * count, tmp.GetCount()); - if (estimate == 0) estimate = 1; - - sum_estimated += estimate; - if (sum_estimated > count) { - estimate -= sum_estimated - count; - sum_estimated = count; - } - - if (estimate > 0) { - if (child->GetStation() == next) { - dest->InsertOrRetrieve(next)->Update(estimate); - } else { - EstimateDestinations(cargo, source, child->GetStation(), estimate, dest); - } - } - } - - } - } - } else { - dest->InsertOrRetrieve(INVALID_STATION)->Update(count); - } - } - - /** - * Build up the cargo view for PLANNED mode and a specific cargo. - * @param i Cargo to show. - * @param flows The current station's flows for that cargo. - * @param cargo The CargoDataEntry to save the results in. - */ - void BuildFlowList(CargoID i, const FlowStatMap &flows, CargoDataEntry *cargo) - { - const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i); - for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) { - StationID from = it->first; - const CargoDataEntry *source_entry = source_dest->Retrieve(from); - const FlowStat::SharesMap *shares = it->second.GetShares(); - for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) { - const CargoDataEntry *via_entry = source_entry->Retrieve(flow_it->second); - for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) { - CargoDataEntry *dest_entry = *dest_it; - ShowCargo(cargo, i, from, flow_it->second, dest_entry->GetStation(), dest_entry->GetCount()); - } - } - } - } - - /** - * Build up the cargo view for WAITING mode and a specific cargo. - * @param i Cargo to show. - * @param packets The current station's cargo list for that cargo. - * @param cargo The CargoDataEntry to save the result in. - */ - void BuildCargoList(CargoID i, const StationCargoList &packets, CargoDataEntry *cargo) - { - const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i); - for (StationCargoList::ConstIterator it = packets.Packets()->begin(); it != packets.Packets()->end(); it++) { - const CargoPacket *cp = *it; - StationID next = it.GetKey(); - - const CargoDataEntry *source_entry = source_dest->Retrieve(cp->SourceStation()); - if (source_entry == NULL) { - this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count()); - continue; - } - - const CargoDataEntry *via_entry = source_entry->Retrieve(next); - if (via_entry == NULL) { - this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count()); - continue; - } - - for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) { - CargoDataEntry *dest_entry = *dest_it; - uint val = DivideApprox(cp->Count() * dest_entry->GetCount(), via_entry->GetCount()); - this->ShowCargo(cargo, i, cp->SourceStation(), next, dest_entry->GetStation(), val); - } - } - this->ShowCargo(cargo, i, NEW_STATION, NEW_STATION, NEW_STATION, packets.ReservedCount()); - } - - /** - * Build up the cargo view for all cargoes. - * @param cargo The root cargo entry to save all results in. - * @param st The station to calculate the cargo view from. - */ - void BuildCargoList(CargoDataEntry *cargo, const Station *st) - { - for (CargoID i = 0; i < NUM_CARGO; i++) { - - if (this->cached_destinations.Retrieve(i) == NULL) { - this->RecalcDestinations(i); - } - - if (this->current_mode == MODE_WAITING) { - this->BuildCargoList(i, st->goods[i].cargo, cargo); - } else { - this->BuildFlowList(i, st->goods[i].flows, cargo); - } - } - } - - /** - * Mark a specific row, characterized by its CargoDataEntry, as expanded. - * @param data The row to be marked as expanded. - */ - void SetDisplayedRow(const CargoDataEntry *data) - { - std::list stations; - const CargoDataEntry *parent = data->GetParent(); - if (parent->GetParent() == NULL) { - this->displayed_rows.push_back(RowDisplay(&this->expanded_rows, data->GetCargo())); - return; - } - - StationID next = data->GetStation(); - while (parent->GetParent()->GetParent() != NULL) { - stations.push_back(parent->GetStation()); - parent = parent->GetParent(); - } - - CargoID cargo = parent->GetCargo(); - CargoDataEntry *filter = this->expanded_rows.Retrieve(cargo); - while (!stations.empty()) { - filter = filter->Retrieve(stations.back()); - stations.pop_back(); - } - - this->displayed_rows.push_back(RowDisplay(filter, next)); - } - - /** - * Select the correct string for an entry referring to the specified station. - * @param station Station the entry is showing cargo for. - * @param here String to be shown if the entry refers to the same station as this station GUI belongs to. - * @param other_station String to be shown if the entry refers to a specific other station. - * @param any String to be shown if the entry refers to "any station". - * @return One of the three given strings or STR_STATION_VIEW_RESERVED, depending on what station the entry refers to. - */ - StringID GetEntryString(StationID station, StringID here, StringID other_station, StringID any) - { - if (station == this->window_number) { - return here; - } else if (station == INVALID_STATION) { - return any; - } else if (station == NEW_STATION) { - return STR_STATION_VIEW_RESERVED; - } else { - SetDParam(2, station); - return other_station; - } - } - - /** - * Determine if we need to show the special "non-stop" string. - * @param cd Entry we are going to show. - * @param station Station the entry refers to. - * @param column The "column" the entry will be shown in. - * @return either STR_STATION_VIEW_VIA or STR_STATION_VIEW_NONSTOP. - */ - StringID SearchNonStop(CargoDataEntry *cd, StationID station, int column) - { - CargoDataEntry *parent = cd->GetParent(); - for (int i = column - 1; i > 0; --i) { - if (this->groupings[i] == GR_DESTINATION) { - if (parent->GetStation() == station) { - return STR_STATION_VIEW_NONSTOP; - } else { - return STR_STATION_VIEW_VIA; - } - } - parent = parent->GetParent(); - } - - if (this->groupings[column + 1] == GR_DESTINATION) { - CargoDataSet::iterator begin = cd->Begin(); - CargoDataSet::iterator end = cd->End(); - if (begin != end && ++(cd->Begin()) == end && (*(begin))->GetStation() == station) { - return STR_STATION_VIEW_NONSTOP; - } else { - return STR_STATION_VIEW_VIA; - } - } - - return STR_STATION_VIEW_VIA; - } - - /** - * Draw the given cargo entries in the station GUI. - * @param entry Root entry for all cargo to be drawn. - * @param r Screen rectangle to draw into. - * @param pos Current row to be drawn to (counted down from 0 to -maxrows, same as vscroll->GetPosition()). - * @param maxrows Maximum row to be drawn. - * @param column Current "column" being drawn. - * @param cargo Current cargo being drawn (if cargo column has been passed). - * @return row (in "pos" counting) after the one we have last drawn to. - */ - int DrawEntries(CargoDataEntry *entry, Rect &r, int pos, int maxrows, int column, CargoID cargo = CT_INVALID) - { - if (this->sortings[column] == ST_AS_GROUPING) { - if (this->groupings[column] != GR_CARGO) { - entry->Resort(ST_STATION_STRING, this->sort_orders[column]); - } - } else { - entry->Resort(ST_COUNT, this->sort_orders[column]); - } - for (CargoDataSet::iterator i = entry->Begin(); i != entry->End(); ++i) { - CargoDataEntry *cd = *i; - - Grouping grouping = this->groupings[column]; - if (grouping == GR_CARGO) cargo = cd->GetCargo(); - bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL; - - if (pos > -maxrows && pos <= 0) { - StringID str = STR_EMPTY; - int y = r.top + WD_FRAMERECT_TOP - pos * FONT_HEIGHT_NORMAL; - SetDParam(0, cargo); - SetDParam(1, cd->GetCount()); - - if (this->groupings[column] == GR_CARGO) { - str = STR_STATION_VIEW_WAITING_CARGO; - DrawCargoIcons(cd->GetCargo(), cd->GetCount(), r.left + WD_FRAMERECT_LEFT + this->expand_shrink_width, r.right - WD_FRAMERECT_RIGHT - this->expand_shrink_width, y); - } else { - if (!auto_distributed) grouping = GR_SOURCE; - StationID station = cd->GetStation(); - - switch (grouping) { - case GR_SOURCE: - str = this->GetEntryString(station, STR_STATION_VIEW_FROM_HERE, STR_STATION_VIEW_FROM, STR_STATION_VIEW_FROM_ANY); - break; - case GR_NEXT: - str = this->GetEntryString(station, STR_STATION_VIEW_VIA_HERE, STR_STATION_VIEW_VIA, STR_STATION_VIEW_VIA_ANY); - if (str == STR_STATION_VIEW_VIA) str = this->SearchNonStop(cd, station, column); - break; - case GR_DESTINATION: - str = this->GetEntryString(station, STR_STATION_VIEW_TO_HERE, STR_STATION_VIEW_TO, STR_STATION_VIEW_TO_ANY); - break; - default: - NOT_REACHED(); - } - if (pos == -this->scroll_to_row && Station::IsValidID(station)) { - ScrollMainWindowToTile(Station::Get(station)->xy); - } - } - - bool rtl = _current_text_dir == TD_RTL; - int text_left = rtl ? r.left + this->expand_shrink_width : r.left + WD_FRAMERECT_LEFT + column * this->expand_shrink_width; - int text_right = rtl ? r.right - WD_FRAMERECT_LEFT - column * this->expand_shrink_width : r.right - this->expand_shrink_width; - int shrink_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - this->expand_shrink_width + WD_FRAMERECT_LEFT; - int shrink_right = rtl ? r.left + this->expand_shrink_width - WD_FRAMERECT_RIGHT : r.right - WD_FRAMERECT_RIGHT; - - DrawString(text_left, text_right, y, str); - - if (column < NUM_COLUMNS - 1) { - const char *sym = NULL; - if (cd->GetNumChildren() > 0) { - sym = "-"; - } else if (auto_distributed && str != STR_STATION_VIEW_RESERVED) { - sym = "+"; - } else { - /* Only draw '+' if there is something to be shown. */ - const StationCargoList &list = Station::Get(this->window_number)->goods[cargo].cargo; - if (grouping == GR_CARGO && (list.ReservedCount() > 0 || cd->HasTransfers())) { - sym = "+"; - } - } - if (sym) DrawString(shrink_left, shrink_right, y, sym, TC_YELLOW); - } - this->SetDisplayedRow(cd); - } - --pos; - if (auto_distributed || column == 0) { - pos = this->DrawEntries(cd, r, pos, maxrows, column + 1, cargo); - } - } - return pos; - } - - /** - * Draw accepted cargo in the #WID_SV_ACCEPT_RATING_LIST widget. - * @param r Rectangle of the widget. - * @return Number of lines needed for drawing the accepted cargo. - */ - int DrawAcceptedCargo(const Rect &r) const - { - const Station *st = Station::Get(this->window_number); - - uint32 cargo_mask = 0; - for (CargoID i = 0; i < NUM_CARGO; i++) { - if (HasBit(st->goods[i].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE)) SetBit(cargo_mask, i); - } - SetDParam(0, cargo_mask); - int bottom = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INT32_MAX, STR_STATION_VIEW_ACCEPTS_CARGO); - return CeilDiv(bottom - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL); - } - - /** - * Draw cargo ratings in the #WID_SV_ACCEPT_RATING_LIST widget. - * @param r Rectangle of the widget. - * @return Number of lines needed for drawing the cargo ratings. - */ - int DrawCargoRatings(const Rect &r) const - { - const Station *st = Station::Get(this->window_number); - int y = r.top + WD_FRAMERECT_TOP; - - if (st->town->exclusive_counter > 0) { - SetDParam(0, st->town->exclusivity); - y = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, r.bottom, st->town->exclusivity == st->owner ? STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF : STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY); - y += WD_PAR_VSEP_WIDE; - } - - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_VIEW_SUPPLY_RATINGS_TITLE); - y += FONT_HEIGHT_NORMAL; - - const CargoSpec *cs; - FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { - const GoodsEntry *ge = &st->goods[cs->Index()]; - if (!ge->HasRating()) continue; - - const LinkGraph *lg = LinkGraph::GetIfValid(ge->link_graph); - SetDParam(0, cs->name); - SetDParam(1, lg != NULL ? lg->Monthly((*lg)[ge->node].Supply()) : 0); - SetDParam(2, STR_CARGO_RATING_APPALLING + (ge->rating >> 5)); - SetDParam(3, ToPercent8(ge->rating)); - DrawString(r.left + WD_FRAMERECT_LEFT + 6, r.right - WD_FRAMERECT_RIGHT - 6, y, STR_STATION_VIEW_CARGO_SUPPLY_RATING); - y += FONT_HEIGHT_NORMAL; - } - return CeilDiv(y - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL); - } - - /** - * Expand or collapse a specific row. - * @param filter Parent of the row. - * @param next ID pointing to the row. - */ - template - void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next) - { - if (filter->Retrieve(next) != NULL) { - filter->Remove(next); - } else { - filter->InsertOrRetrieve(next); - } - } - - /** - * Handle a click on a specific row in the cargo view. - * @param row Row being clicked. - */ - void HandleCargoWaitingClick(int row) - { - if (row < 0 || (uint)row >= this->displayed_rows.size()) return; - if (_ctrl_pressed) { - this->scroll_to_row = row; - } else { - RowDisplay &display = this->displayed_rows[row]; - if (display.filter == &this->expanded_rows) { - this->HandleCargoWaitingClick(display.filter, display.next_cargo); - } else { - this->HandleCargoWaitingClick(display.filter, display.next_station); - } - } - this->SetWidgetDirty(WID_SV_WAITING); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_SV_WAITING: - this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL) - this->vscroll->GetPosition()); - break; - - case WID_SV_LOCATION: - if (_ctrl_pressed) { - ShowExtraViewPortWindow(Station::Get(this->window_number)->xy); - } else { - ScrollMainWindowToTile(Station::Get(this->window_number)->xy); - } - break; - - case WID_SV_ACCEPTS_RATINGS: { - /* Swap between 'accepts' and 'ratings' view. */ - int height_change; - NWidgetCore *nwi = this->GetWidget(WID_SV_ACCEPTS_RATINGS); - if (this->GetWidget(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) { - nwi->SetDataTip(STR_STATION_VIEW_ACCEPTS_BUTTON, STR_STATION_VIEW_ACCEPTS_TOOLTIP); // Switch to accepts view. - height_change = this->rating_lines - this->accepts_lines; - } else { - nwi->SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP); // Switch to ratings view. - height_change = this->accepts_lines - this->rating_lines; - } - this->ReInit(0, height_change * FONT_HEIGHT_NORMAL); - break; - } - - case WID_SV_RENAME: - SetDParam(0, this->window_number); - ShowQueryString(STR_STATION_NAME, STR_STATION_VIEW_RENAME_STATION_CAPTION, MAX_LENGTH_STATION_NAME_CHARS, - this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); - break; - - case WID_SV_CLOSE_AIRPORT: - DoCommandP(0, this->window_number, 0, CMD_OPEN_CLOSE_AIRPORT); - break; - - case WID_SV_TRAINS: // Show list of scheduled trains to this station - case WID_SV_ROADVEHS: // Show list of scheduled road-vehicles to this station - case WID_SV_SHIPS: // Show list of scheduled ships to this station - case WID_SV_PLANES: { // Show list of scheduled aircraft to this station - Owner owner = Station::Get(this->window_number)->owner; - ShowVehicleListWindow(owner, (VehicleType)(widget - WID_SV_TRAINS), (StationID)this->window_number); - break; - } - - case WID_SV_SORT_BY: { - /* The initial selection is composed of current mode and - * sorting criteria for columns 1, 2, and 3. Column 0 is always - * sorted by cargo ID. The others can theoretically be sorted - * by different things but there is no UI for that. */ - ShowDropDownMenu(this, _sort_names, - this->current_mode * 2 + (this->sortings[1] == ST_COUNT ? 1 : 0), - WID_SV_SORT_BY, 0, 0); - break; - } - - case WID_SV_GROUP_BY: { - ShowDropDownMenu(this, _group_names, this->grouping_index, WID_SV_GROUP_BY, 0, 0); - break; - } - - case WID_SV_SORT_ORDER: { // flip sorting method asc/desc - this->SelectSortOrder(this->sort_orders[1] == SO_ASCENDING ? SO_DESCENDING : SO_ASCENDING); - this->SetTimeout(); - this->LowerWidget(WID_SV_SORT_ORDER); - break; - } - } - } - - /** - * Select a new sort order for the cargo view. - * @param order New sort order. - */ - void SelectSortOrder(SortOrder order) - { - this->sort_orders[1] = this->sort_orders[2] = this->sort_orders[3] = order; - _settings_client.gui.station_gui_sort_order = this->sort_orders[1]; - this->SetDirty(); - } - - /** - * Select a new sort criterium for the cargo view. - * @param index Row being selected in the sort criteria drop down. - */ - void SelectSortBy(int index) - { - _settings_client.gui.station_gui_sort_by = index; - switch (_sort_names[index]) { - case STR_STATION_VIEW_WAITING_STATION: - this->current_mode = MODE_WAITING; - this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING; - break; - case STR_STATION_VIEW_WAITING_AMOUNT: - this->current_mode = MODE_WAITING; - this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT; - break; - case STR_STATION_VIEW_PLANNED_STATION: - this->current_mode = MODE_PLANNED; - this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING; - break; - case STR_STATION_VIEW_PLANNED_AMOUNT: - this->current_mode = MODE_PLANNED; - this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT; - break; - default: - NOT_REACHED(); - } - /* Display the current sort variant */ - this->GetWidget(WID_SV_SORT_BY)->widget_data = _sort_names[index]; - this->SetDirty(); - } - - /** - * Select a new grouping mode for the cargo view. - * @param index Row being selected in the grouping drop down. - */ - void SelectGroupBy(int index) - { - this->grouping_index = index; - _settings_client.gui.station_gui_group_order = index; - this->GetWidget(WID_SV_GROUP_BY)->widget_data = _group_names[index]; - switch (_group_names[index]) { - case STR_STATION_VIEW_GROUP_S_V_D: - this->groupings[1] = GR_SOURCE; - this->groupings[2] = GR_NEXT; - this->groupings[3] = GR_DESTINATION; - break; - case STR_STATION_VIEW_GROUP_S_D_V: - this->groupings[1] = GR_SOURCE; - this->groupings[2] = GR_DESTINATION; - this->groupings[3] = GR_NEXT; - break; - case STR_STATION_VIEW_GROUP_V_S_D: - this->groupings[1] = GR_NEXT; - this->groupings[2] = GR_SOURCE; - this->groupings[3] = GR_DESTINATION; - break; - case STR_STATION_VIEW_GROUP_V_D_S: - this->groupings[1] = GR_NEXT; - this->groupings[2] = GR_DESTINATION; - this->groupings[3] = GR_SOURCE; - break; - case STR_STATION_VIEW_GROUP_D_S_V: - this->groupings[1] = GR_DESTINATION; - this->groupings[2] = GR_SOURCE; - this->groupings[3] = GR_NEXT; - break; - case STR_STATION_VIEW_GROUP_D_V_S: - this->groupings[1] = GR_DESTINATION; - this->groupings[2] = GR_NEXT; - this->groupings[3] = GR_SOURCE; - break; - } - this->SetDirty(); - } - - virtual void OnDropdownSelect(int widget, int index) - { - if (widget == WID_SV_SORT_BY) { - this->SelectSortBy(index); - } else { - this->SelectGroupBy(index); - } - } - - virtual void OnQueryTextFinished(char *str) - { - if (str == NULL) return; - - DoCommandP(0, this->window_number, 0, CMD_RENAME_STATION | CMD_MSG(STR_ERROR_CAN_T_RENAME_STATION), NULL, str); - } - - virtual void OnResize() - { - this->vscroll->SetCapacityFromWidget(this, WID_SV_WAITING, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); - } - - /** - * Some data on this window has become invalid. Invalidate the cache for the given cargo if necessary. - * @param data Information about the changed data. If it's a valid cargo ID, invalidate the cargo 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (gui_scope) { - if (data >= 0 && data < NUM_CARGO) { - this->cached_destinations.Remove((CargoID)data); - } else { - this->ReInit(); - } - } - } -}; - -const StringID StationViewWindow::_sort_names[] = { - STR_STATION_VIEW_WAITING_STATION, - STR_STATION_VIEW_WAITING_AMOUNT, - STR_STATION_VIEW_PLANNED_STATION, - STR_STATION_VIEW_PLANNED_AMOUNT, - INVALID_STRING_ID -}; - -const StringID StationViewWindow::_group_names[] = { - STR_STATION_VIEW_GROUP_S_V_D, - STR_STATION_VIEW_GROUP_S_D_V, - STR_STATION_VIEW_GROUP_V_S_D, - STR_STATION_VIEW_GROUP_V_D_S, - STR_STATION_VIEW_GROUP_D_S_V, - STR_STATION_VIEW_GROUP_D_V_S, - INVALID_STRING_ID -}; - -static WindowDesc _station_view_desc( - WDP_AUTO, "view_station", 249, 117, - WC_STATION_VIEW, WC_NONE, - 0, - _nested_station_view_widgets, lengthof(_nested_station_view_widgets) -); - -/** - * Opens StationViewWindow for given station - * - * @param station station which window should be opened - */ -void ShowStationViewWindow(StationID station) -{ - AllocateWindowDescFront(&_station_view_desc, station); -} - -/** Struct containing TileIndex and StationID */ -struct TileAndStation { - TileIndex tile; ///< TileIndex - StationID station; ///< StationID -}; - -static SmallVector _deleted_stations_nearby; -static SmallVector _stations_nearby_list; - -/** - * Add station on this tile to _stations_nearby_list if it's fully within the - * station spread. - * @param tile Tile just being checked - * @param user_data Pointer to TileArea context - * @tparam T the type of station to look for - */ -template -static bool AddNearbyStation(TileIndex tile, void *user_data) -{ - TileArea *ctx = (TileArea *)user_data; - - /* First check if there were deleted stations here */ - for (uint i = 0; i < _deleted_stations_nearby.Length(); i++) { - TileAndStation *ts = _deleted_stations_nearby.Get(i); - if (ts->tile == tile) { - *_stations_nearby_list.Append() = _deleted_stations_nearby[i].station; - _deleted_stations_nearby.Erase(ts); - i--; - } - } - - /* Check if own station and if we stay within station spread */ - if (!IsTileType(tile, MP_STATION)) return false; - - StationID sid = GetStationIndex(tile); - - /* This station is (likely) a waypoint */ - if (!T::IsValidID(sid)) return false; - - T *st = T::Get(sid); - if (st->owner != _local_company || _stations_nearby_list.Contains(sid)) return false; - - if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) { - *_stations_nearby_list.Append() = sid; - } - - return false; // We want to include *all* nearby stations -} - -/** - * Circulate around the to-be-built station to find stations we could join. - * Make sure that only stations are returned where joining wouldn't exceed - * station spread and are our own station. - * @param ta Base tile area of the to-be-built station - * @param distant_join Search for adjacent stations (false) or stations fully - * within station spread - * @tparam T the type of station to look for - */ -template -static const T *FindStationsNearby(TileArea ta, bool distant_join) -{ - TileArea ctx = ta; - - _stations_nearby_list.Clear(); - _deleted_stations_nearby.Clear(); - - /* Check the inside, to return, if we sit on another station */ - TILE_AREA_LOOP(t, ta) { - if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t); - } - - /* Look for deleted stations */ - const BaseStation *st; - FOR_ALL_BASE_STATIONS(st) { - if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) { - /* Include only within station spread (yes, it is strictly less than) */ - if (max(DistanceMax(ta.tile, st->xy), DistanceMax(TILE_ADDXY(ta.tile, ta.w - 1, ta.h - 1), st->xy)) < _settings_game.station.station_spread) { - TileAndStation *ts = _deleted_stations_nearby.Append(); - ts->tile = st->xy; - ts->station = st->index; - - /* Add the station when it's within where we're going to build */ - if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) && - IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) { - AddNearbyStation(st->xy, &ctx); - } - } - } - } - - /* Only search tiles where we have a chance to stay within the station spread. - * The complete check needs to be done in the callback as we don't know the - * extent of the found station, yet. */ - if (distant_join && min(ta.w, ta.h) >= _settings_game.station.station_spread) return NULL; - uint max_dist = distant_join ? _settings_game.station.station_spread - min(ta.w, ta.h) : 1; - - TileIndex tile = TILE_ADD(ctx.tile, TileOffsByDir(DIR_N)); - CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation, &ctx); - - return NULL; -} - -static const NWidgetPart _nested_select_station_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_JS_CAPTION), SetDataTip(STR_JOIN_STATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_JS_PANEL), SetResize(1, 0), SetScrollbar(WID_JS_SCROLLBAR), EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_JS_SCROLLBAR), - NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), - EndContainer(), - EndContainer(), -}; - -/** - * Window for selecting stations/waypoints to (distant) join to. - * @tparam T The type of station to join with - */ -template -struct SelectStationWindow : Window { - CommandContainer select_station_cmd; ///< Command to build new station - TileArea area; ///< Location of new station - Scrollbar *vscroll; - - SelectStationWindow(WindowDesc *desc, const CommandContainer &cmd, TileArea ta) : - Window(desc), - select_station_cmd(cmd), - area(ta) - { - this->CreateNestedTree(); - this->vscroll = this->GetScrollbar(WID_JS_SCROLLBAR); - this->GetWidget(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION; - this->FinishInitNested(0); - this->OnInvalidateData(0); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - if (widget != WID_JS_PANEL) return; - - /* Determine the widest string */ - Dimension d = GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); - for (uint i = 0; i < _stations_nearby_list.Length(); i++) { - const T *st = T::Get(_stations_nearby_list[i]); - SetDParam(0, st->index); - SetDParam(1, st->facilities); - d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION)); - } - - resize->height = GetMinSizing(NWST_STEP, d.height); - d.height = 5 * resize->height; - d.width += WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT; - d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - *size = d; - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (widget != WID_JS_PANEL) return; - - uint y = Center(r.top, this->resize.step_height); - if (this->vscroll->GetPosition() == 0) { - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); - y += this->resize.step_height; - } - - for (uint i = max(1, this->vscroll->GetPosition()); i <= _stations_nearby_list.Length(); ++i, y += this->resize.step_height) { - /* Don't draw anything if it extends past the end of the window. */ - if (i - this->vscroll->GetPosition() >= this->vscroll->GetCapacity()) break; - - const T *st = T::Get(_stations_nearby_list[i - 1]); - SetDParam(0, st->index); - SetDParam(1, st->facilities); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION); - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - if (widget != WID_JS_PANEL) return; - - uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WD_FRAMERECT_TOP); - bool distant_join = (st_index > 0); - if (distant_join) st_index--; - - if (distant_join && st_index >= _stations_nearby_list.Length()) return; - - /* Insert station to be joined into stored command */ - SB(this->select_station_cmd.p2, 16, 16, - (distant_join ? _stations_nearby_list[st_index] : NEW_STATION)); - - /* Execute stored Command */ - DoCommandP(&this->select_station_cmd); - - /* Close Window; this might cause double frees! */ - DeleteWindowById(WC_SELECT_STATION, 0); - } - - virtual void OnTick() - { - if (_thd.dirty & 2) { - _thd.dirty &= ~2; - this->SetDirty(); - } - } - - virtual void OnResize() - { - this->vscroll->SetCapacityFromWidget(this, WID_JS_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - FindStationsNearby(this->area, true); - this->vscroll->SetCount(_stations_nearby_list.Length() + 1); - this->SetDirty(); - } -}; - -static WindowDesc _select_station_desc( - WDP_AUTO, "build_station_join", 200, 180, - WC_SELECT_STATION, WC_NONE, - WDF_CONSTRUCTION, - _nested_select_station_widgets, lengthof(_nested_select_station_widgets) -); - - -/** - * Check whether we need to show the station selection window. - * @param cmd Command to build the station. - * @param ta Tile area of the to-be-built station - * @tparam T the type of station - * @return whether we need to show the station selection window. - */ -template -static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta) -{ - /* Only show selection if distant join is enabled in the settings */ - if (!_settings_game.station.distant_join_stations) return false; - - /* If a window is already opened and we didn't ctrl-click, - * return true (i.e. just flash the old window) */ - Window *selection_window = FindWindowById(WC_SELECT_STATION, 0); - if (selection_window != NULL) { - /* Abort current distant-join and start new one */ - delete selection_window; - UpdateTileSelection(); - } - - /* only show the popup, if we press ctrl */ - if (!_ctrl_pressed) return false; - - /* Now check if we could build there */ - if (DoCommand(&cmd, CommandFlagsToDCFlags(GetCommandFlags(cmd.cmd))).Failed()) return false; - - /* Test for adjacent station or station below selection. - * If adjacent-stations is disabled and we are building next to a station, do not show the selection window. - * but join the other station immediately. */ - const T *st = FindStationsNearby(ta, false); - return st == NULL && (_settings_game.station.adjacent_stations || _stations_nearby_list.Length() == 0); -} - -/** - * Show the station selection window when needed. If not, build the station. - * @param cmd Command to build the station. - * @param ta Area to build the station in - * @tparam the class to find stations for - */ -template -void ShowSelectBaseStationIfNeeded(const CommandContainer &cmd, TileArea ta) -{ - if (StationJoinerNeeded(cmd, ta)) { - if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - new SelectStationWindow(&_select_station_desc, cmd, ta); - } else { - DoCommandP(&cmd); - } -} - -/** - * Show the station selection window when needed. If not, build the station. - * @param cmd Command to build the station. - * @param ta Area to build the station in - */ -void ShowSelectStationIfNeeded(const CommandContainer &cmd, TileArea ta) -{ - ShowSelectBaseStationIfNeeded(cmd, ta); -} - -/** - * Show the waypoint selection window when needed. If not, build the waypoint. - * @param cmd Command to build the waypoint. - * @param ta Area to build the waypoint in - */ -void ShowSelectWaypointIfNeeded(const CommandContainer &cmd, TileArea ta) -{ - ShowSelectBaseStationIfNeeded(cmd, ta); -} diff --git a/src/terraform_gui.cpp.orig b/src/terraform_gui.cpp.orig deleted file mode 100644 index d1815ca9b2..0000000000 --- a/src/terraform_gui.cpp.orig +++ /dev/null @@ -1,760 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file terraform_gui.cpp GUI related to terraforming the map. */ - -#include "stdafx.h" -#include "clear_map.h" -#include "company_func.h" -#include "company_base.h" -#include "gui.h" -#include "window_gui.h" -#include "window_func.h" -#include "viewport_func.h" -#include "command_func.h" -#include "signs_func.h" -#include "sound_func.h" -#include "base_station_base.h" -#include "textbuf_gui.h" -#include "genworld.h" -#include "tree_map.h" -#include "landscape_type.h" -#include "tilehighlight_func.h" -#include "strings_func.h" -#include "newgrf_object.h" -#include "object.h" -#include "hotkeys.h" -#include "engine_base.h" -#include "terraform_gui.h" - -#include "widgets/terraform_widget.h" - -#include "table/strings.h" - -void CcTerraform(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Succeeded()) { - if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); - } else { - extern TileIndex _terraform_err_tile; - SetRedErrorSquare(_terraform_err_tile); - } -} - - -/** Scenario editor command that generates desert areas */ -static void GenerateDesertArea(TileIndex end, TileIndex start) -{ - if (_game_mode != GM_EDITOR) return; - - _generating_world = true; - - TileArea ta(start, end); - TILE_AREA_LOOP(tile, ta) { - SetTropicZone(tile, (_ctrl_pressed) ? TROPICZONE_NORMAL : TROPICZONE_DESERT); - DoCommandP(tile, 0, 0, CMD_LANDSCAPE_CLEAR); - MarkTileDirtyByTile(tile); - } - _generating_world = false; - InvalidateWindowClassesData(WC_TOWN_VIEW, 0); -} - -/** Scenario editor command that generates rocky areas */ -static void GenerateRockyArea(TileIndex end, TileIndex start) -{ - if (_game_mode != GM_EDITOR) return; - - bool success = false; - TileArea ta(start, end); - - TILE_AREA_LOOP(tile, ta) { - switch (GetTileType(tile)) { - case MP_TREES: - if (GetTreeGround(tile) == TREE_GROUND_SHORE) continue; - /* FALL THROUGH */ - case MP_CLEAR: - MakeClear(tile, CLEAR_ROCKS, 3); - break; - - default: continue; - } - MarkTileDirtyByTile(tile); - success = true; - } - - if (success && _settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, end); -} - -/** - * A central place to handle all X_AND_Y dragged GUI functions. - * @param proc Procedure related to the dragging - * @param start_tile Begin of the dragging - * @param end_tile End of the dragging - * @return Returns true if the action was found and handled, and false otherwise. This - * allows for additional implements that are more local. For example X_Y drag - * of convertrail which belongs in rail_gui.cpp and not terraform_gui.cpp - */ -bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile) -{ - if (!_settings_game.construction.freeform_edges) { - /* When end_tile is MP_VOID, the error tile will not be visible to the - * user. This happens when terraforming at the southern border. */ - if (TileX(end_tile) == MapMaxX()) end_tile += TileDiffXY(-1, 0); - if (TileY(end_tile) == MapMaxY()) end_tile += TileDiffXY(0, -1); - } - - switch (proc) { - case DDSP_DEMOLISH_AREA: - DoCommandP(end_tile, start_tile, _ctrl_pressed ? 1 : 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound10); - break; - case DDSP_RAISE_AND_LEVEL_AREA: - DoCommandP(end_tile, start_tile, LM_RAISE << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_RAISE_LAND_HERE), CcTerraform); - break; - case DDSP_LOWER_AND_LEVEL_AREA: - DoCommandP(end_tile, start_tile, LM_LOWER << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LOWER_LAND_HERE), CcTerraform); - break; - case DDSP_LEVEL_AREA: - DoCommandP(end_tile, start_tile, LM_LEVEL << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LEVEL_LAND_HERE), CcTerraform); - break; - case DDSP_CREATE_ROCKS: - GenerateRockyArea(end_tile, start_tile); - break; - case DDSP_CREATE_DESERT: - GenerateDesertArea(end_tile, start_tile); - break; - default: - return false; - } - - return true; -} - -/** - * Start a drag for demolishing an area. - * @param tile Position of one corner. - */ -void PlaceProc_DemolishArea(TileIndex tile) -{ - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_DEMOLISH_AREA); -} - -/** Terra form toolbar managing class. */ -struct TerraformToolbarWindow : Window { - int last_user_action; ///< Last started user action. - - TerraformToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) - { - /* This is needed as we like to have the tree available on OnInit. */ - this->CreateNestedTree(); - this->FinishInitNested(window_number); - this->last_user_action = WIDGET_LIST_END; - } - - ~TerraformToolbarWindow() - { - } - - virtual void OnInit() - { - /* Don't show the place object button when there are no objects to place. */ - NWidgetStacked *show_object = this->GetWidget(WID_TT_SHOW_PLACE_OBJECT); - show_object->SetDisplayedPlane(ObjectClass::GetUIClassCount() != 0 ? 0 : SZSP_NONE); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - if (widget < WID_TT_BUTTONS_START) return; - - switch (widget) { - case WID_TT_LOWER_LAND: // Lower land button - HandlePlacePushButton(this, WID_TT_LOWER_LAND, ANIMCURSOR_LOWERLAND, HT_POINT | HT_DIAGONAL); - this->last_user_action = widget; - break; - - case WID_TT_RAISE_LAND: // Raise land button - HandlePlacePushButton(this, WID_TT_RAISE_LAND, ANIMCURSOR_RAISELAND, HT_POINT | HT_DIAGONAL); - this->last_user_action = widget; - break; - - case WID_TT_LEVEL_LAND: // Level land button - HandlePlacePushButton(this, WID_TT_LEVEL_LAND, SPR_CURSOR_LEVEL_LAND, HT_POINT | HT_DIAGONAL); - this->last_user_action = widget; - break; - - case WID_TT_DEMOLISH: // Demolish aka dynamite button - HandlePlacePushButton(this, WID_TT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); - this->last_user_action = widget; - break; - - case WID_TT_BUY_LAND: // Buy land button - HandlePlacePushButton(this, WID_TT_BUY_LAND, SPR_CURSOR_BUY_LAND, HT_RECT); - this->last_user_action = widget; - break; - - case WID_TT_PLANT_TREES: // Plant trees button - ShowBuildTreesToolbar(); - break; - - case WID_TT_PLACE_SIGN: // Place sign button - HandlePlacePushButton(this, WID_TT_PLACE_SIGN, SPR_CURSOR_SIGN, HT_RECT); - this->last_user_action = widget; - break; - - case WID_TT_PLACE_OBJECT: // Place object button - /* Don't show the place object button when there are no objects to place. */ - if (ObjectClass::GetUIClassCount() == 0) return; - if (HandlePlacePushButton(this, WID_TT_PLACE_OBJECT, SPR_CURSOR_TRANSMITTER, HT_RECT)) { - ShowBuildObjectPicker(this); - this->last_user_action = widget; - } - break; - - default: NOT_REACHED(); - } - } - - virtual void OnPlaceObject(Point pt, TileIndex tile) - { - switch (this->last_user_action) { - case WID_TT_LOWER_LAND: // Lower land button - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LOWER_AND_LEVEL_AREA); - break; - - case WID_TT_RAISE_LAND: // Raise land button - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_RAISE_AND_LEVEL_AREA); - break; - - case WID_TT_LEVEL_LAND: // Level land button - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LEVEL_AREA); - break; - - case WID_TT_DEMOLISH: // Demolish aka dynamite button - PlaceProc_DemolishArea(tile); - break; - - case WID_TT_BUY_LAND: // Buy land button - DoCommandP(tile, OBJECT_OWNED_LAND, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_PURCHASE_THIS_LAND), CcPlaySound1E); - break; - - case WID_TT_PLACE_SIGN: // Place sign button - PlaceProc_Sign(tile); - break; - - case WID_TT_PLACE_OBJECT: // Place object button - PlaceProc_Object(tile); - break; - - default: NOT_REACHED(); - } - } - - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) - { - VpSelectTilesWithMethod(pt.x, pt.y, select_method); - } - - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) - { - Point pt = GetToolbarAlignedWindowPosition(sm_width); - pt.y += sm_height; - return pt; - } - - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) - { - if (pt.x != -1) { - switch (select_proc) { - default: NOT_REACHED(); - case DDSP_DEMOLISH_AREA: - case DDSP_RAISE_AND_LEVEL_AREA: - case DDSP_LOWER_AND_LEVEL_AREA: - case DDSP_LEVEL_AREA: - GUIPlaceProcDragXY(select_proc, start_tile, end_tile); - break; - } - } - } - - virtual void OnPlaceObjectAbort() - { - DeleteWindowById(WC_BUILD_OBJECT, 0); - this->RaiseButtons(); - } - - static HotkeyList hotkeys; -}; - -/** - * Handler for global hotkeys of the TerraformToolbarWindow. - * @param hotkey Hotkey - * @return ES_HANDLED if hotkey was accepted. - */ -static EventState TerraformToolbarGlobalHotkeys(int hotkey) -{ - if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED; - Window *w = ShowTerraformToolbar(NULL); - if (w == NULL) return ES_NOT_HANDLED; - return w->OnHotkey(hotkey); -} - -static Hotkey terraform_hotkeys[] = { - Hotkey('Q' | WKC_GLOBAL_HOTKEY, "lower", WID_TT_LOWER_LAND), - Hotkey('W' | WKC_GLOBAL_HOTKEY, "raise", WID_TT_RAISE_LAND), - Hotkey('E' | WKC_GLOBAL_HOTKEY, "level", WID_TT_LEVEL_LAND), - Hotkey('D' | WKC_GLOBAL_HOTKEY, "dynamite", WID_TT_DEMOLISH), - Hotkey('U', "buyland", WID_TT_BUY_LAND), - Hotkey('I', "trees", WID_TT_PLANT_TREES), - Hotkey('O', "placesign", WID_TT_PLACE_SIGN), - Hotkey('P', "placeobject", WID_TT_PLACE_OBJECT), - HOTKEY_LIST_END -}; -HotkeyList TerraformToolbarWindow::hotkeys("terraform", terraform_hotkeys, TerraformToolbarGlobalHotkeys); - -static const NWidgetPart _nested_terraform_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_LANDSCAPING_TOOLBAR, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_LOWER_LAND), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_TERRAFORM_DOWN, STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_RAISE_LAND), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_TERRAFORM_UP, STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_LEVEL_LAND), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_LEVEL_LAND, STR_LANDSCAPING_LEVEL_LAND_TOOLTIP), - - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), EndContainer(), - - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_DEMOLISH), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_BUY_LAND), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_BUY_LAND, STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND), - NWidget(WWT_PUSHIMGBTN, COLOUR_DARK_GREEN, WID_TT_PLANT_TREES), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_PLACE_SIGN), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_TT_SHOW_PLACE_OBJECT), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_PLACE_OBJECT), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_TRANSMITTER, STR_SCENEDIT_TOOLBAR_PLACE_OBJECT), - EndContainer(), - EndContainer(), -}; - -static WindowDesc _terraform_desc( - WDP_MANUAL, "toolbar_landscape", 0, 0, - WC_SCEN_LAND_GEN, WC_NONE, - WDF_CONSTRUCTION, - _nested_terraform_widgets, lengthof(_nested_terraform_widgets), - &TerraformToolbarWindow::hotkeys -); - -/** - * Show the toolbar for terraforming in the game. - * @param link The toolbar we might want to link to. - * @return The allocated toolbar. - */ -Window *ShowTerraformToolbar(Window *link) -{ - if (!Company::IsValidID(_local_company)) return NULL; - - Window *w; - if (link == NULL) { - w = AllocateWindowDescFront(&_terraform_desc, 0); - return w; - } - - /* Delete the terraform toolbar to place it again. */ - DeleteWindowById(WC_SCEN_LAND_GEN, 0, true); - w = AllocateWindowDescFront(&_terraform_desc, 0); - /* Align the terraform toolbar under the main toolbar. */ - w->top -= w->height; - w->SetDirty(); - /* Put the linked toolbar to the left / right of it. */ - link->left = w->left + (_current_text_dir == TD_RTL ? w->width : -link->width); - link->top = w->top; - link->SetDirty(); - - return w; -} - -static byte _terraform_size = 1; - -/** - * Raise/Lower a bigger chunk of land at the same time in the editor. When - * raising get the lowest point, when lowering the highest point, and set all - * tiles in the selection to that height. - * @todo : Incorporate into game itself to allow for ingame raising/lowering of - * larger chunks at the same time OR remove altogether, as we have 'level land' ? - * @param tile The top-left tile where the terraforming will start - * @param mode 1 for raising, 0 for lowering land - */ -static void CommonRaiseLowerBigLand(TileIndex tile, int mode) -{ - if (_terraform_size == 1) { - StringID msg = - mode ? STR_ERROR_CAN_T_RAISE_LAND_HERE : STR_ERROR_CAN_T_LOWER_LAND_HERE; - - DoCommandP(tile, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND | CMD_MSG(msg), CcTerraform); - } else { - assert(_terraform_size != 0); - TileArea ta(tile, _terraform_size, _terraform_size); - ta.ClampToMap(); - - if (ta.w == 0 || ta.h == 0) return; - - if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); - - uint h; - if (mode != 0) { - /* Raise land */ - h = MAX_TILE_HEIGHT; - TILE_AREA_LOOP(tile2, ta) { - h = min(h, TileHeight(tile2)); - } - } else { - /* Lower land */ - h = 0; - TILE_AREA_LOOP(tile2, ta) { - h = max(h, TileHeight(tile2)); - } - } - - TILE_AREA_LOOP(tile2, ta) { - if (TileHeight(tile2) == h) { - DoCommandP(tile2, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND); - } - } - } -} - -static const int8 _multi_terraform_coords[][2] = { - { 0, -2}, - { 4, 0}, { -4, 0}, { 0, 2}, - { -8, 2}, { -4, 4}, { 0, 6}, { 4, 4}, { 8, 2}, - {-12, 0}, { -8, -2}, { -4, -4}, { 0, -6}, { 4, -4}, { 8, -2}, { 12, 0}, - {-16, 2}, {-12, 4}, { -8, 6}, { -4, 8}, { 0, 10}, { 4, 8}, { 8, 6}, { 12, 4}, { 16, 2}, - {-20, 0}, {-16, -2}, {-12, -4}, { -8, -6}, { -4, -8}, { 0,-10}, { 4, -8}, { 8, -6}, { 12, -4}, { 16, -2}, { 20, 0}, - {-24, 2}, {-20, 4}, {-16, 6}, {-12, 8}, { -8, 10}, { -4, 12}, { 0, 14}, { 4, 12}, { 8, 10}, { 12, 8}, { 16, 6}, { 20, 4}, { 24, 2}, - {-28, 0}, {-24, -2}, {-20, -4}, {-16, -6}, {-12, -8}, { -8,-10}, { -4,-12}, { 0,-14}, { 4,-12}, { 8,-10}, { 12, -8}, { 16, -6}, { 20, -4}, { 24, -2}, { 28, 0}, -}; - -static const NWidgetPart _nested_scen_edit_land_gen_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), - NWidget(NWID_HORIZONTAL), SetPadding(2, 2, 7, 2), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_DEMOLISH), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_LOWER_LAND), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_TERRAFORM_DOWN, STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_RAISE_LAND), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_TERRAFORM_UP, STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_LEVEL_LAND), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_LEVEL_LAND, STR_LANDSCAPING_LEVEL_LAND_TOOLTIP), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_PLACE_ROCKS), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_ROCKS, STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_ETT_SHOW_PLACE_DESERT), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_PLACE_DESERT), SetMinimalSize(22, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_DESERT, STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA), - EndContainer(), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_PLACE_OBJECT), SetMinimalSize(23, 22), - SetFill(0, 1), SetDataTip(SPR_IMG_TRANSMITTER, STR_SCENEDIT_TOOLBAR_PLACE_OBJECT), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_ETT_DOTS), SetMinimalSize(59, 31), SetDataTip(STR_EMPTY, STR_NULL), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(NWID_VERTICAL), - NWidget(NWID_SPACER), SetFill(0, 1), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_INCREASE_SIZE), SetMinimalSize(12, 12), SetDataTip(SPR_ARROW_UP, STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA), - NWidget(NWID_SPACER), SetMinimalSize(0, 1), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_DECREASE_SIZE), SetMinimalSize(12, 12), SetDataTip(SPR_ARROW_DOWN, STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA), - NWidget(NWID_SPACER), SetFill(0, 1), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 6), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_ETT_NEW_SCENARIO), SetMinimalSize(160, 12), - SetFill(1, 0), SetDataTip(STR_TERRAFORM_SE_NEW_WORLD, STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND), SetPadding(0, 2, 0, 2), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_ETT_RESET_LANDSCAPE), SetMinimalSize(160, 12), - SetFill(1, 0), SetDataTip(STR_TERRAFORM_RESET_LANDSCAPE, STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP), SetPadding(1, 2, 2, 2), - EndContainer(), -}; - -/** - * Callback function for the scenario editor 'reset landscape' confirmation window - * @param w Window unused - * @param confirmed boolean value, true when yes was clicked, false otherwise - */ -static void ResetLandscapeConfirmationCallback(Window *w, bool confirmed) -{ - if (confirmed) { - /* Set generating_world to true to get instant-green grass after removing - * company property. */ - _generating_world = true; - - /* Delete all companies */ - Company *c; - FOR_ALL_COMPANIES(c) { - ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER); - delete c; - } - - _generating_world = false; - - /* Delete all station signs */ - BaseStation *st; - FOR_ALL_BASE_STATIONS(st) { - /* There can be buoys, remove them */ - if (IsBuoyTile(st->xy)) DoCommand(st->xy, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); - if (!st->IsInUse()) delete st; - } - - /* Now that all vehicles are gone, we can reset the engine pool. Maybe it reduces some NewGRF changing-mess */ - EngineOverrideManager::ResetToCurrentNewGRFConfig(); - - MarkWholeScreenDirty(); - } -} - -/** Landscape generation window handler in the scenario editor. */ -struct ScenarioEditorLandscapeGenerationWindow : Window { - int last_user_action; ///< Last started user action. - - ScenarioEditorLandscapeGenerationWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) - { - this->CreateNestedTree(); - NWidgetStacked *show_desert = this->GetWidget(WID_ETT_SHOW_PLACE_DESERT); - show_desert->SetDisplayedPlane(_settings_game.game_creation.landscape == LT_TROPIC ? 0 : SZSP_NONE); - this->FinishInitNested(window_number); - this->last_user_action = WIDGET_LIST_END; - } - - virtual void OnPaint() - { - this->DrawWidgets(); - - if (this->IsWidgetLowered(WID_ETT_LOWER_LAND) || this->IsWidgetLowered(WID_ETT_RAISE_LAND)) { // change area-size if raise/lower corner is selected - SetTileSelectSize(_terraform_size, _terraform_size); - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (widget != WID_ETT_DOTS) return; - - int center_x = RoundDivSU(r.left + r.right, 2); - int center_y = RoundDivSU(r.top + r.bottom, 2); - - int n = _terraform_size * _terraform_size; - const int8 *coords = &_multi_terraform_coords[0][0]; - - assert(n != 0); - do { - DrawSprite(SPR_WHITE_POINT, PAL_NONE, center_x + coords[0], center_y + coords[1]); - coords += 2; - } while (--n); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - if (widget < WID_ETT_BUTTONS_START) return; - - switch (widget) { - case WID_ETT_DEMOLISH: // Demolish aka dynamite button - HandlePlacePushButton(this, WID_ETT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); - this->last_user_action = widget; - break; - - case WID_ETT_LOWER_LAND: // Lower land button - HandlePlacePushButton(this, WID_ETT_LOWER_LAND, ANIMCURSOR_LOWERLAND, HT_POINT); - this->last_user_action = widget; - break; - - case WID_ETT_RAISE_LAND: // Raise land button - HandlePlacePushButton(this, WID_ETT_RAISE_LAND, ANIMCURSOR_RAISELAND, HT_POINT); - this->last_user_action = widget; - break; - - case WID_ETT_LEVEL_LAND: // Level land button - HandlePlacePushButton(this, WID_ETT_LEVEL_LAND, SPR_CURSOR_LEVEL_LAND, HT_POINT | HT_DIAGONAL); - this->last_user_action = widget; - break; - - case WID_ETT_PLACE_ROCKS: // Place rocks button - HandlePlacePushButton(this, WID_ETT_PLACE_ROCKS, SPR_CURSOR_ROCKY_AREA, HT_RECT); - this->last_user_action = widget; - break; - - case WID_ETT_PLACE_DESERT: // Place desert button (in tropical climate) - HandlePlacePushButton(this, WID_ETT_PLACE_DESERT, SPR_CURSOR_DESERT, HT_RECT); - this->last_user_action = widget; - break; - - case WID_ETT_PLACE_OBJECT: // Place transmitter button - if (HandlePlacePushButton(this, WID_ETT_PLACE_OBJECT, SPR_CURSOR_TRANSMITTER, HT_RECT)) { - ShowBuildObjectPicker(this); - this->last_user_action = widget; - } - break; - - case WID_ETT_INCREASE_SIZE: - case WID_ETT_DECREASE_SIZE: { // Increase/Decrease terraform size - int size = (widget == WID_ETT_INCREASE_SIZE) ? 1 : -1; - this->HandleButtonClick(widget); - size += _terraform_size; - - if (!IsInsideMM(size, 1, 8 + 1)) return; - _terraform_size = size; - - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - this->SetDirty(); - break; - } - - case WID_ETT_NEW_SCENARIO: // gen random land - this->HandleButtonClick(widget); - ShowCreateScenario(); - break; - - case WID_ETT_RESET_LANDSCAPE: // Reset landscape - ShowQuery(STR_QUERY_RESET_LANDSCAPE_CAPTION, STR_RESET_LANDSCAPE_CONFIRMATION_TEXT, NULL, ResetLandscapeConfirmationCallback); - break; - - default: NOT_REACHED(); - } - } - - virtual void OnTimeout() - { - for (uint i = WID_ETT_START; i < this->nested_array_size; i++) { - if (i == WID_ETT_BUTTONS_START) i = WID_ETT_BUTTONS_END; // skip the buttons - if (this->IsWidgetLowered(i)) { - this->RaiseWidget(i); - this->SetWidgetDirty(i); - } - } - } - - virtual void OnPlaceObject(Point pt, TileIndex tile) - { - switch (this->last_user_action) { - case WID_ETT_DEMOLISH: // Demolish aka dynamite button - PlaceProc_DemolishArea(tile); - break; - - case WID_ETT_LOWER_LAND: // Lower land button - CommonRaiseLowerBigLand(tile, 0); - break; - - case WID_ETT_RAISE_LAND: // Raise land button - CommonRaiseLowerBigLand(tile, 1); - break; - - case WID_ETT_LEVEL_LAND: // Level land button - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LEVEL_AREA); - break; - - case WID_ETT_PLACE_ROCKS: // Place rocks button - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_ROCKS); - break; - - case WID_ETT_PLACE_DESERT: // Place desert button (in tropical climate) - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_DESERT); - break; - - case WID_ETT_PLACE_OBJECT: // Place transmitter button - PlaceProc_Object(tile); - break; - - default: NOT_REACHED(); - } - } - - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) - { - VpSelectTilesWithMethod(pt.x, pt.y, select_method); - } - - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) - { - if (pt.x != -1) { - switch (select_proc) { - default: NOT_REACHED(); - case DDSP_CREATE_ROCKS: - case DDSP_CREATE_DESERT: - case DDSP_RAISE_AND_LEVEL_AREA: - case DDSP_LOWER_AND_LEVEL_AREA: - case DDSP_LEVEL_AREA: - case DDSP_DEMOLISH_AREA: - GUIPlaceProcDragXY(select_proc, start_tile, end_tile); - break; - } - } - } - - virtual void OnPlaceObjectAbort() - { - this->RaiseButtons(); - this->SetDirty(); - DeleteWindowById(WC_BUILD_OBJECT, 0); - } - - static HotkeyList hotkeys; -}; - -/** - * Handler for global hotkeys of the ScenarioEditorLandscapeGenerationWindow. - * @param hotkey Hotkey - * @return ES_HANDLED if hotkey was accepted. - */ -static EventState TerraformToolbarEditorGlobalHotkeys(int hotkey) -{ - if (_game_mode != GM_EDITOR) return ES_NOT_HANDLED; - Window *w = ShowEditorTerraformToolbar(); - if (w == NULL) return ES_NOT_HANDLED; - return w->OnHotkey(hotkey); -} - -static Hotkey terraform_editor_hotkeys[] = { - Hotkey('D' | WKC_GLOBAL_HOTKEY, "dynamite", WID_ETT_DEMOLISH), - Hotkey('Q' | WKC_GLOBAL_HOTKEY, "lower", WID_ETT_LOWER_LAND), - Hotkey('W' | WKC_GLOBAL_HOTKEY, "raise", WID_ETT_RAISE_LAND), - Hotkey('E' | WKC_GLOBAL_HOTKEY, "level", WID_ETT_LEVEL_LAND), - Hotkey('R', "rocky", WID_ETT_PLACE_ROCKS), - Hotkey('T', "desert", WID_ETT_PLACE_DESERT), - Hotkey('O', "object", WID_ETT_PLACE_OBJECT), - HOTKEY_LIST_END -}; - -HotkeyList ScenarioEditorLandscapeGenerationWindow::hotkeys("terraform_editor", terraform_editor_hotkeys, TerraformToolbarEditorGlobalHotkeys); - -static WindowDesc _scen_edit_land_gen_desc( - WDP_AUTO, "toolbar_landscape_scen", 0, 0, - WC_SCEN_LAND_GEN, WC_NONE, - WDF_CONSTRUCTION, - _nested_scen_edit_land_gen_widgets, lengthof(_nested_scen_edit_land_gen_widgets), - &ScenarioEditorLandscapeGenerationWindow::hotkeys -); - -/** - * Show the toolbar for terraforming in the scenario editor. - * @return The allocated toolbar. - */ -Window *ShowEditorTerraformToolbar() -{ - return AllocateWindowDescFront(&_scen_edit_land_gen_desc, 0); -} diff --git a/src/toolbar_gui.cpp.orig b/src/toolbar_gui.cpp.orig deleted file mode 100644 index 57bc4d4124..0000000000 --- a/src/toolbar_gui.cpp.orig +++ /dev/null @@ -1,2230 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file toolbar_gui.cpp Code related to the (main) toolbar. */ - -#include "stdafx.h" -#include "gui.h" -#include "window_gui.h" -#include "window_func.h" -#include "viewport_func.h" -#include "command_func.h" -#include "vehicle_gui.h" -#include "rail_gui.h" -#include "road_gui.h" -#include "date_func.h" -#include "vehicle_func.h" -#include "sound_func.h" -#include "terraform_gui.h" -#include "strings_func.h" -#include "company_func.h" -#include "company_gui.h" -#include "vehicle_base.h" -#include "cheat_func.h" -#include "transparency_gui.h" -#include "screenshot.h" -#include "signs_func.h" -#include "fios.h" -#include "console_gui.h" -#include "news_gui.h" -#include "ai/ai_gui.hpp" -#include "tilehighlight_func.h" -#include "smallmap_gui.h" -#include "graph_gui.h" -#include "textbuf_gui.h" -#include "linkgraph/linkgraph_gui.h" -#include "newgrf_debug.h" -#include "hotkeys.h" -#include "engine_base.h" -#include "highscore.h" -#include "game/game.hpp" -#include "goal_base.h" -#include "story_base.h" - -#include "widgets/toolbar_widget.h" - -#include "network/network.h" -#include "network/network_gui.h" -#include "network/network_func.h" - - -RailType _last_built_railtype; -RoadType _last_built_roadtype; - -static ScreenshotType _confirmed_screenshot_type; ///< Screenshot type the current query is about to confirm. - -/** Toobar modes */ -enum ToolbarMode { - TB_NORMAL, - TB_UPPER, - TB_LOWER -}; - -/** Callback functions. */ -enum CallBackFunction { - CBF_NONE, - CBF_PLACE_SIGN, - CBF_PLACE_LANDINFO, -}; - -/** - * Drop down list entry for showing a checked/unchecked toggle item. - */ -class DropDownListCheckedItem : public DropDownListStringItem { - uint checkmark_width; -public: - bool checked; - - DropDownListCheckedItem(StringID string, int result, bool masked, bool checked) : DropDownListStringItem(string, result, masked), checked(checked) - { - this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3; - } - - virtual ~DropDownListCheckedItem() {} - - uint Width() const - { - return DropDownListStringItem::Width() + this->checkmark_width; - } - - void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const - { - bool rtl = _current_text_dir == TD_RTL; - if (this->checked) { - DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK); - } - DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : this->checkmark_width), right - WD_FRAMERECT_RIGHT - (rtl ? this->checkmark_width : 0), top, this->String(), sel ? TC_WHITE : TC_BLACK); - } -}; - -/** - * Drop down list entry for showing a company entry, with companies 'blob'. - */ -class DropDownListCompanyItem : public DropDownListItem { - Dimension icon_size; -public: - bool greyed; - - DropDownListCompanyItem(int result, bool masked, bool greyed) : DropDownListItem(result, masked), greyed(greyed) - { - this->icon_size = GetSpriteSize(SPR_COMPANY_ICON); - } - - virtual ~DropDownListCompanyItem() {} - - bool Selectable() const - { - return true; - } - - uint Width() const - { - CompanyID company = (CompanyID)this->result; - SetDParam(0, company); - SetDParam(1, company); - return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + 3; - } - - uint Height(uint width) const - { - return max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL); - } - - void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const - { - CompanyID company = (CompanyID)this->result; - bool rtl = _current_text_dir == TD_RTL; - - /* It's possible the company is deleted while the dropdown is open */ - if (!Company::IsValidID(company)) return; - - int icon_offset = (bottom - top - icon_size.height) / 2; - int text_offset = (bottom - top - FONT_HEIGHT_NORMAL) / 2; - - DrawCompanyIcon(company, rtl ? right - this->icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + icon_offset); - - SetDParam(0, company); - SetDParam(1, company); - TextColour col; - if (this->greyed) { - col = (sel ? TC_SILVER : TC_GREY) | TC_NO_SHADE; - } else { - col = sel ? TC_WHITE : TC_BLACK; - } - DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : 3 + this->icon_size.width), right - WD_FRAMERECT_RIGHT - (rtl ? 3 + this->icon_size.width : 0), top + text_offset, STR_COMPANY_NAME_COMPANY_NUM, col); - } -}; - -/** - * Pop up a generic text only menu. - * @param w Toolbar - * @param widget Toolbar button - * @param list List of items - * @param def Default item - */ -static void PopupMainToolbMenu(Window *w, int widget, DropDownList *list, int def) -{ - ShowDropDownList(w, list, def, widget, 0, true, true); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); -} - -/** - * Pop up a generic text only menu. - * @param w Toolbar - * @param widget Toolbar button - * @param string String for the first item in the menu - * @param count Number of items in the menu - */ -static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count) -{ - DropDownList *list = new DropDownList(); - for (int i = 0; i < count; i++) { - *list->Append() = new DropDownListStringItem(string + i, i, false); - } - PopupMainToolbMenu(w, widget, list, 0); -} - -/** Enum for the Company Toolbar's network related buttons */ -static const int CTMN_CLIENT_LIST = -1; ///< Show the client list -static const int CTMN_NEW_COMPANY = -2; ///< Create a new company -static const int CTMN_SPECTATE = -3; ///< Become spectator -static const int CTMN_SPECTATOR = -4; ///< Show a company window as spectator - -/** - * Pop up a generic company list menu. - * @param w The toolbar window. - * @param widget The button widget id. - * @param grey A bitbask of which items to mark as disabled. - * @param include_spectator If true, a spectator option is included in the list. - */ -static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0, bool include_spectator = false) -{ - DropDownList *list = new DropDownList(); - -#ifdef ENABLE_NETWORK - if (_networking) { - if (widget == WID_TN_COMPANIES) { - /* Add the client list button for the companies menu */ - *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false); - } - - if (include_spectator) { - if (widget == WID_TN_COMPANIES) { - if (_local_company == COMPANY_SPECTATOR) { - *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, NetworkMaxCompaniesReached()); - } else { - *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, NetworkMaxSpectatorsReached()); - } - } else { - *list->Append() = new DropDownListStringItem(STR_NETWORK_TOOLBAR_LIST_SPECTATOR, CTMN_SPECTATOR, false); - } - } - } -#endif /* ENABLE_NETWORK */ - - for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - if (!Company::IsValidID(c)) continue; - *list->Append() = new DropDownListCompanyItem(c, false, HasBit(grey, c)); - } - - PopupMainToolbMenu(w, widget, list, _local_company == COMPANY_SPECTATOR ? CTMN_CLIENT_LIST : (int)_local_company); -} - - -static ToolbarMode _toolbar_mode; - -static CallBackFunction SelectSignTool() -{ - if (_cursor.sprite == SPR_CURSOR_SIGN) { - ResetObjectToPlace(); - return CBF_NONE; - } else { - SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0); - return CBF_PLACE_SIGN; - } -} - -/* --- Pausing --- */ - -static CallBackFunction ToolbarPauseClick(Window *w) -{ - if (_networking && !_network_server) return CBF_NONE; // only server can pause the game - - if (DoCommandP(0, PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED, CMD_PAUSE)) { - if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP); - } - return CBF_NONE; -} - -/** - * Toggle fast forward mode. - * - * @param w Unused. - * @return #CBF_NONE - */ -static CallBackFunction ToolbarFastForwardClick(Window *w) -{ - _fast_forward ^= true; - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - return CBF_NONE; -} - -/** - * Game Option button menu entries. - */ -enum OptionMenuEntries { - OME_GAMEOPTIONS, - OME_SETTINGS, - OME_SCRIPT_SETTINGS, - OME_NEWGRFSETTINGS, - OME_TRANSPARENCIES, - OME_SHOW_TOWNNAMES, - OME_SHOW_STATIONNAMES, - OME_SHOW_WAYPOINTNAMES, - OME_SHOW_SIGNS, - OME_SHOW_COMPETITOR_SIGNS, - OME_FULL_ANIMATION, - OME_FULL_DETAILS, - OME_TRANSPARENTBUILDINGS, - OME_SHOW_STATIONSIGNS, -}; - -/** - * Handle click on Options button in toolbar. - * - * @param w parent window the shown Drop down list is attached to. - * @return #CBF_NONE - */ -static CallBackFunction ToolbarOptionsClick(Window *w) -{ - DropDownList *list = new DropDownList(); - *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS, OME_GAMEOPTIONS, false); - *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS, OME_SETTINGS, false); - /* Changes to the per-AI settings don't get send from the server to the clients. Clients get - * the settings once they join but never update it. As such don't show the window at all - * to network clients. */ - if (!_networking || _network_server) *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false); - *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS, OME_NEWGRFSETTINGS, false); - *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS, OME_TRANSPARENCIES, false); - *list->Append() = new DropDownListItem(-1, false); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES, false, HasBit(_display_opt, DO_SHOW_STATION_NAMES)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED, OME_SHOW_WAYPOINTNAMES, false, HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SIGNS_DISPLAYED, OME_SHOW_SIGNS, false, HasBit(_display_opt, DO_SHOW_SIGNS)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS, OME_SHOW_COMPETITOR_SIGNS, false, HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_ANIMATION, OME_FULL_ANIMATION, false, HasBit(_display_opt, DO_FULL_ANIMATION)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_DETAIL, OME_FULL_DETAILS, false, HasBit(_display_opt, DO_FULL_DETAIL)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS, OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS)); - - ShowDropDownList(w, list, 0, WID_TN_SETTINGS, 140, true, true); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - return CBF_NONE; -} - -/** - * Handle click on one of the entries in the Options button menu. - * - * @param index Index being clicked. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickSettings(int index) -{ - switch (index) { - case OME_GAMEOPTIONS: ShowGameOptions(); return CBF_NONE; - case OME_SETTINGS: ShowGameSettings(); return CBF_NONE; - case OME_SCRIPT_SETTINGS: ShowAIConfigWindow(); return CBF_NONE; - case OME_NEWGRFSETTINGS: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); return CBF_NONE; - case OME_TRANSPARENCIES: ShowTransparencyToolbar(); break; - - case OME_SHOW_TOWNNAMES: ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES); break; - case OME_SHOW_STATIONNAMES: ToggleBit(_display_opt, DO_SHOW_STATION_NAMES); break; - case OME_SHOW_WAYPOINTNAMES: ToggleBit(_display_opt, DO_SHOW_WAYPOINT_NAMES); break; - case OME_SHOW_SIGNS: ToggleBit(_display_opt, DO_SHOW_SIGNS); break; - case OME_SHOW_COMPETITOR_SIGNS: - ToggleBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS); - InvalidateWindowClassesData(WC_SIGN_LIST, -1); - break; - case OME_FULL_ANIMATION: ToggleBit(_display_opt, DO_FULL_ANIMATION); CheckBlitter(); break; - case OME_FULL_DETAILS: ToggleBit(_display_opt, DO_FULL_DETAIL); break; - case OME_TRANSPARENTBUILDINGS: ToggleTransparency(TO_HOUSES); break; - case OME_SHOW_STATIONSIGNS: ToggleTransparency(TO_SIGNS); break; - } - MarkWholeScreenDirty(); - return CBF_NONE; -} - -/** - * SaveLoad entries in scenario editor mode. - */ -enum SaveLoadEditorMenuEntries { - SLEME_SAVE_SCENARIO = 0, - SLEME_LOAD_SCENARIO, - SLEME_SAVE_HEIGHTMAP, - SLEME_LOAD_HEIGHTMAP, - SLEME_EXIT_TOINTRO, - SLEME_EXIT_GAME = 6, - SLEME_MENUCOUNT, -}; - -/** - * SaveLoad entries in normal game mode. - */ -enum SaveLoadNormalMenuEntries { - SLNME_SAVE_GAME = 0, - SLNME_LOAD_GAME, - SLNME_EXIT_TOINTRO, - SLNME_EXIT_GAME = 4, - SLNME_MENUCOUNT, -}; - -/** - * Handle click on Save button in toolbar in normal game mode. - * - * @param w parent window the shown save dialogue is attached to. - * @return #CBF_NONE - */ -static CallBackFunction ToolbarSaveClick(Window *w) -{ - PopupMainToolbMenu(w, WID_TN_SAVE, STR_FILE_MENU_SAVE_GAME, SLNME_MENUCOUNT); - return CBF_NONE; -} - -/** - * Handle click on SaveLoad button in toolbar in the scenario editor. - * - * @param w parent window the shown save dialogue is attached to. - * @return #CBF_NONE - */ -static CallBackFunction ToolbarScenSaveOrLoad(Window *w) -{ - PopupMainToolbMenu(w, WID_TE_SAVE, STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO, SLEME_MENUCOUNT); - return CBF_NONE; -} - -/** - * Handle click on one of the entries in the SaveLoad menu. - * - * @param index Index being clicked. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickSaveLoad(int index = 0) -{ - if (_game_mode == GM_EDITOR) { - switch (index) { - case SLEME_SAVE_SCENARIO: ShowSaveLoadDialog(SLD_SAVE_SCENARIO); break; - case SLEME_LOAD_SCENARIO: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break; - case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(SLD_SAVE_HEIGHTMAP); break; - case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break; - case SLEME_EXIT_TOINTRO: AskExitToGameMenu(); break; - case SLEME_EXIT_GAME: HandleExitGameRequest(); break; - } - } else { - switch (index) { - case SLNME_SAVE_GAME: ShowSaveLoadDialog(SLD_SAVE_GAME); break; - case SLNME_LOAD_GAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break; - case SLNME_EXIT_TOINTRO: AskExitToGameMenu(); break; - case SLNME_EXIT_GAME: HandleExitGameRequest(); break; - } - } - return CBF_NONE; -} - -/* --- Map button menu --- */ - -enum MapMenuEntries { - MME_SHOW_SMALLMAP = 0, - MME_SHOW_EXTRAVIEWPORTS, - MME_SHOW_LINKGRAPH, - MME_SHOW_SIGNLISTS, - MME_SHOW_TOWNDIRECTORY, - MME_SHOW_INDUSTRYDIRECTORY, -}; - -static CallBackFunction ToolbarMapClick(Window *w) -{ - DropDownList *list = new DropDownList(); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_LINGRAPH_LEGEND, MME_SHOW_LINKGRAPH, false); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false); - PopupMainToolbMenu(w, WID_TN_SMALL_MAP, list, 0); - return CBF_NONE; -} - -static CallBackFunction ToolbarScenMapTownDir(Window *w) -{ - DropDownList *list = new DropDownList(); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false); - *list->Append() = new DropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, MME_SHOW_TOWNDIRECTORY, false); - *list->Append() = new DropDownListStringItem(STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, MME_SHOW_INDUSTRYDIRECTORY, false); - PopupMainToolbMenu(w, WID_TE_SMALL_MAP, list, 0); - return CBF_NONE; -} - -/** - * Handle click on one of the entries in the Map menu. - * - * @param index Index being clicked. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickMap(int index) -{ - switch (index) { - case MME_SHOW_SMALLMAP: ShowSmallMap(); break; - case MME_SHOW_EXTRAVIEWPORTS: ShowExtraViewPortWindow(); break; - case MME_SHOW_LINKGRAPH: ShowLinkGraphLegend(); break; - case MME_SHOW_SIGNLISTS: ShowSignList(); break; - case MME_SHOW_TOWNDIRECTORY: ShowTownDirectory(); break; - case MME_SHOW_INDUSTRYDIRECTORY: ShowIndustryDirectory(); break; - } - return CBF_NONE; -} - -/* --- Town button menu --- */ - -static CallBackFunction ToolbarTownClick(Window *w) -{ - PopupMainToolbMenu(w, WID_TN_TOWNS, STR_TOWN_MENU_TOWN_DIRECTORY, (_settings_game.economy.found_town == TF_FORBIDDEN) ? 1 : 2); - return CBF_NONE; -} - -/** - * Handle click on one of the entries in the Town menu. - * - * @param index Index being clicked. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickTown(int index) -{ - switch (index) { - case 0: ShowTownDirectory(); break; - case 1: // setting could be changed when the dropdown was open - if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow(); - break; - } - return CBF_NONE; -} - -/* --- Subidies button menu --- */ - -static CallBackFunction ToolbarSubsidiesClick(Window *w) -{ - PopupMainToolbMenu(w, WID_TN_SUBSIDIES, STR_SUBSIDIES_MENU_SUBSIDIES, 1); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Subsidies menu. - * - * @param index Unused. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickSubsidies(int index) -{ - switch (index) { - case 0: ShowSubsidiesList(); break; - } - return CBF_NONE; -} - -/* --- Stations button menu --- */ - -static CallBackFunction ToolbarStationsClick(Window *w) -{ - PopupMainCompanyToolbMenu(w, WID_TN_STATIONS); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Stations menu - * - * @param index CompanyID to show station list for - * @return #CBF_NONE - */ -static CallBackFunction MenuClickStations(int index) -{ - ShowCompanyStations((CompanyID)index); - return CBF_NONE; -} - -/* --- Finances button menu --- */ - -static CallBackFunction ToolbarFinancesClick(Window *w) -{ - PopupMainCompanyToolbMenu(w, WID_TN_FINANCES); - return CBF_NONE; -} - -/** - * Handle click on the entry in the finances overview menu. - * - * @param index CompanyID to show finances for. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickFinances(int index) -{ - ShowCompanyFinances((CompanyID)index); - return CBF_NONE; -} - -/* --- Company's button menu --- */ - -static CallBackFunction ToolbarCompaniesClick(Window *w) -{ - PopupMainCompanyToolbMenu(w, WID_TN_COMPANIES, 0, true); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Company menu. - * - * @param index Menu entry to handle. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickCompany(int index) -{ -#ifdef ENABLE_NETWORK - if (_networking) { - switch (index) { - case CTMN_CLIENT_LIST: - ShowClientList(); - return CBF_NONE; - - case CTMN_NEW_COMPANY: - if (_network_server) { - DoCommandP(0, 0, _network_own_client_id, CMD_COMPANY_CTRL); - } else { - NetworkSendCommand(0, 0, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company); - } - return CBF_NONE; - - case CTMN_SPECTATE: - if (_network_server) { - NetworkServerDoMove(CLIENT_ID_SERVER, COMPANY_SPECTATOR); - MarkWholeScreenDirty(); - } else { - NetworkClientRequestMove(COMPANY_SPECTATOR); - } - return CBF_NONE; - } - } -#endif /* ENABLE_NETWORK */ - ShowCompany((CompanyID)index); - return CBF_NONE; -} - -/* --- Story button menu --- */ - -static CallBackFunction ToolbarStoryClick(Window *w) -{ - PopupMainCompanyToolbMenu(w, WID_TN_STORY, 0, true); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Story menu - * - * @param index CompanyID to show story book for - * @return #CBF_NONE - */ -static CallBackFunction MenuClickStory(int index) -{ - ShowStoryBook(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index); - return CBF_NONE; -} - -/* --- Goal button menu --- */ - -static CallBackFunction ToolbarGoalClick(Window *w) -{ - PopupMainCompanyToolbMenu(w, WID_TN_GOAL, 0, true); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Goal menu - * - * @param index CompanyID to show story book for - * @return #CBF_NONE - */ -static CallBackFunction MenuClickGoal(int index) -{ - ShowGoalsList(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index); - return CBF_NONE; -} - -/* --- Graphs button menu --- */ - -static CallBackFunction ToolbarGraphsClick(Window *w) -{ - PopupMainToolbMenu(w, WID_TN_GRAPHS, STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH, (_toolbar_mode == TB_NORMAL) ? 6 : 8); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Graphs menu. - * - * @param index Graph to show. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickGraphs(int index) -{ - switch (index) { - case 0: ShowOperatingProfitGraph(); break; - case 1: ShowIncomeGraph(); break; - case 2: ShowDeliveredCargoGraph(); break; - case 3: ShowPerformanceHistoryGraph(); break; - case 4: ShowCompanyValueGraph(); break; - case 5: ShowCargoPaymentRates(); break; - /* functions for combined graphs/league button */ - case 6: ShowCompanyLeagueTable(); break; - case 7: ShowPerformanceRatingDetail(); break; - } - return CBF_NONE; -} - -/* --- League button menu --- */ - -static CallBackFunction ToolbarLeagueClick(Window *w) -{ - PopupMainToolbMenu(w, WID_TN_LEAGUE, STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, _networking ? 2 : 3); - return CBF_NONE; -} - -/** - * Handle click on the entry in the CompanyLeague menu. - * - * @param index Menu entry number. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickLeague(int index) -{ - switch (index) { - case 0: ShowCompanyLeagueTable(); break; - case 1: ShowPerformanceRatingDetail(); break; - case 2: ShowHighscoreTable(); break; - } - return CBF_NONE; -} - -/* --- Industries button menu --- */ - -static CallBackFunction ToolbarIndustryClick(Window *w) -{ - /* Disable build-industry menu if we are a spectator */ - PopupMainToolbMenu(w, WID_TN_INDUSTRIES, STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, (_local_company == COMPANY_SPECTATOR) ? 2 : 3); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Industry menu. - * - * @param index Menu entry number. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickIndustry(int index) -{ - switch (index) { - case 0: ShowIndustryDirectory(); break; - case 1: ShowIndustryCargoesWindow(); break; - case 2: ShowBuildIndustryWindow(); break; - } - return CBF_NONE; -} - -/* --- Trains button menu + 1 helper function for all vehicles. --- */ - -static void ToolbarVehicleClick(Window *w, VehicleType veh) -{ - const Vehicle *v; - int dis = ~0; - - FOR_ALL_VEHICLES(v) { - if (v->type == veh && v->IsPrimaryVehicle()) ClrBit(dis, v->owner); - } - PopupMainCompanyToolbMenu(w, WID_TN_VEHICLE_START + veh, dis); -} - - -static CallBackFunction ToolbarTrainClick(Window *w) -{ - ToolbarVehicleClick(w, VEH_TRAIN); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Train menu. - * - * @param index CompanyID to show train list for. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickShowTrains(int index) -{ - ShowVehicleListWindow((CompanyID)index, VEH_TRAIN); - return CBF_NONE; -} - -/* --- Road vehicle button menu --- */ - -static CallBackFunction ToolbarRoadClick(Window *w) -{ - ToolbarVehicleClick(w, VEH_ROAD); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Road Vehicles menu. - * - * @param index CompanyID to show road vehicles list for. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickShowRoad(int index) -{ - ShowVehicleListWindow((CompanyID)index, VEH_ROAD); - return CBF_NONE; -} - -/* --- Ship button menu --- */ - -static CallBackFunction ToolbarShipClick(Window *w) -{ - ToolbarVehicleClick(w, VEH_SHIP); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Ships menu. - * - * @param index CompanyID to show ship list for. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickShowShips(int index) -{ - ShowVehicleListWindow((CompanyID)index, VEH_SHIP); - return CBF_NONE; -} - -/* --- Aircraft button menu --- */ - -static CallBackFunction ToolbarAirClick(Window *w) -{ - ToolbarVehicleClick(w, VEH_AIRCRAFT); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Aircraft menu. - * - * @param index CompanyID to show aircraft list for. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickShowAir(int index) -{ - ShowVehicleListWindow((CompanyID)index, VEH_AIRCRAFT); - return CBF_NONE; -} - -/* --- Zoom in button --- */ - -static CallBackFunction ToolbarZoomInClick(Window *w) -{ - if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) { - w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_IN : (byte)WID_TN_ZOOM_IN); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - } - return CBF_NONE; -} - -/* --- Zoom out button --- */ - -static CallBackFunction ToolbarZoomOutClick(Window *w) -{ - if (DoZoomInOutWindow(ZOOM_OUT, FindWindowById(WC_MAIN_WINDOW, 0))) { - w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_OUT : (byte)WID_TN_ZOOM_OUT); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - } - return CBF_NONE; -} - -/* --- Rail button menu --- */ - -static CallBackFunction ToolbarBuildRailClick(Window *w) -{ - ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true, true); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Build Rail menu. - * - * @param index RailType to show the build toolbar for. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickBuildRail(int index) -{ - _last_built_railtype = (RailType)index; - ShowBuildRailToolbar(_last_built_railtype); - return CBF_NONE; -} - -/* --- Road button menu --- */ - -static CallBackFunction ToolbarBuildRoadClick(Window *w) -{ - const Company *c = Company::Get(_local_company); - DropDownList *list = new DropDownList(); - - /* Road is always visible and available. */ - *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_ROAD_CONSTRUCTION, ROADTYPE_ROAD, false); - - /* Tram is only visible when there will be a tram, and available when that has been introduced. */ - Engine *e; - FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { - if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; - if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue; - - *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_TRAM_CONSTRUCTION, ROADTYPE_TRAM, !HasBit(c->avail_roadtypes, ROADTYPE_TRAM)); - break; - } - ShowDropDownList(w, list, _last_built_roadtype, WID_TN_ROADS, 140, true, true); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Build Road menu. - * - * @param index RoadType to show the build toolbar for. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickBuildRoad(int index) -{ - _last_built_roadtype = (RoadType)index; - ShowBuildRoadToolbar(_last_built_roadtype); - return CBF_NONE; -} - -/* --- Water button menu --- */ - -static CallBackFunction ToolbarBuildWaterClick(Window *w) -{ - PopupMainToolbMenu(w, WID_TN_WATER, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 1); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Build Waterways menu. - * - * @param index Unused. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickBuildWater(int index) -{ - ShowBuildDocksToolbar(); - return CBF_NONE; -} - -/* --- Airport button menu --- */ - -static CallBackFunction ToolbarBuildAirClick(Window *w) -{ - PopupMainToolbMenu(w, WID_TN_AIR, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 1); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Build Air menu. - * - * @param index Unused. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickBuildAir(int index) -{ - ShowBuildAirToolbar(); - return CBF_NONE; -} - -/* --- Forest button menu --- */ - -static CallBackFunction ToolbarForestClick(Window *w) -{ - PopupMainToolbMenu(w, WID_TN_LANDSCAPE, STR_LANDSCAPING_MENU_LANDSCAPING, 3); - return CBF_NONE; -} - -/** - * Handle click on the entry in the landscaping menu. - * - * @param index Menu entry clicked. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickForest(int index) -{ - switch (index) { - case 0: ShowTerraformToolbar(); break; - case 1: ShowBuildTreesToolbar(); break; - case 2: return SelectSignTool(); - } - return CBF_NONE; -} - -/* --- Music button menu --- */ - -static CallBackFunction ToolbarMusicClick(Window *w) -{ - PopupMainToolbMenu(w, WID_TN_MUSIC_SOUND, STR_TOOLBAR_SOUND_MUSIC, 1); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Music menu. - * - * @param index Unused. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickMusicWindow(int index) -{ - ShowMusicWindow(); - return CBF_NONE; -} - -/* --- Newspaper button menu --- */ - -static CallBackFunction ToolbarNewspaperClick(Window *w) -{ - PopupMainToolbMenu(w, WID_TN_MESSAGES, STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT, 2); - return CBF_NONE; -} - -/** - * Handle click on the entry in the Newspaper menu. - * - * @param index Menu entry clicked. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickNewspaper(int index) -{ - switch (index) { - case 0: ShowLastNewsMessage(); break; - case 1: ShowMessageHistory(); break; - } - return CBF_NONE; -} - -/* --- Help button menu --- */ - -static CallBackFunction PlaceLandBlockInfo() -{ - if (_cursor.sprite == SPR_CURSOR_QUERY) { - ResetObjectToPlace(); - return CBF_NONE; - } else { - SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0); - return CBF_PLACE_LANDINFO; - } -} - -static CallBackFunction ToolbarHelpClick(Window *w) -{ - PopupMainToolbMenu(w, WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 12 : 9); - return CBF_NONE; -} - -static void MenuClickSmallScreenshot() -{ - MakeScreenshot(SC_VIEWPORT, NULL); -} - -/** - * Callback on the confirmation window for huge screenshots. - * @param w Window with viewport - * @param confirmed true on confirmation - */ -static void ScreenshotConfirmCallback(Window *w, bool confirmed) -{ - if (confirmed) MakeScreenshot(_confirmed_screenshot_type, NULL); -} - -/** - * Make a screenshot of the world. - * Ask for confirmation if the screenshot will be huge. - * @param t Screenshot type: World or viewport screenshot - */ -static void MenuClickLargeWorldScreenshot(ScreenshotType t) -{ - ViewPort vp; - SetupScreenshotViewport(t, &vp); - if ((uint64)vp.width * (uint64)vp.height > 8192 * 8192) { - /* Ask for confirmation */ - SetDParam(0, vp.width); - SetDParam(1, vp.height); - _confirmed_screenshot_type = t; - ShowQuery(STR_WARNING_SCREENSHOT_SIZE_CAPTION, STR_WARNING_SCREENSHOT_SIZE_MESSAGE, NULL, ScreenshotConfirmCallback); - } else { - /* Less than 64M pixels, just do it */ - MakeScreenshot(t, NULL); - } -} - -/** - * Toggle drawing of sprites' bounding boxes. - * @note has only an effect when newgrf_developer_tools are active. - * - * Function is found here and not in viewport.cpp in order to avoid - * importing the settings structs to there. - */ -void ToggleBoundingBoxes() -{ - extern bool _draw_bounding_boxes; - /* Always allow to toggle them off */ - if (_settings_client.gui.newgrf_developer_tools || _draw_bounding_boxes) { - _draw_bounding_boxes = !_draw_bounding_boxes; - MarkWholeScreenDirty(); - } -} - -/** - * Toggle drawing of the dirty blocks. - * @note has only an effect when newgrf_developer_tools are active. - * - * Function is found here and not in viewport.cpp in order to avoid - * importing the settings structs to there. - */ -void ToggleDirtyBlocks() -{ - extern bool _draw_dirty_blocks; - /* Always allow to toggle them off */ - if (_settings_client.gui.newgrf_developer_tools || _draw_dirty_blocks) { - _draw_dirty_blocks = !_draw_dirty_blocks; - MarkWholeScreenDirty(); - } -} - -/** - * Set the starting year for a scenario. - * @param year New starting year. - */ -void SetStartingYear(Year year) -{ - _settings_game.game_creation.starting_year = Clamp(year, MIN_YEAR, MAX_YEAR); - Date new_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1); - /* If you open a savegame as scenario there may already be link graphs.*/ - LinkGraphSchedule::Instance()->ShiftDates(new_date - _date); - SetDate(new_date, 0); -} - -/** - * Choose the proper callback function for the main toolbar's help menu. - * @param index The menu index which was selected. - * @return CBF_NONE - */ -static CallBackFunction MenuClickHelp(int index) -{ - switch (index) { - case 0: return PlaceLandBlockInfo(); - case 2: IConsoleSwitch(); break; - case 3: ShowAIDebugWindow(); break; - case 4: MenuClickSmallScreenshot(); break; - case 5: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break; - case 6: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break; - case 7: MenuClickLargeWorldScreenshot(SC_WORLD); break; - case 8: ShowAboutWindow(); break; - case 9: ShowSpriteAlignerWindow(); break; - case 10: ToggleBoundingBoxes(); break; - case 11: ToggleDirtyBlocks(); break; - } - return CBF_NONE; -} - -/* --- Switch toolbar button --- */ - -static CallBackFunction ToolbarSwitchClick(Window *w) -{ - if (_toolbar_mode != TB_LOWER) { - _toolbar_mode = TB_LOWER; - } else { - _toolbar_mode = TB_UPPER; - } - - w->ReInit(); - w->SetWidgetLoweredState(WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - return CBF_NONE; -} - -/* --- Scenario editor specific handlers. */ - -/** - * Called when clicking at the date panel of the scenario editor toolbar. - */ -static CallBackFunction ToolbarScenDatePanel(Window *w) -{ - SetDParam(0, _settings_game.game_creation.starting_year); - ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, w, CS_NUMERAL, QSF_ENABLE_DEFAULT); - _left_button_clicked = false; - return CBF_NONE; -} - -static CallBackFunction ToolbarScenDateBackward(Window *w) -{ - /* don't allow too fast scrolling */ - if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) { - w->HandleButtonClick(WID_TE_DATE_BACKWARD); - w->SetDirty(); - - SetStartingYear(_settings_game.game_creation.starting_year - 1); - } - _left_button_clicked = false; - return CBF_NONE; -} - -static CallBackFunction ToolbarScenDateForward(Window *w) -{ - /* don't allow too fast scrolling */ - if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) { - w->HandleButtonClick(WID_TE_DATE_FORWARD); - w->SetDirty(); - - SetStartingYear(_settings_game.game_creation.starting_year + 1); - } - _left_button_clicked = false; - return CBF_NONE; -} - -static CallBackFunction ToolbarScenGenLand(Window *w) -{ - w->HandleButtonClick(WID_TE_LAND_GENERATE); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - - ShowEditorTerraformToolbar(); - return CBF_NONE; -} - - -static CallBackFunction ToolbarScenGenTown(Window *w) -{ - w->HandleButtonClick(WID_TE_TOWN_GENERATE); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - ShowFoundTownWindow(); - return CBF_NONE; -} - -static CallBackFunction ToolbarScenGenIndustry(Window *w) -{ - w->HandleButtonClick(WID_TE_INDUSTRY); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - ShowBuildIndustryWindow(); - return CBF_NONE; -} - -static CallBackFunction ToolbarScenBuildRoad(Window *w) -{ - w->HandleButtonClick(WID_TE_ROADS); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - ShowBuildRoadScenToolbar(); - return CBF_NONE; -} - -static CallBackFunction ToolbarScenBuildDocks(Window *w) -{ - w->HandleButtonClick(WID_TE_WATER); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - ShowBuildDocksScenToolbar(); - return CBF_NONE; -} - -static CallBackFunction ToolbarScenPlantTrees(Window *w) -{ - w->HandleButtonClick(WID_TE_TREES); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - ShowBuildTreesToolbar(); - return CBF_NONE; -} - -static CallBackFunction ToolbarScenPlaceSign(Window *w) -{ - w->HandleButtonClick(WID_TE_SIGNS); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - return SelectSignTool(); -} - -static CallBackFunction ToolbarBtn_NULL(Window *w) -{ - return CBF_NONE; -} - -typedef CallBackFunction MenuClickedProc(int index); - -static MenuClickedProc * const _menu_clicked_procs[] = { - NULL, // 0 - NULL, // 1 - MenuClickSettings, // 2 - MenuClickSaveLoad, // 3 - MenuClickMap, // 4 - MenuClickTown, // 5 - MenuClickSubsidies, // 6 - MenuClickStations, // 7 - MenuClickFinances, // 8 - MenuClickCompany, // 9 - MenuClickStory, // 10 - MenuClickGoal, // 11 - MenuClickGraphs, // 12 - MenuClickLeague, // 13 - MenuClickIndustry, // 14 - MenuClickShowTrains, // 15 - MenuClickShowRoad, // 16 - MenuClickShowShips, // 17 - MenuClickShowAir, // 18 - MenuClickMap, // 19 - NULL, // 20 - MenuClickBuildRail, // 21 - MenuClickBuildRoad, // 22 - MenuClickBuildWater, // 23 - MenuClickBuildAir, // 24 - MenuClickForest, // 25 - MenuClickMusicWindow, // 26 - MenuClickNewspaper, // 27 - MenuClickHelp, // 28 -}; - -/** Full blown container to make it behave exactly as we want :) */ -class NWidgetToolbarContainer : public NWidgetContainer { - bool visible[WID_TN_END]; ///< The visible headers -protected: - uint spacers; ///< Number of spacer widgets in this toolbar - -public: - NWidgetToolbarContainer() : NWidgetContainer(NWID_HORIZONTAL) - { - } - - /** - * Check whether the given widget type is a button for us. - * @param type the widget type to check. - * @return true if it is a button for us. - */ - bool IsButton(WidgetType type) const - { - return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN; - } - - void SetupSmallestSize(Window *w, bool init_array) - { - this->smallest_x = 0; // Biggest child - this->smallest_y = 0; // Biggest child - this->fill_x = 1; - this->fill_y = 0; - this->resize_x = 1; // We only resize in this direction - this->resize_y = 0; // We never resize in this direction - this->spacers = 0; - - uint nbuttons = 0; - /* First initialise some variables... */ - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - child_wid->SetupSmallestSize(w, init_array); - this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); - if (this->IsButton(child_wid->type)) { - nbuttons++; - this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); - } else if (child_wid->type == NWID_SPACER) { - this->spacers++; - } - } - - /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */ - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - child_wid->current_y = this->smallest_y; - if (!this->IsButton(child_wid->type)) { - child_wid->current_x = child_wid->smallest_x; - } - } - w->window_desc->default_width = nbuttons * this->smallest_x; - } - - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) - { - assert(given_width >= this->smallest_x && given_height >= this->smallest_y); - - this->pos_x = x; - this->pos_y = y; - this->current_x = given_width; - this->current_y = given_height; - - /* Figure out what are the visible buttons */ - memset(this->visible, 0, sizeof(this->visible)); - uint arrangable_count, button_count, spacer_count; - const byte *arrangement = GetButtonArrangement(given_width, arrangable_count, button_count, spacer_count); - for (uint i = 0; i < arrangable_count; i++) { - this->visible[arrangement[i]] = true; - } - - /* Create us ourselves a quick lookup table */ - NWidgetBase *widgets[WID_TN_END]; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - if (child_wid->type == NWID_SPACER) continue; - widgets[((NWidgetCore*)child_wid)->index] = child_wid; - } - - /* Now assign the widgets to their rightful place */ - uint position = 0; // Place to put next child relative to origin of the container. - uint spacer_space = max(0, (int)given_width - (int)(button_count * this->smallest_x)); // Remaining spacing for 'spacer' widgets - uint button_space = given_width - spacer_space; // Remaining spacing for the buttons - uint spacer_i = 0; - uint button_i = 0; - - /* Index into the arrangement indices. The macro lastof cannot be used here! */ - const byte *cur_wid = rtl ? &arrangement[arrangable_count - 1] : arrangement; - for (uint i = 0; i < arrangable_count; i++) { - NWidgetBase *child_wid = widgets[*cur_wid]; - /* If we have to give space to the spacers, do that */ - if (spacer_space != 0) { - NWidgetBase *possible_spacer = rtl ? child_wid->next : child_wid->prev; - if (possible_spacer != NULL && possible_spacer->type == NWID_SPACER) { - uint add = spacer_space / (spacer_count - spacer_i); - position += add; - spacer_space -= add; - spacer_i++; - } - } - - /* Buttons can be scaled, the others not. */ - if (this->IsButton(child_wid->type)) { - child_wid->current_x = button_space / (button_count - button_i); - button_space -= child_wid->current_x; - button_i++; - } - child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl); - position += child_wid->current_x; - - if (rtl) { - cur_wid--; - } else { - cur_wid++; - } - } - } - - /* virtual */ void Draw(const Window *w) - { - /* Draw brown-red toolbar bg. */ - GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, PC_VERY_DARK_RED); - GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, PC_DARK_RED, FILLRECT_CHECKER); - - bool rtl = _current_text_dir == TD_RTL; - for (NWidgetBase *child_wid = rtl ? this->tail : this->head; child_wid != NULL; child_wid = rtl ? child_wid->prev : child_wid->next) { - if (child_wid->type == NWID_SPACER) continue; - if (!this->visible[((NWidgetCore*)child_wid)->index]) continue; - - child_wid->Draw(w); - } - } - - /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y) - { - if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; - - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - if (child_wid->type == NWID_SPACER) continue; - if (!this->visible[((NWidgetCore*)child_wid)->index]) continue; - - NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y); - if (nwid != NULL) return nwid; - } - return NULL; - } - - /** - * Get the arrangement of the buttons for the toolbar. - * @param width the new width of the toolbar. - * @param arrangable_count output of the number of visible items. - * @param button_count output of the number of visible buttons. - * @param spacer_count output of the number of spacers. - * @return the button configuration. - */ - virtual const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const = 0; -}; - -/** Container for the 'normal' main toolbar */ -class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { - /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const - { - static const uint SMALLEST_ARRANGEMENT = 14; - static const uint BIGGEST_ARRANGEMENT = 20; - static const byte arrange14[] = { - 0, 1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 29, - 2, 3, 4, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29, - }; - static const byte arrange15[] = { - 0, 1, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, - 0, 2, 4, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29, - }; - static const byte arrange16[] = { - 0, 1, 2, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, - 0, 1, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29, - }; - static const byte arrange17[] = { - 0, 1, 2, 4, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, - 0, 1, 3, 4, 6, 5, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29, - }; - static const byte arrange18[] = { - 0, 1, 2, 4, 5, 6, 7, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29, - 0, 1, 3, 4, 5, 6, 7, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29, - }; - static const byte arrange19[] = { - 0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 19, 20, 29, - 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 28, 19, 20, 29, - }; - static const byte arrange20[] = { - 0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 11, 19, 20, 29, - 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29, - }; - static const byte arrange_all[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 - }; - - /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */ - uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT); - if (full_buttons > BIGGEST_ARRANGEMENT) { - button_count = arrangable_count = lengthof(arrange_all); - spacer_count = this->spacers; - return arrange_all; - } - - /* Introduce the split toolbar */ - static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 }; - - button_count = arrangable_count = full_buttons; - spacer_count = this->spacers; - return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0); - } -}; - -/** Container for the scenario editor's toolbar */ -class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { - uint panel_widths[2]; ///< The width of the two panels (the text panel and date panel) - - void SetupSmallestSize(Window *w, bool init_array) - { - this->NWidgetToolbarContainer::SetupSmallestSize(w, init_array); - - /* Find the size of panel_widths */ - uint i = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue; - - assert(i < lengthof(this->panel_widths)); - this->panel_widths[i++] = child_wid->current_x; - w->window_desc->default_width += child_wid->current_x; - } - } - - /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const - { - static const byte arrange_all[] = { - 0, 1, 2, 3, 4, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28, - }; - static const byte arrange_nopanel[] = { - 0, 1, 2, 3, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28, - }; - static const byte arrange_switch[] = { - 18, 8, 11, 12, 13, 14, 15, 16, 17, 29, - 0, 1, 2, 3, 18, 9, 10, 26, 28, 29, - }; - - /* If we can place all buttons *and* the panels, show them. */ - uint min_full_width = (lengthof(arrange_all) - lengthof(this->panel_widths)) * this->smallest_x + this->panel_widths[0] + this->panel_widths[1]; - if (width >= min_full_width) { - width -= this->panel_widths[0] + this->panel_widths[1]; - arrangable_count = lengthof(arrange_all); - button_count = arrangable_count - 2; - spacer_count = this->spacers; - return arrange_all; - } - - /* Otherwise don't show the date panel and if we can't fit half the buttons and the panels anymore, split the toolbar in two */ - uint min_small_width = (lengthof(arrange_switch) - lengthof(this->panel_widths)) * this->smallest_x / 2 + this->panel_widths[1]; - if (width > min_small_width) { - width -= this->panel_widths[1]; - arrangable_count = lengthof(arrange_nopanel); - button_count = arrangable_count - 1; - spacer_count = this->spacers - 1; - return arrange_nopanel; - } - - /* Split toolbar */ - width -= this->panel_widths[1]; - arrangable_count = lengthof(arrange_switch) / 2; - button_count = arrangable_count - 1; - spacer_count = 0; - return arrange_switch + ((_toolbar_mode == TB_LOWER) ? arrangable_count : 0); - } -}; - -/* --- Toolbar handling for the 'normal' case */ - -typedef CallBackFunction ToolbarButtonProc(Window *w); - -static ToolbarButtonProc * const _toolbar_button_procs[] = { - ToolbarPauseClick, - ToolbarFastForwardClick, - ToolbarOptionsClick, - ToolbarSaveClick, - ToolbarMapClick, - ToolbarTownClick, - ToolbarSubsidiesClick, - ToolbarStationsClick, - ToolbarFinancesClick, - ToolbarCompaniesClick, - ToolbarStoryClick, - ToolbarGoalClick, - ToolbarGraphsClick, - ToolbarLeagueClick, - ToolbarIndustryClick, - ToolbarTrainClick, - ToolbarRoadClick, - ToolbarShipClick, - ToolbarAirClick, - ToolbarZoomInClick, - ToolbarZoomOutClick, - ToolbarBuildRailClick, - ToolbarBuildRoadClick, - ToolbarBuildWaterClick, - ToolbarBuildAirClick, - ToolbarForestClick, - ToolbarMusicClick, - ToolbarNewspaperClick, - ToolbarHelpClick, - ToolbarSwitchClick, -}; - -enum MainToolbarHotkeys { - MTHK_PAUSE, - MTHK_FASTFORWARD, - MTHK_SETTINGS, - MTHK_SAVEGAME, - MTHK_LOADGAME, - MTHK_SMALLMAP, - MTHK_TOWNDIRECTORY, - MTHK_SUBSIDIES, - MTHK_STATIONS, - MTHK_FINANCES, - MTHK_COMPANIES, - MTHK_STORY, - MTHK_GOAL, - MTHK_GRAPHS, - MTHK_LEAGUE, - MTHK_INDUSTRIES, - MTHK_TRAIN_LIST, - MTHK_ROADVEH_LIST, - MTHK_SHIP_LIST, - MTHK_AIRCRAFT_LIST, - MTHK_ZOOM_IN, - MTHK_ZOOM_OUT, - MTHK_BUILD_RAIL, - MTHK_BUILD_ROAD, - MTHK_BUILD_DOCKS, - MTHK_BUILD_AIRPORT, - MTHK_BUILD_TREES, - MTHK_MUSIC, - MTHK_AI_DEBUG, - MTHK_SMALL_SCREENSHOT, - MTHK_ZOOMEDIN_SCREENSHOT, - MTHK_DEFAULTZOOM_SCREENSHOT, - MTHK_GIANT_SCREENSHOT, - MTHK_CHEATS, - MTHK_TERRAFORM, - MTHK_EXTRA_VIEWPORT, - MTHK_CLIENT_LIST, - MTHK_SIGN_LIST, -}; - -/** Main toolbar. */ -struct MainToolbarWindow : Window { - CallBackFunction last_started_action; ///< Last started user action. - - MainToolbarWindow(WindowDesc *desc) : Window(desc) - { - this->InitNested(0); - - this->last_started_action = CBF_NONE; - CLRBITS(this->flags, WF_WHITE_BORDER); - this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !_network_server); // if not server, disable pause button - this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button - PositionMainToolbar(this); - DoZoomInOutWindow(ZOOM_NONE, this); - } - - virtual void OnPaint() - { - /* If spectator, disable all construction buttons - * ie : Build road, rail, ships, airports and landscaping - * Since enabled state is the default, just disable when needed */ - this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END); - /* disable company list drop downs, if there are no companies */ - this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFTS, WIDGET_LIST_END); - - this->SetWidgetDisabledState(WID_TN_GOAL, Goal::GetNumItems() == 0); - this->SetWidgetDisabledState(WID_TN_STORY, StoryPage::GetNumItems() == 0); - - this->SetWidgetDisabledState(WID_TN_RAILS, !CanBuildVehicleInfrastructure(VEH_TRAIN)); - this->SetWidgetDisabledState(WID_TN_AIR, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT)); - - this->DrawWidgets(); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this); - } - - virtual void OnDropdownSelect(int widget, int index) - { - CallBackFunction cbf = _menu_clicked_procs[widget](index); - if (cbf != CBF_NONE) this->last_started_action = cbf; - } - - virtual EventState OnHotkey(int hotkey) - { - switch (hotkey) { - case MTHK_PAUSE: ToolbarPauseClick(this); break; - case MTHK_FASTFORWARD: ToolbarFastForwardClick(this); break; - case MTHK_SETTINGS: ShowGameOptions(); break; - case MTHK_SAVEGAME: MenuClickSaveLoad(); break; - case MTHK_LOADGAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break; - case MTHK_SMALLMAP: ShowSmallMap(); break; - case MTHK_TOWNDIRECTORY: ShowTownDirectory(); break; - case MTHK_SUBSIDIES: ShowSubsidiesList(); break; - case MTHK_STATIONS: ShowCompanyStations(_local_company); break; - case MTHK_FINANCES: ShowCompanyFinances(_local_company); break; - case MTHK_COMPANIES: ShowCompany(_local_company); break; - case MTHK_STORY: ShowStoryBook(_local_company); break; - case MTHK_GOAL: ShowGoalsList(_local_company); break; - case MTHK_GRAPHS: ShowOperatingProfitGraph(); break; - case MTHK_LEAGUE: ShowCompanyLeagueTable(); break; - case MTHK_INDUSTRIES: ShowBuildIndustryWindow(); break; - case MTHK_TRAIN_LIST: ShowVehicleListWindow(_local_company, VEH_TRAIN); break; - case MTHK_ROADVEH_LIST: ShowVehicleListWindow(_local_company, VEH_ROAD); break; - case MTHK_SHIP_LIST: ShowVehicleListWindow(_local_company, VEH_SHIP); break; - case MTHK_AIRCRAFT_LIST: ShowVehicleListWindow(_local_company, VEH_AIRCRAFT); break; - case MTHK_ZOOM_IN: ToolbarZoomInClick(this); break; - case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break; - case MTHK_BUILD_RAIL: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype); break; - case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break; - case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break; - case MTHK_BUILD_AIRPORT: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break; - case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break; - case MTHK_MUSIC: ShowMusicWindow(); break; - case MTHK_AI_DEBUG: ShowAIDebugWindow(); break; - case MTHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break; - case MTHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break; - case MTHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break; - case MTHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break; - case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break; - case MTHK_TERRAFORM: ShowTerraformToolbar(); break; - case MTHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break; -#ifdef ENABLE_NETWORK - case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break; -#endif - case MTHK_SIGN_LIST: ShowSignList(); break; - default: return ES_NOT_HANDLED; - } - return ES_HANDLED; - } - - virtual void OnPlaceObject(Point pt, TileIndex tile) - { - switch (this->last_started_action) { - case CBF_PLACE_SIGN: - PlaceProc_Sign(tile); - break; - - case CBF_PLACE_LANDINFO: - ShowLandInfo(tile); - break; - - default: NOT_REACHED(); - } - } - - virtual void OnTick() - { - if (this->IsWidgetLowered(WID_TN_PAUSE) != !!_pause_mode) { - this->ToggleWidgetLoweredState(WID_TN_PAUSE); - this->SetWidgetDirty(WID_TN_PAUSE); - } - - if (this->IsWidgetLowered(WID_TN_FAST_FORWARD) != !!_fast_forward) { - this->ToggleWidgetLoweredState(WID_TN_FAST_FORWARD); - this->SetWidgetDirty(WID_TN_FAST_FORWARD); - } - } - - virtual void OnTimeout() - { - /* We do not want to automatically raise the pause, fast forward and - * switchbar buttons; they have to stay down when pressed etc. */ - for (uint i = WID_TN_SETTINGS; i < WID_TN_SWITCH_BAR; i++) { - if (this->IsWidgetLowered(i)) { - this->RaiseWidget(i); - this->SetWidgetDirty(i); - } - } - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT); - } - - static HotkeyList hotkeys; -}; - -const uint16 _maintoolbar_pause_keys[] = {WKC_F1, WKC_PAUSE, 0}; -const uint16 _maintoolbar_zoomin_keys[] = {WKC_NUM_PLUS, WKC_EQUALS, WKC_SHIFT | WKC_EQUALS, WKC_SHIFT | WKC_F5, 0}; -const uint16 _maintoolbar_zoomout_keys[] = {WKC_NUM_MINUS, WKC_MINUS, WKC_SHIFT | WKC_MINUS, WKC_SHIFT | WKC_F6, 0}; -const uint16 _maintoolbar_smallmap_keys[] = {WKC_F4, 'M', 0}; - -static Hotkey maintoolbar_hotkeys[] = { - Hotkey(_maintoolbar_pause_keys, "pause", MTHK_PAUSE), - Hotkey((uint16)0, "fastforward", MTHK_FASTFORWARD), - Hotkey(WKC_F2, "settings", MTHK_SETTINGS), - Hotkey(WKC_F3, "saveload", MTHK_SAVEGAME), - Hotkey((uint16)0, "load_game", MTHK_LOADGAME), - Hotkey(_maintoolbar_smallmap_keys, "smallmap", MTHK_SMALLMAP), - Hotkey(WKC_F5, "town_list", MTHK_TOWNDIRECTORY), - Hotkey(WKC_F6, "subsidies", MTHK_SUBSIDIES), - Hotkey(WKC_F7, "station_list", MTHK_STATIONS), - Hotkey(WKC_F8, "finances", MTHK_FINANCES), - Hotkey(WKC_F9, "companies", MTHK_COMPANIES), - Hotkey((uint16)0, "story_book", MTHK_STORY), - Hotkey((uint16)0, "goal_list", MTHK_GOAL), - Hotkey(WKC_F10, "graphs", MTHK_GRAPHS), - Hotkey(WKC_F11, "league", MTHK_LEAGUE), - Hotkey(WKC_F12, "industry_list", MTHK_INDUSTRIES), - Hotkey(WKC_SHIFT | WKC_F1, "train_list", MTHK_TRAIN_LIST), - Hotkey(WKC_SHIFT | WKC_F2, "roadveh_list", MTHK_ROADVEH_LIST), - Hotkey(WKC_SHIFT | WKC_F3, "ship_list", MTHK_SHIP_LIST), - Hotkey(WKC_SHIFT | WKC_F4, "aircraft_list", MTHK_AIRCRAFT_LIST), - Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTHK_ZOOM_IN), - Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTHK_ZOOM_OUT), - Hotkey(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL), - Hotkey(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD), - Hotkey(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS), - Hotkey(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT), - Hotkey(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES), - Hotkey(WKC_SHIFT | WKC_F12, "music", MTHK_MUSIC), - Hotkey((uint16)0, "ai_debug", MTHK_AI_DEBUG), - Hotkey(WKC_CTRL | 'S', "small_screenshot", MTHK_SMALL_SCREENSHOT), - Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTHK_ZOOMEDIN_SCREENSHOT), - Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTHK_DEFAULTZOOM_SCREENSHOT), - Hotkey((uint16)0, "giant_screenshot", MTHK_GIANT_SCREENSHOT), - Hotkey(WKC_CTRL | WKC_ALT | 'C', "cheats", MTHK_CHEATS), - Hotkey('L', "terraform", MTHK_TERRAFORM), - Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT), -#ifdef ENABLE_NETWORK - Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST), -#endif - Hotkey((uint16)0, "sign_list", MTHK_SIGN_LIST), - HOTKEY_LIST_END -}; -HotkeyList MainToolbarWindow::hotkeys("maintoolbar", maintoolbar_hotkeys); - -static NWidgetBase *MakeMainToolbar(int *biggest_index) -{ - /** Sprites to use for the different toolbar buttons */ - static const SpriteID toolbar_button_sprites[] = { - SPR_IMG_PAUSE, // WID_TN_PAUSE - SPR_IMG_FASTFORWARD, // WID_TN_FAST_FORWARD - SPR_IMG_SETTINGS, // WID_TN_SETTINGS - SPR_IMG_SAVE, // WID_TN_SAVE - SPR_IMG_SMALLMAP, // WID_TN_SMALL_MAP - SPR_IMG_TOWN, // WID_TN_TOWNS - SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES - SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS - SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES - SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES - SPR_IMG_STORY_BOOK, // WID_TN_STORY - SPR_IMG_GOAL, // WID_TN_GOAL - SPR_IMG_GRAPHS, // WID_TN_GRAPHS - SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE - SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES - SPR_IMG_TRAINLIST, // WID_TN_TRAINS - SPR_IMG_TRUCKLIST, // WID_TN_ROADVEHS - SPR_IMG_SHIPLIST, // WID_TN_SHIPS - SPR_IMG_AIRPLANESLIST, // WID_TN_AIRCRAFT - SPR_IMG_ZOOMIN, // WID_TN_ZOOMIN - SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT - SPR_IMG_BUILDRAIL, // WID_TN_RAILS - SPR_IMG_BUILDROAD, // WID_TN_ROADS - SPR_IMG_BUILDWATER, // WID_TN_WATER - SPR_IMG_BUILDAIR, // WID_TN_AIR - SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE - SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND - SPR_IMG_MESSAGES, // WID_TN_MESSAGES - SPR_IMG_QUERY, // WID_TN_HELP - SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR - }; - - NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer(); - for (uint i = 0; i < WID_TN_END; i++) { - switch (i) { - case 4: case 8: case 15: case 19: case 21: case 26: hor->Add(new NWidgetSpacer(0, 0)); break; - } - hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); - } - - *biggest_index = max(*biggest_index, WID_TN_SWITCH_BAR); - return hor; -} - -static const NWidgetPart _nested_toolbar_normal_widgets[] = { - NWidgetFunction(MakeMainToolbar), -}; - -static WindowDesc _toolb_normal_desc( - WDP_MANUAL, NULL, 640, 22, - WC_MAIN_TOOLBAR, WC_NONE, - WDF_NO_FOCUS, - _nested_toolbar_normal_widgets, lengthof(_nested_toolbar_normal_widgets), - &MainToolbarWindow::hotkeys -); - - -/* --- Toolbar handling for the scenario editor */ - -static ToolbarButtonProc * const _scen_toolbar_button_procs[] = { - ToolbarPauseClick, - ToolbarFastForwardClick, - ToolbarOptionsClick, - ToolbarScenSaveOrLoad, - ToolbarBtn_NULL, - ToolbarScenDatePanel, - ToolbarScenDateBackward, - ToolbarScenDateForward, - ToolbarScenMapTownDir, - ToolbarZoomInClick, - ToolbarZoomOutClick, - ToolbarScenGenLand, - ToolbarScenGenTown, - ToolbarScenGenIndustry, - ToolbarScenBuildRoad, - ToolbarScenBuildDocks, - ToolbarScenPlantTrees, - ToolbarScenPlaceSign, - ToolbarBtn_NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - ToolbarMusicClick, - NULL, - ToolbarHelpClick, - ToolbarSwitchClick, -}; - -enum MainToolbarEditorHotkeys { - MTEHK_PAUSE, - MTEHK_FASTFORWARD, - MTEHK_SETTINGS, - MTEHK_SAVEGAME, - MTEHK_GENLAND, - MTEHK_GENTOWN, - MTEHK_GENINDUSTRY, - MTEHK_BUILD_ROAD, - MTEHK_BUILD_DOCKS, - MTEHK_BUILD_TREES, - MTEHK_SIGN, - MTEHK_MUSIC, - MTEHK_LANDINFO, - MTEHK_SMALL_SCREENSHOT, - MTEHK_ZOOMEDIN_SCREENSHOT, - MTEHK_DEFAULTZOOM_SCREENSHOT, - MTEHK_GIANT_SCREENSHOT, - MTEHK_ZOOM_IN, - MTEHK_ZOOM_OUT, - MTEHK_TERRAFORM, - MTEHK_SMALLMAP, - MTEHK_EXTRA_VIEWPORT, -}; - -struct ScenarioEditorToolbarWindow : Window { - CallBackFunction last_started_action; ///< Last started user action. - - ScenarioEditorToolbarWindow(WindowDesc *desc) : Window(desc) - { - this->InitNested(0); - - this->last_started_action = CBF_NONE; - CLRBITS(this->flags, WF_WHITE_BORDER); - PositionMainToolbar(this); - DoZoomInOutWindow(ZOOM_NONE, this); - } - - virtual void OnPaint() - { - this->SetWidgetDisabledState(WID_TE_DATE_BACKWARD, _settings_game.game_creation.starting_year <= MIN_YEAR); - this->SetWidgetDisabledState(WID_TE_DATE_FORWARD, _settings_game.game_creation.starting_year >= MAX_YEAR); - - this->DrawWidgets(); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_TE_DATE: - SetDParam(0, ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1)); - DrawString(r.left, r.right, (this->height - FONT_HEIGHT_NORMAL) / 2, STR_WHITE_DATE_LONG, TC_FROMSTRING, SA_HOR_CENTER); - break; - - case WID_TE_SPACER: { - int height = r.bottom - r.top; - if (height > 2 * FONT_HEIGHT_NORMAL) { - DrawString(r.left, r.right, (height + 1) / 2 - FONT_HEIGHT_NORMAL, STR_SCENEDIT_TOOLBAR_OPENTTD, TC_FROMSTRING, SA_HOR_CENTER); - DrawString(r.left, r.right, (height + 1) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER); - } else { - DrawString(r.left, r.right, (height - FONT_HEIGHT_NORMAL) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER); - } - break; - } - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_TE_SPACER: - size->width = max(GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_OPENTTD).width, GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - break; - - case WID_TE_DATE: - SetDParam(0, ConvertYMDToDate(MAX_YEAR, 0, 1)); - *size = GetStringBoundingBox(STR_WHITE_DATE_LONG); - size->height = max(size->height, GetSpriteSize(SPR_IMG_SAVE).height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM); - break; - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - if (_game_mode == GM_MENU) return; - CallBackFunction cbf = _scen_toolbar_button_procs[widget](this); - if (cbf != CBF_NONE) this->last_started_action = cbf; - } - - virtual void OnDropdownSelect(int widget, int index) - { - /* The map button is in a different location on the scenario - * editor toolbar, so we need to adjust for it. */ - if (widget == WID_TE_SMALL_MAP) widget = WID_TN_SMALL_MAP; - CallBackFunction cbf = _menu_clicked_procs[widget](index); - if (cbf != CBF_NONE) this->last_started_action = cbf; - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - } - - virtual EventState OnHotkey(int hotkey) - { - CallBackFunction cbf = CBF_NONE; - switch (hotkey) { - case MTEHK_PAUSE: ToolbarPauseClick(this); break; - case MTEHK_FASTFORWARD: ToolbarFastForwardClick(this); break; - case MTEHK_SETTINGS: ShowGameOptions(); break; - case MTEHK_SAVEGAME: MenuClickSaveLoad(); break; - case MTEHK_GENLAND: ToolbarScenGenLand(this); break; - case MTEHK_GENTOWN: ToolbarScenGenTown(this); break; - case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break; - case MTEHK_BUILD_ROAD: ToolbarScenBuildRoad(this); break; - case MTEHK_BUILD_DOCKS: ToolbarScenBuildDocks(this); break; - case MTEHK_BUILD_TREES: ToolbarScenPlantTrees(this); break; - case MTEHK_SIGN: cbf = ToolbarScenPlaceSign(this); break; - case MTEHK_MUSIC: ShowMusicWindow(); break; - case MTEHK_LANDINFO: cbf = PlaceLandBlockInfo(); break; - case MTEHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break; - case MTEHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break; - case MTEHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break; - case MTEHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break; - case MTEHK_ZOOM_IN: ToolbarZoomInClick(this); break; - case MTEHK_ZOOM_OUT: ToolbarZoomOutClick(this); break; - case MTEHK_TERRAFORM: ShowEditorTerraformToolbar(); break; - case MTEHK_SMALLMAP: ShowSmallMap(); break; - case MTEHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break; - default: return ES_NOT_HANDLED; - } - if (cbf != CBF_NONE) this->last_started_action = cbf; - return ES_HANDLED; - } - - virtual void OnPlaceObject(Point pt, TileIndex tile) - { - switch (this->last_started_action) { - case CBF_PLACE_SIGN: - PlaceProc_Sign(tile); - break; - - case CBF_PLACE_LANDINFO: - ShowLandInfo(tile); - break; - - default: NOT_REACHED(); - } - } - - virtual void OnTimeout() - { - this->SetWidgetsLoweredState(false, WID_TE_DATE_BACKWARD, WID_TE_DATE_FORWARD, WIDGET_LIST_END); - this->SetWidgetDirty(WID_TE_DATE_BACKWARD); - this->SetWidgetDirty(WID_TE_DATE_FORWARD); - } - - virtual void OnTick() - { - if (this->IsWidgetLowered(WID_TE_PAUSE) != !!_pause_mode) { - this->ToggleWidgetLoweredState(WID_TE_PAUSE); - this->SetDirty(); - } - - if (this->IsWidgetLowered(WID_TE_FAST_FORWARD) != !!_fast_forward) { - this->ToggleWidgetLoweredState(WID_TE_FAST_FORWARD); - this->SetDirty(); - } - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT); - } - - virtual void OnQueryTextFinished(char *str) - { - /* Was 'cancel' pressed? */ - if (str == NULL) return; - - int32 value; - if (!StrEmpty(str)) { - value = atoi(str); - } else { - /* An empty string means revert to the default */ - value = DEF_START_YEAR; - } - SetStartingYear(value); - - this->SetDirty(); - } - - static HotkeyList hotkeys; -}; - -static Hotkey scenedit_maintoolbar_hotkeys[] = { - Hotkey(_maintoolbar_pause_keys, "pause", MTEHK_PAUSE), - Hotkey((uint16)0, "fastforward", MTEHK_FASTFORWARD), - Hotkey(WKC_F2, "settings", MTEHK_SETTINGS), - Hotkey(WKC_F3, "saveload", MTEHK_SAVEGAME), - Hotkey(WKC_F4, "gen_land", MTEHK_GENLAND), - Hotkey(WKC_F5, "gen_town", MTEHK_GENTOWN), - Hotkey(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY), - Hotkey(WKC_F7, "build_road", MTEHK_BUILD_ROAD), - Hotkey(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS), - Hotkey(WKC_F9, "build_trees", MTEHK_BUILD_TREES), - Hotkey(WKC_F10, "build_sign", MTEHK_SIGN), - Hotkey(WKC_F11, "music", MTEHK_MUSIC), - Hotkey(WKC_F12, "land_info", MTEHK_LANDINFO), - Hotkey(WKC_CTRL | 'S', "small_screenshot", MTEHK_SMALL_SCREENSHOT), - Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTEHK_ZOOMEDIN_SCREENSHOT), - Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTEHK_DEFAULTZOOM_SCREENSHOT), - Hotkey((uint16)0, "giant_screenshot", MTEHK_GIANT_SCREENSHOT), - Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTEHK_ZOOM_IN), - Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTEHK_ZOOM_OUT), - Hotkey('L', "terraform", MTEHK_TERRAFORM), - Hotkey('M', "smallmap", MTEHK_SMALLMAP), - Hotkey('V', "extra_viewport", MTEHK_EXTRA_VIEWPORT), - HOTKEY_LIST_END -}; -HotkeyList ScenarioEditorToolbarWindow::hotkeys("scenedit_maintoolbar", scenedit_maintoolbar_hotkeys); - -static const NWidgetPart _nested_toolb_scen_inner_widgets[] = { - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS), - NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO), - NWidget(NWID_SPACER), - NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(), - NWidget(NWID_SPACER), - NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL), - NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD), - EndContainer(), - EndContainer(), - NWidget(NWID_SPACER), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY), - NWidget(NWID_SPACER), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), - NWidget(NWID_SPACER), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), - NWidget(NWID_SPACER), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR), -}; - -static NWidgetBase *MakeScenarioToolbar(int *biggest_index) -{ - return MakeNWidgets(_nested_toolb_scen_inner_widgets, lengthof(_nested_toolb_scen_inner_widgets), biggest_index, new NWidgetScenarioToolbarContainer()); -} - -static const NWidgetPart _nested_toolb_scen_widgets[] = { - NWidgetFunction(MakeScenarioToolbar), -}; - -static WindowDesc _toolb_scen_desc( - WDP_MANUAL, NULL, 640, 22, - WC_MAIN_TOOLBAR, WC_NONE, - WDF_NO_FOCUS, - _nested_toolb_scen_widgets, lengthof(_nested_toolb_scen_widgets), - &ScenarioEditorToolbarWindow::hotkeys -); - -/** Allocate the toolbar. */ -void AllocateToolbar() -{ - /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */ - _last_built_roadtype = ROADTYPE_ROAD; - - if (_game_mode == GM_EDITOR) { - new ScenarioEditorToolbarWindow(&_toolb_scen_desc); - } else { - new MainToolbarWindow(&_toolb_normal_desc); - } -} diff --git a/src/town_gui.cpp.orig b/src/town_gui.cpp.orig deleted file mode 100644 index 76ee227e29..0000000000 --- a/src/town_gui.cpp.orig +++ /dev/null @@ -1,1199 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file town_gui.cpp GUI for towns. */ - -#include "stdafx.h" -#include "town.h" -#include "viewport_func.h" -#include "error.h" -#include "gui.h" -#include "command_func.h" -#include "company_func.h" -#include "company_base.h" -#include "company_gui.h" -#include "network/network.h" -#include "string_func.h" -#include "strings_func.h" -#include "sound_func.h" -#include "tilehighlight_func.h" -#include "sortlist_type.h" -#include "road_cmd.h" -#include "landscape.h" -#include "querystring_gui.h" -#include "window_func.h" -#include "townname_func.h" -#include "core/geometry_func.hpp" -#include "genworld.h" -#include "widgets/dropdown_func.h" - -#include "widgets/town_widget.h" - -#include "table/strings.h" - -typedef GUIList GUITownList; - -static const NWidgetPart _nested_town_authority_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_BROWN), - NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TA_CAPTION), SetDataTip(STR_LOCAL_AUTHORITY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_BROWN), - NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), - NWidget(WWT_STICKYBOX, COLOUR_BROWN), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), SetFill(1, 1), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_COMMAND_LIST), SetMinimalSize(305, 52), SetResize(1, 0), SetDataTip(0x0, STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), SetScrollbar(WID_TA_SCROLLBAR), EndContainer(), - NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_TA_SCROLLBAR), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 1), SetFill(1, 1), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TA_EXECUTE), SetMinimalSize(317, 12), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_LOCAL_AUTHORITY_DO_IT_BUTTON, STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP), - NWidget(WWT_RESIZEBOX, COLOUR_BROWN), - EndContainer() -}; - -/** Town authority window. */ -struct TownAuthorityWindow : Window { -private: - Town *town; ///< Town being displayed. - int sel_index; ///< Currently selected town action, \c 0 to \c TACT_COUNT-1, \c -1 means no action selected. - Scrollbar *vscroll; - uint actions_step; - uint displayed_actions_on_previous_painting; ///< Actions that were available on the previous call to OnPaint() - - /** - * Get the position of the Nth set bit. - * - * If there is no Nth bit set return -1 - * - * @param bits The value to search in - * @param n The Nth set bit from which we want to know the position - * @return The position of the Nth set bit - */ - static int GetNthSetBit(uint32 bits, int n) - { - if (n >= 0) { - uint i; - FOR_EACH_SET_BIT(i, bits) { - n--; - if (n < 0) return i; - } - } - return -1; - } - -public: - TownAuthorityWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), sel_index(-1), displayed_actions_on_previous_painting(0) - { - this->town = Town::Get(window_number); - this->InitNested(window_number); - this->vscroll = this->GetScrollbar(WID_TA_SCROLLBAR); - this->actions_step = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - this->vscroll->SetCapacity((this->GetWidget(WID_TA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / this->actions_step); - } - - virtual void OnPaint() - { - int numact; - uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); - if (buttons != displayed_actions_on_previous_painting) this->SetDirty(); - displayed_actions_on_previous_painting = buttons; - - this->vscroll->SetCount(numact + 1); - - if (this->sel_index != -1 && !HasBit(buttons, this->sel_index)) { - this->sel_index = -1; - } - - this->SetWidgetDisabledState(WID_TA_EXECUTE, this->sel_index == -1); - - this->DrawWidgets(); - if (!this->IsShaded()) this->DrawRatings(); - } - - /** Draw the contents of the ratings panel. May request a resize of the window if the contents does not fit. */ - void DrawRatings() - { - NWidgetBase *nwid = this->GetWidget(WID_TA_RATING_INFO); - uint left = nwid->pos_x + WD_FRAMERECT_LEFT; - uint right = nwid->pos_x + nwid->current_x - 1 - WD_FRAMERECT_RIGHT; - - uint y = nwid->pos_y + WD_FRAMERECT_TOP; - - DrawString(left, right, y, STR_LOCAL_AUTHORITY_COMPANY_RATINGS); - y += FONT_HEIGHT_NORMAL; - - Dimension icon_size = GetSpriteSize(SPR_COMPANY_ICON); - int icon_width = icon_size.width; - int icon_y_offset = (FONT_HEIGHT_NORMAL - icon_size.height) / 2; - - Dimension exclusive_size = GetSpriteSize(SPR_EXCLUSIVE_TRANSPORT); - int exclusive_width = exclusive_size.width; - int exclusive_y_offset = (FONT_HEIGHT_NORMAL - exclusive_size.height) / 2; - - bool rtl = _current_text_dir == TD_RTL; - uint text_left = left + (rtl ? 0 : icon_width + exclusive_width + 4); - uint text_right = right - (rtl ? icon_width + exclusive_width + 4 : 0); - uint icon_left = rtl ? right - icon_width : left; - uint exclusive_left = rtl ? right - icon_width - exclusive_width - 2 : left + icon_width + 2; - - /* Draw list of companies */ - const Company *c; - FOR_ALL_COMPANIES(c) { - if ((HasBit(this->town->have_ratings, c->index) || this->town->exclusivity == c->index)) { - DrawCompanyIcon(c->index, icon_left, y + icon_y_offset); - - SetDParam(0, c->index); - SetDParam(1, c->index); - - int r = this->town->ratings[c->index]; - StringID str; - (str = STR_CARGO_RATING_APPALLING, r <= RATING_APPALLING) || // Apalling - (str++, r <= RATING_VERYPOOR) || // Very Poor - (str++, r <= RATING_POOR) || // Poor - (str++, r <= RATING_MEDIOCRE) || // Mediocore - (str++, r <= RATING_GOOD) || // Good - (str++, r <= RATING_VERYGOOD) || // Very Good - (str++, r <= RATING_EXCELLENT) || // Excellent - (str++, true); // Outstanding - - SetDParam(2, str); - if (this->town->exclusivity == c->index) { - DrawSprite(SPR_EXCLUSIVE_TRANSPORT, COMPANY_SPRITE_COLOUR(c->index), exclusive_left, y + exclusive_y_offset); - } - - DrawString(text_left, text_right, y, STR_LOCAL_AUTHORITY_COMPANY_RATING); - y += FONT_HEIGHT_NORMAL; - } - } - - y = y + WD_FRAMERECT_BOTTOM - nwid->pos_y; // Compute needed size of the widget. - if (y > nwid->current_y) { - /* If the company list is too big to fit, mark ourself dirty and draw again. */ - ResizeWindow(this, 0, y - nwid->current_y); - } - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_TA_CAPTION) SetDParam(0, this->window_number); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_TA_ACTION_INFO: - if (this->sel_index != -1) { - SetDParam(0, _price[PR_TOWN_ACTION] * _town_action_costs[this->sel_index] >> 8); - DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, - STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING + this->sel_index); - } - break; - case WID_TA_COMMAND_LIST: { - int numact; - uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); - int y = Center(r.top, this->actions_step); - int pos = this->vscroll->GetPosition(); - - if (--pos < 0) { - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTIONS_TITLE); - y += this->actions_step; - } - - for (int i = 0; buttons; i++, buttons >>= 1) { - if (pos <= -5) break; ///< Draw only the 5 fitting lines - - if ((buttons & 1) && --pos < 0) { - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, - STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i, this->sel_index == i ? TC_WHITE : TC_ORANGE); - y += this->actions_step; - } - } - break; - } - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_TA_ACTION_INFO: { - assert(size->width > padding.width && size->height > padding.height); - size->width -= WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - size->height -= WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - Dimension d = {0, 0}; - for (int i = 0; i < TACT_COUNT; i++) { - SetDParam(0, _price[PR_TOWN_ACTION] * _town_action_costs[i] >> 8); - d = maxdim(d, GetStringMultiLineBoundingBox(STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING + i, *size)); - } - *size = maxdim(*size, d); - size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - break; - } - - case WID_TA_COMMAND_LIST: - resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; - size->width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width; - for (uint i = 0; i < TACT_COUNT; i++ ) { - size->width = max(size->width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i).width); - } - size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - break; - - case WID_TA_RATING_INFO: - resize->height = FONT_HEIGHT_NORMAL; - size->height = WD_FRAMERECT_TOP + 9 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; - break; - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_TA_COMMAND_LIST: { - int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, this->actions_step); - if (!IsInsideMM(y, 0, 5)) return; - - y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_company, this->town), y + this->vscroll->GetPosition() - 1); - if (y >= 0) { - this->sel_index = y; - this->SetDirty(); - } - /* FALL THROUGH, when double-clicking. */ - if (click_count == 1 || y < 0) break; - } - - case WID_TA_EXECUTE: - DoCommandP(this->town->xy, this->window_number, this->sel_index, CMD_DO_TOWN_ACTION | CMD_MSG(STR_ERROR_CAN_T_DO_THIS)); - break; - } - } - - virtual void OnHundredthTick() - { - this->SetDirty(); - } -}; - -static WindowDesc _town_authority_desc( - WDP_AUTO, "view_town_authority", 317, 222, - WC_TOWN_AUTHORITY, WC_NONE, - 0, - _nested_town_authority_widgets, lengthof(_nested_town_authority_widgets) -); - -static void ShowTownAuthorityWindow(uint town) -{ - AllocateWindowDescFront(&_town_authority_desc, town); -} - - -/* Town view window. */ -struct TownViewWindow : Window { -private: - Town *town; ///< Town displayed by the window. - -public: - static const int WID_TV_HEIGHT_NORMAL = 150; - - TownViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) - { - this->CreateNestedTree(); - - this->town = Town::Get(window_number); - if (this->town->larger_town) this->GetWidget(WID_TV_CAPTION)->widget_data = STR_TOWN_VIEW_CITY_CAPTION; - - this->FinishInitNested(window_number); - - this->flags |= WF_DISABLE_VP_SCROLL; - NWidgetViewport *nvp = this->GetWidget(WID_TV_VIEWPORT); - nvp->InitializeViewport(this, this->town->xy, ZOOM_LVL_NEWS); - - /* disable renaming town in network games if you are not the server */ - this->SetWidgetDisabledState(WID_TV_CHANGE_NAME, _networking && !_network_server); - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_TV_CAPTION) SetDParam(0, this->town->index); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (widget != WID_TV_INFO) return; - - uint y = r.top + WD_FRAMERECT_TOP; - - SetDParam(0, this->town->cache.population); - SetDParam(1, this->town->cache.num_houses); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, STR_TOWN_VIEW_POPULATION_HOUSES); - - SetDParam(0, this->town->supplied[CT_PASSENGERS].old_act); - SetDParam(1, this->town->supplied[CT_PASSENGERS].old_max); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX); - - SetDParam(0, this->town->supplied[CT_MAIL].old_act); - SetDParam(1, this->town->supplied[CT_MAIL].old_max); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX); - - bool first = true; - for (int i = TE_BEGIN; i < TE_END; i++) { - if (this->town->goal[i] == 0) continue; - if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue; - if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue; - - if (first) { - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH); - first = false; - } - - bool rtl = _current_text_dir == TD_RTL; - uint cargo_text_left = r.left + WD_FRAMERECT_LEFT + (rtl ? 0 : 20); - uint cargo_text_right = r.right - WD_FRAMERECT_RIGHT - (rtl ? 20 : 0); - - const CargoSpec *cargo = FindFirstCargoWithTownEffect((TownEffect)i); - assert(cargo != NULL); - - StringID string; - - if (this->town->goal[i] == TOWN_GROWTH_DESERT || this->town->goal[i] == TOWN_GROWTH_WINTER) { - /* For 'original' gameplay, don't show the amount required (you need 1 or more ..) */ - string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL; - if (this->town->received[i].old_act == 0) { - string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL; - - if (this->town->goal[i] == TOWN_GROWTH_WINTER && TileHeight(this->town->xy) < GetSnowLine()) { - string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER; - } - } - - SetDParam(0, cargo->name); - } else { - string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED; - if (this->town->received[i].old_act < this->town->goal[i]) { - string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED; - } - - SetDParam(0, cargo->Index()); - SetDParam(1, this->town->received[i].old_act); - SetDParam(2, cargo->Index()); - SetDParam(3, this->town->goal[i]); - } - DrawString(cargo_text_left, cargo_text_right, y += FONT_HEIGHT_NORMAL, string); - } - - if (HasBit(this->town->flags, TOWN_IS_GROWING)) { - SetDParam(0, ((this->town->growth_rate & (~TOWN_GROW_RATE_CUSTOM)) * TOWN_GROWTH_TICKS + DAY_TICKS) / DAY_TICKS); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, this->town->fund_buildings_months == 0 ? STR_TOWN_VIEW_TOWN_GROWS_EVERY : STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED); - } else { - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_TOWN_GROW_STOPPED); - } - - /* only show the town noise, if the noise option is activated. */ - if (_settings_game.economy.station_noise_level) { - SetDParam(0, this->town->noise_reached); - SetDParam(1, this->town->MaxTownNoise()); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_NOISE_IN_TOWN); - } - - if (this->town->text != NULL) { - SetDParamStr(0, this->town->text); - DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK); - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_TV_CENTER_VIEW: // scroll to location - if (_ctrl_pressed) { - ShowExtraViewPortWindow(this->town->xy); - } else { - ScrollMainWindowToTile(this->town->xy); - } - break; - - case WID_TV_SHOW_AUTHORITY: // town authority - ShowTownAuthorityWindow(this->window_number); - break; - - case WID_TV_CHANGE_NAME: // rename - SetDParam(0, this->window_number); - ShowQueryString(STR_TOWN_NAME, STR_TOWN_VIEW_RENAME_TOWN_BUTTON, MAX_LENGTH_TOWN_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); - break; - - case WID_TV_EXPAND: { // expand town - only available on Scenario editor - /* Warn the user if towns are not allowed to build roads, but do this only once per OpenTTD run. */ - static bool _warn_town_no_roads = false; - - if (!_settings_game.economy.allow_town_roads && !_warn_town_no_roads) { - ShowErrorMessage(STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS, INVALID_STRING_ID, WL_WARNING); - _warn_town_no_roads = true; - } - - DoCommandP(0, this->window_number, 0, CMD_EXPAND_TOWN | CMD_MSG(STR_ERROR_CAN_T_EXPAND_TOWN)); - break; - } - - case WID_TV_DELETE: // delete town - only available on Scenario editor - DoCommandP(0, this->window_number, 0, CMD_DELETE_TOWN | CMD_MSG(STR_ERROR_TOWN_CAN_T_DELETE)); - break; - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_TV_INFO: - size->height = GetDesiredInfoHeight(size->width); - break; - } - } - - /** - * Gets the desired height for the information panel. - * @return the desired height in pixels. - */ - uint GetDesiredInfoHeight(int width) const - { - uint aimed_height = 3 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - - bool first = true; - for (int i = TE_BEGIN; i < TE_END; i++) { - if (this->town->goal[i] == 0) continue; - if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue; - if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue; - - if (first) { - aimed_height += FONT_HEIGHT_NORMAL; - first = false; - } - aimed_height += FONT_HEIGHT_NORMAL; - } - aimed_height += FONT_HEIGHT_NORMAL; - - if (_settings_game.economy.station_noise_level) aimed_height += FONT_HEIGHT_NORMAL; - - if (this->town->text != NULL) { - SetDParamStr(0, this->town->text); - aimed_height += GetStringHeight(STR_JUST_RAW_STRING, width); - } - - return aimed_height; - } - - void ResizeWindowAsNeeded() - { - const NWidgetBase *nwid_info = this->GetWidget(WID_TV_INFO); - uint aimed_height = GetDesiredInfoHeight(nwid_info->current_x); - if (aimed_height > nwid_info->current_y || (aimed_height < nwid_info->current_y && nwid_info->current_y > nwid_info->smallest_y)) { - this->ReInit(); - } - } - - virtual void OnResize() - { - if (this->viewport != NULL) { - NWidgetViewport *nvp = this->GetWidget(WID_TV_VIEWPORT); - nvp->UpdateViewportCoordinates(this); - - ScrollWindowToTile(this->town->xy, this, true); // Re-center viewport. - } - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - /* Called when setting station noise or required cargoes have changed, in order to resize the window */ - this->SetDirty(); // refresh display for current size. This will allow to avoid glitches when downgrading - this->ResizeWindowAsNeeded(); - } - - virtual void OnQueryTextFinished(char *str) - { - if (str == NULL) return; - - DoCommandP(0, this->window_number, 0, CMD_RENAME_TOWN | CMD_MSG(STR_ERROR_CAN_T_RENAME_TOWN), NULL, str); - } -}; - -static const NWidgetPart _nested_town_game_view_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_BROWN), - NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_BROWN), - NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), - NWidget(WWT_STICKYBOX, COLOUR_BROWN), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN), - NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2), - NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 0), SetResize(1, 1), SetPadding(1, 1, 1, 1), - EndContainer(), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_SHOW_AUTHORITY), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON, STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP), - EndContainer(), - NWidget(WWT_RESIZEBOX, COLOUR_BROWN), - EndContainer(), -}; - -static WindowDesc _town_game_view_desc( - WDP_AUTO, "view_town", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL, - WC_TOWN_VIEW, WC_NONE, - 0, - _nested_town_game_view_widgets, lengthof(_nested_town_game_view_widgets) -); - -static const NWidgetPart _nested_town_editor_view_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_BROWN), - NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetMinimalSize(76, 14), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP), - NWidget(WWT_SHADEBOX, COLOUR_BROWN), - NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), - NWidget(WWT_STICKYBOX, COLOUR_BROWN), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN), - NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2), - NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 1), SetResize(1, 1), SetPadding(1, 1, 1, 1), - EndContainer(), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_EXPAND_BUTTON, STR_TOWN_VIEW_EXPAND_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_DELETE), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_TOWN_VIEW_DELETE_TOOLTIP), - EndContainer(), - NWidget(WWT_RESIZEBOX, COLOUR_BROWN), - EndContainer(), -}; - -static WindowDesc _town_editor_view_desc( - WDP_AUTO, "view_town_scen", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL, - WC_TOWN_VIEW, WC_NONE, - 0, - _nested_town_editor_view_widgets, lengthof(_nested_town_editor_view_widgets) -); - -void ShowTownViewWindow(TownID town) -{ - if (_game_mode == GM_EDITOR) { - AllocateWindowDescFront(&_town_editor_view_desc, town); - } else { - AllocateWindowDescFront(&_town_game_view_desc, town); - } -} - -static const NWidgetPart _nested_town_directory_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_BROWN), - NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_TOWN_DIRECTORY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_BROWN), - NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), - NWidget(WWT_STICKYBOX, COLOUR_BROWN), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_VERTICAL), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TD_SORT_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_TD_SORT_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), - NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TD_LIST), SetMinimalSize(196, 0), SetDataTip(0x0, STR_TOWN_DIRECTORY_LIST_TOOLTIP), - SetFill(1, 0), SetResize(0, 10), SetScrollbar(WID_TD_SCROLLBAR), EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN), - NWidget(WWT_TEXT, COLOUR_BROWN, WID_TD_WORLD_POPULATION), SetPadding(2, 0, 0, 2), SetMinimalSize(196, 12), SetFill(1, 0), SetDataTip(STR_TOWN_POPULATION, STR_NULL), - EndContainer(), - EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_TD_SCROLLBAR), - NWidget(WWT_RESIZEBOX, COLOUR_BROWN), - EndContainer(), - EndContainer(), -}; - -/** Town directory window class. */ -struct TownDirectoryWindow : public Window { -private: - /* Runtime saved values */ - static Listing last_sorting; - static const Town *last_town; - - /* Constants for sorting towns */ - static const StringID sorter_names[]; - static GUITownList::SortFunction * const sorter_funcs[]; - - GUITownList towns; - - Scrollbar *vscroll; - - void BuildSortTownList() - { - if (this->towns.NeedRebuild()) { - this->towns.Clear(); - - const Town *t; - FOR_ALL_TOWNS(t) { - *this->towns.Append() = t; - } - - this->towns.Compact(); - this->towns.RebuildDone(); - this->vscroll->SetCount(this->towns.Length()); // Update scrollbar as well. - } - /* Always sort the towns. */ - this->last_town = NULL; - this->towns.Sort(); - this->SetWidgetDirty(WID_TD_LIST); // Force repaint of the displayed towns. - } - - /** Sort by town name */ - static int CDECL TownNameSorter(const Town * const *a, const Town * const *b) - { - static char buf_cache[64]; - const Town *ta = *a; - const Town *tb = *b; - char buf[64]; - - SetDParam(0, ta->index); - GetString(buf, STR_TOWN_NAME, lastof(buf)); - - /* If 'b' is the same town as in the last round, use the cached value - * We do this to speed stuff up ('b' is called with the same value a lot of - * times after each other) */ - if (tb != last_town) { - last_town = tb; - SetDParam(0, tb->index); - GetString(buf_cache, STR_TOWN_NAME, lastof(buf_cache)); - } - - return strnatcmp(buf, buf_cache); // Sort by name (natural sorting). - } - - /** Sort by population (default descending, as big towns are of the most interest). */ - static int CDECL TownPopulationSorter(const Town * const *a, const Town * const *b) - { - uint32 a_population = (*a)->cache.population; - uint32 b_population = (*b)->cache.population; - if (a_population == b_population) return TownDirectoryWindow::TownNameSorter(a, b); - return (a_population < b_population) ? -1 : 1; - } - - /** Sort by town rating */ - static int CDECL TownRatingSorter(const Town * const *a, const Town * const *b) - { - int before = TownDirectoryWindow::last_sorting.order ? 1 : -1; // Value to get 'a' before 'b'. - - /* Towns without rating are always after towns with rating. */ - if (HasBit((*a)->have_ratings, _local_company)) { - if (HasBit((*b)->have_ratings, _local_company)) { - int16 a_rating = (*a)->ratings[_local_company]; - int16 b_rating = (*b)->ratings[_local_company]; - if (a_rating == b_rating) return TownDirectoryWindow::TownNameSorter(a, b); - return (a_rating < b_rating) ? -1 : 1; - } - return before; - } - if (HasBit((*b)->have_ratings, _local_company)) return -before; - return -before * TownDirectoryWindow::TownNameSorter(a, b); // Sort unrated towns always on ascending town name. - } - -public: - TownDirectoryWindow(WindowDesc *desc) : Window(desc) - { - this->CreateNestedTree(); - - this->vscroll = this->GetScrollbar(WID_TD_SCROLLBAR); - - this->towns.SetListing(this->last_sorting); - this->towns.SetSortFuncs(TownDirectoryWindow::sorter_funcs); - this->towns.ForceRebuild(); - this->BuildSortTownList(); - - this->FinishInitNested(0); - } - - virtual void SetStringParameters(int widget) const - { - switch (widget) { - case WID_TD_WORLD_POPULATION: - SetDParam(0, GetWorldPopulation()); - break; - - case WID_TD_SORT_CRITERIA: - SetDParam(0, TownDirectoryWindow::sorter_names[this->towns.SortType()]); - break; - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_TD_SORT_ORDER: - this->DrawSortButtonState(widget, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP); - break; - - case WID_TD_LIST: { - int n = 0; - int y = r.top + WD_FRAMERECT_TOP; - if (this->towns.Length() == 0) { // No towns available. - DrawString(r.left + WD_FRAMERECT_LEFT, r.right, y, STR_TOWN_DIRECTORY_NONE); - break; - } - - /* At least one town available. */ - bool rtl = _current_text_dir == TD_RTL; - Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD); - int text_left = r.left + WD_FRAMERECT_LEFT + (rtl ? 0 : icon_size.width + 2); - int text_right = r.right - WD_FRAMERECT_RIGHT - (rtl ? icon_size.width + 2 : 0); - int icon_x = rtl ? r.right - WD_FRAMERECT_RIGHT - icon_size.width : r.left + WD_FRAMERECT_LEFT; - - for (uint i = this->vscroll->GetPosition(); i < this->towns.Length(); i++) { - const Town *t = this->towns[i]; - assert(t->xy != INVALID_TILE); - - /* Draw rating icon. */ - if (_game_mode == GM_EDITOR || !HasBit(t->have_ratings, _local_company)) { - DrawSprite(SPR_TOWN_RATING_NA, PAL_NONE, icon_x, y + (this->resize.step_height - icon_size.height) / 2); - } else { - SpriteID icon = SPR_TOWN_RATING_APALLING; - if (t->ratings[_local_company] > RATING_VERYPOOR) icon = SPR_TOWN_RATING_MEDIOCRE; - if (t->ratings[_local_company] > RATING_GOOD) icon = SPR_TOWN_RATING_GOOD; - DrawSprite(icon, PAL_NONE, icon_x, y + (this->resize.step_height - icon_size.height) / 2); - } - - SetDParam(0, t->index); - SetDParam(1, t->cache.population); - DrawString(text_left, text_right, y + (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2, STR_TOWN_DIRECTORY_TOWN); - - y += this->resize.step_height; - if (++n == this->vscroll->GetCapacity()) break; // max number of towns in 1 window - } - break; - } - } - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_TD_SORT_ORDER: { - Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); - d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - case WID_TD_SORT_CRITERIA: { - Dimension d = {0, 0}; - for (uint i = 0; TownDirectoryWindow::sorter_names[i] != INVALID_STRING_ID; i++) { - d = maxdim(d, GetStringBoundingBox(TownDirectoryWindow::sorter_names[i])); - } - d.width += padding.width; - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - case WID_TD_LIST: { - Dimension d = GetStringBoundingBox(STR_TOWN_DIRECTORY_NONE); - for (uint i = 0; i < this->towns.Length(); i++) { - const Town *t = this->towns[i]; - - assert(t != NULL); - - SetDParam(0, t->index); - SetDParamMaxDigits(1, 8); - d = maxdim(d, GetStringBoundingBox(STR_TOWN_DIRECTORY_TOWN)); - } - Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD); - d.width += icon_size.width + 2; - d.height = GetMinSizing(NWST_STEP, max(d.height, icon_size.height)); - resize->height = d.height; - d.height *= 5; - d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - *size = maxdim(*size, d); - break; - } - case WID_TD_WORLD_POPULATION: { - SetDParamMaxDigits(0, 10); - Dimension d = GetStringBoundingBox(STR_TOWN_POPULATION); - d.width += padding.width; - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_TD_SORT_ORDER: // Click on sort order button - if (this->towns.SortType() != 2) { // A different sort than by rating. - this->towns.ToggleSortOrder(); - this->last_sorting = this->towns.GetListing(); // Store new sorting order. - } else { - /* Some parts are always sorted ascending on name. */ - this->last_sorting.order = !this->last_sorting.order; - this->towns.SetListing(this->last_sorting); - this->towns.ForceResort(); - this->towns.Sort(); - } - this->SetDirty(); - break; - - case WID_TD_SORT_CRITERIA: // Click on sort criteria dropdown - ShowDropDownMenu(this, TownDirectoryWindow::sorter_names, this->towns.SortType(), WID_TD_SORT_CRITERIA, 0, 0); - break; - - case WID_TD_LIST: { // Click on Town Matrix - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_TD_LIST, WD_FRAMERECT_TOP); - if (id_v >= this->towns.Length()) return; // click out of town bounds - - const Town *t = this->towns[id_v]; - assert(t != NULL); - if (_ctrl_pressed) { - ShowExtraViewPortWindow(t->xy); - } else { - ScrollMainWindowToTile(t->xy); - } - break; - } - } - } - - virtual void OnDropdownSelect(int widget, int index) - { - if (widget != WID_TD_SORT_CRITERIA) return; - - if (this->towns.SortType() != index) { - this->towns.SetSortType(index); - this->last_sorting = this->towns.GetListing(); // Store new sorting order. - this->BuildSortTownList(); - } - } - - virtual void OnPaint() - { - if (this->towns.NeedRebuild()) this->BuildSortTownList(); - this->DrawWidgets(); - } - - virtual void OnHundredthTick() - { - this->BuildSortTownList(); - this->SetDirty(); - } - - virtual void OnResize() - { - this->vscroll->SetCapacityFromWidget(this, WID_TD_LIST); - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (data == 0) { - /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ - this->towns.ForceRebuild(); - } else { - this->towns.ForceResort(); - } - } -}; - -Listing TownDirectoryWindow::last_sorting = {false, 0}; -const Town *TownDirectoryWindow::last_town = NULL; - -/** Names of the sorting functions. */ -const StringID TownDirectoryWindow::sorter_names[] = { - STR_SORT_BY_NAME, - STR_SORT_BY_POPULATION, - STR_SORT_BY_RATING, - INVALID_STRING_ID -}; - -/** Available town directory sorting functions. */ -GUITownList::SortFunction * const TownDirectoryWindow::sorter_funcs[] = { - &TownNameSorter, - &TownPopulationSorter, - &TownRatingSorter, -}; - -static WindowDesc _town_directory_desc( - WDP_AUTO, "list_towns", 208, 202, - WC_TOWN_DIRECTORY, WC_NONE, - 0, - _nested_town_directory_widgets, lengthof(_nested_town_directory_widgets) -); - -void ShowTownDirectory() -{ - if (BringWindowToFrontById(WC_TOWN_DIRECTORY, 0)) return; - new TownDirectoryWindow(&_town_directory_desc); -} - -void CcFoundTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Failed()) return; - - if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); - if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); -} - -void CcFoundRandomTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Succeeded()) ScrollMainWindowToTile(Town::Get(_new_town_id)->xy); -} - -static const NWidgetPart _nested_found_town_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_FOUND_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), - EndContainer(), - /* Construct new town(s) buttons. */ - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_NEW_TOWN), SetMinimalSize(156, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_NEW_TOWN_BUTTON, STR_FOUND_TOWN_NEW_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_RANDOM_TOWN), SetMinimalSize(156, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_RANDOM_TOWN_BUTTON, STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_MANY_RANDOM_TOWNS), SetMinimalSize(156, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetPadding(0, 2, 0, 2), - /* Town name selection. */ - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(156, 14), SetPadding(0, 2, 0, 2), SetDataTip(STR_FOUND_TOWN_NAME_TITLE, STR_NULL), - NWidget(WWT_EDITBOX, COLOUR_GREY, WID_TF_TOWN_NAME_EDITBOX), SetMinimalSize(156, 12), SetPadding(0, 2, 3, 2), - SetDataTip(STR_FOUND_TOWN_NAME_EDITOR_TITLE, STR_FOUND_TOWN_NAME_EDITOR_HELP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_TOWN_NAME_RANDOM), SetMinimalSize(78, 12), SetPadding(0, 2, 0, 2), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_NAME_RANDOM_BUTTON, STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP), - /* Town size selection. */ - NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_TITLE, STR_NULL), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_SMALL), SetMinimalSize(78, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_MEDIUM), SetMinimalSize(78, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 1), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_LARGE), SetMinimalSize(78, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_RANDOM), SetMinimalSize(78, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_SIZE_RANDOM, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 3), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_CITY), SetPadding(0, 2, 0, 2), SetMinimalSize(156, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_CITY, STR_FOUND_TOWN_CITY_TOOLTIP), SetFill(1, 0), - /* Town roads selection. */ - NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_ROAD_LAYOUT, STR_NULL), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_ORIGINAL), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_BETTER), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 1), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID2), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID3), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_RANDOM), SetPadding(0, 2, 0, 2), SetMinimalSize(0, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), SetFill(1, 0), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - EndContainer(), -}; - -/** Found a town window class. */ -struct FoundTownWindow : Window { -private: - TownSize town_size; ///< Selected town size - TownLayout town_layout; ///< Selected town layout - bool city; ///< Are we building a city? - QueryString townname_editbox; ///< Townname editbox - bool townnamevalid; ///< Is generated town name valid? - uint32 townnameparts; ///< Generated town name - TownNameParams params; ///< Town name parameters - -public: - FoundTownWindow(WindowDesc *desc, WindowNumber window_number) : - Window(desc), - town_size(TSZ_MEDIUM), - town_layout(_settings_game.economy.town_layout), - townname_editbox(MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_TOWN_NAME_CHARS), - params(_settings_game.game_creation.town_name) - { - this->InitNested(window_number); - this->querystrings[WID_TF_TOWN_NAME_EDITBOX] = &this->townname_editbox; - this->RandomTownName(); - this->UpdateButtons(true); - } - - void RandomTownName() - { - this->townnamevalid = GenerateTownName(&this->townnameparts); - - if (!this->townnamevalid) { - this->townname_editbox.text.DeleteAll(); - } else { - GetTownName(this->townname_editbox.text.buf, &this->params, this->townnameparts, &this->townname_editbox.text.buf[this->townname_editbox.text.max_bytes - 1]); - this->townname_editbox.text.UpdateSize(); - } - UpdateOSKOriginalText(this, WID_TF_TOWN_NAME_EDITBOX); - - this->SetWidgetDirty(WID_TF_TOWN_NAME_EDITBOX); - } - - void UpdateButtons(bool check_availability) - { - if (check_availability && _game_mode != GM_EDITOR) { - this->SetWidgetsDisabledState(true, WID_TF_RANDOM_TOWN, WID_TF_MANY_RANDOM_TOWNS, WID_TF_SIZE_LARGE, WIDGET_LIST_END); - this->SetWidgetsDisabledState(_settings_game.economy.found_town != TF_CUSTOM_LAYOUT, - WID_TF_LAYOUT_ORIGINAL, WID_TF_LAYOUT_BETTER, WID_TF_LAYOUT_GRID2, WID_TF_LAYOUT_GRID3, WID_TF_LAYOUT_RANDOM, WIDGET_LIST_END); - if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT) town_layout = _settings_game.economy.town_layout; - } - - for (int i = WID_TF_SIZE_SMALL; i <= WID_TF_SIZE_RANDOM; i++) { - this->SetWidgetLoweredState(i, i == WID_TF_SIZE_SMALL + this->town_size); - } - - this->SetWidgetLoweredState(WID_TF_CITY, this->city); - - for (int i = WID_TF_LAYOUT_ORIGINAL; i <= WID_TF_LAYOUT_RANDOM; i++) { - this->SetWidgetLoweredState(i, i == WID_TF_LAYOUT_ORIGINAL + this->town_layout); - } - - this->SetDirty(); - } - - void ExecuteFoundTownCommand(TileIndex tile, bool random, StringID errstr, CommandCallback cc) - { - const char *name = NULL; - - if (!this->townnamevalid) { - name = this->townname_editbox.text.buf; - } else { - /* If user changed the name, send it */ - char buf[MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH]; - GetTownName(buf, &this->params, this->townnameparts, lastof(buf)); - if (strcmp(buf, this->townname_editbox.text.buf) != 0) name = this->townname_editbox.text.buf; - } - - bool success = DoCommandP(tile, this->town_size | this->city << 2 | this->town_layout << 3 | random << 6, - townnameparts, CMD_FOUND_TOWN | CMD_MSG(errstr), cc, name); - - if (success) this->RandomTownName(); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_TF_NEW_TOWN: - HandlePlacePushButton(this, WID_TF_NEW_TOWN, SPR_CURSOR_TOWN, HT_RECT); - break; - - case WID_TF_RANDOM_TOWN: - this->ExecuteFoundTownCommand(0, true, STR_ERROR_CAN_T_GENERATE_TOWN, CcFoundRandomTown); - break; - - case WID_TF_TOWN_NAME_RANDOM: - this->RandomTownName(); - this->SetFocusedWidget(WID_TF_TOWN_NAME_EDITBOX); - break; - - case WID_TF_MANY_RANDOM_TOWNS: - _generating_world = true; - UpdateNearestTownForRoadTiles(true); - if (!GenerateTowns(this->town_layout)) { - ShowErrorMessage(STR_ERROR_CAN_T_GENERATE_TOWN, STR_ERROR_NO_SPACE_FOR_TOWN, WL_INFO); - } - UpdateNearestTownForRoadTiles(false); - _generating_world = false; - break; - - case WID_TF_SIZE_SMALL: case WID_TF_SIZE_MEDIUM: case WID_TF_SIZE_LARGE: case WID_TF_SIZE_RANDOM: - this->town_size = (TownSize)(widget - WID_TF_SIZE_SMALL); - this->UpdateButtons(false); - break; - - case WID_TF_CITY: - this->city ^= true; - this->SetWidgetLoweredState(WID_TF_CITY, this->city); - this->SetDirty(); - break; - - case WID_TF_LAYOUT_ORIGINAL: case WID_TF_LAYOUT_BETTER: case WID_TF_LAYOUT_GRID2: - case WID_TF_LAYOUT_GRID3: case WID_TF_LAYOUT_RANDOM: - this->town_layout = (TownLayout)(widget - WID_TF_LAYOUT_ORIGINAL); - this->UpdateButtons(false); - break; - } - } - - virtual void OnPlaceObject(Point pt, TileIndex tile) - { - this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown); - } - - virtual void OnPlaceObjectAbort() - { - this->RaiseButtons(); - this->UpdateButtons(false); - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope) return; - this->UpdateButtons(true); - } -}; - -static WindowDesc _found_town_desc( - WDP_AUTO, "build_town", 160, 162, - WC_FOUND_TOWN, WC_NONE, - WDF_CONSTRUCTION, - _nested_found_town_widgets, lengthof(_nested_found_town_widgets) -); - -void ShowFoundTownWindow() -{ - if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return; - AllocateWindowDescFront(&_found_town_desc, 0); -} diff --git a/src/vehicle_gui.cpp.orig b/src/vehicle_gui.cpp.orig deleted file mode 100644 index 3a077e4e50..0000000000 --- a/src/vehicle_gui.cpp.orig +++ /dev/null @@ -1,2840 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file vehicle_gui.cpp The base GUI for all vehicles. */ - -#include "stdafx.h" -#include "debug.h" -#include "company_func.h" -#include "gui.h" -#include "textbuf_gui.h" -#include "command_func.h" -#include "vehicle_gui_base.h" -#include "viewport_func.h" -#include "newgrf_text.h" -#include "newgrf_debug.h" -#include "roadveh.h" -#include "train.h" -#include "aircraft.h" -#include "depot_map.h" -#include "group_gui.h" -#include "strings_func.h" -#include "vehicle_func.h" -#include "autoreplace_gui.h" -#include "string_func.h" -#include "widgets/dropdown_func.h" -#include "timetable.h" -#include "articulated_vehicles.h" -#include "spritecache.h" -#include "core/geometry_func.hpp" -#include "company_base.h" -#include "engine_func.h" -#include "station_base.h" -#include "tilehighlight_func.h" -#include "zoom_func.h" - - -Sorting _sorting; - -static GUIVehicleList::SortFunction VehicleNumberSorter; -static GUIVehicleList::SortFunction VehicleNameSorter; -static GUIVehicleList::SortFunction VehicleAgeSorter; -static GUIVehicleList::SortFunction VehicleProfitThisYearSorter; -static GUIVehicleList::SortFunction VehicleProfitLastYearSorter; -static GUIVehicleList::SortFunction VehicleCargoSorter; -static GUIVehicleList::SortFunction VehicleReliabilitySorter; -static GUIVehicleList::SortFunction VehicleMaxSpeedSorter; -static GUIVehicleList::SortFunction VehicleModelSorter; -static GUIVehicleList::SortFunction VehicleValueSorter; -static GUIVehicleList::SortFunction VehicleLengthSorter; -static GUIVehicleList::SortFunction VehicleTimeToLiveSorter; -static GUIVehicleList::SortFunction VehicleTimetableDelaySorter; - -GUIVehicleList::SortFunction * const BaseVehicleListWindow::vehicle_sorter_funcs[] = { - &VehicleNumberSorter, - &VehicleNameSorter, - &VehicleAgeSorter, - &VehicleProfitThisYearSorter, - &VehicleProfitLastYearSorter, - &VehicleCargoSorter, - &VehicleReliabilitySorter, - &VehicleMaxSpeedSorter, - &VehicleModelSorter, - &VehicleValueSorter, - &VehicleLengthSorter, - &VehicleTimeToLiveSorter, - &VehicleTimetableDelaySorter, -}; - -const StringID BaseVehicleListWindow::vehicle_sorter_names[] = { - STR_SORT_BY_NUMBER, - STR_SORT_BY_NAME, - STR_SORT_BY_AGE, - STR_SORT_BY_PROFIT_THIS_YEAR, - STR_SORT_BY_PROFIT_LAST_YEAR, - STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE, - STR_SORT_BY_RELIABILITY, - STR_SORT_BY_MAX_SPEED, - STR_SORT_BY_MODEL, - STR_SORT_BY_VALUE, - STR_SORT_BY_LENGTH, - STR_SORT_BY_LIFE_TIME, - STR_SORT_BY_TIMETABLE_DELAY, - INVALID_STRING_ID -}; - -const StringID BaseVehicleListWindow::vehicle_depot_name[] = { - STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT, - STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT, - STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT, - STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR -}; - -void BaseVehicleListWindow::BuildVehicleList() -{ - if (!this->vehicles.NeedRebuild()) return; - - DEBUG(misc, 3, "Building vehicle list type %d for company %d given index %d", this->vli.type, this->vli.company, this->vli.index); - - GenerateVehicleSortList(&this->vehicles, this->vli); - - uint unitnumber = 0; - for (const Vehicle **v = this->vehicles.Begin(); v != this->vehicles.End(); v++) { - unitnumber = max(unitnumber, (*v)->unitnumber); - } - - /* Because 111 is much less wide than e.g. 999 we use the - * wider numbers to determine the width instead of just - * the random number that it seems to be. */ - if (unitnumber >= 1000) { - this->unitnumber_digits = 4; - } else if (unitnumber >= 100) { - this->unitnumber_digits = 3; - } else { - this->unitnumber_digits = 2; - } - - this->vehicles.RebuildDone(); - this->vscroll->SetCount(this->vehicles.Length()); -} - -/** - * Compute the size for the Action dropdown. - * @param show_autoreplace If true include the autoreplace item. - * @param show_group If true include group-related stuff. - * @return Required size. - */ -Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bool show_group) -{ - Dimension d = {0, 0}; - - if (show_autoreplace) d = maxdim(d, GetStringBoundingBox(STR_VEHICLE_LIST_REPLACE_VEHICLES)); - d = maxdim(d, GetStringBoundingBox(STR_VEHICLE_LIST_SEND_FOR_SERVICING)); - d = maxdim(d, GetStringBoundingBox(this->vehicle_depot_name[this->vli.vtype])); - - if (show_group) { - d = maxdim(d, GetStringBoundingBox(STR_GROUP_ADD_SHARED_VEHICLE)); - d = maxdim(d, GetStringBoundingBox(STR_GROUP_REMOVE_ALL_VEHICLES)); - } - - return d; -} - -/** - * Display the Action dropdown window. - * @param show_autoreplace If true include the autoreplace item. - * @param show_group If true include group-related stuff. - * @return Itemlist for dropdown - */ -DropDownList *BaseVehicleListWindow::BuildActionDropdownList(bool show_autoreplace, bool show_group) -{ - DropDownList *list = new DropDownList(); - - if (show_autoreplace) *list->Append() = new DropDownListStringItem(STR_VEHICLE_LIST_REPLACE_VEHICLES, ADI_REPLACE, false); - *list->Append() = new DropDownListStringItem(STR_VEHICLE_LIST_SEND_FOR_SERVICING, ADI_SERVICE, false); - *list->Append() = new DropDownListStringItem(this->vehicle_depot_name[this->vli.vtype], ADI_DEPOT, false); - - if (show_group) { - *list->Append() = new DropDownListStringItem(STR_GROUP_ADD_SHARED_VEHICLE, ADI_ADD_SHARED, false); - *list->Append() = new DropDownListStringItem(STR_GROUP_REMOVE_ALL_VEHICLES, ADI_REMOVE_ALL, false); - } - - return list; -} - -/* cached values for VehicleNameSorter to spare many GetString() calls */ -static const Vehicle *_last_vehicle[2] = { NULL, NULL }; - -void BaseVehicleListWindow::SortVehicleList() -{ - if (this->vehicles.Sort()) return; - - /* invalidate cached values for name sorter - vehicle names could change */ - _last_vehicle[0] = _last_vehicle[1] = NULL; -} - -void DepotSortList(VehicleList *list) -{ - if (list->Length() < 2) return; - QSortT(list->Begin(), list->Length(), &VehicleNumberSorter); -} - -/** draw the vehicle profit button in the vehicle list window. */ -static void DrawVehicleProfitButton(const Vehicle *v, int x, int y) -{ - SpriteID spr; - - /* draw profit-based coloured icons */ - if (v->age <= VEHICLE_PROFIT_MIN_AGE) { - spr = SPR_PROFIT_NA; - } else if (v->GetDisplayProfitLastYear() < 0) { - spr = SPR_PROFIT_NEGATIVE; - } else if (v->GetDisplayProfitLastYear() < VEHICLE_PROFIT_THRESHOLD) { - spr = SPR_PROFIT_SOME; - } else { - spr = SPR_PROFIT_LOT; - } - DrawSprite(spr, PAL_NONE, x, y); -} - -/** Maximum number of refit cycles we try, to prevent infinite loops. And we store only a byte anyway */ -static const uint MAX_REFIT_CYCLE = 256; - -/** - * Get the best fitting subtype when 'cloning'/'replacing' \a v_from with \a v_for. - * All articulated parts of both vehicles are tested to find a possibly shared subtype. - * For \a v_for only vehicle refittable to \a dest_cargo_type are considered. - * @param v_from the vehicle to match the subtype from - * @param v_for the vehicle to get the subtype for - * @param dest_cargo_type Destination cargo type. - * @return the best sub type - */ -byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_type) -{ - v_from = v_from->GetFirstEnginePart(); - v_for = v_for->GetFirstEnginePart(); - - /* Create a list of subtypes used by the various parts of v_for */ - static SmallVector subtypes; - subtypes.Clear(); - for (; v_from != NULL; v_from = v_from->HasArticulatedPart() ? v_from->GetNextArticulatedPart() : NULL) { - const Engine *e_from = v_from->GetEngine(); - if (!e_from->CanCarryCargo() || !HasBit(e_from->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) continue; - subtypes.Include(GetCargoSubtypeText(v_from)); - } - - byte ret_refit_cyc = 0; - bool success = false; - if (subtypes.Length() > 0) { - /* Check whether any articulated part is refittable to 'dest_cargo_type' with a subtype listed in 'subtypes' */ - for (Vehicle *v = v_for; v != NULL; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL) { - const Engine *e = v->GetEngine(); - if (!e->CanCarryCargo() || !HasBit(e->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) continue; - if (!HasBit(e->info.refit_mask, dest_cargo_type) && v->cargo_type != dest_cargo_type) continue; - - CargoID old_cargo_type = v->cargo_type; - byte old_cargo_subtype = v->cargo_subtype; - - /* Set the 'destination' cargo */ - v->cargo_type = dest_cargo_type; - - /* Cycle through the refits */ - for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) { - v->cargo_subtype = refit_cyc; - - /* Make sure we don't pick up anything cached. */ - v->First()->InvalidateNewGRFCache(); - v->InvalidateNewGRFCache(); - - StringID subtype = GetCargoSubtypeText(v); - if (subtype == STR_EMPTY) break; - - if (!subtypes.Contains(subtype)) continue; - - /* We found something matching. */ - ret_refit_cyc = refit_cyc; - success = true; - break; - } - - /* Reset the vehicle's cargo type */ - v->cargo_type = old_cargo_type; - v->cargo_subtype = old_cargo_subtype; - - /* Make sure we don't taint the vehicle. */ - v->First()->InvalidateNewGRFCache(); - v->InvalidateNewGRFCache(); - - if (success) break; - } - } - - return ret_refit_cyc; -} - -/** Option to refit a vehicle chain */ -struct RefitOption { - CargoID cargo; ///< Cargo to refit to - byte subtype; ///< Subcargo to use - StringID string; ///< GRF-local String to display for the cargo - - /** - * Inequality operator for #RefitOption. - * @param other Compare to this #RefitOption. - * @return True if both #RefitOption are different. - */ - inline bool operator != (const RefitOption &other) const - { - return other.cargo != this->cargo || other.string != this->string; - } - - /** - * Equality operator for #RefitOption. - * @param other Compare to this #RefitOption. - * @return True if both #RefitOption are equal. - */ - inline bool operator == (const RefitOption &other) const - { - return other.cargo == this->cargo && other.string == this->string; - } -}; - -typedef SmallVector SubtypeList; ///< List of refit subtypes associated to a cargo. - -/** - * Draw the list of available refit options for a consist and highlight the selected refit option (if any). - * @param list List of subtype options for each (sorted) cargo. - * @param sel Selected refit cargo-type in the window - * @param pos Position of the selected item in caller widow - * @param rows Number of rows(capacity) in caller window - * @param delta Step height in caller window - * @param r Rectangle of the matrix widget. - */ -static void DrawVehicleRefitWindow(const SubtypeList list[NUM_CARGO], const int sel[2], uint pos, uint rows, uint delta, const Rect &r) -{ - uint y = Center(r.top, delta); - uint current = 0; - - bool rtl = _current_text_dir == TD_RTL; - uint iconwidth = max(GetSpriteSize(SPR_CIRCLE_FOLDED).width, GetSpriteSize(SPR_CIRCLE_UNFOLDED).width); - uint iconheight = GetSpriteSize(SPR_CIRCLE_FOLDED).height; - int linecolour = _colour_gradient[COLOUR_ORANGE][4]; - - int iconleft = rtl ? r.right - WD_MATRIX_RIGHT - iconwidth : r.left + WD_MATRIX_LEFT; - int iconcenter = rtl ? r.right - WD_MATRIX_RIGHT - iconwidth / 2 : r.left + WD_MATRIX_LEFT + iconwidth / 2; - int iconinner = rtl ? r.right - WD_MATRIX_RIGHT - iconwidth : r.left + WD_MATRIX_LEFT + iconwidth; - - int textleft = r.left + WD_MATRIX_LEFT + (rtl ? 0 : iconwidth + 4); - int textright = r.right - WD_MATRIX_RIGHT - (rtl ? iconwidth + 4 : 0); - - /* Draw the list of subtypes for each cargo, and find the selected refit option (by its position). */ - for (uint i = 0; current < pos + rows && i < NUM_CARGO; i++) { - for (uint j = 0; current < pos + rows && j < list[i].Length(); j++) { - const RefitOption &refit = list[i][j]; - - /* Hide subtypes if sel[0] does not match */ - if (sel[0] != (int)i && refit.subtype != 0xFF) continue; - - /* Refit options with a position smaller than pos don't have to be drawn. */ - if (current < pos) { - current++; - continue; - } - - if (list[i].Length() > 1) { - if (refit.subtype != 0xFF) { - /* Draw tree lines */ - int ycenter = y + FONT_HEIGHT_NORMAL / 2; - GfxDrawLine(iconcenter, y - WD_MATRIX_TOP, iconcenter, j == list[i].Length() - 1 ? ycenter : y - WD_MATRIX_TOP + delta - 1, linecolour); - GfxDrawLine(iconcenter, ycenter, iconinner, ycenter, linecolour); - } else { - /* Draw expand/collapse icon */ - DrawSprite(sel[0] == (int)i ? SPR_CIRCLE_UNFOLDED : SPR_CIRCLE_FOLDED, PAL_NONE, iconleft, y + (FONT_HEIGHT_NORMAL - iconheight) / 2); - } - } - - TextColour colour = (sel[0] == (int)i && (uint)sel[1] == j) ? TC_WHITE : TC_BLACK; - /* Get the cargo name. */ - SetDParam(0, CargoSpec::Get(refit.cargo)->name); - SetDParam(1, refit.string); - DrawString(textleft, textright, y, STR_JUST_STRING_STRING, colour); - - y += delta; - current++; - } - } -} - -/** Refit cargo window. */ -struct RefitWindow : public Window { - int sel[2]; ///< Index in refit options, sel[0] == -1 if nothing is selected. - RefitOption *cargo; ///< Refit option selected by #sel. - SubtypeList list[NUM_CARGO]; ///< List of refit subtypes available for each sorted cargo. - VehicleOrderID order; ///< If not #INVALID_VEH_ORDER_ID, selection is part of a refit order (rather than execute directly). - uint information_width; ///< Width required for correctly displaying all cargoes in the information panel. - Scrollbar *vscroll; ///< The main scrollbar. - Scrollbar *hscroll; ///< Only used for long vehicles. - int vehicle_width; ///< Width of the vehicle being drawn. - int sprite_left; ///< Left position of the vehicle sprite. - int sprite_right; ///< Right position of the vehicle sprite. - uint vehicle_margin; ///< Margin to use while selecting vehicles when the vehicle image is centered. - int click_x; ///< Position of the first click while dragging. - VehicleID selected_vehicle; ///< First vehicle in the current selection. - uint8 num_vehicles; ///< Number of selected vehicles. - bool auto_refit; ///< Select cargo for auto-refitting. - - /** - * Collects all (cargo, subcargo) refit options of a vehicle chain. - */ - void BuildRefitList() - { - for (uint i = 0; i < NUM_CARGO; i++) this->list[i].Clear(); - Vehicle *v = Vehicle::Get(this->window_number); - - /* Check only the selected vehicles. */ - VehicleSet vehicles_to_refit; - GetVehicleSet(vehicles_to_refit, Vehicle::Get(this->selected_vehicle), this->num_vehicles); - - do { - if (v->type == VEH_TRAIN && !vehicles_to_refit.Contains(v->index)) continue; - const Engine *e = v->GetEngine(); - uint32 cmask = e->info.refit_mask; - byte callback_mask = e->info.callback_mask; - - /* Skip this engine if it does not carry anything */ - if (!e->CanCarryCargo()) continue; - /* Skip this engine if we build the list for auto-refitting and engine doesn't allow it. */ - if (this->auto_refit && !HasBit(e->info.misc_flags, EF_AUTO_REFIT)) continue; - - /* Loop through all cargoes in the refit mask */ - int current_index = 0; - const CargoSpec *cs; - FOR_ALL_SORTED_CARGOSPECS(cs) { - CargoID cid = cs->Index(); - /* Skip cargo type if it's not listed */ - if (!HasBit(cmask, cid)) { - current_index++; - continue; - } - - bool first_vehicle = this->list[current_index].Length() == 0; - if (first_vehicle) { - /* Keeping the current subtype is always an option. It also serves as the option in case of no subtypes */ - RefitOption *option = this->list[current_index].Append(); - option->cargo = cid; - option->subtype = 0xFF; - option->string = STR_EMPTY; - } - - /* Check the vehicle's callback mask for cargo suffixes. - * This is not supported for ordered refits, since subtypes only have a meaning - * for a specific vehicle at a specific point in time, which conflicts with shared orders, - * autoreplace, autorenew, clone, order restoration, ... */ - if (this->order == INVALID_VEH_ORDER_ID && HasBit(callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) { - /* Make a note of the original cargo type. It has to be - * changed to test the cargo & subtype... */ - CargoID temp_cargo = v->cargo_type; - byte temp_subtype = v->cargo_subtype; - - v->cargo_type = cid; - - for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) { - v->cargo_subtype = refit_cyc; - - /* Make sure we don't pick up anything cached. */ - v->First()->InvalidateNewGRFCache(); - v->InvalidateNewGRFCache(); - - StringID subtype = GetCargoSubtypeText(v); - - if (first_vehicle) { - /* Append new subtype (don't add duplicates though) */ - if (subtype == STR_EMPTY) break; - - RefitOption option; - option.cargo = cid; - option.subtype = refit_cyc; - option.string = subtype; - this->list[current_index].Include(option); - } else { - /* Intersect the subtypes of earlier vehicles with the subtypes of this vehicle */ - if (subtype == STR_EMPTY) { - /* No more subtypes for this vehicle, delete all subtypes >= refit_cyc */ - SubtypeList &l = this->list[current_index]; - /* 0xFF item is in front, other subtypes are sorted. So just truncate the list in the right spot */ - for (uint i = 1; i < l.Length(); i++) { - if (l[i].subtype >= refit_cyc) { - l.Resize(i); - break; - } - } - break; - } else { - /* Check whether the subtype matches with the subtype of earlier vehicles. */ - uint pos = 1; - SubtypeList &l = this->list[current_index]; - while (pos < l.Length() && l[pos].subtype != refit_cyc) pos++; - if (pos < l.Length() && l[pos].string != subtype) { - /* String mismatch, remove item keeping the order */ - l.ErasePreservingOrder(pos); - } - } - } - } - - /* Reset the vehicle's cargo type */ - v->cargo_type = temp_cargo; - v->cargo_subtype = temp_subtype; - - /* And make sure we haven't tainted the cache */ - v->First()->InvalidateNewGRFCache(); - v->InvalidateNewGRFCache(); - } - current_index++; - } - } while (v->IsGroundVehicle() && (v = v->Next()) != NULL); - } - - /** - * Refresh scrollbar after selection changed - */ - void RefreshScrollbar() - { - uint scroll_row = 0; - uint row = 0; - - for (uint i = 0; i < NUM_CARGO; i++) { - for (uint j = 0; j < this->list[i].Length(); j++) { - const RefitOption &refit = this->list[i][j]; - - /* Hide subtypes if sel[0] does not match */ - if (this->sel[0] != (int)i && refit.subtype != 0xFF) continue; - - if (this->sel[0] == (int)i && (uint)this->sel[1] == j) scroll_row = row; - - row++; - } - } - - this->vscroll->SetCount(row); - if (scroll_row < row) this->vscroll->ScrollTowards(scroll_row); - } - - /** - * Select a row. - * @param click_row Clicked row - */ - void SetSelection(uint click_row) - { - uint row = 0; - - for (uint i = 0; i < NUM_CARGO; i++) { - for (uint j = 0; j < this->list[i].Length(); j++) { - const RefitOption &refit = this->list[i][j]; - - /* Hide subtypes if sel[0] does not match */ - if (this->sel[0] != (int)i && refit.subtype != 0xFF) continue; - - if (row == click_row) { - this->sel[0] = i; - this->sel[1] = j; - return; - } - - row++; - } - } - - this->sel[0] = -1; - this->sel[1] = 0; - } - - /** - * Gets the #RefitOption placed in the selected index. - * @return Pointer to the #RefitOption currently in use. - */ - RefitOption *GetRefitOption() - { - if (this->sel[0] < 0) return NULL; - - SubtypeList &l = this->list[this->sel[0]]; - if ((uint)this->sel[1] >= l.Length()) return NULL; - - return &l[this->sel[1]]; - } - - RefitWindow(WindowDesc *desc, const Vehicle *v, VehicleOrderID order, bool auto_refit) : Window(desc) - { - this->sel[0] = -1; - this->sel[1] = 0; - this->auto_refit = auto_refit; - this->order = order; - this->CreateNestedTree(); - - this->vscroll = this->GetScrollbar(WID_VR_SCROLLBAR); - this->hscroll = (v->IsGroundVehicle() ? this->GetScrollbar(WID_VR_HSCROLLBAR) : NULL); - this->GetWidget(WID_VR_SELECT_HEADER)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type; - this->GetWidget(WID_VR_MATRIX)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type; - NWidgetCore *nwi = this->GetWidget(WID_VR_REFIT); - nwi->widget_data = STR_REFIT_TRAIN_REFIT_BUTTON + v->type; - nwi->tool_tip = STR_REFIT_TRAIN_REFIT_TOOLTIP + v->type; - this->GetWidget(WID_VR_SHOW_HSCROLLBAR)->SetDisplayedPlane(v->IsGroundVehicle() ? 0 : SZSP_HORIZONTAL); - this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY)->tool_tip = (v->type == VEH_TRAIN) ? STR_REFIT_SELECT_VEHICLES_TOOLTIP : STR_NULL; - - this->FinishInitNested(v->index); - this->owner = v->owner; - - this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0); - } - - virtual void OnInit() - { - if (this->cargo != NULL) { - /* Store the RefitOption currently in use. */ - RefitOption current_refit_option = *(this->cargo); - - /* Rebuild the refit list */ - this->BuildRefitList(); - this->sel[0] = -1; - this->sel[1] = 0; - this->cargo = NULL; - for (uint i = 0; this->cargo == NULL && i < NUM_CARGO; i++) { - for (uint j = 0; j < list[i].Length(); j++) { - if (list[i][j] == current_refit_option) { - this->sel[0] = i; - this->sel[1] = j; - this->cargo = &list[i][j]; - break; - } - } - } - - this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0); - this->RefreshScrollbar(); - } else { - /* Rebuild the refit list */ - this->OnInvalidateData(VIWD_CONSIST_CHANGED); - } - } - - virtual void OnPaint() - { - /* Determine amount of items for scroller. */ - if (this->hscroll != NULL) this->hscroll->SetCount(this->vehicle_width); - - /* Calculate sprite position. */ - NWidgetCore *vehicle_panel_display = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); - int sprite_width = max(0, ((int)vehicle_panel_display->current_x - this->vehicle_width) / 2); - this->sprite_left = vehicle_panel_display->pos_x; - this->sprite_right = vehicle_panel_display->pos_x + vehicle_panel_display->current_x - 1; - if (_current_text_dir == TD_RTL) { - this->sprite_right -= sprite_width; - this->vehicle_margin = vehicle_panel_display->current_x - sprite_right; - } else { - this->sprite_left += sprite_width; - this->vehicle_margin = sprite_left; - } - - this->DrawWidgets(); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_VR_MATRIX: - resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM; - size->height = resize->height * 8; - break; - - case WID_VR_VEHICLE_PANEL_DISPLAY: - size->height = GetVehicleHeight(Vehicle::Get(this->window_number)->type); - break; - - case WID_VR_INFO: - size->width = WD_FRAMERECT_LEFT + this->information_width + WD_FRAMERECT_RIGHT; - break; - } - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_VR_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index); - } - - /** - * Gets the #StringID to use for displaying capacity. - * @param Cargo and cargo subtype to check for capacity. - * @return INVALID_STRING_ID if there is no capacity. StringID to use in any other case. - * @post String parameters have been set. - */ - StringID GetCapacityString(RefitOption *option) const - { - assert(_current_company == _local_company); - Vehicle *v = Vehicle::Get(this->window_number); - CommandCost cost = DoCommand(v->tile, this->selected_vehicle, option->cargo | (int)this->auto_refit << 6 | option->subtype << 8 | - this->num_vehicles << 16, DC_QUERY_COST, GetCmdRefitVeh(v->type)); - - if (cost.Failed()) return INVALID_STRING_ID; - - SetDParam(0, option->cargo); - SetDParam(1, _returned_refit_capacity); - - Money money = cost.GetCost(); - if (_returned_mail_refit_capacity > 0) { - SetDParam(2, CT_MAIL); - SetDParam(3, _returned_mail_refit_capacity); - if (money <= 0) { - SetDParam(4, -money); - return STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT; - } else { - SetDParam(4, money); - return STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT; - } - } else { - if (money <= 0) { - SetDParam(2, -money); - return STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT; - } else { - SetDParam(2, money); - return STR_REFIT_NEW_CAPACITY_COST_OF_REFIT; - } - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_VR_VEHICLE_PANEL_DISPLAY: { - Vehicle *v = Vehicle::Get(this->window_number); - DrawVehicleImage(v, this->sprite_left + WD_FRAMERECT_LEFT, this->sprite_right - WD_FRAMERECT_RIGHT, - r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != NULL ? this->hscroll->GetPosition() : 0); - - /* Highlight selected vehicles. */ - if (this->order != INVALID_VEH_ORDER_ID) break; - int x = 0; - switch (v->type) { - case VEH_TRAIN: { - VehicleSet vehicles_to_refit; - GetVehicleSet(vehicles_to_refit, Vehicle::Get(this->selected_vehicle), this->num_vehicles); - - int left = INT32_MIN; - int width = 0; - - for (Train *u = Train::From(v); u != NULL; u = u->Next()) { - /* Start checking. */ - if (vehicles_to_refit.Contains(u->index) && left == INT32_MIN) { - left = x - this->hscroll->GetPosition() + r.left + this->vehicle_margin; - width = 0; - } - - /* Draw a selection. */ - if ((!vehicles_to_refit.Contains(u->index) || u->Next() == NULL) && left != INT32_MIN) { - if (u->Next() == NULL && vehicles_to_refit.Contains(u->index)) { - int current_width = u->GetDisplayImageWidth(); - width += current_width; - x += current_width; - } - - int right = Clamp(left + width, 0, r.right); - left = max(0, left); - - if (_current_text_dir == TD_RTL) { - right = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY)->current_x - left; - left = right - width; - } - - if (left != right) { - DrawFrameRect(left, r.top + WD_FRAMERECT_TOP, right, r.top + WD_FRAMERECT_TOP + 13, COLOUR_WHITE, FR_BORDERONLY); - } - - left = INT32_MIN; - } - - int current_width = u->GetDisplayImageWidth(); - width += current_width; - x += current_width; - } - break; - } - - default: break; - } - break; - } - - case WID_VR_MATRIX: - DrawVehicleRefitWindow(this->list, this->sel, this->vscroll->GetPosition(), this->vscroll->GetCapacity(), this->resize.step_height, r); - break; - - case WID_VR_INFO: - if (this->cargo != NULL) { - StringID string = this->GetCapacityString(this->cargo); - if (string != INVALID_STRING_ID) { - DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, - r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, string); - } - } - break; - } - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - switch (data) { - case VIWD_AUTOREPLACE: // Autoreplace replaced the vehicle; selected_vehicle became invalid. - case VIWD_CONSIST_CHANGED: { // The consist has changed; rebuild the entire list. - /* Clear the selection. */ - Vehicle *v = Vehicle::Get(this->window_number); - this->selected_vehicle = v->index; - this->num_vehicles = UINT8_MAX; - /* FALL THROUGH */ - } - - case 2: { // The vehicle selection has changed; rebuild the entire list. - if (!gui_scope) break; - this->BuildRefitList(); - - /* The vehicle width has changed too. */ - this->vehicle_width = GetVehicleWidth(Vehicle::Get(this->window_number), EIT_IN_DETAILS); - uint max_width = 0; - - /* Check the width of all cargo information strings. */ - for (uint i = 0; i < NUM_CARGO; i++) { - for (uint j = 0; j < this->list[i].Length(); j++) { - StringID string = this->GetCapacityString(&list[i][j]); - if (string != INVALID_STRING_ID) { - Dimension dim = GetStringBoundingBox(string); - max_width = max(dim.width, max_width); - } - } - } - - if (this->information_width < max_width) { - this->information_width = max_width; - this->ReInit(); - } - /* FALL THROUGH */ - } - - case 1: // A new cargo has been selected. - if (!gui_scope) break; - this->cargo = GetRefitOption(); - this->RefreshScrollbar(); - break; - } - } - - int GetClickPosition(int click_x) - { - const NWidgetCore *matrix_widget = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); - if (_current_text_dir == TD_RTL) click_x = matrix_widget->current_x - click_x; - click_x -= this->vehicle_margin; - if (this->hscroll != NULL) click_x += this->hscroll->GetPosition(); - - return click_x; - } - - void SetSelectedVehicles(int drag_x) - { - drag_x = GetClickPosition(drag_x); - - int left_x = min(this->click_x, drag_x); - int right_x = max(this->click_x, drag_x); - this->num_vehicles = 0; - - Vehicle *v = Vehicle::Get(this->window_number); - /* Find the vehicle part that was clicked. */ - switch (v->type) { - case VEH_TRAIN: { - /* Don't select anything if we are not clicking in the vehicle. */ - if (left_x >= 0) { - const Train *u = Train::From(v); - bool start_counting = false; - for (; u != NULL; u = u->Next()) { - int current_width = u->GetDisplayImageWidth(); - left_x -= current_width; - right_x -= current_width; - - if (left_x < 0 && !start_counting) { - this->selected_vehicle = u->index; - start_counting = true; - - /* Count the first vehicle, even if articulated part */ - this->num_vehicles++; - } else if (start_counting && !u->IsArticulatedPart()) { - /* Do not count articulated parts */ - this->num_vehicles++; - } - - if (right_x < 0) break; - } - } - - /* If the selection is not correct, clear it. */ - if (this->num_vehicles != 0) { - if (_ctrl_pressed) this->num_vehicles = UINT8_MAX; - break; - } - /* FALL THROUGH */ - } - - default: - /* Clear the selection. */ - this->selected_vehicle = v->index; - this->num_vehicles = UINT8_MAX; - break; - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image. - if (this->order != INVALID_VEH_ORDER_ID) break; - NWidgetBase *nwi = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); - this->click_x = GetClickPosition(pt.x - nwi->pos_x); - this->SetSelectedVehicles(pt.x - nwi->pos_x); - this->SetWidgetDirty(WID_VR_VEHICLE_PANEL_DISPLAY); - if (!_ctrl_pressed) { - SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this); - } else { - /* The vehicle selection has changed. */ - this->InvalidateData(2); - } - break; - } - - case WID_VR_MATRIX: { // listbox - this->SetSelection(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_VR_MATRIX)); - this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0); - this->InvalidateData(1); - - if (click_count == 1) break; - /* FALL THROUGH */ - } - - case WID_VR_REFIT: // refit button - if (this->cargo != NULL) { - const Vehicle *v = Vehicle::Get(this->window_number); - - if (this->order == INVALID_VEH_ORDER_ID) { - bool delete_window = this->selected_vehicle == v->index && this->num_vehicles == UINT8_MAX; - if (DoCommandP(v->tile, this->selected_vehicle, this->cargo->cargo | this->cargo->subtype << 8 | this->num_vehicles << 16, GetCmdRefitVeh(v)) && delete_window) delete this; - } else { - if (DoCommandP(v->tile, v->index, this->cargo->cargo | this->order << 16, CMD_ORDER_REFIT)) delete this; - } - } - break; - } - } - - virtual void OnMouseDrag(Point pt, int widget) - { - switch (widget) { - case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image. - if (this->order != INVALID_VEH_ORDER_ID) break; - NWidgetBase *nwi = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); - this->SetSelectedVehicles(pt.x - nwi->pos_x); - this->SetWidgetDirty(WID_VR_VEHICLE_PANEL_DISPLAY); - break; - } - } - } - - virtual void OnDragDrop(Point pt, int widget) - { - switch (widget) { - case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image. - if (this->order != INVALID_VEH_ORDER_ID) break; - NWidgetBase *nwi = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); - this->SetSelectedVehicles(pt.x - nwi->pos_x); - this->InvalidateData(2); - break; - } - } - } - - virtual void OnResize() - { - this->vehicle_width = GetVehicleWidth(Vehicle::Get(this->window_number), EIT_IN_DETAILS); - this->vscroll->SetCapacityFromWidget(this, WID_VR_MATRIX); - if (this->hscroll != NULL) this->hscroll->SetCapacityFromWidget(this, WID_VR_VEHICLE_PANEL_DISPLAY); - } -}; - -static const NWidgetPart _nested_vehicle_refit_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, WID_VR_CAPTION), SetDataTip(STR_REFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), - EndContainer(), - /* Vehicle display + scrollbar. */ - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_VR_VEHICLE_PANEL_DISPLAY), SetMinimalSize(228, 14), SetResize(1, 0), SetScrollbar(WID_VR_HSCROLLBAR), EndContainer(), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VR_SHOW_HSCROLLBAR), - NWidget(NWID_HSCROLLBAR, COLOUR_GREY, WID_VR_HSCROLLBAR), - EndContainer(), - EndContainer(), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_VR_SELECT_HEADER), SetDataTip(STR_REFIT_TITLE, STR_NULL), SetResize(1, 0), - /* Matrix + scrollbar. */ - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_VR_MATRIX), SetMinimalSize(228, 112), SetResize(1, 14), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_VR_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VR_SCROLLBAR), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_VR_INFO), SetMinimalTextLines(2, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), SetResize(1, 0), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VR_REFIT), SetFill(1, 0), SetResize(1, 0), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), - EndContainer(), -}; - -static WindowDesc _vehicle_refit_desc( - WDP_AUTO, "view_vehicle_refit", 240, 174, - WC_VEHICLE_REFIT, WC_VEHICLE_VIEW, - WDF_CONSTRUCTION, - _nested_vehicle_refit_widgets, lengthof(_nested_vehicle_refit_widgets) -); - -/** - * Show the refit window for a vehicle - * @param *v The vehicle to show the refit window for - * @param order of the vehicle to assign refit to, or INVALID_VEH_ORDER_ID to refit the vehicle now - * @param parent the parent window of the refit window - * @param auto_refit Choose cargo for auto-refitting - */ -void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit) -{ - DeleteWindowById(WC_VEHICLE_REFIT, v->index); - RefitWindow *w = new RefitWindow(&_vehicle_refit_desc, v, order, auto_refit); - w->parent = parent; -} - -/** Display list of cargo types of the engine, for the purchase information window */ -uint ShowRefitOptionsList(int left, int right, int y, EngineID engine) -{ - /* List of cargo types of this engine */ - uint32 cmask = GetUnionOfArticulatedRefitMasks(engine, false); - /* List of cargo types available in this climate */ - uint32 lmask = _cargo_mask; - - /* Draw nothing if the engine is not refittable */ - if (HasAtMostOneBit(cmask)) return y; - - if (cmask == lmask) { - /* Engine can be refitted to all types in this climate */ - SetDParam(0, STR_PURCHASE_INFO_ALL_TYPES); - } else { - /* Check if we are able to refit to more cargo types and unable to. If - * so, invert the cargo types to list those that we can't refit to. */ - if (CountBits(cmask ^ lmask) < CountBits(cmask) && CountBits(cmask ^ lmask) <= 7) { - cmask ^= lmask; - SetDParam(0, STR_PURCHASE_INFO_ALL_BUT); - } else { - SetDParam(0, STR_JUST_CARGO_LIST); - } - SetDParam(1, cmask); - } - - return DrawStringMultiLine(left, right, y, INT32_MAX, STR_PURCHASE_INFO_REFITTABLE_TO); -} - -/** Get the cargo subtype text from NewGRF for the vehicle details window. */ -StringID GetCargoSubtypeText(const Vehicle *v) -{ - if (HasBit(EngInfo(v->engine_type)->callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) { - uint16 cb = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, v->engine_type, v); - if (cb != CALLBACK_FAILED) { - if (cb > 0x400) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_CARGO_SUFFIX, cb); - if (cb >= 0x400 || (v->GetGRF()->grf_version < 8 && cb == 0xFF)) cb = CALLBACK_FAILED; - } - if (cb != CALLBACK_FAILED) { - return GetGRFStringID(v->GetGRFID(), 0xD000 + cb); - } - } - return STR_EMPTY; -} - -/** Sort vehicles by their number */ -static int CDECL VehicleNumberSorter(const Vehicle * const *a, const Vehicle * const *b) -{ - return (*a)->unitnumber - (*b)->unitnumber; -} - -/** Sort vehicles by their name */ -static int CDECL VehicleNameSorter(const Vehicle * const *a, const Vehicle * const *b) -{ - static char last_name[2][64]; - - if (*a != _last_vehicle[0]) { - _last_vehicle[0] = *a; - SetDParam(0, (*a)->index); - GetString(last_name[0], STR_VEHICLE_NAME, lastof(last_name[0])); - } - - if (*b != _last_vehicle[1]) { - _last_vehicle[1] = *b; - SetDParam(0, (*b)->index); - GetString(last_name[1], STR_VEHICLE_NAME, lastof(last_name[1])); - } - - int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). - return (r != 0) ? r : VehicleNumberSorter(a, b); -} - -/** Sort vehicles by their age */ -static int CDECL VehicleAgeSorter(const Vehicle * const *a, const Vehicle * const *b) -{ - int r = (*a)->age - (*b)->age; - return (r != 0) ? r : VehicleNumberSorter(a, b); -} - -/** Sort vehicles by this year profit */ -static int CDECL VehicleProfitThisYearSorter(const Vehicle * const *a, const Vehicle * const *b) -{ - int r = ClampToI32((*a)->GetDisplayProfitThisYear() - (*b)->GetDisplayProfitThisYear()); - return (r != 0) ? r : VehicleNumberSorter(a, b); -} - -/** Sort vehicles by last year profit */ -static int CDECL VehicleProfitLastYearSorter(const Vehicle * const *a, const Vehicle * const *b) -{ - int r = ClampToI32((*a)->GetDisplayProfitLastYear() - (*b)->GetDisplayProfitLastYear()); - return (r != 0) ? r : VehicleNumberSorter(a, b); -} - -/** Sort vehicles by their cargo */ -static int CDECL VehicleCargoSorter(const Vehicle * const *a, const Vehicle * const *b) -{ - const Vehicle *v; - CargoArray diff; - - /* Append the cargo of the connected waggons */ - for (v = *a; v != NULL; v = v->Next()) diff[v->cargo_type] += v->cargo_cap; - for (v = *b; v != NULL; v = v->Next()) diff[v->cargo_type] -= v->cargo_cap; - - int r = 0; - for (CargoID i = 0; i < NUM_CARGO; i++) { - r = diff[i]; - if (r != 0) break; - } - - return (r != 0) ? r : VehicleNumberSorter(a, b); -} - -/** Sort vehicles by their reliability */ -static int CDECL VehicleReliabilitySorter(const Vehicle * const *a, const Vehicle * const *b) -{ - int r = (*a)->reliability - (*b)->reliability; - return (r != 0) ? r : VehicleNumberSorter(a, b); -} - -/** Sort vehicles by their max speed */ -static int CDECL VehicleMaxSpeedSorter(const Vehicle * const *a, const Vehicle * const *b) -{ - int r = (*a)->vcache.cached_max_speed - (*b)->vcache.cached_max_speed; - return (r != 0) ? r : VehicleNumberSorter(a, b); -} - -/** Sort vehicles by model */ -static int CDECL VehicleModelSorter(const Vehicle * const *a, const Vehicle * const *b) -{ - int r = (*a)->engine_type - (*b)->engine_type; - return (r != 0) ? r : VehicleNumberSorter(a, b); -} - -/** Sort vehicles by their value */ -static int CDECL VehicleValueSorter(const Vehicle * const *a, const Vehicle * const *b) -{ - const Vehicle *u; - Money diff = 0; - - for (u = *a; u != NULL; u = u->Next()) diff += u->value; - for (u = *b; u != NULL; u = u->Next()) diff -= u->value; - - int r = ClampToI32(diff); - return (r != 0) ? r : VehicleNumberSorter(a, b); -} - -/** Sort vehicles by their length */ -static int CDECL VehicleLengthSorter(const Vehicle * const *a, const Vehicle * const *b) -{ - int r = (*a)->GetGroundVehicleCache()->cached_total_length - (*b)->GetGroundVehicleCache()->cached_total_length; - return (r != 0) ? r : VehicleNumberSorter(a, b); -} - -/** Sort vehicles by the time they can still live */ -static int CDECL VehicleTimeToLiveSorter(const Vehicle * const *a, const Vehicle * const *b) -{ - int r = ClampToI32(((*a)->max_age - (*a)->age) - ((*b)->max_age - (*b)->age)); - return (r != 0) ? r : VehicleNumberSorter(a, b); -} - -/** Sort vehicles by the timetable delay */ -static int CDECL VehicleTimetableDelaySorter(const Vehicle * const *a, const Vehicle * const *b) -{ - int r = (*a)->lateness_counter - (*b)->lateness_counter; - return (r != 0) ? r : VehicleNumberSorter(a, b); -} - -void InitializeGUI() -{ - MemSetT(&_sorting, 0); -} - -/** - * Assign a vehicle window a new vehicle - * @param window_class WindowClass to search for - * @param from_index the old vehicle ID - * @param to_index the new vehicle ID - */ -static inline void ChangeVehicleWindow(WindowClass window_class, VehicleID from_index, VehicleID to_index) -{ - Window *w = FindWindowById(window_class, from_index); - if (w != NULL) { - /* Update window_number */ - w->window_number = to_index; - if (w->viewport != NULL) w->viewport->follow_vehicle = to_index; - - /* Update vehicle drag data */ - if (_thd.window_class == window_class && _thd.window_number == (WindowNumber)from_index) { - _thd.window_number = to_index; - } - - /* Notify the window. */ - w->InvalidateData(VIWD_AUTOREPLACE, false); - } -} - -/** - * Report a change in vehicle IDs (due to autoreplace) to affected vehicle windows. - * @param from_index the old vehicle ID - * @param to_index the new vehicle ID - */ -void ChangeVehicleViewWindow(VehicleID from_index, VehicleID to_index) -{ - ChangeVehicleWindow(WC_VEHICLE_VIEW, from_index, to_index); - ChangeVehicleWindow(WC_VEHICLE_ORDERS, from_index, to_index); - ChangeVehicleWindow(WC_VEHICLE_REFIT, from_index, to_index); - ChangeVehicleWindow(WC_VEHICLE_DETAILS, from_index, to_index); - ChangeVehicleWindow(WC_VEHICLE_TIMETABLE, from_index, to_index); -} - -static const NWidgetPart _nested_vehicle_list[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, WID_VL_CAPTION), - NWidget(WWT_SHADEBOX, COLOUR_GREY), - NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), - NWidget(WWT_STICKYBOX, COLOUR_GREY), - EndContainer(), - - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VL_SORT_ORDER), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_SORT_BY_PULLDOWN), SetMinimalSize(167, 12), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetFill(1, 1), SetResize(1, 0), - EndContainer(), - EndContainer(), - - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_VL_LIST), SetMinimalSize(248, 0), SetFill(1, 0), SetResize(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_VL_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VL_SCROLLBAR), - EndContainer(), - - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VL_HIDE_BUTTONS), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VL_AVAILABLE_VEHICLES), SetMinimalSize(106, 12), SetFill(0, 1), - SetDataTip(STR_BLACK_STRING, STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetResize(1, 0), SetFill(1, 1), EndContainer(), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_MANAGE_VEHICLES_DROPDOWN), SetMinimalSize(118, 12), SetFill(0, 1), - SetDataTip(STR_VEHICLE_LIST_MANAGE_LIST, STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VL_STOP_ALL), SetMinimalSize(12, 12), SetFill(0, 1), - SetDataTip(SPR_FLAG_VEH_STOPPED, STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VL_START_ALL), SetMinimalSize(12, 12), SetFill(0, 1), - SetDataTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP), - EndContainer(), - /* Widget to be shown for other companies hiding the previous 5 widgets. */ - NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 0), EndContainer(), - EndContainer(), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), - EndContainer(), -}; - -static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, VehicleOrderID start = 0) -{ - const Order *order = v->GetOrder(start); - if (order == NULL) return; - - int i = 0; - VehicleOrderID oid = start; - - do { - if (oid == v->cur_real_order_index) DrawString(left, right, y, STR_TINY_RIGHT_ARROW, TC_BLACK); - - if (order->IsType(OT_GOTO_STATION)) { - SetDParam(0, order->GetDestination()); - DrawString(left + 6, right - 6, y, STR_TINY_BLACK_STATION); - - y += FONT_HEIGHT_SMALL; - if (++i == 4) break; - } - - oid++; - order = order->next; - if (order == NULL) { - order = v->orders.list->GetFirstOrder(); - oid = 0; - } - } while (oid != start); -} - -/** - * Draws an image of a vehicle chain - * @param v Front vehicle - * @param left The minimum horizontal position - * @param right The maximum horizontal position - * @param y Vertical position to draw at - * @param selection Selected vehicle to draw a frame around - * @param skip Number of pixels to skip at the front (for scrolling) - */ -void DrawVehicleImage(const Vehicle *v, int left, int right, int y, int height, VehicleID selection, EngineImageType image_type, int skip) -{ - y = Center(y, height, GetVehicleHeight(v->type)); - switch (v->type) { - case VEH_TRAIN: DrawTrainImage(Train::From(v), left, right, y, selection, image_type, skip); break; - case VEH_ROAD: DrawRoadVehImage(v, left, right, y, selection, image_type, skip); break; - case VEH_SHIP: DrawShipImage(v, left, right, y, selection, image_type); break; - case VEH_AIRCRAFT: DrawAircraftImage(v, left, right, y, selection, image_type); break; - default: NOT_REACHED(); - } -} - -/** - * Get the height of a vehicle in the vehicle list GUIs. - * @param type the vehicle type to look at - * @param divisor the resulting height must be dividable by this - * @return the height - */ -uint GetVehicleListHeight(VehicleType type, uint divisor) -{ - /* Name + vehicle + profit */ - uint base = GetVehicleHeight(type) + 2 * FONT_HEIGHT_SMALL; - /* Drawing of the 4 small orders + profit*/ - if (type >= VEH_SHIP) base = max(base, 5U * FONT_HEIGHT_SMALL); - - if (divisor == 1) return base; - - /* Make sure the height is dividable by divisor */ - uint rem = base % divisor; - return base + (rem == 0 ? 0 : divisor - rem); -} - -/** - * Draw all the vehicle list items. - * @param selected_vehicle The vehicle that is to be highlighted. - * @param line_height Height of a single item line. - * @param r Rectangle with edge positions of the matrix widget. - */ -void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int line_height, const Rect &r) const -{ - int left = r.left + WD_MATRIX_LEFT; - int right = r.right - WD_MATRIX_RIGHT; - int width = right - left; - bool rtl = _current_text_dir == TD_RTL; - - int text_offset = GetDigitWidth() * this->unitnumber_digits + WD_FRAMERECT_RIGHT; - int text_left = left + (rtl ? 0 : text_offset); - int text_right = right - (rtl ? text_offset : 0); - - bool show_orderlist = this->vli.vtype >= VEH_SHIP; - int orderlist_left = left + (rtl ? 0 : max(100 + text_offset, width / 2)); - int orderlist_right = right - (rtl ? max(100 + text_offset, width / 2) : 0); - - int image_left = (rtl && show_orderlist) ? orderlist_right : text_left; - int image_right = (!rtl && show_orderlist) ? orderlist_left : text_right; - - int vehicle_button_x = rtl ? right - GetSpriteSize(SPR_PROFIT_LOT).width : left; - - int y = r.top; - uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->vehicles.Length()); - for (uint i = this->vscroll->GetPosition(); i < max; ++i) { - const Vehicle *v = this->vehicles[i]; - StringID str; - - SetDParam(0, v->GetDisplayProfitThisYear()); - SetDParam(1, v->GetDisplayProfitLastYear()); - - DrawVehicleImage(v, image_left, image_right, y, line_height, selected_vehicle, EIT_IN_LIST, 0); - DrawString(text_left, text_right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1, STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR); - - if (v->name != NULL) { - /* The vehicle got a name so we will print it */ - SetDParam(0, v->index); - DrawString(text_left, text_right, y, STR_TINY_BLACK_VEHICLE); - } else if (v->group_id != DEFAULT_GROUP) { - /* The vehicle has no name, but is member of a group, so print group name */ - SetDParam(0, v->group_id); - DrawString(text_left, text_right, y, STR_TINY_GROUP, TC_BLACK); - } - - if (show_orderlist) DrawSmallOrderList(v, orderlist_left, orderlist_right, y, v->cur_real_order_index); - - if (v->IsChainInDepot()) { - str = STR_BLUE_COMMA; - } else { - str = (v->age > v->max_age - DAYS_IN_LEAP_YEAR) ? STR_RED_COMMA : STR_BLACK_COMMA; - } - - SetDParam(0, v->unitnumber); - DrawString(left, right, y + 2, str); - - DrawVehicleProfitButton(v, vehicle_button_x, y + FONT_HEIGHT_NORMAL + 3); - - y += line_height; - } -} - -/** - * Window for the (old) vehicle listing. - * - * bitmask for w->window_number - * 0-7 CompanyID (owner) - * 8-10 window type (use flags in vehicle_gui.h) - * 11-15 vehicle type (using VEH_, but can be compressed to fewer bytes if needed) - * 16-31 StationID or OrderID depending on window type (bit 8-10) - */ -struct VehicleListWindow : public BaseVehicleListWindow { -private: - /** Enumeration of planes of the button row at the bottom. */ - enum ButtonPlanes { - BP_SHOW_BUTTONS, ///< Show the buttons. - BP_HIDE_BUTTONS, ///< Show the empty panel. - }; - -public: - VehicleListWindow(WindowDesc *desc, WindowNumber window_number) : BaseVehicleListWindow(desc, window_number) - { - /* Set up sorting. Make the window-specific _sorting variable - * point to the correct global _sorting struct so we are freed - * from having conditionals during window operation */ - switch (this->vli.vtype) { - case VEH_TRAIN: this->sorting = &_sorting.train; break; - case VEH_ROAD: this->sorting = &_sorting.roadveh; break; - case VEH_SHIP: this->sorting = &_sorting.ship; break; - case VEH_AIRCRAFT: this->sorting = &_sorting.aircraft; break; - default: NOT_REACHED(); - } - - this->CreateNestedTree(); - - this->vscroll = this->GetScrollbar(WID_VL_SCROLLBAR); - - this->vehicles.SetListing(*this->sorting); - this->vehicles.ForceRebuild(); - this->vehicles.NeedResort(); - this->BuildVehicleList(); - this->SortVehicleList(); - - /* Set up the window widgets */ - this->GetWidget(WID_VL_LIST)->tool_tip = STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vli.vtype; - - if (this->vli.type == VL_SHARED_ORDERS) { - this->GetWidget(WID_VL_CAPTION)->widget_data = STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION; - } else { - this->GetWidget(WID_VL_CAPTION)->widget_data = STR_VEHICLE_LIST_TRAIN_CAPTION + this->vli.vtype; - } - - this->FinishInitNested(window_number); - if (this->vli.company != OWNER_NONE) this->owner = this->vli.company; - } - - ~VehicleListWindow() - { - *this->sorting = this->vehicles.GetListing(); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_VL_LIST: - resize->height = GetVehicleListHeight(this->vli.vtype, 1); - - switch (this->vli.vtype) { - case VEH_TRAIN: - case VEH_ROAD: - size->height = 6 * resize->height; - break; - case VEH_SHIP: - case VEH_AIRCRAFT: - size->height = 4 * resize->height; - break; - default: NOT_REACHED(); - } - break; - - case WID_VL_SORT_ORDER: { - Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); - d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. - d.height += padding.height; - *size = maxdim(*size, d); - break; - } - - case WID_VL_MANAGE_VEHICLES_DROPDOWN: { - Dimension d = this->GetActionDropdownSize(this->vli.type == VL_STANDARD, false); - d.height += padding.height; - d.width += padding.width; - *size = maxdim(*size, d); - break; - } - } - } - - virtual void SetStringParameters(int widget) const - { - switch (widget) { - case WID_VL_AVAILABLE_VEHICLES: - SetDParam(0, STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vli.vtype); - break; - - case WID_VL_CAPTION: { - switch (this->vli.type) { - case VL_SHARED_ORDERS: // Shared Orders - if (this->vehicles.Length() == 0) { - /* We can't open this window without vehicles using this order - * and we should close the window when deleting the order. */ - NOT_REACHED(); - } - SetDParam(0, this->vscroll->GetCount()); - break; - - case VL_STANDARD: // Company Name - SetDParam(0, STR_COMPANY_NAME); - SetDParam(1, this->vli.index); - SetDParam(3, this->vscroll->GetCount()); - break; - - case VL_STATION_LIST: // Station/Waypoint Name - SetDParam(0, Station::IsExpected(BaseStation::Get(this->vli.index)) ? STR_STATION_NAME : STR_WAYPOINT_NAME); - SetDParam(1, this->vli.index); - SetDParam(3, this->vscroll->GetCount()); - break; - - case VL_DEPOT_LIST: - SetDParam(0, STR_DEPOT_CAPTION); - SetDParam(1, this->vli.vtype); - SetDParam(2, this->vli.index); - SetDParam(3, this->vscroll->GetCount()); - break; - default: NOT_REACHED(); - } - break; - } - } - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case WID_VL_SORT_ORDER: - /* draw arrow pointing up/down for ascending/descending sorting */ - this->DrawSortButtonState(widget, this->vehicles.IsDescSortOrder() ? SBS_DOWN : SBS_UP); - break; - - case WID_VL_LIST: - this->DrawVehicleListItems(INVALID_VEHICLE, this->resize.step_height, r); - break; - } - } - - virtual void OnPaint() - { - this->BuildVehicleList(); - this->SortVehicleList(); - - if (this->vehicles.Length() == 0 && this->IsWidgetLowered(WID_VL_MANAGE_VEHICLES_DROPDOWN)) { - HideDropDownMenu(this); - } - - /* Hide the widgets that we will not use in this window - * Some windows contains actions only fit for the owner */ - int plane_to_show = (this->owner == _local_company) ? BP_SHOW_BUTTONS : BP_HIDE_BUTTONS; - NWidgetStacked *nwi = this->GetWidget(WID_VL_HIDE_BUTTONS); - if (plane_to_show != nwi->shown_plane) { - nwi->SetDisplayedPlane(plane_to_show); - nwi->SetDirty(this); - } - if (this->owner == _local_company) { - this->SetWidgetDisabledState(WID_VL_AVAILABLE_VEHICLES, this->vli.type != VL_STANDARD); - this->SetWidgetsDisabledState(this->vehicles.Length() == 0, - WID_VL_MANAGE_VEHICLES_DROPDOWN, - WID_VL_STOP_ALL, - WID_VL_START_ALL, - WIDGET_LIST_END); - } - - /* Set text of sort by dropdown widget. */ - this->GetWidget(WID_VL_SORT_BY_PULLDOWN)->widget_data = this->vehicle_sorter_names[this->vehicles.SortType()]; - - this->DrawWidgets(); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_VL_SORT_ORDER: // Flip sorting method ascending/descending - this->vehicles.ToggleSortOrder(); - this->SetDirty(); - break; - - case WID_VL_SORT_BY_PULLDOWN:// Select sorting criteria dropdown menu - ShowDropDownMenu(this, this->vehicle_sorter_names, this->vehicles.SortType(), WID_VL_SORT_BY_PULLDOWN, 0, - (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10)); - return; - - case WID_VL_LIST: { // Matrix to show vehicles - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_VL_LIST); - if (id_v >= this->vehicles.Length()) return; // click out of list bound - - const Vehicle *v = this->vehicles[id_v]; - if (!VehicleClicked(v)) ShowVehicleViewWindow(v); - break; - } - - case WID_VL_AVAILABLE_VEHICLES: - ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype); - break; - - case WID_VL_MANAGE_VEHICLES_DROPDOWN: { - DropDownList *list = this->BuildActionDropdownList(VehicleListIdentifier(this->window_number).type == VL_STANDARD, false); - ShowDropDownList(this, list, 0, WID_VL_MANAGE_VEHICLES_DROPDOWN); - break; - } - - case WID_VL_STOP_ALL: - case WID_VL_START_ALL: - DoCommandP(0, (1 << 1) | (widget == WID_VL_START_ALL ? (1 << 0) : 0), this->window_number, CMD_MASS_START_STOP); - break; - } - } - - virtual void OnDropdownSelect(int widget, int index) - { - switch (widget) { - case WID_VL_SORT_BY_PULLDOWN: - this->vehicles.SetSortType(index); - break; - case WID_VL_MANAGE_VEHICLES_DROPDOWN: - assert(this->vehicles.Length() != 0); - - switch (index) { - case ADI_REPLACE: // Replace window - ShowReplaceGroupVehicleWindow(ALL_GROUP, this->vli.vtype); - break; - case ADI_SERVICE: // Send for servicing - case ADI_DEPOT: // Send to Depots - DoCommandP(0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : (DepotCommand)0), this->window_number, GetCmdSendToDepot(this->vli.vtype)); - break; - - default: NOT_REACHED(); - } - break; - default: NOT_REACHED(); - } - this->SetDirty(); - } - - virtual void OnTick() - { - if (_pause_mode != PM_UNPAUSED) return; - if (this->vehicles.NeedResort()) { - StationID station = (this->vli.type == VL_STATION_LIST) ? this->vli.index : INVALID_STATION; - - DEBUG(misc, 3, "Periodic resort %d list company %d at station %d", this->vli.vtype, this->owner, station); - this->SetDirty(); - } - } - - virtual void OnResize() - { - this->vscroll->SetCapacityFromWidget(this, WID_VL_LIST); - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (!gui_scope && HasBit(data, 31) && this->vli.type == VL_SHARED_ORDERS) { - /* Needs to be done in command-scope, so everything stays valid */ - this->vli.index = GB(data, 0, 20); - this->window_number = this->vli.Pack(); - this->vehicles.ForceRebuild(); - return; - } - - if (data == 0) { - /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ - this->vehicles.ForceRebuild(); - } else { - this->vehicles.ForceResort(); - } - } -}; - -static WindowDesc _vehicle_list_other_desc( - WDP_AUTO, "list_vehicles", 260, 246, - WC_INVALID, WC_NONE, - 0, - _nested_vehicle_list, lengthof(_nested_vehicle_list) -); - -static WindowDesc _vehicle_list_train_desc( - WDP_AUTO, "list_vehicles_train", 325, 246, - WC_TRAINS_LIST, WC_NONE, - 0, - _nested_vehicle_list, lengthof(_nested_vehicle_list) -); - -static void ShowVehicleListWindowLocal(CompanyID company, VehicleListType vlt, VehicleType vehicle_type, uint32 unique_number) -{ - if (!Company::IsValidID(company) && company != OWNER_NONE) return; - - WindowNumber num = VehicleListIdentifier(vlt, vehicle_type, company, unique_number).Pack(); - if (vehicle_type == VEH_TRAIN) { - AllocateWindowDescFront(&_vehicle_list_train_desc, num); - } else { - _vehicle_list_other_desc.cls = GetWindowClassForVehicleType(vehicle_type); - AllocateWindowDescFront(&_vehicle_list_other_desc, num); - } -} - -void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type) -{ - /* If _settings_client.gui.advanced_vehicle_list > 1, display the Advanced list - * if _settings_client.gui.advanced_vehicle_list == 1, display Advanced list only for local company - * if _ctrl_pressed, do the opposite action (Advanced list x Normal list) - */ - - if ((_settings_client.gui.advanced_vehicle_list > (uint)(company != _local_company)) != _ctrl_pressed) { - ShowCompanyGroup(company, vehicle_type); - } else { - ShowVehicleListWindowLocal(company, VL_STANDARD, vehicle_type, company); - } -} - -void ShowVehicleListWindow(const Vehicle *v) -{ - ShowVehicleListWindowLocal(v->owner, VL_SHARED_ORDERS, v->type, v->FirstShared()->index); -} - -void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, StationID station) -{ - ShowVehicleListWindowLocal(company, VL_STATION_LIST, vehicle_type, station); -} - -void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, TileIndex depot_tile) -{ - uint16 depot_airport_index; - - if (vehicle_type == VEH_AIRCRAFT) { - depot_airport_index = GetStationIndex(depot_tile); - } else { - depot_airport_index = GetDepotIndex(depot_tile); - } - ShowVehicleListWindowLocal(company, VL_DEPOT_LIST, vehicle_type, depot_airport_index); -} - - -/* Unified vehicle GUI - Vehicle Details Window */ - -assert_compile(WID_VD_DETAILS_CARGO_CARRIED == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_CARGO ); -assert_compile(WID_VD_DETAILS_TRAIN_VEHICLES == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_INFO ); -assert_compile(WID_VD_DETAILS_CAPACITY_OF_EACH == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_CAPACITY); -assert_compile(WID_VD_DETAILS_TOTAL_CARGO == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_TOTALS ); - -/** Vehicle details widgets (other than train). */ -static const NWidgetPart _nested_nontrain_vehicle_details_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, WID_VD_CAPTION), SetDataTip(STR_VEHICLE_DETAILS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_RENAME_VEHICLE), SetMinimalSize(40, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_VEHICLE_NAME_BUTTON, STR_NULL /* filled in later */), - NWidget(WWT_SHADEBOX, COLOUR_GREY), - NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), - NWidget(WWT_STICKYBOX, COLOUR_GREY), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_TOP_DETAILS), SetMinimalSize(405, 42), SetResize(1, 0), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_MIDDLE_DETAILS), SetMinimalSize(405, 45), SetResize(1, 0), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_VD_DECREASE_SERVICING_INTERVAL), SetFill(0, 1), - SetDataTip(AWV_DECREASE, STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_VD_INCREASE_SERVICING_INTERVAL), SetFill(0, 1), - SetDataTip(AWV_INCREASE, STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VD_SERVICE_INTERVAL_DROPDOWN), SetFill(0, 1), - SetDataTip(STR_EMPTY, STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP), - NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_SERVICING_INTERVAL), SetFill(1, 1), SetResize(1, 0), EndContainer(), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), - EndContainer(), -}; - -/** Train details widgets. */ -static const NWidgetPart _nested_train_vehicle_details_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, WID_VD_CAPTION), SetDataTip(STR_VEHICLE_DETAILS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_RENAME_VEHICLE), SetMinimalSize(40, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_VEHICLE_NAME_BUTTON, STR_NULL /* filled in later */), - NWidget(WWT_SHADEBOX, COLOUR_GREY), - NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), - NWidget(WWT_STICKYBOX, COLOUR_GREY), - EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_TOP_DETAILS), SetResize(1, 0), SetMinimalSize(405, 42), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_VD_MATRIX), SetResize(1, 1), SetMinimalSize(393, 45), SetMatrixDataTip(1, 0, STR_NULL), SetFill(1, 0), SetScrollbar(WID_VD_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VD_SCROLLBAR), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_VD_DECREASE_SERVICING_INTERVAL), SetFill(0, 1), - SetDataTip(AWV_DECREASE, STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_VD_INCREASE_SERVICING_INTERVAL), SetFill(0, 1), - SetDataTip(AWV_INCREASE, STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VD_SERVICE_INTERVAL_DROPDOWN), SetFill(0, 1), - SetDataTip(STR_EMPTY, STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP), - NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_SERVICING_INTERVAL), SetFill(1, 1), SetResize(1, 0), EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_DETAILS_CARGO_CARRIED), SetMinimalSize(96, 12), - SetDataTip(STR_VEHICLE_DETAIL_TAB_CARGO, STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP), SetFill(1, 0), SetResize(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_DETAILS_TRAIN_VEHICLES), SetMinimalSize(99, 12), - SetDataTip(STR_VEHICLE_DETAIL_TAB_INFORMATION, STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP), SetFill(1, 0), SetResize(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_DETAILS_CAPACITY_OF_EACH), SetMinimalSize(99, 12), - SetDataTip(STR_VEHICLE_DETAIL_TAB_CAPACITIES, STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP), SetFill(1, 0), SetResize(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_DETAILS_TOTAL_CARGO), SetMinimalSize(99, 12), - SetDataTip(STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO, STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP), SetFill(1, 0), SetResize(1, 0), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), - EndContainer(), -}; - - -extern int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab); -extern void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_pos, uint16 vscroll_cap, TrainDetailsWindowTabs det_tab); -extern void DrawRoadVehDetails(const Vehicle *v, int left, int right, int y); -extern void DrawShipDetails(const Vehicle *v, int left, int right, int y); -extern void DrawAircraftDetails(const Aircraft *v, int left, int right, int y); - -static StringID _service_interval_dropdown[] = { - STR_VEHICLE_DETAILS_DEFAULT, - STR_VEHICLE_DETAILS_DAYS, - STR_VEHICLE_DETAILS_PERCENT, - INVALID_STRING_ID, -}; - -/** Class for managing the vehicle details window. */ -struct VehicleDetailsWindow : Window { - TrainDetailsWindowTabs tab; ///< For train vehicles: which tab is displayed. - Scrollbar *vscroll; - - /** Initialize a newly created vehicle details window */ - VehicleDetailsWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) - { - const Vehicle *v = Vehicle::Get(window_number); - - this->CreateNestedTree(); - this->vscroll = (v->type == VEH_TRAIN ? this->GetScrollbar(WID_VD_SCROLLBAR) : NULL); - this->FinishInitNested(window_number); - - this->GetWidget(WID_VD_RENAME_VEHICLE)->tool_tip = STR_VEHICLE_DETAILS_TRAIN_RENAME + v->type; - - this->owner = v->owner; - this->tab = TDW_TAB_CARGO; - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (data == VIWD_AUTOREPLACE) { - /* Autoreplace replaced the vehicle. - * Nothing to do for this window. */ - return; - } - if (!gui_scope) return; - const Vehicle *v = Vehicle::Get(this->window_number); - if (v->type == VEH_ROAD) { - const NWidgetBase *nwid_info = this->GetWidget(WID_VD_MIDDLE_DETAILS); - uint aimed_height = this->GetRoadVehDetailsHeight(v); - /* If the number of articulated parts changes, the size of the window must change too. */ - if (aimed_height != nwid_info->current_y) { - this->ReInit(); - } - } - } - - /** - * Gets the desired height for the road vehicle details panel. - * @param v Road vehicle being shown. - * @return Desired height in pixels. - */ - uint GetRoadVehDetailsHeight(const Vehicle *v) - { - uint desired_height; - if (v->HasArticulatedPart()) { - /* An articulated RV has its text drawn under the sprite instead of after it, hence 15 pixels extra. */ - desired_height = WD_FRAMERECT_TOP + 15 + 3 * FONT_HEIGHT_NORMAL + 2 + WD_FRAMERECT_BOTTOM; - /* Add space for the cargo amount for each part. */ - for (const Vehicle *u = v; u != NULL; u = u->Next()) { - if (u->cargo_cap != 0) desired_height += FONT_HEIGHT_NORMAL + 1; - } - } else { - desired_height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + 3 + WD_FRAMERECT_BOTTOM; - } - return desired_height; - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_VD_TOP_DETAILS: { - Dimension dim = { 0, 0 }; - size->height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; - - for (uint i = 0; i < 4; i++) SetDParamMaxValue(i, INT16_MAX); - static const StringID info_strings[] = { - STR_VEHICLE_INFO_MAX_SPEED, - STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, - STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE, - STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR, - STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS - }; - for (uint i = 0; i < lengthof(info_strings); i++) { - dim = maxdim(dim, GetStringBoundingBox(info_strings[i])); - } - SetDParam(0, STR_VEHICLE_INFO_AGE); - dim = maxdim(dim, GetStringBoundingBox(STR_VEHICLE_INFO_AGE_RUNNING_COST_YR)); - size->width = dim.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - break; - } - - case WID_VD_MIDDLE_DETAILS: { - const Vehicle *v = Vehicle::Get(this->window_number); - switch (v->type) { - case VEH_ROAD: - size->height = this->GetRoadVehDetailsHeight(v); - break; - - case VEH_SHIP: - size->height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + 3 + WD_FRAMERECT_BOTTOM; - break; - - case VEH_AIRCRAFT: - size->height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + 4 + WD_FRAMERECT_BOTTOM; - break; - - default: - NOT_REACHED(); // Train uses WID_VD_MATRIX instead. - } - break; - } - - case WID_VD_MATRIX: - resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM; - size->height = 4 * resize->height; - break; - - case WID_VD_SERVICE_INTERVAL_DROPDOWN: { - StringID *strs = _service_interval_dropdown; - while (*strs != INVALID_STRING_ID) { - *size = maxdim(*size, GetStringBoundingBox(*strs++)); - } - size->width += padding.width; - size->height = FONT_HEIGHT_NORMAL + WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM; - break; - } - - case WID_VD_SERVICING_INTERVAL: - SetDParamMaxValue(0, MAX_SERVINT_DAYS); // Roughly the maximum interval - SetDParamMaxValue(1, MAX_YEAR * DAYS_IN_YEAR); // Roughly the maximum year - size->width = max(GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT).width, GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - size->height = WD_FRAMERECT_TOP + FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; - break; - } - } - - /** Checks whether service interval is enabled for the vehicle. */ - static bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type, CompanyID company_id) - { - const VehicleDefaultSettings *vds = &Company::Get(company_id)->settings.vehicle; - switch (vehicle_type) { - default: NOT_REACHED(); - case VEH_TRAIN: return vds->servint_trains != 0; - case VEH_ROAD: return vds->servint_roadveh != 0; - case VEH_SHIP: return vds->servint_ships != 0; - case VEH_AIRCRAFT: return vds->servint_aircraft != 0; - } - } - - /** - * Draw the details for the given vehicle at the position of the Details windows - * - * @param v current vehicle - * @param left The left most coordinate to draw - * @param right The right most coordinate to draw - * @param y The y coordinate - * @param vscroll_pos Position of scrollbar (train only) - * @param vscroll_cap Number of lines currently displayed (train only) - * @param det_tab Selected details tab (train only) - */ - static void DrawVehicleDetails(const Vehicle *v, int left, int right, int y, int vscroll_pos, uint vscroll_cap, TrainDetailsWindowTabs det_tab) - { - switch (v->type) { - case VEH_TRAIN: DrawTrainDetails(Train::From(v), left, right, y, vscroll_pos, vscroll_cap, det_tab); break; - case VEH_ROAD: DrawRoadVehDetails(v, left, right, y); break; - case VEH_SHIP: DrawShipDetails(v, left, right, y); break; - case VEH_AIRCRAFT: DrawAircraftDetails(Aircraft::From(v), left, right, y); break; - default: NOT_REACHED(); - } - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_VD_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - const Vehicle *v = Vehicle::Get(this->window_number); - - switch (widget) { - case WID_VD_TOP_DETAILS: { - int y = r.top + WD_FRAMERECT_TOP; - - /* Draw running cost */ - SetDParam(1, v->age / DAYS_IN_LEAP_YEAR); - SetDParam(0, (v->age + DAYS_IN_YEAR < v->max_age) ? STR_VEHICLE_INFO_AGE : STR_VEHICLE_INFO_AGE_RED); - SetDParam(2, v->max_age / DAYS_IN_LEAP_YEAR); - SetDParam(3, v->GetDisplayRunningCost()); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_AGE_RUNNING_COST_YR); - y += FONT_HEIGHT_NORMAL; - - /* Draw max speed */ - StringID string; - if (v->type == VEH_TRAIN || - (v->type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL)) { - const GroundVehicleCache *gcache = v->GetGroundVehicleCache(); - SetDParam(2, v->GetDisplayMaxSpeed()); - SetDParam(1, gcache->cached_power); - SetDParam(0, gcache->cached_weight); - SetDParam(3, gcache->cached_max_te / 1000); - if (v->type == VEH_TRAIN && (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL || - GetRailTypeInfo(Train::From(v)->railtype)->acceleration_type == 2)) { - string = STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED; - } else { - string = STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE; - } - } else { - SetDParam(0, v->GetDisplayMaxSpeed()); - if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->GetRange() > 0) { - SetDParam(1, Aircraft::From(v)->GetRange()); - string = STR_VEHICLE_INFO_MAX_SPEED_RANGE; - } else { - string = STR_VEHICLE_INFO_MAX_SPEED; - } - } - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, string); - y += FONT_HEIGHT_NORMAL; - - /* Draw profit */ - SetDParam(0, v->GetDisplayProfitThisYear()); - SetDParam(1, v->GetDisplayProfitLastYear()); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR); - y += FONT_HEIGHT_NORMAL; - - /* Draw breakdown & reliability */ - SetDParam(0, ToPercent16(v->reliability)); - SetDParam(1, v->breakdowns_since_last_service); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS); - break; - } - - case WID_VD_MATRIX: - /* For trains only. */ - DrawVehicleDetails(v, r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, r.top + WD_MATRIX_TOP, this->vscroll->GetPosition(), this->vscroll->GetCapacity(), this->tab); - break; - - case WID_VD_MIDDLE_DETAILS: { - /* For other vehicles, at the place of the matrix. */ - bool rtl = _current_text_dir == TD_RTL; - uint sprite_width = max(UnScaleByZoom(GetSprite(v->GetImage(rtl ? DIR_E : DIR_W, EIT_IN_DETAILS), ST_NORMAL)->width, ZOOM_LVL_GUI), 70U) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - - uint text_left = r.left + (rtl ? 0 : sprite_width); - uint text_right = r.right - (rtl ? sprite_width : 0); - - /* Articulated road vehicles use a complete line. */ - if (v->type == VEH_ROAD && v->HasArticulatedPart()) { - DrawVehicleImage(v, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, 0); - } else { - uint sprite_left = rtl ? text_right : r.left; - uint sprite_right = rtl ? r.right : text_left; - - DrawVehicleImage(v, sprite_left + WD_FRAMERECT_LEFT, sprite_right - WD_FRAMERECT_RIGHT, r.top, r.bottom - r.top, INVALID_VEHICLE, EIT_IN_DETAILS, 0); - } - DrawVehicleDetails(v, text_left + WD_FRAMERECT_LEFT, text_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, 0, 0, this->tab); - break; - } - - case WID_VD_SERVICING_INTERVAL: - /* Draw service interval text */ - SetDParam(0, v->GetServiceInterval()); - SetDParam(1, v->date_of_last_service); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + (r.bottom - r.top + 1 - FONT_HEIGHT_NORMAL) / 2, - v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT : STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS); - break; - } - } - - /** Repaint vehicle details window. */ - virtual void OnPaint() - { - const Vehicle *v = Vehicle::Get(this->window_number); - - this->SetWidgetDisabledState(WID_VD_RENAME_VEHICLE, v->owner != _local_company); - - if (v->type == VEH_TRAIN) { - this->DisableWidget(this->tab + WID_VD_DETAILS_CARGO_CARRIED); - this->vscroll->SetCount(GetTrainDetailsWndVScroll(v->index, this->tab)); - } - - /* Disable service-scroller when interval is set to disabled */ - this->SetWidgetsDisabledState(!IsVehicleServiceIntervalEnabled(v->type, v->owner), - WID_VD_INCREASE_SERVICING_INTERVAL, - WID_VD_DECREASE_SERVICING_INTERVAL, - WIDGET_LIST_END); - - StringID str = v->ServiceIntervalIsCustom() ? - (v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_PERCENT : STR_VEHICLE_DETAILS_DAYS) : - STR_VEHICLE_DETAILS_DEFAULT; - this->GetWidget(WID_VD_SERVICE_INTERVAL_DROPDOWN)->widget_data = str; - - this->DrawWidgets(); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_VD_RENAME_VEHICLE: { // rename - const Vehicle *v = Vehicle::Get(this->window_number); - SetDParam(0, v->index); - ShowQueryString(STR_VEHICLE_NAME, STR_QUERY_RENAME_TRAIN_CAPTION + v->type, - MAX_LENGTH_VEHICLE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); - break; - } - - case WID_VD_INCREASE_SERVICING_INTERVAL: // increase int - case WID_VD_DECREASE_SERVICING_INTERVAL: { // decrease int - int mod = _ctrl_pressed ? 5 : 10; - const Vehicle *v = Vehicle::Get(this->window_number); - - mod = (widget == WID_VD_DECREASE_SERVICING_INTERVAL) ? -mod : mod; - mod = GetServiceIntervalClamped(mod + v->GetServiceInterval(), v->ServiceIntervalIsPercent()); - if (mod == v->GetServiceInterval()) return; - - DoCommandP(v->tile, v->index, mod | (1 << 16) | (v->ServiceIntervalIsPercent() << 17), CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_SERVICING)); - break; - } - - case WID_VD_SERVICE_INTERVAL_DROPDOWN: { - const Vehicle *v = Vehicle::Get(this->window_number); - ShowDropDownMenu(this, _service_interval_dropdown, v->ServiceIntervalIsCustom() ? (v->ServiceIntervalIsPercent() ? 2 : 1) : 0, widget, 0, 0); - break; - } - - case WID_VD_DETAILS_CARGO_CARRIED: - case WID_VD_DETAILS_TRAIN_VEHICLES: - case WID_VD_DETAILS_CAPACITY_OF_EACH: - case WID_VD_DETAILS_TOTAL_CARGO: - this->SetWidgetsDisabledState(false, - WID_VD_DETAILS_CARGO_CARRIED, - WID_VD_DETAILS_TRAIN_VEHICLES, - WID_VD_DETAILS_CAPACITY_OF_EACH, - WID_VD_DETAILS_TOTAL_CARGO, - widget, - WIDGET_LIST_END); - - this->tab = (TrainDetailsWindowTabs)(widget - WID_VD_DETAILS_CARGO_CARRIED); - this->SetDirty(); - break; - } - } - - virtual void OnDropdownSelect(int widget, int index) - { - switch (widget) { - case WID_VD_SERVICE_INTERVAL_DROPDOWN: { - const Vehicle *v = Vehicle::Get(this->window_number); - bool iscustom = index != 0; - bool ispercent = iscustom ? (index == 2) : Company::Get(v->owner)->settings.vehicle.servint_ispercent; - uint16 interval = GetServiceIntervalClamped(v->GetServiceInterval(), ispercent); - DoCommandP(v->tile, v->index, interval | (iscustom << 16) | (ispercent << 17), CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_SERVICING)); - break; - } - } - } - - virtual void OnQueryTextFinished(char *str) - { - if (str == NULL) return; - - DoCommandP(0, this->window_number, 0, CMD_RENAME_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN + Vehicle::Get(this->window_number)->type), NULL, str); - } - - virtual void OnResize() - { - NWidgetCore *nwi = this->GetWidget(WID_VD_MATRIX); - if (nwi != NULL) { - this->vscroll->SetCapacityFromWidget(this, WID_VD_MATRIX); - } - } -}; - -/** Vehicle details window descriptor. */ -static WindowDesc _train_vehicle_details_desc( - WDP_AUTO, "view_vehicle_details_train", 405, 178, - WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW, - 0, - _nested_train_vehicle_details_widgets, lengthof(_nested_train_vehicle_details_widgets) -); - -/** Vehicle details window descriptor for other vehicles than a train. */ -static WindowDesc _nontrain_vehicle_details_desc( - WDP_AUTO, "view_vehicle_details", 405, 113, - WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW, - 0, - _nested_nontrain_vehicle_details_widgets, lengthof(_nested_nontrain_vehicle_details_widgets) -); - -/** Shows the vehicle details window of the given vehicle. */ -static void ShowVehicleDetailsWindow(const Vehicle *v) -{ - DeleteWindowById(WC_VEHICLE_ORDERS, v->index, false); - DeleteWindowById(WC_VEHICLE_TIMETABLE, v->index, false); - AllocateWindowDescFront((v->type == VEH_TRAIN) ? &_train_vehicle_details_desc : &_nontrain_vehicle_details_desc, v->index); -} - - -/* Unified vehicle GUI - Vehicle View Window */ - -/** Vehicle view widgets. */ -static const NWidgetPart _nested_vehicle_view_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, WID_VV_CAPTION), SetDataTip(STR_VEHICLE_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - NWidget(WWT_DEBUGBOX, COLOUR_GREY), - NWidget(WWT_SHADEBOX, COLOUR_GREY), - NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), - NWidget(WWT_STICKYBOX, COLOUR_GREY), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_GREY), - NWidget(WWT_INSET, COLOUR_GREY), SetPadding(2, 2, 2, 2), - NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_VV_VIEWPORT), SetMinimalSize(226, 84), SetResize(1, 1), SetPadding(1, 1, 1, 1), - EndContainer(), - EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_CENTER_MAIN_VIEW), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(SPR_CENTRE_VIEW_VEHICLE, 0x0 /* filled later */), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VV_SELECT_DEPOT_CLONE), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_GOTO_DEPOT), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(0x0 /* filled later */, 0x0 /* filled later */), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_CLONE), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(0x0 /* filled later */, 0x0 /* filled later */), - EndContainer(), - /* For trains only, 'ignore signal' button. */ - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_FORCE_PROCEED), SetMinimalSize(18, 18), SetFill(1, 1), - SetDataTip(SPR_IGNORE_SIGNALS, STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VV_SELECT_REFIT_TURN), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_REFIT), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(SPR_REFIT_VEHICLE, 0x0 /* filled later */), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_TURN_AROUND), SetMinimalSize(18, 18), SetFill(1, 1), - SetDataTip(SPR_FORCE_VEHICLE_TURN, STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP), - EndContainer(), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_SHOW_ORDERS), SetFill(1, 1), SetMinimalSize(18, 18), SetDataTip(SPR_SHOW_ORDERS, 0x0 /* filled later */), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_SHOW_DETAILS), SetFill(1, 1), SetMinimalSize(18, 18), SetDataTip(SPR_SHOW_VEHICLE_DETAILS, 0x0 /* filled later */), - NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetMinimalSize(18, 0), SetResize(0, 1), EndContainer(), - EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_VV_START_STOP), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetResize(1, 0), SetFill(1, 0), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), - EndContainer(), -}; - -/** Vehicle view window descriptor for all vehicles but trains. */ -static WindowDesc _vehicle_view_desc( - WDP_AUTO, "view_vehicle", 250, 116, - WC_VEHICLE_VIEW, WC_NONE, - 0, - _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets) -); - -/** - * Vehicle view window descriptor for trains. Only minimum_height and - * default_height are different for train view. - */ -static WindowDesc _train_view_desc( - WDP_AUTO, "view_vehicle_train", 250, 134, - WC_VEHICLE_VIEW, WC_NONE, - 0, - _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets) -); - - -/* Just to make sure, nobody has changed the vehicle type constants, as we are - using them for array indexing in a number of places here. */ -assert_compile(VEH_TRAIN == 0); -assert_compile(VEH_ROAD == 1); -assert_compile(VEH_SHIP == 2); -assert_compile(VEH_AIRCRAFT == 3); - -/** Zoom levels for vehicle views indexed by vehicle type. */ -static const ZoomLevel _vehicle_view_zoom_levels[] = { - ZOOM_LVL_TRAIN, - ZOOM_LVL_ROADVEH, - ZOOM_LVL_SHIP, - ZOOM_LVL_AIRCRAFT, -}; - -/* Constants for geometry of vehicle view viewport */ -static const int VV_INITIAL_VIEWPORT_WIDTH = 226; -static const int VV_INITIAL_VIEWPORT_HEIGHT = 84; -static const int VV_INITIAL_VIEWPORT_HEIGHT_TRAIN = 102; - -/** Command indices for the _vehicle_command_translation_table. */ -enum VehicleCommandTranslation { - VCT_CMD_START_STOP = 0, - VCT_CMD_CLONE_VEH, - VCT_CMD_TURN_AROUND, -}; - -/** Command codes for the shared buttons indexed by VehicleCommandTranslation and vehicle type. */ -static const uint32 _vehicle_command_translation_table[][4] = { - { // VCT_CMD_START_STOP - CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_TRAIN), - CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE), - CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_SHIP), - CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_AIRCRAFT) - }, - { // VCT_CMD_CLONE_VEH - CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN), - CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_ROAD_VEHICLE), - CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_SHIP), - CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_AIRCRAFT) - }, - { // VCT_CMD_TURN_AROUND - CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN), - CMD_TURN_ROADVEH | CMD_MSG(STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN), - 0xffffffff, // invalid for ships - 0xffffffff // invalid for aircrafts - }, -}; - -/** - * This is the Callback method after the cloning attempt of a vehicle - * @param result the result of the cloning command - * @param tile unused - * @param p1 vehicle ID - * @param p2 unused - */ -void CcStartStopVehicle(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Failed()) return; - - const Vehicle *v = Vehicle::GetIfValid(p1); - if (v == NULL || !v->IsPrimaryVehicle() || v->owner != _local_company) return; - - StringID msg = (v->vehstatus & VS_STOPPED) ? STR_VEHICLE_COMMAND_STOPPED : STR_VEHICLE_COMMAND_STARTED; - Point pt = RemapCoords(v->x_pos, v->y_pos, v->z_pos); - AddTextEffect(msg, pt.x, pt.y, DAY_TICKS, TE_RISING); -} - -/** - * Executes #CMD_START_STOP_VEHICLE for given vehicle. - * @param v Vehicle to start/stop - * @param texteffect Should a texteffect be shown? - */ -void StartStopVehicle(const Vehicle *v, bool texteffect) -{ - assert(v->IsPrimaryVehicle()); - DoCommandP(v->tile, v->index, 0, _vehicle_command_translation_table[VCT_CMD_START_STOP][v->type], texteffect ? CcStartStopVehicle : NULL); -} - -/** Checks whether the vehicle may be refitted at the moment.*/ -static bool IsVehicleRefitable(const Vehicle *v) -{ - if (!v->IsStoppedInDepot()) return false; - - do { - if (IsEngineRefittable(v->engine_type)) return true; - } while (v->IsGroundVehicle() && (v = v->Next()) != NULL); - - return false; -} - -/** Window manager class for viewing a vehicle. */ -struct VehicleViewWindow : Window { -private: - /** Display planes available in the vehicle view window. */ - enum PlaneSelections { - SEL_DC_GOTO_DEPOT, ///< Display 'goto depot' button in #WID_VV_SELECT_DEPOT_CLONE stacked widget. - SEL_DC_CLONE, ///< Display 'clone vehicle' button in #WID_VV_SELECT_DEPOT_CLONE stacked widget. - - SEL_RT_REFIT, ///< Display 'refit' button in #WID_VV_SELECT_REFIT_TURN stacked widget. - SEL_RT_TURN_AROUND, ///< Display 'turn around' button in #WID_VV_SELECT_REFIT_TURN stacked widget. - - SEL_DC_BASEPLANE = SEL_DC_GOTO_DEPOT, ///< First plane of the #WID_VV_SELECT_DEPOT_CLONE stacked widget. - SEL_RT_BASEPLANE = SEL_RT_REFIT, ///< First plane of the #WID_VV_SELECT_REFIT_TURN stacked widget. - }; - - /** - * Display a plane in the window. - * @param plane Plane to show. - */ - void SelectPlane(PlaneSelections plane) - { - switch (plane) { - case SEL_DC_GOTO_DEPOT: - case SEL_DC_CLONE: - this->GetWidget(WID_VV_SELECT_DEPOT_CLONE)->SetDisplayedPlane(plane - SEL_DC_BASEPLANE); - break; - - case SEL_RT_REFIT: - case SEL_RT_TURN_AROUND: - this->GetWidget(WID_VV_SELECT_REFIT_TURN)->SetDisplayedPlane(plane - SEL_RT_BASEPLANE); - break; - - default: - NOT_REACHED(); - } - } - -public: - VehicleViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) - { - this->CreateNestedTree(); - - /* Sprites for the 'send to depot' button indexed by vehicle type. */ - static const SpriteID vehicle_view_goto_depot_sprites[] = { - SPR_SEND_TRAIN_TODEPOT, - SPR_SEND_ROADVEH_TODEPOT, - SPR_SEND_SHIP_TODEPOT, - SPR_SEND_AIRCRAFT_TODEPOT, - }; - const Vehicle *v = Vehicle::Get(window_number); - this->GetWidget(WID_VV_GOTO_DEPOT)->widget_data = vehicle_view_goto_depot_sprites[v->type]; - - /* Sprites for the 'clone vehicle' button indexed by vehicle type. */ - static const SpriteID vehicle_view_clone_sprites[] = { - SPR_CLONE_TRAIN, - SPR_CLONE_ROADVEH, - SPR_CLONE_SHIP, - SPR_CLONE_AIRCRAFT, - }; - this->GetWidget(WID_VV_CLONE)->widget_data = vehicle_view_clone_sprites[v->type]; - - switch (v->type) { - case VEH_TRAIN: - this->GetWidget(WID_VV_TURN_AROUND)->tool_tip = STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP; - break; - - case VEH_ROAD: - break; - - case VEH_SHIP: - case VEH_AIRCRAFT: - this->SelectPlane(SEL_RT_REFIT); - break; - - default: NOT_REACHED(); - } - this->FinishInitNested(window_number); - this->owner = v->owner; - this->GetWidget(WID_VV_VIEWPORT)->InitializeViewport(this, this->window_number | (1 << 31), _vehicle_view_zoom_levels[v->type]); - - this->GetWidget(WID_VV_START_STOP)->tool_tip = STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP + v->type; - this->GetWidget(WID_VV_CENTER_MAIN_VIEW)->tool_tip = STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP + v->type; - this->GetWidget(WID_VV_REFIT)->tool_tip = STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP + v->type; - this->GetWidget(WID_VV_GOTO_DEPOT)->tool_tip = STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP + v->type; - this->GetWidget(WID_VV_SHOW_ORDERS)->tool_tip = STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP + v->type; - this->GetWidget(WID_VV_SHOW_DETAILS)->tool_tip = STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP + v->type; - this->GetWidget(WID_VV_CLONE)->tool_tip = STR_VEHICLE_VIEW_CLONE_TRAIN_INFO + v->type; - } - - ~VehicleViewWindow() - { - DeleteWindowById(WC_VEHICLE_ORDERS, this->window_number, false); - DeleteWindowById(WC_VEHICLE_REFIT, this->window_number, false); - DeleteWindowById(WC_VEHICLE_DETAILS, this->window_number, false); - DeleteWindowById(WC_VEHICLE_TIMETABLE, this->window_number, false); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - const Vehicle *v = Vehicle::Get(this->window_number); - switch (widget) { - case WID_VV_START_STOP: - size->height = max(size->height, max(GetSpriteSize(SPR_FLAG_VEH_STOPPED).height, GetSpriteSize(SPR_FLAG_VEH_RUNNING).height) + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM); - break; - - case WID_VV_FORCE_PROCEED: - if (v->type != VEH_TRAIN) { - size->height = 0; - size->width = 0; - } - break; - - case WID_VV_VIEWPORT: - size->width = VV_INITIAL_VIEWPORT_WIDTH; - size->height = (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT; - break; - } - } - - virtual void OnPaint() - { - const Vehicle *v = Vehicle::Get(this->window_number); - bool is_localcompany = v->owner == _local_company; - bool refitable_and_stopped_in_depot = IsVehicleRefitable(v); - - this->SetWidgetDisabledState(WID_VV_GOTO_DEPOT, !is_localcompany); - this->SetWidgetDisabledState(WID_VV_REFIT, !refitable_and_stopped_in_depot || !is_localcompany); - this->SetWidgetDisabledState(WID_VV_CLONE, !is_localcompany); - - if (v->type == VEH_TRAIN) { - this->SetWidgetLoweredState(WID_VV_FORCE_PROCEED, Train::From(v)->force_proceed == TFP_SIGNAL); - this->SetWidgetDisabledState(WID_VV_FORCE_PROCEED, !is_localcompany); - this->SetWidgetDisabledState(WID_VV_TURN_AROUND, !is_localcompany); - } - - this->DrawWidgets(); - } - - virtual void SetStringParameters(int widget) const - { - if (widget != WID_VV_CAPTION) return; - - const Vehicle *v = Vehicle::Get(this->window_number); - SetDParam(0, v->index); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (widget != WID_VV_START_STOP) return; - - const Vehicle *v = Vehicle::Get(this->window_number); - StringID str; - if (v->vehstatus & VS_CRASHED) { - str = STR_VEHICLE_STATUS_CRASHED; - } else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) { // check for aircraft necessary? - str = STR_VEHICLE_STATUS_BROKEN_DOWN; - } else if (v->vehstatus & VS_STOPPED) { - if (v->type == VEH_TRAIN) { - if (v->cur_speed == 0) { - if (Train::From(v)->gcache.cached_power == 0) { - str = STR_VEHICLE_STATUS_TRAIN_NO_POWER; - } else { - str = STR_VEHICLE_STATUS_STOPPED; - } - } else { - SetDParam(0, v->GetDisplaySpeed()); - str = STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL; - } - } else { // no train - str = STR_VEHICLE_STATUS_STOPPED; - } - } else if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_TRAIN_STUCK) && !v->current_order.IsType(OT_LOADING)) { - str = STR_VEHICLE_STATUS_TRAIN_STUCK; - } else if (v->type == VEH_AIRCRAFT && HasBit(Aircraft::From(v)->flags, VAF_DEST_TOO_FAR) && !v->current_order.IsType(OT_LOADING)) { - str = STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR; - } else { // vehicle is in a "normal" state, show current order - switch (v->current_order.GetType()) { - case OT_GOTO_STATION: { - SetDParam(0, v->current_order.GetDestination()); - SetDParam(1, v->GetDisplaySpeed()); - str = STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL; - break; - } - - case OT_GOTO_DEPOT: { - SetDParam(0, v->type); - SetDParam(1, v->current_order.GetDestination()); - SetDParam(2, v->GetDisplaySpeed()); - if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) { - /* This case *only* happens when multiple nearest depot orders - * follow each other (including an order list only one order: a - * nearest depot order) and there are no reachable depots. - * It is primarily to guard for the case that there is no - * depot with index 0, which would be used as fallback for - * evaluating the string in the status bar. */ - str = STR_EMPTY; - } else if (v->current_order.GetDepotActionType() & ODATFB_HALT) { - str = STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL; - } else { - str = STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL; - } - break; - } - - case OT_LOADING: - str = STR_VEHICLE_STATUS_LOADING_UNLOADING; - break; - - case OT_GOTO_WAYPOINT: { - assert(v->type == VEH_TRAIN || v->type == VEH_SHIP); - SetDParam(0, v->current_order.GetDestination()); - str = STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL; - SetDParam(1, v->GetDisplaySpeed()); - break; - } - - case OT_LEAVESTATION: - if (v->type != VEH_AIRCRAFT) { - str = STR_VEHICLE_STATUS_LEAVING; - break; - } - /* FALL THROUGH, if aircraft. Does this even happen? */ - - default: - if (v->GetNumManualOrders() == 0) { - str = STR_VEHICLE_STATUS_NO_ORDERS_VEL; - SetDParam(0, v->GetDisplaySpeed()); - } else { - str = STR_EMPTY; - } - break; - } - } - - /* Draw the flag plus orders. */ - bool rtl = (_current_text_dir == TD_RTL); - uint text_offset = max(GetSpriteSize(SPR_FLAG_VEH_STOPPED).width, GetSpriteSize(SPR_FLAG_VEH_RUNNING).width) + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; - int text_left = r.left + (rtl ? (uint)WD_FRAMERECT_LEFT : text_offset); - int text_right = r.right - (rtl ? text_offset : (uint)WD_FRAMERECT_RIGHT); - int image_left = (rtl ? text_right + 1 : r.left) + WD_IMGBTN_LEFT; - int image = ((v->vehstatus & VS_STOPPED) != 0) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING; - int lowered = this->IsWidgetLowered(WID_VV_START_STOP) ? 1 : 0; - DrawSprite(image, PAL_NONE, image_left + lowered, r.top + WD_IMGBTN_TOP + lowered); - DrawString(text_left + lowered, text_right + lowered, Center(r.top + lowered, r.bottom - r.top), str, TC_FROMSTRING, SA_HOR_CENTER); - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - const Vehicle *v = Vehicle::Get(this->window_number); - - switch (widget) { - case WID_VV_START_STOP: // start stop - if (_ctrl_pressed) { - /* Scroll to current order destination */ - TileIndex tile = v->current_order.GetLocation(v); - if (tile != INVALID_TILE) ScrollMainWindowToTile(tile); - } else { - /* Start/Stop */ - StartStopVehicle(v, false); - } - break; - case WID_VV_CENTER_MAIN_VIEW: {// center main view - const Window *mainwindow = FindWindowById(WC_MAIN_WINDOW, 0); - /* code to allow the main window to 'follow' the vehicle if the ctrl key is pressed */ - if (_ctrl_pressed && mainwindow->viewport->zoom <= ZOOM_LVL_OUT_4X) { - mainwindow->viewport->follow_vehicle = v->index; - } else { - ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos); - } - break; - } - - case WID_VV_GOTO_DEPOT: // goto hangar - DoCommandP(v->tile, v->index | (_ctrl_pressed ? DEPOT_SERVICE : 0U), 0, GetCmdSendToDepot(v)); - break; - case WID_VV_REFIT: // refit - ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID, this); - break; - case WID_VV_SHOW_ORDERS: // show orders - if (_ctrl_pressed) { - ShowTimetableWindow(v); - } else { - ShowOrdersWindow(v); - } - break; - case WID_VV_SHOW_DETAILS: // show details - ShowVehicleDetailsWindow(v); - break; - case WID_VV_CLONE: // clone vehicle - /* Suppress the vehicle GUI when share-cloning. - * There is no point to it except for starting the vehicle. - * For starting the vehicle the player has to open the depot GUI, which is - * most likely already open, but is also visible in the vehicle viewport. */ - DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, - _vehicle_command_translation_table[VCT_CMD_CLONE_VEH][v->type], - _ctrl_pressed ? NULL : CcCloneVehicle); - break; - case WID_VV_TURN_AROUND: // turn around - assert(v->IsGroundVehicle()); - DoCommandP(v->tile, v->index, 0, - _vehicle_command_translation_table[VCT_CMD_TURN_AROUND][v->type]); - break; - case WID_VV_FORCE_PROCEED: // force proceed - assert(v->type == VEH_TRAIN); - DoCommandP(v->tile, v->index, 0, CMD_FORCE_TRAIN_PROCEED | CMD_MSG(STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL)); - break; - } - } - - virtual void OnResize() - { - if (this->viewport != NULL) { - NWidgetViewport *nvp = this->GetWidget(WID_VV_VIEWPORT); - nvp->UpdateViewportCoordinates(this); - } - } - - virtual void OnTick() - { - const Vehicle *v = Vehicle::Get(this->window_number); - bool veh_stopped = v->IsStoppedInDepot(); - - /* Widget WID_VV_GOTO_DEPOT must be hidden if the vehicle is already stopped in depot. - * Widget WID_VV_CLONE_VEH should then be shown, since cloning is allowed only while in depot and stopped. - */ - PlaneSelections plane = veh_stopped ? SEL_DC_CLONE : SEL_DC_GOTO_DEPOT; - NWidgetStacked *nwi = this->GetWidget(WID_VV_SELECT_DEPOT_CLONE); // Selection widget 'send to depot' / 'clone'. - if (nwi->shown_plane + SEL_DC_BASEPLANE != plane) { - this->SelectPlane(plane); - this->SetWidgetDirty(WID_VV_SELECT_DEPOT_CLONE); - } - /* The same system applies to widget WID_VV_REFIT_VEH and VVW_WIDGET_TURN_AROUND.*/ - if (v->IsGroundVehicle()) { - PlaneSelections plane = veh_stopped ? SEL_RT_REFIT : SEL_RT_TURN_AROUND; - NWidgetStacked *nwi = this->GetWidget(WID_VV_SELECT_REFIT_TURN); - if (nwi->shown_plane + SEL_RT_BASEPLANE != plane) { - this->SelectPlane(plane); - this->SetWidgetDirty(WID_VV_SELECT_REFIT_TURN); - } - } - } - - /** - * 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. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - if (data == VIWD_AUTOREPLACE) { - /* Autoreplace replaced the vehicle. - * Nothing to do for this window. */ - return; - } - } - - virtual bool IsNewGRFInspectable() const - { - return ::IsNewGRFInspectable(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number); - } - - virtual void ShowNewGRFInspectWindow() const - { - ::ShowNewGRFInspectWindow(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number); - } -}; - - -/** Shows the vehicle view window of the given vehicle. */ -void ShowVehicleViewWindow(const Vehicle *v) -{ - AllocateWindowDescFront((v->type == VEH_TRAIN) ? &_train_view_desc : &_vehicle_view_desc, v->index); -} - -/** - * Dispatch a "vehicle selected" event if any window waits for it. - * @param v selected vehicle; - * @return did any window accept vehicle selection? - */ -bool VehicleClicked(const Vehicle *v) -{ - assert(v != NULL); - if (!(_thd.place_mode & HT_VEHICLE)) return false; - - v = v->First(); - if (!v->IsPrimaryVehicle()) return false; - - return _thd.GetCallbackWnd()->OnVehicleSelect(v); -} - -void StopGlobalFollowVehicle(const Vehicle *v) -{ - Window *w = FindWindowById(WC_MAIN_WINDOW, 0); - if (w != NULL && w->viewport->follow_vehicle == v->index) { - ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos, true); // lock the main view on the vehicle's last position - w->viewport->follow_vehicle = INVALID_VEHICLE; - } -} - - -/** - * This is the Callback method after the construction attempt of a primary vehicle - * @param result indicates completion (or not) of the operation - * @param tile unused - * @param p1 unused - * @param p2 unused - */ -void CcBuildPrimaryVehicle(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) -{ - if (result.Failed()) return; - - const Vehicle *v = Vehicle::Get(_new_vehicle_id); - ShowVehicleViewWindow(v); -} - -/** - * Get the width of a vehicle (including all parts of the consist) in pixels. - * @param v Vehicle to get the width for. - * @return Width of the vehicle. - */ -int GetVehicleWidth(Vehicle *v, EngineImageType image_type) -{ - int vehicle_width = 0; - - switch (v->type) { - case VEH_TRAIN: - for (const Train *u = Train::From(v); u != NULL; u = u->Next()) { - vehicle_width += u->GetDisplayImageWidth(); - } - break; - - case VEH_ROAD: - for (const RoadVehicle *u = RoadVehicle::From(v); u != NULL; u = u->Next()) { - vehicle_width += u->GetDisplayImageWidth(); - } - break; - - default: - bool rtl = _current_text_dir == TD_RTL; - SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type); - const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); - vehicle_width = UnScaleByZoom(real_sprite->width, ZOOM_LVL_GUI); - - break; - } - - return vehicle_width; -} diff --git a/src/vehicle_gui.h.orig b/src/vehicle_gui.h.orig deleted file mode 100644 index 83e098dcd9..0000000000 --- a/src/vehicle_gui.h.orig +++ /dev/null @@ -1,104 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file vehicle_gui.h Functions related to the vehicle's GUIs. */ - -#ifndef VEHICLE_GUI_H -#define VEHICLE_GUI_H - -#include "window_type.h" -#include "vehicle_type.h" -#include "order_type.h" -#include "station_type.h" -#include "engine_type.h" -#include "company_type.h" - -void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit = false); - -/** The tabs in the train details window */ -enum TrainDetailsWindowTabs { - TDW_TAB_CARGO = 0, ///< Tab with cargo carried by the vehicles - TDW_TAB_INFO, ///< Tab with name and value of the vehicles - TDW_TAB_CAPACITY, ///< Tab with cargo capacity of the vehicles - TDW_TAB_TOTALS, ///< Tab with sum of total cargo transported -}; - -/** Special values for vehicle-related windows for the data parameter of #InvalidateWindowData. */ -enum VehicleInvalidateWindowData { - VIWD_REMOVE_ALL_ORDERS = -1, ///< Removed / replaced all orders (after deleting / sharing). - VIWD_MODIFY_ORDERS = -2, ///< Other order modifications. - VIWD_CONSIST_CHANGED = -3, ///< Vehicle composition was changed. - VIWD_AUTOREPLACE = -4, ///< Autoreplace replaced the vehicle. -}; - -int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number); - -void DrawTrainImage(const Train *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip, VehicleID drag_dest = INVALID_VEHICLE); -void DrawRoadVehImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip = 0); -void DrawShipImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type); -void DrawAircraftImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type); - -void ShowBuildVehicleWindow(TileIndex tile, VehicleType type); - -uint ShowRefitOptionsList(int left, int right, int y, EngineID engine); -StringID GetCargoSubtypeText(const Vehicle *v); - -void ShowVehicleListWindow(const Vehicle *v); -void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type); -void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, StationID station); -void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, TileIndex depot_tile); - -/** - * Get the height of a single vehicle in the GUIs. - * @param type the vehicle type to look at - * @return the height - */ -static inline uint GetVehicleHeight(VehicleType type) -{ - return (type == VEH_TRAIN || type == VEH_ROAD) ? 14 : 24; -} - -int GetVehicleWidth(Vehicle *v, EngineImageType image_type); - -/** Dimensions of a cell in the purchase/depot windows. */ -struct VehicleCellSize { - uint height; ///< Vehicle cell height. - uint extend_left; ///< Extend of the cell to the left. - uint extend_right; ///< Extend of the cell to the right. -}; - -VehicleCellSize GetVehicleImageCellSize(VehicleType type, EngineImageType image_type); - -/** - * Get WindowClass for vehicle list of given vehicle type - * @param vt vehicle type to check - * @return corresponding window class - * @note works only for company buildable vehicle types - */ -static inline WindowClass GetWindowClassForVehicleType(VehicleType vt) -{ - switch (vt) { - default: NOT_REACHED(); - case VEH_TRAIN: return WC_TRAINS_LIST; - case VEH_ROAD: return WC_ROADVEH_LIST; - case VEH_SHIP: return WC_SHIPS_LIST; - case VEH_AIRCRAFT: return WC_AIRCRAFT_LIST; - } -} - -/* Unified window procedure */ -void ShowVehicleViewWindow(const Vehicle *v); -bool VehicleClicked(const Vehicle *v); -void StartStopVehicle(const Vehicle *v, bool texteffect); - -Vehicle *CheckClickOnVehicle(const struct ViewPort *vp, int x, int y); - -void DrawVehicleImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip); - -#endif /* VEHICLE_GUI_H */ diff --git a/src/video/sdl_v.cpp.orig b/src/video/sdl_v.cpp.orig deleted file mode 100644 index 3d80153229..0000000000 --- a/src/video/sdl_v.cpp.orig +++ /dev/null @@ -1,868 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file sdl_v.cpp Implementation of the SDL video driver. */ - -#ifdef WITH_SDL - -#include "../stdafx.h" -#include "../openttd.h" -#include "../gfx_func.h" -#include "../sdl.h" -#include "../rev.h" -#include "../blitter/factory.hpp" -#include "../network/network.h" -#include "../thread/thread.h" -#include "../progress.h" -#include "../core/random_func.hpp" -#include "../core/math_func.hpp" -#include "../fileio_func.h" -#include "sdl_v.h" -#include -#ifdef __ANDROID__ -#include -#endif - -static FVideoDriver_SDL iFVideoDriver_SDL; - -static SDL_Surface *_sdl_screen; -static SDL_Surface *_sdl_realscreen; -static bool _all_modes; - -/** Whether the drawing is/may be done in a separate thread. */ -static bool _draw_threaded; -/** Thread used to 'draw' to the screen, i.e. push data to the screen. */ -static ThreadObject *_draw_thread = NULL; -/** Mutex to keep the access to the shared memory controlled. */ -static ThreadMutex *_draw_mutex = NULL; -/** Should we keep continue drawing? */ -static volatile bool _draw_continue; -static Palette _local_palette; - -#define MAX_DIRTY_RECTS 100 -static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS]; -static int _num_dirty_rects; -static int _use_hwpalette; -static int _requested_hwpalette; /* Did we request a HWPALETTE for the current video mode? */ - -void VideoDriver_SDL::MakeDirty(int left, int top, int width, int height) -{ - if (_num_dirty_rects < MAX_DIRTY_RECTS) { - _dirty_rects[_num_dirty_rects].x = left; - _dirty_rects[_num_dirty_rects].y = top; - _dirty_rects[_num_dirty_rects].w = width; - _dirty_rects[_num_dirty_rects].h = height; - } - _num_dirty_rects++; -} - -static void UpdatePalette(bool init = false) -{ - SDL_Color pal[256]; - - for (int i = 0; i != _local_palette.count_dirty; i++) { - pal[i].r = _local_palette.palette[_local_palette.first_dirty + i].r; - pal[i].g = _local_palette.palette[_local_palette.first_dirty + i].g; - pal[i].b = _local_palette.palette[_local_palette.first_dirty + i].b; - pal[i].unused = 0; - } - - SDL_CALL SDL_SetColors(_sdl_screen, pal, _local_palette.first_dirty, _local_palette.count_dirty); - - if (_sdl_screen != _sdl_realscreen && init) { - /* When using a shadow surface, also set our palette on the real screen. This lets SDL - * allocate as much colors (or approximations) as - * possible, instead of using only the default SDL - * palette. This allows us to get more colors exactly - * right and might allow using better approximations for - * other colors. - * - * Note that colors allocations are tried in-order, so - * this favors colors further up into the palette. Also - * note that if two colors from the same animation - * sequence are approximated using the same color, that - * animation will stop working. - * - * Since changing the system palette causes the colours - * to change right away, and allocations might - * drastically change, we can't use this for animation, - * since that could cause weird coloring between the - * palette change and the blitting below, so we only set - * the real palette during initialisation. - */ - SDL_CALL SDL_SetColors(_sdl_realscreen, pal, _local_palette.first_dirty, _local_palette.count_dirty); - } - - if (_sdl_screen != _sdl_realscreen && !init) { - /* We're not using real hardware palette, but are letting SDL - * approximate the palette during shadow -> screen copy. To - * change the palette, we need to recopy the entire screen. - * - * Note that this operation can slow down the rendering - * considerably, especially since changing the shadow - * palette will need the next blit to re-detect the - * best mapping of shadow palette colors to real palette - * colors from scratch. - */ - SDL_CALL SDL_BlitSurface(_sdl_screen, NULL, _sdl_realscreen, NULL); - SDL_CALL SDL_UpdateRect(_sdl_realscreen, 0, 0, 0, 0); - } -} - -static void InitPalette() -{ - _local_palette = _cur_palette; - _local_palette.first_dirty = 0; - _local_palette.count_dirty = 256; - UpdatePalette(true); -} - -static void CheckPaletteAnim() -{ - if (_cur_palette.count_dirty != 0) { - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - - switch (blitter->UsePaletteAnimation()) { - case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: - UpdatePalette(); - break; - - case Blitter::PALETTE_ANIMATION_BLITTER: - blitter->PaletteAnimate(_local_palette); - break; - - case Blitter::PALETTE_ANIMATION_NONE: - break; - - default: - NOT_REACHED(); - } - _cur_palette.count_dirty = 0; - } -} - -static void DrawSurfaceToScreen() -{ - int n = _num_dirty_rects; - if (n == 0) return; - - _num_dirty_rects = 0; - if (n > MAX_DIRTY_RECTS) { - if (_sdl_screen != _sdl_realscreen) { - SDL_CALL SDL_BlitSurface(_sdl_screen, NULL, _sdl_realscreen, NULL); - } - SDL_CALL SDL_UpdateRect(_sdl_realscreen, 0, 0, 0, 0); - } else { - if (_sdl_screen != _sdl_realscreen) { - for (int i = 0; i < n; i++) { - SDL_CALL SDL_BlitSurface(_sdl_screen, &_dirty_rects[i], _sdl_realscreen, &_dirty_rects[i]); - } - } - SDL_CALL SDL_UpdateRects(_sdl_realscreen, n, _dirty_rects); - } -} - -static void DrawSurfaceToScreenThread(void *) -{ - /* First tell the main thread we're started */ - _draw_mutex->BeginCritical(); - _draw_mutex->SendSignal(); - - /* Now wait for the first thing to draw! */ - _draw_mutex->WaitForSignal(); - - while (_draw_continue) { - CheckPaletteAnim(); - /* Then just draw and wait till we stop */ - DrawSurfaceToScreen(); - _draw_mutex->WaitForSignal(); - } - - _draw_mutex->EndCritical(); - _draw_thread->Exit(); -} - -static const Dimension _default_resolutions[] = { - { 640, 480}, - { 800, 600}, - {1024, 768}, - {1152, 864}, - {1280, 800}, - {1280, 960}, - {1280, 1024}, - {1400, 1050}, - {1600, 1200}, - {1680, 1050}, - {1920, 1200} -}; - -static void GetVideoModes() -{ - SDL_Rect **modes = SDL_CALL SDL_ListModes(NULL, SDL_SWSURFACE | SDL_FULLSCREEN); - if (modes == NULL) usererror("sdl: no modes available"); - - _all_modes = (SDL_CALL SDL_ListModes(NULL, SDL_SWSURFACE | (_fullscreen ? SDL_FULLSCREEN : 0)) == (void*)-1); - if (modes == (void*)-1) { - int n = 0; - for (uint i = 0; i < lengthof(_default_resolutions); i++) { - if (SDL_CALL SDL_VideoModeOK(_default_resolutions[i].width, _default_resolutions[i].height, 8, SDL_FULLSCREEN) != 0) { - _resolutions[n] = _default_resolutions[i]; - if (++n == lengthof(_resolutions)) break; - } - } - _num_resolutions = n; - } else { - int n = 0; - for (int i = 0; modes[i]; i++) { - uint w = modes[i]->w; - uint h = modes[i]->h; - int j; - for (j = 0; j < n; j++) { - if (_resolutions[j].width == w && _resolutions[j].height == h) break; - } - - if (j == n) { - _resolutions[j].width = w; - _resolutions[j].height = h; - if (++n == lengthof(_resolutions)) break; - } - } - _num_resolutions = n; - SortResolutions(_num_resolutions); - } -} - -static void GetAvailableVideoMode(uint *w, uint *h) -{ - /* All modes available? */ - if (_all_modes || _num_resolutions == 0) return; - - /* Is the wanted mode among the available modes? */ - for (int i = 0; i != _num_resolutions; i++) { - if (*w == _resolutions[i].width && *h == _resolutions[i].height) return; - } - - /* Use the closest possible resolution */ - int best = 0; - uint delta = Delta(_resolutions[0].width, *w) * Delta(_resolutions[0].height, *h); - for (int i = 1; i != _num_resolutions; ++i) { - uint newdelta = Delta(_resolutions[i].width, *w) * Delta(_resolutions[i].height, *h); - if (newdelta < delta) { - best = i; - delta = newdelta; - } - } - *w = _resolutions[best].width; - *h = _resolutions[best].height; -} - -#ifdef WIN32 -/* Let's redefine the LoadBMP macro with because we are dynamically - * loading SDL and need to 'SDL_CALL' all functions */ -#undef SDL_LoadBMP -#define SDL_LoadBMP(file) SDL_LoadBMP_RW(SDL_CALL SDL_RWFromFile(file, "rb"), 1) -#endif - -bool VideoDriver_SDL::CreateMainSurface(uint w, uint h) -{ - SDL_Surface *newscreen, *icon; - char caption[50]; - int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); - bool want_hwpalette; - - GetAvailableVideoMode(&w, &h); - - DEBUG(driver, 1, "SDL: using mode %ux%ux%d", w, h, bpp); - - if (bpp == 0) usererror("Can't use a blitter that blits 0 bpp for normal visuals"); - - char icon_path[MAX_PATH]; - if (FioFindFullPath(icon_path, lengthof(icon_path), BASESET_DIR, "openttd.32.bmp") != NULL) { - /* Give the application an icon */ - icon = SDL_CALL SDL_LoadBMP(icon_path); - if (icon != NULL) { - /* Get the colourkey, which will be magenta */ - uint32 rgbmap = SDL_CALL SDL_MapRGB(icon->format, 255, 0, 255); - - SDL_CALL SDL_SetColorKey(icon, SDL_SRCCOLORKEY, rgbmap); - SDL_CALL SDL_WM_SetIcon(icon, NULL); - SDL_CALL SDL_FreeSurface(icon); - } - } - - if (_use_hwpalette == 2) { - /* Default is to autodetect when to use SDL_HWPALETTE. - * In this case, SDL_HWPALETTE is only used for 8bpp - * blitters in fullscreen. - * - * When using an 8bpp blitter on a 8bpp system in - * windowed mode with SDL_HWPALETTE, OpenTTD will claim - * the system palette, making all other applications - * get the wrong colours. In this case, we're better of - * trying to approximate the colors we need using system - * colors, using a shadow surface (see below). - * - * On a 32bpp system, SDL_HWPALETTE is ignored, so it - * doesn't matter what we do. - * - * When using a 32bpp blitter on a 8bpp system, setting - * SDL_HWPALETTE messes up rendering (at least on X11), - * so we don't do that. In this case, SDL takes care of - * color approximation using its own shadow surface - * (which we can't force in 8bpp on 8bpp mode, - * unfortunately). - */ - want_hwpalette = (bpp == 8 && _fullscreen); - } else { - /* User specified a value manually */ - want_hwpalette = _use_hwpalette; - } - - if (want_hwpalette) DEBUG(driver, 1, "SDL: requesting hardware palete"); - - /* Free any previously allocated shadow surface */ - if (_sdl_screen != NULL && _sdl_screen != _sdl_realscreen) SDL_CALL SDL_FreeSurface(_sdl_screen); - - if (_sdl_realscreen != NULL) { - if (_requested_hwpalette != want_hwpalette) { - /* SDL (at least the X11 driver), reuses the - * same window and palette settings when the bpp - * (and a few flags) are the same. Since we need - * to hwpalette value to change (in particular - * when switching between fullscreen and - * windowed), we restart the entire video - * subsystem to force creating a new window. - */ - DEBUG(driver, 0, "SDL: Restarting SDL video subsystem, to force hwpalette change"); - SDL_CALL SDL_QuitSubSystem(SDL_INIT_VIDEO); - SDL_CALL SDL_InitSubSystem(SDL_INIT_VIDEO); - ClaimMousePointer(); - SetupKeyboard(); - } - } - /* Remember if we wanted a hwpalette. We can't reliably query - * SDL for the SDL_HWPALETTE flag, since it might get set even - * though we didn't ask for it (when SDL creates a shadow - * surface, for example). */ - _requested_hwpalette = want_hwpalette; - -#ifdef __ANDROID__ - SDL_Rect r; - r.h = SDL_ListModes(NULL, 0)[0]->h / 10; - r.w = r.h; - r.x = SDL_ListModes(NULL, 0)[0]->w - r.w; - r.y = SDL_ListModes(NULL, 0)[0]->h - r.h; - SDL_ANDROID_SetScreenKeyboardButtonPos(SDL_ANDROID_SCREENKEYBOARD_BUTTON_TEXT, &r); -#endif - - /* DO NOT CHANGE TO HWSURFACE, IT DOES NOT WORK */ - newscreen = SDL_CALL SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE | (want_hwpalette ? SDL_HWPALETTE : 0) | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE)); - if (newscreen == NULL) { - DEBUG(driver, 0, "SDL: Couldn't allocate a window to draw on"); - return false; - } - _sdl_realscreen = newscreen; - - if (bpp == 8 && (_sdl_realscreen->flags & SDL_HWPALETTE) != SDL_HWPALETTE) { - /* Using an 8bpp blitter, if we didn't get a hardware - * palette (most likely because we didn't request one, - * see above), we'll have to set up a shadow surface to - * render on. - * - * Our palette will be applied to this shadow surface, - * while the real screen surface will use the shared - * system palette (which will partly contain our colors, - * but most likely will not have enough free color cells - * for all of our colors). SDL can use these two - * palettes at blit time to approximate colors used in - * the shadow surface using system colors automatically. - * - * Note that when using an 8bpp blitter on a 32bpp - * system, SDL will create an internal shadow surface. - * This shadow surface will have SDL_HWPALLETE set, so - * we won't create a second shadow surface in this case. - */ - DEBUG(driver, 1, "SDL: using shadow surface"); - newscreen = SDL_CALL SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, bpp, 0, 0, 0, 0); - if (newscreen == NULL) { - DEBUG(driver, 0, "SDL: Couldn't allocate a shadow surface to draw on"); - return false; - } - } - - /* Delay drawing for this cycle; the next cycle will redraw the whole screen */ - _num_dirty_rects = 0; - - _screen.width = newscreen->w; - _screen.height = newscreen->h; - _screen.pitch = newscreen->pitch / (bpp / 8); - _screen.dst_ptr = newscreen->pixels; - _sdl_screen = newscreen; - - /* When in full screen, we will always have the mouse cursor - * within the window, even though SDL does not give us the - * appropriate event to know this. */ - if (_fullscreen) _cursor.in_window = true; - - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - blitter->PostResize(); - - InitPalette(); - switch (blitter->UsePaletteAnimation()) { - case Blitter::PALETTE_ANIMATION_NONE: - case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: - UpdatePalette(); - break; - - case Blitter::PALETTE_ANIMATION_BLITTER: - if (_video_driver != NULL) blitter->PaletteAnimate(_local_palette); - break; - - default: - NOT_REACHED(); - } - - snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision); - SDL_CALL SDL_WM_SetCaption(caption, caption); - - GameSizeChanged(); - - return true; -} - -bool VideoDriver_SDL::ClaimMousePointer() -{ - SDL_CALL SDL_ShowCursor(0); - return true; -} - -struct VkMapping { -#if SDL_VERSION_ATLEAST(1, 3, 0) - SDL_Keycode vk_from; -#else - uint16 vk_from; -#endif - byte vk_count; - byte map_to; -}; - -#define AS(x, z) {x, 0, z} -#define AM(x, y, z, w) {x, (byte)(y - x), z} - -static const VkMapping _vk_mapping[] = { - /* Pageup stuff + up/down */ - AM(SDLK_PAGEUP, SDLK_PAGEDOWN, WKC_PAGEUP, WKC_PAGEDOWN), - AS(SDLK_UP, WKC_UP), - AS(SDLK_DOWN, WKC_DOWN), - AS(SDLK_LEFT, WKC_LEFT), - AS(SDLK_RIGHT, WKC_RIGHT), - - AS(SDLK_HOME, WKC_HOME), - AS(SDLK_END, WKC_END), - - AS(SDLK_INSERT, WKC_INSERT), - AS(SDLK_DELETE, WKC_DELETE), - - /* Map letters & digits */ - AM(SDLK_a, SDLK_z, 'A', 'Z'), - AM(SDLK_0, SDLK_9, '0', '9'), - - AS(SDLK_ESCAPE, WKC_ESC), - AS(SDLK_PAUSE, WKC_PAUSE), - AS(SDLK_BACKSPACE, WKC_BACKSPACE), - - AS(SDLK_SPACE, WKC_SPACE), - AS(SDLK_RETURN, WKC_RETURN), - AS(SDLK_TAB, WKC_TAB), - - /* Function keys */ - AM(SDLK_F1, SDLK_F12, WKC_F1, WKC_F12), - - /* Numeric part. */ - AM(SDLK_KP0, SDLK_KP9, '0', '9'), - AS(SDLK_KP_DIVIDE, WKC_NUM_DIV), - AS(SDLK_KP_MULTIPLY, WKC_NUM_MUL), - AS(SDLK_KP_MINUS, WKC_NUM_MINUS), - AS(SDLK_KP_PLUS, WKC_NUM_PLUS), - AS(SDLK_KP_ENTER, WKC_NUM_ENTER), - AS(SDLK_KP_PERIOD, WKC_NUM_DECIMAL), - - /* Other non-letter keys */ - AS(SDLK_SLASH, WKC_SLASH), - AS(SDLK_SEMICOLON, WKC_SEMICOLON), - AS(SDLK_EQUALS, WKC_EQUALS), - AS(SDLK_LEFTBRACKET, WKC_L_BRACKET), - AS(SDLK_BACKSLASH, WKC_BACKSLASH), - AS(SDLK_RIGHTBRACKET, WKC_R_BRACKET), - - AS(SDLK_QUOTE, WKC_SINGLEQUOTE), - AS(SDLK_COMMA, WKC_COMMA), - AS(SDLK_MINUS, WKC_MINUS), - AS(SDLK_PERIOD, WKC_PERIOD) -}; - -static uint ConvertSdlKeyIntoMy(SDL_keysym *sym, WChar *character) -{ - const VkMapping *map; - uint key = 0; - - for (map = _vk_mapping; map != endof(_vk_mapping); ++map) { - if ((uint)(sym->sym - map->vk_from) <= map->vk_count) { - key = sym->sym - map->vk_from + map->map_to; - break; - } - } - - /* check scancode for BACKQUOTE key, because we want the key left of "1", not anything else (on non-US keyboards) */ -#if defined(WIN32) || defined(__OS2__) - if (sym->scancode == 41) key = WKC_BACKQUOTE; -#elif defined(__APPLE__) - if (sym->scancode == 10) key = WKC_BACKQUOTE; -#elif defined(__MORPHOS__) - if (sym->scancode == 0) key = WKC_BACKQUOTE; // yes, that key is code '0' under MorphOS :) -#elif defined(__BEOS__) - if (sym->scancode == 17) key = WKC_BACKQUOTE; -#elif defined(__SVR4) && defined(__sun) - if (sym->scancode == 60) key = WKC_BACKQUOTE; - if (sym->scancode == 49) key = WKC_BACKSPACE; -#elif defined(__sgi__) - if (sym->scancode == 22) key = WKC_BACKQUOTE; -#elif defined(__ANDROID__) - if (sym->scancode == SDLK_BACKQUOTE) key = WKC_BACKQUOTE; -#else - if (sym->scancode == 49) key = WKC_BACKQUOTE; -#endif - - /* META are the command keys on mac */ - if (sym->mod & KMOD_META) key |= WKC_META; - if (sym->mod & KMOD_SHIFT) key |= WKC_SHIFT; - if (sym->mod & KMOD_CTRL) key |= WKC_CTRL; - if (sym->mod & KMOD_ALT) key |= WKC_ALT; - - *character = sym->unicode; - return key; -} - -int VideoDriver_SDL::PollEvent() -{ - SDL_Event ev; - - if (!SDL_CALL SDL_PollEvent(&ev)) return -2; - - switch (ev.type) { - case SDL_MOUSEMOTION: - if (_cursor.fix_at) { - int dx = ev.motion.x - _cursor.pos.x; - int dy = ev.motion.y - _cursor.pos.y; - if (dx != 0 || dy != 0) { - _cursor.delta.x = dx; - _cursor.delta.y = dy; - SDL_CALL SDL_WarpMouse(_cursor.pos.x, _cursor.pos.y); - } - } else { - _cursor.delta.x = ev.motion.x - _cursor.pos.x; - _cursor.delta.y = ev.motion.y - _cursor.pos.y; - _cursor.pos.x = ev.motion.x; - _cursor.pos.y = ev.motion.y; - _cursor.dirty = true; - } - HandleMouseEvents(); - break; - - case SDL_MOUSEBUTTONDOWN: - if (_rightclick_emulate && SDL_CALL SDL_GetModState() & KMOD_CTRL) { - ev.button.button = SDL_BUTTON_RIGHT; - } - - switch (ev.button.button) { - case SDL_BUTTON_LEFT: - _left_button_down = true; - break; - - case SDL_BUTTON_RIGHT: - _right_button_down = true; - _right_button_clicked = true; - break; - - case SDL_BUTTON_WHEELUP: _cursor.wheel--; break; - case SDL_BUTTON_WHEELDOWN: _cursor.wheel++; break; - - default: break; - } - HandleMouseEvents(); - break; - - case SDL_MOUSEBUTTONUP: - if (_rightclick_emulate) { - _right_button_down = false; - _left_button_down = false; - _left_button_clicked = false; - } else if (ev.button.button == SDL_BUTTON_LEFT) { - _left_button_down = false; - _left_button_clicked = false; - } else if (ev.button.button == SDL_BUTTON_RIGHT) { - _right_button_down = false; - } - HandleMouseEvents(); - break; -#ifndef __ANDROID__ - case SDL_ACTIVEEVENT: - if (!(ev.active.state & SDL_APPMOUSEFOCUS)) break; - - if (ev.active.gain) { // mouse entered the window, enable cursor - _cursor.in_window = true; - } else { - UndrawMouseCursor(); // mouse left the window, undraw cursor - _cursor.in_window = false; - } - break; -#endif /* not __ANDROID__ */ - case SDL_QUIT: - HandleExitGameRequest(); - break; - - case SDL_KEYDOWN: // Toggle full-screen on ALT + ENTER/F - if ((ev.key.keysym.mod & (KMOD_ALT | KMOD_META)) && - (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_f)) { - ToggleFullScreen(!_fullscreen); - } else { - WChar character; - uint keycode = ConvertSdlKeyIntoMy(&ev.key.keysym, &character); - HandleKeypress(keycode, character); - } - break; -#ifndef __ANDROID__ - case SDL_VIDEORESIZE: { - int w = max(ev.resize.w, 64); - int h = max(ev.resize.h, 64); - CreateMainSurface(w, h); - break; - } -#endif /* not __ANDROID__ */ - case SDL_VIDEOEXPOSE: { - /* Force a redraw of the entire screen. Note - * that SDL 1.2 seems to do this automatically - * in most cases, but 1.3 / 2.0 does not. */ - _num_dirty_rects = MAX_DIRTY_RECTS + 1; - break; - } - } - return -1; -} - -const char *VideoDriver_SDL::Start(const char * const *parm) -{ - char buf[30]; - _use_hwpalette = GetDriverParamInt(parm, "hw_palette", 2); - - const char *s = SdlOpen(SDL_INIT_VIDEO); - if (s != NULL) return s; - - GetVideoModes(); - if (!CreateMainSurface(_cur_resolution.width, _cur_resolution.height)) { - return SDL_CALL SDL_GetError(); - } - - SDL_CALL SDL_VideoDriverName(buf, sizeof buf); - DEBUG(driver, 1, "SDL: using driver '%s'", buf); - - MarkWholeScreenDirty(); - SetupKeyboard(); - - _draw_threaded = GetDriverParam(parm, "no_threads") == NULL && GetDriverParam(parm, "no_thread") == NULL; -#ifdef __ANDROID__ - _draw_threaded = false; -#endif - - return NULL; -} - -void VideoDriver_SDL::SetupKeyboard() -{ - SDL_CALL SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); - SDL_CALL SDL_EnableUNICODE(1); -} - -void VideoDriver_SDL::Stop() -{ - SdlClose(SDL_INIT_VIDEO); -} - -void VideoDriver_SDL::MainLoop() -{ - uint32 cur_ticks = SDL_CALL SDL_GetTicks(); - uint32 last_cur_ticks = cur_ticks; - uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; - uint32 mod; - int numkeys; - Uint8 *keys; - - CheckPaletteAnim(); - - if (_draw_threaded) { - /* Initialise the mutex first, because that's the thing we *need* - * directly in the newly created thread. */ - _draw_mutex = ThreadMutex::New(); - if (_draw_mutex == NULL) { - _draw_threaded = false; - } else { - _draw_mutex->BeginCritical(); - _draw_continue = true; - - _draw_threaded = ThreadObject::New(&DrawSurfaceToScreenThread, NULL, &_draw_thread); - - /* Free the mutex if we won't be able to use it. */ - if (!_draw_threaded) { - _draw_mutex->EndCritical(); - delete _draw_mutex; - _draw_mutex = NULL; - } else { - /* Wait till the draw mutex has started itself. */ - _draw_mutex->WaitForSignal(); - } - } - } - - DEBUG(driver, 1, "SDL: using %sthreads", _draw_threaded ? "" : "no "); - - for (;;) { - uint32 prev_cur_ticks = cur_ticks; // to check for wrapping - InteractiveRandom(); // randomness - - while (PollEvent() == -1) {} - if (_exit_game) break; - - mod = SDL_CALL SDL_GetModState(); -#if SDL_VERSION_ATLEAST(1, 3, 0) - keys = SDL_CALL SDL_GetKeyboardState(&numkeys); -#else - keys = SDL_CALL SDL_GetKeyState(&numkeys); -#endif -#if defined(_DEBUG) - if (_shift_pressed) -#else - /* Speedup when pressing tab, except when using ALT+TAB - * to switch to another application */ -#if SDL_VERSION_ATLEAST(1, 3, 0) - if (keys[SDL_SCANCODE_TAB] && (mod & KMOD_ALT) == 0) -#else - if (keys[SDLK_TAB] && (mod & KMOD_ALT) == 0) -#endif /* SDL_VERSION_ATLEAST(1, 3, 0) */ -#endif /* defined(_DEBUG) */ - { - if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2; - } else if (_fast_forward & 2) { - _fast_forward = 0; - } - - cur_ticks = SDL_CALL SDL_GetTicks(); - if (cur_ticks >= next_tick || (_fast_forward && !_pause_mode) || cur_ticks < prev_cur_ticks) { - _realtime_tick += cur_ticks - last_cur_ticks; - last_cur_ticks = cur_ticks; - next_tick = cur_ticks + MILLISECONDS_PER_TICK; - - bool old_ctrl_pressed = _ctrl_pressed; - - _ctrl_pressed = !!(mod & KMOD_CTRL); - _shift_pressed = !!(mod & KMOD_SHIFT); - - /* determine which directional keys are down */ - _dirkeys = -#if SDL_VERSION_ATLEAST(1, 3, 0) - (keys[SDL_SCANCODE_LEFT] ? 1 : 0) | - (keys[SDL_SCANCODE_UP] ? 2 : 0) | - (keys[SDL_SCANCODE_RIGHT] ? 4 : 0) | - (keys[SDL_SCANCODE_DOWN] ? 8 : 0); -#else - (keys[SDLK_LEFT] ? 1 : 0) | - (keys[SDLK_UP] ? 2 : 0) | - (keys[SDLK_RIGHT] ? 4 : 0) | - (keys[SDLK_DOWN] ? 8 : 0); -#endif - if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged(); - - /* The gameloop is the part that can run asynchronously. The rest - * except sleeping can't. */ - if (_draw_mutex != NULL) _draw_mutex->EndCritical(); - - GameLoop(); - - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(); - - UpdateWindows(); - _local_palette = _cur_palette; - } else { - /* Release the thread while sleeping */ - if (_draw_mutex != NULL) _draw_mutex->EndCritical(); - CSleep(1); - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(); - - NetworkDrawChatMessage(); - DrawMouseCursor(); - } - - /* End of the critical part. */ - if (_draw_mutex != NULL && !HasModalProgress()) { - _draw_mutex->SendSignal(); - } else { - /* Oh, we didn't have threads, then just draw unthreaded */ - CheckPaletteAnim(); - DrawSurfaceToScreen(); - } - } - - if (_draw_mutex != NULL) { - _draw_continue = false; - /* Sending signal if there is no thread blocked - * is very valid and results in noop */ - _draw_mutex->SendSignal(); - _draw_mutex->EndCritical(); - _draw_thread->Join(); - - delete _draw_mutex; - delete _draw_thread; - - _draw_mutex = NULL; - _draw_thread = NULL; - } -} - -bool VideoDriver_SDL::ChangeResolution(int w, int h) -{ - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); - bool ret = CreateMainSurface(w, h); - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); - return ret; -} - -bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen) -{ - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); - _fullscreen = fullscreen; - GetVideoModes(); // get the list of available video modes - bool ret = _num_resolutions != 0 && CreateMainSurface(_cur_resolution.width, _cur_resolution.height); - - if (!ret) { - /* switching resolution failed, put back full_screen to original status */ - _fullscreen ^= true; - } - - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); - return ret; -} - -bool VideoDriver_SDL::AfterBlitterChange() -{ - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); - bool ret = CreateMainSurface(_screen.width, _screen.height); - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); - return ret; -} - -#endif /* WITH_SDL */ diff --git a/src/viewport.cpp.orig b/src/viewport.cpp.orig deleted file mode 100644 index f6585d4779..0000000000 --- a/src/viewport.cpp.orig +++ /dev/null @@ -1,3012 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** - * @file viewport.cpp Handling of all viewports. - * - * \verbatim - * The in-game coordinate system looks like this * - * * - * ^ Z * - * | * - * | * - * | * - * | * - * / \ * - * / \ * - * / \ * - * / \ * - * X < > Y * - * \endverbatim - */ - -#include "stdafx.h" -#include "landscape.h" -#include "viewport_func.h" -#include "station_base.h" -#include "waypoint_base.h" -#include "town.h" -#include "signs_base.h" -#include "signs_func.h" -#include "vehicle_base.h" -#include "vehicle_gui.h" -#include "blitter/factory.hpp" -#include "strings_func.h" -#include "zoom_func.h" -#include "vehicle_func.h" -#include "company_func.h" -#include "waypoint_func.h" -#include "window_func.h" -#include "tilehighlight_func.h" -#include "window_gui.h" -#include "linkgraph/linkgraph_gui.h" -#include "viewport_sprite_sorter.h" - -#include "table/strings.h" -#include "table/palettes.h" - -Point _tile_fract_coords; - -struct StringSpriteToDraw { - StringID string; - Colours colour; - int32 x; - int32 y; - uint64 params[2]; - uint16 width; -}; - -struct TileSpriteToDraw { - SpriteID image; - PaletteID pal; - const SubSprite *sub; ///< only draw a rectangular part of the sprite - int32 x; ///< screen X coordinate of sprite - int32 y; ///< screen Y coordinate of sprite -}; - -struct ChildScreenSpriteToDraw { - SpriteID image; - PaletteID pal; - const SubSprite *sub; ///< only draw a rectangular part of the sprite - int32 x; - int32 y; - int next; ///< next child to draw (-1 at the end) -}; - -/** Enumeration of multi-part foundations */ -enum FoundationPart { - FOUNDATION_PART_NONE = 0xFF, ///< Neither foundation nor groundsprite drawn yet. - FOUNDATION_PART_NORMAL = 0, ///< First part (normal foundation or no foundation) - FOUNDATION_PART_HALFTILE = 1, ///< Second part (halftile foundation) - FOUNDATION_PART_END -}; - -/** - * Mode of "sprite combining" - * @see StartSpriteCombine - */ -enum SpriteCombineMode { - SPRITE_COMBINE_NONE, ///< Every #AddSortableSpriteToDraw start its own bounding box - SPRITE_COMBINE_PENDING, ///< %Sprite combining will start with the next unclipped sprite. - SPRITE_COMBINE_ACTIVE, ///< %Sprite combining is active. #AddSortableSpriteToDraw outputs child sprites. -}; - -typedef SmallVector TileSpriteToDrawVector; -typedef SmallVector StringSpriteToDrawVector; -typedef SmallVector ParentSpriteToDrawVector; -typedef SmallVector ChildScreenSpriteToDrawVector; - -/** Data structure storing rendering information */ -struct ViewportDrawer { - DrawPixelInfo dpi; - - StringSpriteToDrawVector string_sprites_to_draw; - TileSpriteToDrawVector tile_sprites_to_draw; - ParentSpriteToDrawVector parent_sprites_to_draw; - ParentSpriteToSortVector parent_sprites_to_sort; ///< Parent sprite pointer array used for sorting - ChildScreenSpriteToDrawVector child_screen_sprites_to_draw; - - int *last_child; - - SpriteCombineMode combine_sprites; ///< Current mode of "sprite combining". @see StartSpriteCombine - - int foundation[FOUNDATION_PART_END]; ///< Foundation sprites (index into parent_sprites_to_draw). - FoundationPart foundation_part; ///< Currently active foundation for ground sprite drawing. - int *last_foundation_child[FOUNDATION_PART_END]; ///< Tail of ChildSprite list of the foundations. (index into child_screen_sprites_to_draw) - Point foundation_offset[FOUNDATION_PART_END]; ///< Pixel offset for ground sprites on the foundations. -}; - -static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom); - -static ViewportDrawer _vd; - -TileHighlightData _thd; -static TileInfo *_cur_ti; -bool _draw_bounding_boxes = false; -bool _draw_dirty_blocks = false; -uint _dirty_block_colour = 0; -static VpSpriteSorter _vp_sprite_sorter = NULL; - -static Point MapXYZToViewport(const ViewPort *vp, int x, int y, int z) -{ - Point p = RemapCoords(x, y, z); - p.x -= vp->virtual_width / 2; - p.y -= vp->virtual_height / 2; - return p; -} - -void DeleteWindowViewport(Window *w) -{ - if (w->viewport == NULL) return; - - delete w->viewport->overlay; - free(w->viewport); - w->viewport = NULL; -} - -/** - * Initialize viewport of the window for use. - * @param w Window to use/display the viewport in - * @param x Offset of left edge of viewport with respect to left edge window \a w - * @param y Offset of top edge of viewport with respect to top edge window \a w - * @param width Width of the viewport - * @param height Height of the viewport - * @param follow_flags Flags controlling the viewport. - * - If bit 31 is set, the lower 20 bits are the vehicle that the viewport should follow. - * - If bit 31 is clear, it is a #TileIndex. - * @param zoom Zoomlevel to display - */ -void InitializeWindowViewport(Window *w, int x, int y, - int width, int height, uint32 follow_flags, ZoomLevel zoom) -{ - assert(w->viewport == NULL); - - ViewportData *vp = CallocT(1); - - vp->left = x + w->left; - vp->top = y + w->top; - vp->width = width; - vp->height = height; - - vp->zoom = static_cast(Clamp(zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max)); - - vp->virtual_width = ScaleByZoom(width, zoom); - vp->virtual_height = ScaleByZoom(height, zoom); - - Point pt; - - if (follow_flags & 0x80000000) { - const Vehicle *veh; - - vp->follow_vehicle = (VehicleID)(follow_flags & 0xFFFFF); - veh = Vehicle::Get(vp->follow_vehicle); - pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos); - } else { - uint x = TileX(follow_flags) * TILE_SIZE; - uint y = TileY(follow_flags) * TILE_SIZE; - - vp->follow_vehicle = INVALID_VEHICLE; - pt = MapXYZToViewport(vp, x, y, GetSlopePixelZ(x, y)); - } - - vp->scrollpos_x = pt.x; - vp->scrollpos_y = pt.y; - vp->dest_scrollpos_x = pt.x; - vp->dest_scrollpos_y = pt.y; - - vp->overlay = NULL; - - w->viewport = vp; - vp->virtual_left = 0;//pt.x; - vp->virtual_top = 0;//pt.y; -} - -static Point _vp_move_offs; - -static void DoSetViewportPosition(const Window *w, int left, int top, int width, int height) -{ - FOR_ALL_WINDOWS_FROM_BACK_FROM(w, w) { - if (left + width > w->left && - w->left + w->width > left && - top + height > w->top && - w->top + w->height > top) { - - if (left < w->left) { - DoSetViewportPosition(w, left, top, w->left - left, height); - DoSetViewportPosition(w, left + (w->left - left), top, width - (w->left - left), height); - return; - } - - if (left + width > w->left + w->width) { - DoSetViewportPosition(w, left, top, (w->left + w->width - left), height); - DoSetViewportPosition(w, left + (w->left + w->width - left), top, width - (w->left + w->width - left), height); - return; - } - - if (top < w->top) { - DoSetViewportPosition(w, left, top, width, (w->top - top)); - DoSetViewportPosition(w, left, top + (w->top - top), width, height - (w->top - top)); - return; - } - - if (top + height > w->top + w->height) { - DoSetViewportPosition(w, left, top, width, (w->top + w->height - top)); - DoSetViewportPosition(w, left, top + (w->top + w->height - top), width, height - (w->top + w->height - top)); - return; - } - - return; - } - } - - { - int xo = _vp_move_offs.x; - int yo = _vp_move_offs.y; - - if (abs(xo) >= width || abs(yo) >= height) { - /* fully_outside */ - RedrawScreenRect(left, top, left + width, top + height); - return; - } - - GfxScroll(left, top, width, height, xo, yo); - - if (xo > 0) { - RedrawScreenRect(left, top, xo + left, top + height); - left += xo; - width -= xo; - } else if (xo < 0) { - RedrawScreenRect(left + width + xo, top, left + width, top + height); - width += xo; - } - - if (yo > 0) { - RedrawScreenRect(left, top, width + left, top + yo); - } else if (yo < 0) { - RedrawScreenRect(left, top + height + yo, width + left, top + height); - } - } -} - -static void SetViewportPosition(Window *w, int x, int y) -{ - ViewPort *vp = w->viewport; - int old_left = vp->virtual_left; - int old_top = vp->virtual_top; - int i; - int left, top, width, height; - - vp->virtual_left = x; - vp->virtual_top = y; - - /* Viewport is bound to its left top corner, so it must be rounded down (UnScaleByZoomLower) - * else glitch described in FS#1412 will happen (offset by 1 pixel with zoom level > NORMAL) - */ - old_left = UnScaleByZoomLower(old_left, vp->zoom); - old_top = UnScaleByZoomLower(old_top, vp->zoom); - x = UnScaleByZoomLower(x, vp->zoom); - y = UnScaleByZoomLower(y, vp->zoom); - - old_left -= x; - old_top -= y; - - if (old_top == 0 && old_left == 0) return; - - _vp_move_offs.x = old_left; - _vp_move_offs.y = old_top; - - left = vp->left; - top = vp->top; - width = vp->width; - height = vp->height; - - if (left < 0) { - width += left; - left = 0; - } - - i = left + width - _screen.width; - if (i >= 0) width -= i; - - if (width > 0) { - if (top < 0) { - height += top; - top = 0; - } - - i = top + height - _screen.height; - if (i >= 0) height -= i; - - if (height > 0) DoSetViewportPosition(w->z_front, left, top, width, height); - } -} - -/** - * Is a xy position inside the viewport of the window? - * @param w Window to examine its viewport - * @param x X coordinate of the xy position - * @param y Y coordinate of the xy position - * @return Pointer to the viewport if the xy position is in the viewport of the window, - * otherwise \c NULL is returned. - */ -ViewPort *IsPtInWindowViewport(const Window *w, int x, int y) -{ - ViewPort *vp = w->viewport; - - if (vp != NULL && - IsInsideMM(x, vp->left, vp->left + vp->width) && - IsInsideMM(y, vp->top, vp->top + vp->height)) - return vp; - - return NULL; -} - -/** - * Translate screen coordinate in a viewport to a tile coordinate - * @param vp Viewport that contains the (\a x, \a y) screen coordinate - * @param x Screen x coordinate - * @param y Screen y coordinate - * @return Tile coordinate - */ -static Point TranslateXYToTileCoord(const ViewPort *vp, int x, int y) -{ - Point pt; - int a, b; - int z; - - if ( (uint)(x -= vp->left) >= (uint)vp->width || - (uint)(y -= vp->top) >= (uint)vp->height) { - Point pt = {-1, -1}; - return pt; - } - - x = (ScaleByZoom(x, vp->zoom) + vp->virtual_left) >> (2 + ZOOM_LVL_SHIFT); - y = (ScaleByZoom(y, vp->zoom) + vp->virtual_top) >> (1 + ZOOM_LVL_SHIFT); - - a = y - x; - b = y + x; - - /* we need to move variables in to the valid range, as the - * GetTileZoomCenterWindow() function can call here with invalid x and/or y, - * when the user tries to zoom out along the sides of the map */ - a = Clamp(a, -4 * (int)TILE_SIZE, (int)(MapMaxX() * TILE_SIZE) - 1); - b = Clamp(b, -4 * (int)TILE_SIZE, (int)(MapMaxY() * TILE_SIZE) - 1); - - /* (a, b) is the X/Y-world coordinate that belongs to (x,y) if the landscape would be completely flat on height 0. - * Now find the Z-world coordinate by fix point iteration. - * This is a bit tricky because the tile height is non-continuous at foundations. - * The clicked point should be approached from the back, otherwise there are regions that are not clickable. - * (FOUNDATION_HALFTILE_LOWER on SLOPE_STEEP_S hides north halftile completely) - * So give it a z-malus of 4 in the first iterations. - */ - z = 0; - - int min_coord = _settings_game.construction.freeform_edges ? TILE_SIZE : 0; - - for (int i = 0; i < 5; i++) z = GetSlopePixelZ(Clamp(a + max(z, 4) - 4, min_coord, MapMaxX() * TILE_SIZE - 1), Clamp(b + max(z, 4) - 4, min_coord, MapMaxY() * TILE_SIZE - 1)) / 2; - for (int malus = 3; malus > 0; malus--) z = GetSlopePixelZ(Clamp(a + max(z, malus) - malus, min_coord, MapMaxX() * TILE_SIZE - 1), Clamp(b + max(z, malus) - malus, min_coord, MapMaxY() * TILE_SIZE - 1)) / 2; - for (int i = 0; i < 5; i++) z = GetSlopePixelZ(Clamp(a + z, min_coord, MapMaxX() * TILE_SIZE - 1), Clamp(b + z, min_coord, MapMaxY() * TILE_SIZE - 1)) / 2; - - pt.x = Clamp(a + z, min_coord, MapMaxX() * TILE_SIZE - 1); - pt.y = Clamp(b + z, min_coord, MapMaxY() * TILE_SIZE - 1); - - return pt; -} - -/* When used for zooming, check area below current coordinates (x,y) - * and return the tile of the zoomed out/in position (zoom_x, zoom_y) - * when you just want the tile, make x = zoom_x and y = zoom_y */ -static Point GetTileFromScreenXY(int x, int y, int zoom_x, int zoom_y) -{ - Window *w; - ViewPort *vp; - Point pt; - - if ( (w = FindWindowFromPt(x, y)) != NULL && - (vp = IsPtInWindowViewport(w, x, y)) != NULL) - return TranslateXYToTileCoord(vp, zoom_x, zoom_y); - - pt.y = pt.x = -1; - return pt; -} - -Point GetTileBelowCursor() -{ - return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, _cursor.pos.x, _cursor.pos.y); -} - - -Point GetTileZoomCenterWindow(bool in, Window * w) -{ - int x, y; - ViewPort *vp = w->viewport; - - if (in) { - x = ((_cursor.pos.x - vp->left) >> 1) + (vp->width >> 2); - y = ((_cursor.pos.y - vp->top) >> 1) + (vp->height >> 2); - } else { - x = vp->width - (_cursor.pos.x - vp->left); - y = vp->height - (_cursor.pos.y - vp->top); - } - /* Get the tile below the cursor and center on the zoomed-out center */ - return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp->left, y + vp->top); -} - -/** - * Update the status of the zoom-buttons according to the zoom-level - * of the viewport. This will update their status and invalidate accordingly - * @param w Window pointer to the window that has the zoom buttons - * @param vp pointer to the viewport whose zoom-level the buttons represent - * @param widget_zoom_in widget index for window with zoom-in button - * @param widget_zoom_out widget index for window with zoom-out button - */ -void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out) -{ - w->SetWidgetDisabledState(widget_zoom_in, vp->zoom <= _settings_client.gui.zoom_min); - w->SetWidgetDirty(widget_zoom_in); - - w->SetWidgetDisabledState(widget_zoom_out, vp->zoom >= _settings_client.gui.zoom_max); - w->SetWidgetDirty(widget_zoom_out); -} - -/** - * Schedules a tile sprite for drawing. - * - * @param image the image to draw. - * @param pal the provided palette. - * @param x position x (world coordinates) of the sprite. - * @param y position y (world coordinates) of the sprite. - * @param z position z (world coordinates) of the sprite. - * @param sub Only draw a part of the sprite. - * @param extra_offs_x Pixel X offset for the sprite position. - * @param extra_offs_y Pixel Y offset for the sprite position. - */ -static void AddTileSpriteToDraw(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub = NULL, int extra_offs_x = 0, int extra_offs_y = 0) -{ - assert((image & SPRITE_MASK) < MAX_SPRITES); - - TileSpriteToDraw *ts = _vd.tile_sprites_to_draw.Append(); - ts->image = image; - ts->pal = pal; - ts->sub = sub; - Point pt = RemapCoords(x, y, z); - ts->x = pt.x + extra_offs_x; - ts->y = pt.y + extra_offs_y; -} - -/** - * Adds a child sprite to the active foundation. - * - * The pixel offset of the sprite relative to the ParentSprite is the sum of the offset passed to OffsetGroundSprite() and extra_offs_?. - * - * @param image the image to draw. - * @param pal the provided palette. - * @param sub Only draw a part of the sprite. - * @param foundation_part Foundation part. - * @param extra_offs_x Pixel X offset for the sprite position. - * @param extra_offs_y Pixel Y offset for the sprite position. - */ -static void AddChildSpriteToFoundation(SpriteID image, PaletteID pal, const SubSprite *sub, FoundationPart foundation_part, int extra_offs_x, int extra_offs_y) -{ - assert(IsInsideMM(foundation_part, 0, FOUNDATION_PART_END)); - assert(_vd.foundation[foundation_part] != -1); - Point offs = _vd.foundation_offset[foundation_part]; - - /* Change the active ChildSprite list to the one of the foundation */ - int *old_child = _vd.last_child; - _vd.last_child = _vd.last_foundation_child[foundation_part]; - - AddChildSpriteScreen(image, pal, offs.x + extra_offs_x, offs.y + extra_offs_y, false, sub, false); - - /* Switch back to last ChildSprite list */ - _vd.last_child = old_child; -} - -/** - * Draws a ground sprite at a specific world-coordinate relative to the current tile. - * If the current tile is drawn on top of a foundation the sprite is added as child sprite to the "foundation"-ParentSprite. - * - * @param image the image to draw. - * @param pal the provided palette. - * @param x position x (world coordinates) of the sprite relative to current tile. - * @param y position y (world coordinates) of the sprite relative to current tile. - * @param z position z (world coordinates) of the sprite relative to current tile. - * @param sub Only draw a part of the sprite. - * @param extra_offs_x Pixel X offset for the sprite position. - * @param extra_offs_y Pixel Y offset for the sprite position. - */ -void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub, int extra_offs_x, int extra_offs_y) -{ - /* Switch to first foundation part, if no foundation was drawn */ - if (_vd.foundation_part == FOUNDATION_PART_NONE) _vd.foundation_part = FOUNDATION_PART_NORMAL; - - if (_vd.foundation[_vd.foundation_part] != -1) { - Point pt = RemapCoords(x, y, z); - AddChildSpriteToFoundation(image, pal, sub, _vd.foundation_part, pt.x + extra_offs_x * ZOOM_LVL_BASE, pt.y + extra_offs_y * ZOOM_LVL_BASE); - } else { - AddTileSpriteToDraw(image, pal, _cur_ti->x + x, _cur_ti->y + y, _cur_ti->z + z, sub, extra_offs_x * ZOOM_LVL_BASE, extra_offs_y * ZOOM_LVL_BASE); - } -} - -/** - * Draws a ground sprite for the current tile. - * If the current tile is drawn on top of a foundation the sprite is added as child sprite to the "foundation"-ParentSprite. - * - * @param image the image to draw. - * @param pal the provided palette. - * @param sub Only draw a part of the sprite. - * @param extra_offs_x Pixel X offset for the sprite position. - * @param extra_offs_y Pixel Y offset for the sprite position. - */ -void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y) -{ - DrawGroundSpriteAt(image, pal, 0, 0, 0, sub, extra_offs_x, extra_offs_y); -} - -/** - * Called when a foundation has been drawn for the current tile. - * Successive ground sprites for the current tile will be drawn as child sprites of the "foundation"-ParentSprite, not as TileSprites. - * - * @param x sprite x-offset (screen coordinates) of ground sprites relative to the "foundation"-ParentSprite. - * @param y sprite y-offset (screen coordinates) of ground sprites relative to the "foundation"-ParentSprite. - */ -void OffsetGroundSprite(int x, int y) -{ - /* Switch to next foundation part */ - switch (_vd.foundation_part) { - case FOUNDATION_PART_NONE: - _vd.foundation_part = FOUNDATION_PART_NORMAL; - break; - case FOUNDATION_PART_NORMAL: - _vd.foundation_part = FOUNDATION_PART_HALFTILE; - break; - default: NOT_REACHED(); - } - - /* _vd.last_child == NULL if foundation sprite was clipped by the viewport bounds */ - if (_vd.last_child != NULL) _vd.foundation[_vd.foundation_part] = _vd.parent_sprites_to_draw.Length() - 1; - - _vd.foundation_offset[_vd.foundation_part].x = x * ZOOM_LVL_BASE; - _vd.foundation_offset[_vd.foundation_part].y = y * ZOOM_LVL_BASE; - _vd.last_foundation_child[_vd.foundation_part] = _vd.last_child; -} - -/** - * Adds a child sprite to a parent sprite. - * In contrast to "AddChildSpriteScreen()" the sprite position is in world coordinates - * - * @param image the image to draw. - * @param pal the provided palette. - * @param x position x of the sprite. - * @param y position y of the sprite. - * @param z position z of the sprite. - * @param sub Only draw a part of the sprite. - */ -static void AddCombinedSprite(SpriteID image, PaletteID pal, int x, int y, int z, const SubSprite *sub) -{ - Point pt = RemapCoords(x, y, z); - const Sprite *spr = GetSprite(image & SPRITE_MASK, ST_NORMAL); - - if (pt.x + spr->x_offs >= _vd.dpi.left + _vd.dpi.width || - pt.x + spr->x_offs + spr->width <= _vd.dpi.left || - pt.y + spr->y_offs >= _vd.dpi.top + _vd.dpi.height || - pt.y + spr->y_offs + spr->height <= _vd.dpi.top) - return; - - const ParentSpriteToDraw *pstd = _vd.parent_sprites_to_draw.End() - 1; - AddChildSpriteScreen(image, pal, pt.x - pstd->left, pt.y - pstd->top, false, sub, false); -} - -/** - * Draw a (transparent) sprite at given coordinates with a given bounding box. - * The bounding box extends from (x + bb_offset_x, y + bb_offset_y, z + bb_offset_z) to (x + w - 1, y + h - 1, z + dz - 1), both corners included. - * Bounding boxes with bb_offset_x == w or bb_offset_y == h or bb_offset_z == dz are allowed and produce thin slices. - * - * @note Bounding boxes are normally specified with bb_offset_x = bb_offset_y = bb_offset_z = 0. The extent of the bounding box in negative direction is - * defined by the sprite offset in the grf file. - * However if modifying the sprite offsets is not suitable (e.g. when using existing graphics), the bounding box can be tuned by bb_offset. - * - * @pre w >= bb_offset_x, h >= bb_offset_y, dz >= bb_offset_z. Else w, h or dz are ignored. - * - * @param image the image to combine and draw, - * @param pal the provided palette, - * @param x position X (world) of the sprite, - * @param y position Y (world) of the sprite, - * @param w bounding box extent towards positive X (world), - * @param h bounding box extent towards positive Y (world), - * @param dz bounding box extent towards positive Z (world), - * @param z position Z (world) of the sprite, - * @param transparent if true, switch the palette between the provided palette and the transparent palette, - * @param bb_offset_x bounding box extent towards negative X (world), - * @param bb_offset_y bounding box extent towards negative Y (world), - * @param bb_offset_z bounding box extent towards negative Z (world) - * @param sub Only draw a part of the sprite. - */ -void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub) -{ - int32 left, right, top, bottom; - - assert((image & SPRITE_MASK) < MAX_SPRITES); - - /* make the sprites transparent with the right palette */ - if (transparent) { - SetBit(image, PALETTE_MODIFIER_TRANSPARENT); - pal = PALETTE_TO_TRANSPARENT; - } - - if (_vd.combine_sprites == SPRITE_COMBINE_ACTIVE) { - AddCombinedSprite(image, pal, x, y, z, sub); - return; - } - - _vd.last_child = NULL; - - Point pt = RemapCoords(x, y, z); - int tmp_left, tmp_top, tmp_x = pt.x, tmp_y = pt.y; - - /* Compute screen extents of sprite */ - if (image == SPR_EMPTY_BOUNDING_BOX) { - left = tmp_left = RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x; - right = RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1; - top = tmp_top = RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y; - bottom = RemapCoords(x + w , y + h , z + bb_offset_z).y + 1; - } else { - const Sprite *spr = GetSprite(image & SPRITE_MASK, ST_NORMAL); - left = tmp_left = (pt.x += spr->x_offs); - right = (pt.x + spr->width ); - top = tmp_top = (pt.y += spr->y_offs); - bottom = (pt.y + spr->height); - } - - if (_draw_bounding_boxes && (image != SPR_EMPTY_BOUNDING_BOX)) { - /* Compute maximal extents of sprite and its bounding box */ - left = min(left , RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x); - right = max(right , RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1); - top = min(top , RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y); - bottom = max(bottom, RemapCoords(x + w , y + h , z + bb_offset_z).y + 1); - } - - /* Do not add the sprite to the viewport, if it is outside */ - if (left >= _vd.dpi.left + _vd.dpi.width || - right <= _vd.dpi.left || - top >= _vd.dpi.top + _vd.dpi.height || - bottom <= _vd.dpi.top) { - return; - } - - ParentSpriteToDraw *ps = _vd.parent_sprites_to_draw.Append(); - ps->x = tmp_x; - ps->y = tmp_y; - - ps->left = tmp_left; - ps->top = tmp_top; - - ps->image = image; - ps->pal = pal; - ps->sub = sub; - ps->xmin = x + bb_offset_x; - ps->xmax = x + max(bb_offset_x, w) - 1; - - ps->ymin = y + bb_offset_y; - ps->ymax = y + max(bb_offset_y, h) - 1; - - ps->zmin = z + bb_offset_z; - ps->zmax = z + max(bb_offset_z, dz) - 1; - - ps->comparison_done = false; - ps->first_child = -1; - - _vd.last_child = &ps->first_child; - - if (_vd.combine_sprites == SPRITE_COMBINE_PENDING) _vd.combine_sprites = SPRITE_COMBINE_ACTIVE; -} - -/** - * Starts a block of sprites, which are "combined" into a single bounding box. - * - * Subsequent calls to #AddSortableSpriteToDraw will be drawn into the same bounding box. - * That is: The first sprite that is not clipped by the viewport defines the bounding box, and - * the following sprites will be child sprites to that one. - * - * That implies: - * - The drawing order is definite. No other sprites will be sorted between those of the block. - * - You have to provide a valid bounding box for all sprites, - * as you won't know which one is the first non-clipped one. - * Preferable you use the same bounding box for all. - * - You cannot use #AddChildSpriteScreen inside the block, as its result will be indefinite. - * - * The block is terminated by #EndSpriteCombine. - * - * You cannot nest "combined" blocks. - */ -void StartSpriteCombine() -{ - assert(_vd.combine_sprites == SPRITE_COMBINE_NONE); - _vd.combine_sprites = SPRITE_COMBINE_PENDING; -} - -/** - * Terminates a block of sprites started by #StartSpriteCombine. - * Take a look there for details. - */ -void EndSpriteCombine() -{ - assert(_vd.combine_sprites != SPRITE_COMBINE_NONE); - _vd.combine_sprites = SPRITE_COMBINE_NONE; -} - -/** - * Check if the parameter "check" is inside the interval between - * begin and end, including both begin and end. - * @note Whether \c begin or \c end is the biggest does not matter. - * This method will account for that. - * @param begin The begin of the interval. - * @param end The end of the interval. - * @param check The value to check. - */ -static bool IsInRangeInclusive(int begin, int end, int check) -{ - if (begin > end) Swap(begin, end); - return begin <= check && check <= end; -} - -/** - * Checks whether a point is inside the selected a diagonal rectangle given by _thd.size and _thd.pos - * @param x The x coordinate of the point to be checked. - * @param y The y coordinate of the point to be checked. - * @return True if the point is inside the rectangle, else false. - */ -bool IsInsideRotatedRectangle(int x, int y) -{ - int dist_a = (_thd.size.x + _thd.size.y); // Rotated coordinate system for selected rectangle. - int dist_b = (_thd.size.x - _thd.size.y); // We don't have to divide by 2. It's all relative! - int a = ((x - _thd.pos.x) + (y - _thd.pos.y)); // Rotated coordinate system for the point under scrutiny. - int b = ((x - _thd.pos.x) - (y - _thd.pos.y)); - - /* Check if a and b are between 0 and dist_a or dist_b respectively. */ - return IsInRangeInclusive(dist_a, 0, a) && IsInRangeInclusive(dist_b, 0, b); -} - -/** - * Add a child sprite to a parent sprite. - * - * @param image the image to draw. - * @param pal the provided palette. - * @param x sprite x-offset (screen coordinates) relative to parent sprite. - * @param y sprite y-offset (screen coordinates) relative to parent sprite. - * @param transparent if true, switch the palette between the provided palette and the transparent palette, - * @param sub Only draw a part of the sprite. - */ -void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent, const SubSprite *sub, bool scale) -{ - assert((image & SPRITE_MASK) < MAX_SPRITES); - - /* If the ParentSprite was clipped by the viewport bounds, do not draw the ChildSprites either */ - if (_vd.last_child == NULL) return; - - /* make the sprites transparent with the right palette */ - if (transparent) { - SetBit(image, PALETTE_MODIFIER_TRANSPARENT); - pal = PALETTE_TO_TRANSPARENT; - } - - *_vd.last_child = _vd.child_screen_sprites_to_draw.Length(); - - ChildScreenSpriteToDraw *cs = _vd.child_screen_sprites_to_draw.Append(); - cs->image = image; - cs->pal = pal; - cs->sub = sub; - cs->x = scale ? x * ZOOM_LVL_BASE : x; - cs->y = scale ? y * ZOOM_LVL_BASE : y; - cs->next = -1; - - /* Append the sprite to the active ChildSprite list. - * If the active ParentSprite is a foundation, update last_foundation_child as well. - * Note: ChildSprites of foundations are NOT sequential in the vector, as selection sprites are added at last. */ - if (_vd.last_foundation_child[0] == _vd.last_child) _vd.last_foundation_child[0] = &cs->next; - if (_vd.last_foundation_child[1] == _vd.last_child) _vd.last_foundation_child[1] = &cs->next; - _vd.last_child = &cs->next; -} - -static void AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2, Colours colour, uint16 width) -{ - assert(width != 0); - StringSpriteToDraw *ss = _vd.string_sprites_to_draw.Append(); - ss->string = string; - ss->x = x; - ss->y = y; - ss->params[0] = params_1; - ss->params[1] = params_2; - ss->width = width; - ss->colour = colour; -} - - -/** - * Draws sprites between ground sprite and everything above. - * - * The sprite is either drawn as TileSprite or as ChildSprite of the active foundation. - * - * @param image the image to draw. - * @param pal the provided palette. - * @param ti TileInfo Tile that is being drawn - * @param z_offset Z offset relative to the groundsprite. Only used for the sprite position, not for sprite sorting. - * @param foundation_part Foundation part the sprite belongs to. - */ -static void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part) -{ - /* FIXME: This is not totally valid for some autorail highlights that extend over the edges of the tile. */ - if (_vd.foundation[foundation_part] == -1) { - /* draw on real ground */ - AddTileSpriteToDraw(image, pal, ti->x, ti->y, ti->z + z_offset); - } else { - /* draw on top of foundation */ - AddChildSpriteToFoundation(image, pal, NULL, foundation_part, 0, -z_offset * ZOOM_LVL_BASE); - } -} - -/** - * Draws a selection rectangle on a tile. - * - * @param ti TileInfo Tile that is being drawn - * @param pal Palette to apply. - */ -static void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal) -{ - if (!IsValidTile(ti->tile)) return; - - SpriteID sel; - if (IsHalftileSlope(ti->tileh)) { - Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); - SpriteID sel2 = SPR_HALFTILE_SELECTION_FLAT + halftile_corner; - DrawSelectionSprite(sel2, pal, ti, 7 + TILE_HEIGHT, FOUNDATION_PART_HALFTILE); - - Corner opposite_corner = OppositeCorner(halftile_corner); - if (IsSteepSlope(ti->tileh)) { - sel = SPR_HALFTILE_SELECTION_DOWN; - } else { - sel = ((ti->tileh & SlopeWithOneCornerRaised(opposite_corner)) != 0 ? SPR_HALFTILE_SELECTION_UP : SPR_HALFTILE_SELECTION_FLAT); - } - sel += opposite_corner; - } else { - sel = SPR_SELECT_TILE + SlopeToSpriteOffset(ti->tileh); - } - DrawSelectionSprite(sel, pal, ti, 7, FOUNDATION_PART_NORMAL); -} - -static bool IsPartOfAutoLine(int px, int py) -{ - px -= _thd.selstart.x; - py -= _thd.selstart.y; - - if ((_thd.drawstyle & HT_DRAG_MASK) != HT_LINE) return false; - - switch (_thd.drawstyle & HT_DIR_MASK) { - case HT_DIR_X: return py == 0; // x direction - case HT_DIR_Y: return px == 0; // y direction - case HT_DIR_HU: return px == -py || px == -py - 16; // horizontal upper - case HT_DIR_HL: return px == -py || px == -py + 16; // horizontal lower - case HT_DIR_VL: return px == py || px == py + 16; // vertical left - case HT_DIR_VR: return px == py || px == py - 16; // vertical right - default: - NOT_REACHED(); - } -} - -/* [direction][side] */ -static const HighLightStyle _autorail_type[6][2] = { - { HT_DIR_X, HT_DIR_X }, - { HT_DIR_Y, HT_DIR_Y }, - { HT_DIR_HU, HT_DIR_HL }, - { HT_DIR_HL, HT_DIR_HU }, - { HT_DIR_VL, HT_DIR_VR }, - { HT_DIR_VR, HT_DIR_VL } -}; - -#include "table/autorail.h" - -/** - * Draws autorail highlights. - * - * @param *ti TileInfo Tile that is being drawn - * @param autorail_type Offset into _AutorailTilehSprite[][] - */ -static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type) -{ - SpriteID image; - PaletteID pal; - int offset; - - FoundationPart foundation_part = FOUNDATION_PART_NORMAL; - Slope autorail_tileh = RemoveHalftileSlope(ti->tileh); - if (IsHalftileSlope(ti->tileh)) { - static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U }; - Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); - if (autorail_type != _lower_rail[halftile_corner]) { - foundation_part = FOUNDATION_PART_HALFTILE; - /* Here we draw the highlights of the "three-corners-raised"-slope. That looks ok to me. */ - autorail_tileh = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner)); - } - } - - offset = _AutorailTilehSprite[autorail_tileh][autorail_type]; - if (offset >= 0) { - image = SPR_AUTORAIL_BASE + offset; - pal = PAL_NONE; - } else { - image = SPR_AUTORAIL_BASE - offset; - pal = PALETTE_SEL_TILE_RED; - } - - DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part); -} - -/** - * Checks if the specified tile is selected and if so draws selection using correct selectionstyle. - * @param *ti TileInfo Tile that is being drawn - */ -static void DrawTileSelection(const TileInfo *ti) -{ - /* Draw a red error square? */ - bool is_redsq = _thd.redsq == ti->tile; - if (is_redsq) DrawTileSelectionRect(ti, PALETTE_TILE_RED_PULSATING); - - /* No tile selection active? */ - if ((_thd.drawstyle & HT_DRAG_MASK) == HT_NONE) return; - - if (_thd.diagonal) { // We're drawing a 45 degrees rotated (diagonal) rectangle - if (IsInsideRotatedRectangle((int)ti->x, (int)ti->y)) goto draw_inner; - return; - } - - /* Inside the inner area? */ - if (IsInsideBS(ti->x, _thd.pos.x, _thd.size.x) && - IsInsideBS(ti->y, _thd.pos.y, _thd.size.y)) { -draw_inner: - if (_thd.drawstyle & HT_RECT) { - if (!is_redsq) DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE); - } else if (_thd.drawstyle & HT_POINT) { - /* Figure out the Z coordinate for the single dot. */ - int z = 0; - FoundationPart foundation_part = FOUNDATION_PART_NORMAL; - if (ti->tileh & SLOPE_N) { - z += TILE_HEIGHT; - if (RemoveHalftileSlope(ti->tileh) == SLOPE_STEEP_N) z += TILE_HEIGHT; - } - if (IsHalftileSlope(ti->tileh)) { - Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); - if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z += TILE_HEIGHT; - if (halftile_corner != CORNER_S) { - foundation_part = FOUNDATION_PART_HALFTILE; - if (IsSteepSlope(ti->tileh)) z -= TILE_HEIGHT; - } - } - DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z, foundation_part); - } else if (_thd.drawstyle & HT_RAIL) { - /* autorail highlight piece under cursor */ - HighLightStyle type = _thd.drawstyle & HT_DIR_MASK; - assert(type < HT_DIR_END); - DrawAutorailSelection(ti, _autorail_type[type][0]); - } else if (IsPartOfAutoLine(ti->x, ti->y)) { - /* autorail highlighting long line */ - HighLightStyle dir = _thd.drawstyle & HT_DIR_MASK; - uint side; - - if (dir == HT_DIR_X || dir == HT_DIR_Y) { - side = 0; - } else { - TileIndex start = TileVirtXY(_thd.selstart.x, _thd.selstart.y); - side = Delta(Delta(TileX(start), TileX(ti->tile)), Delta(TileY(start), TileY(ti->tile))); - } - - DrawAutorailSelection(ti, _autorail_type[dir][side]); - } - return; - } - - /* Check if it's inside the outer area? */ - if (!is_redsq && _thd.outersize.x > 0 && - IsInsideBS(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) && - IsInsideBS(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) { - /* Draw a blue rect. */ - DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE); - return; - } -} - -static void ViewportAddLandscape() -{ - int x, y, width, height; - TileInfo ti; - bool direction; - - _cur_ti = &ti; - - /* Transform into tile coordinates and round to closest full tile */ - x = ((_vd.dpi.top >> (1 + ZOOM_LVL_SHIFT)) - (_vd.dpi.left >> (2 + ZOOM_LVL_SHIFT))) & ~TILE_UNIT_MASK; - y = ((_vd.dpi.top >> (1 + ZOOM_LVL_SHIFT)) + (_vd.dpi.left >> (2 + ZOOM_LVL_SHIFT)) - TILE_SIZE) & ~TILE_UNIT_MASK; - - /* determine size of area */ - { - Point pt = RemapCoords(x, y, 241); - width = (_vd.dpi.left + _vd.dpi.width - pt.x + 96 * ZOOM_LVL_BASE - 1) >> (6 + ZOOM_LVL_SHIFT); - height = (_vd.dpi.top + _vd.dpi.height - pt.y) >> (5 + ZOOM_LVL_SHIFT) << 1; - } - - assert(width > 0); - assert(height > 0); - - direction = false; - - do { - int width_cur = width; - uint x_cur = x; - uint y_cur = y; - - do { - TileType tt = MP_VOID; - - ti.x = x_cur; - ti.y = y_cur; - - ti.z = 0; - - ti.tileh = SLOPE_FLAT; - ti.tile = INVALID_TILE; - - if (x_cur < MapMaxX() * TILE_SIZE && - y_cur < MapMaxY() * TILE_SIZE) { - TileIndex tile = TileVirtXY(x_cur, y_cur); - - if (!_settings_game.construction.freeform_edges || (TileX(tile) != 0 && TileY(tile) != 0)) { - if (x_cur == ((int)MapMaxX() - 1) * TILE_SIZE || y_cur == ((int)MapMaxY() - 1) * TILE_SIZE) { - uint maxh = max(TileHeight(tile), 1); - for (uint h = 0; h < maxh; h++) { - AddTileSpriteToDraw(SPR_SHADOW_CELL, PAL_NONE, ti.x, ti.y, h * TILE_HEIGHT); - } - } - - ti.tile = tile; - ti.tileh = GetTilePixelSlope(tile, &ti.z); - tt = GetTileType(tile); - } - } - - _vd.foundation_part = FOUNDATION_PART_NONE; - _vd.foundation[0] = -1; - _vd.foundation[1] = -1; - _vd.last_foundation_child[0] = NULL; - _vd.last_foundation_child[1] = NULL; - - _tile_type_procs[tt]->draw_tile_proc(&ti); - - if ((x_cur == (int)MapMaxX() * TILE_SIZE && IsInsideMM(y_cur, 0, MapMaxY() * TILE_SIZE + 1)) || - (y_cur == (int)MapMaxY() * TILE_SIZE && IsInsideMM(x_cur, 0, MapMaxX() * TILE_SIZE + 1))) { - TileIndex tile = TileVirtXY(x_cur, y_cur); - ti.tile = tile; - ti.tileh = GetTilePixelSlope(tile, &ti.z); - tt = GetTileType(tile); - } - if (ti.tile != INVALID_TILE) DrawTileSelection(&ti); - - y_cur += 0x10; - x_cur -= 0x10; - } while (--width_cur); - - if ((direction ^= 1) != 0) { - y += 0x10; - } else { - x += 0x10; - } - } while (--height); -} - -/** - * Add a string to draw in the viewport - * @param dpi current viewport area - * @param small_from Zoomlevel from when the small font should be used - * @param sign sign position and dimension - * @param string_normal String for normal and 2x zoom level - * @param string_small String for 4x and 8x zoom level - * @param string_small_shadow Shadow string for 4x and 8x zoom level; or #STR_NULL if no shadow - * @param colour colour of the sign background; or INVALID_COLOUR if transparent - */ -void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, uint64 params_1, uint64 params_2, Colours colour) -{ - bool small = dpi->zoom >= small_from; - - int left = dpi->left; - int top = dpi->top; - int right = left + dpi->width; - int bottom = top + dpi->height; - - int sign_height = ScaleByZoom(VPSM_TOP + FONT_HEIGHT_NORMAL + VPSM_BOTTOM, dpi->zoom); - int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, dpi->zoom); - - if (bottom < sign->top || - top > sign->top + sign_height || - right < sign->center - sign_half_width || - left > sign->center + sign_half_width) { - return; - } - - if (!small) { - AddStringToDraw(sign->center - sign_half_width, sign->top, string_normal, params_1, params_2, colour, sign->width_normal); - } else { - int shadow_offset = 0; - if (string_small_shadow != STR_NULL) { - shadow_offset = 4; - AddStringToDraw(sign->center - sign_half_width + shadow_offset, sign->top, string_small_shadow, params_1, params_2, INVALID_COLOUR, sign->width_small); - } - AddStringToDraw(sign->center - sign_half_width, sign->top - shadow_offset, string_small, params_1, params_2, - colour, sign->width_small | 0x8000); - } -} - -static void ViewportAddTownNames(DrawPixelInfo *dpi) -{ - if (!HasBit(_display_opt, DO_SHOW_TOWN_NAMES) || _game_mode == GM_MENU) return; - - const Town *t; - FOR_ALL_TOWNS(t) { - ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &t->cache.sign, - _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN, - STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK, - t->index, t->cache.population); - } -} - - -static void ViewportAddStationNames(DrawPixelInfo *dpi) -{ - if (!(HasBit(_display_opt, DO_SHOW_STATION_NAMES) || HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)) || _game_mode == GM_MENU) return; - - const BaseStation *st; - FOR_ALL_BASE_STATIONS(st) { - /* Check whether the base station is a station or a waypoint */ - bool is_station = Station::IsExpected(st); - - /* Don't draw if the display options are disabled */ - if (!HasBit(_display_opt, is_station ? DO_SHOW_STATION_NAMES : DO_SHOW_WAYPOINT_NAMES)) continue; - - /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */ - if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != st->owner && st->owner != OWNER_NONE) continue; - - ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &st->sign, - is_station ? STR_VIEWPORT_STATION : STR_VIEWPORT_WAYPOINT, - (is_station ? STR_VIEWPORT_STATION : STR_VIEWPORT_WAYPOINT) + 1, STR_NULL, - st->index, st->facilities, (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]); - } -} - - -static void ViewportAddSigns(DrawPixelInfo *dpi) -{ - /* Signs are turned off or are invisible */ - if (!HasBit(_display_opt, DO_SHOW_SIGNS) || IsInvisibilitySet(TO_SIGNS)) return; - - const Sign *si; - FOR_ALL_SIGNS(si) { - /* Don't draw if sign is owned by another company and competitor signs should be hidden. - * Note: It is intentional that also signs owned by OWNER_NONE are hidden. Bankrupt - * companies can leave OWNER_NONE signs after them. */ - if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != si->owner && si->owner != OWNER_DEITY) continue; - - ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &si->sign, - STR_WHITE_SIGN, - (IsTransparencySet(TO_SIGNS) || si->owner == OWNER_DEITY) ? STR_VIEWPORT_SIGN_SMALL_WHITE : STR_VIEWPORT_SIGN_SMALL_BLACK, STR_NULL, - si->index, 0, (si->owner == OWNER_NONE) ? COLOUR_GREY : (si->owner == OWNER_DEITY ? INVALID_COLOUR : _company_colours[si->owner])); - } -} - -/** - * Update the position of the viewport sign. - * @param center the (preferred) center of the viewport sign - * @param top the new top of the sign - * @param str the string to show in the sign - */ -void ViewportSign::UpdatePosition(int center, int top, StringID str) -{ - if (this->width_normal != 0) this->MarkDirty(); - - this->top = top; - - char buffer[DRAW_STRING_BUFFER]; - - GetString(buffer, str, lastof(buffer)); - this->width_normal = VPSM_LEFT + Align(GetStringBoundingBox(buffer).width, 2) + VPSM_RIGHT; - this->center = center; - - /* zoomed out version */ - this->width_small = VPSM_LEFT + Align(GetStringBoundingBox(buffer, FS_SMALL).width, 2) + VPSM_RIGHT; - - this->MarkDirty(); -} - -/** - * Mark the sign dirty in all viewports. - * @param maxzoom Maximum %ZoomLevel at which the text is visible. - * - * @ingroup dirty - */ -void ViewportSign::MarkDirty(ZoomLevel maxzoom) const -{ - Rect zoomlevels[ZOOM_LVL_COUNT]; - - for (ZoomLevel zoom = ZOOM_LVL_BEGIN; zoom != ZOOM_LVL_END; zoom++) { - /* FIXME: This doesn't switch to width_small when appropriate. */ - zoomlevels[zoom].left = this->center - ScaleByZoom(this->width_normal / 2 + 1, zoom); - zoomlevels[zoom].top = this->top - ScaleByZoom(1, zoom); - zoomlevels[zoom].right = this->center + ScaleByZoom(this->width_normal / 2 + 1, zoom); - zoomlevels[zoom].bottom = this->top + ScaleByZoom(VPSM_TOP + FONT_HEIGHT_NORMAL + VPSM_BOTTOM + 1, zoom); - } - - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - ViewPort *vp = w->viewport; - if (vp != NULL && vp->zoom <= maxzoom) { - assert(vp->width != 0); - Rect &zl = zoomlevels[vp->zoom]; - MarkViewportDirty(vp, zl.left, zl.top, zl.right, zl.bottom); - } - } -} - -static void ViewportDrawTileSprites(const TileSpriteToDrawVector *tstdv) -{ - const TileSpriteToDraw *tsend = tstdv->End(); - for (const TileSpriteToDraw *ts = tstdv->Begin(); ts != tsend; ++ts) { - DrawSpriteViewport(ts->image, ts->pal, ts->x, ts->y, ts->sub); - } -} - -/** This fallback sprite checker always exists. */ -static bool ViewportSortParentSpritesChecker() -{ - return true; -} - -/** Sort parent sprites pointer array */ -static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv) -{ - ParentSpriteToDraw **psdvend = psdv->End(); - ParentSpriteToDraw **psd = psdv->Begin(); - while (psd != psdvend) { - ParentSpriteToDraw *ps = *psd; - - if (ps->comparison_done) { - psd++; - continue; - } - - ps->comparison_done = true; - - for (ParentSpriteToDraw **psd2 = psd + 1; psd2 != psdvend; psd2++) { - ParentSpriteToDraw *ps2 = *psd2; - - if (ps2->comparison_done) continue; - - /* Decide which comparator to use, based on whether the bounding - * boxes overlap - */ - if (ps->xmax >= ps2->xmin && ps->xmin <= ps2->xmax && // overlap in X? - ps->ymax >= ps2->ymin && ps->ymin <= ps2->ymax && // overlap in Y? - ps->zmax >= ps2->zmin && ps->zmin <= ps2->zmax) { // overlap in Z? - /* Use X+Y+Z as the sorting order, so sprites closer to the bottom of - * the screen and with higher Z elevation, are drawn in front. - * Here X,Y,Z are the coordinates of the "center of mass" of the sprite, - * i.e. X=(left+right)/2, etc. - * However, since we only care about order, don't actually divide / 2 - */ - if (ps->xmin + ps->xmax + ps->ymin + ps->ymax + ps->zmin + ps->zmax <= - ps2->xmin + ps2->xmax + ps2->ymin + ps2->ymax + ps2->zmin + ps2->zmax) { - continue; - } - } else { - /* We only change the order, if it is definite. - * I.e. every single order of X, Y, Z says ps2 is behind ps or they overlap. - * That is: If one partial order says ps behind ps2, do not change the order. - */ - if (ps->xmax < ps2->xmin || - ps->ymax < ps2->ymin || - ps->zmax < ps2->zmin) { - continue; - } - } - - /* Move ps2 in front of ps */ - ParentSpriteToDraw *temp = ps2; - for (ParentSpriteToDraw **psd3 = psd2; psd3 > psd; psd3--) { - *psd3 = *(psd3 - 1); - } - *psd = temp; - } - } -} - -static void ViewportDrawParentSprites(const ParentSpriteToSortVector *psd, const ChildScreenSpriteToDrawVector *csstdv) -{ - const ParentSpriteToDraw * const *psd_end = psd->End(); - for (const ParentSpriteToDraw * const *it = psd->Begin(); it != psd_end; it++) { - const ParentSpriteToDraw *ps = *it; - if (ps->image != SPR_EMPTY_BOUNDING_BOX) DrawSpriteViewport(ps->image, ps->pal, ps->x, ps->y, ps->sub); - - int child_idx = ps->first_child; - while (child_idx >= 0) { - const ChildScreenSpriteToDraw *cs = csstdv->Get(child_idx); - child_idx = cs->next; - DrawSpriteViewport(cs->image, cs->pal, ps->left + cs->x, ps->top + cs->y, cs->sub); - } - } -} - -/** - * Draws the bounding boxes of all ParentSprites - * @param psd Array of ParentSprites - */ -static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd) -{ - const ParentSpriteToDraw * const *psd_end = psd->End(); - for (const ParentSpriteToDraw * const *it = psd->Begin(); it != psd_end; it++) { - const ParentSpriteToDraw *ps = *it; - Point pt1 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmax + 1); // top front corner - Point pt2 = RemapCoords(ps->xmin , ps->ymax + 1, ps->zmax + 1); // top left corner - Point pt3 = RemapCoords(ps->xmax + 1, ps->ymin , ps->zmax + 1); // top right corner - Point pt4 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmin ); // bottom front corner - - DrawBox( pt1.x, pt1.y, - pt2.x - pt1.x, pt2.y - pt1.y, - pt3.x - pt1.x, pt3.y - pt1.y, - pt4.x - pt1.x, pt4.y - pt1.y); - } -} - -/** - * Draw/colour the blocks that have been redrawn. - */ -static void ViewportDrawDirtyBlocks() -{ - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - const DrawPixelInfo *dpi = _cur_dpi; - void *dst; - int right = UnScaleByZoom(dpi->width, dpi->zoom); - int bottom = UnScaleByZoom(dpi->height, dpi->zoom); - - int colour = _string_colourmap[_dirty_block_colour & 0xF]; - - dst = dpi->dst_ptr; - - byte bo = UnScaleByZoom(dpi->left + dpi->top, dpi->zoom) & 1; - do { - for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8)colour); - dst = blitter->MoveTo(dst, 0, 1); - } while (--bottom > 0); -} - -static void ViewportDrawStrings(ZoomLevel zoom, const StringSpriteToDrawVector *sstdv) -{ - const StringSpriteToDraw *ssend = sstdv->End(); - for (const StringSpriteToDraw *ss = sstdv->Begin(); ss != ssend; ++ss) { - TextColour colour = TC_BLACK; - bool small = HasBit(ss->width, 15); - int w = GB(ss->width, 0, 15); - int x = UnScaleByZoom(ss->x, zoom); - int y = UnScaleByZoom(ss->y, zoom); - int h = VPSM_TOP + (small ? FONT_HEIGHT_SMALL : FONT_HEIGHT_NORMAL) + VPSM_BOTTOM; - - SetDParam(0, ss->params[0]); - SetDParam(1, ss->params[1]); - - if (ss->colour != INVALID_COLOUR) { - /* Do not draw signs nor station names if they are set invisible */ - if (IsInvisibilitySet(TO_SIGNS) && ss->string != STR_WHITE_SIGN) continue; - - if (IsTransparencySet(TO_SIGNS) && ss->string != STR_WHITE_SIGN) { - /* Don't draw the rectangle. - * Real colours need the TC_IS_PALETTE_COLOUR flag. - * Otherwise colours from _string_colourmap are assumed. */ - colour = (TextColour)_colour_gradient[ss->colour][6] | TC_IS_PALETTE_COLOUR; - } else { - /* Draw the rectangle if 'transparent station signs' is off, - * or if we are drawing a general text sign (STR_WHITE_SIGN). */ - DrawFrameRect( - x, y, x + w, y + h, ss->colour, - IsTransparencySet(TO_SIGNS) ? FR_TRANSPARENT : FR_NONE - ); - } - } - - DrawString(x + VPSM_LEFT, x + w - 1 - VPSM_RIGHT, y + VPSM_TOP, ss->string, colour, SA_HOR_CENTER); - } -} - -void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom) -{ - DrawPixelInfo *old_dpi = _cur_dpi; - _cur_dpi = &_vd.dpi; - - _vd.dpi.zoom = vp->zoom; - int mask = ScaleByZoom(-1, vp->zoom); - - _vd.combine_sprites = SPRITE_COMBINE_NONE; - - _vd.dpi.width = (right - left) & mask; - _vd.dpi.height = (bottom - top) & mask; - _vd.dpi.left = left & mask; - _vd.dpi.top = top & mask; - _vd.dpi.pitch = old_dpi->pitch; - _vd.last_child = NULL; - - int x = UnScaleByZoom(_vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left; - int y = UnScaleByZoom(_vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top; - - _vd.dpi.dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(old_dpi->dst_ptr, x - old_dpi->left, y - old_dpi->top); - - ViewportAddLandscape(); - ViewportAddVehicles(&_vd.dpi); - - ViewportAddTownNames(&_vd.dpi); - ViewportAddStationNames(&_vd.dpi); - ViewportAddSigns(&_vd.dpi); - - DrawTextEffects(&_vd.dpi); - - if (_vd.tile_sprites_to_draw.Length() != 0) ViewportDrawTileSprites(&_vd.tile_sprites_to_draw); - - ParentSpriteToDraw *psd_end = _vd.parent_sprites_to_draw.End(); - for (ParentSpriteToDraw *it = _vd.parent_sprites_to_draw.Begin(); it != psd_end; it++) { - *_vd.parent_sprites_to_sort.Append() = it; - } - - _vp_sprite_sorter(&_vd.parent_sprites_to_sort); - ViewportDrawParentSprites(&_vd.parent_sprites_to_sort, &_vd.child_screen_sprites_to_draw); - - if (_draw_bounding_boxes) ViewportDrawBoundingBoxes(&_vd.parent_sprites_to_sort); - if (_draw_dirty_blocks) ViewportDrawDirtyBlocks(); - - DrawPixelInfo dp = _vd.dpi; - ZoomLevel zoom = _vd.dpi.zoom; - dp.zoom = ZOOM_LVL_NORMAL; - dp.width = UnScaleByZoom(dp.width, zoom); - dp.height = UnScaleByZoom(dp.height, zoom); - _cur_dpi = &dp; - - if (vp->overlay != NULL && vp->overlay->GetCargoMask() != 0 && vp->overlay->GetCompanyMask() != 0) { - /* translate to window coordinates */ - dp.left = x; - dp.top = y; - vp->overlay->Draw(&dp); - } - - if (_vd.string_sprites_to_draw.Length() != 0) { - /* translate to world coordinates */ - dp.left = UnScaleByZoom(_vd.dpi.left, zoom); - dp.top = UnScaleByZoom(_vd.dpi.top, zoom); - ViewportDrawStrings(zoom, &_vd.string_sprites_to_draw); - } - - _cur_dpi = old_dpi; - - _vd.string_sprites_to_draw.Clear(); - _vd.tile_sprites_to_draw.Clear(); - _vd.parent_sprites_to_draw.Clear(); - _vd.parent_sprites_to_sort.Clear(); - _vd.child_screen_sprites_to_draw.Clear(); -} - -/** - * Make sure we don't draw a too big area at a time. - * If we do, the sprite memory will overflow. - */ -static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom) -{ - if (ScaleByZoom(bottom - top, vp->zoom) * ScaleByZoom(right - left, vp->zoom) > 180000 * ZOOM_LVL_BASE * ZOOM_LVL_BASE) { - if ((bottom - top) > (right - left)) { - int t = (top + bottom) >> 1; - ViewportDrawChk(vp, left, top, right, t); - ViewportDrawChk(vp, left, t, right, bottom); - } else { - int t = (left + right) >> 1; - ViewportDrawChk(vp, left, top, t, bottom); - ViewportDrawChk(vp, t, top, right, bottom); - } - } else { - ViewportDoDraw(vp, - ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left, - ScaleByZoom(top - vp->top, vp->zoom) + vp->virtual_top, - ScaleByZoom(right - vp->left, vp->zoom) + vp->virtual_left, - ScaleByZoom(bottom - vp->top, vp->zoom) + vp->virtual_top - ); - } -} - -static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right, int bottom) -{ - if (right <= vp->left || bottom <= vp->top) return; - - if (left >= vp->left + vp->width) return; - - if (left < vp->left) left = vp->left; - if (right > vp->left + vp->width) right = vp->left + vp->width; - - if (top >= vp->top + vp->height) return; - - if (top < vp->top) top = vp->top; - if (bottom > vp->top + vp->height) bottom = vp->top + vp->height; - - ViewportDrawChk(vp, left, top, right, bottom); -} - -/** - * Draw the viewport of this window. - */ -void Window::DrawViewport() const -{ - DrawPixelInfo *dpi = _cur_dpi; - - dpi->left += this->left; - dpi->top += this->top; - - ViewportDraw(this->viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height); - - dpi->left -= this->left; - dpi->top -= this->top; -} - -static inline void ClampViewportToMap(const ViewPort *vp, int &x, int &y) -{ - /* Centre of the viewport is hot spot */ - x += vp->virtual_width / 2; - y += vp->virtual_height / 2; - - /* Convert viewport coordinates to map coordinates - * Calculation is scaled by 4 to avoid rounding errors */ - int vx = -x + y * 2; - int vy = x + y * 2; - - /* clamp to size of map */ - vx = Clamp(vx, 0, MapMaxX() * TILE_SIZE * 4 * ZOOM_LVL_BASE); - vy = Clamp(vy, 0, MapMaxY() * TILE_SIZE * 4 * ZOOM_LVL_BASE); - - /* Convert map coordinates to viewport coordinates */ - x = (-vx + vy) / 2; - y = ( vx + vy) / 4; - - /* Remove centering */ - x -= vp->virtual_width / 2; - y -= vp->virtual_height / 2; -} - -/** - * Update the viewport position being displayed. - * @param w %Window owning the viewport. - */ -void UpdateViewportPosition(Window *w) -{ - const ViewPort *vp = w->viewport; - - if (w->viewport->follow_vehicle != INVALID_VEHICLE) { - const Vehicle *veh = Vehicle::Get(w->viewport->follow_vehicle); - Point pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos); - - w->viewport->scrollpos_x = pt.x; - w->viewport->scrollpos_y = pt.y; - SetViewportPosition(w, pt.x, pt.y); - } else { - /* Ensure the destination location is within the map */ - ClampViewportToMap(vp, w->viewport->dest_scrollpos_x, w->viewport->dest_scrollpos_y); - - int delta_x = w->viewport->dest_scrollpos_x - w->viewport->scrollpos_x; - int delta_y = w->viewport->dest_scrollpos_y - w->viewport->scrollpos_y; - - bool update_overlay = false; - if (delta_x != 0 || delta_y != 0) { - if (_settings_client.gui.smooth_scroll) { - int max_scroll = ScaleByMapSize1D(512 * ZOOM_LVL_BASE); - /* Not at our desired position yet... */ - w->viewport->scrollpos_x += Clamp(delta_x / 4, -max_scroll, max_scroll); - w->viewport->scrollpos_y += Clamp(delta_y / 4, -max_scroll, max_scroll); - } else { - w->viewport->scrollpos_x = w->viewport->dest_scrollpos_x; - w->viewport->scrollpos_y = w->viewport->dest_scrollpos_y; - } - update_overlay = (w->viewport->scrollpos_x == w->viewport->dest_scrollpos_x && - w->viewport->scrollpos_y == w->viewport->dest_scrollpos_y); - } - - ClampViewportToMap(vp, w->viewport->scrollpos_x, w->viewport->scrollpos_y); - - SetViewportPosition(w, w->viewport->scrollpos_x, w->viewport->scrollpos_y); - if (update_overlay) RebuildViewportOverlay(w); - } -} - -/** - * Marks a viewport as dirty for repaint if it displays (a part of) the area the needs to be repainted. - * @param vp The viewport to mark as dirty - * @param left Left edge of area to repaint - * @param top Top edge of area to repaint - * @param right Right edge of area to repaint - * @param bottom Bottom edge of area to repaint - * @ingroup dirty - */ -static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom) -{ - right -= vp->virtual_left; - if (right <= 0) return; - - bottom -= vp->virtual_top; - if (bottom <= 0) return; - - left = max(0, left - vp->virtual_left); - - if (left >= vp->virtual_width) return; - - top = max(0, top - vp->virtual_top); - - if (top >= vp->virtual_height) return; - - SetDirtyBlocks( - UnScaleByZoomLower(left, vp->zoom) + vp->left, - UnScaleByZoomLower(top, vp->zoom) + vp->top, - UnScaleByZoom(right, vp->zoom) + vp->left + 1, - UnScaleByZoom(bottom, vp->zoom) + vp->top + 1 - ); -} - -/** - * Mark all viewports that display an area as dirty (in need of repaint). - * @param left Left edge of area to repaint - * @param top Top edge of area to repaint - * @param right Right edge of area to repaint - * @param bottom Bottom edge of area to repaint - * @ingroup dirty - */ -void MarkAllViewportsDirty(int left, int top, int right, int bottom) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - ViewPort *vp = w->viewport; - if (vp != NULL) { - assert(vp->width != 0); - MarkViewportDirty(vp, left, top, right, bottom); - } - } -} - -void ConstrainAllViewportsZoom() -{ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if (w->viewport == NULL) continue; - - ZoomLevel zoom = static_cast(Clamp(w->viewport->zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max)); - if (zoom != w->viewport->zoom) { - while (w->viewport->zoom < zoom) DoZoomInOutWindow(ZOOM_OUT, w); - while (w->viewport->zoom > zoom) DoZoomInOutWindow(ZOOM_IN, w); - } - } -} - -/** - * Mark a tile given by its index dirty for repaint. - * @param tile The tile to mark dirty. - * @ingroup dirty - */ -void MarkTileDirtyByTile(TileIndex tile) -{ - Point pt = RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, GetTilePixelZ(tile)); - MarkAllViewportsDirty( - pt.x - 31 * ZOOM_LVL_BASE, - pt.y - 122 * ZOOM_LVL_BASE, - pt.x - 31 * ZOOM_LVL_BASE + 67 * ZOOM_LVL_BASE, - pt.y - 122 * ZOOM_LVL_BASE + 154 * ZOOM_LVL_BASE - ); -} - -/** - * Marks the selected tiles as dirty. - * - * This function marks the selected tiles as dirty for repaint - * - * @ingroup dirty - */ -static void SetSelectionTilesDirty() -{ - int x_size = _thd.size.x; - int y_size = _thd.size.y; - - if (!_thd.diagonal) { // Selecting in a straight rectangle (or a single square) - int x_start = _thd.pos.x; - int y_start = _thd.pos.y; - - if (_thd.outersize.x != 0) { - x_size += _thd.outersize.x; - x_start += _thd.offs.x; - y_size += _thd.outersize.y; - y_start += _thd.offs.y; - } - - x_size -= TILE_SIZE; - y_size -= TILE_SIZE; - - assert(x_size >= 0); - assert(y_size >= 0); - - int x_end = Clamp(x_start + x_size, 0, MapSizeX() * TILE_SIZE - TILE_SIZE); - int y_end = Clamp(y_start + y_size, 0, MapSizeY() * TILE_SIZE - TILE_SIZE); - - x_start = Clamp(x_start, 0, MapSizeX() * TILE_SIZE - TILE_SIZE); - y_start = Clamp(y_start, 0, MapSizeY() * TILE_SIZE - TILE_SIZE); - - /* make sure everything is multiple of TILE_SIZE */ - assert((x_end | y_end | x_start | y_start) % TILE_SIZE == 0); - - /* How it works: - * Suppose we have to mark dirty rectangle of 3x4 tiles: - * x - * xxx - * xxxxx - * xxxxx - * xxx - * x - * This algorithm marks dirty columns of tiles, so it is done in 3+4-1 steps: - * 1) x 2) x - * xxx Oxx - * Oxxxx xOxxx - * xxxxx Oxxxx - * xxx xxx - * x x - * And so forth... - */ - - int top_x = x_end; // coordinates of top dirty tile - int top_y = y_start; - int bot_x = top_x; // coordinates of bottom dirty tile - int bot_y = top_y; - - do { - /* topmost dirty point */ - TileIndex top_tile = TileVirtXY(top_x, top_y); - Point top = RemapCoords(top_x, top_y, GetTileMaxPixelZ(top_tile)); - - /* bottommost point */ - TileIndex bottom_tile = TileVirtXY(bot_x, bot_y); - Point bot = RemapCoords(bot_x + TILE_SIZE, bot_y + TILE_SIZE, GetTilePixelZ(bottom_tile)); // bottommost point - - /* the 'x' coordinate of 'top' and 'bot' is the same (and always in the same distance from tile middle), - * tile height/slope affects only the 'y' on-screen coordinate! */ - - int l = top.x - (TILE_PIXELS - 2) * ZOOM_LVL_BASE; // 'x' coordinate of left side of dirty rectangle - int t = top.y; // 'y' coordinate of top side -//- - int r = top.x + (TILE_PIXELS - 2) * ZOOM_LVL_BASE; // right side of dirty rectangle - int b = bot.y; // bottom -//- - - static const int OVERLAY_WIDTH = 4 * ZOOM_LVL_BASE; // part of selection sprites is drawn outside the selected area - - /* For halftile foundations on SLOPE_STEEP_S the sprite extents some more towards the top */ - MarkAllViewportsDirty(l - OVERLAY_WIDTH, t - OVERLAY_WIDTH - TILE_HEIGHT * ZOOM_LVL_BASE, r + OVERLAY_WIDTH, b + OVERLAY_WIDTH * ZOOM_LVL_BASE); - - /* haven't we reached the topmost tile yet? */ - if (top_x != x_start) { - top_x -= TILE_SIZE; - } else { - top_y += TILE_SIZE; - } - - /* the way the bottom tile changes is different when we reach the bottommost tile */ - if (bot_y != y_end) { - bot_y += TILE_SIZE; - } else { - bot_x -= TILE_SIZE; - } - } while (bot_x >= top_x); - } else { // Selecting in a 45 degrees rotated (diagonal) rectangle. - /* a_size, b_size describe a rectangle with rotated coordinates */ - int a_size = x_size + y_size, b_size = x_size - y_size; - - int interval_a = a_size < 0 ? -(int)TILE_SIZE : (int)TILE_SIZE; - int interval_b = b_size < 0 ? -(int)TILE_SIZE : (int)TILE_SIZE; - - for (int a = -interval_a; a != a_size + interval_a; a += interval_a) { - for (int b = -interval_b; b != b_size + interval_b; b += interval_b) { - uint x = (_thd.pos.x + (a + b) / 2) / TILE_SIZE; - uint y = (_thd.pos.y + (a - b) / 2) / TILE_SIZE; - - if (x < MapMaxX() && y < MapMaxY()) { - MarkTileDirtyByTile(TileXY(x, y)); - } - } - } - } -} - - -void SetSelectionRed(bool b) -{ - _thd.make_square_red = b; - SetSelectionTilesDirty(); -} - -/** - * Test whether a sign is below the mouse - * @param vp the clicked viewport - * @param x X position of click - * @param y Y position of click - * @param sign the sign to check - * @return true if the sign was hit - */ -static bool CheckClickOnViewportSign(const ViewPort *vp, int x, int y, const ViewportSign *sign) -{ - bool small = (vp->zoom >= ZOOM_LVL_OUT_16X); - int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, vp->zoom); - int sign_height = ScaleByZoom(VPSM_TOP + (small ? FONT_HEIGHT_SMALL : FONT_HEIGHT_NORMAL) + VPSM_BOTTOM, vp->zoom); - - x = ScaleByZoom(x - vp->left, vp->zoom) + vp->virtual_left; - y = ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top; - - return y >= sign->top && y < sign->top + sign_height && - x >= sign->center - sign_half_width && x < sign->center + sign_half_width; -} - -static bool CheckClickOnTown(const ViewPort *vp, int x, int y) -{ - if (!HasBit(_display_opt, DO_SHOW_TOWN_NAMES)) return false; - - const Town *t; - FOR_ALL_TOWNS(t) { - if (CheckClickOnViewportSign(vp, x, y, &t->cache.sign)) { - ShowTownViewWindow(t->index); - return true; - } - } - - return false; -} - -static bool CheckClickOnStation(const ViewPort *vp, int x, int y) -{ - if (!(HasBit(_display_opt, DO_SHOW_STATION_NAMES) || HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)) || IsInvisibilitySet(TO_SIGNS)) return false; - - const BaseStation *st; - FOR_ALL_BASE_STATIONS(st) { - /* Check whether the base station is a station or a waypoint */ - bool is_station = Station::IsExpected(st); - - /* Don't check if the display options are disabled */ - if (!HasBit(_display_opt, is_station ? DO_SHOW_STATION_NAMES : DO_SHOW_WAYPOINT_NAMES)) continue; - - /* Don't check if competitor signs are not shown and the sign isn't owned by the local company */ - if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != st->owner && st->owner != OWNER_NONE) continue; - - if (CheckClickOnViewportSign(vp, x, y, &st->sign)) { - if (is_station) { - ShowStationViewWindow(st->index); - } else { - ShowWaypointWindow(Waypoint::From(st)); - } - return true; - } - } - - return false; -} - - -static bool CheckClickOnSign(const ViewPort *vp, int x, int y) -{ - /* Signs are turned off, or they are transparent and invisibility is ON, or company is a spectator */ - if (!HasBit(_display_opt, DO_SHOW_SIGNS) || IsInvisibilitySet(TO_SIGNS) || _local_company == COMPANY_SPECTATOR) return false; - - const Sign *si; - FOR_ALL_SIGNS(si) { - /* If competitor signs are hidden, don't check signs that aren't owned by local company */ - if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != si->owner && si->owner != OWNER_DEITY) continue; - if (si->owner == OWNER_DEITY && _game_mode != GM_EDITOR) continue; - - if (CheckClickOnViewportSign(vp, x, y, &si->sign)) { - HandleClickOnSign(si); - return true; - } - } - - return false; -} - - -static bool CheckClickOnLandscape(const ViewPort *vp, int x, int y) -{ - Point pt = TranslateXYToTileCoord(vp, x, y); - - if (pt.x != -1) return ClickTile(TileVirtXY(pt.x, pt.y)); - return true; -} - -static void PlaceObject() -{ - Point pt; - Window *w; - - pt = GetTileBelowCursor(); - if (pt.x == -1) return; - - if ((_thd.place_mode & HT_DRAG_MASK) == HT_POINT) { - pt.x += TILE_SIZE / 2; - pt.y += TILE_SIZE / 2; - } - - _tile_fract_coords.x = pt.x & TILE_UNIT_MASK; - _tile_fract_coords.y = pt.y & TILE_UNIT_MASK; - - w = _thd.GetCallbackWnd(); - if (w != NULL) w->OnPlaceObject(pt, TileVirtXY(pt.x, pt.y)); -} - - -bool HandleViewportClicked(const ViewPort *vp, int x, int y) -{ - const Vehicle *v = CheckClickOnVehicle(vp, x, y); - - if (_thd.place_mode & HT_VEHICLE) { - if (v != NULL && VehicleClicked(v)) return true; - } - - /* Vehicle placement mode already handled above. */ - if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) { - PlaceObject(); - return true; - } - - if (CheckClickOnTown(vp, x, y)) return true; - if (CheckClickOnStation(vp, x, y)) return true; - if (CheckClickOnSign(vp, x, y)) return true; - bool result = CheckClickOnLandscape(vp, x, y); - - if (v != NULL) { - DEBUG(misc, 2, "Vehicle %d (index %d) at %p", v->unitnumber, v->index, v); - if (IsCompanyBuildableVehicleType(v)) { - v = v->First(); - if (_ctrl_pressed && v->owner == _local_company) { - StartStopVehicle(v, true); - } else { - ShowVehicleViewWindow(v); - } - } - return true; - } - return result; -} - -void RebuildViewportOverlay(Window *w) -{ - if (w->viewport->overlay != NULL && - w->viewport->overlay->GetCompanyMask() != 0 && - w->viewport->overlay->GetCargoMask() != 0) { - w->viewport->overlay->RebuildCache(); - w->SetDirty(); - } -} - -/** - * Scrolls the viewport in a window to a given location. - * @param x Desired x location of the map to scroll to (world coordinate). - * @param y Desired y location of the map to scroll to (world coordinate). - * @param z Desired z location of the map to scroll to (world coordinate). Use \c -1 to scroll to the height of the map at the \a x, \a y location. - * @param w %Window containing the viewport. - * @param instant Jump to the location instead of slowly moving to it. - * @return Destination of the viewport was changed (to activate other actions when the viewport is already at the desired position). - */ -bool ScrollWindowTo(int x, int y, int z, Window *w, bool instant) -{ - /* The slope cannot be acquired outside of the map, so make sure we are always within the map. */ - if (z == -1) z = GetSlopePixelZ(Clamp(x, 0, MapSizeX() * TILE_SIZE - 1), Clamp(y, 0, MapSizeY() * TILE_SIZE - 1)); - - Point pt = MapXYZToViewport(w->viewport, x, y, z); - w->viewport->follow_vehicle = INVALID_VEHICLE; - - if (w->viewport->dest_scrollpos_x == pt.x && w->viewport->dest_scrollpos_y == pt.y) return false; - - if (instant) { - w->viewport->scrollpos_x = pt.x; - w->viewport->scrollpos_y = pt.y; - RebuildViewportOverlay(w); - } - - w->viewport->dest_scrollpos_x = pt.x; - w->viewport->dest_scrollpos_y = pt.y; - return true; -} - -/** - * Scrolls the viewport in a window to a given location. - * @param tile Desired tile to center on. - * @param w %Window containing the viewport. - * @param instant Jump to the location instead of slowly moving to it. - * @return Destination of the viewport was changed (to activate other actions when the viewport is already at the desired position). - */ -bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant) -{ - return ScrollWindowTo(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, -1, w, instant); -} - -/** - * Scrolls the viewport of the main window to a given location. - * @param tile Desired tile to center on. - * @param instant Jump to the location instead of slowly moving to it. - * @return Destination of the viewport was changed (to activate other actions when the viewport is already at the desired position). - */ -bool ScrollMainWindowToTile(TileIndex tile, bool instant) -{ - return ScrollMainWindowTo(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, -1, instant); -} - -/** - * Set a tile to display a red error square. - * @param tile Tile that should show the red error square. - */ -void SetRedErrorSquare(TileIndex tile) -{ - TileIndex old; - - old = _thd.redsq; - _thd.redsq = tile; - - if (tile != old) { - if (tile != INVALID_TILE) MarkTileDirtyByTile(tile); - if (old != INVALID_TILE) MarkTileDirtyByTile(old); - } -} - -/** - * Highlight \a w by \a h tiles at the cursor. - * @param w Width of the highlighted tiles rectangle. - * @param h Height of the highlighted tiles rectangle. - */ -void SetTileSelectSize(int w, int h) -{ - _thd.new_size.x = w * TILE_SIZE; - _thd.new_size.y = h * TILE_SIZE; - _thd.new_outersize.x = 0; - _thd.new_outersize.y = 0; -} - -void SetTileSelectBigSize(int ox, int oy, int sx, int sy) -{ - _thd.offs.x = ox * TILE_SIZE; - _thd.offs.y = oy * TILE_SIZE; - _thd.new_outersize.x = sx * TILE_SIZE; - _thd.new_outersize.y = sy * TILE_SIZE; -} - -/** returns the best autorail highlight type from map coordinates */ -static HighLightStyle GetAutorailHT(int x, int y) -{ - return HT_RAIL | _autorail_piece[x & TILE_UNIT_MASK][y & TILE_UNIT_MASK]; -} - -/** - * Reset tile highlighting. - */ -void TileHighlightData::Reset() -{ - this->pos.x = 0; - this->pos.y = 0; - this->new_pos.x = 0; - this->new_pos.y = 0; -} - -/** - * Is the user dragging a 'diagonal rectangle'? - * @return User is dragging a rotated rectangle. - */ -bool TileHighlightData::IsDraggingDiagonal() -{ - return (this->place_mode & HT_DIAGONAL) != 0 && _ctrl_pressed && _left_button_down; -} - -/** - * Get the window that started the current highlighting. - * @return The window that requested the current tile highlighting, or \c NULL if not available. - */ -Window *TileHighlightData::GetCallbackWnd() -{ - return FindWindowById(this->window_class, this->window_number); -} - - - -/** - * Updates tile highlighting for all cases. - * Uses _thd.selstart and _thd.selend and _thd.place_mode (set elsewhere) to determine _thd.pos and _thd.size - * Also drawstyle is determined. Uses _thd.new.* as a buffer and calls SetSelectionTilesDirty() twice, - * Once for the old and once for the new selection. - * _thd is TileHighlightData, found in viewport.h - */ -void UpdateTileSelection() -{ - int x1; - int y1; - - HighLightStyle new_drawstyle = HT_NONE; - bool new_diagonal = false; - - if ((_thd.place_mode & HT_DRAG_MASK) == HT_SPECIAL) { - x1 = _thd.selend.x; - y1 = _thd.selend.y; - if (x1 != -1) { - int x2 = _thd.selstart.x & ~TILE_UNIT_MASK; - int y2 = _thd.selstart.y & ~TILE_UNIT_MASK; - x1 &= ~TILE_UNIT_MASK; - y1 &= ~TILE_UNIT_MASK; - - if (_thd.IsDraggingDiagonal()) { - new_diagonal = true; - } else { - if (x1 >= x2) Swap(x1, x2); - if (y1 >= y2) Swap(y1, y2); - } - _thd.new_pos.x = x1; - _thd.new_pos.y = y1; - _thd.new_size.x = x2 - x1; - _thd.new_size.y = y2 - y1; - if (!new_diagonal) { - _thd.new_size.x += TILE_SIZE; - _thd.new_size.y += TILE_SIZE; - } - new_drawstyle = _thd.next_drawstyle; - } - } else if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) { - Point pt = GetTileBelowCursor(); - x1 = pt.x; - y1 = pt.y; - if (x1 != -1) { - switch (_thd.place_mode & HT_DRAG_MASK) { - case HT_RECT: - new_drawstyle = HT_RECT; - break; - case HT_POINT: - new_drawstyle = HT_POINT; - x1 += TILE_SIZE / 2; - y1 += TILE_SIZE / 2; - break; - case HT_RAIL: - /* Draw one highlighted tile in any direction */ - new_drawstyle = GetAutorailHT(pt.x, pt.y); - break; - case HT_LINE: - switch (_thd.place_mode & HT_DIR_MASK) { - case HT_DIR_X: new_drawstyle = HT_LINE | HT_DIR_X; break; - case HT_DIR_Y: new_drawstyle = HT_LINE | HT_DIR_Y; break; - - case HT_DIR_HU: - case HT_DIR_HL: - new_drawstyle = (pt.x & TILE_UNIT_MASK) + (pt.y & TILE_UNIT_MASK) <= TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL; - break; - - case HT_DIR_VL: - case HT_DIR_VR: - new_drawstyle = (pt.x & TILE_UNIT_MASK) > (pt.y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; - break; - - default: NOT_REACHED(); - } - _thd.selstart.x = x1 & ~TILE_UNIT_MASK; - _thd.selstart.y = y1 & ~TILE_UNIT_MASK; - break; - default: - NOT_REACHED(); - break; - } - _thd.new_pos.x = x1 & ~TILE_UNIT_MASK; - _thd.new_pos.y = y1 & ~TILE_UNIT_MASK; - } - } - - /* redraw selection */ - if (_thd.drawstyle != new_drawstyle || - _thd.pos.x != _thd.new_pos.x || _thd.pos.y != _thd.new_pos.y || - _thd.size.x != _thd.new_size.x || _thd.size.y != _thd.new_size.y || - _thd.outersize.x != _thd.new_outersize.x || - _thd.outersize.y != _thd.new_outersize.y || - _thd.diagonal != new_diagonal) { - /* Clear the old tile selection? */ - if ((_thd.drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty(); - - _thd.drawstyle = new_drawstyle; - _thd.pos = _thd.new_pos; - _thd.size = _thd.new_size; - _thd.outersize = _thd.new_outersize; - _thd.diagonal = new_diagonal; - _thd.dirty = 0xff; - - /* Draw the new tile selection? */ - if ((new_drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty(); - } -} - -/** - * Displays the measurement tooltips when selecting multiple tiles - * @param str String to be displayed - * @param paramcount number of params to deal with - * @param params (optional) up to 5 pieces of additional information that may be added to a tooltip - * @param close_cond Condition for closing this tooltip. - */ -static inline void ShowMeasurementTooltips(StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_cond = TCC_LEFT_CLICK) -{ - if (!_settings_client.gui.measure_tooltip) return; - GuiShowTooltips(_thd.GetCallbackWnd(), str, paramcount, params, close_cond); -} - -/** highlighting tiles while only going over them with the mouse */ -void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process) -{ - _thd.select_method = method; - _thd.select_proc = process; - _thd.selend.x = TileX(tile) * TILE_SIZE; - _thd.selstart.x = TileX(tile) * TILE_SIZE; - _thd.selend.y = TileY(tile) * TILE_SIZE; - _thd.selstart.y = TileY(tile) * TILE_SIZE; - - /* Needed so several things (road, autoroad, bridges, ...) are placed correctly. - * In effect, placement starts from the centre of a tile - */ - if (method == VPM_X_OR_Y || method == VPM_FIX_X || method == VPM_FIX_Y) { - _thd.selend.x += TILE_SIZE / 2; - _thd.selend.y += TILE_SIZE / 2; - _thd.selstart.x += TILE_SIZE / 2; - _thd.selstart.y += TILE_SIZE / 2; - } - - HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK); - if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT) { - _thd.place_mode = HT_SPECIAL | others; - _thd.next_drawstyle = HT_RECT | others; - } else if (_thd.place_mode & (HT_RAIL | HT_LINE)) { - _thd.place_mode = HT_SPECIAL | others; - _thd.next_drawstyle = _thd.drawstyle | others; - } else { - _thd.place_mode = HT_SPECIAL | others; - _thd.next_drawstyle = HT_POINT | others; - } - _special_mouse_mode = WSM_SIZING; -} - -void VpSetPlaceSizingLimit(int limit) -{ - _thd.sizelimit = limit; -} - -/** - * Highlights all tiles between a set of two tiles. Used in dock and tunnel placement - * @param from TileIndex of the first tile to highlight - * @param to TileIndex of the last tile to highlight - */ -void VpSetPresizeRange(TileIndex from, TileIndex to) -{ - uint64 distance = DistanceManhattan(from, to) + 1; - - _thd.selend.x = TileX(to) * TILE_SIZE; - _thd.selend.y = TileY(to) * TILE_SIZE; - _thd.selstart.x = TileX(from) * TILE_SIZE; - _thd.selstart.y = TileY(from) * TILE_SIZE; - _thd.next_drawstyle = HT_RECT; - - /* show measurement only if there is any length to speak of */ - if (distance > 1) ShowMeasurementTooltips(STR_MEASURE_LENGTH, 1, &distance, TCC_HOVER); -} - -void VpStartPreSizing() -{ - _thd.selend.x = -1; - _special_mouse_mode = WSM_PRESIZE; -} - -/** - * returns information about the 2x1 piece to be build. - * The lower bits (0-3) are the track type. - */ -static HighLightStyle Check2x1AutoRail(int mode) -{ - int fxpy = _tile_fract_coords.x + _tile_fract_coords.y; - int sxpy = (_thd.selend.x & TILE_UNIT_MASK) + (_thd.selend.y & TILE_UNIT_MASK); - int fxmy = _tile_fract_coords.x - _tile_fract_coords.y; - int sxmy = (_thd.selend.x & TILE_UNIT_MASK) - (_thd.selend.y & TILE_UNIT_MASK); - - switch (mode) { - default: NOT_REACHED(); - case 0: // end piece is lower right - if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL; - if (fxmy < -3 && sxmy > 3) return HT_DIR_VR; - return HT_DIR_Y; - - case 1: - if (fxmy > 3 && sxmy < -3) return HT_DIR_VL; - if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU; - return HT_DIR_Y; - - case 2: - if (fxmy > 3 && sxmy < -3) return HT_DIR_VL; - if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL; - return HT_DIR_X; - - case 3: - if (fxmy < -3 && sxmy > 3) return HT_DIR_VR; - if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU; - return HT_DIR_X; - } -} - -/** - * Check if the direction of start and end tile should be swapped based on - * the dragging-style. Default directions are: - * in the case of a line (HT_RAIL, HT_LINE): DIR_NE, DIR_NW, DIR_N, DIR_E - * in the case of a rect (HT_RECT, HT_POINT): DIR_S, DIR_E - * For example dragging a rectangle area from south to north should be swapped to - * north-south (DIR_S) to obtain the same results with less code. This is what - * the return value signifies. - * @param style HighLightStyle dragging style - * @param start_tile start tile of drag - * @param end_tile end tile of drag - * @return boolean value which when true means start/end should be swapped - */ -static bool SwapDirection(HighLightStyle style, TileIndex start_tile, TileIndex end_tile) -{ - uint start_x = TileX(start_tile); - uint start_y = TileY(start_tile); - uint end_x = TileX(end_tile); - uint end_y = TileY(end_tile); - - switch (style & HT_DRAG_MASK) { - case HT_RAIL: - case HT_LINE: return (end_x > start_x || (end_x == start_x && end_y > start_y)); - - case HT_RECT: - case HT_POINT: return (end_x != start_x && end_y < start_y); - default: NOT_REACHED(); - } - - return false; -} - -/** - * Calculates height difference between one tile and another. - * Multiplies the result to suit the standard given by #TILE_HEIGHT_STEP. - * - * To correctly get the height difference we need the direction we are dragging - * in, as well as with what kind of tool we are dragging. For example a horizontal - * autorail tool that starts in bottom and ends at the top of a tile will need the - * maximum of SW, S and SE, N corners respectively. This is handled by the lookup table below - * See #_tileoffs_by_dir in map.cpp for the direction enums if you can't figure out the values yourself. - * @param style Highlighting style of the drag. This includes direction and style (autorail, rect, etc.) - * @param distance Number of tiles dragged, important for horizontal/vertical drags, ignored for others. - * @param start_tile Start tile of the drag operation. - * @param end_tile End tile of the drag operation. - * @return Height difference between two tiles. The tile measurement tool utilizes this value in its tooltip. - */ -static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_tile, TileIndex end_tile) -{ - bool swap = SwapDirection(style, start_tile, end_tile); - uint h0, h1; // Start height and end height. - - if (start_tile == end_tile) return 0; - if (swap) Swap(start_tile, end_tile); - - switch (style & HT_DRAG_MASK) { - case HT_RECT: { - static const TileIndexDiffC heightdiff_area_by_dir[] = { - /* Start */ {1, 0}, /* Dragging east */ {0, 0}, // Dragging south - /* End */ {0, 1}, /* Dragging east */ {1, 1} // Dragging south - }; - - /* In the case of an area we can determine whether we were dragging south or - * east by checking the X-coordinates of the tiles */ - byte style_t = (byte)(TileX(end_tile) > TileX(start_tile)); - start_tile = TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_area_by_dir[style_t])); - end_tile = TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_area_by_dir[2 + style_t])); - /* FALL THROUGH */ - } - - case HT_POINT: - h0 = TileHeight(start_tile); - h1 = TileHeight(end_tile); - break; - default: { // All other types, this is mostly only line/autorail - static const HighLightStyle flip_style_direction[] = { - HT_DIR_X, HT_DIR_Y, HT_DIR_HL, HT_DIR_HU, HT_DIR_VR, HT_DIR_VL - }; - static const TileIndexDiffC heightdiff_line_by_dir[] = { - /* Start */ {1, 0}, {1, 1}, /* HT_DIR_X */ {0, 1}, {1, 1}, // HT_DIR_Y - /* Start */ {1, 0}, {0, 0}, /* HT_DIR_HU */ {1, 0}, {1, 1}, // HT_DIR_HL - /* Start */ {1, 0}, {1, 1}, /* HT_DIR_VL */ {0, 1}, {1, 1}, // HT_DIR_VR - - /* Start */ {0, 1}, {0, 0}, /* HT_DIR_X */ {1, 0}, {0, 0}, // HT_DIR_Y - /* End */ {0, 1}, {0, 0}, /* HT_DIR_HU */ {1, 1}, {0, 1}, // HT_DIR_HL - /* End */ {1, 0}, {0, 0}, /* HT_DIR_VL */ {0, 0}, {0, 1}, // HT_DIR_VR - }; - - distance %= 2; // we're only interested if the distance is even or uneven - style &= HT_DIR_MASK; - - /* To handle autorail, we do some magic to be able to use a lookup table. - * Firstly if we drag the other way around, we switch start&end, and if needed - * also flip the drag-position. Eg if it was on the left, and the distance is even - * that means the end, which is now the start is on the right */ - if (swap && distance == 0) style = flip_style_direction[style]; - - /* Use lookup table for start-tile based on HighLightStyle direction */ - byte style_t = style * 2; - assert(style_t < lengthof(heightdiff_line_by_dir) - 13); - h0 = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t]))); - uint ht = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t + 1]))); - h0 = max(h0, ht); - - /* Use lookup table for end-tile based on HighLightStyle direction - * flip around side (lower/upper, left/right) based on distance */ - if (distance == 0) style_t = flip_style_direction[style] * 2; - assert(style_t < lengthof(heightdiff_line_by_dir) - 13); - h1 = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t]))); - ht = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t + 1]))); - h1 = max(h1, ht); - break; - } - } - - if (swap) Swap(h0, h1); - return (int)(h1 - h0) * TILE_HEIGHT_STEP; -} - -static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF}; - -/** - * Check for underflowing the map. - * @param test the variable to test for underflowing - * @param other the other variable to update to keep the line - * @param mult the constant to multiply the difference by for \c other - */ -static void CheckUnderflow(int &test, int &other, int mult) -{ - if (test >= 0) return; - - other += mult * test; - test = 0; -} - -/** - * Check for overflowing the map. - * @param test the variable to test for overflowing - * @param other the other variable to update to keep the line - * @param max the maximum value for the \c test variable - * @param mult the constant to multiply the difference by for \c other - */ -static void CheckOverflow(int &test, int &other, int max, int mult) -{ - if (test <= max) return; - - other += mult * (test - max); - test = max; -} - -/** while dragging */ -static void CalcRaildirsDrawstyle(int x, int y, int method) -{ - HighLightStyle b; - - int dx = _thd.selstart.x - (_thd.selend.x & ~TILE_UNIT_MASK); - int dy = _thd.selstart.y - (_thd.selend.y & ~TILE_UNIT_MASK); - uint w = abs(dx) + TILE_SIZE; - uint h = abs(dy) + TILE_SIZE; - - if (method & ~(VPM_RAILDIRS | VPM_SIGNALDIRS)) { - /* We 'force' a selection direction; first four rail buttons. */ - method &= ~(VPM_RAILDIRS | VPM_SIGNALDIRS); - int raw_dx = _thd.selstart.x - _thd.selend.x; - int raw_dy = _thd.selstart.y - _thd.selend.y; - switch (method) { - case VPM_FIX_X: - b = HT_LINE | HT_DIR_Y; - x = _thd.selstart.x; - break; - - case VPM_FIX_Y: - b = HT_LINE | HT_DIR_X; - y = _thd.selstart.y; - break; - - case VPM_FIX_HORIZONTAL: - if (dx == -dy) { - /* We are on a straight horizontal line. Determine the 'rail' - * to build based the sub tile location. */ - b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU; - } else { - /* We are not on a straight line. Determine the rail to build - * based on whether we are above or below it. */ - b = dx + dy >= (int)TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL; - - /* Calculate where a horizontal line through the start point and - * a vertical line from the selected end point intersect and - * use that point as the end point. */ - int offset = (raw_dx - raw_dy) / 2; - x = _thd.selstart.x - (offset & ~TILE_UNIT_MASK); - y = _thd.selstart.y + (offset & ~TILE_UNIT_MASK); - - /* 'Build' the last half rail tile if needed */ - if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) { - if (dx + dy >= (int)TILE_SIZE) { - x += (dx + dy < 0) ? (int)TILE_SIZE : -(int)TILE_SIZE; - } else { - y += (dx + dy < 0) ? (int)TILE_SIZE : -(int)TILE_SIZE; - } - } - - /* Make sure we do not overflow the map! */ - CheckUnderflow(x, y, 1); - CheckUnderflow(y, x, 1); - CheckOverflow(x, y, (MapMaxX() - 1) * TILE_SIZE, 1); - CheckOverflow(y, x, (MapMaxY() - 1) * TILE_SIZE, 1); - assert(x >= 0 && y >= 0 && x <= (int)(MapMaxX() * TILE_SIZE) && y <= (int)(MapMaxY() * TILE_SIZE)); - } - break; - - case VPM_FIX_VERTICAL: - if (dx == dy) { - /* We are on a straight vertical line. Determine the 'rail' - * to build based the sub tile location. */ - b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; - } else { - /* We are not on a straight line. Determine the rail to build - * based on whether we are left or right from it. */ - b = dx < dy ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; - - /* Calculate where a vertical line through the start point and - * a horizontal line from the selected end point intersect and - * use that point as the end point. */ - int offset = (raw_dx + raw_dy + (int)TILE_SIZE) / 2; - x = _thd.selstart.x - (offset & ~TILE_UNIT_MASK); - y = _thd.selstart.y - (offset & ~TILE_UNIT_MASK); - - /* 'Build' the last half rail tile if needed */ - if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) { - if (dx - dy < 0) { - y += (dx > dy) ? (int)TILE_SIZE : -(int)TILE_SIZE; - } else { - x += (dx < dy) ? (int)TILE_SIZE : -(int)TILE_SIZE; - } - } - - /* Make sure we do not overflow the map! */ - CheckUnderflow(x, y, -1); - CheckUnderflow(y, x, -1); - CheckOverflow(x, y, (MapMaxX() - 1) * TILE_SIZE, -1); - CheckOverflow(y, x, (MapMaxY() - 1) * TILE_SIZE, -1); - assert(x >= 0 && y >= 0 && x <= (int)(MapMaxX() * TILE_SIZE) && y <= (int)(MapMaxY() * TILE_SIZE)); - } - break; - - default: - NOT_REACHED(); - } - } else if (TileVirtXY(_thd.selstart.x, _thd.selstart.y) == TileVirtXY(x, y)) { // check if we're only within one tile - if (method & VPM_RAILDIRS) { - b = GetAutorailHT(x, y); - } else { // rect for autosignals on one tile - b = HT_RECT; - } - } else if (h == TILE_SIZE) { // Is this in X direction? - if (dx == (int)TILE_SIZE) { // 2x1 special handling - b = (Check2x1AutoRail(3)) | HT_LINE; - } else if (dx == -(int)TILE_SIZE) { - b = (Check2x1AutoRail(2)) | HT_LINE; - } else { - b = HT_LINE | HT_DIR_X; - } - y = _thd.selstart.y; - } else if (w == TILE_SIZE) { // Or Y direction? - if (dy == (int)TILE_SIZE) { // 2x1 special handling - b = (Check2x1AutoRail(1)) | HT_LINE; - } else if (dy == -(int)TILE_SIZE) { // 2x1 other direction - b = (Check2x1AutoRail(0)) | HT_LINE; - } else { - b = HT_LINE | HT_DIR_Y; - } - x = _thd.selstart.x; - } else if (w > h * 2) { // still count as x dir? - b = HT_LINE | HT_DIR_X; - y = _thd.selstart.y; - } else if (h > w * 2) { // still count as y dir? - b = HT_LINE | HT_DIR_Y; - x = _thd.selstart.x; - } else { // complicated direction - int d = w - h; - _thd.selend.x = _thd.selend.x & ~TILE_UNIT_MASK; - _thd.selend.y = _thd.selend.y & ~TILE_UNIT_MASK; - - /* four cases. */ - if (x > _thd.selstart.x) { - if (y > _thd.selstart.y) { - /* south */ - if (d == 0) { - b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; - } else if (d >= 0) { - x = _thd.selstart.x + h; - b = HT_LINE | HT_DIR_VL; - } else { - y = _thd.selstart.y + w; - b = HT_LINE | HT_DIR_VR; - } - } else { - /* west */ - if (d == 0) { - b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU; - } else if (d >= 0) { - x = _thd.selstart.x + h; - b = HT_LINE | HT_DIR_HL; - } else { - y = _thd.selstart.y - w; - b = HT_LINE | HT_DIR_HU; - } - } - } else { - if (y > _thd.selstart.y) { - /* east */ - if (d == 0) { - b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU; - } else if (d >= 0) { - x = _thd.selstart.x - h; - b = HT_LINE | HT_DIR_HU; - } else { - y = _thd.selstart.y + w; - b = HT_LINE | HT_DIR_HL; - } - } else { - /* north */ - if (d == 0) { - b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; - } else if (d >= 0) { - x = _thd.selstart.x - h; - b = HT_LINE | HT_DIR_VR; - } else { - y = _thd.selstart.y - w; - b = HT_LINE | HT_DIR_VL; - } - } - } - } - - if (_settings_client.gui.measure_tooltip) { - TileIndex t0 = TileVirtXY(_thd.selstart.x, _thd.selstart.y); - TileIndex t1 = TileVirtXY(x, y); - uint distance = DistanceManhattan(t0, t1) + 1; - byte index = 0; - uint64 params[2]; - - if (distance != 1) { - int heightdiff = CalcHeightdiff(b, distance, t0, t1); - /* If we are showing a tooltip for horizontal or vertical drags, - * 2 tiles have a length of 1. To bias towards the ceiling we add - * one before division. It feels more natural to count 3 lengths as 2 */ - if ((b & HT_DIR_MASK) != HT_DIR_X && (b & HT_DIR_MASK) != HT_DIR_Y) { - distance = CeilDiv(distance, 2); - } - - params[index++] = distance; - if (heightdiff != 0) params[index++] = heightdiff; - } - - ShowMeasurementTooltips(measure_strings_length[index], index, params); - } - - _thd.selend.x = x; - _thd.selend.y = y; - _thd.next_drawstyle = b; -} - -/** - * Selects tiles while dragging - * @param x X coordinate of end of selection - * @param y Y coordinate of end of selection - * @param method modifies the way tiles are selected. Possible - * methods are VPM_* in viewport.h - */ -void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method) -{ - int sx, sy; - HighLightStyle style; - - if (x == -1) { - _thd.selend.x = -1; - return; - } - - /* Special handling of drag in any (8-way) direction */ - if (method & (VPM_RAILDIRS | VPM_SIGNALDIRS)) { - _thd.selend.x = x; - _thd.selend.y = y; - CalcRaildirsDrawstyle(x, y, method); - return; - } - - /* Needed so level-land is placed correctly */ - if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_POINT) { - x += TILE_SIZE / 2; - y += TILE_SIZE / 2; - } - - sx = _thd.selstart.x; - sy = _thd.selstart.y; - - int limit = 0; - - switch (method) { - case VPM_X_OR_Y: // drag in X or Y direction - if (abs(sy - y) < abs(sx - x)) { - y = sy; - style = HT_DIR_X; - } else { - x = sx; - style = HT_DIR_Y; - } - goto calc_heightdiff_single_direction; - - case VPM_X_LIMITED: // Drag in X direction (limited size). - limit = (_thd.sizelimit - 1) * TILE_SIZE; - /* FALL THROUGH */ - - case VPM_FIX_X: // drag in Y direction - x = sx; - style = HT_DIR_Y; - goto calc_heightdiff_single_direction; - - case VPM_Y_LIMITED: // Drag in Y direction (limited size). - limit = (_thd.sizelimit - 1) * TILE_SIZE; - /* FALL THROUGH */ - - case VPM_FIX_Y: // drag in X direction - y = sy; - style = HT_DIR_X; - -calc_heightdiff_single_direction:; - if (limit > 0) { - x = sx + Clamp(x - sx, -limit, limit); - y = sy + Clamp(y - sy, -limit, limit); - } - if (_settings_client.gui.measure_tooltip) { - TileIndex t0 = TileVirtXY(sx, sy); - TileIndex t1 = TileVirtXY(x, y); - uint distance = DistanceManhattan(t0, t1) + 1; - byte index = 0; - uint64 params[2]; - - if (distance != 1) { - /* With current code passing a HT_LINE style to calculate the height - * difference is enough. However if/when a point-tool is created - * with this method, function should be called with new_style (below) - * instead of HT_LINE | style case HT_POINT is handled specially - * new_style := (_thd.next_drawstyle & HT_RECT) ? HT_LINE | style : _thd.next_drawstyle; */ - int heightdiff = CalcHeightdiff(HT_LINE | style, 0, t0, t1); - - params[index++] = distance; - if (heightdiff != 0) params[index++] = heightdiff; - } - - ShowMeasurementTooltips(measure_strings_length[index], index, params); - } - break; - - case VPM_X_AND_Y_LIMITED: // Drag an X by Y constrained rect area. - limit = (_thd.sizelimit - 1) * TILE_SIZE; - x = sx + Clamp(x - sx, -limit, limit); - y = sy + Clamp(y - sy, -limit, limit); - /* FALL THROUGH */ - - case VPM_X_AND_Y: // drag an X by Y area - if (_settings_client.gui.measure_tooltip) { - static const StringID measure_strings_area[] = { - STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF - }; - - TileIndex t0 = TileVirtXY(sx, sy); - TileIndex t1 = TileVirtXY(x, y); - uint dx = Delta(TileX(t0), TileX(t1)) + 1; - uint dy = Delta(TileY(t0), TileY(t1)) + 1; - byte index = 0; - uint64 params[3]; - - /* If dragging an area (eg dynamite tool) and it is actually a single - * row/column, change the type to 'line' to get proper calculation for height */ - style = (HighLightStyle)_thd.next_drawstyle; - if (_thd.IsDraggingDiagonal()) { - /* Determine the "area" of the diagonal dragged selection. - * We assume the area is the number of tiles along the X - * edge and the number of tiles along the Y edge. However, - * multiplying these two numbers does not give the exact - * number of tiles; basically we are counting the black - * squares on a chess board and ignore the white ones to - * make the tile counts at the edges match up. There is no - * other way to make a proper count though. - * - * First convert to the rotated coordinate system. */ - int dist_x = TileX(t0) - TileX(t1); - int dist_y = TileY(t0) - TileY(t1); - int a_max = dist_x + dist_y; - int b_max = dist_y - dist_x; - - /* Now determine the size along the edge, but due to the - * chess board principle this counts double. */ - a_max = abs(a_max + (a_max > 0 ? 2 : -2)) / 2; - b_max = abs(b_max + (b_max > 0 ? 2 : -2)) / 2; - - /* We get a 1x1 on normal 2x1 rectangles, due to it being - * a seen as two sides. As the result for actual building - * will be the same as non-diagonal dragging revert to that - * behaviour to give it a more normally looking size. */ - if (a_max != 1 || b_max != 1) { - dx = a_max; - dy = b_max; - } - } else if (style & HT_RECT) { - if (dx == 1) { - style = HT_LINE | HT_DIR_Y; - } else if (dy == 1) { - style = HT_LINE | HT_DIR_X; - } - } - - if (dx != 1 || dy != 1) { - int heightdiff = CalcHeightdiff(style, 0, t0, t1); - - params[index++] = dx - (style & HT_POINT ? 1 : 0); - params[index++] = dy - (style & HT_POINT ? 1 : 0); - if (heightdiff != 0) params[index++] = heightdiff; - } - - ShowMeasurementTooltips(measure_strings_area[index], index, params); - } - break; - - default: NOT_REACHED(); - } - - _thd.selend.x = x; - _thd.selend.y = y; -} - -/** - * Handle the mouse while dragging for placement/resizing. - * @return State of handling the event. - */ -EventState VpHandlePlaceSizingDrag() -{ - if (_special_mouse_mode != WSM_SIZING) return ES_NOT_HANDLED; - - /* stop drag mode if the window has been closed */ - Window *w = _thd.GetCallbackWnd(); - if (w == NULL) { - ResetObjectToPlace(); - return ES_HANDLED; - } - - /* while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ) */ - if (_left_button_down) { - w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor()); - return ES_HANDLED; - } - - /* mouse button released.. - * keep the selected tool, but reset it to the original mode. */ - _special_mouse_mode = WSM_NONE; - HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK); - if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_RECT) { - _thd.place_mode = HT_RECT | others; - } else if (_thd.select_method & VPM_SIGNALDIRS) { - _thd.place_mode = HT_RECT | others; - } else if (_thd.select_method & VPM_RAILDIRS) { - _thd.place_mode = (_thd.select_method & ~VPM_RAILDIRS) ? _thd.next_drawstyle : (HT_RAIL | others); - } else { - _thd.place_mode = HT_POINT | others; - } - SetTileSelectSize(1, 1); - - w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y)); - - return ES_HANDLED; -} - -void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w) -{ - SetObjectToPlace(icon, pal, mode, w->window_class, w->window_number); -} - -#include "table/animcursors.h" - -void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num) -{ - if (_thd.window_class != WC_INVALID) { - /* Undo clicking on button and drag & drop */ - Window *w = _thd.GetCallbackWnd(); - /* Call the abort function, but set the window class to something - * that will never be used to avoid infinite loops. Setting it to - * the 'next' window class must not be done because recursion into - * this function might in some cases reset the newly set object to - * place or not properly reset the original selection. */ - _thd.window_class = WC_INVALID; - if (w != NULL) w->OnPlaceObjectAbort(); - } - - /* Mark the old selection dirty, in case the selection shape or colour changes */ - if ((_thd.drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty(); - - SetTileSelectSize(1, 1); - - _thd.make_square_red = false; - - if (mode == HT_DRAG) { // HT_DRAG is for dragdropping trains in the depot window - mode = HT_NONE; - _special_mouse_mode = WSM_DRAGDROP; - } else { - _special_mouse_mode = WSM_NONE; - } - - _thd.place_mode = mode; - _thd.window_class = window_class; - _thd.window_number = window_num; - - if ((mode & HT_DRAG_MASK) == HT_SPECIAL) { // special tools, like tunnels or docks start with presizing mode - VpStartPreSizing(); - } - - if ((icon & ANIMCURSOR_FLAG) != 0) { - SetAnimatedMouseCursor(_animcursors[icon & ~ANIMCURSOR_FLAG]); - } else { - SetMouseCursor(icon, pal); - } - -} - -void ResetObjectToPlace() -{ - SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0); -} - -Point GetViewportStationMiddle(const ViewPort *vp, const Station *st) -{ - int x = TileX(st->xy) * TILE_SIZE; - int y = TileY(st->xy) * TILE_SIZE; - int z = GetSlopePixelZ(Clamp(x, 0, MapSizeX() * TILE_SIZE - 1), Clamp(y, 0, MapSizeY() * TILE_SIZE - 1)); - - Point p = RemapCoords(x, y, z); - p.x = UnScaleByZoom(p.x - vp->virtual_left, vp->zoom) + vp->left; - p.y = UnScaleByZoom(p.y - vp->virtual_top, vp->zoom) + vp->top; - return p; -} - -/** Helper class for getting the best sprite sorter. */ -struct ViewportSSCSS { - VpSorterChecker fct_checker; ///< The check function. - VpSpriteSorter fct_sorter; ///< The sorting function. -}; - -/** List of sorters ordered from best to worst. */ -static ViewportSSCSS _vp_sprite_sorters[] = { -#ifdef WITH_SSE - { &ViewportSortParentSpritesSSE41Checker, &ViewportSortParentSpritesSSE41 }, -#endif - { &ViewportSortParentSpritesChecker, &ViewportSortParentSprites } -}; - -/** Choose the "best" sprite sorter and set _vp_sprite_sorter. */ -void InitializeSpriteSorter() -{ - for (uint i = 0; i < lengthof(_vp_sprite_sorters); i++) { - if (_vp_sprite_sorters[i].fct_checker()) { - _vp_sprite_sorter = _vp_sprite_sorters[i].fct_sorter; - break; - } - } - assert(_vp_sprite_sorter != NULL); -} diff --git a/src/widget.cpp.orig b/src/widget.cpp.orig deleted file mode 100644 index 1acdcf74d7..0000000000 --- a/src/widget.cpp.orig +++ /dev/null @@ -1,2932 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file widget.cpp Handling of the default/simple widgets. */ - -#include "stdafx.h" -#include "company_func.h" -#include "window_gui.h" -#include "viewport_func.h" -#include "zoom_func.h" -#include "strings_func.h" -#include "transparency.h" -#include "core/geometry_func.hpp" -#include "settings_type.h" -#include "querystring_gui.h" - -#include "table/sprites.h" -#include "table/strings.h" -#include "table/palettes.h" - -static const char *UPARROW = "\xEE\x8A\xA0"; ///< String containing an upwards pointing arrow. -static const char *DOWNARROW = "\xEE\x8A\xAA"; ///< String containing a downwards pointing arrow. - -/** - * Compute the vertical position of the draggable part of scrollbar - * @param sb Scrollbar list data - * @param top Top position of the scrollbar (top position of the up-button) - * @param bottom Bottom position of the scrollbar (bottom position of the down-button) - * @param horizontal Whether the scrollbar is horizontal or not - * @return A Point, with x containing the top coordinate of the draggable part, and - * y containing the bottom coordinate of the draggable part - */ -static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom, bool horizontal) -{ - /* Base for reversion */ - int rev_base = top + bottom; - int button_size; - if (horizontal) { - button_size = NWidgetScrollbar::GetHorizontalDimension().width; - } else { - button_size = NWidgetScrollbar::GetVerticalDimension().height; - } - top += button_size; // top points to just below the up-button - bottom -= button_size; // bottom points to top of the down-button - - int height = (bottom - top); - int pos = sb->GetPosition(); - int count = sb->GetCount(); - int cap = sb->GetCapacity(); - - if (count != 0) top += height * pos / count; - - if (cap > count) cap = count; - if (count != 0) bottom -= (count - pos - cap) * height / count; - - Point pt; - if (horizontal && _current_text_dir == TD_RTL) { - pt.x = rev_base - bottom; - pt.y = rev_base - top; - } else { - pt.x = top; - pt.y = bottom; - } - return pt; -} - -/** - * Compute new position of the scrollbar after a click and updates the window flags. - * @param w Window on which a scroll was performed. - * @param sb Scrollbar - * @param mi Minimum coordinate of the scroll bar. - * @param ma Maximum coordinate of the scroll bar. - * @param x The X coordinate of the mouse click. - * @param y The Y coordinate of the mouse click. - */ -static void ScrollbarClickPositioning(Window *w, NWidgetScrollbar *sb, int x, int y, int mi, int ma) -{ - int pos; - int button_size; - bool rtl = false; - - if (sb->type == NWID_HSCROLLBAR) { - pos = x; - rtl = _current_text_dir == TD_RTL; - button_size = NWidgetScrollbar::GetHorizontalDimension().width; - } else { - pos = y; - button_size = NWidgetScrollbar::GetVerticalDimension().height; - } - if (pos < mi + button_size) { - /* Pressing the upper button? */ - SetBit(sb->disp_flags, NDB_SCROLLBAR_UP); - if (_scroller_click_timeout <= 1) { - _scroller_click_timeout = 3; - sb->UpdatePosition(rtl ? 1 : -1); - } - w->scrolling_scrollbar = sb->index; - } else if (pos >= ma - button_size) { - /* Pressing the lower button? */ - SetBit(sb->disp_flags, NDB_SCROLLBAR_DOWN); - - if (_scroller_click_timeout <= 1) { - _scroller_click_timeout = 3; - sb->UpdatePosition(rtl ? -1 : 1); - } - w->scrolling_scrollbar = sb->index; - } else { - Point pt = HandleScrollbarHittest(sb, mi, ma, sb->type == NWID_HSCROLLBAR); - - if (pos < pt.x) { - sb->UpdatePosition(rtl ? 1 : -1, Scrollbar::SS_BIG); - } else if (pos > pt.y) { - sb->UpdatePosition(rtl ? -1 : 1, Scrollbar::SS_BIG); - } else { - _scrollbar_start_pos = pt.x - mi - button_size; - _scrollbar_size = ma - mi - button_size * 2; - w->scrolling_scrollbar = sb->index; - _cursorpos_drag_start = _cursor.pos; - } - } - - w->SetDirty(); -} - -/** - * Special handling for the scrollbar widget type. - * Handles the special scrolling buttons and other scrolling. - * @param w Window on which a scroll was performed. - * @param nw Pointer to the scrollbar widget. - * @param x The X coordinate of the mouse click. - * @param y The Y coordinate of the mouse click. - */ -void ScrollbarClickHandler(Window *w, NWidgetCore *nw, int x, int y) -{ - int mi, ma; - - if (nw->type == NWID_HSCROLLBAR) { - mi = nw->pos_x; - ma = nw->pos_x + nw->current_x; - } else { - mi = nw->pos_y; - ma = nw->pos_y + nw->current_y; - } - NWidgetScrollbar *scrollbar = dynamic_cast(nw); - assert(scrollbar != NULL); - ScrollbarClickPositioning(w, scrollbar, x, y, mi, ma); -} - -/** - * Returns the index for the widget located at the given position - * relative to the window. It includes all widget-corner pixels as well. - * @param *w Window to look inside - * @param x The Window client X coordinate - * @param y The Window client y coordinate - * @return A widget index, or -1 if no widget was found. - */ -int GetWidgetFromPos(const Window *w, int x, int y) -{ - NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y); - return (nw != NULL) ? nw->index : -1; -} - -/** - * Draw frame rectangle. - * @param left Left edge of the frame - * @param top Top edge of the frame - * @param right Right edge of the frame - * @param bottom Bottom edge of the frame - * @param colour Colour table to use. @see _colour_gradient - * @param flags Flags controlling how to draw the frame. @see FrameFlags - */ -void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags) -{ - assert(colour < COLOUR_END); - - uint dark = _colour_gradient[colour][3]; - uint medium_dark = _colour_gradient[colour][5]; - uint medium_light = _colour_gradient[colour][6]; - uint light = _colour_gradient[colour][7]; - - if (flags & FR_TRANSPARENT) { - GfxFillRect(left, top, right, bottom, PALETTE_TO_TRANSPARENT, FILLRECT_RECOLOUR); - } else { - uint interior; - - if (flags & FR_LOWERED) { - GfxFillRect(left, top, left, bottom, dark); - GfxFillRect(left + WD_BEVEL_LEFT, top, right, top, dark); - GfxFillRect(right, top + WD_BEVEL_TOP, right, bottom - WD_BEVEL_BOTTOM, light); - GfxFillRect(left + WD_BEVEL_LEFT, bottom, right, bottom, light); - interior = (flags & FR_DARKENED ? medium_dark : medium_light); - } else { - GfxFillRect(left, top, left, bottom - WD_BEVEL_BOTTOM, light); - GfxFillRect(left + WD_BEVEL_LEFT, top, right - WD_BEVEL_RIGHT, top, light); - GfxFillRect(right, top, right, bottom - WD_BEVEL_BOTTOM, dark); - GfxFillRect(left, bottom, right, bottom, dark); - interior = medium_dark; - } - if (!(flags & FR_BORDERONLY)) { - GfxFillRect(left + WD_BEVEL_LEFT, top + WD_BEVEL_TOP, right - WD_BEVEL_RIGHT, bottom - WD_BEVEL_BOTTOM, interior); - } - } -} - -/** - * Draw an image button. - * @param r Rectangle of the button. - * @param type Widget type (#WWT_IMGBTN or #WWT_IMGBTN_2). - * @param colour Colour of the button. - * @param clicked Button is lowered. - * @param img Sprite to draw. - */ -static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colour, bool clicked, SpriteID img) -{ - assert(img != 0); - DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); - - if ((type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++; // Show different image when clicked for #WWT_IMGBTN_2. - Dimension d2 = GetSpriteSize(img); - DrawSprite(img, PAL_NONE, Center(r.left + clicked, r.right - r.left, d2.width), Center(r.top + clicked, r.bottom - r.top, d2.height)); -} - -/** - * Draw the label-part of a widget. - * @param r Rectangle of the label background. - * @param type Widget type (#WWT_TEXTBTN, #WWT_TEXTBTN_2, or #WWT_LABEL). - * @param clicked Label is rendered lowered. - * @param str Text to draw. - */ -static inline void DrawLabel(const Rect &r, WidgetType type, bool clicked, StringID str) -{ - if (str == STR_NULL) return; - if ((type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++; - Dimension d = GetStringBoundingBox(str); - int offset = max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered - DrawString(r.left + clicked, r.right + clicked, r.top + offset + clicked, str, TC_FROMSTRING, SA_HOR_CENTER); -} - -/** - * Draw text. - * @param r Rectangle of the background. - * @param colour Colour of the text. - * @param str Text to draw. - */ -static inline void DrawText(const Rect &r, TextColour colour, StringID str) -{ - Dimension d = GetStringBoundingBox(str); - int offset = max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered - if (str != STR_NULL) DrawString(r.left, r.right, r.top + offset, str, colour); -} - -/** - * Draw an inset widget. - * @param r Rectangle of the background. - * @param colour Colour of the inset. - * @param str Text to draw. - */ -static inline void DrawInset(const Rect &r, Colours colour, StringID str) -{ - DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_LOWERED | FR_DARKENED); - if (str != STR_NULL) DrawString(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + WD_INSET_TOP, str); -} - -/** - * Draw a matrix widget. - * @param r Rectangle of the matrix background. - * @param colour Colour of the background. - * @param clicked Matrix is rendered lowered. - * @param data Data of the widget, number of rows and columns of the widget. - * @param resize_x Matrix resize unit size. - * @param resize_y Matrix resize unit size. - */ -static inline void DrawMatrix(const Rect &r, Colours colour, bool clicked, uint16 data, uint resize_x, uint resize_y) -{ - DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); - - int num_columns = GB(data, MAT_COL_START, MAT_COL_BITS); // Lower 8 bits of the widget data: Number of columns in the matrix. - int column_width; // Width of a single column in the matrix. - if (num_columns == 0) { - column_width = resize_x; - num_columns = (r.right - r.left + 1) / column_width; - } else { - column_width = (r.right - r.left + 1) / num_columns; - } - - int num_rows = GB(data, MAT_ROW_START, MAT_ROW_BITS); // Upper 8 bits of the widget data: Number of rows in the matrix. - int row_height; // Height of a single row in the matrix. - if (num_rows == 0) { - row_height = resize_y; - num_rows = (r.bottom - r.top + 1) / row_height; - } else { - row_height = (r.bottom - r.top + 1) / num_rows; - } - - int col = _colour_gradient[colour & 0xF][6]; - - int x = r.left; - for (int ctr = num_columns; ctr > 1; ctr--) { - x += column_width; - GfxFillRect(x, r.top + 1, x, r.bottom - 1, col); - } - - x = r.top; - for (int ctr = num_rows; ctr > 1; ctr--) { - x += row_height; - GfxFillRect(r.left + 1, x, r.right - 1, x, col); - } - - col = _colour_gradient[colour & 0xF][4]; - - x = r.left - 1; - for (int ctr = num_columns; ctr > 1; ctr--) { - x += column_width; - GfxFillRect(x, r.top + 1, x, r.bottom - 1, col); - } - - x = r.top - 1; - for (int ctr = num_rows; ctr > 1; ctr--) { - x += row_height; - GfxFillRect(r.left + 1, x, r.right - 1, x, col); - } -} - -/** - * Draw a vertical scrollbar. - * @param r Rectangle of the scrollbar widget. - * @param colour Colour of the scrollbar widget. - * @param up_clicked Up-arrow is clicked. - * @param bar_dragged Bar is dragged. - * @param down_clicked Down-arrow is clicked. - * @param scrollbar Scrollbar size, offset, and capacity information. - */ -static inline void DrawVerticalScrollbar(const Rect &r, Colours colour, bool up_clicked, bool bar_dragged, bool down_clicked, const Scrollbar *scrollbar) -{ - int centre = (r.right - r.left) / 2; - int height = NWidgetScrollbar::GetVerticalDimension().height; - - /* draw up/down buttons */ - DrawFrameRect(r.left, r.top, r.right, r.top + height - 1, colour, (up_clicked) ? FR_LOWERED : FR_NONE); - DrawString(r.left + up_clicked, r.right + up_clicked, r.top + up_clicked, UPARROW, TC_BLACK, SA_HOR_CENTER); - - DrawFrameRect(r.left, r.bottom - (height - 1), r.right, r.bottom, colour, (down_clicked) ? FR_LOWERED : FR_NONE); - DrawString(r.left + down_clicked, r.right + down_clicked, r.bottom - (height - 1) + down_clicked, DOWNARROW, TC_BLACK, SA_HOR_CENTER); - - int c1 = _colour_gradient[colour & 0xF][3]; - int c2 = _colour_gradient[colour & 0xF][7]; - - /* draw "shaded" background */ - GfxFillRect(r.left, r.top + height, r.right, r.bottom - height, c2); - GfxFillRect(r.left, r.top + height, r.right, r.bottom - height, c1, FILLRECT_CHECKER); - - /* draw shaded lines */ - GfxFillRect(r.left + centre - 3, r.top + height, r.left + centre - 3, r.bottom - height, c1); - GfxFillRect(r.left + centre - 2, r.top + height, r.left + centre - 2, r.bottom - height, c2); - GfxFillRect(r.left + centre + 2, r.top + height, r.left + centre + 2, r.bottom - height, c1); - GfxFillRect(r.left + centre + 3, r.top + height, r.left + centre + 3, r.bottom - height, c2); - - Point pt = HandleScrollbarHittest(scrollbar, r.top, r.bottom, false); - DrawFrameRect(r.left, pt.x, r.right, pt.y, colour, bar_dragged ? FR_LOWERED : FR_NONE); -} - -/** - * Draw a horizontal scrollbar. - * @param r Rectangle of the scrollbar widget. - * @param colour Colour of the scrollbar widget. - * @param left_clicked Left-arrow is clicked. - * @param bar_dragged Bar is dragged. - * @param right_clicked Right-arrow is clicked. - * @param scrollbar Scrollbar size, offset, and capacity information. - */ -static inline void DrawHorizontalScrollbar(const Rect &r, Colours colour, bool left_clicked, bool bar_dragged, bool right_clicked, const Scrollbar *scrollbar) -{ - int centre = (r.bottom - r.top) / 2; - int width = NWidgetScrollbar::GetHorizontalDimension().width; - - DrawFrameRect(r.left, r.top, r.left + width - 1, r.bottom, colour, left_clicked ? FR_LOWERED : FR_NONE); - DrawSprite(SPR_ARROW_LEFT, PAL_NONE, r.left + 1 + left_clicked, r.top + 1 + left_clicked); - - DrawFrameRect(r.right - (width - 1), r.top, r.right, r.bottom, colour, right_clicked ? FR_LOWERED : FR_NONE); - DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, r.right - (width - 2) + right_clicked, r.top + 1 + right_clicked); - - int c1 = _colour_gradient[colour & 0xF][3]; - int c2 = _colour_gradient[colour & 0xF][7]; - - /* draw "shaded" background */ - GfxFillRect(r.left + width, r.top, r.right - width, r.bottom, c2); - GfxFillRect(r.left + width, r.top, r.right - width, r.bottom, c1, FILLRECT_CHECKER); - - /* draw shaded lines */ - GfxFillRect(r.left + width, r.top + centre - 3, r.right - width, r.top + centre - 3, c1); - GfxFillRect(r.left + width, r.top + centre - 2, r.right - width, r.top + centre - 2, c2); - GfxFillRect(r.left + width, r.top + centre + 2, r.right - width, r.top + centre + 2, c1); - GfxFillRect(r.left + width, r.top + centre + 3, r.right - width, r.top + centre + 3, c2); - - /* draw actual scrollbar */ - Point pt = HandleScrollbarHittest(scrollbar, r.left, r.right, true); - DrawFrameRect(pt.x, r.top, pt.y, r.bottom, colour, bar_dragged ? FR_LOWERED : FR_NONE); -} - -/** - * Draw a frame widget. - * @param r Rectangle of the frame. - * @param colour Colour of the frame. - * @param str Text of the frame. - */ -static inline void DrawFrame(const Rect &r, Colours colour, StringID str) -{ - int x2 = r.left; // by default the left side is the left side of the widget - - if (str != STR_NULL) x2 = DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top, str); - - int c1 = _colour_gradient[colour][3]; - int c2 = _colour_gradient[colour][7]; - - /* If the frame has text, adjust the top bar to fit half-way through */ - int dy1 = 4; - if (str != STR_NULL) dy1 = FONT_HEIGHT_NORMAL / 2 - 1; - int dy2 = dy1 + 1; - - if (_current_text_dir == TD_LTR) { - /* Line from upper left corner to start of text */ - GfxFillRect(r.left, r.top + dy1, r.left + 4, r.top + dy1, c1); - GfxFillRect(r.left + 1, r.top + dy2, r.left + 4, r.top + dy2, c2); - - /* Line from end of text to upper right corner */ - GfxFillRect(x2, r.top + dy1, r.right - 1, r.top + dy1, c1); - GfxFillRect(x2, r.top + dy2, r.right - 2, r.top + dy2, c2); - } else { - /* Line from upper left corner to start of text */ - GfxFillRect(r.left, r.top + dy1, x2 - 2, r.top + dy1, c1); - GfxFillRect(r.left + 1, r.top + dy2, x2 - 2, r.top + dy2, c2); - - /* Line from end of text to upper right corner */ - GfxFillRect(r.right - 5, r.top + dy1, r.right - 1, r.top + dy1, c1); - GfxFillRect(r.right - 5, r.top + dy2, r.right - 2, r.top + dy2, c2); - } - - /* Line from upper left corner to bottom left corner */ - GfxFillRect(r.left, r.top + dy2, r.left, r.bottom - 1, c1); - GfxFillRect(r.left + 1, r.top + dy2 + 1, r.left + 1, r.bottom - 2, c2); - - /* Line from upper right corner to bottom right corner */ - GfxFillRect(r.right - 1, r.top + dy2, r.right - 1, r.bottom - 2, c1); - GfxFillRect(r.right, r.top + dy1, r.right, r.bottom - 1, c2); - - GfxFillRect(r.left + 1, r.bottom - 1, r.right - 1, r.bottom - 1, c1); - GfxFillRect(r.left, r.bottom, r.right, r.bottom, c2); -} - -/** - * Draw a resize box. - * @param r Rectangle of the box. - * @param colour Colour of the resize box. - * @param at_left Resize box is at left-side of the window, - * @param clicked Box is lowered. - */ -static inline void DrawResizeBox(const Rect &r, Colours colour, bool at_left, bool clicked) -{ - DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); - Dimension d = GetSpriteSize(at_left ? SPR_WINDOW_RESIZE_LEFT : SPR_WINDOW_RESIZE_RIGHT); - if (at_left) { - DrawSprite(SPR_WINDOW_RESIZE_LEFT, PAL_NONE, r.left + WD_RESIZEBOX_LEFT + clicked, - r.bottom - WD_RESIZEBOX_BOTTOM - d.height + clicked); - } else { - DrawSprite(SPR_WINDOW_RESIZE_RIGHT, PAL_NONE, r.right - WD_RESIZEBOX_RIGHT - d.width + clicked, - r.bottom - WD_RESIZEBOX_BOTTOM - d.height + clicked); - } -} - -/** - * Draw a close box. - * @param r Rectangle of the box. - * @param colour Colour of the close box. - * @param str Cross to draw (#STR_BLACK_CROSS or #STR_SILVER_CROSS). - */ -static inline void DrawCloseBox(const Rect &r, Colours colour, StringID str) -{ - assert(str == STR_BLACK_CROSS || str == STR_SILVER_CROSS); // black or silver cross - DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_NONE); - DrawString(r.left, r.right, r.top + WD_CLOSEBOX_TOP, str, TC_FROMSTRING, SA_HOR_CENTER); -} - -/** - * Draw a caption bar. - * @param r Rectangle of the bar. - * @param colour Colour of the window. - * @param owner 'Owner' of the window. - * @param str Text to draw in the bar. - */ -void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str) -{ - DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_BORDERONLY); - DrawFrameRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, colour, (owner == INVALID_OWNER) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY); - - if (owner != INVALID_OWNER) { - GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, _colour_gradient[_company_colours[owner]][4]); - } - - if (str != STR_NULL) { - Dimension d = GetStringBoundingBox(str); - int offset = max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered - DrawString(r.left + WD_CAPTIONTEXT_LEFT, r.right - WD_CAPTIONTEXT_RIGHT, r.top + offset, str, TC_FROMSTRING, SA_HOR_CENTER); - } -} - -/** - * Draw a button with a dropdown (#WWT_DROPDOWN and #NWID_BUTTON_DROPDOWN). - * @param r Rectangle containing the widget. - * @param colour Background colour of the widget. - * @param clicked_button The button-part is lowered. - * @param clicked_dropdown The drop-down part is lowered. - * @param str Text of the button. - * - * @note Magic constants are also used in #NWidgetLeaf::ButtonHit. - */ -static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicked_button, bool clicked_dropdown, StringID str) -{ - int text_offset = max(0, ((int)(r.bottom - r.top + 1) - FONT_HEIGHT_NORMAL) / 2); // Offset for rendering the text vertically centered - - int dd_width = GetMinSizing(NWST_STEP, NWidgetLeaf::dropdown_dimension.width); - - if (_current_text_dir == TD_LTR) { - DrawFrameRect(r.left, r.top, r.right - dd_width, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); - DrawFrameRect(r.right + 1 - dd_width, r.top, r.right, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE); - DrawString(r.right - dd_width + (clicked_dropdown ? 2 : 1), r.right, r.top + (clicked_dropdown ? 2 : 1), DOWNARROW, TC_BLACK, SA_HOR_CENTER); - if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - dd_width - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK); - } else { - DrawFrameRect(r.left + dd_width, r.top, r.right, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); - DrawFrameRect(r.left, r.top, r.left + dd_width - 1, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE); - DrawString(r.left + (clicked_dropdown ? 2 : 1), r.left + dd_width, r.top + (clicked_dropdown ? 2 : 1), DOWNARROW, TC_BLACK, SA_HOR_CENTER); - if (str != STR_NULL) DrawString(r.left + dd_width + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK); - } -} - -/** - * Draw a dropdown #WWT_DROPDOWN widget. - * @param r Rectangle containing the widget. - * @param colour Background colour of the widget. - * @param clicked The widget is lowered. - * @param str Text of the button. - */ -static inline void DrawDropdown(const Rect &r, Colours colour, bool clicked, StringID str) -{ - DrawButtonDropdown(r, colour, false, clicked, str); -} - -/** - * Paint all widgets of a window. - */ -void Window::DrawWidgets() const -{ - this->nested_root->Draw(this); - - if (this->flags & WF_WHITE_BORDER) { - DrawFrameRect(0, 0, this->width - 1, this->height - 1, COLOUR_WHITE, FR_BORDERONLY); - } - - if (this->flags & WF_HIGHLIGHTED) { - extern bool _window_highlight_colour; - for (uint i = 0; i < this->nested_array_size; i++) { - const NWidgetBase *widget = this->GetWidget(i); - if (widget == NULL || !widget->IsHighlighted()) continue; - - int left = widget->pos_x; - int top = widget->pos_y; - int right = left + widget->current_x - 1; - int bottom = top + widget->current_y - 1; - - int colour = _string_colourmap[_window_highlight_colour ? widget->GetHighlightColour() : TC_WHITE]; - - GfxFillRect(left, top, left, bottom - WD_BEVEL_BOTTOM, colour); - GfxFillRect(left + WD_BEVEL_LEFT, top, right - WD_BEVEL_RIGHT, top, colour); - GfxFillRect(right, top, right, bottom - WD_BEVEL_BOTTOM, colour); - GfxFillRect(left, bottom, right, bottom, colour); - } - } -} - -/** - * Draw a sort button's up or down arrow symbol. - * @param widget Sort button widget - * @param state State of sort button - */ -void Window::DrawSortButtonState(int widget, SortButtonState state) const -{ - if (state == SBS_OFF) return; - - assert(this->nested_array != NULL); - const NWidgetBase *nwid = this->GetWidget(widget); - - int offset = this->IsWidgetLowered(widget) ? 1 : 0; - int base = offset + nwid->pos_x + (_current_text_dir == TD_LTR ? nwid->current_x - WD_SORTBUTTON_ARROW_WIDTH : 0); - int top = nwid->pos_y; - - DrawString(base, base + WD_SORTBUTTON_ARROW_WIDTH, top + 1 + offset, state == SBS_DOWN ? DOWNARROW : UPARROW, TC_BLACK, SA_HOR_CENTER); -} - - -/** - * @defgroup NestedWidgets Hierarchical widgets - * Hierarchical widgets, also known as nested widgets, are widgets stored in a tree. At the leafs of the tree are (mostly) the 'real' widgets - * visible to the user. At higher levels, widgets get organized in container widgets, until all widgets of the window are merged. - * - * \section nestedwidgetkinds Hierarchical widget kinds - * A leaf widget is one of - *
    - *
  • #NWidgetLeaf for widgets visible for the user, or - *
  • #NWidgetSpacer for creating (flexible) empty space between widgets. - *
- * The purpose of a leaf widget is to provide interaction with the user by displaying settings, and/or allowing changing the settings. - * - * A container widget is one of - *
    - *
  • #NWidgetHorizontal for organizing child widgets in a (horizontal) row. The row switches order depending on the language setting (thus supporting - * right-to-left languages), - *
  • #NWidgetHorizontalLTR for organizing child widgets in a (horizontal) row, always in the same order. All children below this container will also - * never swap order. - *
  • #NWidgetVertical for organizing child widgets underneath each other. - *
  • #NWidgetMatrix for organizing child widgets in a matrix form. - *
  • #NWidgetBackground for adding a background behind its child widget. - *
  • #NWidgetStacked for stacking child widgets on top of each other. - *
- * The purpose of a container widget is to structure its leafs and sub-containers to allow proper resizing. - * - * \section nestedwidgetscomputations Hierarchical widget computations - * The first 'computation' is the creation of the nested widgets tree by calling the constructors of the widgets listed above and calling \c Add() for every child, - * or by means of specifying the tree as a collection of nested widgets parts and instantiating the tree from the array. - * - * After the creation step, - * - The leafs have their own minimal size (\e min_x, \e min_y), filling (\e fill_x, \e fill_y), and resize steps (\e resize_x, \e resize_y). - * - Containers only know what their children are, \e fill_x, \e fill_y, \e resize_x, and \e resize_y are not initialized. - * - * Computations in the nested widgets take place as follows: - *
    - *
  1. A bottom-up sweep by recursively calling NWidgetBase::SetupSmallestSize() to initialize the smallest size (\e smallest_x, \e smallest_y) and - * to propagate filling and resize steps upwards to the root of the tree. - *
  2. A top-down sweep by recursively calling NWidgetBase::AssignSizePosition() with #ST_SMALLEST to make the smallest sizes consistent over - * the entire tree, and to assign the top-left (\e pos_x, \e pos_y) position of each widget in the tree. This step uses \e fill_x and \e fill_y at each - * node in the tree to decide how to fill each widget towards consistent sizes. Also the current size (\e current_x and \e current_y) is set. - *
  3. After initializing the smallest size in the widget tree with #ST_SMALLEST, the tree can be resized (the current size modified) by calling - * NWidgetBase::AssignSizePosition() at the root with #ST_RESIZE and the new size of the window. For proper functioning, the new size should be the smallest - * size + a whole number of resize steps in both directions (ie you can only resize in steps of length resize_{x,y} from smallest_{x,y}). - *
- * After the second step, the current size of the widgets are set to the smallest size. - * - * To resize, perform the last step with the new window size. This can be done as often as desired. - * When the smallest size of at least one widget changes, the whole procedure has to be redone from the start. - * - * @see NestedWidgetParts - */ - -/** - * Base class constructor. - * @param tp Nested widget type. - */ -NWidgetBase::NWidgetBase(WidgetType tp) : ZeroedMemoryAllocator() -{ - this->type = tp; -} - -/* ~NWidgetContainer() takes care of #next and #prev data members. */ - -/** - * @fn void NWidgetBase::SetupSmallestSize(Window *w, bool init_array) - * Compute smallest size needed by the widget. - * - * The smallest size of a widget is the smallest size that a widget needs to - * display itself properly. In addition, filling and resizing of the widget are computed. - * The function calls #Window::UpdateWidgetSize for each leaf widget and - * background widget without child with a non-negative index. - * - * @param w Window owning the widget. - * @param init_array Initialize the \c w->nested_array. - * - * @note After the computation, the results can be queried by accessing the #smallest_x and #smallest_y data members of the widget. - */ - -/** - * @fn void NWidgetBase::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) - * Assign size and position to the widget. - * @param sizing Type of resizing to perform. - * @param x Horizontal offset of the widget relative to the left edge of the window. - * @param y Vertical offset of the widget relative to the top edge of the window. - * @param given_width Width allocated to the widget. - * @param given_height Height allocated to the widget. - * @param rtl Adapt for right-to-left languages (position contents of horizontal containers backwards). - * - * Afterwards, \e pos_x and \e pos_y contain the top-left position of the widget, \e smallest_x and \e smallest_y contain - * the smallest size such that all widgets of the window are consistent, and \e current_x and \e current_y contain the current size. - */ - -/** - * @fn void FillNestedArray(NWidgetBase **array, uint length) - * Fill the Window::nested_array array with pointers to nested widgets in the tree. - * @param array Base pointer of the array. - * @param length Length of the array. - */ - -/** - * @fn void NWidgetBase::Draw(const Window *w) - * Draw the widgets of the tree. - * The function calls #Window::DrawWidget for each widget with a non-negative index, after the widget itself is painted. - * @param w Window that owns the tree. - */ - -/** - * Mark the widget as 'dirty' (in need of repaint). - * @param w Window owning the widget. - */ -void NWidgetBase::SetDirty(const Window *w) const -{ - int abs_left = w->left + this->pos_x; - int abs_top = w->top + this->pos_y; - SetDirtyBlocks(abs_left, abs_top, abs_left + this->current_x, abs_top + this->current_y); -} - -/** - * @fn NWidgetCore *NWidgetBase::GetWidgetFromPos(int x, int y) - * Retrieve a widget by its position. - * @param x Horizontal position relative to the left edge of the window. - * @param y Vertical position relative to the top edge of the window. - * @return Returns the deepest nested widget that covers the given position, or \c NULL if no widget can be found. - */ - -/** - * Retrieve a widget by its type. - * @param tp Widget type to search for. - * @return Returns the first widget of the specified type, or \c NULL if no widget can be found. - */ -NWidgetBase *NWidgetBase::GetWidgetOfType(WidgetType tp) -{ - return (this->type == tp) ? this : NULL; -} - -/** - * Constructor for resizable nested widgets. - * @param tp Nested widget type. - * @param fill_x Horizontal fill step size, \c 0 means no filling is allowed. - * @param fill_y Vertical fill step size, \c 0 means no filling is allowed. - */ -NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : NWidgetBase(tp) -{ - this->sizing_type = NWST_NONE; - this->fill_x = fill_x; - this->fill_y = fill_y; -} - -/** - * Set minimal size of the widget. - * @param min_x Horizontal minimal size of the widget. - * @param min_y Vertical minimal size of the widget. - */ -void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y) -{ - uint min_size = 0; - switch (this->sizing_type) { - case NWST_NONE: - case NWST_OVERRIDE: - min_size = 0; - break; - case NWST_BUTTON: - min_size = _settings_client.gui.min_button; - break; - case NWST_STEP: - min_size = _settings_client.gui.min_step; - break; - default: NOT_REACHED(); - } - - this->min_x = max(min_x, min_size); - this->min_y = max(min_y, min_size); -} - -/** - * Set minimal text lines for the widget. - * @param min_lines Number of text lines of the widget. - * @param spacing Extra spacing (eg WD_FRAMERECT_TOP + _BOTTOM) of the widget. - * @param size Font size of text. - */ -void NWidgetResizeBase::SetMinimalTextLines(uint8 min_lines, uint8 spacing, FontSize size) -{ - this->min_y = min_lines * GetCharacterHeight(size) + spacing; -} - -/** - * Set the filling of the widget from initial size. - * @param fill_x Horizontal fill step size, \c 0 means no filling is allowed. - * @param fill_y Vertical fill step size, \c 0 means no filling is allowed. - */ -void NWidgetResizeBase::SetFill(uint fill_x, uint fill_y) -{ - this->fill_x = fill_x; - this->fill_y = fill_y; -} - -/** - * Set resize step of the widget. - * @param resize_x Resize step in horizontal direction, value \c 0 means no resize, otherwise the step size in pixels. - * @param resize_y Resize step in vertical direction, value \c 0 means no resize, otherwise the step size in pixels. - */ -void NWidgetResizeBase::SetResize(uint resize_x, uint resize_y) -{ - this->resize_x = resize_x; - this->resize_y = resize_y; -} - -void NWidgetResizeBase::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) -{ - this->StoreSizePosition(sizing, x, y, given_width, given_height); -} - -/** - * Initialization of a 'real' widget. - * @param tp Type of the widget. - * @param colour Colour of the widget. - * @param fill_x Default horizontal filling. - * @param fill_y Default vertical filling. - * @param widget_data Data component of the widget. @see Widget::data - * @param tool_tip Tool tip of the widget. @see Widget::tooltips - */ -NWidgetCore::NWidgetCore(WidgetType tp, Colours colour, uint fill_x, uint fill_y, uint32 widget_data, StringID tool_tip) : NWidgetResizeBase(tp, fill_x, fill_y) -{ - this->sizing_type = NWST_NONE; - this->colour = colour; - this->index = -1; - this->widget_data = widget_data; - this->tool_tip = tool_tip; - this->scrollbar_index = -1; -} - -/** - * Set index of the nested widget in the widget array. - * @param index Index to use. - */ -void NWidgetCore::SetIndex(int index) -{ - assert(index >= 0); - this->index = index; -} - -/** - * Set data and tool tip of the nested widget. - * @param widget_data Data to use. - * @param tool_tip Tool tip string to use. - */ -void NWidgetCore::SetDataTip(uint32 widget_data, StringID tool_tip) -{ - this->widget_data = widget_data; - this->tool_tip = tool_tip; -} - -void NWidgetCore::FillNestedArray(NWidgetBase **array, uint length) -{ - if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; -} - -NWidgetCore *NWidgetCore::GetWidgetFromPos(int x, int y) -{ - return (IsInsideBS(x, this->pos_x, this->current_x) && IsInsideBS(y, this->pos_y, this->current_y)) ? this : NULL; -} - -/** - * Constructor container baseclass. - * @param tp Type of the container. - */ -NWidgetContainer::NWidgetContainer(WidgetType tp) : NWidgetBase(tp) -{ - this->head = NULL; - this->tail = NULL; -} - -NWidgetContainer::~NWidgetContainer() -{ - while (this->head != NULL) { - NWidgetBase *wid = this->head->next; - delete this->head; - this->head = wid; - } - this->tail = NULL; -} - -NWidgetBase *NWidgetContainer::GetWidgetOfType(WidgetType tp) -{ - if (this->type == tp) return this; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - NWidgetBase *nwid = child_wid->GetWidgetOfType(tp); - if (nwid != NULL) return nwid; - } - return NULL; -} - -/** - * Append widget \a wid to container. - * @param wid Widget to append. - */ -void NWidgetContainer::Add(NWidgetBase *wid) -{ - assert(wid->next == NULL && wid->prev == NULL); - - if (this->head == NULL) { - this->head = wid; - this->tail = wid; - } else { - assert(this->tail != NULL); - assert(this->tail->next == NULL); - - this->tail->next = wid; - wid->prev = this->tail; - this->tail = wid; - } -} - -void NWidgetContainer::FillNestedArray(NWidgetBase **array, uint length) -{ - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - child_wid->FillNestedArray(array, length); - } -} - -/** - * Widgets stacked on top of each other. - */ -NWidgetStacked::NWidgetStacked() : NWidgetContainer(NWID_SELECTION) -{ - this->index = -1; -} - -void NWidgetStacked::SetIndex(int index) -{ - this->index = index; -} - -void NWidgetStacked::SetupSmallestSize(Window *w, bool init_array) -{ - if (this->index >= 0 && init_array) { // Fill w->nested_array[] - assert(w->nested_array_size > (uint)this->index); - w->nested_array[this->index] = this; - } - - /* Zero size plane selected */ - if (this->shown_plane >= SZSP_BEGIN) { - Dimension size = {0, 0}; - Dimension padding = {0, 0}; - Dimension fill = {(this->shown_plane == SZSP_HORIZONTAL), (this->shown_plane == SZSP_VERTICAL)}; - Dimension resize = {(this->shown_plane == SZSP_HORIZONTAL), (this->shown_plane == SZSP_VERTICAL)}; - /* Here we're primarily interested in the value of resize */ - if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, padding, &fill, &resize); - - this->smallest_x = size.width; - this->smallest_y = size.height; - this->fill_x = fill.width; - this->fill_y = fill.height; - this->resize_x = resize.width; - this->resize_y = resize.height; - return; - } - - /* First sweep, recurse down and compute minimal size and filling. */ - this->smallest_x = 0; - this->smallest_y = 0; - this->fill_x = (this->head != NULL) ? 1 : 0; - this->fill_y = (this->head != NULL) ? 1 : 0; - this->resize_x = (this->head != NULL) ? 1 : 0; - this->resize_y = (this->head != NULL) ? 1 : 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - child_wid->SetupSmallestSize(w, init_array); - - this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); - this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); - this->fill_x = LeastCommonMultiple(this->fill_x, child_wid->fill_x); - this->fill_y = LeastCommonMultiple(this->fill_y, child_wid->fill_y); - this->resize_x = LeastCommonMultiple(this->resize_x, child_wid->resize_x); - this->resize_y = LeastCommonMultiple(this->resize_y, child_wid->resize_y); - } -} - -void NWidgetStacked::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) -{ - assert(given_width >= this->smallest_x && given_height >= this->smallest_y); - this->StoreSizePosition(sizing, x, y, given_width, given_height); - - if (this->shown_plane >= SZSP_BEGIN) return; - - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - uint hor_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing); - uint child_width = ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding_left - child_wid->padding_right, hor_step); - uint child_pos_x = (rtl ? child_wid->padding_right : child_wid->padding_left); - - uint vert_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing); - uint child_height = ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding_top - child_wid->padding_bottom, vert_step); - uint child_pos_y = child_wid->padding_top; - - child_wid->AssignSizePosition(sizing, x + child_pos_x, y + child_pos_y, child_width, child_height, rtl); - } -} - -void NWidgetStacked::FillNestedArray(NWidgetBase **array, uint length) -{ - if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; - NWidgetContainer::FillNestedArray(array, length); -} - -void NWidgetStacked::Draw(const Window *w) -{ - if (this->shown_plane >= SZSP_BEGIN) return; - - int plane = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; plane++, child_wid = child_wid->next) { - if (plane == this->shown_plane) { - child_wid->Draw(w); - return; - } - } - - NOT_REACHED(); -} - -NWidgetCore *NWidgetStacked::GetWidgetFromPos(int x, int y) -{ - if (this->shown_plane >= SZSP_BEGIN) return NULL; - - if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; - int plane = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; plane++, child_wid = child_wid->next) { - if (plane == this->shown_plane) { - return child_wid->GetWidgetFromPos(x, y); - } - } - return NULL; -} - -/** - * Select which plane to show (for #NWID_SELECTION only). - * @param plane Plane number to display. - */ -void NWidgetStacked::SetDisplayedPlane(int plane) -{ - this->shown_plane = plane; -} - -NWidgetPIPContainer::NWidgetPIPContainer(WidgetType tp, NWidContainerFlags flags) : NWidgetContainer(tp) -{ - this->flags = flags; -} - -/** - * Set additional pre/inter/post space for the container. - * - * @param pip_pre Additional space in front of the first child widget (above - * for the vertical container, at the left for the horizontal container). - * @param pip_inter Additional space between two child widgets. - * @param pip_post Additional space after the last child widget (below for the - * vertical container, at the right for the horizontal container). - */ -void NWidgetPIPContainer::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) -{ - this->pip_pre = pip_pre; - this->pip_inter = pip_inter; - this->pip_post = pip_post; -} - -void NWidgetPIPContainer::Draw(const Window *w) -{ - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - child_wid->Draw(w); - } -} - -NWidgetCore *NWidgetPIPContainer::GetWidgetFromPos(int x, int y) -{ - if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; - - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y); - if (nwid != NULL) return nwid; - } - return NULL; -} - -/** Horizontal container widget. */ -NWidgetHorizontal::NWidgetHorizontal(NWidContainerFlags flags) : NWidgetPIPContainer(NWID_HORIZONTAL, flags) -{ -} - -void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) -{ - this->smallest_x = 0; // Sum of minimal size of all children. - this->smallest_y = 0; // Biggest child. - this->fill_x = 0; // smallest non-zero child widget fill step. - this->fill_y = 1; // smallest common child fill step. - this->resize_x = 0; // smallest non-zero child widget resize step. - this->resize_y = 1; // smallest common child resize step. - - /* 1a. Forward call, collect biggest nested array index, and longest/widest child length. */ - uint longest = 0; // Longest child found. - uint max_vert_fill = 0; // Biggest vertical fill step. - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - child_wid->SetupSmallestSize(w, init_array); - longest = max(longest, child_wid->smallest_x); - max_vert_fill = max(max_vert_fill, child_wid->GetVerticalStepSize(ST_SMALLEST)); - this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); - } - /* 1b. Make the container higher if needed to accommodate all children nicely. */ - uint max_smallest = this->smallest_y + 3 * max_vert_fill; // Upper limit to computing smallest height. - uint cur_height = this->smallest_y; - for (;;) { - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - uint step_size = child_wid->GetVerticalStepSize(ST_SMALLEST); - uint child_height = child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom; - if (step_size > 1 && child_height < cur_height) { // Small step sizes or already fitting children are not interesting. - uint remainder = (cur_height - child_height) % step_size; - if (remainder > 0) { // Child did not fit entirely, widen the container. - cur_height += step_size - remainder; - assert(cur_height < max_smallest); // Safeguard against infinite height expansion. - /* Remaining children will adapt to the new cur_height, thus speeding up the computation. */ - } - } - } - if (this->smallest_y == cur_height) break; - this->smallest_y = cur_height; // Smallest height got changed, try again. - } - /* 2. For containers that must maintain equal width, extend child minimal size. */ - if (this->flags & NC_EQUALSIZE) { - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - if (child_wid->fill_x == 1) child_wid->smallest_x = longest; - } - } - /* 3. Move PIP space to the children, compute smallest, fill, and resize values of the container. */ - if (this->head != NULL) this->head->padding_left += this->pip_pre; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - if (child_wid->next != NULL) { - child_wid->padding_right += this->pip_inter; - } else { - child_wid->padding_right += this->pip_post; - } - - this->smallest_x += child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right; - if (child_wid->fill_x > 0) { - if (this->fill_x == 0 || this->fill_x > child_wid->fill_x) this->fill_x = child_wid->fill_x; - } - this->fill_y = LeastCommonMultiple(this->fill_y, child_wid->fill_y); - - if (child_wid->resize_x > 0) { - if (this->resize_x == 0 || this->resize_x > child_wid->resize_x) this->resize_x = child_wid->resize_x; - } - this->resize_y = LeastCommonMultiple(this->resize_y, child_wid->resize_y); - } - /* We need to zero the PIP settings so we can re-initialize the tree. */ - this->pip_pre = this->pip_inter = this->pip_post = 0; -} - -void NWidgetHorizontal::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) -{ - assert(given_width >= this->smallest_x && given_height >= this->smallest_y); - - /* Compute additional width given to us. */ - uint additional_length = given_width; - if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) { - /* For EQUALSIZE containers this does not sum to smallest_x during initialisation */ - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - additional_length -= child_wid->smallest_x + child_wid->padding_right + child_wid->padding_left; - } - } else { - additional_length -= this->smallest_x; - } - - this->StoreSizePosition(sizing, x, y, given_width, given_height); - - /* In principle, the additional horizontal space is distributed evenly over the available resizable children. Due to step sizes, this may not always be feasible. - * To make resizing work as good as possible, first children with biggest step sizes are done. These may get less due to rounding down. - * This additional space is then given to children with smaller step sizes. This will give a good result when resize steps of each child is a multiple - * of the child with the smallest non-zero stepsize. - * - * Since child sizes are computed out of order, positions cannot be calculated until all sizes are known. That means it is not possible to compute the child - * size and position, and directly call child->AssignSizePosition() with the computed values. - * Instead, computed child widths and heights are stored in child->current_x and child->current_y values. That is allowed, since this method overwrites those values - * then we call the child. - */ - - /* First loop: Find biggest stepsize, find number of children that want a piece of the pie, handle vertical size for all children, - * handle horizontal size for non-resizing children. - */ - int num_changing_childs = 0; // Number of children that can change size. - uint biggest_stepsize = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - uint hor_step = child_wid->GetHorizontalStepSize(sizing); - if (hor_step > 0) { - num_changing_childs++; - biggest_stepsize = max(biggest_stepsize, hor_step); - } else { - child_wid->current_x = child_wid->smallest_x; - } - - uint vert_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing); - child_wid->current_y = ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding_top - child_wid->padding_bottom, vert_step); - } - - /* Second loop: Allocate the additional horizontal space over the resizing children, starting with the biggest resize steps. */ - while (biggest_stepsize > 0) { - uint next_biggest_stepsize = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - uint hor_step = child_wid->GetHorizontalStepSize(sizing); - if (hor_step > biggest_stepsize) continue; // Already done - if (hor_step == biggest_stepsize) { - uint increment = additional_length / num_changing_childs; - num_changing_childs--; - if (hor_step > 1) increment -= increment % hor_step; - child_wid->current_x = child_wid->smallest_x + increment; - additional_length -= increment; - continue; - } - next_biggest_stepsize = max(next_biggest_stepsize, hor_step); - } - biggest_stepsize = next_biggest_stepsize; - } - assert(num_changing_childs == 0); - - /* Third loop: Compute position and call the child. */ - uint position = rtl ? this->current_x : 0; // Place to put next child relative to origin of the container. - NWidgetBase *child_wid = this->head; - while (child_wid != NULL) { - uint child_width = child_wid->current_x; - uint child_x = x + (rtl ? position - child_width - child_wid->padding_left : position + child_wid->padding_left); - uint child_y = y + child_wid->padding_top; - - child_wid->AssignSizePosition(sizing, child_x, child_y, child_width, child_wid->current_y, rtl); - uint padded_child_width = child_width + child_wid->padding_right + child_wid->padding_left; - position = rtl ? position - padded_child_width : position + padded_child_width; - - child_wid = child_wid->next; - } -} - -/** Horizontal left-to-right container widget. */ -NWidgetHorizontalLTR::NWidgetHorizontalLTR(NWidContainerFlags flags) : NWidgetHorizontal(flags) -{ - this->type = NWID_HORIZONTAL_LTR; -} - -void NWidgetHorizontalLTR::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) -{ - NWidgetHorizontal::AssignSizePosition(sizing, x, y, given_width, given_height, false); -} - -/** Vertical container widget. */ -NWidgetVertical::NWidgetVertical(NWidContainerFlags flags) : NWidgetPIPContainer(NWID_VERTICAL, flags) -{ -} - -void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) -{ - this->smallest_x = 0; // Biggest child. - this->smallest_y = 0; // Sum of minimal size of all children. - this->fill_x = 1; // smallest common child fill step. - this->fill_y = 0; // smallest non-zero child widget fill step. - this->resize_x = 1; // smallest common child resize step. - this->resize_y = 0; // smallest non-zero child widget resize step. - - /* 1a. Forward call, collect biggest nested array index, and longest/widest child length. */ - uint highest = 0; // Highest child found. - uint max_hor_fill = 0; // Biggest horizontal fill step. - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - child_wid->SetupSmallestSize(w, init_array); - highest = max(highest, child_wid->smallest_y); - max_hor_fill = max(max_hor_fill, child_wid->GetHorizontalStepSize(ST_SMALLEST)); - this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); - } - /* 1b. Make the container wider if needed to accommodate all children nicely. */ - uint max_smallest = this->smallest_x + 3 * max_hor_fill; // Upper limit to computing smallest height. - uint cur_width = this->smallest_x; - for (;;) { - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - uint step_size = child_wid->GetHorizontalStepSize(ST_SMALLEST); - uint child_width = child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right; - if (step_size > 1 && child_width < cur_width) { // Small step sizes or already fitting children are not interesting. - uint remainder = (cur_width - child_width) % step_size; - if (remainder > 0) { // Child did not fit entirely, widen the container. - cur_width += step_size - remainder; - assert(cur_width < max_smallest); // Safeguard against infinite width expansion. - /* Remaining children will adapt to the new cur_width, thus speeding up the computation. */ - } - } - } - if (this->smallest_x == cur_width) break; - this->smallest_x = cur_width; // Smallest width got changed, try again. - } - /* 2. For containers that must maintain equal width, extend children minimal size. */ - if (this->flags & NC_EQUALSIZE) { - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - if (child_wid->fill_y == 1) child_wid->smallest_y = highest; - } - } - /* 3. Move PIP space to the child, compute smallest, fill, and resize values of the container. */ - if (this->head != NULL) this->head->padding_top += this->pip_pre; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - if (child_wid->next != NULL) { - child_wid->padding_bottom += this->pip_inter; - } else { - child_wid->padding_bottom += this->pip_post; - } - - this->smallest_y += child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom; - if (child_wid->fill_y > 0) { - if (this->fill_y == 0 || this->fill_y > child_wid->fill_y) this->fill_y = child_wid->fill_y; - } - this->fill_x = LeastCommonMultiple(this->fill_x, child_wid->fill_x); - - if (child_wid->resize_y > 0) { - if (this->resize_y == 0 || this->resize_y > child_wid->resize_y) this->resize_y = child_wid->resize_y; - } - this->resize_x = LeastCommonMultiple(this->resize_x, child_wid->resize_x); - } - /* We need to zero the PIP settings so we can re-initialize the tree. */ - this->pip_pre = this->pip_inter = this->pip_post = 0; -} - -void NWidgetVertical::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) -{ - assert(given_width >= this->smallest_x && given_height >= this->smallest_y); - - /* Compute additional height given to us. */ - uint additional_length = given_height; - if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) { - /* For EQUALSIZE containers this does not sum to smallest_y during initialisation */ - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - additional_length -= child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom; - } - } else { - additional_length -= this->smallest_y; - } - - this->StoreSizePosition(sizing, x, y, given_width, given_height); - - /* Like the horizontal container, the vertical container also distributes additional height evenly, starting with the children with the biggest resize steps. - * It also stores computed widths and heights into current_x and current_y values of the child. - */ - - /* First loop: Find biggest stepsize, find number of children that want a piece of the pie, handle horizontal size for all children, handle vertical size for non-resizing child. */ - int num_changing_childs = 0; // Number of children that can change size. - uint biggest_stepsize = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - uint vert_step = child_wid->GetVerticalStepSize(sizing); - if (vert_step > 0) { - num_changing_childs++; - biggest_stepsize = max(biggest_stepsize, vert_step); - } else { - child_wid->current_y = child_wid->smallest_y; - } - - uint hor_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing); - child_wid->current_x = ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding_left - child_wid->padding_right, hor_step); - } - - /* Second loop: Allocate the additional vertical space over the resizing children, starting with the biggest resize steps. */ - while (biggest_stepsize > 0) { - uint next_biggest_stepsize = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - uint vert_step = child_wid->GetVerticalStepSize(sizing); - if (vert_step > biggest_stepsize) continue; // Already done - if (vert_step == biggest_stepsize) { - uint increment = additional_length / num_changing_childs; - num_changing_childs--; - if (vert_step > 1) increment -= increment % vert_step; - child_wid->current_y = child_wid->smallest_y + increment; - additional_length -= increment; - continue; - } - next_biggest_stepsize = max(next_biggest_stepsize, vert_step); - } - biggest_stepsize = next_biggest_stepsize; - } - assert(num_changing_childs == 0); - - /* Third loop: Compute position and call the child. */ - uint position = 0; // Place to put next child relative to origin of the container. - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - uint child_x = x + (rtl ? child_wid->padding_right : child_wid->padding_left); - uint child_height = child_wid->current_y; - - child_wid->AssignSizePosition(sizing, child_x, y + position + child_wid->padding_top, child_wid->current_x, child_height, rtl); - position += child_height + child_wid->padding_top + child_wid->padding_bottom; - } -} - -/** - * Generic spacer widget. - * @param length Horizontal size of the spacer widget. - * @param height Vertical size of the spacer widget. - */ -NWidgetSpacer::NWidgetSpacer(int length, int height) : NWidgetResizeBase(NWID_SPACER, 0, 0) -{ - this->SetMinimalSize(length, height); - this->SetResize(0, 0); -} - -void NWidgetSpacer::SetupSmallestSize(Window *w, bool init_array) -{ - this->smallest_x = this->min_x; - this->smallest_y = this->min_y; -} - -void NWidgetSpacer::FillNestedArray(NWidgetBase **array, uint length) -{ -} - -void NWidgetSpacer::Draw(const Window *w) -{ - /* Spacer widget is never visible. */ -} - -void NWidgetSpacer::SetDirty(const Window *w) const -{ - /* Spacer widget never need repainting. */ -} - -NWidgetCore *NWidgetSpacer::GetWidgetFromPos(int x, int y) -{ - return NULL; -} - -NWidgetMatrix::NWidgetMatrix() : NWidgetPIPContainer(NWID_MATRIX, NC_EQUALSIZE), index(-1), clicked(-1), count(-1) -{ -} - -void NWidgetMatrix::SetIndex(int index) -{ - this->index = index; -} - -void NWidgetMatrix::SetColour(Colours colour) -{ - this->colour = colour; -} - -/** - * Sets the clicked widget in the matrix. - * @param clicked The clicked widget. - */ -void NWidgetMatrix::SetClicked(int clicked) -{ - this->clicked = clicked; - if (this->clicked >= 0 && this->sb != NULL && this->widgets_x != 0) { - int vpos = (this->clicked / this->widgets_x) * this->widget_h; // Vertical position of the top. - /* Need to scroll down -> Scroll to the bottom. - * However, last entry has no 'this->pip_inter' underneath, and we must stay below this->sb->GetCount() */ - if (this->sb->GetPosition() < vpos) vpos += this->widget_h - this->pip_inter - 1; - this->sb->ScrollTowards(vpos); - } -} - -/** - * Set the number of elements in this matrix. - * @note Updates the number of elements/capacity of the real scrollbar. - * @param count The number of elements. - */ -void NWidgetMatrix::SetCount(int count) -{ - this->count = count; - - if (this->sb == NULL || this->widgets_x == 0) return; - - /* We need to get the number of pixels the matrix is high/wide. - * So, determine the number of rows/columns based on the number of - * columns/rows (one is constant/unscrollable). - * Then multiply that by the height of a widget, and add the pre - * and post spacing "offsets". */ - count = CeilDiv(count, this->sb->IsVertical() ? this->widgets_x : this->widgets_y); - count *= (this->sb->IsVertical() ? this->head->smallest_y : this->head->smallest_x) + this->pip_inter; - if (count > 0) count -= this->pip_inter; // We counted an inter too much in the multiplication above - count += this->pip_pre + this->pip_post; - this->sb->SetCount(count); - this->sb->SetCapacity(this->sb->IsVertical() ? this->current_y : this->current_x); - this->sb->SetStepSize(this->sb->IsVertical() ? this->widget_h : this->widget_w); -} - -/** - * Assign a scrollbar to this matrix. - * @param sb The scrollbar to assign to us. - */ -void NWidgetMatrix::SetScrollbar(Scrollbar *sb) -{ - this->sb = sb; -} - -void NWidgetMatrix::SetupSmallestSize(Window *w, bool init_array) -{ - assert(this->head != NULL); - assert(this->head->next == NULL); - - if (this->index >= 0 && init_array) { // Fill w->nested_array[] - assert(w->nested_array_size > (uint)this->index); - w->nested_array[this->index] = this; - } - - /* Reset the widget number. */ - NWidgetCore *nw = dynamic_cast(this->head); - assert(nw != NULL); - SB(nw->index, 16, 16, 0); - this->head->SetupSmallestSize(w, init_array); - - Dimension padding = {this->pip_pre + this->pip_post, this->pip_pre + this->pip_post}; - Dimension size = {this->head->smallest_x + padding.width, this->head->smallest_y + padding.height}; - Dimension fill = {0, 0}; - Dimension resize = {this->pip_inter + this->head->smallest_x, this->pip_inter + this->head->smallest_y}; - - if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, padding, &fill, &resize); - - this->smallest_x = size.width; - this->smallest_y = size.height; - this->fill_x = fill.width; - this->fill_y = fill.height; - this->resize_x = resize.width; - this->resize_y = resize.height; -} - -void NWidgetMatrix::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) -{ - assert(given_width >= this->smallest_x && given_height >= this->smallest_y); - - this->pos_x = x; - this->pos_y = y; - this->current_x = given_width; - this->current_y = given_height; - - /* Determine the size of the widgets, and the number of visible widgets on each of the axis. */ - this->widget_w = this->head->smallest_x + this->pip_inter; - this->widget_h = this->head->smallest_y + this->pip_inter; - - /* Account for the pip_inter is between widgets, so we need to account for that when - * the division assumes pip_inter is used for all widgets. */ - this->widgets_x = CeilDiv(this->current_x - this->pip_pre - this->pip_post + this->pip_inter, this->widget_w); - this->widgets_y = CeilDiv(this->current_y - this->pip_pre - this->pip_post + this->pip_inter, this->widget_h); - - /* When resizing, update the scrollbar's count. E.g. with a vertical - * scrollbar becoming wider or narrower means the amount of rows in - * the scrollbar becomes respectively smaller or higher. */ - this->SetCount(this->count); -} - -void NWidgetMatrix::FillNestedArray(NWidgetBase **array, uint length) -{ - if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; - NWidgetContainer::FillNestedArray(array, length); -} - -NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y) -{ - /* Falls outside of the matrix widget. */ - if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; - - int start_x, start_y, base_offs_x, base_offs_y; - this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y); - - bool rtl = _current_text_dir == TD_RTL; - - int widget_col = (rtl ? - -x + (int)this->pip_post + (int)this->pos_x + base_offs_x + (int)this->widget_w - 1 - (int)this->pip_inter : - x - (int)this->pip_pre - (int)this->pos_x - base_offs_x - ) / this->widget_w; - - int widget_row = (y - base_offs_y - (int)this->pip_pre - (int)this->pos_y) / this->widget_h; - - int sub_wid = (widget_row + start_y) * this->widgets_x + start_x + widget_col; - if (sub_wid >= this->count) return NULL; - - NWidgetCore *child = dynamic_cast(this->head); - assert(child != NULL); - child->AssignSizePosition(ST_RESIZE, - this->pos_x + (rtl ? this->pip_post - widget_col * this->widget_w : this->pip_pre + widget_col * this->widget_w) + base_offs_x, - this->pos_y + this->pip_pre + widget_row * this->widget_h + base_offs_y, - child->smallest_x, child->smallest_y, rtl); - - SB(child->index, 16, 16, sub_wid); - - return child->GetWidgetFromPos(x, y); -} - -/* virtual */ void NWidgetMatrix::Draw(const Window *w) -{ - /* Fill the background. */ - GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, _colour_gradient[this->colour & 0xF][5]); - - /* Set up a clipping area for the previews. */ - bool rtl = _current_text_dir == TD_RTL; - DrawPixelInfo tmp_dpi; - if (!FillDrawPixelInfo(&tmp_dpi, this->pos_x + (rtl ? this->pip_post : this->pip_pre), this->pos_y + this->pip_pre, this->current_x - this->pip_pre - this->pip_post, this->current_y - this->pip_pre - this->pip_post)) return; - DrawPixelInfo *old_dpi = _cur_dpi; - _cur_dpi = &tmp_dpi; - - /* Get the appropriate offsets so we can draw the right widgets. */ - NWidgetCore *child = dynamic_cast(this->head); - assert(child != NULL); - int start_x, start_y, base_offs_x, base_offs_y; - this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y); - - int offs_y = base_offs_y; - for (int y = start_y; y < start_y + this->widgets_y + 1; y++, offs_y += this->widget_h) { - /* Are we within bounds? */ - if (offs_y + child->smallest_y <= 0) continue; - if (offs_y >= (int)this->current_y) break; - - /* We've passed our amount of widgets. */ - if (y * this->widgets_x >= this->count) break; - - int offs_x = base_offs_x; - for (int x = start_x; x < start_x + this->widgets_x + 1; x++, offs_x += rtl ? -this->widget_w : this->widget_w) { - /* Are we within bounds? */ - if (offs_x + child->smallest_x <= 0) continue; - if (offs_x >= (int)this->current_x) continue; - - /* Do we have this many widgets? */ - int sub_wid = y * this->widgets_x + x; - if (sub_wid >= this->count) break; - - child->AssignSizePosition(ST_RESIZE, offs_x, offs_y, child->smallest_x, child->smallest_y, rtl); - child->SetLowered(this->clicked == sub_wid); - SB(child->index, 16, 16, sub_wid); - child->Draw(w); - } - } - - /* Restore the clipping area. */ - _cur_dpi = old_dpi; -} - -/** - * Get the different offsets that are influenced by scrolling. - * @param [out] start_x The start position in columns (index of the left-most column, swapped in RTL). - * @param [out] start_y The start position in rows. - * @param [out] base_offs_x The base horizontal offset in pixels (X position of the column \a start_x). - * @param [out] base_offs_y The base vertical offset in pixels (Y position of the column \a start_y). - */ -void NWidgetMatrix::GetScrollOffsets(int &start_x, int &start_y, int &base_offs_x, int &base_offs_y) -{ - base_offs_x = _current_text_dir == TD_RTL ? this->widget_w * (this->widgets_x - 1) : 0; - base_offs_y = 0; - start_x = 0; - start_y = 0; - if (this->sb != NULL) { - if (this->sb->IsVertical()) { - start_y = this->sb->GetPosition() / this->widget_h; - base_offs_y += -this->sb->GetPosition() + start_y * this->widget_h; - } else { - start_x = this->sb->GetPosition() / this->widget_w; - int sub_x = this->sb->GetPosition() - start_x * this->widget_w; - if (_current_text_dir == TD_RTL) { - base_offs_x += sub_x; - } else { - base_offs_x -= sub_x; - } - } - } -} - -/** - * Constructor parent nested widgets. - * @param tp Type of parent widget. - * @param colour Colour of the parent widget. - * @param index Index in the widget array used by the window system. - * @param child Child container widget (if supplied). If not supplied, a - * vertical container will be inserted while adding the first - * child widget. - */ -NWidgetBackground::NWidgetBackground(WidgetType tp, Colours colour, int index, NWidgetPIPContainer *child) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL) -{ - assert(tp == WWT_PANEL || tp == WWT_INSET || tp == WWT_FRAME); - if (index >= 0) this->SetIndex(index); - this->child = child; -} - -NWidgetBackground::~NWidgetBackground() -{ - if (this->child != NULL) delete this->child; -} - -/** - * Add a child to the parent. - * @param nwid Nested widget to add to the background widget. - * - * Unless a child container has been given in the constructor, a parent behaves as a vertical container. - * You can add several children to it, and they are put underneath each other. - */ -void NWidgetBackground::Add(NWidgetBase *nwid) -{ - if (this->child == NULL) { - this->child = new NWidgetVertical(); - } - this->child->Add(nwid); -} - -/** - * Set additional pre/inter/post space for the background widget. - * - * @param pip_pre Additional space in front of the first child widget (above - * for the vertical container, at the left for the horizontal container). - * @param pip_inter Additional space between two child widgets. - * @param pip_post Additional space after the last child widget (below for the - * vertical container, at the right for the horizontal container). - * @note Using this function implies that the widget has (or will have) child widgets. - */ -void NWidgetBackground::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) -{ - if (this->child == NULL) { - this->child = new NWidgetVertical(); - } - this->child->SetPIP(pip_pre, pip_inter, pip_post); -} - -void NWidgetBackground::SetupSmallestSize(Window *w, bool init_array) -{ - if (init_array && this->index >= 0) { - assert(w->nested_array_size > (uint)this->index); - w->nested_array[this->index] = this; - } - if (this->child != NULL) { - this->child->SetupSmallestSize(w, init_array); - - this->smallest_x = this->child->smallest_x; - this->smallest_y = this->child->smallest_y; - this->fill_x = this->child->fill_x; - this->fill_y = this->child->fill_y; - this->resize_x = this->child->resize_x; - this->resize_y = this->child->resize_y; - - /* Account for the size of the frame's text if that exists */ - if (w != NULL && this->type == WWT_FRAME) { - this->child->padding_left = WD_FRAMETEXT_LEFT; - this->child->padding_right = WD_FRAMETEXT_RIGHT; - this->child->padding_top = max((int)WD_FRAMETEXT_TOP, this->widget_data != STR_NULL ? FONT_HEIGHT_NORMAL + WD_FRAMETEXT_TOP / 2 : 0); - this->child->padding_bottom = WD_FRAMETEXT_BOTTOM; - - this->smallest_x += this->child->padding_left + this->child->padding_right; - this->smallest_y += this->child->padding_top + this->child->padding_bottom; - - if (this->index >= 0) w->SetStringParameters(this->index); - this->smallest_x = max(this->smallest_x, GetStringBoundingBox(this->widget_data).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT); - } - } else { - Dimension d = {this->min_x, this->min_y}; - Dimension fill = {this->fill_x, this->fill_y}; - Dimension resize = {this->resize_x, this->resize_y}; - if (w != NULL) { // A non-NULL window pointer acts as switch to turn dynamic widget size on. - if (this->type == WWT_FRAME || this->type == WWT_INSET) { - if (this->index >= 0) w->SetStringParameters(this->index); - Dimension background = GetStringBoundingBox(this->widget_data); - background.width += (this->type == WWT_FRAME) ? (WD_FRAMETEXT_LEFT + WD_FRAMERECT_RIGHT) : (WD_INSET_LEFT + WD_INSET_RIGHT); - d = maxdim(d, background); - } - if (this->index >= 0) { - static const Dimension padding = {0, 0}; - w->UpdateWidgetSize(this->index, &d, padding, &fill, &resize); - } - } - this->smallest_x = d.width; - this->smallest_y = d.height; - this->fill_x = fill.width; - this->fill_y = fill.height; - this->resize_x = resize.width; - this->resize_y = resize.height; - } -} - -void NWidgetBackground::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) -{ - this->StoreSizePosition(sizing, x, y, given_width, given_height); - - if (this->child != NULL) { - uint x_offset = (rtl ? this->child->padding_right : this->child->padding_left); - uint width = given_width - this->child->padding_right - this->child->padding_left; - uint height = given_height - this->child->padding_top - this->child->padding_bottom; - this->child->AssignSizePosition(sizing, x + x_offset, y + this->child->padding_top, width, height, rtl); - } -} - -void NWidgetBackground::FillNestedArray(NWidgetBase **array, uint length) -{ - if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; - if (this->child != NULL) this->child->FillNestedArray(array, length); -} - -void NWidgetBackground::Draw(const Window *w) -{ - if (this->current_x == 0 || this->current_y == 0) return; - - Rect r; - r.left = this->pos_x; - r.right = this->pos_x + this->current_x - 1; - r.top = this->pos_y; - r.bottom = this->pos_y + this->current_y - 1; - - const DrawPixelInfo *dpi = _cur_dpi; - if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return; - - switch (this->type) { - case WWT_PANEL: - assert(this->widget_data == 0); - DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, this->IsLowered() ? FR_LOWERED : FR_NONE); - break; - - case WWT_FRAME: - if (this->index >= 0) w->SetStringParameters(this->index); - DrawFrame(r, this->colour, this->widget_data); - break; - - case WWT_INSET: - if (this->index >= 0) w->SetStringParameters(this->index); - DrawInset(r, this->colour, this->widget_data); - break; - - default: - NOT_REACHED(); - } - - if (this->index >= 0) w->DrawWidget(r, this->index); - if (this->child != NULL) this->child->Draw(w); - - if (this->IsDisabled()) { - GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); - } -} - -NWidgetCore *NWidgetBackground::GetWidgetFromPos(int x, int y) -{ - NWidgetCore *nwid = NULL; - if (IsInsideBS(x, this->pos_x, this->current_x) && IsInsideBS(y, this->pos_y, this->current_y)) { - if (this->child != NULL) nwid = this->child->GetWidgetFromPos(x, y); - if (nwid == NULL) nwid = this; - } - return nwid; -} - -NWidgetBase *NWidgetBackground::GetWidgetOfType(WidgetType tp) -{ - NWidgetBase *nwid = NULL; - if (this->child != NULL) nwid = this->child->GetWidgetOfType(tp); - if (nwid == NULL && this->type == tp) nwid = this; - return nwid; -} - -NWidgetViewport::NWidgetViewport(int index) : NWidgetCore(NWID_VIEWPORT, INVALID_COLOUR, 1, 1, 0x0, STR_NULL) -{ - this->SetIndex(index); -} - -void NWidgetViewport::SetupSmallestSize(Window *w, bool init_array) -{ - if (init_array && this->index >= 0) { - assert(w->nested_array_size > (uint)this->index); - w->nested_array[this->index] = this; - } - this->smallest_x = this->min_x; - this->smallest_y = this->min_y; -} - -void NWidgetViewport::Draw(const Window *w) -{ - if (this->disp_flags & ND_NO_TRANSPARENCY) { - TransparencyOptionBits to_backup = _transparency_opt; - _transparency_opt &= (1 << TO_SIGNS) | (1 << TO_LOADING); // Disable all transparency, except textual stuff - w->DrawViewport(); - _transparency_opt = to_backup; - } else { - w->DrawViewport(); - } - - /* Optionally shade the viewport. */ - if (this->disp_flags & (ND_SHADE_GREY | ND_SHADE_DIMMED)) { - GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, - (this->disp_flags & ND_SHADE_DIMMED) ? PALETTE_TO_TRANSPARENT : PALETTE_NEWSPAPER, FILLRECT_RECOLOUR); - } -} - -/** - * Initialize the viewport of the window. - * @param w Window owning the viewport. - * @param follow_flags Type of viewport, see #InitializeWindowViewport(). - * @param zoom Zoom level. - */ -void NWidgetViewport::InitializeViewport(Window *w, uint32 follow_flags, ZoomLevel zoom) -{ - InitializeWindowViewport(w, this->pos_x, this->pos_y, this->current_x, this->current_y, follow_flags, zoom); -} - -/** - * Update the position and size of the viewport (after eg a resize). - * @param w Window owning the viewport. - */ -void NWidgetViewport::UpdateViewportCoordinates(Window *w) -{ - ViewPort *vp = w->viewport; - if (vp != NULL) { - vp->left = w->left + this->pos_x; - vp->top = w->top + this->pos_y; - vp->width = this->current_x; - vp->height = this->current_y; - - vp->virtual_width = ScaleByZoom(vp->width, vp->zoom); - vp->virtual_height = ScaleByZoom(vp->height, vp->zoom); - } -} - -/** - * Compute the row of a scrolled widget that a user clicked in. - * @param clickpos Vertical position of the mouse click (without taking scrolling into account). - * @param w The window the click was in. - * @param widget Widget number of the widget clicked in. - * @param padding Amount of empty space between the widget edge and the top of the first row. Default value is \c 0. - * @param line_height Height of a single row. A negative value means using the vertical resize step of the widget. - * @return Row number clicked at. If clicked at a wrong position, #INT_MAX is returned. - */ -int Scrollbar::GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding, int line_height) const -{ - uint pos = w->GetRowFromWidget(clickpos, widget, padding, line_height); - if (pos != INT_MAX) pos += this->GetPosition(); - return (pos >= this->GetCount()) ? INT_MAX : pos; -} - -/** - * Set capacity of visible elements from the size and resize properties of a widget. - * @param w Window. - * @param widget Widget with size and resize properties. - * @param padding Padding to subtract from the size. - * @note Updates the position if needed. - */ -void Scrollbar::SetCapacityFromWidget(Window *w, int widget, int padding) -{ - NWidgetBase *nwid = w->GetWidget(widget); - if (this->IsVertical()) { - this->SetCapacity(((int)nwid->current_y - padding) / (int)nwid->resize_y); - } else { - this->SetCapacity(((int)nwid->current_x - padding) / (int)nwid->resize_x); - } -} - -/** - * Scrollbar widget. - * @param tp Scrollbar type. (horizontal/vertical) - * @param colour Colour of the scrollbar. - * @param index Index in the widget array used by the window system. - */ -NWidgetScrollbar::NWidgetScrollbar(WidgetType tp, Colours colour, int index) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL), Scrollbar(tp != NWID_HSCROLLBAR) -{ - assert(tp == NWID_HSCROLLBAR || tp == NWID_VSCROLLBAR); - this->sizing_type = NWST_STEP; - this->SetIndex(index); - - switch (this->type) { - case NWID_HSCROLLBAR: - this->SetMinimalSize(0, NWidgetScrollbar::GetHorizontalDimension().height); - this->SetResize(1, 0); - this->SetFill(1, 0); - this->SetDataTip(0x0, STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST); - break; - - case NWID_VSCROLLBAR: - this->SetMinimalSize(NWidgetScrollbar::GetVerticalDimension().width, 0); - this->SetResize(0, 1); - this->SetFill(0, 1); - this->SetDataTip(0x0, STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST); - break; - - default: NOT_REACHED(); - } -} - -void NWidgetScrollbar::SetupSmallestSize(Window *w, bool init_array) -{ - if (init_array && this->index >= 0) { - assert(w->nested_array_size > (uint)this->index); - w->nested_array[this->index] = this; - } - this->smallest_x = this->min_x; - this->smallest_y = this->min_y; -} - -void NWidgetScrollbar::Draw(const Window *w) -{ - if (this->current_x == 0 || this->current_y == 0) return; - - Rect r; - r.left = this->pos_x; - r.right = this->pos_x + this->current_x - 1; - r.top = this->pos_y; - r.bottom = this->pos_y + this->current_y - 1; - - const DrawPixelInfo *dpi = _cur_dpi; - if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return; - - bool up_lowered = HasBit(this->disp_flags, NDB_SCROLLBAR_UP); - bool down_lowered = HasBit(this->disp_flags, NDB_SCROLLBAR_DOWN); - bool middle_lowered = !(this->disp_flags & ND_SCROLLBAR_BTN) && w->scrolling_scrollbar == this->index; - - if (this->type == NWID_HSCROLLBAR) { - DrawHorizontalScrollbar(r, this->colour, up_lowered, middle_lowered, down_lowered, this); - } else { - DrawVerticalScrollbar(r, this->colour, up_lowered, middle_lowered, down_lowered, this); - } - - if (this->IsDisabled()) { - GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); - } -} - -/* static */ void NWidgetScrollbar::InvalidateDimensionCache() -{ - vertical_dimension.width = vertical_dimension.height = 0; - horizontal_dimension.width = horizontal_dimension.height = 0; -} - -/* static */ Dimension NWidgetScrollbar::GetVerticalDimension() -{ - static const Dimension extra = {WD_SCROLLBAR_LEFT + WD_SCROLLBAR_RIGHT, WD_SCROLLBAR_TOP + WD_SCROLLBAR_BOTTOM}; - if (vertical_dimension.width == 0) { - vertical_dimension = maxdim(GetSpriteSize(SPR_ARROW_UP), GetSpriteSize(SPR_ARROW_DOWN)); - vertical_dimension.width += extra.width; - vertical_dimension.width = GetMinSizing(NWST_STEP, vertical_dimension.width); - vertical_dimension.height += extra.height; - vertical_dimension.height = GetMinSizing(NWST_STEP, vertical_dimension.height); - } - return vertical_dimension; -} - -/* static */ Dimension NWidgetScrollbar::GetHorizontalDimension() -{ - static const Dimension extra = {WD_SCROLLBAR_LEFT + WD_SCROLLBAR_RIGHT, WD_SCROLLBAR_TOP + WD_SCROLLBAR_BOTTOM}; - if (horizontal_dimension.width == 0) { - horizontal_dimension = maxdim(GetSpriteSize(SPR_ARROW_LEFT), GetSpriteSize(SPR_ARROW_RIGHT)); - horizontal_dimension.width += extra.width; - horizontal_dimension.width = GetMinSizing(NWST_STEP, horizontal_dimension.width); - horizontal_dimension.height += extra.height; - horizontal_dimension.height = GetMinSizing(NWST_STEP, horizontal_dimension.height); - } - return horizontal_dimension; -} - -Dimension NWidgetScrollbar::vertical_dimension = {0, 0}; -Dimension NWidgetScrollbar::horizontal_dimension = {0, 0}; - -/** Reset the cached dimensions. */ -/* static */ void NWidgetLeaf::InvalidateDimensionCache() -{ - shadebox_dimension.width = shadebox_dimension.height = 0; - debugbox_dimension.width = debugbox_dimension.height = 0; - defsizebox_dimension.width = defsizebox_dimension.height = 0; - stickybox_dimension.width = stickybox_dimension.height = 0; - resizebox_dimension.width = resizebox_dimension.height = 0; - closebox_dimension.width = closebox_dimension.height = 0; - dropdown_dimension.width = dropdown_dimension.height = 0; -} - -Dimension NWidgetLeaf::shadebox_dimension = {0, 0}; -Dimension NWidgetLeaf::debugbox_dimension = {0, 0}; -Dimension NWidgetLeaf::defsizebox_dimension = {0, 0}; -Dimension NWidgetLeaf::stickybox_dimension = {0, 0}; -Dimension NWidgetLeaf::resizebox_dimension = {0, 0}; -Dimension NWidgetLeaf::closebox_dimension = {0, 0}; -Dimension NWidgetLeaf::dropdown_dimension = {0, 0}; - -/** - * Nested leaf widget. - * @param tp Type of leaf widget. - * @param colour Colour of the leaf widget. - * @param index Index in the widget array used by the window system. - * @param data Data of the widget. - * @param tip Tooltip of the widget. - */ -NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, StringID tip) : NWidgetCore(tp, colour, 1, 1, data, tip) -{ - assert(this->sizing_type < NWST_END); - assert(index >= 0 || tp == WWT_LABEL || tp == WWT_TEXT || tp == WWT_CAPTION || tp == WWT_RESIZEBOX || tp == WWT_SHADEBOX || tp == WWT_DEFSIZEBOX || tp == WWT_DEBUGBOX || tp == WWT_STICKYBOX || tp == WWT_CLOSEBOX); - if (index >= 0) this->SetIndex(index); - - if (this->sizing_type == NWST_NONE) { - switch (tp) { - case WWT_PUSHBTN: - case WWT_IMGBTN: - case WWT_PUSHIMGBTN: - case WWT_IMGBTN_2: - case WWT_TEXTBTN: - case WWT_PUSHTXTBTN: - case WWT_TEXTBTN_2: - case WWT_PUSHARROWBTN: - case WWT_EDITBOX: - case WWT_CAPTION: - case WWT_STICKYBOX: - case WWT_SHADEBOX: - case WWT_DEBUGBOX: - case WWT_DEFSIZEBOX: - case WWT_RESIZEBOX: - case WWT_CLOSEBOX: - this->sizing_type = NWST_BUTTON; - break; - case NWID_PUSHBUTTON_DROPDOWN: - case NWID_BUTTON_DROPDOWN: - case WWT_DROPDOWN: - this->sizing_type = NWST_STEP; - break; - default: - this->sizing_type = NWST_OVERRIDE; - } - } - - this->SetMinimalSize(0, 0); - this->SetResize(0, 0); - - switch (tp) { - case WWT_EMPTY: - break; - - case WWT_PUSHBTN: - case WWT_IMGBTN: - case WWT_PUSHIMGBTN: - case WWT_IMGBTN_2: - case WWT_TEXTBTN: - case WWT_PUSHTXTBTN: - case WWT_TEXTBTN_2: - case WWT_LABEL: - case WWT_TEXT: - case WWT_MATRIX: - case NWID_BUTTON_DROPDOWN: - case NWID_PUSHBUTTON_DROPDOWN: - case WWT_ARROWBTN: - case WWT_PUSHARROWBTN: - this->SetFill(0, 0); - break; - - case WWT_EDITBOX: { - Dimension sprite_size = GetSpriteSize(_current_text_dir == TD_RTL ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); - this->SetMinimalSize(30 + sprite_size.width, sprite_size.height); - this->SetFill(0, 0); - break; - } - - case WWT_CAPTION: - this->SetFill(1, 0); - this->SetResize(1, 0); - this->min_y = WD_CAPTION_HEIGHT; - this->SetDataTip(data, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); - break; - - case WWT_STICKYBOX: - this->SetFill(0, 0); - this->SetMinimalSize(WD_STICKYBOX_WIDTH, WD_CAPTION_HEIGHT); - this->SetDataTip(STR_NULL, STR_TOOLTIP_STICKY); - break; - - case WWT_SHADEBOX: - this->SetFill(0, 0); - this->SetMinimalSize(WD_SHADEBOX_TOP, WD_CAPTION_HEIGHT); - this->SetDataTip(STR_NULL, STR_TOOLTIP_SHADE); - break; - - case WWT_DEBUGBOX: - this->SetFill(0, 0); - this->SetMinimalSize(WD_DEBUGBOX_TOP, WD_CAPTION_HEIGHT); - this->SetDataTip(STR_NULL, STR_TOOLTIP_DEBUG); - break; - - case WWT_DEFSIZEBOX: - this->SetFill(0, 0); - this->SetMinimalSize(WD_DEFSIZEBOX_TOP, WD_CAPTION_HEIGHT); - this->SetDataTip(STR_NULL, STR_TOOLTIP_DEFSIZE); - break; - - case WWT_RESIZEBOX: - this->SetFill(0, 0); - this->SetMinimalSize(WD_RESIZEBOX_WIDTH, 12); - this->SetDataTip(STR_NULL, STR_TOOLTIP_RESIZE); - break; - - case WWT_CLOSEBOX: - this->SetFill(0, 0); - this->SetMinimalSize(WD_CLOSEBOX_WIDTH, WD_CAPTION_HEIGHT); - this->SetDataTip(STR_BLACK_CROSS, STR_TOOLTIP_CLOSE_WINDOW); - break; - - case WWT_DROPDOWN: - this->SetFill(0, 0); - this->min_y = WD_DROPDOWN_HEIGHT; - break; - - default: - NOT_REACHED(); - } -} - -void NWidgetLeaf::SetupSmallestSize(Window *w, bool init_array) -{ - if (this->index >= 0 && init_array) { // Fill w->nested_array[] - assert(w->nested_array_size > (uint)this->index); - w->nested_array[this->index] = this; - } - - Dimension size = {this->min_x, this->min_y}; - Dimension fill = {this->fill_x, this->fill_y}; - Dimension resize = {this->resize_x, this->resize_y}; - /* Get padding, and update size with the real content size if appropriate. */ - const Dimension *padding = NULL; - switch (this->type) { - case WWT_EMPTY: { - static const Dimension extra = {0, 0}; - padding = &extra; - break; - } - case WWT_MATRIX: { - static const Dimension extra = {WD_MATRIX_LEFT + WD_MATRIX_RIGHT, WD_MATRIX_TOP + WD_MATRIX_BOTTOM}; - padding = &extra; - break; - } - case WWT_SHADEBOX: { - static const Dimension extra = {WD_SHADEBOX_LEFT + WD_SHADEBOX_RIGHT, WD_SHADEBOX_TOP + WD_SHADEBOX_BOTTOM}; - padding = &extra; - if (NWidgetLeaf::shadebox_dimension.width == 0) { - NWidgetLeaf::shadebox_dimension = maxdim(GetSpriteSize(SPR_WINDOW_SHADE), GetSpriteSize(SPR_WINDOW_UNSHADE)); - NWidgetLeaf::shadebox_dimension.width += extra.width; - NWidgetLeaf::shadebox_dimension.height += extra.height; - } - size = maxdim(size, NWidgetLeaf::shadebox_dimension); - break; - } - case WWT_DEBUGBOX: - if (_settings_client.gui.newgrf_developer_tools && w->IsNewGRFInspectable()) { - static const Dimension extra = {WD_DEBUGBOX_LEFT + WD_DEBUGBOX_RIGHT, WD_DEBUGBOX_TOP + WD_DEBUGBOX_BOTTOM}; - padding = &extra; - if (NWidgetLeaf::debugbox_dimension.width == 0) { - NWidgetLeaf::debugbox_dimension = GetSpriteSize(SPR_WINDOW_DEBUG); - NWidgetLeaf::debugbox_dimension.width += extra.width; - NWidgetLeaf::debugbox_dimension.height += extra.height; - } - size = maxdim(size, NWidgetLeaf::debugbox_dimension); - } else { - /* If the setting is disabled we don't want to see it! */ - size.width = 0; - fill.width = 0; - resize.width = 0; - } - break; - - case WWT_STICKYBOX: { - static const Dimension extra = {WD_STICKYBOX_LEFT + WD_STICKYBOX_RIGHT, WD_STICKYBOX_TOP + WD_STICKYBOX_BOTTOM}; - padding = &extra; - if (NWidgetLeaf::stickybox_dimension.width == 0) { - NWidgetLeaf::stickybox_dimension = maxdim(GetSpriteSize(SPR_PIN_UP), GetSpriteSize(SPR_PIN_DOWN)); - NWidgetLeaf::stickybox_dimension.width += extra.width; - NWidgetLeaf::stickybox_dimension.height += extra.height; - } - size = maxdim(size, NWidgetLeaf::stickybox_dimension); - break; - } - - case WWT_DEFSIZEBOX: { - static const Dimension extra = {WD_DEFSIZEBOX_LEFT + WD_DEFSIZEBOX_RIGHT, WD_DEFSIZEBOX_TOP + WD_DEFSIZEBOX_BOTTOM}; - padding = &extra; - if (NWidgetLeaf::defsizebox_dimension.width == 0) { - NWidgetLeaf::defsizebox_dimension = GetSpriteSize(SPR_WINDOW_DEFSIZE); - NWidgetLeaf::defsizebox_dimension.width += extra.width; - NWidgetLeaf::defsizebox_dimension.height += extra.height; - } - size = maxdim(size, NWidgetLeaf::defsizebox_dimension); - break; - } - - case WWT_RESIZEBOX: { - static const Dimension extra = {WD_RESIZEBOX_LEFT + WD_RESIZEBOX_RIGHT, WD_RESIZEBOX_TOP + WD_RESIZEBOX_BOTTOM}; - padding = &extra; - if (NWidgetLeaf::resizebox_dimension.width == 0) { - NWidgetLeaf::resizebox_dimension = maxdim(GetSpriteSize(SPR_WINDOW_RESIZE_LEFT), GetSpriteSize(SPR_WINDOW_RESIZE_RIGHT)); - NWidgetLeaf::resizebox_dimension.width += extra.width; - NWidgetLeaf::resizebox_dimension.height += extra.height; - } - size = maxdim(size, NWidgetLeaf::resizebox_dimension); - break; - } - case WWT_EDITBOX: - size.height = max(size.height, GetStringBoundingBox("_").height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); - /* FALL THROUGH */ - case WWT_PUSHBTN: { - static const Dimension extra = {WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM}; - padding = &extra; - break; - } - case WWT_IMGBTN: - case WWT_IMGBTN_2: - case WWT_PUSHIMGBTN: { - static const Dimension extra = {WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT, WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM}; - padding = &extra; - Dimension d2 = GetSpriteSize(this->widget_data); - if (this->type == WWT_IMGBTN_2) d2 = maxdim(d2, GetSpriteSize(this->widget_data + 1)); - d2.width += extra.width; - d2.height += extra.height; - size = maxdim(size, d2); - break; - } - case WWT_ARROWBTN: - case WWT_PUSHARROWBTN: { - static const Dimension extra = {WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT, WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM}; - padding = &extra; - Dimension d2 = maxdim(GetSpriteSize(SPR_ARROW_LEFT), GetSpriteSize(SPR_ARROW_RIGHT)); - d2.width += extra.width; - d2.height += extra.height; - size = maxdim(size, d2); - break; - } - - case WWT_CLOSEBOX: { - static const Dimension extra = {WD_CLOSEBOX_LEFT + WD_CLOSEBOX_RIGHT, WD_CLOSEBOX_TOP + WD_CLOSEBOX_BOTTOM}; - padding = &extra; - if (NWidgetLeaf::closebox_dimension.width == 0) { - NWidgetLeaf::closebox_dimension = maxdim(GetStringBoundingBox(STR_BLACK_CROSS), GetStringBoundingBox(STR_SILVER_CROSS)); - NWidgetLeaf::closebox_dimension.width += extra.width; - NWidgetLeaf::closebox_dimension.height += extra.height; - } - size = maxdim(size, NWidgetLeaf::closebox_dimension); - break; - } - case WWT_TEXTBTN: - case WWT_PUSHTXTBTN: - case WWT_TEXTBTN_2: { - static const Dimension extra = {WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM}; - padding = &extra; - if (this->index >= 0) w->SetStringParameters(this->index); - Dimension d2 = GetStringBoundingBox(this->widget_data); - d2.width += extra.width; - d2.height += extra.height; - size = maxdim(size, d2); - break; - } - case WWT_LABEL: - case WWT_TEXT: { - static const Dimension extra = {0, 0}; - padding = &extra; - if (this->index >= 0) w->SetStringParameters(this->index); - size = maxdim(size, GetStringBoundingBox(this->widget_data)); - break; - } - case WWT_CAPTION: { - static const Dimension extra = {WD_CAPTIONTEXT_LEFT + WD_CAPTIONTEXT_RIGHT, WD_CAPTIONTEXT_TOP + WD_CAPTIONTEXT_BOTTOM}; - padding = &extra; - if (this->index >= 0) w->SetStringParameters(this->index); - Dimension d2 = GetStringBoundingBox(this->widget_data); - d2.width += extra.width; - d2.height += extra.height; - size = maxdim(size, d2); - break; - } - case WWT_DROPDOWN: - case NWID_BUTTON_DROPDOWN: - case NWID_PUSHBUTTON_DROPDOWN: { - static Dimension extra = {WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM}; - padding = &extra; - if (NWidgetLeaf::dropdown_dimension.width == 0) { - NWidgetLeaf::dropdown_dimension = GetSpriteSize(SPR_ARROW_DOWN); - NWidgetLeaf::dropdown_dimension.width += WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT; - NWidgetLeaf::dropdown_dimension.height += WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM; - extra.width = WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT + NWidgetLeaf::dropdown_dimension.width; - } - if (this->index >= 0) w->SetStringParameters(this->index); - Dimension d2 = GetStringBoundingBox(this->widget_data); - d2.width += extra.width; - d2.height += extra.height; - size = maxdim(size, d2); - break; - } - default: - NOT_REACHED(); - } - - if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, *padding, &fill, &resize); - - this->smallest_x = size.width; - this->smallest_y = size.height; - this->fill_x = fill.width; - this->fill_y = fill.height; - this->resize_x = resize.width; - this->resize_y = resize.height; -} - -void NWidgetLeaf::Draw(const Window *w) -{ - if (this->current_x == 0 || this->current_y == 0) return; - - Rect r; - r.left = this->pos_x; - r.right = this->pos_x + this->current_x - 1; - r.top = this->pos_y; - r.bottom = this->pos_y + this->current_y - 1; - - const DrawPixelInfo *dpi = _cur_dpi; - if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return; - - bool clicked = this->IsLowered(); - switch (this->type) { - case WWT_EMPTY: - break; - - case WWT_PUSHBTN: - assert(this->widget_data == 0); - DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, (clicked) ? FR_LOWERED : FR_NONE); - break; - - case WWT_IMGBTN: - case WWT_PUSHIMGBTN: - case WWT_IMGBTN_2: - DrawImageButtons(r, this->type, this->colour, clicked, this->widget_data); - break; - - case WWT_TEXTBTN: - case WWT_PUSHTXTBTN: - case WWT_TEXTBTN_2: - if (this->index >= 0) w->SetStringParameters(this->index); - DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawLabel(r, this->type, clicked, this->widget_data); - break; - - case WWT_ARROWBTN: - case WWT_PUSHARROWBTN: { - SpriteID sprite; - switch (this->widget_data) { - case AWV_DECREASE: sprite = _current_text_dir != TD_RTL ? SPR_ARROW_LEFT : SPR_ARROW_RIGHT; break; - case AWV_INCREASE: sprite = _current_text_dir == TD_RTL ? SPR_ARROW_LEFT : SPR_ARROW_RIGHT; break; - case AWV_LEFT: sprite = SPR_ARROW_LEFT; break; - case AWV_RIGHT: sprite = SPR_ARROW_RIGHT; break; - default: NOT_REACHED(); - } - DrawImageButtons(r, WWT_PUSHIMGBTN, this->colour, clicked, sprite); - break; - } - - case WWT_LABEL: - if (this->index >= 0) w->SetStringParameters(this->index); - DrawLabel(r, this->type, clicked, this->widget_data); - break; - - case WWT_TEXT: - if (this->index >= 0) w->SetStringParameters(this->index); - DrawText(r, (TextColour)this->colour, this->widget_data); - break; - - case WWT_MATRIX: - DrawMatrix(r, this->colour, clicked, this->widget_data, this->resize_x, this->resize_y); - break; - - case WWT_EDITBOX: { - const QueryString *query = w->GetQueryString(this->index); - if (query != NULL) query->DrawEditBox(w, this->index); - break; - } - - case WWT_CAPTION: - if (this->index >= 0) w->SetStringParameters(this->index); - DrawCaption(r, this->colour, w->owner, this->widget_data); - break; - - case WWT_SHADEBOX: - assert(this->widget_data == 0); - DrawImageButtons(r, WWT_SHADEBOX, this->colour, w->IsShaded(), w->IsShaded() ? SPR_WINDOW_SHADE : SPR_WINDOW_UNSHADE); - break; - - case WWT_DEBUGBOX: - DrawImageButtons(r, WWT_DEBUGBOX, this->colour, clicked, SPR_WINDOW_DEBUG); - break; - - case WWT_STICKYBOX: { - assert(this->widget_data == 0); - bool clicked = !!(w->flags & WF_STICKY); - DrawImageButtons(r, WWT_STICKYBOX, this->colour, clicked, clicked ? SPR_PIN_DOWN : SPR_PIN_UP); - break; - } - - case WWT_DEFSIZEBOX: - assert(this->widget_data == 0); - DrawImageButtons(r, WWT_DEFSIZEBOX, this->colour, clicked, SPR_WINDOW_DEFSIZE); - break; - - case WWT_RESIZEBOX: - assert(this->widget_data == 0); - DrawResizeBox(r, this->colour, this->pos_x < (uint)(w->width / 2), !!(w->flags & WF_SIZING)); - break; - - case WWT_CLOSEBOX: - DrawCloseBox(r, this->colour, this->widget_data); - break; - - case WWT_DROPDOWN: - if (this->index >= 0) w->SetStringParameters(this->index); - DrawDropdown(r, this->colour, clicked, this->widget_data); - break; - - case NWID_BUTTON_DROPDOWN: - case NWID_PUSHBUTTON_DROPDOWN: - if (this->index >= 0) w->SetStringParameters(this->index); - DrawButtonDropdown(r, this->colour, clicked, (this->disp_flags & ND_DROPDOWN_ACTIVE) != 0, this->widget_data); - break; - - default: - NOT_REACHED(); - } - if (this->index >= 0) w->DrawWidget(r, this->index); - - if (this->IsDisabled()) { - GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); - } -} - -/** - * For a #NWID_BUTTON_DROPDOWN, test whether \a pt refers to the button or to the drop-down. - * @param pt Point in the widget. - * @return The point refers to the button. - * - * @note The magic constants are also used at #DrawButtonDropdown. - */ -bool NWidgetLeaf::ButtonHit(const Point &pt) -{ - uint button_size = GetMinSizing(NWST_STEP, 12); - if (_current_text_dir == TD_LTR) { - int button_width = this->pos_x + this->current_x - button_size; - return pt.x < button_width; - } else { - int button_left = this->pos_x + button_size; - return pt.x >= button_left; - } -} - -/* == Conversion code from NWidgetPart array to NWidgetBase* tree == */ - -/** - * Construct a single nested widget in \a *dest from its parts. - * - * Construct a NWidgetBase object from a #NWidget function, and apply all - * settings that follow it, until encountering a #EndContainer, another - * #NWidget, or the end of the parts array. - * - * @param parts Array with parts of the nested widget. - * @param count Length of the \a parts array. - * @param dest Address of pointer to use for returning the composed widget. - * @param fill_dest Fill the composed widget with child widgets. - * @param biggest_index Pointer to biggest nested widget index in the tree encountered so far. - * @return Number of widget part elements used to compose the widget. - * @pre \c biggest_index != NULL. - */ -static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, bool *fill_dest, int *biggest_index) -{ - int num_used = 0; - - *dest = NULL; - *fill_dest = false; - - while (count > num_used) { - switch (parts->type) { - case NWID_SPACER: - if (*dest != NULL) return num_used; - *dest = new NWidgetSpacer(0, 0); - break; - - case NWID_HORIZONTAL: - if (*dest != NULL) return num_used; - *dest = new NWidgetHorizontal(parts->u.cont_flags); - *fill_dest = true; - break; - - case NWID_HORIZONTAL_LTR: - if (*dest != NULL) return num_used; - *dest = new NWidgetHorizontalLTR(parts->u.cont_flags); - *fill_dest = true; - break; - - case WWT_PANEL: - case WWT_INSET: - case WWT_FRAME: - if (*dest != NULL) return num_used; - *dest = new NWidgetBackground(parts->type, parts->u.widget.colour, parts->u.widget.index); - *biggest_index = max(*biggest_index, (int)parts->u.widget.index); - *fill_dest = true; - break; - - case NWID_VERTICAL: - if (*dest != NULL) return num_used; - *dest = new NWidgetVertical(parts->u.cont_flags); - *fill_dest = true; - break; - - case NWID_MATRIX: { - if (*dest != NULL) return num_used; - NWidgetMatrix *nwm = new NWidgetMatrix(); - *dest = nwm; - *fill_dest = true; - nwm->SetIndex(parts->u.widget.index); - nwm->SetColour(parts->u.widget.colour); - *biggest_index = max(*biggest_index, (int)parts->u.widget.index); - break; - } - - case WPT_FUNCTION: { - if (*dest != NULL) return num_used; - /* Ensure proper functioning even when the called code simply writes its largest index. */ - int biggest = -1; - *dest = parts->u.func_ptr(&biggest); - *biggest_index = max(*biggest_index, biggest); - *fill_dest = false; - break; - } - - case WPT_RESIZE: { - NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != NULL) { - assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0); - nwrb->SetResize(parts->u.xy.x, parts->u.xy.y); - } - break; - } - - case WPT_SIZINGTYPE: { - NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != NULL) { - assert(parts->u.sizing_type < NWST_END); - nwrb->sizing_type = parts->u.sizing_type; - nwrb->SetMinimalSize(0, 0); - } - break; - } - - case WPT_MINSIZE: { - NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != NULL) { - assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0); - nwrb->SetMinimalSize(parts->u.xy.x, parts->u.xy.y); - } - break; - } - - case WPT_MINTEXTLINES: { - NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != NULL) { - assert(parts->u.text_lines.size >= FS_BEGIN && parts->u.text_lines.size < FS_END); - nwrb->SetMinimalTextLines(parts->u.text_lines.lines, parts->u.text_lines.spacing, parts->u.text_lines.size); - } - break; - } - - case WPT_FILL: { - NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != NULL) nwrb->SetFill(parts->u.xy.x, parts->u.xy.y); - break; - } - - case WPT_DATATIP: { - NWidgetCore *nwc = dynamic_cast(*dest); - if (nwc != NULL) { - nwc->widget_data = parts->u.data_tip.data; - nwc->tool_tip = parts->u.data_tip.tooltip; - } - break; - } - - case WPT_PADDING: - if (*dest != NULL) (*dest)->SetPadding(parts->u.padding.top, parts->u.padding.right, parts->u.padding.bottom, parts->u.padding.left); - break; - - case WPT_PIPSPACE: { - NWidgetPIPContainer *nwc = dynamic_cast(*dest); - if (nwc != NULL) nwc->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); - - NWidgetBackground *nwb = dynamic_cast(*dest); - if (nwb != NULL) nwb->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); - break; - } - - case WPT_SCROLLBAR: { - NWidgetCore *nwc = dynamic_cast(*dest); - if (nwc != NULL) { - nwc->scrollbar_index = parts->u.widget.index; - } - break; - } - - case WPT_ENDCONTAINER: - return num_used; - - case NWID_VIEWPORT: - if (*dest != NULL) return num_used; - *dest = new NWidgetViewport(parts->u.widget.index); - *biggest_index = max(*biggest_index, (int)parts->u.widget.index); - break; - - case NWID_HSCROLLBAR: - case NWID_VSCROLLBAR: - if (*dest != NULL) return num_used; - *dest = new NWidgetScrollbar(parts->type, parts->u.widget.colour, parts->u.widget.index); - *biggest_index = max(*biggest_index, (int)parts->u.widget.index); - break; - - case NWID_SELECTION: { - if (*dest != NULL) return num_used; - NWidgetStacked *nws = new NWidgetStacked(); - *dest = nws; - *fill_dest = true; - nws->SetIndex(parts->u.widget.index); - *biggest_index = max(*biggest_index, (int)parts->u.widget.index); - break; - } - - default: - if (*dest != NULL) return num_used; - assert((parts->type & WWT_MASK) < WWT_LAST || (parts->type & WWT_MASK) == NWID_BUTTON_DROPDOWN); - *dest = new NWidgetLeaf(parts->type, parts->u.widget.colour, parts->u.widget.index, 0x0, STR_NULL); - *biggest_index = max(*biggest_index, (int)parts->u.widget.index); - break; - } - num_used++; - parts++; - } - - return num_used; -} - -/** - * Build a nested widget tree by recursively filling containers with nested widgets read from their parts. - * @param parts Array with parts of the nested widgets. - * @param count Length of the \a parts array. - * @param parent Pointer or container to use for storing the child widgets (*parent == NULL or *parent == container or background widget). - * @param biggest_index Pointer to biggest nested widget index in the tree. - * @return Number of widget part elements used to fill the container. - * @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used. - */ -static int MakeWidgetTree(const NWidgetPart *parts, int count, NWidgetBase **parent, int *biggest_index) -{ - /* If *parent == NULL, only the first widget is read and returned. Otherwise, *parent must point to either - * a #NWidgetContainer or a #NWidgetBackground object, and parts are added as much as possible. */ - NWidgetContainer *nwid_cont = dynamic_cast(*parent); - NWidgetBackground *nwid_parent = dynamic_cast(*parent); - assert(*parent == NULL || (nwid_cont != NULL && nwid_parent == NULL) || (nwid_cont == NULL && nwid_parent != NULL)); - - int total_used = 0; - for (;;) { - NWidgetBase *sub_widget = NULL; - bool fill_sub = false; - int num_used = MakeNWidget(parts, count - total_used, &sub_widget, &fill_sub, biggest_index); - parts += num_used; - total_used += num_used; - - /* Break out of loop when end reached */ - if (sub_widget == NULL) break; - - /* If sub-widget is a container, recursively fill that container. */ - WidgetType tp = sub_widget->type; - if (fill_sub && (tp == NWID_HORIZONTAL || tp == NWID_HORIZONTAL_LTR || tp == NWID_VERTICAL || tp == NWID_MATRIX - || tp == WWT_PANEL || tp == WWT_FRAME || tp == WWT_INSET || tp == NWID_SELECTION)) { - NWidgetBase *sub_ptr = sub_widget; - int num_used = MakeWidgetTree(parts, count - total_used, &sub_ptr, biggest_index); - parts += num_used; - total_used += num_used; - } - - /* Add sub_widget to parent container if available, otherwise return the widget to the caller. */ - if (nwid_cont != NULL) nwid_cont->Add(sub_widget); - if (nwid_parent != NULL) nwid_parent->Add(sub_widget); - if (nwid_cont == NULL && nwid_parent == NULL) { - *parent = sub_widget; - return total_used; - } - } - - if (count == total_used) return total_used; // Reached the end of the array of parts? - - assert(total_used < count); - assert(parts->type == WPT_ENDCONTAINER); - return total_used + 1; // *parts is also 'used' -} - -/** - * Construct a nested widget tree from an array of parts. - * @param parts Array with parts of the widgets. - * @param count Length of the \a parts array. - * @param biggest_index Pointer to biggest nested widget index collected in the tree. - * @param container Container to add the nested widgets to. In case it is NULL a vertical container is used. - * @return Root of the nested widget tree, a vertical container containing the entire GUI. - * @ingroup NestedWidgetParts - * @pre \c biggest_index != NULL - * @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used. - */ -NWidgetContainer *MakeNWidgets(const NWidgetPart *parts, int count, int *biggest_index, NWidgetContainer *container) -{ - *biggest_index = -1; - if (container == NULL) container = new NWidgetVertical(); - NWidgetBase *cont_ptr = container; - MakeWidgetTree(parts, count, &cont_ptr, biggest_index); - return container; -} - -/** - * Make a nested widget tree for a window from a parts array. Besides loading, it inserts a shading selection widget - * between the title bar and the window body if the first widget in the parts array looks like a title bar (it is a horizontal - * container with a caption widget) and has a shade box widget. - * @param parts Array with parts of the widgets. - * @param count Length of the \a parts array. - * @param biggest_index Pointer to biggest nested widget index collected in the tree. - * @param [out] shade_select Pointer to the inserted shade selection widget (\c NULL if not unserted). - * @return Root of the nested widget tree, a vertical container containing the entire GUI. - * @ingroup NestedWidgetParts - * @pre \c biggest_index != NULL - * @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used. - */ -NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *parts, int count, int *biggest_index, NWidgetStacked **shade_select) -{ - *biggest_index = -1; - - /* Read the first widget recursively from the array. */ - NWidgetBase *nwid = NULL; - int num_used = MakeWidgetTree(parts, count, &nwid, biggest_index); - assert(nwid != NULL); - parts += num_used; - count -= num_used; - - NWidgetContainer *root = new NWidgetVertical; - root->Add(nwid); - if (count == 0) { // There is no body at all. - *shade_select = NULL; - return root; - } - - /* If the first widget looks like a titlebar, treat it as such. - * If it has a shading box, silently add a shade selection widget in the tree. */ - NWidgetHorizontal *hor_cont = dynamic_cast(nwid); - NWidgetContainer *body; - if (hor_cont != NULL && hor_cont->GetWidgetOfType(WWT_CAPTION) != NULL && hor_cont->GetWidgetOfType(WWT_SHADEBOX) != NULL) { - *shade_select = new NWidgetStacked; - root->Add(*shade_select); - body = new NWidgetVertical; - (*shade_select)->Add(body); - } else { - *shade_select = NULL; - body = root; - } - - /* Load the remaining parts into 'body'. */ - int biggest2 = -1; - MakeNWidgets(parts, count, &biggest2, body); - - *biggest_index = max(*biggest_index, biggest2); - return root; -} - -/** - * Make a number of rows with button-like graphics, for enabling/disabling each company. - * @param biggest_index Storage for collecting the biggest index used in the returned tree. - * @param widget_first The first widget index to use. - * @param widget_last The last widget index to use. - * @param max_length Maximal number of company buttons in one row. - * @param button_tooltip The tooltip-string of every button. - * @return Panel with rows of company buttons. - * @post \c *biggest_index contains the largest used index in the tree. - */ -NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int widget_last, int max_length, StringID button_tooltip) -{ - assert(max_length >= 1); - NWidgetVertical *vert = NULL; // Storage for all rows. - NWidgetHorizontal *hor = NULL; // Storage for buttons in one row. - int hor_length = 0; - - Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON); - sprite_size.width += WD_MATRIX_LEFT + WD_MATRIX_RIGHT; - sprite_size.height += WD_MATRIX_TOP + WD_MATRIX_BOTTOM + 1; // 1 for the 'offset' of being pressed - - for (int widnum = widget_first; widnum <= widget_last; widnum++) { - /* Ensure there is room in 'hor' for another button. */ - if (hor_length == max_length) { - if (vert == NULL) vert = new NWidgetVertical(); - vert->Add(hor); - hor = NULL; - hor_length = 0; - } - if (hor == NULL) { - hor = new NWidgetHorizontal(); - hor_length = 0; - } - - NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum); - panel->sizing_type = NWST_STEP; - panel->SetMinimalSize(sprite_size.width, sprite_size.height); - panel->SetFill(1, 1); - panel->SetResize(1, 0); - panel->SetDataTip(0x0, button_tooltip); - hor->Add(panel); - hor_length++; - } - *biggest_index = widget_last; - if (vert == NULL) return hor; // All buttons fit in a single row. - - if (hor_length > 0 && hor_length < max_length) { - /* Last row is partial, add a spacer at the end to force all buttons to the left. */ - NWidgetSpacer *spc = new NWidgetSpacer(sprite_size.width, sprite_size.height); - spc->SetFill(1, 1); - spc->SetResize(1, 0); - hor->Add(spc); - } - if (hor != NULL) vert->Add(hor); - return vert; -} - -/** - * Return the minimal automatic size for a widget. - * @param type The automatic sizing type to use. - * @param min_1 Minimal passed value. - * @return At least the passed value, or the minimal size for the associated sizing type. - */ -uint GetMinSizing(NWidSizingType type, uint min_1) -{ - uint min_sizing; - switch (type) { - case NWST_NONE: - case NWST_OVERRIDE: - return min_1; - case NWST_BUTTON: - min_sizing = _settings_client.gui.min_button; - break; - case NWST_STEP: - min_sizing = _settings_client.gui.min_step; - break; - case NWST_KEYBOARD: - min_sizing = 2 * _settings_client.gui.min_button; - break; - default: NOT_REACHED(); - } - - return max(min_sizing, min_1); -} diff --git a/src/window.cpp.orig b/src/window.cpp.orig deleted file mode 100644 index 710a9f4140..0000000000 --- a/src/window.cpp.orig +++ /dev/null @@ -1,3515 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file window.cpp Windowing system, widgets and events */ - -#include "stdafx.h" -#include -#include "company_func.h" -#include "gfx_func.h" -#include "console_func.h" -#include "console_gui.h" -#include "viewport_func.h" -#include "progress.h" -#include "blitter/factory.hpp" -#include "zoom_func.h" -#include "vehicle_base.h" -#include "window_func.h" -#include "tilehighlight_func.h" -#include "network/network.h" -#include "querystring_gui.h" -#include "widgets/dropdown_func.h" -#include "strings_func.h" -#include "settings_type.h" -#include "settings_func.h" -#include "ini_type.h" -#include "newgrf_debug.h" -#include "hotkeys.h" -#include "toolbar_gui.h" -#include "statusbar_gui.h" -#include "error.h" -#include "game/game.hpp" -#include "video/video_driver.hpp" -#include "settings_gui.h" -#include "fontcache.h" -#include "error.h" -#include "station_base.h" -#include "waypoint_base.h" -#include "command_func.h" - -#include "table/strings.h" - -/** Values for _settings_client.gui.auto_scrolling */ -enum ViewportAutoscrolling { - VA_DISABLED, //!< Do not autoscroll when mouse is at edge of viewport. - VA_MAIN_VIEWPORT_FULLSCREEN, //!< Scroll main viewport at edge when using fullscreen. - VA_MAIN_VIEWPORT, //!< Scroll main viewport at edge. - VA_EVERY_VIEWPORT, //!< Scroll all viewports at their edges. -}; - -static Point _drag_delta; ///< delta between mouse cursor and upper left corner of dragged window -static Window *_mouseover_last_w = NULL; ///< Window of the last #MOUSEOVER event. -static Window *_last_scroll_window = NULL; ///< Window of the last scroll event. - -/** List of windows opened at the screen sorted from the front. */ -Window *_z_front_window = NULL; -/** List of windows opened at the screen sorted from the back. */ -Window *_z_back_window = NULL; - -/** If false, highlight is white, otherwise the by the widget defined colour. */ -bool _window_highlight_colour = false; - -/* - * Window that currently has focus. - The main purpose is to generate - * #FocusLost events, not to give next window in z-order focus when a - * window is closed. - */ -Window *_focused_window; - -Point _cursorpos_drag_start; - -int _scrollbar_start_pos; -int _scrollbar_size; -byte _scroller_click_timeout = 0; - -bool _scrolling_viewport; ///< A viewport is being scrolled with the mouse. -bool _mouse_hovering; ///< The mouse is hovering over the same point. - -SpecialMouseMode _special_mouse_mode; ///< Mode of the mouse. - -/** - * List of all WindowDescs. - * This is a pointer to ensure initialisation order with the various static WindowDesc instances. - */ -static SmallVector *_window_descs = NULL; - -/** Config file to store WindowDesc */ -char *_windows_file; - -/** Window description constructor. */ -WindowDesc::WindowDesc(WindowPosition def_pos, const char *ini_key, int16 def_width, int16 def_height, - WindowClass window_class, WindowClass parent_class, uint32 flags, - const NWidgetPart *nwid_parts, int16 nwid_length, HotkeyList *hotkeys) : - default_pos(def_pos), - default_width(def_width), - default_height(def_height), - cls(window_class), - parent_cls(parent_class), - ini_key(ini_key), - flags(flags), - nwid_parts(nwid_parts), - nwid_length(nwid_length), - hotkeys(hotkeys), - pref_sticky(false), - pref_width(0), - pref_height(0) -{ - if (_window_descs == NULL) _window_descs = new SmallVector(); - *_window_descs->Append() = this; -} - -WindowDesc::~WindowDesc() -{ - _window_descs->Erase(_window_descs->Find(this)); -} - -/** - * Load all WindowDesc settings from _windows_file. - */ -void WindowDesc::LoadFromConfig() -{ - IniFile *ini = new IniFile(); - ini->LoadFromDisk(_windows_file, BASE_DIR); - for (WindowDesc **it = _window_descs->Begin(); it != _window_descs->End(); ++it) { - if ((*it)->ini_key == NULL) continue; - IniLoadWindowSettings(ini, (*it)->ini_key, *it); - } - delete ini; -} - -/** - * Sort WindowDesc by ini_key. - */ -static int CDECL DescSorter(WindowDesc * const *a, WindowDesc * const *b) -{ - if ((*a)->ini_key != NULL && (*b)->ini_key != NULL) return strcmp((*a)->ini_key, (*b)->ini_key); - return ((*b)->ini_key != NULL ? 1 : 0) - ((*a)->ini_key != NULL ? 1 : 0); -} - -/** - * Save all WindowDesc settings to _windows_file. - */ -void WindowDesc::SaveToConfig() -{ - /* Sort the stuff to get a nice ini file on first write */ - QSortT(_window_descs->Begin(), _window_descs->Length(), DescSorter); - - IniFile *ini = new IniFile(); - ini->LoadFromDisk(_windows_file, BASE_DIR); - for (WindowDesc **it = _window_descs->Begin(); it != _window_descs->End(); ++it) { - if ((*it)->ini_key == NULL) continue; - IniSaveWindowSettings(ini, (*it)->ini_key, *it); - } - ini->SaveToDisk(_windows_file); - delete ini; -} - -/** - * Read default values from WindowDesc configuration an apply them to the window. - */ -void Window::ApplyDefaults() -{ - if (this->nested_root != NULL && this->nested_root->GetWidgetOfType(WWT_STICKYBOX) != NULL) { - if (this->window_desc->pref_sticky) this->flags |= WF_STICKY; - } else { - /* There is no stickybox; clear the preference in case someone tried to be funny */ - this->window_desc->pref_sticky = false; - } -} - -/** - * Compute the row of a widget that a user clicked in. - * @param clickpos Vertical position of the mouse click. - * @param widget Widget number of the widget clicked in. - * @param padding Amount of empty space between the widget edge and the top of the first row. - * @param line_height Height of a single row. A negative value means using the vertical resize step of the widget. - * @return Row number clicked at. If clicked at a wrong position, #INT_MAX is returned. - * @note The widget does not know where a list printed at the widget ends, so below a list is not a wrong position. - */ -int Window::GetRowFromWidget(int clickpos, int widget, int padding, int line_height) const -{ - const NWidgetBase *wid = this->GetWidget(widget); - if (line_height < 0) line_height = wid->resize_y; - if (clickpos < (int)wid->pos_y + padding) return INT_MAX; - return (clickpos - (int)wid->pos_y - padding) / line_height; -} - -/** - * Disable the highlighted status of all widgets. - */ -void Window::DisableAllWidgetHighlight() -{ - for (uint i = 0; i < this->nested_array_size; i++) { - NWidgetBase *nwid = this->GetWidget(i); - if (nwid == NULL) continue; - - if (nwid->IsHighlighted()) { - nwid->SetHighlighted(TC_INVALID); - this->SetWidgetDirty(i); - } - } - - CLRBITS(this->flags, WF_HIGHLIGHTED); -} - -/** - * Sets the highlighted status of a widget. - * @param widget_index index of this widget in the window - * @param highlighted_colour Colour of highlight, or TC_INVALID to disable. - */ -void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour) -{ - assert(widget_index < this->nested_array_size); - - NWidgetBase *nwid = this->GetWidget(widget_index); - if (nwid == NULL) return; - - nwid->SetHighlighted(highlighted_colour); - this->SetWidgetDirty(widget_index); - - if (highlighted_colour != TC_INVALID) { - /* If we set a highlight, the window has a highlight */ - this->flags |= WF_HIGHLIGHTED; - } else { - /* If we disable a highlight, check all widgets if anyone still has a highlight */ - bool valid = false; - for (uint i = 0; i < this->nested_array_size; i++) { - NWidgetBase *nwid = this->GetWidget(i); - if (nwid == NULL) continue; - if (!nwid->IsHighlighted()) continue; - - valid = true; - } - /* If nobody has a highlight, disable the flag on the window */ - if (!valid) CLRBITS(this->flags, WF_HIGHLIGHTED); - } -} - -/** - * Gets the highlighted status of a widget. - * @param widget_index index of this widget in the window - * @return status of the widget ie: highlighted = true, not highlighted = false - */ -bool Window::IsWidgetHighlighted(byte widget_index) const -{ - assert(widget_index < this->nested_array_size); - - const NWidgetBase *nwid = this->GetWidget(widget_index); - if (nwid == NULL) return false; - - return nwid->IsHighlighted(); -} - -/** - * A dropdown window associated to this window has been closed. - * @param pt the point inside the window the mouse resides on after closure. - * @param widget the widget (button) that the dropdown is associated with. - * @param index the element in the dropdown that is selected. - * @param instant_close whether the dropdown was configured to close on mouse up. - */ -void Window::OnDropdownClose(Point pt, int widget, int index, bool instant_close) -{ - if (widget < 0) return; - - if (instant_close) { - /* Send event for selected option if we're still - * on the parent button of the dropdown (behaviour of the dropdowns in the main toolbar). */ - if (GetWidgetFromPos(this, pt.x, pt.y) == widget) { - this->OnDropdownSelect(widget, index); - } - } - - /* Raise the dropdown button */ - NWidgetCore *nwi2 = this->GetWidget(widget); - if ((nwi2->type & WWT_MASK) == NWID_BUTTON_DROPDOWN) { - nwi2->disp_flags &= ~ND_DROPDOWN_ACTIVE; - } else { - this->RaiseWidget(widget); - } - this->SetWidgetDirty(widget); -} - -/** - * Return the Scrollbar to a widget index. - * @param widnum Scrollbar widget index - * @return Scrollbar to the widget - */ -const Scrollbar *Window::GetScrollbar(uint widnum) const -{ - return this->GetWidget(widnum); -} - -/** - * Return the Scrollbar to a widget index. - * @param widnum Scrollbar widget index - * @return Scrollbar to the widget - */ -Scrollbar *Window::GetScrollbar(uint widnum) -{ - return this->GetWidget(widnum); -} - -/** - * Return the querystring associated to a editbox. - * @param widnum Editbox widget index - * @return QueryString or NULL. - */ -const QueryString *Window::GetQueryString(uint widnum) const -{ - const SmallMap::Pair *query = this->querystrings.Find(widnum); - return query != this->querystrings.End() ? query->second : NULL; -} - -/** - * Return the querystring associated to a editbox. - * @param widnum Editbox widget index - * @return QueryString or NULL. - */ -QueryString *Window::GetQueryString(uint widnum) -{ - SmallMap::Pair *query = this->querystrings.Find(widnum); - return query != this->querystrings.End() ? query->second : NULL; -} - -/** - * Get the current input text if an edit box has the focus. - * @return The currently focused input text or NULL if no input focused. - */ -/* virtual */ const char *Window::GetFocusedText() const -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { - return this->GetQueryString(this->nested_focus->index)->GetText(); - } - - return NULL; -} - -/** - * Get the string at the caret if an edit box has the focus. - * @return The text at the caret or NULL if no edit box is focused. - */ -/* virtual */ const char *Window::GetCaret() const -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { - return this->GetQueryString(this->nested_focus->index)->GetCaret(); - } - - return NULL; -} - -/** - * Get the range of the currently marked input text. - * @param[out] length Length of the marked text. - * @return Pointer to the start of the marked text or NULL if no text is marked. - */ -/* virtual */ const char *Window::GetMarkedText(size_t *length) const -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { - return this->GetQueryString(this->nested_focus->index)->GetMarkedText(length); - } - - return NULL; -} - -/** - * Get the current caret position if an edit box has the focus. - * @return Top-left location of the caret, relative to the window. - */ -/* virtual */ Point Window::GetCaretPosition() const -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { - return this->GetQueryString(this->nested_focus->index)->GetCaretPosition(this, this->nested_focus->index); - } - - Point pt = {0, 0}; - return pt; -} - -/** - * Get the bounding rectangle for a text range if an edit box has the focus. - * @param from Start of the string range. - * @param to End of the string range. - * @return Rectangle encompassing the string range, relative to the window. - */ -/* virtual */ Rect Window::GetTextBoundingRect(const char *from, const char *to) const -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { - return this->GetQueryString(this->nested_focus->index)->GetBoundingRect(this, this->nested_focus->index, from, to); - } - - Rect r = {0, 0, 0, 0}; - return r; -} - -/** - * Get the character that is rendered at a position by the focused edit box. - * @param pt The position to test. - * @return Pointer to the character at the position or NULL if no character is at the position. - */ -/* virtual */ const char *Window::GetTextCharacterAtPosition(const Point &pt) const -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { - return this->GetQueryString(this->nested_focus->index)->GetCharAtPosition(this, this->nested_focus->index, pt); - } - - return NULL; -} - -/** - * Set the window that has the focus - * @param w The window to set the focus on - */ -void SetFocusedWindow(Window *w) -{ - if (_focused_window == w) return; - - /* Invalidate focused widget */ - if (_focused_window != NULL) { - if (_focused_window->nested_focus != NULL) _focused_window->nested_focus->SetDirty(_focused_window); - } - - /* Remember which window was previously focused */ - Window *old_focused = _focused_window; - _focused_window = w; - - /* So we can inform it that it lost focus */ - if (old_focused != NULL) old_focused->OnFocusLost(); - if (_focused_window != NULL) _focused_window->OnFocus(); -} - -/** - * Check if an edit box is in global focus. That is if focused window - * has a edit box as focused widget, or if a console is focused. - * @return returns true if an edit box is in global focus or if the focused window is a console, else false - */ -bool EditBoxInGlobalFocus() -{ - if (_focused_window == NULL) return false; - - /* The console does not have an edit box so a special case is needed. */ - if (_focused_window->window_class == WC_CONSOLE) return true; - - return _focused_window->nested_focus != NULL && _focused_window->nested_focus->type == WWT_EDITBOX; -} - -/** - * Makes no widget on this window have focus. The function however doesn't change which window has focus. - */ -void Window::UnfocusFocusedWidget() -{ - if (this->nested_focus != NULL) { - if (this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus(); - - /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ - this->nested_focus->SetDirty(this); - this->nested_focus = NULL; - } -} - -/** - * Set focus within this window to the given widget. The function however doesn't change which window has focus. - * @param widget_index Index of the widget in the window to set the focus to. - * @return Focus has changed. - */ -bool Window::SetFocusedWidget(int widget_index) -{ - /* Do nothing if widget_index is already focused, or if it wasn't a valid widget. */ - if ((uint)widget_index >= this->nested_array_size) return false; - - assert(this->nested_array[widget_index] != NULL); // Setting focus to a non-existing widget is a bad idea. - if (this->nested_focus != NULL) { - if (this->GetWidget(widget_index) == this->nested_focus) return false; - - /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ - this->nested_focus->SetDirty(this); - if (this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus(); - } - this->nested_focus = this->GetWidget(widget_index); - return true; -} - -/** - * Called when window looses focus - */ -void Window::OnFocusLost() -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus(); -} - -/** - * Sets the enabled/disabled status of a list of widgets. - * By default, widgets are enabled. - * On certain conditions, they have to be disabled. - * @param disab_stat status to use ie: disabled = true, enabled = false - * @param widgets list of widgets ended by WIDGET_LIST_END - */ -void CDECL Window::SetWidgetsDisabledState(bool disab_stat, int widgets, ...) -{ - va_list wdg_list; - - va_start(wdg_list, widgets); - - while (widgets != WIDGET_LIST_END) { - SetWidgetDisabledState(widgets, disab_stat); - widgets = va_arg(wdg_list, int); - } - - va_end(wdg_list); -} - -/** - * Sets the lowered/raised status of a list of widgets. - * @param lowered_stat status to use ie: lowered = true, raised = false - * @param widgets list of widgets ended by WIDGET_LIST_END - */ -void CDECL Window::SetWidgetsLoweredState(bool lowered_stat, int widgets, ...) -{ - va_list wdg_list; - - va_start(wdg_list, widgets); - - while (widgets != WIDGET_LIST_END) { - SetWidgetLoweredState(widgets, lowered_stat); - widgets = va_arg(wdg_list, int); - } - - va_end(wdg_list); -} - -/** - * Raise the buttons of the window. - * @param autoraise Raise only the push buttons of the window. - */ -void Window::RaiseButtons(bool autoraise) -{ - for (uint i = 0; i < this->nested_array_size; i++) { - if (this->nested_array[i] == NULL) continue; - WidgetType type = this->nested_array[i]->type; - if (((type & ~WWB_PUSHBUTTON) < WWT_LAST || type == NWID_PUSHBUTTON_DROPDOWN) && - (!autoraise || (type & WWB_PUSHBUTTON) || type == WWT_EDITBOX) && this->IsWidgetLowered(i)) { - this->RaiseWidget(i); - this->SetWidgetDirty(i); - } - } - - /* Special widgets without widget index */ - NWidgetCore *wid = this->nested_root != NULL ? (NWidgetCore*)this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX) : NULL; - if (wid != NULL) { - wid->SetLowered(false); - wid->SetDirty(this); - } -} - -/** - * Invalidate a widget, i.e. mark it as being changed and in need of redraw. - * @param widget_index the widget to redraw. - */ -void Window::SetWidgetDirty(byte widget_index) const -{ - /* Sometimes this function is called before the window is even fully initialized */ - if (this->nested_array == NULL) return; - - this->nested_array[widget_index]->SetDirty(this); -} - -/** - * A hotkey has been pressed. - * @param hotkey Hotkey index, by default a widget index of a button or editbox. - * @return #ES_HANDLED if the key press has been handled, and the hotkey is not unavailable for some reason. - */ -EventState Window::OnHotkey(int hotkey) -{ - if (hotkey < 0) return ES_NOT_HANDLED; - - NWidgetCore *nw = this->GetWidget(hotkey); - if (nw == NULL || nw->IsDisabled()) return ES_NOT_HANDLED; - - if (nw->type == WWT_EDITBOX) { - if (this->IsShaded()) return ES_NOT_HANDLED; - - /* Focus editbox */ - this->SetFocusedWidget(hotkey); - SetFocusedWindow(this); - } else { - /* Click button */ - this->OnClick(Point(), hotkey, 1); - } - return ES_HANDLED; -} - -/** - * Do all things to make a button look clicked and mark it to be - * unclicked in a few ticks. - * @param widget the widget to "click" - */ -void Window::HandleButtonClick(byte widget) -{ - this->LowerWidget(widget); - this->SetTimeout(); - this->SetWidgetDirty(widget); -} - -static void StartWindowDrag(Window *w); -static void StartWindowSizing(Window *w, bool to_left); - -/** - * Dispatch left mouse-button (possibly double) click in window. - * @param w Window to dispatch event in - * @param x X coordinate of the click - * @param y Y coordinate of the click - * @param click_count Number of fast consecutive clicks at same position - */ -static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count) -{ - NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y); - WidgetType widget_type = (nw != NULL) ? nw->type : WWT_EMPTY; - - bool focused_widget_changed = false; - /* If clicked on a window that previously did dot have focus */ - if (_focused_window != w && // We already have focus, right? - (w->window_desc->flags & WDF_NO_FOCUS) == 0 && // Don't lose focus to toolbars - widget_type != WWT_CLOSEBOX) { // Don't change focused window if 'X' (close button) was clicked - focused_widget_changed = true; - SetFocusedWindow(w); - } - - if (nw == NULL) return; // exit if clicked outside of widgets - - /* don't allow any interaction if the button has been disabled */ - if (nw->IsDisabled()) return; - - int widget_index = nw->index; ///< Index of the widget - - /* Clicked on a widget that is not disabled. - * So unless the clicked widget is the caption bar, change focus to this widget. - * Exception: In the OSK we always want the editbox to stay focussed. */ - if (widget_type != WWT_CAPTION && w->window_class != WC_OSK) { - /* focused_widget_changed is 'now' only true if the window this widget - * is in gained focus. In that case it must remain true, also if the - * local widget focus did not change. As such it's the logical-or of - * both changed states. - * - * If this is not preserved, then the OSK window would be opened when - * a user has the edit box focused and then click on another window and - * then back again on the edit box (to type some text). - */ - focused_widget_changed |= w->SetFocusedWidget(widget_index); - } - - /* Close any child drop down menus. If the button pressed was the drop down - * list's own button, then we should not process the click any further. */ - if (HideDropDownMenu(w) == widget_index && widget_index >= 0) return; - - if ((widget_type & ~WWB_PUSHBUTTON) < WWT_LAST && (widget_type & WWB_PUSHBUTTON)) w->HandleButtonClick(widget_index); - - Point pt = { x, y }; - - switch (widget_type) { - case NWID_VSCROLLBAR: - case NWID_HSCROLLBAR: - ScrollbarClickHandler(w, nw, x, y); - break; - - case WWT_EDITBOX: { - QueryString *query = w->GetQueryString(widget_index); - if (query != NULL) query->ClickEditBox(w, pt, widget_index, click_count, focused_widget_changed); - break; - } - - case WWT_CLOSEBOX: // 'X' - delete w; - return; - - case WWT_CAPTION: // 'Title bar' - StartWindowDrag(w); - return; - - case WWT_RESIZEBOX: - /* When the resize widget is on the left size of the window - * we assume that that button is used to resize to the left. */ - StartWindowSizing(w, (int)nw->pos_x < (w->width / 2)); - nw->SetDirty(w); - return; - - case WWT_DEFSIZEBOX: { - if (_ctrl_pressed) { - w->window_desc->pref_width = w->width; - w->window_desc->pref_height = w->height; - } else { - int16 def_width = max(min(w->window_desc->GetDefaultWidth(), _screen.width), w->nested_root->smallest_x); - int16 def_height = max(min(w->window_desc->GetDefaultHeight(), _screen.height - 50), w->nested_root->smallest_y); - - int dx = (w->resize.step_width == 0) ? 0 : def_width - w->width; - int dy = (w->resize.step_height == 0) ? 0 : def_height - w->height; - /* dx and dy has to go by step.. calculate it. - * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */ - if (w->resize.step_width > 1) dx -= dx % (int)w->resize.step_width; - if (w->resize.step_height > 1) dy -= dy % (int)w->resize.step_height; - ResizeWindow(w, dx, dy, false); - } - - nw->SetLowered(true); - nw->SetDirty(w); - w->SetTimeout(); - break; - } - - case WWT_DEBUGBOX: - w->ShowNewGRFInspectWindow(); - break; - - case WWT_SHADEBOX: - nw->SetDirty(w); - w->SetShaded(!w->IsShaded()); - return; - - case WWT_STICKYBOX: - w->flags ^= WF_STICKY; - nw->SetDirty(w); - if (_ctrl_pressed) w->window_desc->pref_sticky = (w->flags & WF_STICKY) != 0; - return; - - default: - break; - } - - /* Widget has no index, so the window is not interested in it. */ - if (widget_index < 0) return; - - /* Check if the widget is highlighted; if so, disable highlight and dispatch an event to the GameScript */ - if (w->IsWidgetHighlighted(widget_index)) { - w->SetWidgetHighlight(widget_index, TC_INVALID); - Game::NewEvent(new ScriptEventWindowWidgetClick((ScriptWindow::WindowClass)w->window_class, w->window_number, widget_index)); - } - - w->OnClick(pt, widget_index, click_count); -} - -/** - * Dispatch right mouse-button click in window. - * @param w Window to dispatch event in - * @param x X coordinate of the click - * @param y Y coordinate of the click - */ -static void DispatchRightClickEvent(Window *w, int x, int y) -{ - NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y); - if (wid == NULL) return; - - /* No widget to handle, or the window is not interested in it. */ - if (wid->index >= 0) { - Point pt = { x, y }; - if (w->OnRightClick(pt, wid->index)) return; - } - - if (_settings_client.gui.hover_delay == 0 && wid->tool_tip != 0) GuiShowTooltips(w, wid->tool_tip, 0, NULL, TCC_RIGHT_CLICK); -} - -/** - * Dispatch hover of the mouse over a window. - * @param w Window to dispatch event in. - * @param x X coordinate of the click. - * @param y Y coordinate of the click. - */ -static void DispatchHoverEvent(Window *w, int x, int y) -{ - NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y); - - /* No widget to handle */ - if (wid == NULL) return; - - /* Show the tooltip if there is any */ - if (wid->tool_tip != 0) { - GuiShowTooltips(w, wid->tool_tip); - return; - } - - /* Widget has no index, so the window is not interested in it. */ - if (wid->index < 0) return; - - Point pt = { x, y }; - w->OnHover(pt, wid->index); -} - -/** - * Dispatch the mousewheel-action to the window. - * The window will scroll any compatible scrollbars if the mouse is pointed over the bar or its contents - * @param w Window - * @param nwid the widget where the scrollwheel was used - * @param wheel scroll up or down - */ -static void DispatchMouseWheelEvent(Window *w, NWidgetCore *nwid, int wheel) -{ - if (nwid == NULL) return; - - /* Using wheel on caption/shade-box shades or unshades the window. */ - if (nwid->type == WWT_CAPTION || nwid->type == WWT_SHADEBOX) { - w->SetShaded(wheel < 0); - return; - } - - /* Wheeling a vertical scrollbar. */ - if (nwid->type == NWID_VSCROLLBAR) { - NWidgetScrollbar *sb = static_cast(nwid); - if (sb->GetCount() > sb->GetCapacity()) { - sb->UpdatePosition(wheel); - w->SetDirty(); - } - return; - } - - /* Scroll the widget attached to the scrollbar. */ - Scrollbar *sb = (nwid->scrollbar_index >= 0 ? w->GetScrollbar(nwid->scrollbar_index) : NULL); - if (sb != NULL && sb->GetCount() > sb->GetCapacity()) { - sb->UpdatePosition(wheel); - w->SetDirty(); - } -} - -/** - * Returns whether a window may be shown or not. - * @param w The window to consider. - * @return True iff it may be shown, otherwise false. - */ -static bool MayBeShown(const Window *w) -{ - /* If we're not modal, everything is okay. */ - if (!HasModalProgress()) return true; - - switch (w->window_class) { - case WC_MAIN_WINDOW: ///< The background, i.e. the game. - case WC_MODAL_PROGRESS: ///< The actual progress window. - case WC_CONFIRM_POPUP_QUERY: ///< The abort window. - return true; - - default: - return false; - } -} - -/** - * Generate repaint events for the visible part of window w within the rectangle. - * - * The function goes recursively upwards in the window stack, and splits the rectangle - * into multiple pieces at the window edges, so obscured parts are not redrawn. - * - * @param w Window that needs to be repainted - * @param left Left edge of the rectangle that should be repainted - * @param top Top edge of the rectangle that should be repainted - * @param right Right edge of the rectangle that should be repainted - * @param bottom Bottom edge of the rectangle that should be repainted - */ -static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom) -{ - const Window *v; - FOR_ALL_WINDOWS_FROM_BACK_FROM(v, w->z_front) { - if (MayBeShown(v) && - right > v->left && - bottom > v->top && - left < v->left + v->width && - top < v->top + v->height) { - /* v and rectangle intersect with each other */ - int x; - - if (left < (x = v->left)) { - DrawOverlappedWindow(w, left, top, x, bottom); - DrawOverlappedWindow(w, x, top, right, bottom); - return; - } - - if (right > (x = v->left + v->width)) { - DrawOverlappedWindow(w, left, top, x, bottom); - DrawOverlappedWindow(w, x, top, right, bottom); - return; - } - - if (top < (x = v->top)) { - DrawOverlappedWindow(w, left, top, right, x); - DrawOverlappedWindow(w, left, x, right, bottom); - return; - } - - if (bottom > (x = v->top + v->height)) { - DrawOverlappedWindow(w, left, top, right, x); - DrawOverlappedWindow(w, left, x, right, bottom); - return; - } - - return; - } - } - - /* Setup blitter, and dispatch a repaint event to window *wz */ - DrawPixelInfo *dp = _cur_dpi; - dp->width = right - left; - dp->height = bottom - top; - dp->left = left - w->left; - dp->top = top - w->top; - dp->pitch = _screen.pitch; - dp->dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(_screen.dst_ptr, left, top); - dp->zoom = ZOOM_LVL_NORMAL; - w->OnPaint(); -} - -/** - * From a rectangle that needs redrawing, find the windows that intersect with the rectangle. - * These windows should be re-painted. - * @param left Left edge of the rectangle that should be repainted - * @param top Top edge of the rectangle that should be repainted - * @param right Right edge of the rectangle that should be repainted - * @param bottom Bottom edge of the rectangle that should be repainted - */ -void DrawOverlappedWindowForAll(int left, int top, int right, int bottom) -{ - Window *w; - DrawPixelInfo bk; - _cur_dpi = &bk; - - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (MayBeShown(w) && - right > w->left && - bottom > w->top && - left < w->left + w->width && - top < w->top + w->height) { - /* Window w intersects with the rectangle => needs repaint */ - DrawOverlappedWindow(w, left, top, right, bottom); - } - } -} - -/** - * Mark entire window as dirty (in need of re-paint) - * @ingroup dirty - */ -void Window::SetDirty() const -{ - SetDirtyBlocks(this->left, this->top, this->left + this->width, this->top + this->height); -} - -/** - * Re-initialize a window, and optionally change its size. - * @param rx Horizontal resize of the window. - * @param ry Vertical resize of the window. - * @note For just resizing the window, use #ResizeWindow instead. - */ -void Window::ReInit(int rx, int ry) -{ - this->SetDirty(); // Mark whole current window as dirty. - - /* Save current size. */ - int window_width = this->width; - int window_height = this->height; - - this->OnInit(); - /* Re-initialize the window from the ground up. No need to change the nested_array, as all widgets stay where they are. */ - this->nested_root->SetupSmallestSize(this, false); - this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL); - this->width = this->nested_root->smallest_x; - this->height = this->nested_root->smallest_y; - this->resize.step_width = this->nested_root->resize_x; - this->resize.step_height = this->nested_root->resize_y; - - /* Resize as close to the original size + requested resize as possible. */ - window_width = max(window_width + rx, this->width); - window_height = max(window_height + ry, this->height); - int dx = (this->resize.step_width == 0) ? 0 : window_width - this->width; - int dy = (this->resize.step_height == 0) ? 0 : window_height - this->height; - /* dx and dy has to go by step.. calculate it. - * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */ - if (this->resize.step_width > 1) dx -= dx % (int)this->resize.step_width; - if (this->resize.step_height > 1) dy -= dy % (int)this->resize.step_height; - - ResizeWindow(this, dx, dy); - /* ResizeWindow() does this->SetDirty() already, no need to do it again here. */ -} - -/** - * Set the shaded state of the window to \a make_shaded. - * @param make_shaded If \c true, shade the window (roll up until just the title bar is visible), else unshade/unroll the window to its original size. - * @note The method uses #Window::ReInit(), thus after the call, the whole window should be considered changed. - */ -void Window::SetShaded(bool make_shaded) -{ - if (this->shade_select == NULL) return; - - int desired = make_shaded ? SZSP_HORIZONTAL : 0; - if (this->shade_select->shown_plane != desired) { - if (make_shaded) { - if (this->nested_focus != NULL) this->UnfocusFocusedWidget(); - this->unshaded_size.width = this->width; - this->unshaded_size.height = this->height; - this->shade_select->SetDisplayedPlane(desired); - this->ReInit(0, -this->height); - } else { - this->shade_select->SetDisplayedPlane(desired); - int dx = ((int)this->unshaded_size.width > this->width) ? (int)this->unshaded_size.width - this->width : 0; - int dy = ((int)this->unshaded_size.height > this->height) ? (int)this->unshaded_size.height - this->height : 0; - this->ReInit(dx, dy); - } - } -} - -/** - * Find the Window whose parent pointer points to this window - * @param w parent Window to find child of - * @param wc Window class of the window to remove; #WC_INVALID if class does not matter - * @return a Window pointer that is the child of \a w, or \c NULL otherwise - */ -static Window *FindChildWindow(const Window *w, WindowClass wc) -{ - Window *v; - FOR_ALL_WINDOWS_FROM_BACK(v) { - if ((wc == WC_INVALID || wc == v->window_class) && v->parent == w) return v; - } - - return NULL; -} - -/** - * Delete all children a window might have in a head-recursive manner - * @param wc Window class of the window to remove; #WC_INVALID if class does not matter - */ -void Window::DeleteChildWindows(WindowClass wc) const -{ - Window *child = FindChildWindow(this, wc); - while (child != NULL) { - delete child; - child = FindChildWindow(this, wc); - } -} - -/** - * Remove window and all its child windows from the window stack. - */ -Window::~Window() -{ - if (_thd.window_class == this->window_class && - _thd.window_number == this->window_number) { - ResetObjectToPlace(); - } - - /* Prevent Mouseover() from resetting mouse-over coordinates on a non-existing window */ - if (_mouseover_last_w == this) _mouseover_last_w = NULL; - - /* We can't scroll the window when it's closed. */ - if (_last_scroll_window == this) _last_scroll_window = NULL; - - /* Make sure we don't try to access this window as the focused window when it doesn't exist anymore. */ - if (_focused_window == this) { - this->OnFocusLost(); - _focused_window = NULL; - } - - this->DeleteChildWindows(); - - if (this->viewport != NULL) DeleteWindowViewport(this); - - this->SetDirty(); - - free(this->nested_array); // Contents is released through deletion of #nested_root. - delete this->nested_root; - - this->window_class = WC_INVALID; -} - -/** - * Find a window by its class and window number - * @param cls Window class - * @param number Number of the window within the window class - * @return Pointer to the found window, or \c NULL if not available - */ -Window *FindWindowById(WindowClass cls, WindowNumber number) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls && w->window_number == number) return w; - } - - return NULL; -} - -/** - * Find any window by its class. Useful when searching for a window that uses - * the window number as a #WindowType, like #WC_SEND_NETWORK_MSG. - * @param cls Window class - * @return Pointer to the found window, or \c NULL if not available - */ -Window *FindWindowByClass(WindowClass cls) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls) return w; - } - - return NULL; -} - -/** - * Delete a window by its class and window number (if it is open). - * @param cls Window class - * @param number Number of the window within the window class - * @param force force deletion; if false don't delete when stickied - */ -void DeleteWindowById(WindowClass cls, WindowNumber number, bool force) -{ - Window *w = FindWindowById(cls, number); - if (force || w == NULL || - (w->flags & WF_STICKY) == 0) { - delete w; - } -} - -/** - * Delete all windows of a given class - * @param cls Window class of windows to delete - */ -void DeleteWindowByClass(WindowClass cls) -{ - Window *w; - -restart_search: - /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others - * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls) { - delete w; - goto restart_search; - } - } -} - -/** - * Delete all windows of a company. We identify windows of a company - * by looking at the caption colour. If it is equal to the company ID - * then we say the window belongs to the company and should be deleted - * @param id company identifier - */ -void DeleteCompanyWindows(CompanyID id) -{ - Window *w; - -restart_search: - /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others - * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->owner == id) { - delete w; - goto restart_search; - } - } - - /* Also delete the company specific windows that don't have a company-colour. */ - DeleteWindowById(WC_BUY_COMPANY, id); -} - -/** - * Change the owner of all the windows one company can take over from another - * company in the case of a company merger. Do not change ownership of windows - * that need to be deleted once takeover is complete - * @param old_owner original owner of the window - * @param new_owner the new owner of the window - */ -void ChangeWindowOwner(Owner old_owner, Owner new_owner) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->owner != old_owner) continue; - - switch (w->window_class) { - case WC_COMPANY_COLOUR: - case WC_FINANCES: - case WC_STATION_LIST: - case WC_TRAINS_LIST: - case WC_ROADVEH_LIST: - case WC_SHIPS_LIST: - case WC_AIRCRAFT_LIST: - case WC_BUY_COMPANY: - case WC_COMPANY: - case WC_COMPANY_INFRASTRUCTURE: - continue; - - default: - w->owner = new_owner; - break; - } - } -} - -static void BringWindowToFront(Window *w); - -/** - * Find a window and make it the relative top-window on the screen. - * The window gets unshaded if it was shaded, and a white border is drawn at its edges for a brief period of time to visualize its "activation". - * @param cls WindowClass of the window to activate - * @param number WindowNumber of the window to activate - * @return a pointer to the window thus activated - */ -Window *BringWindowToFrontById(WindowClass cls, WindowNumber number) -{ - Window *w = FindWindowById(cls, number); - - if (w != NULL) { - if (w->IsShaded()) w->SetShaded(false); // Restore original window size if it was shaded. - - w->SetWhiteBorder(); - BringWindowToFront(w); - w->SetDirty(); - } - - return w; -} - -static inline bool IsVitalWindow(const Window *w) -{ - switch (w->window_class) { - case WC_MAIN_TOOLBAR: - case WC_STATUS_BAR: - case WC_NEWS_WINDOW: - case WC_SEND_NETWORK_MSG: - return true; - - default: - return false; - } -} - -/** - * Get the z-priority for a given window. This is used in comparison with other z-priority values; - * a window with a given z-priority will appear above other windows with a lower value, and below - * those with a higher one (the ordering within z-priorities is arbitrary). - * @param w The window to get the z-priority for - * @pre w->window_class != WC_INVALID - * @return The window's z-priority - */ -static uint GetWindowZPriority(const Window *w) -{ - assert(w->window_class != WC_INVALID); - - uint z_priority = 0; - - switch (w->window_class) { - case WC_ENDSCREEN: - ++z_priority; - - case WC_HIGHSCORE: - ++z_priority; - - case WC_TOOLTIPS: - ++z_priority; - - case WC_DROPDOWN_MENU: - ++z_priority; - - case WC_MAIN_TOOLBAR: - case WC_STATUS_BAR: - ++z_priority; - - case WC_OSK: - ++z_priority; - - case WC_QUERY_STRING: - case WC_SEND_NETWORK_MSG: - ++z_priority; - - case WC_ERRMSG: - case WC_CONFIRM_POPUP_QUERY: - case WC_MODAL_PROGRESS: - case WC_NETWORK_STATUS_WINDOW: - ++z_priority; - - case WC_GENERATE_LANDSCAPE: - case WC_SAVELOAD: - case WC_GAME_OPTIONS: - case WC_CUSTOM_CURRENCY: - case WC_NETWORK_WINDOW: - case WC_GRF_PARAMETERS: - case WC_AI_LIST: - case WC_AI_SETTINGS: - case WC_TEXTFILE: - ++z_priority; - - case WC_CONSOLE: - ++z_priority; - - case WC_NEWS_WINDOW: - ++z_priority; - - default: - ++z_priority; - - case WC_MAIN_WINDOW: - return z_priority; - } -} - -/** - * Adds a window to the z-ordering, according to its z-priority. - * @param w Window to add - */ -static void AddWindowToZOrdering(Window *w) -{ - assert(w->z_front == NULL && w->z_back == NULL); - - if (_z_front_window == NULL) { - /* It's the only window. */ - _z_front_window = _z_back_window = w; - w->z_front = w->z_back = NULL; - } else { - /* Search down the z-ordering for its location. */ - Window *v = _z_front_window; - uint last_z_priority = UINT_MAX; - while (v != NULL && (v->window_class == WC_INVALID || GetWindowZPriority(v) > GetWindowZPriority(w))) { - if (v->window_class != WC_INVALID) { - /* Sanity check z-ordering, while we're at it. */ - assert(last_z_priority >= GetWindowZPriority(v)); - last_z_priority = GetWindowZPriority(v); - } - - v = v->z_back; - } - - if (v == NULL) { - /* It's the new back window. */ - w->z_front = _z_back_window; - w->z_back = NULL; - _z_back_window->z_back = w; - _z_back_window = w; - } else if (v == _z_front_window) { - /* It's the new front window. */ - w->z_front = NULL; - w->z_back = _z_front_window; - _z_front_window->z_front = w; - _z_front_window = w; - } else { - /* It's somewhere else in the z-ordering. */ - w->z_front = v->z_front; - w->z_back = v; - v->z_front->z_back = w; - v->z_front = w; - } - } -} - - -/** - * Removes a window from the z-ordering. - * @param w Window to remove - */ -static void RemoveWindowFromZOrdering(Window *w) -{ - if (w->z_front == NULL) { - assert(_z_front_window == w); - _z_front_window = w->z_back; - } else { - w->z_front->z_back = w->z_back; - } - - if (w->z_back == NULL) { - assert(_z_back_window == w); - _z_back_window = w->z_front; - } else { - w->z_back->z_front = w->z_front; - } - - w->z_front = w->z_back = NULL; -} - -/** - * On clicking on a window, make it the frontmost window of all windows with an equal - * or lower z-priority. The window is marked dirty for a repaint - * @param w window that is put into the relative foreground - */ -static void BringWindowToFront(Window *w) -{ - RemoveWindowFromZOrdering(w); - AddWindowToZOrdering(w); - - w->SetDirty(); -} - -/** - * Initializes the data (except the position and initial size) of a new Window. - * @param desc Window description. - * @param window_number Number being assigned to the new window - * @return Window pointer of the newly created window - * @pre If nested widgets are used (\a widget is \c NULL), #nested_root and #nested_array_size must be initialized. - * In addition, #nested_array is either \c NULL, or already initialized. - */ -void Window::InitializeData(WindowNumber window_number) -{ - /* Set up window properties; some of them are needed to set up smallest size below */ - this->window_class = this->window_desc->cls; - this->SetWhiteBorder(); - if (this->window_desc->default_pos == WDP_CENTER) this->flags |= WF_CENTERED; - this->owner = INVALID_OWNER; - this->nested_focus = NULL; - this->window_number = window_number; - - this->OnInit(); - /* Initialize nested widget tree. */ - if (this->nested_array == NULL) { - this->nested_array = CallocT(this->nested_array_size); - this->nested_root->SetupSmallestSize(this, true); - } else { - this->nested_root->SetupSmallestSize(this, false); - } - /* Initialize to smallest size. */ - this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL); - - /* Further set up window properties, - * this->left, this->top, this->width, this->height, this->resize.width, and this->resize.height are initialized later. */ - this->resize.step_width = this->nested_root->resize_x; - this->resize.step_height = this->nested_root->resize_y; - - /* Give focus to the opened window unless a text box - * of focused window has focus (so we don't interrupt typing). But if the new - * window has a text box, then take focus anyway. */ - if (!EditBoxInGlobalFocus() || this->nested_root->GetWidgetOfType(WWT_EDITBOX) != NULL) SetFocusedWindow(this); - - /* Insert the window into the correct location in the z-ordering. */ - AddWindowToZOrdering(this); -} - -/** - * Set the position and smallest size of the window. - * @param x Offset in pixels from the left of the screen of the new window. - * @param y Offset in pixels from the top of the screen of the new window. - * @param sm_width Smallest width in pixels of the window. - * @param sm_height Smallest height in pixels of the window. - */ -void Window::InitializePositionSize(int x, int y, int sm_width, int sm_height) -{ - this->left = x; - this->top = y; - this->width = sm_width; - this->height = sm_height; -} - -/** - * Resize window towards the default size. - * Prior to construction, a position for the new window (for its default size) - * has been found with LocalGetWindowPlacement(). Initially, the window is - * constructed with minimal size. Resizing the window to its default size is - * done here. - * @param def_width default width in pixels of the window - * @param def_height default height in pixels of the window - * @see Window::Window(), Window::InitializeData(), Window::InitializePositionSize() - */ -void Window::FindWindowPlacementAndResize(int def_width, int def_height) -{ - def_width = max(def_width, this->width); // Don't allow default size to be smaller than smallest size - def_height = max(def_height, this->height); - /* Try to make windows smaller when our window is too small. - * w->(width|height) is normally the same as min_(width|height), - * but this way the GUIs can be made a little more dynamic; - * one can use the same spec for multiple windows and those - * can then determine the real minimum size of the window. */ - if (this->width != def_width || this->height != def_height) { - /* Think about the overlapping toolbars when determining the minimum window size */ - int free_height = _screen.height; - const Window *wt = FindWindowById(WC_STATUS_BAR, 0); - if (wt != NULL) free_height -= wt->height; - wt = FindWindowById(WC_MAIN_TOOLBAR, 0); - if (wt != NULL) free_height -= wt->height; - - int enlarge_x = max(min(def_width - this->width, _screen.width - this->width), 0); - int enlarge_y = max(min(def_height - this->height, free_height - this->height), 0); - - /* X and Y has to go by step.. calculate it. - * The cast to int is necessary else x/y are implicitly casted to - * unsigned int, which won't work. */ - if (this->resize.step_width > 1) enlarge_x -= enlarge_x % (int)this->resize.step_width; - if (this->resize.step_height > 1) enlarge_y -= enlarge_y % (int)this->resize.step_height; - - ResizeWindow(this, enlarge_x, enlarge_y); - /* ResizeWindow() calls this->OnResize(). */ - } else { - /* Always call OnResize; that way the scrollbars and matrices get initialized. */ - this->OnResize(); - } - - int nx = this->left; - int ny = this->top; - - if (nx + this->width > _screen.width) nx -= (nx + this->width - _screen.width); - - const Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0); - ny = max(ny, (wt == NULL || this == wt || this->top == 0) ? 0 : wt->height); - nx = max(nx, 0); - - if (this->viewport != NULL) { - this->viewport->left += nx - this->left; - this->viewport->top += ny - this->top; - } - this->left = nx; - this->top = ny; - - this->SetDirty(); -} - -/** - * Decide whether a given rectangle is a good place to open a completely visible new window. - * The new window should be within screen borders, and not overlap with another already - * existing window (except for the main window in the background). - * @param left Left edge of the rectangle - * @param top Top edge of the rectangle - * @param width Width of the rectangle - * @param height Height of the rectangle - * @param pos If rectangle is good, use this parameter to return the top-left corner of the new window - * @return Boolean indication that the rectangle is a good place for the new window - */ -static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &pos) -{ - int right = width + left; - int bottom = height + top; - - const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); - if (left < 0 || (main_toolbar != NULL && top < main_toolbar->height) || right > _screen.width || bottom > _screen.height) return false; - - /* Make sure it is not obscured by any window. */ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == WC_MAIN_WINDOW) continue; - - if (right > w->left && - w->left + w->width > left && - bottom > w->top && - w->top + w->height > top) { - return false; - } - } - - pos.x = left; - pos.y = top; - return true; -} - -/** - * Decide whether a given rectangle is a good place to open a mostly visible new window. - * The new window should be mostly within screen borders, and not overlap with another already - * existing window (except for the main window in the background). - * @param left Left edge of the rectangle - * @param top Top edge of the rectangle - * @param width Width of the rectangle - * @param height Height of the rectangle - * @param pos If rectangle is good, use this parameter to return the top-left corner of the new window - * @return Boolean indication that the rectangle is a good place for the new window - */ -static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &pos) -{ - /* Left part of the rectangle may be at most 1/4 off-screen, - * right part of the rectangle may be at most 1/2 off-screen - */ - if (left < -(width >> 2) || left > _screen.width - (width >> 1)) return false; - /* Bottom part of the rectangle may be at most 1/4 off-screen */ - if (top < 22 || top > _screen.height - (height >> 2)) return false; - - /* Make sure it is not obscured by any window. */ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == WC_MAIN_WINDOW) continue; - - if (left + width > w->left && - w->left + w->width > left && - top + height > w->top && - w->top + w->height > top) { - return false; - } - } - - pos.x = left; - pos.y = top; - return true; -} - -/** - * Find a good place for opening a new window of a given width and height. - * @param width Width of the new window - * @param height Height of the new window - * @return Top-left coordinate of the new window - */ -static Point GetAutoPlacePosition(int width, int height) -{ - Point pt; - - /* First attempt, try top-left of the screen */ - const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); - if (IsGoodAutoPlace1(0, main_toolbar != NULL ? main_toolbar->height + 2 : 2, width, height, pt)) return pt; - - /* Second attempt, try around all existing windows with a distance of 2 pixels. - * The new window must be entirely on-screen, and not overlap with an existing window. - * Eight starting points are tried, two at each corner. - */ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == WC_MAIN_WINDOW) continue; - - if (IsGoodAutoPlace1(w->left + w->width + 2, w->top, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left - width - 2, w->top, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left, w->top + w->height + 2, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left, w->top - height - 2, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left + w->width + 2, w->top + w->height - height, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left - width - 2, w->top + w->height - height, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left + w->width - width, w->top + w->height + 2, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left + w->width - width, w->top - height - 2, width, height, pt)) return pt; - } - - /* Third attempt, try around all existing windows with a distance of 2 pixels. - * The new window may be partly off-screen, and must not overlap with an existing window. - * Only four starting points are tried. - */ - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == WC_MAIN_WINDOW) continue; - - if (IsGoodAutoPlace2(w->left + w->width + 2, w->top, width, height, pt)) return pt; - if (IsGoodAutoPlace2(w->left - width - 2, w->top, width, height, pt)) return pt; - if (IsGoodAutoPlace2(w->left, w->top + w->height + 2, width, height, pt)) return pt; - if (IsGoodAutoPlace2(w->left, w->top - height - 2, width, height, pt)) return pt; - } - - /* Fourth and final attempt, put window at diagonal starting from (0, 24), try multiples - * of (+5, +5) - */ - int left = 0, top = 24; - -restart: - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->left == left && w->top == top) { - left += 5; - top += 5; - goto restart; - } - } - - pt.x = left; - pt.y = top; - return pt; -} - -/** - * Computer the position of the top-left corner of a window to be opened right - * under the toolbar. - * @param window_width the width of the window to get the position for - * @return Coordinate of the top-left corner of the new window. - */ -Point GetToolbarAlignedWindowPosition(int window_width) -{ - const Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); - assert(w != NULL); - Point pt = { _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width, w->top + w->height }; - return pt; -} - -/** - * Compute the position of the top-left corner of a new window that is opened. - * - * By default position a child window at an offset of 10/10 of its parent. - * With the exception of WC_BUILD_TOOLBAR (build railway/roads/ship docks/airports) - * and WC_SCEN_LAND_GEN (landscaping). Whose child window has an offset of 0/toolbar-height of - * its parent. So it's exactly under the parent toolbar and no buttons will be covered. - * However if it falls too extremely outside window positions, reposition - * it to an automatic place. - * - * @param *desc The pointer to the WindowDesc to be created. - * @param sm_width Smallest width of the window. - * @param sm_height Smallest height of the window. - * @param window_number The window number of the new window. - * - * @return Coordinate of the top-left corner of the new window. - */ -static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number) -{ - Point pt; - const Window *w; - - int16 default_width = max(desc->GetDefaultWidth(), sm_width); - int16 default_height = max(desc->GetDefaultHeight(), sm_height); - - if (desc->parent_cls != 0 /* WC_MAIN_WINDOW */ && - (w = FindWindowById(desc->parent_cls, window_number)) != NULL && - w->left < _screen.width - 20 && w->left > -60 && w->top < _screen.height - 20) { - - pt.x = w->left + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? 0 : 10); - if (pt.x > _screen.width + 10 - default_width) { - pt.x = (_screen.width + 10 - default_width) - 20; - } - pt.y = w->top + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? w->height : 10); - return pt; - } - - switch (desc->default_pos) { - case WDP_ALIGN_TOOLBAR: // Align to the toolbar - return GetToolbarAlignedWindowPosition(default_width); - - case WDP_AUTO: // Find a good automatic position for the window - return GetAutoPlacePosition(default_width, default_height); - - case WDP_CENTER: // Centre the window horizontally - pt.x = (_screen.width - default_width) / 2; - pt.y = (_screen.height - default_height) / 2; - break; - - case WDP_MANUAL: - pt.x = 0; - pt.y = 0; - break; - - default: - NOT_REACHED(); - } - - return pt; -} - -/* virtual */ Point Window::OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) -{ - return LocalGetWindowPlacement(this->window_desc, sm_width, sm_height, window_number); -} - -/** - * Perform the first part of the initialization of a nested widget tree. - * Construct a nested widget tree in #nested_root, and optionally fill the #nested_array array to provide quick access to the uninitialized widgets. - * This is mainly useful for setting very basic properties. - * @param fill_nested Fill the #nested_array (enabling is expensive!). - * @note Filling the nested array requires an additional traversal through the nested widget tree, and is best performed by #FinishInitNested rather than here. - */ -void Window::CreateNestedTree(bool fill_nested) -{ - int biggest_index = -1; - this->nested_root = MakeWindowNWidgetTree(this->window_desc->nwid_parts, this->window_desc->nwid_length, &biggest_index, &this->shade_select); - this->nested_array_size = (uint)(biggest_index + 1); - - if (fill_nested) { - this->nested_array = CallocT(this->nested_array_size); - this->nested_root->FillNestedArray(this->nested_array, this->nested_array_size); - } -} - -/** - * Perform the second part of the initialization of a nested widget tree. - * @param window_number Number of the new window. - */ -void Window::FinishInitNested(WindowNumber window_number) -{ - this->InitializeData(window_number); - this->ApplyDefaults(); - Point pt = this->OnInitialPosition(this->nested_root->smallest_x, this->nested_root->smallest_y, window_number); - this->InitializePositionSize(pt.x, pt.y, this->nested_root->smallest_x, this->nested_root->smallest_y); - this->FindWindowPlacementAndResize(this->window_desc->GetDefaultWidth(), this->window_desc->GetDefaultHeight()); -} - -/** - * Perform complete initialization of the #Window with nested widgets, to allow use. - * @param window_number Number of the new window. - */ -void Window::InitNested(WindowNumber window_number) -{ - this->CreateNestedTree(false); - this->FinishInitNested(window_number); -} - -/** - * Empty constructor, initialization has been moved to #InitNested() called from the constructor of the derived class. - * @param desc The description of the window. - */ -Window::Window(WindowDesc *desc) : window_desc(desc), scrolling_scrollbar(-1) -{ -} - -/** - * Do a search for a window at specific coordinates. For this we start - * at the topmost window, obviously and work our way down to the bottom - * @param x position x to query - * @param y position y to query - * @return a pointer to the found window if any, NULL otherwise - */ -Window *FindWindowFromPt(int x, int y) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if (MayBeShown(w) && IsInsideBS(x, w->left, w->width) && IsInsideBS(y, w->top, w->height)) { - return w; - } - } - - return NULL; -} - -int SETTING_BUTTON_WIDTH = 20; -int SETTING_BUTTON_HEIGHT = 10; - -/** - * Set button size of settings. If automatic sizing is also enabled, it also sets - * the sizing of buttons, scrollbars and font size (recommend restart). - * @todo Check if it can be moved to another file, so we do not need to include error, string and fontcache headers. - * @todo Fix magic numbers 16/18/20/30/32 - */ -void CheckWindowMinSizings() -{ - if (_settings_client.gui.manage_min_sizing) { - /* Fill the min sizing values for the current resolution. */ - uint swap_x = 32; // in longest border, let main toolbar to have 30 buttons. - uint swap_y = 16; // if short border, let main toolbar have 16/18/20 buttons..) - if (_cur_resolution.width < _cur_resolution.height) Swap(swap_x, swap_y); - _settings_client.gui.min_button = min(_cur_resolution.width / swap_x, _cur_resolution.height / swap_y); - _settings_client.gui.min_step = _settings_client.gui.min_button * 3 / 4; - } - - SETTING_BUTTON_HEIGHT = max(GetMinSizing(NWST_STEP) - 10, 10); - SETTING_BUTTON_WIDTH = 2 * SETTING_BUTTON_HEIGHT; - - extern uint _tooltip_width; - _tooltip_width = max(194, 10 * _settings_client.gui.min_button); - - if (!_settings_client.gui.manage_min_sizing) return; - - _freetype.large.size = _settings_client.gui.min_button; - _freetype.medium.size = max(_settings_client.gui.min_step * 2 / 3, 10U); - _freetype.mono.size = _freetype.medium.size; - _freetype.small.size = max(_freetype.medium.size * 2 / 3, 8U); - - InitFreeType(true); - CheckForMissingGlyphs(); - - if (_z_front_window == NULL) return; - - DeleteAllNonVitalWindows(); - - switch (_game_mode) { - default: break; - case GM_MENU: - DeleteWindowById(WC_SELECT_GAME, 0); - extern void ShowSelectGameWindow(); - ShowSelectGameWindow(); - break; - - case GM_NORMAL: - case GM_EDITOR: { - Station *st; - FOR_ALL_STATIONS(st) { st->UpdateVirtCoord(); } - Waypoint *wp; - FOR_ALL_WAYPOINTS(wp) { wp->UpdateVirtCoord(); } - - HideVitalWindows(); - ShowVitalWindows(); - break; - } - } - - ShowErrorMessage(STR_ERROR_RESET_WINDOWS, STR_ERROR_AUTOMATIC_SIZING, WL_WARNING); -} - -/** - * (re)initialize the windowing system - */ -void InitWindowSystem() -{ - IConsoleClose(); - - _z_back_window = NULL; - _z_front_window = NULL; - _focused_window = NULL; - _mouseover_last_w = NULL; - _last_scroll_window = NULL; - _scrolling_viewport = false; - _mouse_hovering = false; - - NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets. - NWidgetScrollbar::InvalidateDimensionCache(); - - ShowFirstError(); -} - -/** - * Close down the windowing system - */ -void UnInitWindowSystem() -{ - UnshowCriticalError(); - - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) delete w; - - for (w = _z_front_window; w != NULL; /* nothing */) { - Window *to_del = w; - w = w->z_back; - free(to_del); - } - - _z_front_window = NULL; - _z_back_window = NULL; -} - -/** - * Reset the windowing system, by means of shutting it down followed by re-initialization - */ -void ResetWindowSystem() -{ - UnInitWindowSystem(); - InitWindowSystem(); - _thd.Reset(); -} - -static void DecreaseWindowCounters() -{ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if (_scroller_click_timeout == 0) { - /* Unclick scrollbar buttons if they are pressed. */ - for (uint i = 0; i < w->nested_array_size; i++) { - NWidgetBase *nwid = w->nested_array[i]; - if (nwid != NULL && (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR)) { - NWidgetScrollbar *sb = static_cast(nwid); - if (sb->disp_flags & (ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN)) { - sb->disp_flags &= ~(ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN); - w->scrolling_scrollbar = -1; - sb->SetDirty(w); - } - } - } - } - - /* Handle editboxes */ - for (SmallMap::Pair *it = w->querystrings.Begin(); it != w->querystrings.End(); ++it) { - it->second->HandleEditBox(w, it->first); - } - - w->OnMouseLoop(); - } - - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if ((w->flags & WF_TIMEOUT) && --w->timeout_timer == 0) { - CLRBITS(w->flags, WF_TIMEOUT); - - w->OnTimeout(); - w->RaiseButtons(true); - } - } -} - -static void HandlePlacePresize() -{ - if (_special_mouse_mode != WSM_PRESIZE) return; - - Window *w = _thd.GetCallbackWnd(); - if (w == NULL) return; - - Point pt = GetTileBelowCursor(); - if (pt.x == -1) { - _thd.selend.x = -1; - return; - } - - w->OnPlacePresize(pt, TileVirtXY(pt.x, pt.y)); -} - -/** - * Handle dragging and dropping in mouse dragging mode (#WSM_DRAGDROP). - * @return State of handling the event. - */ -static EventState HandleMouseDragDrop() -{ - if (_special_mouse_mode != WSM_DRAGDROP) return ES_NOT_HANDLED; - - if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; // Dragging, but the mouse did not move. - - Window *w = _thd.GetCallbackWnd(); - if (w != NULL) { - /* Send an event in client coordinates. */ - Point pt; - pt.x = _cursor.pos.x - w->left; - pt.y = _cursor.pos.y - w->top; - if (_left_button_down) { - w->OnMouseDrag(pt, GetWidgetFromPos(w, pt.x, pt.y)); - } else { - w->OnDragDrop(pt, GetWidgetFromPos(w, pt.x, pt.y)); - } - } - - if (!_left_button_down) ResetObjectToPlace(); // Button released, finished dragging. - return ES_HANDLED; -} - -/** Report position of the mouse to the underlying window. */ -static void HandleMouseOver() -{ - Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); - - /* We changed window, put a MOUSEOVER event to the last window */ - if (_mouseover_last_w != NULL && _mouseover_last_w != w) { - /* Reset mouse-over coordinates of previous window */ - Point pt = { -1, -1 }; - _mouseover_last_w->OnMouseOver(pt, 0); - } - - /* _mouseover_last_w will get reset when the window is deleted, see DeleteWindow() */ - _mouseover_last_w = w; - - if (w != NULL) { - /* send an event in client coordinates. */ - Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top }; - const NWidgetCore *widget = w->nested_root->GetWidgetFromPos(pt.x, pt.y); - if (widget != NULL) w->OnMouseOver(pt, widget->index); - } -} - -/** The minimum number of pixels of the title bar must be visible in both the X or Y direction */ -static const int MIN_VISIBLE_TITLE_BAR = 13; - -/** Direction for moving the window. */ -enum PreventHideDirection { - PHD_UP, ///< Above v is a safe position. - PHD_DOWN, ///< Below v is a safe position. -}; - -/** - * Do not allow hiding of the rectangle with base coordinates \a nx and \a ny behind window \a v. - * If needed, move the window base coordinates to keep it visible. - * @param nx Base horizontal coordinate of the rectangle. - * @param ny Base vertical coordinate of the rectangle. - * @param rect Rectangle that must stay visible for #MIN_VISIBLE_TITLE_BAR pixels (horizontally, vertically, or both) - * @param v Window lying in front of the rectangle. - * @param px Previous horizontal base coordinate. - * @param dir If no room horizontally, move the rectangle to the indicated position. - */ -static void PreventHiding(int *nx, int *ny, const Rect &rect, const Window *v, int px, PreventHideDirection dir) -{ - if (v == NULL) return; - - int v_bottom = v->top + v->height; - int v_right = v->left + v->width; - int safe_y = (dir == PHD_UP) ? (v->top - MIN_VISIBLE_TITLE_BAR - rect.top) : (v_bottom + MIN_VISIBLE_TITLE_BAR - rect.bottom); // Compute safe vertical position. - - if (*ny + rect.top <= v->top - MIN_VISIBLE_TITLE_BAR) return; // Above v is enough space - if (*ny + rect.bottom >= v_bottom + MIN_VISIBLE_TITLE_BAR) return; // Below v is enough space - - /* Vertically, the rectangle is hidden behind v. */ - if (*nx + rect.left + MIN_VISIBLE_TITLE_BAR < v->left) { // At left of v. - if (v->left < MIN_VISIBLE_TITLE_BAR) *ny = safe_y; // But enough room, force it to a safe position. - return; - } - if (*nx + rect.right - MIN_VISIBLE_TITLE_BAR > v_right) { // At right of v. - if (v_right > _screen.width - MIN_VISIBLE_TITLE_BAR) *ny = safe_y; // Not enough room, force it to a safe position. - return; - } - - /* Horizontally also hidden, force movement to a safe area. */ - if (px + rect.left < v->left && v->left >= MIN_VISIBLE_TITLE_BAR) { // Coming from the left, and enough room there. - *nx = v->left - MIN_VISIBLE_TITLE_BAR - rect.left; - } else if (px + rect.right > v_right && v_right <= _screen.width - MIN_VISIBLE_TITLE_BAR) { // Coming from the right, and enough room there. - *nx = v_right + MIN_VISIBLE_TITLE_BAR - rect.right; - } else { - *ny = safe_y; - } -} - -/** - * Make sure at least a part of the caption bar is still visible by moving - * the window if necessary. - * @param w The window to check. - * @param nx The proposed new x-location of the window. - * @param ny The proposed new y-location of the window. - */ -static void EnsureVisibleCaption(Window *w, int nx, int ny) -{ - /* Search for the title bar rectangle. */ - Rect caption_rect; - const NWidgetBase *caption = w->nested_root->GetWidgetOfType(WWT_CAPTION); - if (caption != NULL) { - caption_rect.left = caption->pos_x; - caption_rect.right = caption->pos_x + caption->current_x; - caption_rect.top = caption->pos_y; - caption_rect.bottom = caption->pos_y + caption->current_y; - - /* Make sure the window doesn't leave the screen */ - nx = Clamp(nx, MIN_VISIBLE_TITLE_BAR - caption_rect.right, _screen.width - MIN_VISIBLE_TITLE_BAR - caption_rect.left); - ny = Clamp(ny, 0, _screen.height - MIN_VISIBLE_TITLE_BAR); - - /* Make sure the title bar isn't hidden behind the main tool bar or the status bar. */ - PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_MAIN_TOOLBAR, 0), w->left, PHD_DOWN); - PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_STATUS_BAR, 0), w->left, PHD_UP); - } - - if (w->viewport != NULL) { - w->viewport->left += nx - w->left; - w->viewport->top += ny - w->top; - } - - w->left = nx; - w->top = ny; -} - -/** - * Resize the window. - * Update all the widgets of a window based on their resize flags - * Both the areas of the old window and the new sized window are set dirty - * ensuring proper redrawal. - * @param w Window to resize - * @param delta_x Delta x-size of changed window (positive if larger, etc.) - * @param delta_y Delta y-size of changed window - * @param clamp_to_screen Whether to make sure the whole window stays visible - */ -void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen) -{ - if (delta_x != 0 || delta_y != 0) { - if (clamp_to_screen) { - /* Determine the new right/bottom position. If that is outside of the bounds of - * the resolution clamp it in such a manner that it stays within the bounds. */ - int new_right = w->left + w->width + delta_x; - int new_bottom = w->top + w->height + delta_y; - if (new_right >= (int)_cur_resolution.width) delta_x -= Ceil(new_right - _cur_resolution.width, max(1U, w->nested_root->resize_x)); - if (new_bottom >= (int)_cur_resolution.height) delta_y -= Ceil(new_bottom - _cur_resolution.height, max(1U, w->nested_root->resize_y)); - } - - w->SetDirty(); - - uint new_xinc = max(0, (w->nested_root->resize_x == 0) ? 0 : (int)(w->nested_root->current_x - w->nested_root->smallest_x) + delta_x); - uint new_yinc = max(0, (w->nested_root->resize_y == 0) ? 0 : (int)(w->nested_root->current_y - w->nested_root->smallest_y) + delta_y); - assert(w->nested_root->resize_x == 0 || new_xinc % w->nested_root->resize_x == 0); - assert(w->nested_root->resize_y == 0 || new_yinc % w->nested_root->resize_y == 0); - - w->nested_root->AssignSizePosition(ST_RESIZE, 0, 0, w->nested_root->smallest_x + new_xinc, w->nested_root->smallest_y + new_yinc, _current_text_dir == TD_RTL); - w->width = w->nested_root->current_x; - w->height = w->nested_root->current_y; - } - - EnsureVisibleCaption(w, w->left, w->top); - - /* Always call OnResize to make sure everything is initialised correctly if it needs to be. */ - w->OnResize(); - w->SetDirty(); -} - -/** - * Return the top of the main view available for general use. - * @return Uppermost vertical coordinate available. - * @note Above the upper y coordinate is often the main toolbar. - */ -int GetMainViewTop() -{ - Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); - return (w == NULL) ? 0 : w->top + w->height; -} - -/** - * Return the bottom of the main view available for general use. - * @return The vertical coordinate of the first unusable row, so 'top + height <= bottom' gives the correct result. - * @note At and below the bottom y coordinate is often the status bar. - */ -int GetMainViewBottom() -{ - Window *w = FindWindowById(WC_STATUS_BAR, 0); - return (w == NULL) ? _screen.height : w->top; -} - -static bool _dragging_window; ///< A window is being dragged or resized. - -/** - * Handle dragging/resizing of a window. - * @return State of handling the event. - */ -static EventState HandleWindowDragging() -{ - /* Get out immediately if no window is being dragged at all. */ - if (!_dragging_window) return ES_NOT_HANDLED; - - /* If button still down, but cursor hasn't moved, there is nothing to do. */ - if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; - - /* Otherwise find the window... */ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->flags & WF_DRAGGING) { - /* Stop the dragging if the left mouse button was released */ - if (!_left_button_down) { - w->flags &= ~WF_DRAGGING; - break; - } - - w->SetDirty(); - - int x = _cursor.pos.x + _drag_delta.x; - int y = _cursor.pos.y + _drag_delta.y; - int nx = x; - int ny = y; - - if (_settings_client.gui.window_snap_radius != 0) { - const Window *v; - - int hsnap = _settings_client.gui.window_snap_radius; - int vsnap = _settings_client.gui.window_snap_radius; - int delta; - - FOR_ALL_WINDOWS_FROM_BACK(v) { - if (v == w) continue; // Don't snap at yourself - - if (y + w->height > v->top && y < v->top + v->height) { - /* Your left border <-> other right border */ - delta = abs(v->left + v->width - x); - if (delta <= hsnap) { - nx = v->left + v->width; - hsnap = delta; - } - - /* Your right border <-> other left border */ - delta = abs(v->left - x - w->width); - if (delta <= hsnap) { - nx = v->left - w->width; - hsnap = delta; - } - } - - if (w->top + w->height >= v->top && w->top <= v->top + v->height) { - /* Your left border <-> other left border */ - delta = abs(v->left - x); - if (delta <= hsnap) { - nx = v->left; - hsnap = delta; - } - - /* Your right border <-> other right border */ - delta = abs(v->left + v->width - x - w->width); - if (delta <= hsnap) { - nx = v->left + v->width - w->width; - hsnap = delta; - } - } - - if (x + w->width > v->left && x < v->left + v->width) { - /* Your top border <-> other bottom border */ - delta = abs(v->top + v->height - y); - if (delta <= vsnap) { - ny = v->top + v->height; - vsnap = delta; - } - - /* Your bottom border <-> other top border */ - delta = abs(v->top - y - w->height); - if (delta <= vsnap) { - ny = v->top - w->height; - vsnap = delta; - } - } - - if (w->left + w->width >= v->left && w->left <= v->left + v->width) { - /* Your top border <-> other top border */ - delta = abs(v->top - y); - if (delta <= vsnap) { - ny = v->top; - vsnap = delta; - } - - /* Your bottom border <-> other bottom border */ - delta = abs(v->top + v->height - y - w->height); - if (delta <= vsnap) { - ny = v->top + v->height - w->height; - vsnap = delta; - } - } - } - } - - EnsureVisibleCaption(w, nx, ny); - - w->SetDirty(); - return ES_HANDLED; - } else if (w->flags & WF_SIZING) { - /* Stop the sizing if the left mouse button was released */ - if (!_left_button_down) { - w->flags &= ~WF_SIZING; - w->SetDirty(); - break; - } - - /* Compute difference in pixels between cursor position and reference point in the window. - * If resizing the left edge of the window, moving to the left makes the window bigger not smaller. - */ - int x, y = _cursor.pos.y - _drag_delta.y; - if (w->flags & WF_SIZING_LEFT) { - x = _drag_delta.x - _cursor.pos.x; - } else { - x = _cursor.pos.x - _drag_delta.x; - } - - /* resize.step_width and/or resize.step_height may be 0, which means no resize is possible. */ - if (w->resize.step_width == 0) x = 0; - if (w->resize.step_height == 0) y = 0; - - /* Check the resize button won't go past the bottom of the screen */ - if (w->top + w->height + y > _screen.height) { - y = _screen.height - w->height - w->top; - } - - /* X and Y has to go by step.. calculate it. - * The cast to int is necessary else x/y are implicitly casted to - * unsigned int, which won't work. */ - if (w->resize.step_width > 1) x -= x % (int)w->resize.step_width; - if (w->resize.step_height > 1) y -= y % (int)w->resize.step_height; - - /* Check that we don't go below the minimum set size */ - if ((int)w->width + x < (int)w->nested_root->smallest_x) { - x = w->nested_root->smallest_x - w->width; - } - if ((int)w->height + y < (int)w->nested_root->smallest_y) { - y = w->nested_root->smallest_y - w->height; - } - - /* Window already on size */ - if (x == 0 && y == 0) return ES_HANDLED; - - /* Now find the new cursor pos.. this is NOT _cursor, because we move in steps. */ - _drag_delta.y += y; - if ((w->flags & WF_SIZING_LEFT) && x != 0) { - _drag_delta.x -= x; // x > 0 -> window gets longer -> left-edge moves to left -> subtract x to get new position. - w->SetDirty(); - w->left -= x; // If dragging left edge, move left window edge in opposite direction by the same amount. - /* ResizeWindow() below ensures marking new position as dirty. */ - } else { - _drag_delta.x += x; - } - - /* ResizeWindow sets both pre- and after-size to dirty for redrawal */ - ResizeWindow(w, x, y); - return ES_HANDLED; - } - } - - _dragging_window = false; - return ES_HANDLED; -} - -/** - * Start window dragging - * @param w Window to start dragging - */ -static void StartWindowDrag(Window *w) -{ - w->flags |= WF_DRAGGING; - w->flags &= ~WF_CENTERED; - _dragging_window = true; - - _drag_delta.x = w->left - _cursor.pos.x; - _drag_delta.y = w->top - _cursor.pos.y; - - BringWindowToFront(w); - DeleteWindowById(WC_DROPDOWN_MENU, 0); -} - -/** - * Start resizing a window. - * @param w Window to start resizing. - * @param to_left Whether to drag towards the left or not - */ -static void StartWindowSizing(Window *w, bool to_left) -{ - w->flags |= to_left ? WF_SIZING_LEFT : WF_SIZING_RIGHT; - w->flags &= ~WF_CENTERED; - _dragging_window = true; - - _drag_delta.x = _cursor.pos.x; - _drag_delta.y = _cursor.pos.y; - - BringWindowToFront(w); - DeleteWindowById(WC_DROPDOWN_MENU, 0); -} - -/** - * handle scrollbar scrolling with the mouse. - * @return State of handling the event. - */ -static EventState HandleScrollbarScrolling() -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->scrolling_scrollbar >= 0) { - /* Abort if no button is clicked any more. */ - if (!_left_button_down) { - w->scrolling_scrollbar = -1; - w->SetDirty(); - return ES_HANDLED; - } - - int i; - NWidgetScrollbar *sb = w->GetWidget(w->scrolling_scrollbar); - bool rtl = false; - - if (sb->type == NWID_HSCROLLBAR) { - i = _cursor.pos.x - _cursorpos_drag_start.x; - rtl = _current_text_dir == TD_RTL; - } else { - i = _cursor.pos.y - _cursorpos_drag_start.y; - } - - if (sb->disp_flags & ND_SCROLLBAR_BTN) { - if (_scroller_click_timeout == 1) { - _scroller_click_timeout = 3; - sb->UpdatePosition(rtl == HasBit(sb->disp_flags, NDB_SCROLLBAR_UP) ? 1 : -1); - w->SetDirty(); - } - return ES_HANDLED; - } - - /* Find the item we want to move to and make sure it's inside bounds. */ - int pos = min(max(0, i + _scrollbar_start_pos) * sb->GetCount() / _scrollbar_size, max(0, sb->GetCount() - sb->GetCapacity())); - if (rtl) pos = max(0, sb->GetCount() - sb->GetCapacity() - pos); - if (pos != sb->GetPosition()) { - sb->SetPosition(pos); - w->SetDirty(); - } - return ES_HANDLED; - } - } - - return ES_NOT_HANDLED; -} - -/** - * Handle viewport scrolling with the mouse. - * @return State of handling the event. - */ -static EventState HandleViewportScroll() -{ - bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); - - if (!_scrolling_viewport) return ES_NOT_HANDLED; - - /* When we don't have a last scroll window we are starting to scroll. - * When the last scroll window and this are not the same we went - * outside of the window and should not left-mouse scroll anymore. */ - if (_last_scroll_window == NULL) _last_scroll_window = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); - - if (_last_scroll_window == NULL || !(_right_button_down || scrollwheel_scrolling || (_settings_client.gui.left_mouse_btn_scrolling && _left_button_down))) { - _cursor.fix_at = false; - _scrolling_viewport = false; - _last_scroll_window = NULL; - return ES_NOT_HANDLED; - } - - if (_last_scroll_window == FindWindowById(WC_MAIN_WINDOW, 0) && _last_scroll_window->viewport->follow_vehicle != INVALID_VEHICLE) { - /* If the main window is following a vehicle, then first let go of it! */ - const Vehicle *veh = Vehicle::Get(_last_scroll_window->viewport->follow_vehicle); - ScrollMainWindowTo(veh->x_pos, veh->y_pos, veh->z_pos, true); // This also resets follow_vehicle - return ES_NOT_HANDLED; - } - - Point delta; - if (_settings_client.gui.reverse_scroll || (_settings_client.gui.left_mouse_btn_scrolling && _left_button_down)) { - delta.x = -_cursor.delta.x; - delta.y = -_cursor.delta.y; - } else { - delta.x = _cursor.delta.x; - delta.y = _cursor.delta.y; - } - - if (scrollwheel_scrolling) { - /* We are using scrollwheels for scrolling */ - delta.x = _cursor.h_wheel; - delta.y = _cursor.v_wheel; - _cursor.v_wheel = 0; - _cursor.h_wheel = 0; - } - - /* Create a scroll-event and send it to the window */ - if (delta.x != 0 || delta.y != 0) _last_scroll_window->OnScroll(delta); - - _cursor.delta.x = 0; - _cursor.delta.y = 0; - return ES_HANDLED; -} - -/** - * Check if a window can be made relative top-most window, and if so do - * it. If a window does not obscure any other windows, it will not - * be brought to the foreground. Also if the only obscuring windows - * are so-called system-windows, the window will not be moved. - * The function will return false when a child window of this window is a - * modal-popup; function returns a false and child window gets a white border - * @param w Window to bring relatively on-top - * @return false if the window has an active modal child, true otherwise - */ -static bool MaybeBringWindowToFront(Window *w) -{ - bool bring_to_front = false; - - if (w->window_class == WC_MAIN_WINDOW || - IsVitalWindow(w) || - w->window_class == WC_TOOLTIPS || - w->window_class == WC_DROPDOWN_MENU) { - return true; - } - - /* Use unshaded window size rather than current size for shaded windows. */ - int w_width = w->width; - int w_height = w->height; - if (w->IsShaded()) { - w_width = w->unshaded_size.width; - w_height = w->unshaded_size.height; - } - - Window *u; - FOR_ALL_WINDOWS_FROM_BACK_FROM(u, w->z_front) { - /* A modal child will prevent the activation of the parent window */ - if (u->parent == w && (u->window_desc->flags & WDF_MODAL)) { - u->SetWhiteBorder(); - u->SetDirty(); - return false; - } - - if (u->window_class == WC_MAIN_WINDOW || - IsVitalWindow(u) || - u->window_class == WC_TOOLTIPS || - u->window_class == WC_DROPDOWN_MENU) { - continue; - } - - /* Window sizes don't interfere, leave z-order alone */ - if (w->left + w_width <= u->left || - u->left + u->width <= w->left || - w->top + w_height <= u->top || - u->top + u->height <= w->top) { - continue; - } - - bring_to_front = true; - } - - if (bring_to_front) BringWindowToFront(w); - return true; -} - -/** - * Process keypress for editbox widget. - * @param wid Editbox widget. - * @param key the Unicode value of the key. - * @param keycode the untranslated key code including shift state. - * @return #ES_HANDLED if the key press has been handled and no other - * window should receive the event. - */ -EventState Window::HandleEditBoxKey(int wid, WChar key, uint16 keycode) -{ - QueryString *query = this->GetQueryString(wid); - if (query == NULL) return ES_NOT_HANDLED; - - int action = QueryString::ACTION_NOTHING; - - switch (query->text.HandleKeyPress(key, keycode)) { - case HKPR_EDITING: - this->SetWidgetDirty(wid); - this->OnEditboxChanged(wid); - break; - - case HKPR_CURSOR: - this->SetWidgetDirty(wid); - /* For the OSK also invalidate the parent window */ - if (this->window_class == WC_OSK) this->InvalidateData(); - break; - - case HKPR_CONFIRM: - if (this->window_class == WC_OSK) { - this->OnClick(Point(), WID_OSK_OK, 1); - } else if (query->ok_button >= 0) { - this->OnClick(Point(), query->ok_button, 1); - } else { - action = query->ok_button; - } - break; - - case HKPR_CANCEL: - if (this->window_class == WC_OSK) { - this->OnClick(Point(), WID_OSK_CANCEL, 1); - } else if (query->cancel_button >= 0) { - this->OnClick(Point(), query->cancel_button, 1); - } else { - action = query->cancel_button; - } - break; - - case HKPR_NOT_HANDLED: - return ES_NOT_HANDLED; - - default: break; - } - - switch (action) { - case QueryString::ACTION_DESELECT: - this->UnfocusFocusedWidget(); - break; - - case QueryString::ACTION_CLEAR: - if (query->text.bytes <= 1) { - /* If already empty, unfocus instead */ - this->UnfocusFocusedWidget(); - } else { - query->text.DeleteAll(); - this->SetWidgetDirty(wid); - this->OnEditboxChanged(wid); - } - break; - - default: - break; - } - - return ES_HANDLED; -} - -/** - * Handle keyboard input. - * @param keycode Virtual keycode of the key. - * @param key Unicode character of the key. - */ -void HandleKeypress(uint keycode, WChar key) -{ - /* World generation is multithreaded and messes with companies. - * But there is no company related window open anyway, so _current_company is not used. */ - assert(HasModalProgress() || IsLocalCompany()); - - /* - * The Unicode standard defines an area called the private use area. Code points in this - * area are reserved for private use and thus not portable between systems. For instance, - * Apple defines code points for the arrow keys in this area, but these are only printable - * on a system running OS X. We don't want these keys to show up in text fields and such, - * and thus we have to clear the unicode character when we encounter such a key. - */ - if (key >= 0xE000 && key <= 0xF8FF) key = 0; - - /* - * If both key and keycode is zero, we don't bother to process the event. - */ - if (key == 0 && keycode == 0) return; - - /* Check if the focused window has a focused editbox */ - if (EditBoxInGlobalFocus()) { - /* All input will in this case go to the focused editbox */ - if (_focused_window->window_class == WC_CONSOLE) { - if (_focused_window->OnKeyPress(key, keycode) == ES_HANDLED) return; - } else { - if (_focused_window->HandleEditBoxKey(_focused_window->nested_focus->index, key, keycode) == ES_HANDLED) return; - } - } - - /* Call the event, start with the uppermost window, but ignore the toolbar. */ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if (w->window_class == WC_MAIN_TOOLBAR) continue; - if (w->window_desc->hotkeys != NULL) { - int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); - if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return; - } - if (w->OnKeyPress(key, keycode) == ES_HANDLED) return; - } - - w = FindWindowById(WC_MAIN_TOOLBAR, 0); - /* When there is no toolbar w is null, check for that */ - if (w != NULL) { - if (w->window_desc->hotkeys != NULL) { - int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); - if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return; - } - if (w->OnKeyPress(key, keycode) == ES_HANDLED) return; - } - - HandleGlobalHotkeys(key, keycode); -} - -/** - * State of CONTROL key has changed - */ -void HandleCtrlChanged() -{ - /* Call the event, start with the uppermost window. */ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if (w->OnCTRLStateChange() == ES_HANDLED) return; - } -} - -/** - * Insert a text string at the cursor position into the edit box widget. - * @param wid Edit box widget. - * @param str Text string to insert. - */ -/* virtual */ void Window::InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) -{ - QueryString *query = this->GetQueryString(wid); - if (query == NULL) return; - - if (query->text.InsertString(str, marked, caret, insert_location, replacement_end) || marked) { - this->SetWidgetDirty(wid); - this->OnEditboxChanged(wid); - } -} - -/** - * Handle text input. - * @param str Text string to input. - * @param marked Is the input a marked composition string from an IME? - * @param caret Move the caret to this point in the insertion string. - */ -void HandleTextInput(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) -{ - if (!EditBoxInGlobalFocus()) return; - - _focused_window->InsertTextString(_focused_window->window_class == WC_CONSOLE ? 0 : _focused_window->nested_focus->index, str, marked, caret, insert_location, replacement_end); -} - -/** - * Local counter that is incremented each time an mouse input event is detected. - * The counter is used to stop auto-scrolling. - * @see HandleAutoscroll() - * @see HandleMouseEvents() - */ -static int _input_events_this_tick = 0; - -/** - * If needed and switched on, perform auto scrolling (automatically - * moving window contents when mouse is near edge of the window). - */ -static void HandleAutoscroll() -{ - if (_game_mode == GM_MENU || HasModalProgress()) return; - if (_settings_client.gui.auto_scrolling == VA_DISABLED) return; - if (_settings_client.gui.auto_scrolling == VA_MAIN_VIEWPORT_FULLSCREEN && !_fullscreen) return; - - int x = _cursor.pos.x; - int y = _cursor.pos.y; - Window *w = FindWindowFromPt(x, y); - if (w == NULL || w->flags & WF_DISABLE_VP_SCROLL) return; - if (_settings_client.gui.auto_scrolling != VA_EVERY_VIEWPORT && w->window_class != WC_MAIN_WINDOW) return; - - ViewPort *vp = IsPtInWindowViewport(w, x, y); - if (vp == NULL) return; - - x -= vp->left; - y -= vp->top; - - /* here allows scrolling in both x and y axis */ -#define scrollspeed 3 - if (x - 15 < 0) { - w->viewport->dest_scrollpos_x += ScaleByZoom((x - 15) * scrollspeed, vp->zoom); - } else if (15 - (vp->width - x) > 0) { - w->viewport->dest_scrollpos_x += ScaleByZoom((15 - (vp->width - x)) * scrollspeed, vp->zoom); - } - if (y - 15 < 0) { - w->viewport->dest_scrollpos_y += ScaleByZoom((y - 15) * scrollspeed, vp->zoom); - } else if (15 - (vp->height - y) > 0) { - w->viewport->dest_scrollpos_y += ScaleByZoom((15 - (vp->height - y)) * scrollspeed, vp->zoom); - } -#undef scrollspeed -} - -enum MouseClick { - MC_NONE = 0, - MC_LEFT, - MC_RIGHT, - MC_DOUBLE_LEFT, - MC_HOVER, - - MAX_OFFSET_DOUBLE_CLICK = 5, ///< How much the mouse is allowed to move to call it a double click - TIME_BETWEEN_DOUBLE_CLICK = 500, ///< Time between 2 left clicks before it becoming a double click, in ms - MAX_OFFSET_HOVER = 5, ///< Maximum mouse movement before stopping a hover event. -}; -extern EventState VpHandlePlaceSizingDrag(); - -static void ScrollMainViewport(int x, int y) -{ - if (_game_mode != GM_MENU) { - Window *w = FindWindowById(WC_MAIN_WINDOW, 0); - assert(w); - - w->viewport->dest_scrollpos_x += ScaleByZoom(x, w->viewport->zoom); - w->viewport->dest_scrollpos_y += ScaleByZoom(y, w->viewport->zoom); - } -} - -/** - * Describes all the different arrow key combinations the game allows - * when it is in scrolling mode. - * The real arrow keys are bitwise numbered as - * 1 = left - * 2 = up - * 4 = right - * 8 = down - */ -static const int8 scrollamt[16][2] = { - { 0, 0}, ///< no key specified - {-2, 0}, ///< 1 : left - { 0, -2}, ///< 2 : up - {-2, -1}, ///< 3 : left + up - { 2, 0}, ///< 4 : right - { 0, 0}, ///< 5 : left + right = nothing - { 2, -1}, ///< 6 : right + up - { 0, -2}, ///< 7 : right + left + up = up - { 0, 2}, ///< 8 : down - {-2, 1}, ///< 9 : down + left - { 0, 0}, ///< 10 : down + up = nothing - {-2, 0}, ///< 11 : left + up + down = left - { 2, 1}, ///< 12 : down + right - { 0, 2}, ///< 13 : left + right + down = down - { 2, 0}, ///< 14 : right + up + down = right - { 0, 0}, ///< 15 : left + up + right + down = nothing -}; - -static void HandleKeyScrolling() -{ - /* - * Check that any of the dirkeys is pressed and that the focused window - * doesn't have an edit-box as focused widget. - */ - if (_dirkeys && !EditBoxInGlobalFocus()) { - int factor = _shift_pressed ? 50 : 10; - ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor); - } -} - -static void MouseLoop(MouseClick click, int mousewheel) -{ - /* World generation is multithreaded and messes with companies. - * But there is no company related window open anyway, so _current_company is not used. */ - assert(HasModalProgress() || IsLocalCompany()); - - HandlePlacePresize(); - UpdateTileSelection(); - - if (VpHandlePlaceSizingDrag() == ES_HANDLED) return; - if (HandleMouseDragDrop() == ES_HANDLED) return; - if (HandleWindowDragging() == ES_HANDLED) return; - if (HandleScrollbarScrolling() == ES_HANDLED) return; - if (HandleViewportScroll() == ES_HANDLED) return; - - HandleMouseOver(); - - bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); - if (click == MC_NONE && mousewheel == 0 && !scrollwheel_scrolling) return; - - int x = _cursor.pos.x; - int y = _cursor.pos.y; - Window *w = FindWindowFromPt(x, y); - if (w == NULL) return; - - if (click != MC_HOVER && !MaybeBringWindowToFront(w)) return; - ViewPort *vp = IsPtInWindowViewport(w, x, y); - - /* Don't allow any action in a viewport if either in menu or when having a modal progress window */ - if (vp != NULL && (_game_mode == GM_MENU || HasModalProgress())) return; - - if (mousewheel != 0) { - /* Send mousewheel event to window */ - w->OnMouseWheel(mousewheel); - - /* Dispatch a MouseWheelEvent for widgets if it is not a viewport */ - if (vp == NULL) DispatchMouseWheelEvent(w, w->nested_root->GetWidgetFromPos(x - w->left, y - w->top), mousewheel); - } - - if (vp != NULL) { - if (scrollwheel_scrolling) click = MC_RIGHT; // we are using the scrollwheel in a viewport, so we emulate right mouse button - switch (click) { - case MC_DOUBLE_LEFT: - case MC_LEFT: - DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite); - if (!HandleViewportClicked(vp, x, y) && - !(w->flags & WF_DISABLE_VP_SCROLL) && - _settings_client.gui.left_mouse_btn_scrolling) { - _scrolling_viewport = true; - _cursor.fix_at = false; - } - break; - - case MC_RIGHT: - if (!(w->flags & WF_DISABLE_VP_SCROLL)) { - _scrolling_viewport = true; - _cursor.fix_at = true; - - /* clear 2D scrolling caches before we start a 2D scroll */ - _cursor.h_wheel = 0; - _cursor.v_wheel = 0; - } - break; - - default: - break; - } - } else { - switch (click) { - case MC_LEFT: - case MC_DOUBLE_LEFT: - DispatchLeftClickEvent(w, x - w->left, y - w->top, click == MC_DOUBLE_LEFT ? 2 : 1); - break; - - default: - if (!scrollwheel_scrolling || w == NULL || w->window_class != WC_SMALLMAP) break; - /* We try to use the scrollwheel to scroll since we didn't touch any of the buttons. - * Simulate a right button click so we can get started. */ - /* FALL THROUGH */ - - case MC_RIGHT: DispatchRightClickEvent(w, x - w->left, y - w->top); break; - - case MC_HOVER: DispatchHoverEvent(w, x - w->left, y - w->top); break; - } - } -} - -/** - * Handle a mouse event from the video driver - */ -void HandleMouseEvents() -{ - /* World generation is multithreaded and messes with companies. - * But there is no company related window open anyway, so _current_company is not used. */ - assert(HasModalProgress() || IsLocalCompany()); - - static int double_click_time = 0; - static Point double_click_pos = {0, 0}; - - /* Mouse event? */ - MouseClick click = MC_NONE; - if (_left_button_down && !_left_button_clicked) { - click = MC_LEFT; - if (double_click_time != 0 && _realtime_tick - double_click_time < TIME_BETWEEN_DOUBLE_CLICK && - double_click_pos.x != 0 && abs(_cursor.pos.x - double_click_pos.x) < MAX_OFFSET_DOUBLE_CLICK && - double_click_pos.y != 0 && abs(_cursor.pos.y - double_click_pos.y) < MAX_OFFSET_DOUBLE_CLICK) { - click = MC_DOUBLE_LEFT; - } - double_click_time = _realtime_tick; - double_click_pos = _cursor.pos; - _left_button_clicked = true; - _input_events_this_tick++; - } else if (_right_button_clicked) { - _right_button_clicked = false; - click = MC_RIGHT; - _input_events_this_tick++; - } - - int mousewheel = 0; - if (_cursor.wheel) { - mousewheel = _cursor.wheel; - _cursor.wheel = 0; - _input_events_this_tick++; - } - - static uint32 hover_time = 0; - static Point hover_pos = {0, 0}; - - if (_settings_client.gui.hover_delay > 0) { - if (!_cursor.in_window || click != MC_NONE || mousewheel != 0 || _left_button_down || _right_button_down || - hover_pos.x == 0 || abs(_cursor.pos.x - hover_pos.x) >= MAX_OFFSET_HOVER || - hover_pos.y == 0 || abs(_cursor.pos.y - hover_pos.y) >= MAX_OFFSET_HOVER) { - hover_pos = _cursor.pos; - hover_time = _realtime_tick; - _mouse_hovering = false; - } else { - if (hover_time != 0 && _realtime_tick > hover_time + _settings_client.gui.hover_delay * 1000) { - click = MC_HOVER; - _input_events_this_tick++; - _mouse_hovering = true; - } - } - } - - /* Handle sprite picker before any GUI interaction */ - if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW && _newgrf_debug_sprite_picker.click_time != _realtime_tick) { - /* Next realtime tick? Then redraw has finished */ - _newgrf_debug_sprite_picker.mode = SPM_NONE; - InvalidateWindowData(WC_SPRITE_ALIGNER, 0, 1); - } - - if (click == MC_LEFT && _newgrf_debug_sprite_picker.mode == SPM_WAIT_CLICK) { - /* Mark whole screen dirty, and wait for the next realtime tick, when drawing is finished. */ - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - _newgrf_debug_sprite_picker.clicked_pixel = blitter->MoveTo(_screen.dst_ptr, _cursor.pos.x, _cursor.pos.y); - _newgrf_debug_sprite_picker.click_time = _realtime_tick; - _newgrf_debug_sprite_picker.sprites.Clear(); - _newgrf_debug_sprite_picker.mode = SPM_REDRAW; - MarkWholeScreenDirty(); - } else { - MouseLoop(click, mousewheel); - } - - /* We have moved the mouse the required distance, - * no need to move it at any later time. */ - _cursor.delta.x = 0; - _cursor.delta.y = 0; -} - -/** - * Check the soft limit of deletable (non vital, non sticky) windows. - */ -static void CheckSoftLimit() -{ - if (_settings_client.gui.window_soft_limit == 0) return; - - for (;;) { - uint deletable_count = 0; - Window *w, *last_deletable = NULL; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if (w->window_class == WC_MAIN_WINDOW || IsVitalWindow(w) || (w->flags & WF_STICKY)) continue; - - last_deletable = w; - deletable_count++; - } - - /* We've not reached the soft limit yet. */ - if (deletable_count <= _settings_client.gui.window_soft_limit) break; - - assert(last_deletable != NULL); - delete last_deletable; - } -} - -/** - * Regular call from the global game loop - */ -void InputLoop() -{ - /* World generation is multithreaded and messes with companies. - * But there is no company related window open anyway, so _current_company is not used. */ - assert(HasModalProgress() || IsLocalCompany()); - - CheckSoftLimit(); - HandleKeyScrolling(); - - /* Do the actual free of the deleted windows. */ - for (Window *v = _z_front_window; v != NULL; /* nothing */) { - Window *w = v; - v = v->z_back; - - if (w->window_class != WC_INVALID) continue; - - RemoveWindowFromZOrdering(w); - free(w); - } - - if (_scroller_click_timeout != 0) _scroller_click_timeout--; - DecreaseWindowCounters(); - - if (_input_events_this_tick != 0) { - /* The input loop is called only once per GameLoop() - so we can clear the counter here */ - _input_events_this_tick = 0; - /* there were some inputs this tick, don't scroll ??? */ - return; - } - - /* HandleMouseEvents was already called for this tick */ - HandleMouseEvents(); - HandleAutoscroll(); -} - -/** - * Update the continuously changing contents of the windows, such as the viewports - */ -void UpdateWindows() -{ - Window *w; - - static int highlight_timer = 1; - if (--highlight_timer == 0) { - highlight_timer = 15; - _window_highlight_colour = !_window_highlight_colour; - } - - FOR_ALL_WINDOWS_FROM_FRONT(w) { - w->ProcessScheduledInvalidations(); - w->ProcessHighlightedInvalidations(); - } - - static int we4_timer = 0; - int t = we4_timer + 1; - - if (t >= 100) { - FOR_ALL_WINDOWS_FROM_FRONT(w) { - w->OnHundredthTick(); - } - t = 0; - } - we4_timer = t; - - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if ((w->flags & WF_WHITE_BORDER) && --w->white_border_timer == 0) { - CLRBITS(w->flags, WF_WHITE_BORDER); - w->SetDirty(); - } - } - - DrawDirtyBlocks(); - - FOR_ALL_WINDOWS_FROM_BACK(w) { - /* Update viewport only if window is not shaded. */ - if (w->viewport != NULL && !w->IsShaded()) UpdateViewportPosition(w); - } - NetworkDrawChatMessage(); - /* Redraw mouse cursor in case it was hidden */ - DrawMouseCursor(); -} - -/** - * Mark window as dirty (in need of repainting) - * @param cls Window class - * @param number Window number in that class - */ -void SetWindowDirty(WindowClass cls, WindowNumber number) -{ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls && w->window_number == number) w->SetDirty(); - } -} - -/** - * Mark a particular widget in a particular window as dirty (in need of repainting) - * @param cls Window class - * @param number Window number in that class - * @param widget_index Index number of the widget that needs repainting - */ -void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index) -{ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls && w->window_number == number) { - w->SetWidgetDirty(widget_index); - } - } -} - -/** - * Mark all windows of a particular class as dirty (in need of repainting) - * @param cls Window class - */ -void SetWindowClassesDirty(WindowClass cls) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls) w->SetDirty(); - } -} - -/** - * Mark this window's data as invalid (in need of re-computing) - * @param data The data to invalidate with - * @param gui_scope Whether the function is called from GUI scope. - */ -void Window::InvalidateData(int data, bool gui_scope) -{ - this->SetDirty(); - if (!gui_scope) { - /* Schedule GUI-scope invalidation for next redraw. */ - *this->scheduled_invalidation_data.Append() = data; - } - this->OnInvalidateData(data, gui_scope); -} - -/** - * Process all scheduled invalidations. - */ -void Window::ProcessScheduledInvalidations() -{ - for (int *data = this->scheduled_invalidation_data.Begin(); this->window_class != WC_INVALID && data != this->scheduled_invalidation_data.End(); data++) { - this->OnInvalidateData(*data, true); - } - this->scheduled_invalidation_data.Clear(); -} - -/** - * Process all invalidation of highlighted widgets. - */ -void Window::ProcessHighlightedInvalidations() -{ - if ((this->flags & WF_HIGHLIGHTED) == 0) return; - - for (uint i = 0; i < this->nested_array_size; i++) { - if (this->IsWidgetHighlighted(i)) this->SetWidgetDirty(i); - } -} - -/** - * Mark window data of the window of a given class and specific window number as invalid (in need of re-computing) - * - * Note that by default the invalidation is not considered to be called from GUI scope. - * That means only a part of invalidation is executed immediately. The rest is scheduled for the next redraw. - * The asynchronous execution is important to prevent GUI code being executed from command scope. - * When not in GUI-scope: - * - OnInvalidateData() may not do test-runs on commands, as they might affect the execution of - * the command which triggered the invalidation. (town rating and such) - * - OnInvalidateData() may not rely on _current_company == _local_company. - * This implies that no NewGRF callbacks may be run. - * - * However, when invalidations are scheduled, then multiple calls may be scheduled before execution starts. Earlier scheduled - * invalidations may be called with invalidation-data, which is already invalid at the point of execution. - * That means some stuff requires to be executed immediately in command scope, while not everything may be executed in command - * scope. While GUI-scope calls have no restrictions on what they may do, they cannot assume the game to still be in the state - * when the invalidation was scheduled; passed IDs may have got invalid in the mean time. - * - * Finally, note that invalidations triggered from commands or the game loop result in OnInvalidateData() being called twice. - * Once in command-scope, once in GUI-scope. So make sure to not process differential-changes twice. - * - * @param cls Window class - * @param number Window number within the class - * @param data The data to invalidate with - * @param gui_scope Whether the call is done from GUI scope - */ -void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls && w->window_number == number) { - w->InvalidateData(data, gui_scope); - } - } -} - -/** - * Mark window data of all windows of a given class as invalid (in need of re-computing) - * Note that by default the invalidation is not considered to be called from GUI scope. - * See InvalidateWindowData() for details on GUI-scope vs. command-scope. - * @param cls Window class - * @param data The data to invalidate with - * @param gui_scope Whether the call is done from GUI scope - */ -void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope) -{ - Window *w; - - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls) { - w->InvalidateData(data, gui_scope); - } - } -} - -/** - * Dispatch WE_TICK event over all windows - */ -void CallWindowTickEvent() -{ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - w->OnTick(); - } -} - -/** - * Try to delete a non-vital window. - * Non-vital windows are windows other than the game selection, main toolbar, - * status bar, toolbar menu, and tooltip windows. Stickied windows are also - * considered vital. - */ -void DeleteNonVitalWindows() -{ - Window *w; - -restart_search: - /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others - * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class != WC_MAIN_WINDOW && - w->window_class != WC_SELECT_GAME && - w->window_class != WC_MAIN_TOOLBAR && - w->window_class != WC_STATUS_BAR && - w->window_class != WC_TOOLTIPS && - (w->flags & WF_STICKY) == 0) { // do not delete windows which are 'pinned' - - delete w; - goto restart_search; - } - } -} - -/** - * It is possible that a stickied window gets to a position where the - * 'close' button is outside the gaming area. You cannot close it then; except - * with this function. It closes all windows calling the standard function, - * then, does a little hacked loop of closing all stickied windows. Note - * that standard windows (status bar, etc.) are not stickied, so these aren't affected - */ -void DeleteAllNonVitalWindows() -{ - Window *w; - - /* Delete every window except for stickied ones, then sticky ones as well */ - DeleteNonVitalWindows(); - -restart_search: - /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others - * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->flags & WF_STICKY) { - delete w; - goto restart_search; - } - } -} - -/** - * Delete all windows that are used for construction of vehicle etc. - * Once done with that invalidate the others to ensure they get refreshed too. - */ -void DeleteConstructionWindows() -{ - Window *w; - -restart_search: - /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others - * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_desc->flags & WDF_CONSTRUCTION) { - delete w; - goto restart_search; - } - } - - FOR_ALL_WINDOWS_FROM_BACK(w) w->SetDirty(); -} - -/** Delete all always on-top windows to get an empty screen */ -void HideVitalWindows() -{ - DeleteWindowById(WC_MAIN_TOOLBAR, 0); - DeleteWindowById(WC_STATUS_BAR, 0); -} - -/** Re-initialize all windows. */ -void ReInitAllWindows() -{ - NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets. - NWidgetScrollbar::InvalidateDimensionCache(); - - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - w->ReInit(); - } -#ifdef ENABLE_NETWORK - void NetworkReInitChatBoxSize(); - NetworkReInitChatBoxSize(); -#endif - - /* Make sure essential parts of all windows are visible */ - RelocateAllWindows(_cur_resolution.width, _cur_resolution.height); - MarkWholeScreenDirty(); -} - -/** - * (Re)position a window at the screen. - * @param w Window structure of the window, may also be \c NULL. - * @param clss The class of the window to position. - * @param setting The actual setting used for the window's position. - * @return X coordinate of left edge of the repositioned window. - */ -static int PositionWindow(Window *w, WindowClass clss, int setting) -{ - if (w == NULL || w->window_class != clss) { - w = FindWindowById(clss, 0); - } - if (w == NULL) return 0; - - int old_left = w->left; - switch (setting) { - case 1: w->left = (_screen.width - w->width) / 2; break; - case 2: w->left = _screen.width - w->width; break; - default: w->left = 0; break; - } - if (w->viewport != NULL) w->viewport->left += w->left - old_left; - SetDirtyBlocks(0, w->top, _screen.width, w->top + w->height); // invalidate the whole row - return w->left; -} - -/** - * (Re)position main toolbar window at the screen. - * @param w Window structure of the main toolbar window, may also be \c NULL. - * @return X coordinate of left edge of the repositioned toolbar window. - */ -int PositionMainToolbar(Window *w) -{ - DEBUG(misc, 5, "Repositioning Main Toolbar..."); - return PositionWindow(w, WC_MAIN_TOOLBAR, _settings_client.gui.toolbar_pos); -} - -/** - * (Re)position statusbar window at the screen. - * @param w Window structure of the statusbar window, may also be \c NULL. - * @return X coordinate of left edge of the repositioned statusbar. - */ -int PositionStatusbar(Window *w) -{ - DEBUG(misc, 5, "Repositioning statusbar..."); - return PositionWindow(w, WC_STATUS_BAR, _settings_client.gui.statusbar_pos); -} - -/** - * (Re)position news message window at the screen. - * @param w Window structure of the news message window, may also be \c NULL. - * @return X coordinate of left edge of the repositioned news message. - */ -int PositionNewsMessage(Window *w) -{ - DEBUG(misc, 5, "Repositioning news message..."); - return PositionWindow(w, WC_NEWS_WINDOW, _settings_client.gui.statusbar_pos); -} - -/** - * (Re)position network chat window at the screen. - * @param w Window structure of the network chat window, may also be \c NULL. - * @return X coordinate of left edge of the repositioned network chat window. - */ -int PositionNetworkChatWindow(Window *w) -{ - DEBUG(misc, 5, "Repositioning network chat window..."); - return PositionWindow(w, WC_SEND_NETWORK_MSG, _settings_client.gui.statusbar_pos); -} - - -/** - * Switches viewports following vehicles, which get autoreplaced - * @param from_index the old vehicle ID - * @param to_index the new vehicle ID - */ -void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->viewport != NULL && w->viewport->follow_vehicle == from_index) { - w->viewport->follow_vehicle = to_index; - w->SetDirty(); - } - } -} - - -/** - * Relocate all windows to fit the new size of the game application screen - * @param neww New width of the game application screen - * @param newh New height of the game application screen. - */ -void RelocateAllWindows(int neww, int newh) -{ - Window *w; - - FOR_ALL_WINDOWS_FROM_BACK(w) { - int left, top; - /* XXX - this probably needs something more sane. For example specifying - * in a 'backup'-desc that the window should always be centered. */ - switch (w->window_class) { - case WC_MAIN_WINDOW: - case WC_BOOTSTRAP: - ResizeWindow(w, neww, newh); - continue; - - case WC_MAIN_TOOLBAR: - ResizeWindow(w, min(neww, w->window_desc->default_width) - w->width, 0, false); - - top = w->top; - left = PositionMainToolbar(w); // changes toolbar orientation - break; - - case WC_NEWS_WINDOW: - top = newh - w->height; - left = PositionNewsMessage(w); - break; - - case WC_STATUS_BAR: - ResizeWindow(w, min(neww, w->window_desc->default_width) - w->width, 0, false); - - top = newh - w->height; - left = PositionStatusbar(w); - break; - - case WC_SEND_NETWORK_MSG: - ResizeWindow(w, Clamp(neww, 320, 640) - w->width, 0, false); - top = newh - w->height - FindWindowById(WC_STATUS_BAR, 0)->height; - left = PositionNetworkChatWindow(w); - break; - - case WC_CONSOLE: - IConsoleResize(w); - continue; - - default: { - if (w->flags & WF_CENTERED) { - top = (newh - w->height) >> 1; - left = (neww - w->width) >> 1; - break; - } - - left = w->left; - if (left + (w->width >> 1) >= neww) left = neww - w->width; - if (left < 0) left = 0; - - top = w->top; - if (top + (w->height >> 1) >= newh) top = newh - w->height; - break; - } - } - - EnsureVisibleCaption(w, left, top); - } -} - -/** - * Destructor of the base class PickerWindowBase - * Main utility is to stop the base Window destructor from triggering - * a free while the child will already be free, in this case by the ResetObjectToPlace(). - */ -PickerWindowBase::~PickerWindowBase() -{ - this->window_class = WC_INVALID; // stop the ancestor from freeing the already (to be) child - ResetObjectToPlace(); -} From f43337d022872ac9beddabf39ac5f3e97645ec8e Mon Sep 17 00:00:00 2001 From: Juanjo Date: Fri, 27 Sep 2013 20:38:34 +0000 Subject: [PATCH 040/187] Some amends about sizings. --- src/network/network_gui.cpp | 2 +- src/settings_gui.cpp | 5 +++-- src/widget.cpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 18135dfedf..e324a58442 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -494,7 +494,7 @@ public: switch (widget) { case WID_NG_CONN_BTN: *size = maxdim(GetStringBoundingBox(_lan_internet_types_dropdown[0]), GetStringBoundingBox(_lan_internet_types_dropdown[1])); - size->width += padding.width; + size->width += padding.width + GetMinSizing(NWST_STEP, 11U); size->height += padding.height; break; diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 755b829ff9..a02dc915f0 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1150,8 +1150,9 @@ uint SettingEntry::Draw(GameSettings *settings_ptr, int left, int right, int bas break; case SEF_SUBTREE_KIND: if (cur_row >= first_row) { - DrawSprite((this->d.sub.folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED), PAL_NONE, rtl ? x - 8 : x, y + (SETTING_HEIGHT - 11) / 2); - DrawString(rtl ? left : x + 12, rtl ? x - 12 : right, Center(y, SETTING_HEIGHT), this->d.sub.title); + Dimension d = GetSpriteSize(SPR_CIRCLE_UNFOLDED); + DrawSprite((this->d.sub.folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED), PAL_NONE, rtl ? x - d.width : x, Center(y, SETTING_HEIGHT, d.height)); + DrawString(rtl ? left : x + d.width + 2, rtl ? x - (d.width + 2) : right, Center(y, SETTING_HEIGHT), this->d.sub.title); } cur_row++; if (!this->d.sub.folded) { diff --git a/src/widget.cpp b/src/widget.cpp index 1ead186b78..40e531b678 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -2347,7 +2347,7 @@ void NWidgetLeaf::SetupSmallestSize(Window *w, bool init_array) padding = &extra; if (this->index >= 0) w->SetStringParameters(this->index); Dimension d2 = GetStringBoundingBox(this->widget_data); - d2.width += extra.width; + d2.width += extra.width + GetMinSizing(NWST_STEP, 11U); d2.height += extra.height; size = maxdim(size, d2); break; From b69c4bb7a98a526b9dbf29abdf38ecc6be1d336a Mon Sep 17 00:00:00 2001 From: Juanjo Date: Thu, 26 Sep 2013 10:56:20 +0000 Subject: [PATCH 041/187] Add scrollbars to tracklist window and set min sizing. --- src/music_gui.cpp | 134 ++++++++++++++++--------- src/script/api/game/game_window.hpp.sq | 2 + src/script/api/script_window.hpp | 8 +- src/widgets/music_widget.h | 22 ++-- 4 files changed, 107 insertions(+), 59 deletions(-) diff --git a/src/music_gui.cpp b/src/music_gui.cpp index 896624cb7d..26910e952b 100644 --- a/src/music_gui.cpp +++ b/src/music_gui.cpp @@ -290,13 +290,32 @@ static void SelectPlaylist(byte list) } struct MusicTrackSelectionWindow : public Window { + Scrollbar *left_sb; + Scrollbar *right_sb; + + /** Count the number of tracks of current tracklist. */ + uint GetNumberOfTracksOfTracklist() const + { + uint i = 0; + for (; _playlists[_settings_client.music.playlist][i] > 0; i++) {} + return i; + } + MusicTrackSelectionWindow(WindowDesc *desc, WindowNumber number) : Window(desc) { - this->InitNested(number); + + this->CreateNestedTree(); + this->left_sb = this->GetScrollbar(WID_MTS_LEFT_SCROLLBAR); + this->right_sb = this->GetScrollbar(WID_MTS_RIGHT_SCROLLBAR); + this->LowerWidget(WID_MTS_LIST_LEFT); this->LowerWidget(WID_MTS_LIST_RIGHT); this->SetWidgetDisabledState(WID_MTS_CLEAR, _settings_client.music.playlist <= 3); this->LowerWidget(WID_MTS_ALL + _settings_client.music.playlist); + this->FinishInitNested(number); + + this->left_sb->SetCount(NUM_SONGS_AVAILABLE); + this->right_sb->SetCount(GetNumberOfTracksOfTracklist()); } virtual void SetStringParameters(int widget) const @@ -320,6 +339,7 @@ struct MusicTrackSelectionWindow : public Window { this->SetWidgetLoweredState(WID_MTS_ALL + i, i == _settings_client.music.playlist); } this->SetWidgetDisabledState(WID_MTS_CLEAR, _settings_client.music.playlist <= 3); + this->right_sb->SetCount(GetNumberOfTracksOfTracklist()); this->SetDirty(); } @@ -339,7 +359,8 @@ struct MusicTrackSelectionWindow : public Window { break; } - case WID_MTS_LIST_LEFT: case WID_MTS_LIST_RIGHT: { + case WID_MTS_LIST_LEFT: + case WID_MTS_LIST_RIGHT: { Dimension d = {0, 0}; for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) { @@ -349,12 +370,11 @@ struct MusicTrackSelectionWindow : public Window { SetDParam(0, GetTrackNumber(i)); SetDParam(1, 2); SetDParamStr(2, GetSongName(i)); - Dimension d2 = GetStringBoundingBox(STR_PLAYLIST_TRACK_NAME); - d.width = max(d.width, d2.width); - d.height += d2.height; + d = maxdim(d, GetStringBoundingBox(STR_PLAYLIST_TRACK_NAME)); } - d.width += padding.width; - d.height += padding.height; + resize->height = GetMinSizing(NWST_STEP, d.height); + d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + d.height = 10 * resize->height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); break; } @@ -368,15 +388,17 @@ struct MusicTrackSelectionWindow : public Window { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK); int y = r.top + WD_FRAMERECT_TOP; - for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) { + uint vscroll_max = min(this->left_sb->GetPosition() + this->left_sb->GetCapacity(), NUM_SONGS_AVAILABLE); + + for (uint i = this->left_sb->GetPosition(); i < vscroll_max; i++) { const char *song_name = GetSongName(i); if (StrEmpty(song_name)) continue; SetDParam(0, GetTrackNumber(i)); SetDParam(1, 2); SetDParamStr(2, song_name); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_PLAYLIST_TRACK_NAME); - y += FONT_HEIGHT_SMALL; + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(y, this->resize.step_height, FONT_HEIGHT_SMALL), STR_PLAYLIST_TRACK_NAME); + y += this->resize.step_height; } break; } @@ -385,13 +407,15 @@ struct MusicTrackSelectionWindow : public Window { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK); int y = r.top + WD_FRAMERECT_TOP; - for (const byte *p = _playlists[_settings_client.music.playlist]; *p != 0; p++) { - uint i = *p - 1; - SetDParam(0, GetTrackNumber(i)); + uint vscroll_max = min(this->right_sb->GetPosition() + this->right_sb->GetCapacity(), this->GetNumberOfTracksOfTracklist()); + + for (uint i = this->right_sb->GetPosition(); i < vscroll_max; i++) { + uint j = _playlists[_settings_client.music.playlist][i] - 1; + SetDParam(0, GetTrackNumber(j)); SetDParam(1, 2); - SetDParamStr(2, GetSongName(i)); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_PLAYLIST_TRACK_NAME); - y += FONT_HEIGHT_SMALL; + SetDParamStr(2, GetSongName(j)); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(y, this->resize.step_height, FONT_HEIGHT_SMALL), STR_PLAYLIST_TRACK_NAME); + y += this->resize.step_height; } break; } @@ -402,22 +426,22 @@ struct MusicTrackSelectionWindow : public Window { { switch (widget) { case WID_MTS_LIST_LEFT: { // add to playlist - int y = this->GetRowFromWidget(pt.y, widget, 0, FONT_HEIGHT_SMALL); - if (_settings_client.music.playlist < 4) return; - if (!IsInsideMM(y, 0, BaseMusic::GetUsedSet()->num_available)) return; + int id_m = this->left_sb->GetScrolledRowFromWidget(pt.y, this, WID_MTS_LIST_LEFT, WD_FRAMERECT_TOP, this->resize.step_height); + if (!IsInsideMM(id_m, 0, BaseMusic::GetUsedSet()->num_available)) return; byte *p = _playlists[_settings_client.music.playlist]; for (uint i = 0; i != NUM_SONGS_PLAYLIST - 1; i++) { if (p[i] == 0) { /* Find the actual song number */ for (uint j = 0; j < NUM_SONGS_AVAILABLE; j++) { - if (GetTrackNumber(j) == y + 1) { + if (GetTrackNumber(j) == id_m + 1) { p[i] = j + 1; break; } } p[i + 1] = 0; + this->right_sb->SetCount(GetNumberOfTracksOfTracklist()); this->SetDirty(); SelectSongToPlay(); break; @@ -427,16 +451,16 @@ struct MusicTrackSelectionWindow : public Window { } case WID_MTS_LIST_RIGHT: { // remove from playlist - int y = this->GetRowFromWidget(pt.y, widget, 0, FONT_HEIGHT_SMALL); - if (_settings_client.music.playlist < 4) return; - if (!IsInsideMM(y, 0, NUM_SONGS_PLAYLIST)) return; + int id_m = this->right_sb->GetScrolledRowFromWidget(pt.y, this, WID_MTS_LIST_RIGHT, WD_FRAMERECT_TOP, this->resize.step_height); + if (!IsInsideMM(id_m, 0, NUM_SONGS_PLAYLIST)) return; byte *p = _playlists[_settings_client.music.playlist]; - for (uint i = y; i != NUM_SONGS_PLAYLIST - 1; i++) { + for (uint i = id_m; i != NUM_SONGS_PLAYLIST - 1; i++) { p[i] = p[i + 1]; } + this->right_sb->SetCount(GetNumberOfTracksOfTracklist()); this->SetDirty(); SelectSongToPlay(); break; @@ -444,55 +468,74 @@ struct MusicTrackSelectionWindow : public Window { case WID_MTS_CLEAR: // clear for (uint i = 0; _playlists[_settings_client.music.playlist][i] != 0; i++) _playlists[_settings_client.music.playlist][i] = 0; + this->right_sb->SetCount(GetNumberOfTracksOfTracklist()); this->SetDirty(); StopMusic(); SelectSongToPlay(); break; - case WID_MTS_ALL: case WID_MTS_OLD: case WID_MTS_NEW: - case WID_MTS_EZY: case WID_MTS_CUSTOM1: case WID_MTS_CUSTOM2: // set playlist + case WID_MTS_ALL: + case WID_MTS_OLD: + case WID_MTS_NEW: + case WID_MTS_EZY: + case WID_MTS_CUSTOM1: + case WID_MTS_CUSTOM2: // set playlist SelectPlaylist(widget - WID_MTS_ALL); + this->right_sb->SetCount(GetNumberOfTracksOfTracklist()); + this->SetDirty(); StopMusic(); SelectSongToPlay(); break; } } + + virtual void OnResize() + { + this->left_sb->SetCapacityFromWidget(this, WID_MTS_LIST_LEFT); + this->right_sb->SetCapacityFromWidget(this, WID_MTS_LIST_RIGHT); + } }; static const NWidgetPart _nested_music_track_selection_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_PLAYLIST_MUSIC_PROGRAM_SELECTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2), /* Left panel. */ NWidget(NWID_VERTICAL), NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_PLAYLIST_TRACK_INDEX, STR_NULL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_MTS_LIST_LEFT), SetMinimalSize(180, 194), SetDataTip(0x0, STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_MTS_LIST_LEFT), SetMinimalSize(180, 100), SetMatrixDataTip(1, 0, STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK), + SetFill(1, 0), SetResize(1, 1), SetScrollbar(WID_MTS_LEFT_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_MTS_LEFT_SCROLLBAR), + EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), EndContainer(), - /* Middle buttons. */ - NWidget(NWID_VERTICAL), - NWidget(NWID_SPACER), SetMinimalSize(60, 30), // Space above the first button from the title bar. - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_ALL), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_ALL, STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_OLD), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_OLD_STYLE, STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_NEW), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_NEW_STYLE, STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_EZY), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_EZY_STREET, STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_CUSTOM1), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_CUSTOM_1, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_CUSTOM2), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_CUSTOM_2, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED), - NWidget(NWID_SPACER), SetMinimalSize(0, 16), // Space above 'clear' button - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_MTS_CLEAR), SetFill(1, 0), SetDataTip(STR_PLAYLIST_CLEAR, STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1), - NWidget(NWID_SPACER), SetFill(0, 1), - EndContainer(), /* Right panel. */ NWidget(NWID_VERTICAL), NWidget(WWT_LABEL, COLOUR_GREY, WID_MTS_PLAYLIST), SetDataTip(STR_PLAYLIST_PROGRAM, STR_NULL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_MTS_LIST_RIGHT), SetMinimalSize(180, 194), SetDataTip(0x0, STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_MTS_LIST_RIGHT), SetMinimalSize(180, 100), SetMatrixDataTip(1, 0, STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK), + SetFill(1, 0), SetResize(1, 1), SetScrollbar(WID_MTS_RIGHT_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_MTS_RIGHT_SCROLLBAR), + EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), EndContainer(), EndContainer(), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_ALL), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_ALL, STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_OLD), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_OLD_STYLE, STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_NEW), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_NEW_STYLE, STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_EZY), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_EZY_STREET, STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_CUSTOM1), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_CUSTOM_1, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_CUSTOM2), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_CUSTOM_2, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_MTS_CLEAR), SetFill(1, 0), SetDataTip(STR_PLAYLIST_CLEAR, STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), }; static WindowDesc _music_track_selection_desc( @@ -570,7 +613,7 @@ struct MusicWindow : public Window { SetDParam(1, 2); str = STR_MUSIC_TRACK_DIGIT; } - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(r.top, r.bottom - r.top, FONT_HEIGHT_SMALL), str); break; } @@ -581,7 +624,7 @@ struct MusicWindow : public Window { str = STR_MUSIC_TITLE_NAME; SetDParamStr(0, GetSongName(_music_wnd_cursong - 1)); } - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_FROMSTRING, SA_HOR_CENTER); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(r.top, r.bottom - r.top, FONT_HEIGHT_SMALL), str, TC_FROMSTRING, SA_HOR_CENTER); break; } @@ -672,7 +715,6 @@ struct MusicWindow : public Window { SelectPlaylist(widget - WID_M_ALL); StopMusic(); SelectSongToPlay(); - this->SetDirty(); break; } } @@ -737,11 +779,11 @@ static const NWidgetPart _nested_music_window_widgets[] = { EndContainer(), NWidget(NWID_VERTICAL), SetPadding(0, 0, 3, 3), NWidget(WWT_LABEL, COLOUR_GREY, WID_M_TRACK), SetFill(0, 0), SetDataTip(STR_MUSIC_TRACK, STR_NULL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_M_TRACK_NR), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_M_TRACK_NR), SetFill(0, 1), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), SetPadding(0, 3, 3, 0), NWidget(WWT_LABEL, COLOUR_GREY, WID_M_TRACK_TITLE), SetFill(1, 0), SetDataTip(STR_MUSIC_XTITLE, STR_NULL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_M_TRACK_NAME), SetFill(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_M_TRACK_NAME), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(0, 1), diff --git a/src/script/api/game/game_window.hpp.sq b/src/script/api/game/game_window.hpp.sq index 0439a3a97d..280bf1e532 100644 --- a/src/script/api/game/game_window.hpp.sq +++ b/src/script/api/game/game_window.hpp.sq @@ -620,8 +620,10 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_VSCROLLBAR, "WID_TF_VSCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_HSCROLLBAR, "WID_TF_HSCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LIST_LEFT, "WID_MTS_LIST_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LEFT_SCROLLBAR, "WID_MTS_LEFT_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_PLAYLIST, "WID_MTS_PLAYLIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LIST_RIGHT, "WID_MTS_LIST_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_RIGHT_SCROLLBAR, "WID_MTS_RIGHT_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_ALL, "WID_MTS_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_OLD, "WID_MTS_OLD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_NEW, "WID_MTS_NEW"); diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp index d7f3879afd..f8bb2a3e42 100644 --- a/src/script/api/script_window.hpp +++ b/src/script/api/script_window.hpp @@ -1567,9 +1567,11 @@ public: /* automatically generated from ../../widgets/music_widget.h */ /** Widgets of the #MusicTrackSelectionWindow class. */ enum MusicTrackSelectionWidgets { - WID_MTS_LIST_LEFT = ::WID_MTS_LIST_LEFT, ///< Left button. - WID_MTS_PLAYLIST = ::WID_MTS_PLAYLIST, ///< Playlist. - WID_MTS_LIST_RIGHT = ::WID_MTS_LIST_RIGHT, ///< Right button. + WID_MTS_LIST_LEFT = ::WID_MTS_LIST_LEFT, ///< Left list. + WID_MTS_LEFT_SCROLLBAR = ::WID_MTS_LEFT_SCROLLBAR, ///< Scrollbar of left list. + WID_MTS_PLAYLIST = ::WID_MTS_PLAYLIST, ///< Playlist name. + WID_MTS_LIST_RIGHT = ::WID_MTS_LIST_RIGHT, ///< Right list. + WID_MTS_RIGHT_SCROLLBAR = ::WID_MTS_RIGHT_SCROLLBAR, ///< Scrollbar of right list. WID_MTS_ALL = ::WID_MTS_ALL, ///< All button. WID_MTS_OLD = ::WID_MTS_OLD, ///< Old button. WID_MTS_NEW = ::WID_MTS_NEW, ///< New button. diff --git a/src/widgets/music_widget.h b/src/widgets/music_widget.h index 3a99bc6150..ebd7ea057d 100644 --- a/src/widgets/music_widget.h +++ b/src/widgets/music_widget.h @@ -14,16 +14,18 @@ /** Widgets of the #MusicTrackSelectionWindow class. */ enum MusicTrackSelectionWidgets { - WID_MTS_LIST_LEFT, ///< Left button. - WID_MTS_PLAYLIST, ///< Playlist. - WID_MTS_LIST_RIGHT, ///< Right button. - WID_MTS_ALL, ///< All button. - WID_MTS_OLD, ///< Old button. - WID_MTS_NEW, ///< New button. - WID_MTS_EZY, ///< Ezy button. - WID_MTS_CUSTOM1, ///< Custom1 button. - WID_MTS_CUSTOM2, ///< Custom2 button. - WID_MTS_CLEAR, ///< Clear button. + WID_MTS_LIST_LEFT, ///< Left list. + WID_MTS_LEFT_SCROLLBAR, ///< Scrollbar of left list. + WID_MTS_PLAYLIST, ///< Playlist name. + WID_MTS_LIST_RIGHT, ///< Right list. + WID_MTS_RIGHT_SCROLLBAR, ///< Scrollbar of right list. + WID_MTS_ALL, ///< All button. + WID_MTS_OLD, ///< Old button. + WID_MTS_NEW, ///< New button. + WID_MTS_EZY, ///< Ezy button. + WID_MTS_CUSTOM1, ///< Custom1 button. + WID_MTS_CUSTOM2, ///< Custom2 button. + WID_MTS_CLEAR, ///< Clear button. }; /** Widgets of the #MusicWindow class. */ From 0fffd1dd3ca1b0dcdefdb8d1677d64e5fa8d0546 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 24 Jun 2013 17:35:48 +0200 Subject: [PATCH 042/187] Allow calling init presizing mode from outside viewport.cpp. --- src/tilehighlight_func.h | 1 + src/viewport.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tilehighlight_func.h b/src/tilehighlight_func.h index 3edef509a2..af44c4d88f 100644 --- a/src/tilehighlight_func.h +++ b/src/tilehighlight_func.h @@ -25,6 +25,7 @@ void ResetObjectToPlace(); void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method); void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process); +void VpStartPreSizing(); void VpSetPresizeRange(TileIndex from, TileIndex to); void VpSetPlaceSizingLimit(int limit); diff --git a/src/viewport.cpp b/src/viewport.cpp index c3ccea8735..f6585d4779 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -2301,7 +2301,7 @@ void VpSetPresizeRange(TileIndex from, TileIndex to) if (distance > 1) ShowMeasurementTooltips(STR_MEASURE_LENGTH, 1, &distance, TCC_HOVER); } -static void VpStartPreSizing() +void VpStartPreSizing() { _thd.selend.x = -1; _special_mouse_mode = WSM_PRESIZE; From 6c368cbde58e1fb57f7df28b4f3c103821d75219 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Tue, 18 Jun 2013 08:34:56 +0200 Subject: [PATCH 043/187] Add new viewport methods. --- src/viewport.cpp | 14 ++++++++++++-- src/viewport_type.h | 4 ++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/viewport.cpp b/src/viewport.cpp index f6585d4779..84ae0c6e3e 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -2264,7 +2264,9 @@ void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDrag } HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK); - if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT) { + if (method == VPM_SINGLE_TILE) { + /* Nothing to do. */ + } else if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT) { _thd.place_mode = HT_SPECIAL | others; _thd.next_drawstyle = HT_RECT | others; } else if (_thd.place_mode & (HT_RAIL | HT_LINE)) { @@ -2743,6 +2745,11 @@ void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method) int limit = 0; switch (method) { + case VPM_SINGLE_TILE: + _thd.selstart.x = x; + _thd.selstart.y = y; + break; + case VPM_X_OR_Y: // drag in X or Y direction if (abs(sy - y) < abs(sx - x)) { y = sy; @@ -2901,7 +2908,9 @@ EventState VpHandlePlaceSizingDrag() * keep the selected tool, but reset it to the original mode. */ _special_mouse_mode = WSM_NONE; HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK); - if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_RECT) { + if (_thd.select_method == VPM_SINGLE_TILE) { + goto place_mouseup; + } else if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_RECT) { _thd.place_mode = HT_RECT | others; } else if (_thd.select_method & VPM_SIGNALDIRS) { _thd.place_mode = HT_RECT | others; @@ -2912,6 +2921,7 @@ EventState VpHandlePlaceSizingDrag() } SetTileSelectSize(1, 1); +place_mouseup: w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y)); return ES_HANDLED; diff --git a/src/viewport_type.h b/src/viewport_type.h index 800c8b4952..3566c4144b 100644 --- a/src/viewport_type.h +++ b/src/viewport_type.h @@ -84,6 +84,7 @@ enum ViewportPlaceMethod { VPM_FIX_VERTICAL = 6, ///< drag only in vertical direction VPM_X_LIMITED = 7, ///< Drag only in X axis with limited size VPM_Y_LIMITED = 8, ///< Drag only in Y axis with limited size + VPM_SINGLE_TILE = 9, ///< Drag around the screen, selecting only the end tile VPM_RAILDIRS = 0x40, ///< all rail directions VPM_SIGNALDIRS = 0x80, ///< similar to VMP_RAILDIRS, but with different cursor }; @@ -120,6 +121,9 @@ enum ViewportDragDropSelectionProcess { DDSP_BUILD_TRUCKSTOP, ///< Road stop placement (trucks) DDSP_REMOVE_BUSSTOP, ///< Road stop removal (buses) DDSP_REMOVE_TRUCKSTOP, ///< Road stop removal (trucks) + + /* Single tile dragging */ + DDSP_SINGLE_TILE, ///< Single tile actions (build industry, town, etc.) }; #endif /* VIEWPORT_TYPE_H */ From c872509d7b262f98794c392bd509f226a0336b2f Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 24 Jun 2013 17:34:25 +0200 Subject: [PATCH 044/187] Do actions when releasing the mouse, instead of when clicking: Build town, industry, airport, dock, lock, buoy, aqueduct, depots, change bridge rail/road specs. --- src/airport_gui.cpp | 18 +++++++--- src/dock_gui.cpp | 77 +++++++++++++++++++++++++++++++------------ src/industry_gui.cpp | 17 ++++++++-- src/rail_gui.cpp | 71 ++++++++++++++++++++++++--------------- src/road_gui.cpp | 47 +++++++++++++------------- src/terraform_gui.cpp | 23 +++++++++---- src/town_gui.cpp | 13 +++++++- 7 files changed, 181 insertions(+), 85 deletions(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 623a047d59..2b17fbe411 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -99,13 +99,13 @@ struct BuildAirToolbarWindow : Window { } } - virtual void OnPlaceObject(Point pt, TileIndex tile) { switch (this->last_user_action) { - case WID_AT_AIRPORT: - PlaceAirport(tile); + case WID_AT_AIRPORT: { + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_BUILD_STATION); break; + } case WID_AT_DEMOLISH: PlaceProc_DemolishArea(tile); @@ -122,8 +122,16 @@ struct BuildAirToolbarWindow : Window { virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) { - if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) { - GUIPlaceProcDragXY(select_proc, start_tile, end_tile); + if (pt.x == -1) return; + switch (select_proc) { + case DDSP_BUILD_STATION: + assert(start_tile == end_tile); + PlaceAirport(end_tile); + break; + case DDSP_DEMOLISH_AREA: + GUIPlaceProcDragXY(select_proc, start_tile, end_tile); + break; + default: NOT_REACHED(); } } diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index 89e925073a..de8016c2e5 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -26,6 +26,7 @@ #include "company_base.h" #include "hotkeys.h" #include "gui.h" +#include "bridge_map.h" #include "widgets/dock_widget.h" @@ -172,33 +173,21 @@ struct BuildDocksToolbarWindow : Window { break; case WID_DT_LOCK: // Build lock button - DoCommandP(tile, 0, 0, CMD_BUILD_LOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_LOCKS), CcBuildDocks); + /* Reuse DDSP_REMOVE_TRUCKSTOP. */ + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_REMOVE_TRUCKSTOP); break; case WID_DT_DEMOLISH: // Demolish aka dynamite button PlaceProc_DemolishArea(tile); break; + case WID_DT_STATION: // Build station button + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_BUILD_STATION); + break; + case WID_DT_DEPOT: // Build depot button - DoCommandP(tile, _ship_depot_direction, 0, CMD_BUILD_SHIP_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_SHIP_DEPOT), CcBuildDocks); - break; - - case WID_DT_STATION: { // Build station button - uint32 p2 = (uint32)INVALID_STATION << 16; // no station to join - - /* tile is always the land tile, so need to evaluate _thd.pos */ - CommandContainer cmdcont = { tile, _ctrl_pressed, p2, CMD_BUILD_DOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_DOCK_HERE), CcBuildDocks, "" }; - - /* Determine the watery part of the dock. */ - DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile)); - TileIndex tile_to = (dir != INVALID_DIAGDIR ? TileAddByDiagDir(tile, ReverseDiagDir(dir)) : tile); - - ShowSelectStationIfNeeded(cmdcont, TileArea(tile, tile_to)); - break; - } - case WID_DT_BUOY: // Build buoy button - DoCommandP(tile, 0, 0, CMD_BUILD_BUOY | CMD_MSG(STR_ERROR_CAN_T_POSITION_BUOY_HERE), CcBuildDocks); + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_SINGLE_TILE); break; case WID_DT_RIVER: // Build river button (in scenario editor) @@ -206,7 +195,7 @@ struct BuildDocksToolbarWindow : Window { break; case WID_DT_BUILD_AQUEDUCT: // Build aqueduct button - DoCommandP(tile, GetOtherAqueductEnd(tile), TRANSPORT_WATER << 15, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE), CcBuildBridge); + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_BUILD_BRIDGE); break; default: NOT_REACHED(); @@ -215,7 +204,16 @@ struct BuildDocksToolbarWindow : Window { virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) { - VpSelectTilesWithMethod(pt.x, pt.y, select_method); + switch (last_clicked_widget) { + case WID_DT_BUILD_AQUEDUCT: + case WID_DT_LOCK: + case WID_DT_STATION: + this->OnPlacePresize(pt, TileVirtXY(pt.x, pt.y)); + break; + default: + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + break; + } } virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) @@ -231,6 +229,42 @@ struct BuildDocksToolbarWindow : Window { case DDSP_CREATE_RIVER: DoCommandP(end_tile, start_tile, WATER_CLASS_RIVER, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_PLACE_RIVERS), CcBuildCanal); break; + case DDSP_BUILD_STATION: { + uint32 p2 = (uint32)INVALID_STATION << 16; // no station to join + + /* Tile is always the land tile, so need to evaluate _thd.pos. */ + CommandContainer cmdcont = { start_tile, _ctrl_pressed, p2, CMD_BUILD_DOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_DOCK_HERE), CcBuildDocks, "" }; + + //SetObjectToPlace(SPR_CURSOR_DOCK, PAL_NONE, HT_SPECIAL, this->window_class, this->window_number); + ShowSelectStationIfNeeded(cmdcont, TileArea(start_tile, end_tile)); + VpStartPreSizing(); + break; + } + + case DDSP_BUILD_BRIDGE: + DoCommandP(start_tile, GetOtherAqueductEnd(start_tile), TRANSPORT_WATER << 15, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE), CcBuildBridge); + VpStartPreSizing(); + break; + + case DDSP_REMOVE_TRUCKSTOP: { // Reusing for locks. + TileIndex middle_tile = start_tile; + if (start_tile != end_tile) middle_tile = TileAddByDiagDir(start_tile, DiagdirBetweenTiles(start_tile, end_tile)); + DoCommandP(middle_tile, 0, 0, CMD_BUILD_LOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_LOCKS), CcBuildDocks); + VpStartPreSizing(); + break; + } + + case DDSP_SINGLE_TILE: + assert(start_tile == end_tile); + switch (last_clicked_widget) { + case WID_DT_BUOY: + DoCommandP(end_tile, 0, 0, CMD_BUILD_BUOY | CMD_MSG(STR_ERROR_CAN_T_POSITION_BUOY_HERE), CcBuildDocks); + break; + case WID_DT_DEPOT: // Build depot button + DoCommandP(end_tile, _ship_depot_direction, 0, CMD_BUILD_SHIP_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_SHIP_DEPOT), CcBuildDocks); + break; + default: NOT_REACHED(); + } default: break; } @@ -249,6 +283,7 @@ struct BuildDocksToolbarWindow : Window { virtual void OnPlacePresize(Point pt, TileIndex tile_from) { + if (!IsValidTile(tile_from)) return; TileIndex tile_to = tile_from; if (this->last_clicked_widget == WID_DT_BUILD_AQUEDUCT) { diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 45a62a7fd3..60519fd388 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -544,6 +544,19 @@ public: virtual void OnPlaceObject(Point pt, TileIndex tile) { + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_SINGLE_TILE); + } + + virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + { + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + } + + virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + { + if (pt.x == -1) return; + assert(end_tile == start_tile); + bool success = true; /* We do not need to protect ourselves against "Random Many Industries" in this mode */ const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); @@ -561,14 +574,14 @@ public: _generating_world = true; _ignore_restrictions = true; - DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, + DoCommandP(end_tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY), &CcBuildIndustry); cur_company.Restore(); _ignore_restrictions = false; _generating_world = false; } else { - success = DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY)); + success = DoCommandP(end_tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY)); } /* If an industry has been built, just reset the cursor and the system */ diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 6b90d00a05..c8ed4a915c 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -252,22 +252,6 @@ static void GenericPlaceSignals(TileIndex tile) } } -/** - * Start placing a rail bridge. - * @param tile Position of the first tile of the bridge. - * @param w Rail toolbar window. - */ -static void PlaceRail_Bridge(TileIndex tile, Window *w) -{ - if (IsBridgeTile(tile)) { - TileIndex other_tile = GetOtherTunnelBridgeEnd(tile); - Point pt = {0, 0}; - w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile); - } else { - VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE); - } -} - /** Command callback for building a tunnel */ void CcBuildRailTunnel(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { @@ -632,9 +616,7 @@ struct BuildRailToolbarWindow : Window { break; case WID_RAT_BUILD_DEPOT: - DoCommandP(tile, _cur_railtype, _build_depot_direction, - CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT), - CcRailDepot); + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_SINGLE_TILE); break; case WID_RAT_BUILD_WAYPOINT: @@ -650,11 +632,11 @@ struct BuildRailToolbarWindow : Window { break; case WID_RAT_BUILD_BRIDGE: - PlaceRail_Bridge(tile, this); + VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE); break; case WID_RAT_BUILD_TUNNEL: - DoCommandP(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel); + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_BUILD_BRIDGE); break; case WID_RAT_CONVERT_RAIL: @@ -670,6 +652,14 @@ struct BuildRailToolbarWindow : Window { /* no dragging if you have pressed the convert button */ if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && this->IsWidgetLowered(WID_RAT_BUILD_SIGNALS)) return; + switch (this->last_user_action) { + case WID_RAT_BUILD_TUNNEL: + this->OnPlacePresize(pt, TileVirtXY(pt.x, pt.y)); + return; + default: + break; + } + VpSelectTilesWithMethod(pt.x, pt.y, select_method); } @@ -678,9 +668,21 @@ struct BuildRailToolbarWindow : Window { if (pt.x != -1) { switch (select_proc) { default: NOT_REACHED(); + case DDSP_PLACE_AUTOROAD: + assert(this->last_user_action == WID_RAT_BUILD_BRIDGE); case DDSP_BUILD_BRIDGE: - if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype); + switch (this->last_user_action) { + case WID_RAT_BUILD_TUNNEL: + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + else VpStartPreSizing(); + DoCommandP(end_tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel); + break; + case WID_RAT_BUILD_BRIDGE: + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype); + break; + default: NOT_REACHED(); + } break; case DDSP_PLACE_RAIL: @@ -722,6 +724,14 @@ struct BuildRailToolbarWindow : Window { } } break; + + case DDSP_SINGLE_TILE: + assert(end_tile == start_tile); + assert(last_user_action == WID_RAT_BUILD_DEPOT); + DoCommandP(end_tile, _cur_railtype, _build_depot_direction, + CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT), + CcRailDepot); + break; } } } @@ -740,10 +750,19 @@ struct BuildRailToolbarWindow : Window { DeleteWindowByClass(WC_BUILD_BRIDGE); } - virtual void OnPlacePresize(Point pt, TileIndex tile) + virtual void OnPlacePresize(Point pt, TileIndex tile_from) { - DoCommand(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); - VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); + TileIndex tile_to = tile_from; + + if (this->last_user_action == WID_RAT_BUILD_BRIDGE) { + tile_to = IsBridgeTile(tile_from) ? GetOtherBridgeEnd(tile_from) : TileVirtXY(pt.x, pt.y); + } else { + assert(this->last_user_action == WID_RAT_BUILD_TUNNEL); + DoCommand(tile_from, _cur_railtype | (TRANSPORT_RAIL << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); + tile_to = _build_tunnel_endtile == 0 ? tile_from : _build_tunnel_endtile; + } + + VpSetPresizeRange(tile_from, tile_to); } virtual EventState OnCTRLStateChange() diff --git a/src/road_gui.cpp b/src/road_gui.cpp index e0b83758ca..f5266ff9fd 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -66,21 +66,6 @@ void CcPlaySound1D(const CommandCost &result, TileIndex tile, uint32 p1, uint32 if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT, tile); } -/** - * Callback to start placing a bridge. - * @param tile Start tile of the bridge. - */ -static void PlaceRoad_Bridge(TileIndex tile, Window *w) -{ - if (IsBridgeTile(tile)) { - TileIndex other_tile = GetOtherTunnelBridgeEnd(tile); - Point pt = {0, 0}; - w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile); - } else { - VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE); - } -} - /** * Callback executed after a build road tunnel command has been called. * @@ -508,8 +493,7 @@ struct BuildRoadToolbarWindow : Window { break; case WID_ROT_DEPOT: - DoCommandP(tile, _cur_roadtype << 2 | _road_depot_orientation, 0, - CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot); + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_SINGLE_TILE); break; case WID_ROT_BUS_STATION: @@ -521,12 +505,11 @@ struct BuildRoadToolbarWindow : Window { break; case WID_ROT_BUILD_BRIDGE: - PlaceRoad_Bridge(tile, this); + VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE); break; case WID_ROT_BUILD_TUNNEL: - DoCommandP(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, - CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRoadTunnel); + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_BUILD_BRIDGE); break; default: NOT_REACHED(); @@ -583,7 +566,6 @@ struct BuildRoadToolbarWindow : Window { /* Set dir = Y */ _place_road_flag |= RF_DIR_Y; } - break; default: @@ -599,8 +581,19 @@ struct BuildRoadToolbarWindow : Window { switch (select_proc) { default: NOT_REACHED(); case DDSP_BUILD_BRIDGE: - if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype)); + switch (last_started_action) { + case WID_ROT_BUILD_TUNNEL: + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + else VpStartPreSizing(); + DoCommandP(end_tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, + CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRoadTunnel); + break; + case WID_ROT_BUILD_BRIDGE: + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype)); + break; + default: NOT_REACHED(); + } break; case DDSP_DEMOLISH_AREA: @@ -641,6 +634,14 @@ struct BuildRoadToolbarWindow : Window { DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound1D); break; } + + case DDSP_SINGLE_TILE: + /* Build depot. */ + assert(start_tile == end_tile); + assert(last_started_action == WID_ROT_DEPOT); + DoCommandP(start_tile, _cur_roadtype << 2 | _road_depot_orientation, 0, + CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot); + break; } } } diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index be85e8a0b1..e87d16bb58 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -239,15 +239,9 @@ struct TerraformToolbarWindow : Window { break; case WID_TT_BUY_LAND: // Buy land button - DoCommandP(tile, OBJECT_OWNED_LAND, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_PURCHASE_THIS_LAND), CcPlaySound1E); - break; - case WID_TT_PLACE_SIGN: // Place sign button - PlaceProc_Sign(tile); - break; - case WID_TT_PLACE_OBJECT: // Place object button - PlaceProc_Object(tile); + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_SINGLE_TILE); break; default: NOT_REACHED(); @@ -270,6 +264,21 @@ struct TerraformToolbarWindow : Window { case DDSP_LEVEL_AREA: GUIPlaceProcDragXY(select_proc, start_tile, end_tile); break; + + case DDSP_SINGLE_TILE: + assert(start_tile == end_tile); + switch (this->last_user_action) { + case WID_TT_BUY_LAND: + DoCommandP(end_tile, OBJECT_OWNED_LAND, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_PURCHASE_THIS_LAND), CcPlaySound1E); + break; + case WID_TT_PLACE_SIGN: + PlaceProc_Sign(end_tile); + break; + case WID_TT_PLACE_OBJECT: + PlaceProc_Object(end_tile); + break; + default: NOT_REACHED(); + } } } } diff --git a/src/town_gui.cpp b/src/town_gui.cpp index e6ad46e33b..85bc255fee 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -1164,7 +1164,18 @@ public: virtual void OnPlaceObject(Point pt, TileIndex tile) { - this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown); + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_SINGLE_TILE); + } + + virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + { + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + } + + virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + { + assert(start_tile == end_tile); + this->ExecuteFoundTownCommand(end_tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown); } virtual void OnPlaceObjectAbort() From 381c4e98aa3e94cf2870b8b326c2b67b04ef123c Mon Sep 17 00:00:00 2001 From: Juanjo Date: Tue, 16 Jul 2013 22:31:44 +0200 Subject: [PATCH 045/187] Place station when releasing the mouse. --- src/rail_gui.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index c8ed4a915c..b1eab4f805 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -189,15 +189,7 @@ static void PlaceRail_Station(TileIndex tile) VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_STATION); VpSetPlaceSizingLimit(_settings_game.station.station_spread); } else { - uint32 p1 = _cur_railtype | _railstation.orientation << 4 | _settings_client.gui.station_numtracks << 8 | _settings_client.gui.station_platlength << 16 | _ctrl_pressed << 24; - uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16; - - int w = _settings_client.gui.station_numtracks; - int h = _settings_client.gui.station_platlength; - if (!_railstation.orientation) Swap(w, h); - - CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" }; - ShowSelectStationIfNeeded(cmdcont, TileArea(tile, w, h)); + VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_BUILD_STATION); } } @@ -701,8 +693,22 @@ struct BuildRailToolbarWindow : Window { DoCommandP(end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 0x10 : 0), CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound10); break; - case DDSP_REMOVE_STATION: case DDSP_BUILD_STATION: + if (!_remove_button_clicked && !_settings_client.gui.station_dragdrop) { + uint32 p1 = _cur_railtype | _railstation.orientation << 4 | _settings_client.gui.station_numtracks << 8 | _settings_client.gui.station_platlength << 16 | _ctrl_pressed << 24; + uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16; + + int w = _settings_client.gui.station_numtracks; + int h = _settings_client.gui.station_platlength; + if (!_railstation.orientation) Swap(w, h); + + CommandContainer cmdcont = { end_tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" }; + ShowSelectStationIfNeeded(cmdcont, TileArea(end_tile, w, h)); + break; + } + /* Fall through. */ + + case DDSP_REMOVE_STATION: if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) { /* Station */ if (_remove_button_clicked) { From fbd9b7c906cc34c3d22c87fc8715ba0c41b9c54b Mon Sep 17 00:00:00 2001 From: Juanjo Date: Tue, 18 Jun 2013 16:32:04 +0200 Subject: [PATCH 046/187] Add functions for cycling inside an enum. --- src/core/enum_type.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/core/enum_type.hpp b/src/core/enum_type.hpp index 35a0cb2926..b5a12c4836 100644 --- a/src/core/enum_type.hpp +++ b/src/core/enum_type.hpp @@ -28,6 +28,19 @@ } +/** Some enums need to have cycling through values */ +#define DECLARE_CYCLE(type, min_val, max_val) \ + inline type CycleUp(type e) \ + { \ + assert(!((int)e < min_val || (int)e > max_val)); \ + return e == max_val ? (type)min_val : (type)((int)e + 1); \ + } \ + inline type CycleDown(type e) \ + { \ + assert(!((int)e < min_val || (int)e > max_val)); \ + return e == min_val ? (type)max_val : (type)((int)e - 1); \ + } + /** Operators to allow to work with enum as with type safe bit set in C++ */ # define DECLARE_ENUM_AS_BIT_SET(mask_t) \ From cf89f0ff5e5c3f113520db288bd49c11e8b08ef9 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 29 Jun 2013 19:17:27 +0200 Subject: [PATCH 047/187] Toolbar types. --- projects/openttd_vs100.vcxproj | 1 + projects/openttd_vs100.vcxproj.filters | 3 +++ projects/openttd_vs80.vcproj | 4 ++++ projects/openttd_vs90.vcproj | 4 ++++ source.list | 1 + 5 files changed, 13 insertions(+) diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj index 2feba86c26..c85b1d6840 100644 --- a/projects/openttd_vs100.vcxproj +++ b/projects/openttd_vs100.vcxproj @@ -623,6 +623,7 @@ + diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters index 82b64ff76b..40dc6beb81 100644 --- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -1098,6 +1098,9 @@ Header Files + + Header Files + Header Files diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index e417f4a136..3326538783 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -1766,6 +1766,10 @@ RelativePath=".\..\src\timetable.h" > + + diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index 6d9c92c40c..e7da3fb5ea 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -1763,6 +1763,10 @@ RelativePath=".\..\src\timetable.h" > + + diff --git a/source.list b/source.list index 17b937fb43..3e29ab45fe 100644 --- a/source.list +++ b/source.list @@ -358,6 +358,7 @@ tilehighlight_func.h tilehighlight_type.h tilematrix_type.hpp timetable.h +toolbar_type.h toolbar_gui.h town.h town_type.h From 06a276e5ad63f00f3502d57fbe632fd1220f2dcc Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 24 Jun 2013 17:59:37 +0200 Subject: [PATCH 048/187] Add a window for touchscreen devices. --- src/gfx.cpp | 8 +- src/gfx_func.h | 2 + src/lang/english.txt | 12 ++ src/script/api/game/game_window.hpp.sq | 6 + src/script/api/script_window.hpp | 15 +++ .../api/template/template_window.hpp.sq | 2 + src/toolbar_gui.cpp | 107 ++++++++++++++++++ src/toolbar_gui.h | 2 + src/video/sdl_v.cpp | 7 +- src/widgets/toolbar_widget.h | 9 ++ src/window.cpp | 1 + src/window_type.h | 6 + 12 files changed, 171 insertions(+), 6 deletions(-) diff --git a/src/gfx.cpp b/src/gfx.cpp index 01f29b9fb9..e489bae363 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -31,11 +31,14 @@ bool _fullscreen; CursorVars _cursor; bool _ctrl_pressed; ///< Is Ctrl pressed? bool _shift_pressed; ///< Is Shift pressed? +bool _move_pressed; + byte _fast_forward; bool _left_button_down; ///< Is left mouse button pressed? bool _left_button_clicked; ///< Is left mouse button clicked? bool _right_button_down; ///< Is right mouse button pressed? bool _right_button_clicked; ///< Is right mouse button clicked? + DrawPixelInfo _screen; bool _screen_disable_anim = false; ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot) bool _exit_game; @@ -1184,10 +1187,7 @@ void UndrawMouseCursor() void DrawMouseCursor() { -#if defined(WINCE) - /* Don't ever draw the mouse for WinCE, as we work with a stylus */ - return; -#endif + if (_settings_client.gui.touchscreen_mode != 0) return; /* Don't draw the mouse cursor if the screen is not ready */ if (_screen.dst_ptr == NULL) return; diff --git a/src/gfx_func.h b/src/gfx_func.h index 80437b5448..211fb97d04 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -55,6 +55,8 @@ extern bool _fullscreen; extern CursorVars _cursor; extern bool _ctrl_pressed; ///< Is Ctrl pressed? extern bool _shift_pressed; ///< Is Shift pressed? +extern bool _move_pressed; + extern byte _fast_forward; extern bool _left_button_down; diff --git a/src/lang/english.txt b/src/lang/english.txt index c6f76f5cd0..3b7889bd8f 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2440,6 +2440,18 @@ STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Raise a STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Level an area of land to the height of the first selected corner. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Purchase land for future use. Shift toggles building/showing cost estimate +# Tablet toolbar +STR_TABLET_X :{BLACK}X +STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP :{BLACK}Toggle transparency +STR_TABLET_CLOSE :{BLACK}Supr +STR_TABLET_CLOSE_TOOLTIP :{BLACK}Close all opened windows (except pinned ones) +STR_TABLET_SHIFT :{BLACK}Shift +STR_TABLET_SHIFT_TOOLTIP :{BLACK}Press it for getting an estimated cost of executing an action +STR_TABLET_CTRL :{BLACK}Ctrl +STR_TABLET_CTRL_TOOLTIP :{BLACK}Use it for actions that use the "CTRL" key +STR_TABLET_MOVE :{BLACK}Move +STR_TABLET_MOVE_TOOLTIP :{BLACK}Press it to move around viewports. No action will be executed on viewports while this is active + # Object construction window STR_OBJECT_BUILD_CAPTION :{WHITE}Object Selection STR_OBJECT_BUILD_TOOLTIP :{BLACK}Select object to build. Shift toggles building/showing cost estimate diff --git a/src/script/api/game/game_window.hpp.sq b/src/script/api/game/game_window.hpp.sq index 280bf1e532..231e29b667 100644 --- a/src/script/api/game/game_window.hpp.sq +++ b/src/script/api/game/game_window.hpp.sq @@ -40,6 +40,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_WINDOW, "WC_MAIN_WINDOW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_TOOLBAR, "WC_MAIN_TOOLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATUS_BAR, "WC_STATUS_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TABLET_BAR, "WC_TABLET_BAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TOOLBAR, "WC_BUILD_TOOLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_BUILD_TOOLBAR, "WC_SCEN_BUILD_TOOLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TREES, "WC_BUILD_TREES"); @@ -1202,6 +1203,11 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_MUSIC_SOUND, "WID_TE_MUSIC_SOUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_HELP, "WID_TE_HELP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SWITCH_BAR, "WID_TE_SWITCH_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_X, "WID_TT_X"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_DELETE, "WID_TT_DELETE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SHIFT, "WID_TT_SHIFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_CTRL, "WID_TT_CTRL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_MOVE, "WID_TT_MOVE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_ORDER, "WID_TD_SORT_ORDER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_CRITERIA, "WID_TD_SORT_CRITERIA"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_LIST, "WID_TD_LIST"); diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp index f8bb2a3e42..2fde7166dc 100644 --- a/src/script/api/script_window.hpp +++ b/src/script/api/script_window.hpp @@ -141,6 +141,12 @@ public: */ WC_STATUS_BAR = ::WC_STATUS_BAR, + /** + * Tablet bar; %Window numbers: + * - 0 = #StatusbarWidgets + */ + WC_TABLET_BAR = ::WC_TABLET_BAR, + /** * Build toolbar; %Window numbers: * - #TRANSPORT_RAIL = #RailToolbarWidgets @@ -2399,6 +2405,15 @@ public: WID_TE_SWITCH_BAR = ::WID_TE_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. }; + /** Widgets of the TabletToolbar class. */ + enum ToolbarTabletWidgets { + WID_TT_X = ::WID_TT_X, ///< Press X (toggle transparency). + WID_TT_DELETE = ::WID_TT_DELETE, ///< Press DELETE. + WID_TT_SHIFT = ::WID_TT_SHIFT, ///< Press SHIFT. + WID_TT_CTRL = ::WID_TT_CTRL, ///< Press CTRL. + WID_TT_MOVE = ::WID_TT_MOVE, ///< Click for moving around viewports. + }; + /* automatically generated from ../../widgets/town_widget.h */ /** Widgets of the #TownDirectoryWindow class. */ enum TownDirectoryWidgets { diff --git a/src/script/api/template/template_window.hpp.sq b/src/script/api/template/template_window.hpp.sq index 9f01e42d5a..931c37d283 100644 --- a/src/script/api/template/template_window.hpp.sq +++ b/src/script/api/template/template_window.hpp.sq @@ -223,6 +223,8 @@ namespace SQConvert { template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolbarNormalWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ToolbarEditorWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolbarEditorWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolbarEditorWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::ToolbarTabletWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolbarTabletWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolbarTabletWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TownDirectoryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownDirectoryWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownDirectoryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TownAuthorityWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownAuthorityWidgets)tmp; } diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index c06fe88b31..74ff152444 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -2216,6 +2216,111 @@ static WindowDesc _toolb_scen_desc( &ScenarioEditorToolbarWindow::hotkeys ); + +/** Tablet toolbar. */ +struct TabletToolbar : Window { + + TabletToolbar(WindowDesc *desc) : Window(desc) + { + this->InitNested(0); + this->flags |= WF_STICKY; + ResetObjectToPlace(); + this->OnInvalidateData(1 << 2); // Disable widgets. + if (_current_text_dir == TD_RTL) { this->left = _screen.width - this->width; } + } + + ~TabletToolbar() { + _shift_pressed = false; + _move_pressed = false; + + if (_ctrl_pressed) { + _ctrl_pressed = false; + HandleCtrlChanged(); + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_TT_X: + extern void ResetRestoreAllTransparency(); + ResetRestoreAllTransparency(); + break; + case WID_TT_DELETE: + DeleteNonVitalWindows(); + break; + case WID_TT_SHIFT: + _shift_pressed = !_shift_pressed; + this->ToggleWidgetLoweredState(WID_TT_SHIFT); + this->SetWidgetDirty(WID_TT_SHIFT); + break; + case WID_TT_CTRL: + _ctrl_pressed = !_ctrl_pressed; + this->ToggleWidgetLoweredState(WID_TT_CTRL); + HandleCtrlChanged(); + this->SetWidgetDirty(WID_TT_CTRL); + break; + case WID_TT_MOVE: + _move_pressed = !_move_pressed; + this->ToggleWidgetLoweredState(WID_TT_MOVE); + this->SetWidgetDirty(WID_TT_MOVE); + break; + default: + NOT_REACHED(); + } + } + + /** + * 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. + * @note bit 2 -> Update tile selection. + * bit 3 -> Set window dirty. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + /* Selection has changed. */ + if (HasBit(data, 2)) { UpdateTileSelection(); } + + /* This window is dirty. */ + if (HasBit(data, 3)) { this->SetDirty(); } + } +}; + +static const NWidgetPart _nested_tablet_simple_widgets[] = { + NWidget(NWID_VERTICAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), + EndContainer(), +}; + +static WindowDesc _toolbar_tablet_simple_desc( + WDP_AUTO, NULL, 0, 0, + WC_TABLET_BAR, WC_NONE, + WDF_NO_FOCUS, + _nested_tablet_simple_widgets, lengthof(_nested_tablet_simple_widgets) +); + +void ResetTabletWindow() +{ + if (_game_mode == GM_MENU) return; + + DeleteWindowByClass(WC_TABLET_BAR); + + switch (_settings_client.gui.touchscreen_mode) { + case TSC_NONE: + break; + case TSC_SIMPLE: + new TabletToolbar(&_toolbar_tablet_simple_desc); + break; + default: NOT_REACHED(); + + } +} + /** Allocate the toolbar. */ void AllocateToolbar() { @@ -2227,4 +2332,6 @@ void AllocateToolbar() } else { new MainToolbarWindow(&_toolb_normal_desc); } + + ResetTabletWindow(); } diff --git a/src/toolbar_gui.h b/src/toolbar_gui.h index d3eba5b272..acfe0ed418 100644 --- a/src/toolbar_gui.h +++ b/src/toolbar_gui.h @@ -16,4 +16,6 @@ void AllocateToolbar(); void ToggleBoundingBoxes(); void ToggleDirtyBlocks(); +void ResetTabletWindow(); + #endif /* TOOLBAR_GUI_H */ diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index 3d80153229..23508fceff 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -23,6 +23,7 @@ #include "../core/random_func.hpp" #include "../core/math_func.hpp" #include "../fileio_func.h" +#include "../settings_type.h" #include "sdl_v.h" #include #ifdef __ANDROID__ @@ -769,8 +770,10 @@ void VideoDriver_SDL::MainLoop() bool old_ctrl_pressed = _ctrl_pressed; - _ctrl_pressed = !!(mod & KMOD_CTRL); - _shift_pressed = !!(mod & KMOD_SHIFT); + if (_settings_client.gui.touchscreen_mode == TSC_NONE) { + _ctrl_pressed = !!(mod & KMOD_CTRL); + _shift_pressed = !!(mod & KMOD_SHIFT); + } /* determine which directional keys are down */ _dirkeys = diff --git a/src/widgets/toolbar_widget.h b/src/widgets/toolbar_widget.h index 6ede3ad634..c7bac73b39 100644 --- a/src/widgets/toolbar_widget.h +++ b/src/widgets/toolbar_widget.h @@ -75,4 +75,13 @@ enum ToolbarEditorWidgets { WID_TE_SWITCH_BAR = WID_TN_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. }; +/** Widgets of the TabletToolbar class. */ +enum ToolbarTabletWidgets { + WID_TT_X, ///< Press X (toggle transparency). + WID_TT_DELETE, ///< Press DELETE. + WID_TT_SHIFT, ///< Press SHIFT. + WID_TT_CTRL, ///< Press CTRL. + WID_TT_MOVE, ///< Click for moving around viewports. +}; + #endif /* WIDGETS_TOOLBAR_WIDGET_H */ diff --git a/src/window.cpp b/src/window.cpp index 710a9f4140..6fd8cf3377 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1290,6 +1290,7 @@ static uint GetWindowZPriority(const Window *w) ++z_priority; case WC_NEWS_WINDOW: + case WC_TABLET_BAR: ++z_priority; default: diff --git a/src/window_type.h b/src/window_type.h index 9727cf9f12..9ad14702b4 100644 --- a/src/window_type.h +++ b/src/window_type.h @@ -58,6 +58,12 @@ enum WindowClass { */ WC_STATUS_BAR, + /** + * Tablet bar; %Window numbers: + * - 0 = #StatusbarWidgets + */ + WC_TABLET_BAR, + /** * Build toolbar; %Window numbers: * - #TRANSPORT_RAIL = #RailToolbarWidgets From 90914e262ab06398036eea46f508974017e52fe8 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 24 Jun 2013 18:07:55 +0200 Subject: [PATCH 049/187] Changes on viewport related files to deal with touchscreen options. --- src/viewport.cpp | 3 ++- src/window.cpp | 18 +++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/viewport.cpp b/src/viewport.cpp index 84ae0c6e3e..d2e6f1b2c2 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1951,6 +1951,8 @@ static void PlaceObject() bool HandleViewportClicked(const ViewPort *vp, int x, int y) { + if (_move_pressed) return false; + const Vehicle *v = CheckClickOnVehicle(vp, x, y); if (_thd.place_mode & HT_VEHICLE) { @@ -2923,7 +2925,6 @@ EventState VpHandlePlaceSizingDrag() place_mouseup: w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y)); - return ES_HANDLED; } diff --git a/src/window.cpp b/src/window.cpp index 6fd8cf3377..905c2fa7d7 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2437,7 +2437,9 @@ static EventState HandleViewportScroll() * outside of the window and should not left-mouse scroll anymore. */ if (_last_scroll_window == NULL) _last_scroll_window = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); - if (_last_scroll_window == NULL || !(_right_button_down || scrollwheel_scrolling || (_settings_client.gui.left_mouse_btn_scrolling && _left_button_down))) { + + if (_last_scroll_window == NULL || !(_right_button_down || scrollwheel_scrolling || + (_left_button_down && (_move_pressed || _settings_client.gui.left_mouse_btn_scrolling)))) { _cursor.fix_at = false; _scrolling_viewport = false; _last_scroll_window = NULL; @@ -2827,6 +2829,12 @@ static void MouseLoop(MouseClick click, int mousewheel) * But there is no company related window open anyway, so _current_company is not used. */ assert(HasModalProgress() || IsLocalCompany()); + int x = _cursor.pos.x; + int y = _cursor.pos.y; + Window *w = FindWindowFromPt(x, y); + if (w == NULL) return; + ViewPort *vp = IsPtInWindowViewport(w, x, y); + HandlePlacePresize(); UpdateTileSelection(); @@ -2841,13 +2849,9 @@ static void MouseLoop(MouseClick click, int mousewheel) bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); if (click == MC_NONE && mousewheel == 0 && !scrollwheel_scrolling) return; - int x = _cursor.pos.x; - int y = _cursor.pos.y; - Window *w = FindWindowFromPt(x, y); if (w == NULL) return; - if (click != MC_HOVER && !MaybeBringWindowToFront(w)) return; - ViewPort *vp = IsPtInWindowViewport(w, x, y); + if (click != MC_NONE && click != MC_HOVER && !MaybeBringWindowToFront(w)) return; /* Don't allow any action in a viewport if either in menu or when having a modal progress window */ if (vp != NULL && (_game_mode == GM_MENU || HasModalProgress())) return; @@ -2868,7 +2872,7 @@ static void MouseLoop(MouseClick click, int mousewheel) DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite); if (!HandleViewportClicked(vp, x, y) && !(w->flags & WF_DISABLE_VP_SCROLL) && - _settings_client.gui.left_mouse_btn_scrolling) { + (_settings_client.gui.left_mouse_btn_scrolling || _move_pressed)) { _scrolling_viewport = true; _cursor.fix_at = false; } From d5669bb6773589d7dedc374f3eac9b2576a74fd5 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Fri, 18 Oct 2013 18:52:01 +0000 Subject: [PATCH 050/187] Set construction child windows to screen borders. --- src/window.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/window.cpp b/src/window.cpp index 905c2fa7d7..b9a9651491 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1684,14 +1684,19 @@ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int int16 default_width = max(desc->GetDefaultWidth(), sm_width); int16 default_height = max(desc->GetDefaultHeight(), sm_height); - if (desc->parent_cls != 0 /* WC_MAIN_WINDOW */ && + if (desc->parent_cls != WC_NONE && (w = FindWindowById(desc->parent_cls, window_number)) != NULL && w->left < _screen.width - 20 && w->left > -60 && w->top < _screen.height - 20) { - pt.x = w->left + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? 0 : 10); - if (pt.x > _screen.width + 10 - default_width) { - pt.x = (_screen.width + 10 - default_width) - 20; + if (_settings_client.gui.touchscreen_mode != TSC_NONE) { + pt.x = _current_text_dir == TD_RTL ? 0 : (_screen.width - default_width); + } else { + pt.x = w->left + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? 0 : 10); + if (pt.x > _screen.width + 10 - default_width) { + pt.x = (_screen.width + 10 - default_width) - 20; + } } + pt.y = w->top + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? w->height : 10); return pt; } @@ -1717,6 +1722,8 @@ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int NOT_REACHED(); } + // try to put it to + return pt; } From 96d3b0695cb1e09584efbadad1588767aeefaa32 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 24 Jun 2013 20:32:29 +0200 Subject: [PATCH 051/187] Amend gui's to work with touchscreen controls. --- src/airport_gui.cpp | 3 +++ src/industry_gui.cpp | 4 ++++ src/terraform_gui.cpp | 2 ++ src/town_gui.cpp | 4 ++++ src/tree_gui.cpp | 8 ++++++++ 5 files changed, 21 insertions(+) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 2b17fbe411..ddef5249cb 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -77,6 +77,7 @@ struct BuildAirToolbarWindow : Window { ~BuildAirToolbarWindow() { + if (_thd.GetCallbackWnd() == this) this->OnPlaceObjectAbort(); if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } @@ -141,6 +142,8 @@ struct BuildAirToolbarWindow : Window { DeleteWindowById(WC_BUILD_STATION, TRANSPORT_AIR); DeleteWindowById(WC_SELECT_STATION, 0); + + ResetObjectToPlace(); } static HotkeyList hotkeys; diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 60519fd388..2a0ff6cd30 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -279,6 +279,10 @@ public: this->SetButtons(); } + ~BuildIndustryWindow() { + if (_thd.GetCallbackWnd() == this) this->OnPlaceObjectAbort(); + } + virtual void OnInit() { this->SetupArrays(); diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index e87d16bb58..c711026c56 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -158,6 +158,7 @@ struct TerraformToolbarWindow : Window { ~TerraformToolbarWindow() { + if (_thd.GetCallbackWnd() == this) this->OnPlaceObjectAbort(); } virtual void OnInit() @@ -287,6 +288,7 @@ struct TerraformToolbarWindow : Window { { DeleteWindowById(WC_BUILD_OBJECT, 0); this->RaiseButtons(); + ResetObjectToPlace(); } static HotkeyList hotkeys; diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 85bc255fee..8d6c081af6 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -1061,6 +1061,10 @@ public: this->UpdateButtons(true); } + ~FoundTownWindow() { + if (_thd.GetCallbackWnd() == this) this->OnPlaceObjectAbort(); + } + void RandomTownName() { this->townnamevalid = GenerateTownName(&this->townnameparts); diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index d1429d1443..51ed85e7b7 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -18,6 +18,7 @@ #include "command_func.h" #include "sound_func.h" #include "tree_map.h" +#include "window_func.h" #include "widgets/tree_widget.h" @@ -58,6 +59,11 @@ public: ResetObjectToPlace(); } + ~BuildTreesWindow() + { + if (_thd.GetCallbackWnd() == this) this->OnPlaceObjectAbort(); + } + /** * Calculate the maximum size of all tree sprites * @return Dimension of the largest tree sprite @@ -171,6 +177,8 @@ public: virtual void OnPlaceObjectAbort() { this->RaiseButtons(); + + ResetObjectToPlace(); } }; From a4c61028223bad910dac14831f56a4a7c6e2fa4c Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 29 Jun 2013 19:00:13 +0200 Subject: [PATCH 052/187] Add settings for touchscreen controls. --- src/lang/english.txt | 4 ++++ src/settings.cpp | 7 +++++++ src/settings_gui.cpp | 1 + src/settings_type.h | 2 ++ src/table/settings.ini | 16 ++++++++++++++++ 5 files changed, 30 insertions(+) diff --git a/src/lang/english.txt b/src/lang/english.txt index 3b7889bd8f..60ea491032 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1184,6 +1184,10 @@ STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :Select on which STR_CONFIG_SETTING_SIGNALSIDE_LEFT :On the left STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :On the driving side STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :On the right +STR_CONFIG_SETTING_TOUCHSCREEN_MODE :Control mode for touchscreen devices: {STRING2} +STR_CONFIG_SETTING_TOUCHSCREEN_MODE_HELPTEXT :If playing with a mouse, choose no adaptation. Other modes are for touchscreen devices. Associated hotkey: N +STR_CONFIG_SETTING_TOUCHSCREEN_NONE :no adaptation +STR_CONFIG_SETTING_TOUCHSCREEN_SIMPLE :simple STR_CONFIG_SETTING_SHOWFINANCES :Show finances window at the end of the year: {STRING2} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :If enabled, the finances window pops up at the end of each year to allow easy inspection of the financial status of the company STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :New orders are 'non-stop' by default: {STRING2} diff --git a/src/settings.cpp b/src/settings.cpp index 970c169b4a..16f8f5d15b 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -64,6 +64,7 @@ #include "roadveh.h" #include "fios.h" #include "strings_func.h" +#include "toolbar_gui.h" #include "void_map.h" #include "station_base.h" @@ -1069,6 +1070,12 @@ static bool ZoomMinMaxChanged(int32 p1) return true; } +static bool TouchscreenModeChanged(int32 p1) +{ + //ResetTabletWindow(); + return true; +} + /** * Update any possible saveload window and delete any newgrf dialogue as * its widget parts might change. Reinit all windows as it allows access to the diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index a02dc915f0..bf1af26cc0 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1487,6 +1487,7 @@ static SettingEntry _settings_ui[] = { SettingEntry(&_settings_ui_interaction_page, STR_CONFIG_SETTING_INTERACTION), SettingEntry(&_settings_ui_sound_page, STR_CONFIG_SETTING_SOUND), SettingEntry(&_settings_ui_news_page, STR_CONFIG_SETTING_NEWS), + SettingEntry("gui.touchscreen_mode"), SettingEntry("gui.show_finances"), SettingEntry("gui.errmsg_duration"), SettingEntry("gui.hover_delay"), diff --git a/src/settings_type.h b/src/settings_type.h index f87c6bf354..cb9d95bb0f 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -21,6 +21,7 @@ #include "linkgraph/linkgraph_type.h" #include "zoom_type.h" #include "openttd.h" +#include "toolbar_type.h" /** Settings profiles and highscore tables. */ @@ -77,6 +78,7 @@ struct GUISettings { bool lost_vehicle_warn; ///< if a vehicle can't find its destination, show a warning uint8 order_review_system; ///< perform order reviews on vehicles bool vehicle_income_warn; ///< if a vehicle isn't generating income, show a warning + TouchscreenModeByte touchscreen_mode; ///< touchscreen mode for toolbars uint min_button; ///< min size of most button widgets uint min_step; ///< min size of scrollbar/dropdown elements bool manage_min_sizing; ///< automatically set min_button and min_step diff --git a/src/table/settings.ini b/src/table/settings.ini index 7c55ae9ef6..f3cca6dd2b 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -40,6 +40,7 @@ static bool RedrawTownAuthority(int32 p1); static bool InvalidateCompanyInfrastructureWindow(int32 p1); static bool InvalidateCompanyWindow(int32 p1); static bool ZoomMinMaxChanged(int32 p1); +static bool TouchscreenModeChanged(int32 p1); #ifdef ENABLE_NETWORK static bool UpdateClientName(int32 p1); @@ -2496,6 +2497,21 @@ str = STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES strhelp = STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT strval = STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG +[SDTC_VAR] +var = gui.touchscreen_mode +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +type = SLE_UINT8 +guiflags = SGF_MULTISTRING +def = 0 +min = 0 +max = 1 +interval = 1 +str = STR_CONFIG_SETTING_TOUCHSCREEN_MODE +strval = STR_CONFIG_SETTING_TOUCHSCREEN_NONE +strhelp = STR_CONFIG_SETTING_TOUCHSCREEN_MODE_HELPTEXT +proc = TouchscreenModeChanged +cat = SC_BASIC + [SDTC_BOOL] var = gui.show_finances flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC From dc853a0a3f9607797157080558ac12fb6231ebd6 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Thu, 26 Sep 2013 12:11:59 +0000 Subject: [PATCH 053/187] amend vehicle gui --- src/vehicle_gui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index ce1865db70..387976596e 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -1670,6 +1670,7 @@ public: virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_VL_LIST); + this->GetWidget(WID_VL_LIST)->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); } /** From 94abe055a222133ba2eab446fd53ed847ebd141e Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 28 Sep 2013 15:00:43 +0000 Subject: [PATCH 054/187] Settings in three columns for tablets. --- src/settings_gui.cpp | 89 ++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index bf1af26cc0..bd02004e7b 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -570,16 +570,6 @@ static const NWidgetPart _nested_game_options_widgets[] = { NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_AUTOSAVE_FRAME, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_AUTOSAVE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP), SetFill(1, 0), EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_RESOLUTION, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_RESOLUTION_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_RESOLUTION_TOOLTIP), SetFill(1, 0), SetPadding(0, 0, 3, 0), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_FULLSCREEN, STR_NULL), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_FULLSCREEN_BUTTON), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP), - EndContainer(), - EndContainer(), - EndContainer(), - - NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_TOWN_NAMES_FRAME, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_TOWNNAME_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP), SetFill(1, 0), EndContainer(), @@ -591,44 +581,55 @@ static const NWidgetPart _nested_game_options_widgets[] = { EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 0), SetFill(0, 1), EndContainer(), - EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_GRF, STR_NULL), SetPadding(0, 10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_GRF_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_GRF_TOOLTIP), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), + NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_RESOLUTION, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_RESOLUTION_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_RESOLUTION_TOOLTIP), SetFill(1, 0), SetPadding(0, 0, 3, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_FULLSCREEN, STR_NULL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_FULLSCREEN_BUTTON), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_GRF, STR_NULL), + NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_GRF_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_GRF_TOOLTIP), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + EndContainer(), EndContainer(), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), - EndContainer(), - EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_SFX, STR_NULL), SetPadding(0, 10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_SFX_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_SFX_TOOLTIP), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_SFX_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), - EndContainer(), - EndContainer(), + NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_SFX, STR_NULL), SetPadding(0, 10, 0, 10), + NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_SFX_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_SFX_TOOLTIP), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_SFX_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_MUSIC, STR_NULL), SetPadding(0, 10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_MUSIC_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), - EndContainer(), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_MUSIC, STR_NULL), SetPadding(0, 10, 0, 10), + NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_MUSIC_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + EndContainer(), EndContainer(), EndContainer(), EndContainer(), From 2beebef91b9cc00eae26693ea66ca842e427870b Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sun, 28 Jul 2013 11:44:10 +0000 Subject: [PATCH 055/187] When clicking the console and when in touchscreen modes, open a query string window. --- src/console_gui.cpp | 19 +++++++++++++++++++ src/lang/english.txt | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/src/console_gui.cpp b/src/console_gui.cpp index c3dcdaa122..031a4900ad 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -22,6 +22,7 @@ #include "console_func.h" #include "rev.h" #include "video/video_driver.hpp" +#include "textbuf_gui.h" #include "widgets/console_widget.h" @@ -227,6 +228,24 @@ struct IConsoleWindow : Window } } + virtual void OnClick(Point pt, int widget, int click_count) + { + if (_settings_client.gui.touchscreen_mode == 0) return; + + ShowQueryString(STR_EMPTY, STR_CONSOLE_QUERY_STRING, ICON_CMDLN_SIZE, + this, CS_ALPHANUMERAL, QSF_NONE); + } + + virtual void OnQueryTextFinished(char *str) + { + _focused_window = this; + + if (str == NULL) return; + + _iconsole_cmdline.Assign(str); + this->OnKeyPress(0, WKC_RETURN); + } + virtual void OnHundredthTick() { if (IConsoleLine::Truncate() && diff --git a/src/lang/english.txt b/src/lang/english.txt index 60ea491032..3a875fc014 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2663,6 +2663,10 @@ STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE :Lighthouse STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS :Company headquarters STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :Company-owned land +# Console + +STR_CONSOLE_QUERY_STRING :Enter a console command + # About OpenTTD window STR_ABOUT_OPENTTD :{WHITE}About OpenTTD STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Original copyright {COPYRIGHT} 1995 Chris Sawyer, All rights reserved From fee23f7be01a064c63f982b7198acaef503c0268 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sun, 28 Jul 2013 14:21:56 +0000 Subject: [PATCH 056/187] Add a console command to open cheat window. --- src/console_cmds.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 1a4ea9239c..11cf46b009 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -423,6 +423,20 @@ DEF_CONSOLE_CMD(ConListFiles) return true; } +/* Open the cheat window. */ +DEF_CONSOLE_CMD(ConOpenCheats) +{ + if (argc == 0) { + IConsoleHelp("Open the cheat window. Usage: 'open_cheats'"); + return true; + } + + extern void ShowCheatWindow(); + ShowCheatWindow(); + + return true; +} + /* Change the dir via console */ DEF_CONSOLE_CMD(ConChangeDirectory) { @@ -1926,6 +1940,7 @@ void IConsoleStdLibRegister() IConsoleCmdRegister("save", ConSave); IConsoleCmdRegister("saveconfig", ConSaveConfig); IConsoleCmdRegister("ls", ConListFiles); + IConsoleCmdRegister("open_cheats", ConOpenCheats); IConsoleCmdRegister("cd", ConChangeDirectory); IConsoleCmdRegister("pwd", ConPrintWorkingDirectory); IConsoleCmdRegister("clear", ConClearBuffer); From 4f608417955277549a3eae5ec98d40bb3c9dec4c Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sun, 13 Oct 2013 13:53:11 +0000 Subject: [PATCH 057/187] Base functions for a confirm action mode. --- src/command.cpp | 74 ++++++++++++++++++++++++++++++++ src/command_func.h | 6 +++ src/lang/english.txt | 3 ++ src/script/api/script_window.hpp | 1 + src/table/settings.ini | 2 +- src/toolbar_gui.cpp | 39 ++++++++++++++++- src/toolbar_type.h | 3 +- src/widgets/toolbar_widget.h | 1 + 8 files changed, 125 insertions(+), 4 deletions(-) diff --git a/src/command.cpp b/src/command.cpp index 2891a06af6..9b965faab3 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -26,6 +26,7 @@ #include "signal_func.h" #include "core/backup_type.hpp" #include "object_base.h" +#include "string_func.h" #include "table/strings.h" @@ -525,6 +526,79 @@ bool DoCommandP(const CommandContainer *container, bool my_cmd) return DoCommandP(container->tile, container->p1, container->p2, container->cmd, container->callback, container->text, my_cmd); } +/* Stored data for a command that is waiting for user confirmation. */ +bool _is_queued_command; +bool _my_cmd; +CommandContainer _queued_command; + +/** + * Store a command that needs user confirmation. + * If current mode doesn't need confirmation, execute it immediately via DoCommandP. + * @param tile The tile to perform a command on (see #CommandProc) + * @param p1 Additional data for the command (see #CommandProc) + * @param p2 Additional data for the command (see #CommandProc) + * @param cmd The command to execute (a CMD_* value) + * @param callback A callback function to call after the command is finished + * @param text The text to pass + * @param my_cmd indicator if the command is from a company or server (to display error messages for a user) + * @return \c true if the command succeeded or is stored, else \c false. + */ +bool TouchCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd) +{ + if (_settings_client.gui.touchscreen_mode == TSC_CONFIRM && !_shift_pressed) { + _queued_command.tile = tile; + _queued_command.p1 = p1; + _queued_command.p2 = p2; + _queued_command.cmd = cmd; + _queued_command.callback = callback; + if (text != NULL) ttd_strlcpy(_queued_command.text, text, 32 * MAX_CHAR_LENGTH); + _my_cmd = my_cmd; + _is_queued_command = true; + extern void UpdateTouchscreenBar(); + UpdateTouchscreenBar(); + return true; + } else { + return DoCommandP(tile, p1, p2, cmd, callback, text, my_cmd); + } +} + +/** + * Shortcut for the long TouchCommandP when having a container with the data. + * Store a command that needs user confirmation. + * If current mode doesn't need confirmation, execute it immediately via DoCommandP. + * @param container the container with information. + * @param my_cmd indicator if the command is from a company or server (to display error messages for a user) + * @return true if the command succeeded or when it is stored, else false + */ +bool TouchCommandP(const CommandContainer *container, bool my_cmd) +{ + return TouchCommandP(container->tile, container->p1, container->p2, container->cmd, container->callback, container->text, my_cmd); +} + +/** Return whether there is a command stored waiting for confirmation. */ +bool IsQueuedTouchCommand() +{ + return _is_queued_command; +} + +/** Execute a stored command. Keep it when asking for estimated cost. */ +bool DoQueuedTouchCommand() +{ + bool result = DoCommandP(&_queued_command, _my_cmd); + if (!_shift_pressed && result) EraseQueuedTouchCommand(); + return result; +} + +/** Erase a stored command and update viewport and touchscreen bar. */ +void EraseQueuedTouchCommand() +{ + if (!IsQueuedTouchCommand()) return; + _is_queued_command = false; + extern void UpdateTouchscreenBar(); + UpdateTouchscreenBar(); + //reset selection of tiles +} + /*! * Toplevel network safe docommand function for the current company. Must not be called recursively. * The callback is called when the command succeeded or failed. The parameters diff --git a/src/command_func.h b/src/command_func.h index c4cc51e3da..ab9fb05d42 100644 --- a/src/command_func.h +++ b/src/command_func.h @@ -40,6 +40,12 @@ CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags); bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = NULL, const char *text = NULL, bool my_cmd = true); bool DoCommandP(const CommandContainer *container, bool my_cmd = true); +bool TouchCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = NULL, const char *text = NULL, bool my_cmd = true); +bool TouchCommandP(const CommandContainer *container, bool my_cmd = true); +bool IsQueuedTouchCommand(); +bool DoQueuedTouchCommand(); +void EraseQueuedTouchCommand(); + CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only); #ifdef ENABLE_NETWORK diff --git a/src/lang/english.txt b/src/lang/english.txt index 3a875fc014..ad4759305a 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1188,6 +1188,7 @@ STR_CONFIG_SETTING_TOUCHSCREEN_MODE :Control mode fo STR_CONFIG_SETTING_TOUCHSCREEN_MODE_HELPTEXT :If playing with a mouse, choose no adaptation. Other modes are for touchscreen devices. Associated hotkey: N STR_CONFIG_SETTING_TOUCHSCREEN_NONE :no adaptation STR_CONFIG_SETTING_TOUCHSCREEN_SIMPLE :simple +STR_CONFIG_SETTING_TOUCHSCREEN_CONFIRM :confirm STR_CONFIG_SETTING_SHOWFINANCES :Show finances window at the end of the year: {STRING2} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :If enabled, the finances window pops up at the end of each year to allow easy inspection of the financial status of the company STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :New orders are 'non-stop' by default: {STRING2} @@ -2455,6 +2456,8 @@ STR_TABLET_CTRL :{BLACK}Ctrl STR_TABLET_CTRL_TOOLTIP :{BLACK}Use it for actions that use the "CTRL" key STR_TABLET_MOVE :{BLACK}Move STR_TABLET_MOVE_TOOLTIP :{BLACK}Press it to move around viewports. No action will be executed on viewports while this is active +STR_TABLET_CONFIRM :{BLACK}Do +STR_TABLET_CONFIRM_TOOLTIP :{BLACK}Press it to confirm an action # Object construction window STR_OBJECT_BUILD_CAPTION :{WHITE}Object Selection diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp index 2fde7166dc..62570aa6fa 100644 --- a/src/script/api/script_window.hpp +++ b/src/script/api/script_window.hpp @@ -2412,6 +2412,7 @@ public: WID_TT_SHIFT = ::WID_TT_SHIFT, ///< Press SHIFT. WID_TT_CTRL = ::WID_TT_CTRL, ///< Press CTRL. WID_TT_MOVE = ::WID_TT_MOVE, ///< Click for moving around viewports. + WID_TT_CONFIRM = ::WID_TT_CONFIRM, ///< Confirm action. }; /* automatically generated from ../../widgets/town_widget.h */ diff --git a/src/table/settings.ini b/src/table/settings.ini index f3cca6dd2b..c742c0f657 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -2504,7 +2504,7 @@ type = SLE_UINT8 guiflags = SGF_MULTISTRING def = 0 min = 0 -max = 1 +max = 2 interval = 1 str = STR_CONFIG_SETTING_TOUCHSCREEN_MODE strval = STR_CONFIG_SETTING_TOUCHSCREEN_NONE diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 74ff152444..20f66d98a4 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -2265,6 +2265,9 @@ struct TabletToolbar : Window { this->ToggleWidgetLoweredState(WID_TT_MOVE); this->SetWidgetDirty(WID_TT_MOVE); break; + case WID_TT_CONFIRM: + DoQueuedTouchCommand(); + break; default: NOT_REACHED(); } @@ -2283,7 +2286,10 @@ struct TabletToolbar : Window { if (HasBit(data, 2)) { UpdateTileSelection(); } /* This window is dirty. */ - if (HasBit(data, 3)) { this->SetDirty(); } + if (HasBit(data, 3)) { + SetWidgetDisabledState(WID_TT_CONFIRM, !IsQueuedTouchCommand()); + this->SetWidgetDirty(WID_TT_CONFIRM); + } } }; @@ -2297,6 +2303,17 @@ static const NWidgetPart _nested_tablet_simple_widgets[] = { EndContainer(), }; +static const NWidgetPart _nested_tablet_confirm_widgets[] = { + NWidget(NWID_VERTICAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_CONFIRM), SetDataTip(STR_TABLET_CONFIRM, STR_TABLET_CONFIRM_TOOLTIP), + EndContainer(), +}; + static WindowDesc _toolbar_tablet_simple_desc( WDP_AUTO, NULL, 0, 0, WC_TABLET_BAR, WC_NONE, @@ -2304,11 +2321,19 @@ static WindowDesc _toolbar_tablet_simple_desc( _nested_tablet_simple_widgets, lengthof(_nested_tablet_simple_widgets) ); +static WindowDesc _toolbar_tablet_confirm_desc( + WDP_AUTO, NULL, 0, 0, + WC_TABLET_BAR, WC_NONE, + WDF_NO_FOCUS, + _nested_tablet_confirm_widgets, lengthof(_nested_tablet_confirm_widgets) +); + void ResetTabletWindow() { if (_game_mode == GM_MENU) return; DeleteWindowByClass(WC_TABLET_BAR); + EraseQueuedTouchCommand(); switch (_settings_client.gui.touchscreen_mode) { case TSC_NONE: @@ -2316,9 +2341,14 @@ void ResetTabletWindow() case TSC_SIMPLE: new TabletToolbar(&_toolbar_tablet_simple_desc); break; + case TSC_CONFIRM: + new TabletToolbar(&_toolbar_tablet_confirm_desc); + InvalidateWindowData(WC_TABLET_BAR, 0, 1 << 3); + break; default: NOT_REACHED(); - } + + MarkWholeScreenDirty(); } /** Allocate the toolbar. */ @@ -2335,3 +2365,8 @@ void AllocateToolbar() ResetTabletWindow(); } + +void UpdateTouchscreenBar() +{ + InvalidateWindowData(WC_TABLET_BAR, 0, 1 << 3); +} diff --git a/src/toolbar_type.h b/src/toolbar_type.h index cfde179dcc..682cf2f568 100644 --- a/src/toolbar_type.h +++ b/src/toolbar_type.h @@ -16,8 +16,9 @@ enum TouchscreenMode { TSC_NONE = 0, TSC_SIMPLE, + TSC_CONFIRM, }; -DECLARE_CYCLE(TouchscreenMode, TSC_NONE, TSC_SIMPLE) +DECLARE_CYCLE(TouchscreenMode, TSC_NONE, TSC_CONFIRM) typedef SimpleTinyEnumT TouchscreenModeByte; #endif /* TOOLBAR_TYPE_H */ diff --git a/src/widgets/toolbar_widget.h b/src/widgets/toolbar_widget.h index c7bac73b39..4399b5d10c 100644 --- a/src/widgets/toolbar_widget.h +++ b/src/widgets/toolbar_widget.h @@ -82,6 +82,7 @@ enum ToolbarTabletWidgets { WID_TT_SHIFT, ///< Press SHIFT. WID_TT_CTRL, ///< Press CTRL. WID_TT_MOVE, ///< Click for moving around viewports. + WID_TT_CONFIRM, ///< Confirm action. }; #endif /* WIDGETS_TOOLBAR_WIDGET_H */ From f70dbfdc320094f2f8b006365403476c8378be03 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 14 Oct 2013 17:55:30 +0000 Subject: [PATCH 058/187] Set selection tiles dirty when erasing a queued command. --- src/command.cpp | 4 +++- src/tilehighlight_func.h | 1 + src/viewport.cpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/command.cpp b/src/command.cpp index 9b965faab3..7dfc7529f2 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -27,6 +27,7 @@ #include "core/backup_type.hpp" #include "object_base.h" #include "string_func.h" +#include "tilehighlight_func.h" #include "table/strings.h" @@ -596,7 +597,8 @@ void EraseQueuedTouchCommand() _is_queued_command = false; extern void UpdateTouchscreenBar(); UpdateTouchscreenBar(); - //reset selection of tiles + SetSelectionTilesDirty(); + _thd.Reset(); } /*! diff --git a/src/tilehighlight_func.h b/src/tilehighlight_func.h index af44c4d88f..ac1567277b 100644 --- a/src/tilehighlight_func.h +++ b/src/tilehighlight_func.h @@ -30,6 +30,7 @@ void VpSetPresizeRange(TileIndex from, TileIndex to); void VpSetPlaceSizingLimit(int limit); void UpdateTileSelection(); +void SetSelectionTilesDirty(); extern TileHighlightData _thd; diff --git a/src/viewport.cpp b/src/viewport.cpp index d2e6f1b2c2..84aa495469 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1717,7 +1717,7 @@ void MarkTileDirtyByTile(TileIndex tile) * * @ingroup dirty */ -static void SetSelectionTilesDirty() +void SetSelectionTilesDirty() { int x_size = _thd.size.x; int y_size = _thd.size.y; From 77a101280b027b9b6b317ad093e63f4b46eb32d4 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 14 Oct 2013 17:58:51 +0000 Subject: [PATCH 059/187] Set dirty selection tiles when bridge is too long to build. --- src/bridge_gui.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp index 78e7ff811f..9ce304fed8 100644 --- a/src/bridge_gui.cpp +++ b/src/bridge_gui.cpp @@ -24,6 +24,7 @@ #include "cmd_helper.h" #include "tunnelbridge_map.h" #include "road_gui.h" +#include "tilehighlight_func.h" #include "widgets/bridge_widget.h" @@ -429,6 +430,8 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo new BuildBridgeWindow(&_build_bridge_desc, start, end, type, bl); } else { delete bl; + SetSelectionTilesDirty(); + _thd.Reset(); ShowErrorMessage(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, errmsg, WL_INFO, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE); } } From 90c00f5b58a93d2f7bf69184910afb22847b1c46 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Fri, 25 Oct 2013 17:26:13 +0000 Subject: [PATCH 060/187] Adaptation of viewport for confirm mode. --- src/script/api/game/game_window.hpp.sq | 1 + src/script/api/game/game_window.hpp.sq.orig | 1334 +++++++ src/window.cpp | 16 +- src/window.cpp.orig | 3527 +++++++++++++++++++ 4 files changed, 4873 insertions(+), 5 deletions(-) create mode 100644 src/script/api/game/game_window.hpp.sq.orig create mode 100644 src/window.cpp.orig diff --git a/src/script/api/game/game_window.hpp.sq b/src/script/api/game/game_window.hpp.sq index 231e29b667..f25359e344 100644 --- a/src/script/api/game/game_window.hpp.sq +++ b/src/script/api/game/game_window.hpp.sq @@ -1208,6 +1208,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SHIFT, "WID_TT_SHIFT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_CTRL, "WID_TT_CTRL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_MOVE, "WID_TT_MOVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_CONFIRM, "WID_TT_CONFIRM"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_ORDER, "WID_TD_SORT_ORDER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_CRITERIA, "WID_TD_SORT_CRITERIA"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_LIST, "WID_TD_LIST"); diff --git a/src/script/api/game/game_window.hpp.sq.orig b/src/script/api/game/game_window.hpp.sq.orig new file mode 100644 index 0000000000..231e29b667 --- /dev/null +++ b/src/script/api/game/game_window.hpp.sq.orig @@ -0,0 +1,1334 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ + +#include "../script_window.hpp" +#include "../template/template_window.hpp.sq" + + +template <> const char *GetClassName() { return "GSWindow"; } + +void SQGSWindow_Register(Squirrel *engine) +{ + DefSQClass SQGSWindow("GSWindow"); + SQGSWindow.PreRegister(engine); + SQGSWindow.AddConstructor(engine, "x"); + + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_AI, "WN_GAME_OPTIONS_AI"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_ABOUT, "WN_GAME_OPTIONS_ABOUT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_NEWGRF_STATE, "WN_GAME_OPTIONS_NEWGRF_STATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_GAME_OPTIONS, "WN_GAME_OPTIONS_GAME_OPTIONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_GAME_SETTINGS, "WN_GAME_OPTIONS_GAME_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_QUERY_STRING, "WN_QUERY_STRING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_QUERY_STRING_SIGN, "WN_QUERY_STRING_SIGN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_CONFIRM_POPUP_QUERY, "WN_CONFIRM_POPUP_QUERY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_CONFIRM_POPUP_QUERY_BOOTSTRAP, "WN_CONFIRM_POPUP_QUERY_BOOTSTRAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_GAME, "WN_NETWORK_WINDOW_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_LOBBY, "WN_NETWORK_WINDOW_LOBBY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_CONTENT_LIST, "WN_NETWORK_WINDOW_CONTENT_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_START, "WN_NETWORK_WINDOW_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_STATUS_WINDOW_JOIN, "WN_NETWORK_STATUS_WINDOW_JOIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD, "WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NONE, "WC_NONE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_WINDOW, "WC_MAIN_WINDOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_TOOLBAR, "WC_MAIN_TOOLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATUS_BAR, "WC_STATUS_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TABLET_BAR, "WC_TABLET_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TOOLBAR, "WC_BUILD_TOOLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_BUILD_TOOLBAR, "WC_SCEN_BUILD_TOOLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TREES, "WC_BUILD_TREES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRANSPARENCY_TOOLBAR, "WC_TRANSPARENCY_TOOLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_SIGNAL, "WC_BUILD_SIGNAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SMALLMAP, "WC_SMALLMAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ERRMSG, "WC_ERRMSG"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOOLTIPS, "WC_TOOLTIPS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_QUERY_STRING, "WC_QUERY_STRING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CONFIRM_POPUP_QUERY, "WC_CONFIRM_POPUP_QUERY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GOAL_QUESTION, "WC_GOAL_QUESTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SAVELOAD, "WC_SAVELOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_LAND_INFO, "WC_LAND_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_DROPDOWN_MENU, "WC_DROPDOWN_MENU"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_OSK, "WC_OSK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SET_DATE, "WC_SET_DATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_SETTINGS, "WC_AI_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GRF_PARAMETERS, "WC_GRF_PARAMETERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TEXTFILE, "WC_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_AUTHORITY, "WC_TOWN_AUTHORITY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_DETAILS, "WC_VEHICLE_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_REFIT, "WC_VEHICLE_REFIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_ORDERS, "WC_VEHICLE_ORDERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_REPLACE_VEHICLE, "WC_REPLACE_VEHICLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_TIMETABLE, "WC_VEHICLE_TIMETABLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_COLOUR, "WC_COMPANY_COLOUR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_MANAGER_FACE, "WC_COMPANY_MANAGER_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_STATION, "WC_SELECT_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NEWS_WINDOW, "WC_NEWS_WINDOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_DIRECTORY, "WC_TOWN_DIRECTORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SUBSIDIES_LIST, "WC_SUBSIDIES_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_DIRECTORY, "WC_INDUSTRY_DIRECTORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MESSAGE_HISTORY, "WC_MESSAGE_HISTORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SIGN_LIST, "WC_SIGN_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_LIST, "WC_AI_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GOALS_LIST, "WC_GOALS_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STORY_BOOK, "WC_STORY_BOOK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATION_LIST, "WC_STATION_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRAINS_LIST, "WC_TRAINS_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ROADVEH_LIST, "WC_ROADVEH_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SHIPS_LIST, "WC_SHIPS_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AIRCRAFT_LIST, "WC_AIRCRAFT_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_VIEW, "WC_TOWN_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_VIEW, "WC_VEHICLE_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATION_VIEW, "WC_STATION_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_DEPOT, "WC_VEHICLE_DEPOT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_WAYPOINT_VIEW, "WC_WAYPOINT_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_VIEW, "WC_INDUSTRY_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY, "WC_COMPANY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_OBJECT, "WC_BUILD_OBJECT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_VEHICLE, "WC_BUILD_VEHICLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_BRIDGE, "WC_BUILD_BRIDGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_STATION, "WC_BUILD_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUS_STATION, "WC_BUS_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRUCK_STATION, "WC_TRUCK_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_DEPOT, "WC_BUILD_DEPOT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_WAYPOINT, "WC_BUILD_WAYPOINT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_FOUND_TOWN, "WC_FOUND_TOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_INDUSTRY, "WC_BUILD_INDUSTRY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_GAME, "WC_SELECT_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_LAND_GEN, "WC_SCEN_LAND_GEN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GENERATE_LANDSCAPE, "WC_GENERATE_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MODAL_PROGRESS, "WC_MODAL_PROGRESS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NETWORK_WINDOW, "WC_NETWORK_WINDOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CLIENT_LIST, "WC_CLIENT_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CLIENT_LIST_POPUP, "WC_CLIENT_LIST_POPUP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NETWORK_STATUS_WINDOW, "WC_NETWORK_STATUS_WINDOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SEND_NETWORK_MSG, "WC_SEND_NETWORK_MSG"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_PASSWORD_WINDOW, "WC_COMPANY_PASSWORD_WINDOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_CARGOES, "WC_INDUSTRY_CARGOES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GRAPH_LEGEND, "WC_GRAPH_LEGEND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_FINANCES, "WC_FINANCES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INCOME_GRAPH, "WC_INCOME_GRAPH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_OPERATING_PROFIT, "WC_OPERATING_PROFIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_DELIVERED_CARGO, "WC_DELIVERED_CARGO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PERFORMANCE_HISTORY, "WC_PERFORMANCE_HISTORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_VALUE, "WC_COMPANY_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_LEAGUE, "WC_COMPANY_LEAGUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PAYMENT_RATES, "WC_PAYMENT_RATES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PERFORMANCE_DETAIL, "WC_PERFORMANCE_DETAIL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_INFRASTRUCTURE, "WC_COMPANY_INFRASTRUCTURE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUY_COMPANY, "WC_BUY_COMPANY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ENGINE_PREVIEW, "WC_ENGINE_PREVIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MUSIC_WINDOW, "WC_MUSIC_WINDOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MUSIC_TRACK_SELECTION, "WC_MUSIC_TRACK_SELECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GAME_OPTIONS, "WC_GAME_OPTIONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CUSTOM_CURRENCY, "WC_CUSTOM_CURRENCY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CHEATS, "WC_CHEATS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_EXTRA_VIEW_PORT, "WC_EXTRA_VIEW_PORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CONSOLE, "WC_CONSOLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BOOTSTRAP, "WC_BOOTSTRAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_HIGHSCORE, "WC_HIGHSCORE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ENDSCREEN, "WC_ENDSCREEN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_DEBUG, "WC_AI_DEBUG"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NEWGRF_INSPECT, "WC_NEWGRF_INSPECT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SPRITE_ALIGNER, "WC_SPRITE_ALIGNER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_LINKGRAPH_LEGEND, "WC_LINKGRAPH_LEGEND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INVALID, "WC_INVALID"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BLUE, "TC_BLUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_SILVER, "TC_SILVER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GOLD, "TC_GOLD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_RED, "TC_RED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_PURPLE, "TC_PURPLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_LIGHT_BROWN, "TC_LIGHT_BROWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_ORANGE, "TC_ORANGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GREEN, "TC_GREEN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_YELLOW, "TC_YELLOW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_DARK_GREEN, "TC_DARK_GREEN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_CREAM, "TC_CREAM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BROWN, "TC_BROWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_WHITE, "TC_WHITE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_LIGHT_BLUE, "TC_LIGHT_BLUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GREY, "TC_GREY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_DARK_BLUE, "TC_DARK_BLUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BLACK, "TC_BLACK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::TC_INVALID, "TC_INVALID"); + SQGSWindow.DefSQConst(engine, ScriptWindow::NUMBER_ALL, "NUMBER_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WIDGET_ALL, "WIDGET_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_CAPTION, "WID_AIL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_LIST, "WID_AIL_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_SCROLLBAR, "WID_AIL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_INFO_BG, "WID_AIL_INFO_BG"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_ACCEPT, "WID_AIL_ACCEPT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_CANCEL, "WID_AIL_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_CAPTION, "WID_AIS_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_BACKGROUND, "WID_AIS_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_SCROLLBAR, "WID_AIS_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_ACCEPT, "WID_AIS_ACCEPT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_RESET, "WID_AIS_RESET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_BACKGROUND, "WID_AIC_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_DECREASE, "WID_AIC_DECREASE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_INCREASE, "WID_AIC_INCREASE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_NUMBER, "WID_AIC_NUMBER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_GAMELIST, "WID_AIC_GAMELIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_LIST, "WID_AIC_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_SCROLLBAR, "WID_AIC_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_MOVE_UP, "WID_AIC_MOVE_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_MOVE_DOWN, "WID_AIC_MOVE_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CHANGE, "WID_AIC_CHANGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CONFIGURE, "WID_AIC_CONFIGURE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CLOSE, "WID_AIC_CLOSE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_TEXTFILE, "WID_AIC_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CONTENT_DOWNLOAD, "WID_AIC_CONTENT_DOWNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_VIEW, "WID_AID_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_NAME_TEXT, "WID_AID_NAME_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SETTINGS, "WID_AID_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SCRIPT_GAME, "WID_AID_SCRIPT_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_RELOAD_TOGGLE, "WID_AID_RELOAD_TOGGLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_LOG_PANEL, "WID_AID_LOG_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SCROLLBAR, "WID_AID_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_COMPANY_BUTTON_START, "WID_AID_COMPANY_BUTTON_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_COMPANY_BUTTON_END, "WID_AID_COMPANY_BUTTON_END"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STRING_WIDGETS, "WID_AID_BREAK_STRING_WIDGETS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STR_ON_OFF_BTN, "WID_AID_BREAK_STR_ON_OFF_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STR_EDIT_BOX, "WID_AID_BREAK_STR_EDIT_BOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_MATCH_CASE_BTN, "WID_AID_MATCH_CASE_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_CONTINUE_BTN, "WID_AID_CONTINUE_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AT_AIRPORT, "WID_AT_AIRPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AT_DEMOLISH, "WID_AT_DEMOLISH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_CLASS_DROPDOWN, "WID_AP_CLASS_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_AIRPORT_LIST, "WID_AP_AIRPORT_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_SCROLLBAR, "WID_AP_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_NUM, "WID_AP_LAYOUT_NUM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_DECREASE, "WID_AP_LAYOUT_DECREASE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_INCREASE, "WID_AP_LAYOUT_INCREASE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_AIRPORT_SPRITE, "WID_AP_AIRPORT_SPRITE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_EXTRA_TEXT, "WID_AP_EXTRA_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BOTTOMPANEL, "WID_AP_BOTTOMPANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_COVERAGE_LABEL, "WID_AP_COVERAGE_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BTN_DONTHILIGHT, "WID_AP_BTN_DONTHILIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BTN_DOHILIGHT, "WID_AP_BTN_DOHILIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_CAPTION, "WID_RV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_MATRIX, "WID_RV_LEFT_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_SCROLLBAR, "WID_RV_LEFT_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_MATRIX, "WID_RV_RIGHT_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_SCROLLBAR, "WID_RV_RIGHT_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_DETAILS, "WID_RV_LEFT_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_DETAILS, "WID_RV_RIGHT_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_START_REPLACE, "WID_RV_START_REPLACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_INFO_TAB, "WID_RV_INFO_TAB"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_STOP_REPLACE, "WID_RV_STOP_REPLACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_ENGINEWAGON_TOGGLE, "WID_RV_TRAIN_ENGINEWAGON_TOGGLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_FLUFF_LEFT, "WID_RV_TRAIN_FLUFF_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_RAILTYPE_DROPDOWN, "WID_RV_TRAIN_RAILTYPE_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_FLUFF_RIGHT, "WID_RV_TRAIN_FLUFF_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_WAGONREMOVE_TOGGLE, "WID_RV_TRAIN_WAGONREMOVE_TOGGLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BB_BACKGROUND, "WID_BB_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_QUESTION, "WID_BAFD_QUESTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_YES, "WID_BAFD_YES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_NO, "WID_BAFD_NO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_CAPTION, "WID_BBS_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_DROPDOWN_ORDER, "WID_BBS_DROPDOWN_ORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_DROPDOWN_CRITERIA, "WID_BBS_DROPDOWN_CRITERIA"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_BRIDGE_LIST, "WID_BBS_BRIDGE_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_SCROLLBAR, "WID_BBS_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_CAPTION, "WID_BV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SORT_ASSENDING_DESCENDING, "WID_BV_SORT_ASSENDING_DESCENDING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SORT_DROPDOWN, "WID_BV_SORT_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_CARGO_FILTER_DROPDOWN, "WID_BV_CARGO_FILTER_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_LIST, "WID_BV_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SCROLLBAR, "WID_BV_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_PANEL, "WID_BV_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_BUILD, "WID_BV_BUILD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_BUILD_SEL, "WID_BV_BUILD_SEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_RENAME, "WID_BV_RENAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_PANEL, "WID_C_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_CAPTION, "WID_C_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_FACE, "WID_C_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_FACE_TITLE, "WID_C_FACE_TITLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INAUGURATION, "WID_C_DESC_INAUGURATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COLOUR_SCHEME, "WID_C_DESC_COLOUR_SCHEME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COLOUR_SCHEME_EXAMPLE, "WID_C_DESC_COLOUR_SCHEME_EXAMPLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_VEHICLE, "WID_C_DESC_VEHICLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_VEHICLE_COUNTS, "WID_C_DESC_VEHICLE_COUNTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COMPANY_VALUE, "WID_C_DESC_COMPANY_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INFRASTRUCTURE, "WID_C_DESC_INFRASTRUCTURE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INFRASTRUCTURE_COUNTS, "WID_C_DESC_INFRASTRUCTURE_COUNTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_DESC_OWNERS, "WID_C_SELECT_DESC_OWNERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_OWNERS, "WID_C_DESC_OWNERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_BUTTONS, "WID_C_SELECT_BUTTONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_NEW_FACE, "WID_C_NEW_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COLOUR_SCHEME, "WID_C_COLOUR_SCHEME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_PRESIDENT_NAME, "WID_C_PRESIDENT_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_NAME, "WID_C_COMPANY_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BUY_SHARE, "WID_C_BUY_SHARE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELL_SHARE, "WID_C_SELL_SHARE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_VIEW_BUILD_HQ, "WID_C_SELECT_VIEW_BUILD_HQ"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_VIEW_HQ, "WID_C_VIEW_HQ"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BUILD_HQ, "WID_C_BUILD_HQ"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_RELOCATE, "WID_C_SELECT_RELOCATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_RELOCATE_HQ, "WID_C_RELOCATE_HQ"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_VIEW_INFRASTRUCTURE, "WID_C_VIEW_INFRASTRUCTURE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_HAS_PASSWORD, "WID_C_HAS_PASSWORD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_MULTIPLAYER, "WID_C_SELECT_MULTIPLAYER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_PASSWORD, "WID_C_COMPANY_PASSWORD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_JOIN, "WID_C_COMPANY_JOIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_CAPTION, "WID_CF_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOGGLE_SIZE, "WID_CF_TOGGLE_SIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_PANEL, "WID_CF_SEL_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_CATEGORY, "WID_CF_EXPS_CATEGORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE1, "WID_CF_EXPS_PRICE1"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE2, "WID_CF_EXPS_PRICE2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE3, "WID_CF_EXPS_PRICE3"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOTAL_PANEL, "WID_CF_TOTAL_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_MAXLOAN, "WID_CF_SEL_MAXLOAN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_BALANCE_VALUE, "WID_CF_BALANCE_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_LOAN_VALUE, "WID_CF_LOAN_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_LOAN_LINE, "WID_CF_LOAN_LINE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOTAL_VALUE, "WID_CF_TOTAL_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_MAXLOAN_GAP, "WID_CF_MAXLOAN_GAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_MAXLOAN_VALUE, "WID_CF_MAXLOAN_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_BUTTONS, "WID_CF_SEL_BUTTONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_INCREASE_LOAN, "WID_CF_INCREASE_LOAN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_REPAY_LOAN, "WID_CF_REPAY_LOAN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_INFRASTRUCTURE, "WID_CF_INFRASTRUCTURE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CAPTION, "WID_SCL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_GENERAL, "WID_SCL_CLASS_GENERAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_RAIL, "WID_SCL_CLASS_RAIL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_ROAD, "WID_SCL_CLASS_ROAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_SHIP, "WID_SCL_CLASS_SHIP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_AIRCRAFT, "WID_SCL_CLASS_AIRCRAFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_SPACER_DROPDOWN, "WID_SCL_SPACER_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_PRI_COL_DROPDOWN, "WID_SCL_PRI_COL_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_SEC_COL_DROPDOWN, "WID_SCL_SEC_COL_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_MATRIX, "WID_SCL_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CAPTION, "WID_SCMF_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TOGGLE_LARGE_SMALL, "WID_SCMF_TOGGLE_LARGE_SMALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SELECT_FACE, "WID_SCMF_SELECT_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CANCEL, "WID_SCMF_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ACCEPT, "WID_SCMF_ACCEPT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_MALE, "WID_SCMF_MALE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FEMALE, "WID_SCMF_FEMALE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_MALE2, "WID_SCMF_MALE2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FEMALE2, "WID_SCMF_FEMALE2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_LOADSAVE, "WID_SCMF_SEL_LOADSAVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_MALEFEMALE, "WID_SCMF_SEL_MALEFEMALE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_PARTS, "WID_SCMF_SEL_PARTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_RANDOM_NEW_FACE, "WID_SCMF_RANDOM_NEW_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON, "WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FACE, "WID_SCMF_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LOAD, "WID_SCMF_LOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FACECODE, "WID_SCMF_FACECODE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SAVE, "WID_SCMF_SAVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT, "WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_TEXT, "WID_SCMF_TIE_EARRING_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_TEXT, "WID_SCMF_LIPS_MOUSTACHE_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_GLASSES_TEXT, "WID_SCMF_HAS_GLASSES_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_TEXT, "WID_SCMF_HAIR_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_TEXT, "WID_SCMF_EYEBROWS_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_TEXT, "WID_SCMF_EYECOLOUR_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_TEXT, "WID_SCMF_GLASSES_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_TEXT, "WID_SCMF_NOSE_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_TEXT, "WID_SCMF_CHIN_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_TEXT, "WID_SCMF_JACKET_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_TEXT, "WID_SCMF_COLLAR_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ETHNICITY_EUR, "WID_SCMF_ETHNICITY_EUR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ETHNICITY_AFR, "WID_SCMF_ETHNICITY_AFR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_MOUSTACHE_EARRING, "WID_SCMF_HAS_MOUSTACHE_EARRING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_GLASSES, "WID_SCMF_HAS_GLASSES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_L, "WID_SCMF_EYECOLOUR_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR, "WID_SCMF_EYECOLOUR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_R, "WID_SCMF_EYECOLOUR_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_L, "WID_SCMF_CHIN_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN, "WID_SCMF_CHIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_R, "WID_SCMF_CHIN_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_L, "WID_SCMF_EYEBROWS_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS, "WID_SCMF_EYEBROWS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_R, "WID_SCMF_EYEBROWS_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_L, "WID_SCMF_LIPS_MOUSTACHE_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE, "WID_SCMF_LIPS_MOUSTACHE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_R, "WID_SCMF_LIPS_MOUSTACHE_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_L, "WID_SCMF_NOSE_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE, "WID_SCMF_NOSE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_R, "WID_SCMF_NOSE_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_L, "WID_SCMF_HAIR_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR, "WID_SCMF_HAIR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_R, "WID_SCMF_HAIR_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_L, "WID_SCMF_JACKET_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET, "WID_SCMF_JACKET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_R, "WID_SCMF_JACKET_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_L, "WID_SCMF_COLLAR_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR, "WID_SCMF_COLLAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_R, "WID_SCMF_COLLAR_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_L, "WID_SCMF_TIE_EARRING_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING, "WID_SCMF_TIE_EARRING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_R, "WID_SCMF_TIE_EARRING_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_L, "WID_SCMF_GLASSES_L"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES, "WID_SCMF_GLASSES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_R, "WID_SCMF_GLASSES_R"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_CAPTION, "WID_CI_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_RAIL_DESC, "WID_CI_RAIL_DESC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_RAIL_COUNT, "WID_CI_RAIL_COUNT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_DESC, "WID_CI_ROAD_DESC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_COUNT, "WID_CI_ROAD_COUNT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_DESC, "WID_CI_WATER_DESC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_COUNT, "WID_CI_WATER_COUNT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_STATION_DESC, "WID_CI_STATION_DESC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_STATION_COUNT, "WID_CI_STATION_COUNT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TOTAL_DESC, "WID_CI_TOTAL_DESC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TOTAL, "WID_CI_TOTAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_CAPTION, "WID_BC_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_FACE, "WID_BC_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_QUESTION, "WID_BC_QUESTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_NO, "WID_BC_NO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_YES, "WID_BC_YES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BACKGROUND, "WID_C_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_DAY, "WID_SD_DAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_MONTH, "WID_SD_MONTH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_YEAR, "WID_SD_YEAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_SET_DATE, "WID_SD_SET_DATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_CAPTION, "WID_D_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL, "WID_D_SELL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_SELL_CHAIN, "WID_D_SHOW_SELL_CHAIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL_CHAIN, "WID_D_SELL_CHAIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL_ALL, "WID_D_SELL_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_AUTOREPLACE, "WID_D_AUTOREPLACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_MATRIX, "WID_D_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_V_SCROLL, "WID_D_V_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_H_SCROLL, "WID_D_SHOW_H_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_H_SCROLL, "WID_D_H_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_BUILD, "WID_D_BUILD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_CLONE, "WID_D_CLONE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_LOCATION, "WID_D_LOCATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_RENAME, "WID_D_SHOW_RENAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_RENAME, "WID_D_RENAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_VEHICLE_LIST, "WID_D_VEHICLE_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_STOP_ALL, "WID_D_STOP_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_START_ALL, "WID_D_START_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_BACKGROUND, "WID_BDD_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_X, "WID_BDD_X"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_Y, "WID_BDD_Y"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_CANAL, "WID_DT_CANAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_LOCK, "WID_DT_LOCK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_DEMOLISH, "WID_DT_DEMOLISH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_DEPOT, "WID_DT_DEPOT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_STATION, "WID_DT_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_BUOY, "WID_DT_BUOY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_RIVER, "WID_DT_RIVER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_BUILD_AQUEDUCT, "WID_DT_BUILD_AQUEDUCT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_INVALID, "WID_DT_INVALID"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_ITEMS, "WID_DM_ITEMS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_SHOW_SCROLL, "WID_DM_SHOW_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_SCROLL, "WID_DM_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_QUESTION, "WID_EP_QUESTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_NO, "WID_EP_NO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_YES, "WID_EP_YES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_CAPTION, "WID_EM_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_FACE, "WID_EM_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_MESSAGE, "WID_EM_MESSAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CAPTION, "WID_SL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SORT_BYNAME, "WID_SL_SORT_BYNAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SORT_BYDATE, "WID_SL_SORT_BYDATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_BACKGROUND, "WID_SL_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_FILE_BACKGROUND, "WID_SL_FILE_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_HOME_BUTTON, "WID_SL_HOME_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DRIVES_DIRECTORIES_LIST, "WID_SL_DRIVES_DIRECTORIES_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SCROLLBAR, "WID_SL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CONTENT_DOWNLOAD, "WID_SL_CONTENT_DOWNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SAVE_OSK_TITLE, "WID_SL_SAVE_OSK_TITLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DELETE_SELECTION, "WID_SL_DELETE_SELECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SAVE_GAME, "WID_SL_SAVE_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CONTENT_DOWNLOAD_SEL, "WID_SL_CONTENT_DOWNLOAD_SEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DETAILS, "WID_SL_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_NEWGRF_INFO, "WID_SL_NEWGRF_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_LOAD_BUTTON, "WID_SL_LOAD_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_MISSING_NEWGRFS, "WID_SL_MISSING_NEWGRFS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TEMPERATE, "WID_GL_TEMPERATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_ARCTIC, "WID_GL_ARCTIC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TROPICAL, "WID_GL_TROPICAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TOYLAND, "WID_GL_TOYLAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAPSIZE_X_PULLDOWN, "WID_GL_MAPSIZE_X_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAPSIZE_Y_PULLDOWN, "WID_GL_MAPSIZE_Y_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TOWN_PULLDOWN, "WID_GL_TOWN_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_INDUSTRY_PULLDOWN, "WID_GL_INDUSTRY_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RANDOM_EDITBOX, "WID_GL_RANDOM_EDITBOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RANDOM_BUTTON, "WID_GL_RANDOM_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_GENERATE_BUTTON, "WID_GL_GENERATE_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_DOWN, "WID_GL_START_DATE_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_TEXT, "WID_GL_START_DATE_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_UP, "WID_GL_START_DATE_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_DOWN, "WID_GL_SNOW_LEVEL_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_TEXT, "WID_GL_SNOW_LEVEL_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_UP, "WID_GL_SNOW_LEVEL_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TREE_PULLDOWN, "WID_GL_TREE_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LANDSCAPE_PULLDOWN, "WID_GL_LANDSCAPE_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_NAME_TEXT, "WID_GL_HEIGHTMAP_NAME_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_SIZE_TEXT, "WID_GL_HEIGHTMAP_SIZE_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_ROTATION_PULLDOWN, "WID_GL_HEIGHTMAP_ROTATION_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TERRAIN_PULLDOWN, "WID_GL_TERRAIN_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_PULLDOWN, "WID_GL_WATER_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RIVER_PULLDOWN, "WID_GL_RIVER_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SMOOTHNESS_PULLDOWN, "WID_GL_SMOOTHNESS_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_VARIETY_PULLDOWN, "WID_GL_VARIETY_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_BORDERS_RANDOM, "WID_GL_BORDERS_RANDOM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_NW, "WID_GL_WATER_NW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_NE, "WID_GL_WATER_NE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_SE, "WID_GL_WATER_SE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_SW, "WID_GL_WATER_SW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TEMPERATE, "WID_CS_TEMPERATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_ARCTIC, "WID_CS_ARCTIC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TROPICAL, "WID_CS_TROPICAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TOYLAND, "WID_CS_TOYLAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_EMPTY_WORLD, "WID_CS_EMPTY_WORLD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_RANDOM_WORLD, "WID_CS_RANDOM_WORLD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_MAPSIZE_X_PULLDOWN, "WID_CS_MAPSIZE_X_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_MAPSIZE_Y_PULLDOWN, "WID_CS_MAPSIZE_Y_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_DOWN, "WID_CS_START_DATE_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_TEXT, "WID_CS_START_DATE_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_UP, "WID_CS_START_DATE_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_DOWN, "WID_CS_FLAT_LAND_HEIGHT_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_TEXT, "WID_CS_FLAT_LAND_HEIGHT_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_UP, "WID_CS_FLAT_LAND_HEIGHT_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_PROGRESS_BAR, "WID_GP_PROGRESS_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_PROGRESS_TEXT, "WID_GP_PROGRESS_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_ABORT, "WID_GP_ABORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_CAPTION, "WID_GOAL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_LIST, "WID_GOAL_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_SCROLLBAR, "WID_GOAL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_CAPTION, "WID_GQ_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_QUESTION, "WID_GQ_QUESTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTONS, "WID_GQ_BUTTONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_1, "WID_GQ_BUTTON_1"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_2, "WID_GQ_BUTTON_2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_3, "WID_GQ_BUTTON_3"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_BACKGROUND, "WID_GL_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_FIRST_COMPANY, "WID_GL_FIRST_COMPANY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LAST_COMPANY, "WID_GL_LAST_COMPANY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_KEY_BUTTON, "WID_CV_KEY_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_BACKGROUND, "WID_CV_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_GRAPH, "WID_CV_GRAPH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_RESIZE, "WID_CV_RESIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_KEY, "WID_PHG_KEY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_DETAILED_PERFORMANCE, "WID_PHG_DETAILED_PERFORMANCE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_BACKGROUND, "WID_PHG_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_GRAPH, "WID_PHG_GRAPH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_RESIZE, "WID_PHG_RESIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_BACKGROUND, "WID_CPR_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_HEADER, "WID_CPR_HEADER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_GRAPH, "WID_CPR_GRAPH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_RESIZE, "WID_CPR_RESIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_FOOTER, "WID_CPR_FOOTER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_ENABLE_CARGOES, "WID_CPR_ENABLE_CARGOES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_DISABLE_CARGOES, "WID_CPR_DISABLE_CARGOES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_CARGO_FIRST, "WID_CPR_CARGO_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CL_BACKGROUND, "WID_CL_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_SCORE_FIRST, "WID_PRD_SCORE_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_SCORE_LAST, "WID_PRD_SCORE_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_COMPANY_FIRST, "WID_PRD_COMPANY_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_COMPANY_LAST, "WID_PRD_COMPANY_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_CAPTION, "WID_GL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SORT_BY_ORDER, "WID_GL_SORT_BY_ORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SORT_BY_DROPDOWN, "WID_GL_SORT_BY_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_VEHICLE, "WID_GL_LIST_VEHICLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_VEHICLE_SCROLLBAR, "WID_GL_LIST_VEHICLE_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_AVAILABLE_VEHICLES, "WID_GL_AVAILABLE_VEHICLES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MANAGE_VEHICLES_DROPDOWN, "WID_GL_MANAGE_VEHICLES_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_STOP_ALL, "WID_GL_STOP_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_ALL, "WID_GL_START_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_ALL_VEHICLES, "WID_GL_ALL_VEHICLES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_DEFAULT_VEHICLES, "WID_GL_DEFAULT_VEHICLES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_GROUP, "WID_GL_LIST_GROUP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_GROUP_SCROLLBAR, "WID_GL_LIST_GROUP_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_CREATE_GROUP, "WID_GL_CREATE_GROUP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_DELETE_GROUP, "WID_GL_DELETE_GROUP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RENAME_GROUP, "WID_GL_RENAME_GROUP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_REPLACE_PROTECTION, "WID_GL_REPLACE_PROTECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_H_BACKGROUND, "WID_H_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_MATRIX_WIDGET, "WID_DPI_MATRIX_WIDGET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_SCROLLBAR, "WID_DPI_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_INFOPANEL, "WID_DPI_INFOPANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_DISPLAY_WIDGET, "WID_DPI_DISPLAY_WIDGET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_FUND_WIDGET, "WID_DPI_FUND_WIDGET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_CAPTION, "WID_IV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_VIEWPORT, "WID_IV_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_INFO, "WID_IV_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_GOTO, "WID_IV_GOTO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_DISPLAY, "WID_IV_DISPLAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_DROPDOWN_ORDER, "WID_ID_DROPDOWN_ORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_DROPDOWN_CRITERIA, "WID_ID_DROPDOWN_CRITERIA"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_INDUSTRY_LIST, "WID_ID_INDUSTRY_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_SCROLLBAR, "WID_ID_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_CAPTION, "WID_IC_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_NOTIFY, "WID_IC_NOTIFY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_PANEL, "WID_IC_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_SCROLLBAR, "WID_IC_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_CARGO_DROPDOWN, "WID_IC_CARGO_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_IND_DROPDOWN, "WID_IC_IND_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_GENERATE_GAME, "WID_SGI_GENERATE_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_LOAD_GAME, "WID_SGI_LOAD_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_SCENARIO, "WID_SGI_PLAY_SCENARIO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_HEIGHTMAP, "WID_SGI_PLAY_HEIGHTMAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_EDIT_SCENARIO, "WID_SGI_EDIT_SCENARIO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_NETWORK, "WID_SGI_PLAY_NETWORK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TEMPERATE_LANDSCAPE, "WID_SGI_TEMPERATE_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_ARCTIC_LANDSCAPE, "WID_SGI_ARCTIC_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TROPIC_LANDSCAPE, "WID_SGI_TROPIC_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TOYLAND_LANDSCAPE, "WID_SGI_TOYLAND_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TRANSLATION_SELECTION, "WID_SGI_TRANSLATION_SELECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TRANSLATION, "WID_SGI_TRANSLATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_OPTIONS, "WID_SGI_OPTIONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_HIGHSCORE, "WID_SGI_HIGHSCORE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_SETTINGS_OPTIONS, "WID_SGI_SETTINGS_OPTIONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_GRF_SETTINGS, "WID_SGI_GRF_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_CONTENT_DOWNLOAD, "WID_SGI_CONTENT_DOWNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_AI_SETTINGS, "WID_SGI_AI_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_EXIT, "WID_SGI_EXIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CAPTION, "WID_LGL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION, "WID_LGL_SATURATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION_FIRST, "WID_LGL_SATURATION_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION_LAST, "WID_LGL_SATURATION_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES, "WID_LGL_COMPANIES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANY_FIRST, "WID_LGL_COMPANY_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANY_LAST, "WID_LGL_COMPANY_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES_ALL, "WID_LGL_COMPANIES_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES_NONE, "WID_LGL_COMPANIES_NONE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES, "WID_LGL_CARGOES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGO_FIRST, "WID_LGL_CARGO_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGO_LAST, "WID_LGL_CARGO_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES_ALL, "WID_LGL_CARGOES_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES_NONE, "WID_LGL_CARGOES_NONE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_VIEWPORT, "WID_M_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LI_BACKGROUND, "WID_LI_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BACKGROUND, "WID_TT_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_A_SCROLLING_TEXT, "WID_A_SCROLLING_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_A_WEBSITE, "WID_A_WEBSITE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_CAPTION, "WID_QS_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_TEXT, "WID_QS_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_DEFAULT, "WID_QS_DEFAULT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_CANCEL, "WID_QS_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_OK, "WID_QS_OK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_CAPTION, "WID_Q_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_TEXT, "WID_Q_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_NO, "WID_Q_NO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_YES, "WID_Q_YES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_CAPTION, "WID_TF_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_WRAPTEXT, "WID_TF_WRAPTEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_BACKGROUND, "WID_TF_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_VSCROLLBAR, "WID_TF_VSCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_HSCROLLBAR, "WID_TF_HSCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LIST_LEFT, "WID_MTS_LIST_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LEFT_SCROLLBAR, "WID_MTS_LEFT_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_PLAYLIST, "WID_MTS_PLAYLIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LIST_RIGHT, "WID_MTS_LIST_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_RIGHT_SCROLLBAR, "WID_MTS_RIGHT_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_ALL, "WID_MTS_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_OLD, "WID_MTS_OLD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_NEW, "WID_MTS_NEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_EZY, "WID_MTS_EZY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CUSTOM1, "WID_MTS_CUSTOM1"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CUSTOM2, "WID_MTS_CUSTOM2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CLEAR, "WID_MTS_CLEAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PREV, "WID_M_PREV"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_NEXT, "WID_M_NEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_STOP, "WID_M_STOP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PLAY, "WID_M_PLAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_SLIDERS, "WID_M_SLIDERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_MUSIC_VOL, "WID_M_MUSIC_VOL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_EFFECT_VOL, "WID_M_EFFECT_VOL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_BACKGROUND, "WID_M_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK, "WID_M_TRACK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_NR, "WID_M_TRACK_NR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_TITLE, "WID_M_TRACK_TITLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_NAME, "WID_M_TRACK_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_SHUFFLE, "WID_M_SHUFFLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PROGRAMME, "WID_M_PROGRAMME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_ALL, "WID_M_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_OLD, "WID_M_OLD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_NEW, "WID_M_NEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_EZY, "WID_M_EZY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_CUSTOM1, "WID_M_CUSTOM1"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_CUSTOM2, "WID_M_CUSTOM2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_CLOSE, "WID_NC_CLOSE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_BACKGROUND, "WID_NC_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_DESTINATION, "WID_NC_DESTINATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_TEXTBOX, "WID_NC_TEXTBOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_SENDBUTTON, "WID_NC_SENDBUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCDS_BACKGROUND, "WID_NCDS_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCDS_CANCELOK, "WID_NCDS_CANCELOK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_BACKGROUND, "WID_NCL_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_FILTER_CAPT, "WID_NCL_FILTER_CAPT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_FILTER, "WID_NCL_FILTER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_CHECKBOX, "WID_NCL_CHECKBOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_TYPE, "WID_NCL_TYPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_NAME, "WID_NCL_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_MATRIX, "WID_NCL_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SCROLLBAR, "WID_NCL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_DETAILS, "WID_NCL_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_TEXTFILE, "WID_NCL_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SELECT_ALL, "WID_NCL_SELECT_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SELECT_UPDATE, "WID_NCL_SELECT_UPDATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_UNSELECT, "WID_NCL_UNSELECT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_OPEN_URL, "WID_NCL_OPEN_URL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_CANCEL, "WID_NCL_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_DOWNLOAD, "WID_NCL_DOWNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SEL_ALL_UPDATE, "WID_NCL_SEL_ALL_UPDATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SEARCH_EXTERNAL, "WID_NCL_SEARCH_EXTERNAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MAIN, "WID_NG_MAIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CONNECTION, "WID_NG_CONNECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CONN_BTN, "WID_NG_CONN_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENT_LABEL, "WID_NG_CLIENT_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENT, "WID_NG_CLIENT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FILTER_LABEL, "WID_NG_FILTER_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FILTER, "WID_NG_FILTER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_HEADER, "WID_NG_HEADER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NAME, "WID_NG_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENTS, "WID_NG_CLIENTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MAPSIZE, "WID_NG_MAPSIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DATE, "WID_NG_DATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_YEARS, "WID_NG_YEARS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_INFO, "WID_NG_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MATRIX, "WID_NG_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_SCROLLBAR, "WID_NG_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED_LABEL, "WID_NG_LASTJOINED_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED, "WID_NG_LASTJOINED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED_SPACER, "WID_NG_LASTJOINED_SPACER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DETAILS, "WID_NG_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DETAILS_SPACER, "WID_NG_DETAILS_SPACER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_JOIN, "WID_NG_JOIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_REFRESH, "WID_NG_REFRESH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF, "WID_NG_NEWGRF"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_SEL, "WID_NG_NEWGRF_SEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_MISSING, "WID_NG_NEWGRF_MISSING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_MISSING_SEL, "WID_NG_NEWGRF_MISSING_SEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FIND, "WID_NG_FIND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_ADD, "WID_NG_ADD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_START, "WID_NG_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CANCEL, "WID_NG_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_BACKGROUND, "WID_NSS_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GAMENAME_LABEL, "WID_NSS_GAMENAME_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GAMENAME, "WID_NSS_GAMENAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SETPWD, "WID_NSS_SETPWD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CONNTYPE_LABEL, "WID_NSS_CONNTYPE_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CONNTYPE_BTN, "WID_NSS_CONNTYPE_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_LABEL, "WID_NSS_CLIENTS_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_BTND, "WID_NSS_CLIENTS_BTND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_TXT, "WID_NSS_CLIENTS_TXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_BTNU, "WID_NSS_CLIENTS_BTNU"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_LABEL, "WID_NSS_COMPANIES_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_BTND, "WID_NSS_COMPANIES_BTND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_TXT, "WID_NSS_COMPANIES_TXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_BTNU, "WID_NSS_COMPANIES_BTNU"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_LABEL, "WID_NSS_SPECTATORS_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_BTND, "WID_NSS_SPECTATORS_BTND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_TXT, "WID_NSS_SPECTATORS_TXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_BTNU, "WID_NSS_SPECTATORS_BTNU"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LANGUAGE_LABEL, "WID_NSS_LANGUAGE_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LANGUAGE_BTN, "WID_NSS_LANGUAGE_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GENERATE_GAME, "WID_NSS_GENERATE_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LOAD_GAME, "WID_NSS_LOAD_GAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_PLAY_SCENARIO, "WID_NSS_PLAY_SCENARIO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_PLAY_HEIGHTMAP, "WID_NSS_PLAY_HEIGHTMAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CANCEL, "WID_NSS_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_BACKGROUND, "WID_NL_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_TEXT, "WID_NL_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_HEADER, "WID_NL_HEADER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_MATRIX, "WID_NL_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_SCROLLBAR, "WID_NL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_DETAILS, "WID_NL_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_JOIN, "WID_NL_JOIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_NEW, "WID_NL_NEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_SPECTATE, "WID_NL_SPECTATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_REFRESH, "WID_NL_REFRESH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_CANCEL, "WID_NL_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CL_PANEL, "WID_CL_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CLP_PANEL, "WID_CLP_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NJS_BACKGROUND, "WID_NJS_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NJS_CANCELOK, "WID_NJS_CANCELOK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_BACKGROUND, "WID_NCP_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_LABEL, "WID_NCP_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_PASSWORD, "WID_NCP_PASSWORD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_SAVE_AS_DEFAULT_PASSWORD, "WID_NCP_SAVE_AS_DEFAULT_PASSWORD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_CANCEL, "WID_NCP_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_OK, "WID_NCP_OK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_CAPTION, "WID_NGRFI_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_PARENT, "WID_NGRFI_PARENT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_PREV, "WID_NGRFI_VEH_PREV"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_NEXT, "WID_NGRFI_VEH_NEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_CHAIN, "WID_NGRFI_VEH_CHAIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_MAINPANEL, "WID_NGRFI_MAINPANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_SCROLLBAR, "WID_NGRFI_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_CAPTION, "WID_SA_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_PREVIOUS, "WID_SA_PREVIOUS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_GOTO, "WID_SA_GOTO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_NEXT, "WID_SA_NEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_UP, "WID_SA_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_LEFT, "WID_SA_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_RIGHT, "WID_SA_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_DOWN, "WID_SA_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_SPRITE, "WID_SA_SPRITE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_OFFSETS, "WID_SA_OFFSETS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_PICKER, "WID_SA_PICKER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_LIST, "WID_SA_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_SCROLLBAR, "WID_SA_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SHOW_NUMPAR, "WID_NP_SHOW_NUMPAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_DEC, "WID_NP_NUMPAR_DEC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_INC, "WID_NP_NUMPAR_INC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR, "WID_NP_NUMPAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_TEXT, "WID_NP_NUMPAR_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_BACKGROUND, "WID_NP_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SCROLLBAR, "WID_NP_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_ACCEPT, "WID_NP_ACCEPT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_RESET, "WID_NP_RESET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SHOW_DESCRIPTION, "WID_NP_SHOW_DESCRIPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_DESCRIPTION, "WID_NP_DESCRIPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_LIST, "WID_NS_PRESET_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_SAVE, "WID_NS_PRESET_SAVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_DELETE, "WID_NS_PRESET_DELETE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_ADD, "WID_NS_ADD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_REMOVE, "WID_NS_REMOVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_MOVE_UP, "WID_NS_MOVE_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_MOVE_DOWN, "WID_NS_MOVE_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_FILTER, "WID_NS_FILTER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_FILE_LIST, "WID_NS_FILE_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SCROLLBAR, "WID_NS_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_AVAIL_LIST, "WID_NS_AVAIL_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SCROLL2BAR, "WID_NS_SCROLL2BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_INFO_TITLE, "WID_NS_NEWGRF_INFO_TITLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_INFO, "WID_NS_NEWGRF_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_OPEN_URL, "WID_NS_OPEN_URL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_TEXTFILE, "WID_NS_NEWGRF_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SET_PARAMETERS, "WID_NS_SET_PARAMETERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_VIEW_PARAMETERS, "WID_NS_VIEW_PARAMETERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_TOGGLE_PALETTE, "WID_NS_TOGGLE_PALETTE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_APPLY_CHANGES, "WID_NS_APPLY_CHANGES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_RESCAN_FILES, "WID_NS_RESCAN_FILES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_RESCAN_FILES2, "WID_NS_RESCAN_FILES2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_CONTENT_DOWNLOAD, "WID_NS_CONTENT_DOWNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_CONTENT_DOWNLOAD2, "WID_NS_CONTENT_DOWNLOAD2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SHOW_REMOVE, "WID_NS_SHOW_REMOVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SHOW_APPLY, "WID_NS_SHOW_APPLY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SP_PROGRESS_BAR, "WID_SP_PROGRESS_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SP_PROGRESS_TEXT, "WID_SP_PROGRESS_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_PANEL, "WID_N_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_TITLE, "WID_N_TITLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_HEADLINE, "WID_N_HEADLINE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_CLOSEBOX, "WID_N_CLOSEBOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_DATE, "WID_N_DATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_CAPTION, "WID_N_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_INSET, "WID_N_INSET"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VIEWPORT, "WID_N_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_COMPANY_MSG, "WID_N_COMPANY_MSG"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MESSAGE, "WID_N_MESSAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MGR_FACE, "WID_N_MGR_FACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MGR_NAME, "WID_N_MGR_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_TITLE, "WID_N_VEH_TITLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_BKGND, "WID_N_VEH_BKGND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_NAME, "WID_N_VEH_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_SPR, "WID_N_VEH_SPR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_INFO, "WID_N_VEH_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_STICKYBOX, "WID_MH_STICKYBOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_BACKGROUND, "WID_MH_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_SCROLLBAR, "WID_MH_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_CLASS_LIST, "WID_BO_CLASS_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SCROLLBAR, "WID_BO_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_MATRIX, "WID_BO_OBJECT_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_SPRITE, "WID_BO_OBJECT_SPRITE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_NAME, "WID_BO_OBJECT_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_SIZE, "WID_BO_OBJECT_SIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_INFO, "WID_BO_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_MATRIX, "WID_BO_SELECT_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_IMAGE, "WID_BO_SELECT_IMAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_SCROLL, "WID_BO_SELECT_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_CAPTION, "WID_O_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_TIMETABLE_VIEW, "WID_O_TIMETABLE_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_ORDER_LIST, "WID_O_ORDER_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SCROLLBAR, "WID_O_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SKIP, "WID_O_SKIP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_DELETE, "WID_O_DELETE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_STOP_SHARING, "WID_O_STOP_SHARING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_NON_STOP, "WID_O_NON_STOP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_GOTO, "WID_O_GOTO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_FULL_LOAD, "WID_O_FULL_LOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_UNLOAD, "WID_O_UNLOAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_REFIT, "WID_O_REFIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SERVICE, "WID_O_SERVICE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_EMPTY, "WID_O_EMPTY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_REFIT_DROPDOWN, "WID_O_REFIT_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_VARIABLE, "WID_O_COND_VARIABLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_COMPARATOR, "WID_O_COND_COMPARATOR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_VALUE, "WID_O_COND_VALUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_LEFT, "WID_O_SEL_TOP_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_MIDDLE, "WID_O_SEL_TOP_MIDDLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_RIGHT, "WID_O_SEL_TOP_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_ROW_GROUNDVEHICLE, "WID_O_SEL_TOP_ROW_GROUNDVEHICLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_ROW, "WID_O_SEL_TOP_ROW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_BOTTOM_MIDDLE, "WID_O_SEL_BOTTOM_MIDDLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SHARED_ORDER_LIST, "WID_O_SHARED_ORDER_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CAPTION, "WID_OSK_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_TEXT, "WID_OSK_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CANCEL, "WID_OSK_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_OK, "WID_OSK_OK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_BACKSPACE, "WID_OSK_BACKSPACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SPECIAL, "WID_OSK_SPECIAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CAPS, "WID_OSK_CAPS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SHIFT, "WID_OSK_SHIFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SPACE, "WID_OSK_SPACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_LEFT, "WID_OSK_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_RIGHT, "WID_OSK_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_LETTERS, "WID_OSK_LETTERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_NUMBERS_FIRST, "WID_OSK_NUMBERS_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_NUMBERS_LAST, "WID_OSK_NUMBERS_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_QWERTY_FIRST, "WID_OSK_QWERTY_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_QWERTY_LAST, "WID_OSK_QWERTY_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ASDFG_FIRST, "WID_OSK_ASDFG_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ASDFG_LAST, "WID_OSK_ASDFG_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ZXCVB_FIRST, "WID_OSK_ZXCVB_FIRST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ZXCVB_LAST, "WID_OSK_ZXCVB_LAST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_CAPTION, "WID_RAT_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_NS, "WID_RAT_BUILD_NS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_X, "WID_RAT_BUILD_X"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_EW, "WID_RAT_BUILD_EW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_Y, "WID_RAT_BUILD_Y"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_AUTORAIL, "WID_RAT_AUTORAIL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_DEMOLISH, "WID_RAT_DEMOLISH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_DEPOT, "WID_RAT_BUILD_DEPOT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_WAYPOINT, "WID_RAT_BUILD_WAYPOINT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_STATION, "WID_RAT_BUILD_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_SIGNALS, "WID_RAT_BUILD_SIGNALS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_BRIDGE, "WID_RAT_BUILD_BRIDGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_TUNNEL, "WID_RAT_BUILD_TUNNEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_REMOVE, "WID_RAT_REMOVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_CONVERT_RAIL, "WID_RAT_CONVERT_RAIL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DIR_X, "WID_BRAS_PLATFORM_DIR_X"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DIR_Y, "WID_BRAS_PLATFORM_DIR_Y"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_1, "WID_BRAS_PLATFORM_NUM_1"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_2, "WID_BRAS_PLATFORM_NUM_2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_3, "WID_BRAS_PLATFORM_NUM_3"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_4, "WID_BRAS_PLATFORM_NUM_4"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_5, "WID_BRAS_PLATFORM_NUM_5"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_6, "WID_BRAS_PLATFORM_NUM_6"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_7, "WID_BRAS_PLATFORM_NUM_7"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_1, "WID_BRAS_PLATFORM_LEN_1"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_2, "WID_BRAS_PLATFORM_LEN_2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_3, "WID_BRAS_PLATFORM_LEN_3"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_4, "WID_BRAS_PLATFORM_LEN_4"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_5, "WID_BRAS_PLATFORM_LEN_5"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_6, "WID_BRAS_PLATFORM_LEN_6"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_7, "WID_BRAS_PLATFORM_LEN_7"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DRAG_N_DROP, "WID_BRAS_PLATFORM_DRAG_N_DROP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_HIGHLIGHT_OFF, "WID_BRAS_HIGHLIGHT_OFF"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_HIGHLIGHT_ON, "WID_BRAS_HIGHLIGHT_ON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_COVERAGE_TEXTS, "WID_BRAS_COVERAGE_TEXTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_MATRIX, "WID_BRAS_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_IMAGE, "WID_BRAS_IMAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_MATRIX_SCROLL, "WID_BRAS_MATRIX_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_DEFSIZE, "WID_BRAS_SHOW_NEWST_DEFSIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_ADDITIONS, "WID_BRAS_SHOW_NEWST_ADDITIONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_MATRIX, "WID_BRAS_SHOW_NEWST_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_RESIZE, "WID_BRAS_SHOW_NEWST_RESIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_TYPE, "WID_BRAS_SHOW_NEWST_TYPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_NEWST_LIST, "WID_BRAS_NEWST_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_NEWST_SCROLL, "WID_BRAS_NEWST_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_BEGIN, "WID_BRAS_PLATFORM_NUM_BEGIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_BEGIN, "WID_BRAS_PLATFORM_LEN_BEGIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_NORM, "WID_BS_SEMAPHORE_NORM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_ENTRY, "WID_BS_SEMAPHORE_ENTRY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_EXIT, "WID_BS_SEMAPHORE_EXIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_COMBO, "WID_BS_SEMAPHORE_COMBO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_PBS, "WID_BS_SEMAPHORE_PBS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_PBS_OWAY, "WID_BS_SEMAPHORE_PBS_OWAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_NORM, "WID_BS_ELECTRIC_NORM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_ENTRY, "WID_BS_ELECTRIC_ENTRY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_EXIT, "WID_BS_ELECTRIC_EXIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_COMBO, "WID_BS_ELECTRIC_COMBO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_PBS, "WID_BS_ELECTRIC_PBS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_PBS_OWAY, "WID_BS_ELECTRIC_PBS_OWAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_CONVERT, "WID_BS_CONVERT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_LABEL, "WID_BS_DRAG_SIGNALS_DENSITY_LABEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, "WID_BS_DRAG_SIGNALS_DENSITY_DECREASE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, "WID_BS_DRAG_SIGNALS_DENSITY_INCREASE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_NE, "WID_BRAD_DEPOT_NE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_SE, "WID_BRAD_DEPOT_SE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_SW, "WID_BRAD_DEPOT_SW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_NW, "WID_BRAD_DEPOT_NW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT_MATRIX, "WID_BRW_WAYPOINT_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT, "WID_BRW_WAYPOINT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_SCROLL, "WID_BRW_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_X, "WID_ROT_ROAD_X"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_Y, "WID_ROT_ROAD_Y"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_AUTOROAD, "WID_ROT_AUTOROAD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_DEMOLISH, "WID_ROT_DEMOLISH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_DEPOT, "WID_ROT_DEPOT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUS_STATION, "WID_ROT_BUS_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_TRUCK_STATION, "WID_ROT_TRUCK_STATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ONE_WAY, "WID_ROT_ONE_WAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_BRIDGE, "WID_ROT_BUILD_BRIDGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_TUNNEL, "WID_ROT_BUILD_TUNNEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_REMOVE, "WID_ROT_REMOVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_CAPTION, "WID_BROD_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_NE, "WID_BROD_DEPOT_NE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_SE, "WID_BROD_DEPOT_SE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_SW, "WID_BROD_DEPOT_SW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_NW, "WID_BROD_DEPOT_NW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_CAPTION, "WID_BROS_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_BACKGROUND, "WID_BROS_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_NE, "WID_BROS_STATION_NE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_SE, "WID_BROS_STATION_SE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_SW, "WID_BROS_STATION_SW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_NW, "WID_BROS_STATION_NW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_X, "WID_BROS_STATION_X"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_Y, "WID_BROS_STATION_Y"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_LT_OFF, "WID_BROS_LT_OFF"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_LT_ON, "WID_BROS_LT_ON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_INFO, "WID_BROS_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BACKGROUND, "WID_GO_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_CURRENCY_DROPDOWN, "WID_GO_CURRENCY_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_DISTANCE_DROPDOWN, "WID_GO_DISTANCE_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_ROADSIDE_DROPDOWN, "WID_GO_ROADSIDE_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_TOWNNAME_DROPDOWN, "WID_GO_TOWNNAME_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_AUTOSAVE_DROPDOWN, "WID_GO_AUTOSAVE_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_LANG_DROPDOWN, "WID_GO_LANG_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_RESOLUTION_DROPDOWN, "WID_GO_RESOLUTION_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_FULLSCREEN_BUTTON, "WID_GO_FULLSCREEN_BUTTON"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_SCREENSHOT_DROPDOWN, "WID_GO_SCREENSHOT_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_DROPDOWN, "WID_GO_BASE_GRF_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_STATUS, "WID_GO_BASE_GRF_STATUS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_TEXTFILE, "WID_GO_BASE_GRF_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_DESCRIPTION, "WID_GO_BASE_GRF_DESCRIPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_DROPDOWN, "WID_GO_BASE_SFX_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_TEXTFILE, "WID_GO_BASE_SFX_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_DESCRIPTION, "WID_GO_BASE_SFX_DESCRIPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_DROPDOWN, "WID_GO_BASE_MUSIC_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_STATUS, "WID_GO_BASE_MUSIC_STATUS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_TEXTFILE, "WID_GO_BASE_MUSIC_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_DESCRIPTION, "WID_GO_BASE_MUSIC_DESCRIPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_FILTER, "WID_GS_FILTER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_OPTIONSPANEL, "WID_GS_OPTIONSPANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_SCROLLBAR, "WID_GS_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_HELP_TEXT, "WID_GS_HELP_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_EXPAND_ALL, "WID_GS_EXPAND_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_COLLAPSE_ALL, "WID_GS_COLLAPSE_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_CATEGORY, "WID_GS_RESTRICT_CATEGORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_TYPE, "WID_GS_RESTRICT_TYPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_DROPDOWN, "WID_GS_RESTRICT_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_TYPE_DROPDOWN, "WID_GS_TYPE_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE_DOWN, "WID_CC_RATE_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE_UP, "WID_CC_RATE_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE, "WID_CC_RATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SEPARATOR_EDIT, "WID_CC_SEPARATOR_EDIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SEPARATOR, "WID_CC_SEPARATOR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREFIX_EDIT, "WID_CC_PREFIX_EDIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREFIX, "WID_CC_PREFIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SUFFIX_EDIT, "WID_CC_SUFFIX_EDIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SUFFIX, "WID_CC_SUFFIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR_DOWN, "WID_CC_YEAR_DOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR_UP, "WID_CC_YEAR_UP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR, "WID_CC_YEAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREVIEW, "WID_CC_PREVIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_CAPTION, "WID_SIL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_LIST, "WID_SIL_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_SCROLLBAR, "WID_SIL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_TEXT, "WID_SIL_FILTER_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_MATCH_CASE_BTN, "WID_SIL_FILTER_MATCH_CASE_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_ENTER_BTN, "WID_SIL_FILTER_ENTER_BTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_CAPTION, "WID_QES_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_TEXT, "WID_QES_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_OK, "WID_QES_OK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_CANCEL, "WID_QES_CANCEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_DELETE, "WID_QES_DELETE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_PREVIOUS, "WID_QES_PREVIOUS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_NEXT, "WID_QES_NEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CAPTION, "WID_SM_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_MAP_BORDER, "WID_SM_MAP_BORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_MAP, "WID_SM_MAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_LEGEND, "WID_SM_LEGEND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_BLANK, "WID_SM_BLANK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ZOOM_IN, "WID_SM_ZOOM_IN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ZOOM_OUT, "WID_SM_ZOOM_OUT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CONTOUR, "WID_SM_CONTOUR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_VEHICLES, "WID_SM_VEHICLES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_INDUSTRIES, "WID_SM_INDUSTRIES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_LINKSTATS, "WID_SM_LINKSTATS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ROUTES, "WID_SM_ROUTES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_VEGETATION, "WID_SM_VEGETATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_OWNERS, "WID_SM_OWNERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CENTERMAP, "WID_SM_CENTERMAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_TOGGLETOWNNAME, "WID_SM_TOGGLETOWNNAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_SELECT_BUTTONS, "WID_SM_SELECT_BUTTONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ENABLE_ALL, "WID_SM_ENABLE_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_DISABLE_ALL, "WID_SM_DISABLE_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_SHOW_HEIGHT, "WID_SM_SHOW_HEIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_CAPTION, "WID_SV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SORT_ORDER, "WID_SV_SORT_ORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SORT_BY, "WID_SV_SORT_BY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_GROUP, "WID_SV_GROUP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_GROUP_BY, "WID_SV_GROUP_BY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_WAITING, "WID_SV_WAITING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SCROLLBAR, "WID_SV_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ACCEPT_RATING_LIST, "WID_SV_ACCEPT_RATING_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_LOCATION, "WID_SV_LOCATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ACCEPTS_RATINGS, "WID_SV_ACCEPTS_RATINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_RENAME, "WID_SV_RENAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_CLOSE_AIRPORT, "WID_SV_CLOSE_AIRPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_TRAINS, "WID_SV_TRAINS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ROADVEHS, "WID_SV_ROADVEHS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SHIPS, "WID_SV_SHIPS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_PLANES, "WID_SV_PLANES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CAPTION, "WID_STL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_LIST, "WID_STL_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SCROLLBAR, "WID_STL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_TRAIN, "WID_STL_TRAIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_TRUCK, "WID_STL_TRUCK"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_BUS, "WID_STL_BUS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_AIRPLANE, "WID_STL_AIRPLANE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SHIP, "WID_STL_SHIP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_FACILALL, "WID_STL_FACILALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_NOCARGOWAITING, "WID_STL_NOCARGOWAITING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CARGOALL, "WID_STL_CARGOALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SORTBY, "WID_STL_SORTBY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SORTDROPBTN, "WID_STL_SORTDROPBTN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CARGOSTART, "WID_STL_CARGOSTART"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_CAPTION, "WID_JS_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_PANEL, "WID_JS_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_SCROLLBAR, "WID_JS_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_LEFT, "WID_S_LEFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_MIDDLE, "WID_S_MIDDLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_RIGHT, "WID_S_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_CAPTION, "WID_SB_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_SEL_PAGE, "WID_SB_SEL_PAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_PAGE_PANEL, "WID_SB_PAGE_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_SCROLLBAR, "WID_SB_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_PREV_PAGE, "WID_SB_PREV_PAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_NEXT_PAGE, "WID_SB_NEXT_PAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SUL_PANEL, "WID_SUL_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SUL_SCROLLBAR, "WID_SUL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SHOW_PLACE_OBJECT, "WID_TT_SHOW_PLACE_OBJECT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUTTONS_START, "WID_TT_BUTTONS_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LOWER_LAND, "WID_TT_LOWER_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_RAISE_LAND, "WID_TT_RAISE_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LEVEL_LAND, "WID_TT_LEVEL_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_DEMOLISH, "WID_TT_DEMOLISH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUY_LAND, "WID_TT_BUY_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLANT_TREES, "WID_TT_PLANT_TREES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLACE_SIGN, "WID_TT_PLACE_SIGN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLACE_OBJECT, "WID_TT_PLACE_OBJECT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_SHOW_PLACE_DESERT, "WID_ETT_SHOW_PLACE_DESERT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_START, "WID_ETT_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DOTS, "WID_ETT_DOTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_BUTTONS_START, "WID_ETT_BUTTONS_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DEMOLISH, "WID_ETT_DEMOLISH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_LOWER_LAND, "WID_ETT_LOWER_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_RAISE_LAND, "WID_ETT_RAISE_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_LEVEL_LAND, "WID_ETT_LEVEL_LAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_ROCKS, "WID_ETT_PLACE_ROCKS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_DESERT, "WID_ETT_PLACE_DESERT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_OBJECT, "WID_ETT_PLACE_OBJECT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_BUTTONS_END, "WID_ETT_BUTTONS_END"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_INCREASE_SIZE, "WID_ETT_INCREASE_SIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DECREASE_SIZE, "WID_ETT_DECREASE_SIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_NEW_SCENARIO, "WID_ETT_NEW_SCENARIO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_RESET_LANDSCAPE, "WID_ETT_RESET_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CAPTION, "WID_VT_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ORDER_VIEW, "WID_VT_ORDER_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_TIMETABLE_PANEL, "WID_VT_TIMETABLE_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ARRIVAL_DEPARTURE_PANEL, "WID_VT_ARRIVAL_DEPARTURE_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SCROLLBAR, "WID_VT_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SUMMARY_PANEL, "WID_VT_SUMMARY_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_START_DATE, "WID_VT_START_DATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CHANGE_TIME, "WID_VT_CHANGE_TIME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CLEAR_TIME, "WID_VT_CLEAR_TIME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_RESET_LATENESS, "WID_VT_RESET_LATENESS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_AUTOFILL, "WID_VT_AUTOFILL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_EXPECTED, "WID_VT_EXPECTED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SHARED_ORDER_LIST, "WID_VT_SHARED_ORDER_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ARRIVAL_DEPARTURE_SELECTION, "WID_VT_ARRIVAL_DEPARTURE_SELECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_EXPECTED_SELECTION, "WID_VT_EXPECTED_SELECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CHANGE_SPEED, "WID_VT_CHANGE_SPEED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CLEAR_SPEED, "WID_VT_CLEAR_SPEED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_PAUSE, "WID_TN_PAUSE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_FAST_FORWARD, "WID_TN_FAST_FORWARD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SETTINGS, "WID_TN_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SAVE, "WID_TN_SAVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SMALL_MAP, "WID_TN_SMALL_MAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_TOWNS, "WID_TN_TOWNS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SUBSIDIES, "WID_TN_SUBSIDIES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_STATIONS, "WID_TN_STATIONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_FINANCES, "WID_TN_FINANCES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_COMPANIES, "WID_TN_COMPANIES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_STORY, "WID_TN_STORY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_GOAL, "WID_TN_GOAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_GRAPHS, "WID_TN_GRAPHS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_LEAGUE, "WID_TN_LEAGUE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_INDUSTRIES, "WID_TN_INDUSTRIES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_VEHICLE_START, "WID_TN_VEHICLE_START"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_TRAINS, "WID_TN_TRAINS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ROADVEHS, "WID_TN_ROADVEHS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SHIPS, "WID_TN_SHIPS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_AIRCRAFTS, "WID_TN_AIRCRAFTS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ZOOM_IN, "WID_TN_ZOOM_IN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ZOOM_OUT, "WID_TN_ZOOM_OUT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_RAILS, "WID_TN_RAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ROADS, "WID_TN_ROADS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_WATER, "WID_TN_WATER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_AIR, "WID_TN_AIR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_LANDSCAPE, "WID_TN_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_MUSIC_SOUND, "WID_TN_MUSIC_SOUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_MESSAGES, "WID_TN_MESSAGES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_HELP, "WID_TN_HELP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SWITCH_BAR, "WID_TN_SWITCH_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_END, "WID_TN_END"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_PAUSE, "WID_TE_PAUSE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_FAST_FORWARD, "WID_TE_FAST_FORWARD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SETTINGS, "WID_TE_SETTINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SAVE, "WID_TE_SAVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SPACER, "WID_TE_SPACER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE, "WID_TE_DATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_BACKWARD, "WID_TE_DATE_BACKWARD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_FORWARD, "WID_TE_DATE_FORWARD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SMALL_MAP, "WID_TE_SMALL_MAP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ZOOM_IN, "WID_TE_ZOOM_IN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ZOOM_OUT, "WID_TE_ZOOM_OUT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_LAND_GENERATE, "WID_TE_LAND_GENERATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TOWN_GENERATE, "WID_TE_TOWN_GENERATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_INDUSTRY, "WID_TE_INDUSTRY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ROADS, "WID_TE_ROADS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_WATER, "WID_TE_WATER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TREES, "WID_TE_TREES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SIGNS, "WID_TE_SIGNS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_PANEL, "WID_TE_DATE_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_MUSIC_SOUND, "WID_TE_MUSIC_SOUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_HELP, "WID_TE_HELP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SWITCH_BAR, "WID_TE_SWITCH_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_X, "WID_TT_X"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_DELETE, "WID_TT_DELETE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SHIFT, "WID_TT_SHIFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_CTRL, "WID_TT_CTRL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_MOVE, "WID_TT_MOVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_ORDER, "WID_TD_SORT_ORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_CRITERIA, "WID_TD_SORT_CRITERIA"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_LIST, "WID_TD_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SCROLLBAR, "WID_TD_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_WORLD_POPULATION, "WID_TD_WORLD_POPULATION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_CAPTION, "WID_TA_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_RATING_INFO, "WID_TA_RATING_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_COMMAND_LIST, "WID_TA_COMMAND_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_SCROLLBAR, "WID_TA_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_ACTION_INFO, "WID_TA_ACTION_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_EXECUTE, "WID_TA_EXECUTE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CAPTION, "WID_TV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_VIEWPORT, "WID_TV_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_INFO, "WID_TV_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CENTER_VIEW, "WID_TV_CENTER_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_SHOW_AUTHORITY, "WID_TV_SHOW_AUTHORITY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CHANGE_NAME, "WID_TV_CHANGE_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_EXPAND, "WID_TV_EXPAND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_DELETE, "WID_TV_DELETE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_NEW_TOWN, "WID_TF_NEW_TOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_RANDOM_TOWN, "WID_TF_RANDOM_TOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_MANY_RANDOM_TOWNS, "WID_TF_MANY_RANDOM_TOWNS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_TOWN_NAME_EDITBOX, "WID_TF_TOWN_NAME_EDITBOX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_TOWN_NAME_RANDOM, "WID_TF_TOWN_NAME_RANDOM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_SMALL, "WID_TF_SIZE_SMALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_MEDIUM, "WID_TF_SIZE_MEDIUM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_LARGE, "WID_TF_SIZE_LARGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_RANDOM, "WID_TF_SIZE_RANDOM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_CITY, "WID_TF_CITY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_ORIGINAL, "WID_TF_LAYOUT_ORIGINAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_BETTER, "WID_TF_LAYOUT_BETTER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_GRID2, "WID_TF_LAYOUT_GRID2"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_GRID3, "WID_TF_LAYOUT_GRID3"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_RANDOM, "WID_TF_LAYOUT_RANDOM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BEGIN, "WID_TT_BEGIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SIGNS, "WID_TT_SIGNS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_TREES, "WID_TT_TREES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_HOUSES, "WID_TT_HOUSES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_INDUSTRIES, "WID_TT_INDUSTRIES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUILDINGS, "WID_TT_BUILDINGS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BRIDGES, "WID_TT_BRIDGES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_STRUCTURES, "WID_TT_STRUCTURES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_CATENARY, "WID_TT_CATENARY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LOADING, "WID_TT_LOADING"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_END, "WID_TT_END"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUTTONS, "WID_TT_BUTTONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_11, "WID_BT_TYPE_11"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_12, "WID_BT_TYPE_12"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_13, "WID_BT_TYPE_13"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_14, "WID_BT_TYPE_14"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_21, "WID_BT_TYPE_21"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_22, "WID_BT_TYPE_22"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_23, "WID_BT_TYPE_23"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_24, "WID_BT_TYPE_24"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_31, "WID_BT_TYPE_31"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_32, "WID_BT_TYPE_32"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_33, "WID_BT_TYPE_33"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_34, "WID_BT_TYPE_34"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_RANDOM, "WID_BT_TYPE_RANDOM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_MANY_RANDOM, "WID_BT_MANY_RANDOM"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CAPTION, "WID_VV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_VIEWPORT, "WID_VV_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_START_STOP, "WID_VV_START_STOP"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CENTER_MAIN_VIEW, "WID_VV_CENTER_MAIN_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_GOTO_DEPOT, "WID_VV_GOTO_DEPOT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_REFIT, "WID_VV_REFIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SHOW_ORDERS, "WID_VV_SHOW_ORDERS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SHOW_DETAILS, "WID_VV_SHOW_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CLONE, "WID_VV_CLONE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SELECT_DEPOT_CLONE, "WID_VV_SELECT_DEPOT_CLONE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SELECT_REFIT_TURN, "WID_VV_SELECT_REFIT_TURN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_TURN_AROUND, "WID_VV_TURN_AROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_FORCE_PROCEED, "WID_VV_FORCE_PROCEED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_CAPTION, "WID_VR_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_VEHICLE_PANEL_DISPLAY, "WID_VR_VEHICLE_PANEL_DISPLAY"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SHOW_HSCROLLBAR, "WID_VR_SHOW_HSCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_HSCROLLBAR, "WID_VR_HSCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SELECT_HEADER, "WID_VR_SELECT_HEADER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_MATRIX, "WID_VR_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SCROLLBAR, "WID_VR_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_INFO, "WID_VR_INFO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_REFIT, "WID_VR_REFIT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_CAPTION, "WID_VD_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_RENAME_VEHICLE, "WID_VD_RENAME_VEHICLE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_TOP_DETAILS, "WID_VD_TOP_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_INCREASE_SERVICING_INTERVAL, "WID_VD_INCREASE_SERVICING_INTERVAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DECREASE_SERVICING_INTERVAL, "WID_VD_DECREASE_SERVICING_INTERVAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SERVICE_INTERVAL_DROPDOWN, "WID_VD_SERVICE_INTERVAL_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SERVICING_INTERVAL, "WID_VD_SERVICING_INTERVAL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_MIDDLE_DETAILS, "WID_VD_MIDDLE_DETAILS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_MATRIX, "WID_VD_MATRIX"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SCROLLBAR, "WID_VD_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_CARGO_CARRIED, "WID_VD_DETAILS_CARGO_CARRIED"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_TRAIN_VEHICLES, "WID_VD_DETAILS_TRAIN_VEHICLES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_CAPACITY_OF_EACH, "WID_VD_DETAILS_CAPACITY_OF_EACH"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_TOTAL_CARGO, "WID_VD_DETAILS_TOTAL_CARGO"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_CAPTION, "WID_VL_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SORT_ORDER, "WID_VL_SORT_ORDER"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SORT_BY_PULLDOWN, "WID_VL_SORT_BY_PULLDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_LIST, "WID_VL_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SCROLLBAR, "WID_VL_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_HIDE_BUTTONS, "WID_VL_HIDE_BUTTONS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_AVAILABLE_VEHICLES, "WID_VL_AVAILABLE_VEHICLES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_MANAGE_VEHICLES_DROPDOWN, "WID_VL_MANAGE_VEHICLES_DROPDOWN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_STOP_ALL, "WID_VL_STOP_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_START_ALL, "WID_VL_START_ALL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_CAPTION, "WID_EV_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_VIEWPORT, "WID_EV_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_ZOOM_IN, "WID_EV_ZOOM_IN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_ZOOM_OUT, "WID_EV_ZOOM_OUT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_MAIN_TO_VIEW, "WID_EV_MAIN_TO_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_VIEW_TO_MAIN, "WID_EV_VIEW_TO_MAIN"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_CAPTION, "WID_W_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_VIEWPORT, "WID_W_VIEWPORT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_CENTER_VIEW, "WID_W_CENTER_VIEW"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_RENAME, "WID_W_RENAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_SHOW_VEHICLES, "WID_W_SHOW_VEHICLES"); + + SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::Close, "Close", 3, ".ii"); + SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::IsOpen, "IsOpen", 3, ".ii"); + SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::Highlight, "Highlight", 5, ".iiii"); + + SQGSWindow.PostRegister(engine); +} diff --git a/src/window.cpp b/src/window.cpp index b9a9651491..cad3e3ca31 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2841,9 +2841,18 @@ static void MouseLoop(MouseClick click, int mousewheel) Window *w = FindWindowFromPt(x, y); if (w == NULL) return; ViewPort *vp = IsPtInWindowViewport(w, x, y); + bool confirm = (_settings_client.gui.touchscreen_mode == TSC_CONFIRM); - HandlePlacePresize(); - UpdateTileSelection(); + /* Don't allow any action in a viewport if either in menu or when having a modal progress window */ + if (vp != NULL && (_game_mode == GM_MENU || HasModalProgress())) return; + + /* On confirm mode do not update tile selection unless we are clicking on a viewport. */ + if (!confirm || (vp != NULL && _left_button_down && !_move_pressed)) { + HandlePlacePresize(); + UpdateTileSelection(); + } else { + //if presize, show tooltip if needed + } if (VpHandlePlaceSizingDrag() == ES_HANDLED) return; if (HandleMouseDragDrop() == ES_HANDLED) return; @@ -2860,9 +2869,6 @@ static void MouseLoop(MouseClick click, int mousewheel) if (click != MC_NONE && click != MC_HOVER && !MaybeBringWindowToFront(w)) return; - /* Don't allow any action in a viewport if either in menu or when having a modal progress window */ - if (vp != NULL && (_game_mode == GM_MENU || HasModalProgress())) return; - if (mousewheel != 0) { /* Send mousewheel event to window */ w->OnMouseWheel(mousewheel); diff --git a/src/window.cpp.orig b/src/window.cpp.orig new file mode 100644 index 0000000000..b9a9651491 --- /dev/null +++ b/src/window.cpp.orig @@ -0,0 +1,3527 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file window.cpp Windowing system, widgets and events */ + +#include "stdafx.h" +#include +#include "company_func.h" +#include "gfx_func.h" +#include "console_func.h" +#include "console_gui.h" +#include "viewport_func.h" +#include "progress.h" +#include "blitter/factory.hpp" +#include "zoom_func.h" +#include "vehicle_base.h" +#include "window_func.h" +#include "tilehighlight_func.h" +#include "network/network.h" +#include "querystring_gui.h" +#include "widgets/dropdown_func.h" +#include "strings_func.h" +#include "settings_type.h" +#include "settings_func.h" +#include "ini_type.h" +#include "newgrf_debug.h" +#include "hotkeys.h" +#include "toolbar_gui.h" +#include "statusbar_gui.h" +#include "error.h" +#include "game/game.hpp" +#include "video/video_driver.hpp" +#include "settings_gui.h" +#include "fontcache.h" +#include "error.h" +#include "station_base.h" +#include "waypoint_base.h" +#include "command_func.h" + +#include "table/strings.h" + +/** Values for _settings_client.gui.auto_scrolling */ +enum ViewportAutoscrolling { + VA_DISABLED, //!< Do not autoscroll when mouse is at edge of viewport. + VA_MAIN_VIEWPORT_FULLSCREEN, //!< Scroll main viewport at edge when using fullscreen. + VA_MAIN_VIEWPORT, //!< Scroll main viewport at edge. + VA_EVERY_VIEWPORT, //!< Scroll all viewports at their edges. +}; + +static Point _drag_delta; ///< delta between mouse cursor and upper left corner of dragged window +static Window *_mouseover_last_w = NULL; ///< Window of the last #MOUSEOVER event. +static Window *_last_scroll_window = NULL; ///< Window of the last scroll event. + +/** List of windows opened at the screen sorted from the front. */ +Window *_z_front_window = NULL; +/** List of windows opened at the screen sorted from the back. */ +Window *_z_back_window = NULL; + +/** If false, highlight is white, otherwise the by the widget defined colour. */ +bool _window_highlight_colour = false; + +/* + * Window that currently has focus. - The main purpose is to generate + * #FocusLost events, not to give next window in z-order focus when a + * window is closed. + */ +Window *_focused_window; + +Point _cursorpos_drag_start; + +int _scrollbar_start_pos; +int _scrollbar_size; +byte _scroller_click_timeout = 0; + +bool _scrolling_viewport; ///< A viewport is being scrolled with the mouse. +bool _mouse_hovering; ///< The mouse is hovering over the same point. + +SpecialMouseMode _special_mouse_mode; ///< Mode of the mouse. + +/** + * List of all WindowDescs. + * This is a pointer to ensure initialisation order with the various static WindowDesc instances. + */ +static SmallVector *_window_descs = NULL; + +/** Config file to store WindowDesc */ +char *_windows_file; + +/** Window description constructor. */ +WindowDesc::WindowDesc(WindowPosition def_pos, const char *ini_key, int16 def_width, int16 def_height, + WindowClass window_class, WindowClass parent_class, uint32 flags, + const NWidgetPart *nwid_parts, int16 nwid_length, HotkeyList *hotkeys) : + default_pos(def_pos), + default_width(def_width), + default_height(def_height), + cls(window_class), + parent_cls(parent_class), + ini_key(ini_key), + flags(flags), + nwid_parts(nwid_parts), + nwid_length(nwid_length), + hotkeys(hotkeys), + pref_sticky(false), + pref_width(0), + pref_height(0) +{ + if (_window_descs == NULL) _window_descs = new SmallVector(); + *_window_descs->Append() = this; +} + +WindowDesc::~WindowDesc() +{ + _window_descs->Erase(_window_descs->Find(this)); +} + +/** + * Load all WindowDesc settings from _windows_file. + */ +void WindowDesc::LoadFromConfig() +{ + IniFile *ini = new IniFile(); + ini->LoadFromDisk(_windows_file, BASE_DIR); + for (WindowDesc **it = _window_descs->Begin(); it != _window_descs->End(); ++it) { + if ((*it)->ini_key == NULL) continue; + IniLoadWindowSettings(ini, (*it)->ini_key, *it); + } + delete ini; +} + +/** + * Sort WindowDesc by ini_key. + */ +static int CDECL DescSorter(WindowDesc * const *a, WindowDesc * const *b) +{ + if ((*a)->ini_key != NULL && (*b)->ini_key != NULL) return strcmp((*a)->ini_key, (*b)->ini_key); + return ((*b)->ini_key != NULL ? 1 : 0) - ((*a)->ini_key != NULL ? 1 : 0); +} + +/** + * Save all WindowDesc settings to _windows_file. + */ +void WindowDesc::SaveToConfig() +{ + /* Sort the stuff to get a nice ini file on first write */ + QSortT(_window_descs->Begin(), _window_descs->Length(), DescSorter); + + IniFile *ini = new IniFile(); + ini->LoadFromDisk(_windows_file, BASE_DIR); + for (WindowDesc **it = _window_descs->Begin(); it != _window_descs->End(); ++it) { + if ((*it)->ini_key == NULL) continue; + IniSaveWindowSettings(ini, (*it)->ini_key, *it); + } + ini->SaveToDisk(_windows_file); + delete ini; +} + +/** + * Read default values from WindowDesc configuration an apply them to the window. + */ +void Window::ApplyDefaults() +{ + if (this->nested_root != NULL && this->nested_root->GetWidgetOfType(WWT_STICKYBOX) != NULL) { + if (this->window_desc->pref_sticky) this->flags |= WF_STICKY; + } else { + /* There is no stickybox; clear the preference in case someone tried to be funny */ + this->window_desc->pref_sticky = false; + } +} + +/** + * Compute the row of a widget that a user clicked in. + * @param clickpos Vertical position of the mouse click. + * @param widget Widget number of the widget clicked in. + * @param padding Amount of empty space between the widget edge and the top of the first row. + * @param line_height Height of a single row. A negative value means using the vertical resize step of the widget. + * @return Row number clicked at. If clicked at a wrong position, #INT_MAX is returned. + * @note The widget does not know where a list printed at the widget ends, so below a list is not a wrong position. + */ +int Window::GetRowFromWidget(int clickpos, int widget, int padding, int line_height) const +{ + const NWidgetBase *wid = this->GetWidget(widget); + if (line_height < 0) line_height = wid->resize_y; + if (clickpos < (int)wid->pos_y + padding) return INT_MAX; + return (clickpos - (int)wid->pos_y - padding) / line_height; +} + +/** + * Disable the highlighted status of all widgets. + */ +void Window::DisableAllWidgetHighlight() +{ + for (uint i = 0; i < this->nested_array_size; i++) { + NWidgetBase *nwid = this->GetWidget(i); + if (nwid == NULL) continue; + + if (nwid->IsHighlighted()) { + nwid->SetHighlighted(TC_INVALID); + this->SetWidgetDirty(i); + } + } + + CLRBITS(this->flags, WF_HIGHLIGHTED); +} + +/** + * Sets the highlighted status of a widget. + * @param widget_index index of this widget in the window + * @param highlighted_colour Colour of highlight, or TC_INVALID to disable. + */ +void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour) +{ + assert(widget_index < this->nested_array_size); + + NWidgetBase *nwid = this->GetWidget(widget_index); + if (nwid == NULL) return; + + nwid->SetHighlighted(highlighted_colour); + this->SetWidgetDirty(widget_index); + + if (highlighted_colour != TC_INVALID) { + /* If we set a highlight, the window has a highlight */ + this->flags |= WF_HIGHLIGHTED; + } else { + /* If we disable a highlight, check all widgets if anyone still has a highlight */ + bool valid = false; + for (uint i = 0; i < this->nested_array_size; i++) { + NWidgetBase *nwid = this->GetWidget(i); + if (nwid == NULL) continue; + if (!nwid->IsHighlighted()) continue; + + valid = true; + } + /* If nobody has a highlight, disable the flag on the window */ + if (!valid) CLRBITS(this->flags, WF_HIGHLIGHTED); + } +} + +/** + * Gets the highlighted status of a widget. + * @param widget_index index of this widget in the window + * @return status of the widget ie: highlighted = true, not highlighted = false + */ +bool Window::IsWidgetHighlighted(byte widget_index) const +{ + assert(widget_index < this->nested_array_size); + + const NWidgetBase *nwid = this->GetWidget(widget_index); + if (nwid == NULL) return false; + + return nwid->IsHighlighted(); +} + +/** + * A dropdown window associated to this window has been closed. + * @param pt the point inside the window the mouse resides on after closure. + * @param widget the widget (button) that the dropdown is associated with. + * @param index the element in the dropdown that is selected. + * @param instant_close whether the dropdown was configured to close on mouse up. + */ +void Window::OnDropdownClose(Point pt, int widget, int index, bool instant_close) +{ + if (widget < 0) return; + + if (instant_close) { + /* Send event for selected option if we're still + * on the parent button of the dropdown (behaviour of the dropdowns in the main toolbar). */ + if (GetWidgetFromPos(this, pt.x, pt.y) == widget) { + this->OnDropdownSelect(widget, index); + } + } + + /* Raise the dropdown button */ + NWidgetCore *nwi2 = this->GetWidget(widget); + if ((nwi2->type & WWT_MASK) == NWID_BUTTON_DROPDOWN) { + nwi2->disp_flags &= ~ND_DROPDOWN_ACTIVE; + } else { + this->RaiseWidget(widget); + } + this->SetWidgetDirty(widget); +} + +/** + * Return the Scrollbar to a widget index. + * @param widnum Scrollbar widget index + * @return Scrollbar to the widget + */ +const Scrollbar *Window::GetScrollbar(uint widnum) const +{ + return this->GetWidget(widnum); +} + +/** + * Return the Scrollbar to a widget index. + * @param widnum Scrollbar widget index + * @return Scrollbar to the widget + */ +Scrollbar *Window::GetScrollbar(uint widnum) +{ + return this->GetWidget(widnum); +} + +/** + * Return the querystring associated to a editbox. + * @param widnum Editbox widget index + * @return QueryString or NULL. + */ +const QueryString *Window::GetQueryString(uint widnum) const +{ + const SmallMap::Pair *query = this->querystrings.Find(widnum); + return query != this->querystrings.End() ? query->second : NULL; +} + +/** + * Return the querystring associated to a editbox. + * @param widnum Editbox widget index + * @return QueryString or NULL. + */ +QueryString *Window::GetQueryString(uint widnum) +{ + SmallMap::Pair *query = this->querystrings.Find(widnum); + return query != this->querystrings.End() ? query->second : NULL; +} + +/** + * Get the current input text if an edit box has the focus. + * @return The currently focused input text or NULL if no input focused. + */ +/* virtual */ const char *Window::GetFocusedText() const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetText(); + } + + return NULL; +} + +/** + * Get the string at the caret if an edit box has the focus. + * @return The text at the caret or NULL if no edit box is focused. + */ +/* virtual */ const char *Window::GetCaret() const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetCaret(); + } + + return NULL; +} + +/** + * Get the range of the currently marked input text. + * @param[out] length Length of the marked text. + * @return Pointer to the start of the marked text or NULL if no text is marked. + */ +/* virtual */ const char *Window::GetMarkedText(size_t *length) const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetMarkedText(length); + } + + return NULL; +} + +/** + * Get the current caret position if an edit box has the focus. + * @return Top-left location of the caret, relative to the window. + */ +/* virtual */ Point Window::GetCaretPosition() const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetCaretPosition(this, this->nested_focus->index); + } + + Point pt = {0, 0}; + return pt; +} + +/** + * Get the bounding rectangle for a text range if an edit box has the focus. + * @param from Start of the string range. + * @param to End of the string range. + * @return Rectangle encompassing the string range, relative to the window. + */ +/* virtual */ Rect Window::GetTextBoundingRect(const char *from, const char *to) const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetBoundingRect(this, this->nested_focus->index, from, to); + } + + Rect r = {0, 0, 0, 0}; + return r; +} + +/** + * Get the character that is rendered at a position by the focused edit box. + * @param pt The position to test. + * @return Pointer to the character at the position or NULL if no character is at the position. + */ +/* virtual */ const char *Window::GetTextCharacterAtPosition(const Point &pt) const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetCharAtPosition(this, this->nested_focus->index, pt); + } + + return NULL; +} + +/** + * Set the window that has the focus + * @param w The window to set the focus on + */ +void SetFocusedWindow(Window *w) +{ + if (_focused_window == w) return; + + /* Invalidate focused widget */ + if (_focused_window != NULL) { + if (_focused_window->nested_focus != NULL) _focused_window->nested_focus->SetDirty(_focused_window); + } + + /* Remember which window was previously focused */ + Window *old_focused = _focused_window; + _focused_window = w; + + /* So we can inform it that it lost focus */ + if (old_focused != NULL) old_focused->OnFocusLost(); + if (_focused_window != NULL) _focused_window->OnFocus(); +} + +/** + * Check if an edit box is in global focus. That is if focused window + * has a edit box as focused widget, or if a console is focused. + * @return returns true if an edit box is in global focus or if the focused window is a console, else false + */ +bool EditBoxInGlobalFocus() +{ + if (_focused_window == NULL) return false; + + /* The console does not have an edit box so a special case is needed. */ + if (_focused_window->window_class == WC_CONSOLE) return true; + + return _focused_window->nested_focus != NULL && _focused_window->nested_focus->type == WWT_EDITBOX; +} + +/** + * Makes no widget on this window have focus. The function however doesn't change which window has focus. + */ +void Window::UnfocusFocusedWidget() +{ + if (this->nested_focus != NULL) { + if (this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus(); + + /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ + this->nested_focus->SetDirty(this); + this->nested_focus = NULL; + } +} + +/** + * Set focus within this window to the given widget. The function however doesn't change which window has focus. + * @param widget_index Index of the widget in the window to set the focus to. + * @return Focus has changed. + */ +bool Window::SetFocusedWidget(int widget_index) +{ + /* Do nothing if widget_index is already focused, or if it wasn't a valid widget. */ + if ((uint)widget_index >= this->nested_array_size) return false; + + assert(this->nested_array[widget_index] != NULL); // Setting focus to a non-existing widget is a bad idea. + if (this->nested_focus != NULL) { + if (this->GetWidget(widget_index) == this->nested_focus) return false; + + /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ + this->nested_focus->SetDirty(this); + if (this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus(); + } + this->nested_focus = this->GetWidget(widget_index); + return true; +} + +/** + * Called when window looses focus + */ +void Window::OnFocusLost() +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus(); +} + +/** + * Sets the enabled/disabled status of a list of widgets. + * By default, widgets are enabled. + * On certain conditions, they have to be disabled. + * @param disab_stat status to use ie: disabled = true, enabled = false + * @param widgets list of widgets ended by WIDGET_LIST_END + */ +void CDECL Window::SetWidgetsDisabledState(bool disab_stat, int widgets, ...) +{ + va_list wdg_list; + + va_start(wdg_list, widgets); + + while (widgets != WIDGET_LIST_END) { + SetWidgetDisabledState(widgets, disab_stat); + widgets = va_arg(wdg_list, int); + } + + va_end(wdg_list); +} + +/** + * Sets the lowered/raised status of a list of widgets. + * @param lowered_stat status to use ie: lowered = true, raised = false + * @param widgets list of widgets ended by WIDGET_LIST_END + */ +void CDECL Window::SetWidgetsLoweredState(bool lowered_stat, int widgets, ...) +{ + va_list wdg_list; + + va_start(wdg_list, widgets); + + while (widgets != WIDGET_LIST_END) { + SetWidgetLoweredState(widgets, lowered_stat); + widgets = va_arg(wdg_list, int); + } + + va_end(wdg_list); +} + +/** + * Raise the buttons of the window. + * @param autoraise Raise only the push buttons of the window. + */ +void Window::RaiseButtons(bool autoraise) +{ + for (uint i = 0; i < this->nested_array_size; i++) { + if (this->nested_array[i] == NULL) continue; + WidgetType type = this->nested_array[i]->type; + if (((type & ~WWB_PUSHBUTTON) < WWT_LAST || type == NWID_PUSHBUTTON_DROPDOWN) && + (!autoraise || (type & WWB_PUSHBUTTON) || type == WWT_EDITBOX) && this->IsWidgetLowered(i)) { + this->RaiseWidget(i); + this->SetWidgetDirty(i); + } + } + + /* Special widgets without widget index */ + NWidgetCore *wid = this->nested_root != NULL ? (NWidgetCore*)this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX) : NULL; + if (wid != NULL) { + wid->SetLowered(false); + wid->SetDirty(this); + } +} + +/** + * Invalidate a widget, i.e. mark it as being changed and in need of redraw. + * @param widget_index the widget to redraw. + */ +void Window::SetWidgetDirty(byte widget_index) const +{ + /* Sometimes this function is called before the window is even fully initialized */ + if (this->nested_array == NULL) return; + + this->nested_array[widget_index]->SetDirty(this); +} + +/** + * A hotkey has been pressed. + * @param hotkey Hotkey index, by default a widget index of a button or editbox. + * @return #ES_HANDLED if the key press has been handled, and the hotkey is not unavailable for some reason. + */ +EventState Window::OnHotkey(int hotkey) +{ + if (hotkey < 0) return ES_NOT_HANDLED; + + NWidgetCore *nw = this->GetWidget(hotkey); + if (nw == NULL || nw->IsDisabled()) return ES_NOT_HANDLED; + + if (nw->type == WWT_EDITBOX) { + if (this->IsShaded()) return ES_NOT_HANDLED; + + /* Focus editbox */ + this->SetFocusedWidget(hotkey); + SetFocusedWindow(this); + } else { + /* Click button */ + this->OnClick(Point(), hotkey, 1); + } + return ES_HANDLED; +} + +/** + * Do all things to make a button look clicked and mark it to be + * unclicked in a few ticks. + * @param widget the widget to "click" + */ +void Window::HandleButtonClick(byte widget) +{ + this->LowerWidget(widget); + this->SetTimeout(); + this->SetWidgetDirty(widget); +} + +static void StartWindowDrag(Window *w); +static void StartWindowSizing(Window *w, bool to_left); + +/** + * Dispatch left mouse-button (possibly double) click in window. + * @param w Window to dispatch event in + * @param x X coordinate of the click + * @param y Y coordinate of the click + * @param click_count Number of fast consecutive clicks at same position + */ +static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count) +{ + NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y); + WidgetType widget_type = (nw != NULL) ? nw->type : WWT_EMPTY; + + bool focused_widget_changed = false; + /* If clicked on a window that previously did dot have focus */ + if (_focused_window != w && // We already have focus, right? + (w->window_desc->flags & WDF_NO_FOCUS) == 0 && // Don't lose focus to toolbars + widget_type != WWT_CLOSEBOX) { // Don't change focused window if 'X' (close button) was clicked + focused_widget_changed = true; + SetFocusedWindow(w); + } + + if (nw == NULL) return; // exit if clicked outside of widgets + + /* don't allow any interaction if the button has been disabled */ + if (nw->IsDisabled()) return; + + int widget_index = nw->index; ///< Index of the widget + + /* Clicked on a widget that is not disabled. + * So unless the clicked widget is the caption bar, change focus to this widget. + * Exception: In the OSK we always want the editbox to stay focussed. */ + if (widget_type != WWT_CAPTION && w->window_class != WC_OSK) { + /* focused_widget_changed is 'now' only true if the window this widget + * is in gained focus. In that case it must remain true, also if the + * local widget focus did not change. As such it's the logical-or of + * both changed states. + * + * If this is not preserved, then the OSK window would be opened when + * a user has the edit box focused and then click on another window and + * then back again on the edit box (to type some text). + */ + focused_widget_changed |= w->SetFocusedWidget(widget_index); + } + + /* Close any child drop down menus. If the button pressed was the drop down + * list's own button, then we should not process the click any further. */ + if (HideDropDownMenu(w) == widget_index && widget_index >= 0) return; + + if ((widget_type & ~WWB_PUSHBUTTON) < WWT_LAST && (widget_type & WWB_PUSHBUTTON)) w->HandleButtonClick(widget_index); + + Point pt = { x, y }; + + switch (widget_type) { + case NWID_VSCROLLBAR: + case NWID_HSCROLLBAR: + ScrollbarClickHandler(w, nw, x, y); + break; + + case WWT_EDITBOX: { + QueryString *query = w->GetQueryString(widget_index); + if (query != NULL) query->ClickEditBox(w, pt, widget_index, click_count, focused_widget_changed); + break; + } + + case WWT_CLOSEBOX: // 'X' + delete w; + return; + + case WWT_CAPTION: // 'Title bar' + StartWindowDrag(w); + return; + + case WWT_RESIZEBOX: + /* When the resize widget is on the left size of the window + * we assume that that button is used to resize to the left. */ + StartWindowSizing(w, (int)nw->pos_x < (w->width / 2)); + nw->SetDirty(w); + return; + + case WWT_DEFSIZEBOX: { + if (_ctrl_pressed) { + w->window_desc->pref_width = w->width; + w->window_desc->pref_height = w->height; + } else { + int16 def_width = max(min(w->window_desc->GetDefaultWidth(), _screen.width), w->nested_root->smallest_x); + int16 def_height = max(min(w->window_desc->GetDefaultHeight(), _screen.height - 50), w->nested_root->smallest_y); + + int dx = (w->resize.step_width == 0) ? 0 : def_width - w->width; + int dy = (w->resize.step_height == 0) ? 0 : def_height - w->height; + /* dx and dy has to go by step.. calculate it. + * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */ + if (w->resize.step_width > 1) dx -= dx % (int)w->resize.step_width; + if (w->resize.step_height > 1) dy -= dy % (int)w->resize.step_height; + ResizeWindow(w, dx, dy, false); + } + + nw->SetLowered(true); + nw->SetDirty(w); + w->SetTimeout(); + break; + } + + case WWT_DEBUGBOX: + w->ShowNewGRFInspectWindow(); + break; + + case WWT_SHADEBOX: + nw->SetDirty(w); + w->SetShaded(!w->IsShaded()); + return; + + case WWT_STICKYBOX: + w->flags ^= WF_STICKY; + nw->SetDirty(w); + if (_ctrl_pressed) w->window_desc->pref_sticky = (w->flags & WF_STICKY) != 0; + return; + + default: + break; + } + + /* Widget has no index, so the window is not interested in it. */ + if (widget_index < 0) return; + + /* Check if the widget is highlighted; if so, disable highlight and dispatch an event to the GameScript */ + if (w->IsWidgetHighlighted(widget_index)) { + w->SetWidgetHighlight(widget_index, TC_INVALID); + Game::NewEvent(new ScriptEventWindowWidgetClick((ScriptWindow::WindowClass)w->window_class, w->window_number, widget_index)); + } + + w->OnClick(pt, widget_index, click_count); +} + +/** + * Dispatch right mouse-button click in window. + * @param w Window to dispatch event in + * @param x X coordinate of the click + * @param y Y coordinate of the click + */ +static void DispatchRightClickEvent(Window *w, int x, int y) +{ + NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y); + if (wid == NULL) return; + + /* No widget to handle, or the window is not interested in it. */ + if (wid->index >= 0) { + Point pt = { x, y }; + if (w->OnRightClick(pt, wid->index)) return; + } + + if (_settings_client.gui.hover_delay == 0 && wid->tool_tip != 0) GuiShowTooltips(w, wid->tool_tip, 0, NULL, TCC_RIGHT_CLICK); +} + +/** + * Dispatch hover of the mouse over a window. + * @param w Window to dispatch event in. + * @param x X coordinate of the click. + * @param y Y coordinate of the click. + */ +static void DispatchHoverEvent(Window *w, int x, int y) +{ + NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y); + + /* No widget to handle */ + if (wid == NULL) return; + + /* Show the tooltip if there is any */ + if (wid->tool_tip != 0) { + GuiShowTooltips(w, wid->tool_tip); + return; + } + + /* Widget has no index, so the window is not interested in it. */ + if (wid->index < 0) return; + + Point pt = { x, y }; + w->OnHover(pt, wid->index); +} + +/** + * Dispatch the mousewheel-action to the window. + * The window will scroll any compatible scrollbars if the mouse is pointed over the bar or its contents + * @param w Window + * @param nwid the widget where the scrollwheel was used + * @param wheel scroll up or down + */ +static void DispatchMouseWheelEvent(Window *w, NWidgetCore *nwid, int wheel) +{ + if (nwid == NULL) return; + + /* Using wheel on caption/shade-box shades or unshades the window. */ + if (nwid->type == WWT_CAPTION || nwid->type == WWT_SHADEBOX) { + w->SetShaded(wheel < 0); + return; + } + + /* Wheeling a vertical scrollbar. */ + if (nwid->type == NWID_VSCROLLBAR) { + NWidgetScrollbar *sb = static_cast(nwid); + if (sb->GetCount() > sb->GetCapacity()) { + sb->UpdatePosition(wheel); + w->SetDirty(); + } + return; + } + + /* Scroll the widget attached to the scrollbar. */ + Scrollbar *sb = (nwid->scrollbar_index >= 0 ? w->GetScrollbar(nwid->scrollbar_index) : NULL); + if (sb != NULL && sb->GetCount() > sb->GetCapacity()) { + sb->UpdatePosition(wheel); + w->SetDirty(); + } +} + +/** + * Returns whether a window may be shown or not. + * @param w The window to consider. + * @return True iff it may be shown, otherwise false. + */ +static bool MayBeShown(const Window *w) +{ + /* If we're not modal, everything is okay. */ + if (!HasModalProgress()) return true; + + switch (w->window_class) { + case WC_MAIN_WINDOW: ///< The background, i.e. the game. + case WC_MODAL_PROGRESS: ///< The actual progress window. + case WC_CONFIRM_POPUP_QUERY: ///< The abort window. + return true; + + default: + return false; + } +} + +/** + * Generate repaint events for the visible part of window w within the rectangle. + * + * The function goes recursively upwards in the window stack, and splits the rectangle + * into multiple pieces at the window edges, so obscured parts are not redrawn. + * + * @param w Window that needs to be repainted + * @param left Left edge of the rectangle that should be repainted + * @param top Top edge of the rectangle that should be repainted + * @param right Right edge of the rectangle that should be repainted + * @param bottom Bottom edge of the rectangle that should be repainted + */ +static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom) +{ + const Window *v; + FOR_ALL_WINDOWS_FROM_BACK_FROM(v, w->z_front) { + if (MayBeShown(v) && + right > v->left && + bottom > v->top && + left < v->left + v->width && + top < v->top + v->height) { + /* v and rectangle intersect with each other */ + int x; + + if (left < (x = v->left)) { + DrawOverlappedWindow(w, left, top, x, bottom); + DrawOverlappedWindow(w, x, top, right, bottom); + return; + } + + if (right > (x = v->left + v->width)) { + DrawOverlappedWindow(w, left, top, x, bottom); + DrawOverlappedWindow(w, x, top, right, bottom); + return; + } + + if (top < (x = v->top)) { + DrawOverlappedWindow(w, left, top, right, x); + DrawOverlappedWindow(w, left, x, right, bottom); + return; + } + + if (bottom > (x = v->top + v->height)) { + DrawOverlappedWindow(w, left, top, right, x); + DrawOverlappedWindow(w, left, x, right, bottom); + return; + } + + return; + } + } + + /* Setup blitter, and dispatch a repaint event to window *wz */ + DrawPixelInfo *dp = _cur_dpi; + dp->width = right - left; + dp->height = bottom - top; + dp->left = left - w->left; + dp->top = top - w->top; + dp->pitch = _screen.pitch; + dp->dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(_screen.dst_ptr, left, top); + dp->zoom = ZOOM_LVL_NORMAL; + w->OnPaint(); +} + +/** + * From a rectangle that needs redrawing, find the windows that intersect with the rectangle. + * These windows should be re-painted. + * @param left Left edge of the rectangle that should be repainted + * @param top Top edge of the rectangle that should be repainted + * @param right Right edge of the rectangle that should be repainted + * @param bottom Bottom edge of the rectangle that should be repainted + */ +void DrawOverlappedWindowForAll(int left, int top, int right, int bottom) +{ + Window *w; + DrawPixelInfo bk; + _cur_dpi = &bk; + + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (MayBeShown(w) && + right > w->left && + bottom > w->top && + left < w->left + w->width && + top < w->top + w->height) { + /* Window w intersects with the rectangle => needs repaint */ + DrawOverlappedWindow(w, left, top, right, bottom); + } + } +} + +/** + * Mark entire window as dirty (in need of re-paint) + * @ingroup dirty + */ +void Window::SetDirty() const +{ + SetDirtyBlocks(this->left, this->top, this->left + this->width, this->top + this->height); +} + +/** + * Re-initialize a window, and optionally change its size. + * @param rx Horizontal resize of the window. + * @param ry Vertical resize of the window. + * @note For just resizing the window, use #ResizeWindow instead. + */ +void Window::ReInit(int rx, int ry) +{ + this->SetDirty(); // Mark whole current window as dirty. + + /* Save current size. */ + int window_width = this->width; + int window_height = this->height; + + this->OnInit(); + /* Re-initialize the window from the ground up. No need to change the nested_array, as all widgets stay where they are. */ + this->nested_root->SetupSmallestSize(this, false); + this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL); + this->width = this->nested_root->smallest_x; + this->height = this->nested_root->smallest_y; + this->resize.step_width = this->nested_root->resize_x; + this->resize.step_height = this->nested_root->resize_y; + + /* Resize as close to the original size + requested resize as possible. */ + window_width = max(window_width + rx, this->width); + window_height = max(window_height + ry, this->height); + int dx = (this->resize.step_width == 0) ? 0 : window_width - this->width; + int dy = (this->resize.step_height == 0) ? 0 : window_height - this->height; + /* dx and dy has to go by step.. calculate it. + * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */ + if (this->resize.step_width > 1) dx -= dx % (int)this->resize.step_width; + if (this->resize.step_height > 1) dy -= dy % (int)this->resize.step_height; + + ResizeWindow(this, dx, dy); + /* ResizeWindow() does this->SetDirty() already, no need to do it again here. */ +} + +/** + * Set the shaded state of the window to \a make_shaded. + * @param make_shaded If \c true, shade the window (roll up until just the title bar is visible), else unshade/unroll the window to its original size. + * @note The method uses #Window::ReInit(), thus after the call, the whole window should be considered changed. + */ +void Window::SetShaded(bool make_shaded) +{ + if (this->shade_select == NULL) return; + + int desired = make_shaded ? SZSP_HORIZONTAL : 0; + if (this->shade_select->shown_plane != desired) { + if (make_shaded) { + if (this->nested_focus != NULL) this->UnfocusFocusedWidget(); + this->unshaded_size.width = this->width; + this->unshaded_size.height = this->height; + this->shade_select->SetDisplayedPlane(desired); + this->ReInit(0, -this->height); + } else { + this->shade_select->SetDisplayedPlane(desired); + int dx = ((int)this->unshaded_size.width > this->width) ? (int)this->unshaded_size.width - this->width : 0; + int dy = ((int)this->unshaded_size.height > this->height) ? (int)this->unshaded_size.height - this->height : 0; + this->ReInit(dx, dy); + } + } +} + +/** + * Find the Window whose parent pointer points to this window + * @param w parent Window to find child of + * @param wc Window class of the window to remove; #WC_INVALID if class does not matter + * @return a Window pointer that is the child of \a w, or \c NULL otherwise + */ +static Window *FindChildWindow(const Window *w, WindowClass wc) +{ + Window *v; + FOR_ALL_WINDOWS_FROM_BACK(v) { + if ((wc == WC_INVALID || wc == v->window_class) && v->parent == w) return v; + } + + return NULL; +} + +/** + * Delete all children a window might have in a head-recursive manner + * @param wc Window class of the window to remove; #WC_INVALID if class does not matter + */ +void Window::DeleteChildWindows(WindowClass wc) const +{ + Window *child = FindChildWindow(this, wc); + while (child != NULL) { + delete child; + child = FindChildWindow(this, wc); + } +} + +/** + * Remove window and all its child windows from the window stack. + */ +Window::~Window() +{ + if (_thd.window_class == this->window_class && + _thd.window_number == this->window_number) { + ResetObjectToPlace(); + } + + /* Prevent Mouseover() from resetting mouse-over coordinates on a non-existing window */ + if (_mouseover_last_w == this) _mouseover_last_w = NULL; + + /* We can't scroll the window when it's closed. */ + if (_last_scroll_window == this) _last_scroll_window = NULL; + + /* Make sure we don't try to access this window as the focused window when it doesn't exist anymore. */ + if (_focused_window == this) { + this->OnFocusLost(); + _focused_window = NULL; + } + + this->DeleteChildWindows(); + + if (this->viewport != NULL) DeleteWindowViewport(this); + + this->SetDirty(); + + free(this->nested_array); // Contents is released through deletion of #nested_root. + delete this->nested_root; + + this->window_class = WC_INVALID; +} + +/** + * Find a window by its class and window number + * @param cls Window class + * @param number Number of the window within the window class + * @return Pointer to the found window, or \c NULL if not available + */ +Window *FindWindowById(WindowClass cls, WindowNumber number) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls && w->window_number == number) return w; + } + + return NULL; +} + +/** + * Find any window by its class. Useful when searching for a window that uses + * the window number as a #WindowType, like #WC_SEND_NETWORK_MSG. + * @param cls Window class + * @return Pointer to the found window, or \c NULL if not available + */ +Window *FindWindowByClass(WindowClass cls) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls) return w; + } + + return NULL; +} + +/** + * Delete a window by its class and window number (if it is open). + * @param cls Window class + * @param number Number of the window within the window class + * @param force force deletion; if false don't delete when stickied + */ +void DeleteWindowById(WindowClass cls, WindowNumber number, bool force) +{ + Window *w = FindWindowById(cls, number); + if (force || w == NULL || + (w->flags & WF_STICKY) == 0) { + delete w; + } +} + +/** + * Delete all windows of a given class + * @param cls Window class of windows to delete + */ +void DeleteWindowByClass(WindowClass cls) +{ + Window *w; + +restart_search: + /* When we find the window to delete, we need to restart the search + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls) { + delete w; + goto restart_search; + } + } +} + +/** + * Delete all windows of a company. We identify windows of a company + * by looking at the caption colour. If it is equal to the company ID + * then we say the window belongs to the company and should be deleted + * @param id company identifier + */ +void DeleteCompanyWindows(CompanyID id) +{ + Window *w; + +restart_search: + /* When we find the window to delete, we need to restart the search + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->owner == id) { + delete w; + goto restart_search; + } + } + + /* Also delete the company specific windows that don't have a company-colour. */ + DeleteWindowById(WC_BUY_COMPANY, id); +} + +/** + * Change the owner of all the windows one company can take over from another + * company in the case of a company merger. Do not change ownership of windows + * that need to be deleted once takeover is complete + * @param old_owner original owner of the window + * @param new_owner the new owner of the window + */ +void ChangeWindowOwner(Owner old_owner, Owner new_owner) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->owner != old_owner) continue; + + switch (w->window_class) { + case WC_COMPANY_COLOUR: + case WC_FINANCES: + case WC_STATION_LIST: + case WC_TRAINS_LIST: + case WC_ROADVEH_LIST: + case WC_SHIPS_LIST: + case WC_AIRCRAFT_LIST: + case WC_BUY_COMPANY: + case WC_COMPANY: + case WC_COMPANY_INFRASTRUCTURE: + continue; + + default: + w->owner = new_owner; + break; + } + } +} + +static void BringWindowToFront(Window *w); + +/** + * Find a window and make it the relative top-window on the screen. + * The window gets unshaded if it was shaded, and a white border is drawn at its edges for a brief period of time to visualize its "activation". + * @param cls WindowClass of the window to activate + * @param number WindowNumber of the window to activate + * @return a pointer to the window thus activated + */ +Window *BringWindowToFrontById(WindowClass cls, WindowNumber number) +{ + Window *w = FindWindowById(cls, number); + + if (w != NULL) { + if (w->IsShaded()) w->SetShaded(false); // Restore original window size if it was shaded. + + w->SetWhiteBorder(); + BringWindowToFront(w); + w->SetDirty(); + } + + return w; +} + +static inline bool IsVitalWindow(const Window *w) +{ + switch (w->window_class) { + case WC_MAIN_TOOLBAR: + case WC_STATUS_BAR: + case WC_NEWS_WINDOW: + case WC_SEND_NETWORK_MSG: + return true; + + default: + return false; + } +} + +/** + * Get the z-priority for a given window. This is used in comparison with other z-priority values; + * a window with a given z-priority will appear above other windows with a lower value, and below + * those with a higher one (the ordering within z-priorities is arbitrary). + * @param w The window to get the z-priority for + * @pre w->window_class != WC_INVALID + * @return The window's z-priority + */ +static uint GetWindowZPriority(const Window *w) +{ + assert(w->window_class != WC_INVALID); + + uint z_priority = 0; + + switch (w->window_class) { + case WC_ENDSCREEN: + ++z_priority; + + case WC_HIGHSCORE: + ++z_priority; + + case WC_TOOLTIPS: + ++z_priority; + + case WC_DROPDOWN_MENU: + ++z_priority; + + case WC_MAIN_TOOLBAR: + case WC_STATUS_BAR: + ++z_priority; + + case WC_OSK: + ++z_priority; + + case WC_QUERY_STRING: + case WC_SEND_NETWORK_MSG: + ++z_priority; + + case WC_ERRMSG: + case WC_CONFIRM_POPUP_QUERY: + case WC_MODAL_PROGRESS: + case WC_NETWORK_STATUS_WINDOW: + ++z_priority; + + case WC_GENERATE_LANDSCAPE: + case WC_SAVELOAD: + case WC_GAME_OPTIONS: + case WC_CUSTOM_CURRENCY: + case WC_NETWORK_WINDOW: + case WC_GRF_PARAMETERS: + case WC_AI_LIST: + case WC_AI_SETTINGS: + case WC_TEXTFILE: + ++z_priority; + + case WC_CONSOLE: + ++z_priority; + + case WC_NEWS_WINDOW: + case WC_TABLET_BAR: + ++z_priority; + + default: + ++z_priority; + + case WC_MAIN_WINDOW: + return z_priority; + } +} + +/** + * Adds a window to the z-ordering, according to its z-priority. + * @param w Window to add + */ +static void AddWindowToZOrdering(Window *w) +{ + assert(w->z_front == NULL && w->z_back == NULL); + + if (_z_front_window == NULL) { + /* It's the only window. */ + _z_front_window = _z_back_window = w; + w->z_front = w->z_back = NULL; + } else { + /* Search down the z-ordering for its location. */ + Window *v = _z_front_window; + uint last_z_priority = UINT_MAX; + while (v != NULL && (v->window_class == WC_INVALID || GetWindowZPriority(v) > GetWindowZPriority(w))) { + if (v->window_class != WC_INVALID) { + /* Sanity check z-ordering, while we're at it. */ + assert(last_z_priority >= GetWindowZPriority(v)); + last_z_priority = GetWindowZPriority(v); + } + + v = v->z_back; + } + + if (v == NULL) { + /* It's the new back window. */ + w->z_front = _z_back_window; + w->z_back = NULL; + _z_back_window->z_back = w; + _z_back_window = w; + } else if (v == _z_front_window) { + /* It's the new front window. */ + w->z_front = NULL; + w->z_back = _z_front_window; + _z_front_window->z_front = w; + _z_front_window = w; + } else { + /* It's somewhere else in the z-ordering. */ + w->z_front = v->z_front; + w->z_back = v; + v->z_front->z_back = w; + v->z_front = w; + } + } +} + + +/** + * Removes a window from the z-ordering. + * @param w Window to remove + */ +static void RemoveWindowFromZOrdering(Window *w) +{ + if (w->z_front == NULL) { + assert(_z_front_window == w); + _z_front_window = w->z_back; + } else { + w->z_front->z_back = w->z_back; + } + + if (w->z_back == NULL) { + assert(_z_back_window == w); + _z_back_window = w->z_front; + } else { + w->z_back->z_front = w->z_front; + } + + w->z_front = w->z_back = NULL; +} + +/** + * On clicking on a window, make it the frontmost window of all windows with an equal + * or lower z-priority. The window is marked dirty for a repaint + * @param w window that is put into the relative foreground + */ +static void BringWindowToFront(Window *w) +{ + RemoveWindowFromZOrdering(w); + AddWindowToZOrdering(w); + + w->SetDirty(); +} + +/** + * Initializes the data (except the position and initial size) of a new Window. + * @param desc Window description. + * @param window_number Number being assigned to the new window + * @return Window pointer of the newly created window + * @pre If nested widgets are used (\a widget is \c NULL), #nested_root and #nested_array_size must be initialized. + * In addition, #nested_array is either \c NULL, or already initialized. + */ +void Window::InitializeData(WindowNumber window_number) +{ + /* Set up window properties; some of them are needed to set up smallest size below */ + this->window_class = this->window_desc->cls; + this->SetWhiteBorder(); + if (this->window_desc->default_pos == WDP_CENTER) this->flags |= WF_CENTERED; + this->owner = INVALID_OWNER; + this->nested_focus = NULL; + this->window_number = window_number; + + this->OnInit(); + /* Initialize nested widget tree. */ + if (this->nested_array == NULL) { + this->nested_array = CallocT(this->nested_array_size); + this->nested_root->SetupSmallestSize(this, true); + } else { + this->nested_root->SetupSmallestSize(this, false); + } + /* Initialize to smallest size. */ + this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL); + + /* Further set up window properties, + * this->left, this->top, this->width, this->height, this->resize.width, and this->resize.height are initialized later. */ + this->resize.step_width = this->nested_root->resize_x; + this->resize.step_height = this->nested_root->resize_y; + + /* Give focus to the opened window unless a text box + * of focused window has focus (so we don't interrupt typing). But if the new + * window has a text box, then take focus anyway. */ + if (!EditBoxInGlobalFocus() || this->nested_root->GetWidgetOfType(WWT_EDITBOX) != NULL) SetFocusedWindow(this); + + /* Insert the window into the correct location in the z-ordering. */ + AddWindowToZOrdering(this); +} + +/** + * Set the position and smallest size of the window. + * @param x Offset in pixels from the left of the screen of the new window. + * @param y Offset in pixels from the top of the screen of the new window. + * @param sm_width Smallest width in pixels of the window. + * @param sm_height Smallest height in pixels of the window. + */ +void Window::InitializePositionSize(int x, int y, int sm_width, int sm_height) +{ + this->left = x; + this->top = y; + this->width = sm_width; + this->height = sm_height; +} + +/** + * Resize window towards the default size. + * Prior to construction, a position for the new window (for its default size) + * has been found with LocalGetWindowPlacement(). Initially, the window is + * constructed with minimal size. Resizing the window to its default size is + * done here. + * @param def_width default width in pixels of the window + * @param def_height default height in pixels of the window + * @see Window::Window(), Window::InitializeData(), Window::InitializePositionSize() + */ +void Window::FindWindowPlacementAndResize(int def_width, int def_height) +{ + def_width = max(def_width, this->width); // Don't allow default size to be smaller than smallest size + def_height = max(def_height, this->height); + /* Try to make windows smaller when our window is too small. + * w->(width|height) is normally the same as min_(width|height), + * but this way the GUIs can be made a little more dynamic; + * one can use the same spec for multiple windows and those + * can then determine the real minimum size of the window. */ + if (this->width != def_width || this->height != def_height) { + /* Think about the overlapping toolbars when determining the minimum window size */ + int free_height = _screen.height; + const Window *wt = FindWindowById(WC_STATUS_BAR, 0); + if (wt != NULL) free_height -= wt->height; + wt = FindWindowById(WC_MAIN_TOOLBAR, 0); + if (wt != NULL) free_height -= wt->height; + + int enlarge_x = max(min(def_width - this->width, _screen.width - this->width), 0); + int enlarge_y = max(min(def_height - this->height, free_height - this->height), 0); + + /* X and Y has to go by step.. calculate it. + * The cast to int is necessary else x/y are implicitly casted to + * unsigned int, which won't work. */ + if (this->resize.step_width > 1) enlarge_x -= enlarge_x % (int)this->resize.step_width; + if (this->resize.step_height > 1) enlarge_y -= enlarge_y % (int)this->resize.step_height; + + ResizeWindow(this, enlarge_x, enlarge_y); + /* ResizeWindow() calls this->OnResize(). */ + } else { + /* Always call OnResize; that way the scrollbars and matrices get initialized. */ + this->OnResize(); + } + + int nx = this->left; + int ny = this->top; + + if (nx + this->width > _screen.width) nx -= (nx + this->width - _screen.width); + + const Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0); + ny = max(ny, (wt == NULL || this == wt || this->top == 0) ? 0 : wt->height); + nx = max(nx, 0); + + if (this->viewport != NULL) { + this->viewport->left += nx - this->left; + this->viewport->top += ny - this->top; + } + this->left = nx; + this->top = ny; + + this->SetDirty(); +} + +/** + * Decide whether a given rectangle is a good place to open a completely visible new window. + * The new window should be within screen borders, and not overlap with another already + * existing window (except for the main window in the background). + * @param left Left edge of the rectangle + * @param top Top edge of the rectangle + * @param width Width of the rectangle + * @param height Height of the rectangle + * @param pos If rectangle is good, use this parameter to return the top-left corner of the new window + * @return Boolean indication that the rectangle is a good place for the new window + */ +static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &pos) +{ + int right = width + left; + int bottom = height + top; + + const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); + if (left < 0 || (main_toolbar != NULL && top < main_toolbar->height) || right > _screen.width || bottom > _screen.height) return false; + + /* Make sure it is not obscured by any window. */ + const Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == WC_MAIN_WINDOW) continue; + + if (right > w->left && + w->left + w->width > left && + bottom > w->top && + w->top + w->height > top) { + return false; + } + } + + pos.x = left; + pos.y = top; + return true; +} + +/** + * Decide whether a given rectangle is a good place to open a mostly visible new window. + * The new window should be mostly within screen borders, and not overlap with another already + * existing window (except for the main window in the background). + * @param left Left edge of the rectangle + * @param top Top edge of the rectangle + * @param width Width of the rectangle + * @param height Height of the rectangle + * @param pos If rectangle is good, use this parameter to return the top-left corner of the new window + * @return Boolean indication that the rectangle is a good place for the new window + */ +static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &pos) +{ + /* Left part of the rectangle may be at most 1/4 off-screen, + * right part of the rectangle may be at most 1/2 off-screen + */ + if (left < -(width >> 2) || left > _screen.width - (width >> 1)) return false; + /* Bottom part of the rectangle may be at most 1/4 off-screen */ + if (top < 22 || top > _screen.height - (height >> 2)) return false; + + /* Make sure it is not obscured by any window. */ + const Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == WC_MAIN_WINDOW) continue; + + if (left + width > w->left && + w->left + w->width > left && + top + height > w->top && + w->top + w->height > top) { + return false; + } + } + + pos.x = left; + pos.y = top; + return true; +} + +/** + * Find a good place for opening a new window of a given width and height. + * @param width Width of the new window + * @param height Height of the new window + * @return Top-left coordinate of the new window + */ +static Point GetAutoPlacePosition(int width, int height) +{ + Point pt; + + /* First attempt, try top-left of the screen */ + const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); + if (IsGoodAutoPlace1(0, main_toolbar != NULL ? main_toolbar->height + 2 : 2, width, height, pt)) return pt; + + /* Second attempt, try around all existing windows with a distance of 2 pixels. + * The new window must be entirely on-screen, and not overlap with an existing window. + * Eight starting points are tried, two at each corner. + */ + const Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == WC_MAIN_WINDOW) continue; + + if (IsGoodAutoPlace1(w->left + w->width + 2, w->top, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left - width - 2, w->top, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left, w->top + w->height + 2, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left, w->top - height - 2, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left + w->width + 2, w->top + w->height - height, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left - width - 2, w->top + w->height - height, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left + w->width - width, w->top + w->height + 2, width, height, pt)) return pt; + if (IsGoodAutoPlace1(w->left + w->width - width, w->top - height - 2, width, height, pt)) return pt; + } + + /* Third attempt, try around all existing windows with a distance of 2 pixels. + * The new window may be partly off-screen, and must not overlap with an existing window. + * Only four starting points are tried. + */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == WC_MAIN_WINDOW) continue; + + if (IsGoodAutoPlace2(w->left + w->width + 2, w->top, width, height, pt)) return pt; + if (IsGoodAutoPlace2(w->left - width - 2, w->top, width, height, pt)) return pt; + if (IsGoodAutoPlace2(w->left, w->top + w->height + 2, width, height, pt)) return pt; + if (IsGoodAutoPlace2(w->left, w->top - height - 2, width, height, pt)) return pt; + } + + /* Fourth and final attempt, put window at diagonal starting from (0, 24), try multiples + * of (+5, +5) + */ + int left = 0, top = 24; + +restart: + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->left == left && w->top == top) { + left += 5; + top += 5; + goto restart; + } + } + + pt.x = left; + pt.y = top; + return pt; +} + +/** + * Computer the position of the top-left corner of a window to be opened right + * under the toolbar. + * @param window_width the width of the window to get the position for + * @return Coordinate of the top-left corner of the new window. + */ +Point GetToolbarAlignedWindowPosition(int window_width) +{ + const Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); + assert(w != NULL); + Point pt = { _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width, w->top + w->height }; + return pt; +} + +/** + * Compute the position of the top-left corner of a new window that is opened. + * + * By default position a child window at an offset of 10/10 of its parent. + * With the exception of WC_BUILD_TOOLBAR (build railway/roads/ship docks/airports) + * and WC_SCEN_LAND_GEN (landscaping). Whose child window has an offset of 0/toolbar-height of + * its parent. So it's exactly under the parent toolbar and no buttons will be covered. + * However if it falls too extremely outside window positions, reposition + * it to an automatic place. + * + * @param *desc The pointer to the WindowDesc to be created. + * @param sm_width Smallest width of the window. + * @param sm_height Smallest height of the window. + * @param window_number The window number of the new window. + * + * @return Coordinate of the top-left corner of the new window. + */ +static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number) +{ + Point pt; + const Window *w; + + int16 default_width = max(desc->GetDefaultWidth(), sm_width); + int16 default_height = max(desc->GetDefaultHeight(), sm_height); + + if (desc->parent_cls != WC_NONE && + (w = FindWindowById(desc->parent_cls, window_number)) != NULL && + w->left < _screen.width - 20 && w->left > -60 && w->top < _screen.height - 20) { + + if (_settings_client.gui.touchscreen_mode != TSC_NONE) { + pt.x = _current_text_dir == TD_RTL ? 0 : (_screen.width - default_width); + } else { + pt.x = w->left + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? 0 : 10); + if (pt.x > _screen.width + 10 - default_width) { + pt.x = (_screen.width + 10 - default_width) - 20; + } + } + + pt.y = w->top + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? w->height : 10); + return pt; + } + + switch (desc->default_pos) { + case WDP_ALIGN_TOOLBAR: // Align to the toolbar + return GetToolbarAlignedWindowPosition(default_width); + + case WDP_AUTO: // Find a good automatic position for the window + return GetAutoPlacePosition(default_width, default_height); + + case WDP_CENTER: // Centre the window horizontally + pt.x = (_screen.width - default_width) / 2; + pt.y = (_screen.height - default_height) / 2; + break; + + case WDP_MANUAL: + pt.x = 0; + pt.y = 0; + break; + + default: + NOT_REACHED(); + } + + // try to put it to + + return pt; +} + +/* virtual */ Point Window::OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) +{ + return LocalGetWindowPlacement(this->window_desc, sm_width, sm_height, window_number); +} + +/** + * Perform the first part of the initialization of a nested widget tree. + * Construct a nested widget tree in #nested_root, and optionally fill the #nested_array array to provide quick access to the uninitialized widgets. + * This is mainly useful for setting very basic properties. + * @param fill_nested Fill the #nested_array (enabling is expensive!). + * @note Filling the nested array requires an additional traversal through the nested widget tree, and is best performed by #FinishInitNested rather than here. + */ +void Window::CreateNestedTree(bool fill_nested) +{ + int biggest_index = -1; + this->nested_root = MakeWindowNWidgetTree(this->window_desc->nwid_parts, this->window_desc->nwid_length, &biggest_index, &this->shade_select); + this->nested_array_size = (uint)(biggest_index + 1); + + if (fill_nested) { + this->nested_array = CallocT(this->nested_array_size); + this->nested_root->FillNestedArray(this->nested_array, this->nested_array_size); + } +} + +/** + * Perform the second part of the initialization of a nested widget tree. + * @param window_number Number of the new window. + */ +void Window::FinishInitNested(WindowNumber window_number) +{ + this->InitializeData(window_number); + this->ApplyDefaults(); + Point pt = this->OnInitialPosition(this->nested_root->smallest_x, this->nested_root->smallest_y, window_number); + this->InitializePositionSize(pt.x, pt.y, this->nested_root->smallest_x, this->nested_root->smallest_y); + this->FindWindowPlacementAndResize(this->window_desc->GetDefaultWidth(), this->window_desc->GetDefaultHeight()); +} + +/** + * Perform complete initialization of the #Window with nested widgets, to allow use. + * @param window_number Number of the new window. + */ +void Window::InitNested(WindowNumber window_number) +{ + this->CreateNestedTree(false); + this->FinishInitNested(window_number); +} + +/** + * Empty constructor, initialization has been moved to #InitNested() called from the constructor of the derived class. + * @param desc The description of the window. + */ +Window::Window(WindowDesc *desc) : window_desc(desc), scrolling_scrollbar(-1) +{ +} + +/** + * Do a search for a window at specific coordinates. For this we start + * at the topmost window, obviously and work our way down to the bottom + * @param x position x to query + * @param y position y to query + * @return a pointer to the found window if any, NULL otherwise + */ +Window *FindWindowFromPt(int x, int y) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if (MayBeShown(w) && IsInsideBS(x, w->left, w->width) && IsInsideBS(y, w->top, w->height)) { + return w; + } + } + + return NULL; +} + +int SETTING_BUTTON_WIDTH = 20; +int SETTING_BUTTON_HEIGHT = 10; + +/** + * Set button size of settings. If automatic sizing is also enabled, it also sets + * the sizing of buttons, scrollbars and font size (recommend restart). + * @todo Check if it can be moved to another file, so we do not need to include error, string and fontcache headers. + * @todo Fix magic numbers 16/18/20/30/32 + */ +void CheckWindowMinSizings() +{ + if (_settings_client.gui.manage_min_sizing) { + /* Fill the min sizing values for the current resolution. */ + uint swap_x = 32; // in longest border, let main toolbar to have 30 buttons. + uint swap_y = 16; // if short border, let main toolbar have 16/18/20 buttons..) + if (_cur_resolution.width < _cur_resolution.height) Swap(swap_x, swap_y); + _settings_client.gui.min_button = min(_cur_resolution.width / swap_x, _cur_resolution.height / swap_y); + _settings_client.gui.min_step = _settings_client.gui.min_button * 3 / 4; + } + + SETTING_BUTTON_HEIGHT = max(GetMinSizing(NWST_STEP) - 10, 10); + SETTING_BUTTON_WIDTH = 2 * SETTING_BUTTON_HEIGHT; + + extern uint _tooltip_width; + _tooltip_width = max(194, 10 * _settings_client.gui.min_button); + + if (!_settings_client.gui.manage_min_sizing) return; + + _freetype.large.size = _settings_client.gui.min_button; + _freetype.medium.size = max(_settings_client.gui.min_step * 2 / 3, 10U); + _freetype.mono.size = _freetype.medium.size; + _freetype.small.size = max(_freetype.medium.size * 2 / 3, 8U); + + InitFreeType(true); + CheckForMissingGlyphs(); + + if (_z_front_window == NULL) return; + + DeleteAllNonVitalWindows(); + + switch (_game_mode) { + default: break; + case GM_MENU: + DeleteWindowById(WC_SELECT_GAME, 0); + extern void ShowSelectGameWindow(); + ShowSelectGameWindow(); + break; + + case GM_NORMAL: + case GM_EDITOR: { + Station *st; + FOR_ALL_STATIONS(st) { st->UpdateVirtCoord(); } + Waypoint *wp; + FOR_ALL_WAYPOINTS(wp) { wp->UpdateVirtCoord(); } + + HideVitalWindows(); + ShowVitalWindows(); + break; + } + } + + ShowErrorMessage(STR_ERROR_RESET_WINDOWS, STR_ERROR_AUTOMATIC_SIZING, WL_WARNING); +} + +/** + * (re)initialize the windowing system + */ +void InitWindowSystem() +{ + IConsoleClose(); + + _z_back_window = NULL; + _z_front_window = NULL; + _focused_window = NULL; + _mouseover_last_w = NULL; + _last_scroll_window = NULL; + _scrolling_viewport = false; + _mouse_hovering = false; + + NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets. + NWidgetScrollbar::InvalidateDimensionCache(); + + ShowFirstError(); +} + +/** + * Close down the windowing system + */ +void UnInitWindowSystem() +{ + UnshowCriticalError(); + + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) delete w; + + for (w = _z_front_window; w != NULL; /* nothing */) { + Window *to_del = w; + w = w->z_back; + free(to_del); + } + + _z_front_window = NULL; + _z_back_window = NULL; +} + +/** + * Reset the windowing system, by means of shutting it down followed by re-initialization + */ +void ResetWindowSystem() +{ + UnInitWindowSystem(); + InitWindowSystem(); + _thd.Reset(); +} + +static void DecreaseWindowCounters() +{ + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if (_scroller_click_timeout == 0) { + /* Unclick scrollbar buttons if they are pressed. */ + for (uint i = 0; i < w->nested_array_size; i++) { + NWidgetBase *nwid = w->nested_array[i]; + if (nwid != NULL && (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR)) { + NWidgetScrollbar *sb = static_cast(nwid); + if (sb->disp_flags & (ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN)) { + sb->disp_flags &= ~(ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN); + w->scrolling_scrollbar = -1; + sb->SetDirty(w); + } + } + } + } + + /* Handle editboxes */ + for (SmallMap::Pair *it = w->querystrings.Begin(); it != w->querystrings.End(); ++it) { + it->second->HandleEditBox(w, it->first); + } + + w->OnMouseLoop(); + } + + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if ((w->flags & WF_TIMEOUT) && --w->timeout_timer == 0) { + CLRBITS(w->flags, WF_TIMEOUT); + + w->OnTimeout(); + w->RaiseButtons(true); + } + } +} + +static void HandlePlacePresize() +{ + if (_special_mouse_mode != WSM_PRESIZE) return; + + Window *w = _thd.GetCallbackWnd(); + if (w == NULL) return; + + Point pt = GetTileBelowCursor(); + if (pt.x == -1) { + _thd.selend.x = -1; + return; + } + + w->OnPlacePresize(pt, TileVirtXY(pt.x, pt.y)); +} + +/** + * Handle dragging and dropping in mouse dragging mode (#WSM_DRAGDROP). + * @return State of handling the event. + */ +static EventState HandleMouseDragDrop() +{ + if (_special_mouse_mode != WSM_DRAGDROP) return ES_NOT_HANDLED; + + if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; // Dragging, but the mouse did not move. + + Window *w = _thd.GetCallbackWnd(); + if (w != NULL) { + /* Send an event in client coordinates. */ + Point pt; + pt.x = _cursor.pos.x - w->left; + pt.y = _cursor.pos.y - w->top; + if (_left_button_down) { + w->OnMouseDrag(pt, GetWidgetFromPos(w, pt.x, pt.y)); + } else { + w->OnDragDrop(pt, GetWidgetFromPos(w, pt.x, pt.y)); + } + } + + if (!_left_button_down) ResetObjectToPlace(); // Button released, finished dragging. + return ES_HANDLED; +} + +/** Report position of the mouse to the underlying window. */ +static void HandleMouseOver() +{ + Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); + + /* We changed window, put a MOUSEOVER event to the last window */ + if (_mouseover_last_w != NULL && _mouseover_last_w != w) { + /* Reset mouse-over coordinates of previous window */ + Point pt = { -1, -1 }; + _mouseover_last_w->OnMouseOver(pt, 0); + } + + /* _mouseover_last_w will get reset when the window is deleted, see DeleteWindow() */ + _mouseover_last_w = w; + + if (w != NULL) { + /* send an event in client coordinates. */ + Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top }; + const NWidgetCore *widget = w->nested_root->GetWidgetFromPos(pt.x, pt.y); + if (widget != NULL) w->OnMouseOver(pt, widget->index); + } +} + +/** The minimum number of pixels of the title bar must be visible in both the X or Y direction */ +static const int MIN_VISIBLE_TITLE_BAR = 13; + +/** Direction for moving the window. */ +enum PreventHideDirection { + PHD_UP, ///< Above v is a safe position. + PHD_DOWN, ///< Below v is a safe position. +}; + +/** + * Do not allow hiding of the rectangle with base coordinates \a nx and \a ny behind window \a v. + * If needed, move the window base coordinates to keep it visible. + * @param nx Base horizontal coordinate of the rectangle. + * @param ny Base vertical coordinate of the rectangle. + * @param rect Rectangle that must stay visible for #MIN_VISIBLE_TITLE_BAR pixels (horizontally, vertically, or both) + * @param v Window lying in front of the rectangle. + * @param px Previous horizontal base coordinate. + * @param dir If no room horizontally, move the rectangle to the indicated position. + */ +static void PreventHiding(int *nx, int *ny, const Rect &rect, const Window *v, int px, PreventHideDirection dir) +{ + if (v == NULL) return; + + int v_bottom = v->top + v->height; + int v_right = v->left + v->width; + int safe_y = (dir == PHD_UP) ? (v->top - MIN_VISIBLE_TITLE_BAR - rect.top) : (v_bottom + MIN_VISIBLE_TITLE_BAR - rect.bottom); // Compute safe vertical position. + + if (*ny + rect.top <= v->top - MIN_VISIBLE_TITLE_BAR) return; // Above v is enough space + if (*ny + rect.bottom >= v_bottom + MIN_VISIBLE_TITLE_BAR) return; // Below v is enough space + + /* Vertically, the rectangle is hidden behind v. */ + if (*nx + rect.left + MIN_VISIBLE_TITLE_BAR < v->left) { // At left of v. + if (v->left < MIN_VISIBLE_TITLE_BAR) *ny = safe_y; // But enough room, force it to a safe position. + return; + } + if (*nx + rect.right - MIN_VISIBLE_TITLE_BAR > v_right) { // At right of v. + if (v_right > _screen.width - MIN_VISIBLE_TITLE_BAR) *ny = safe_y; // Not enough room, force it to a safe position. + return; + } + + /* Horizontally also hidden, force movement to a safe area. */ + if (px + rect.left < v->left && v->left >= MIN_VISIBLE_TITLE_BAR) { // Coming from the left, and enough room there. + *nx = v->left - MIN_VISIBLE_TITLE_BAR - rect.left; + } else if (px + rect.right > v_right && v_right <= _screen.width - MIN_VISIBLE_TITLE_BAR) { // Coming from the right, and enough room there. + *nx = v_right + MIN_VISIBLE_TITLE_BAR - rect.right; + } else { + *ny = safe_y; + } +} + +/** + * Make sure at least a part of the caption bar is still visible by moving + * the window if necessary. + * @param w The window to check. + * @param nx The proposed new x-location of the window. + * @param ny The proposed new y-location of the window. + */ +static void EnsureVisibleCaption(Window *w, int nx, int ny) +{ + /* Search for the title bar rectangle. */ + Rect caption_rect; + const NWidgetBase *caption = w->nested_root->GetWidgetOfType(WWT_CAPTION); + if (caption != NULL) { + caption_rect.left = caption->pos_x; + caption_rect.right = caption->pos_x + caption->current_x; + caption_rect.top = caption->pos_y; + caption_rect.bottom = caption->pos_y + caption->current_y; + + /* Make sure the window doesn't leave the screen */ + nx = Clamp(nx, MIN_VISIBLE_TITLE_BAR - caption_rect.right, _screen.width - MIN_VISIBLE_TITLE_BAR - caption_rect.left); + ny = Clamp(ny, 0, _screen.height - MIN_VISIBLE_TITLE_BAR); + + /* Make sure the title bar isn't hidden behind the main tool bar or the status bar. */ + PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_MAIN_TOOLBAR, 0), w->left, PHD_DOWN); + PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_STATUS_BAR, 0), w->left, PHD_UP); + } + + if (w->viewport != NULL) { + w->viewport->left += nx - w->left; + w->viewport->top += ny - w->top; + } + + w->left = nx; + w->top = ny; +} + +/** + * Resize the window. + * Update all the widgets of a window based on their resize flags + * Both the areas of the old window and the new sized window are set dirty + * ensuring proper redrawal. + * @param w Window to resize + * @param delta_x Delta x-size of changed window (positive if larger, etc.) + * @param delta_y Delta y-size of changed window + * @param clamp_to_screen Whether to make sure the whole window stays visible + */ +void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen) +{ + if (delta_x != 0 || delta_y != 0) { + if (clamp_to_screen) { + /* Determine the new right/bottom position. If that is outside of the bounds of + * the resolution clamp it in such a manner that it stays within the bounds. */ + int new_right = w->left + w->width + delta_x; + int new_bottom = w->top + w->height + delta_y; + if (new_right >= (int)_cur_resolution.width) delta_x -= Ceil(new_right - _cur_resolution.width, max(1U, w->nested_root->resize_x)); + if (new_bottom >= (int)_cur_resolution.height) delta_y -= Ceil(new_bottom - _cur_resolution.height, max(1U, w->nested_root->resize_y)); + } + + w->SetDirty(); + + uint new_xinc = max(0, (w->nested_root->resize_x == 0) ? 0 : (int)(w->nested_root->current_x - w->nested_root->smallest_x) + delta_x); + uint new_yinc = max(0, (w->nested_root->resize_y == 0) ? 0 : (int)(w->nested_root->current_y - w->nested_root->smallest_y) + delta_y); + assert(w->nested_root->resize_x == 0 || new_xinc % w->nested_root->resize_x == 0); + assert(w->nested_root->resize_y == 0 || new_yinc % w->nested_root->resize_y == 0); + + w->nested_root->AssignSizePosition(ST_RESIZE, 0, 0, w->nested_root->smallest_x + new_xinc, w->nested_root->smallest_y + new_yinc, _current_text_dir == TD_RTL); + w->width = w->nested_root->current_x; + w->height = w->nested_root->current_y; + } + + EnsureVisibleCaption(w, w->left, w->top); + + /* Always call OnResize to make sure everything is initialised correctly if it needs to be. */ + w->OnResize(); + w->SetDirty(); +} + +/** + * Return the top of the main view available for general use. + * @return Uppermost vertical coordinate available. + * @note Above the upper y coordinate is often the main toolbar. + */ +int GetMainViewTop() +{ + Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); + return (w == NULL) ? 0 : w->top + w->height; +} + +/** + * Return the bottom of the main view available for general use. + * @return The vertical coordinate of the first unusable row, so 'top + height <= bottom' gives the correct result. + * @note At and below the bottom y coordinate is often the status bar. + */ +int GetMainViewBottom() +{ + Window *w = FindWindowById(WC_STATUS_BAR, 0); + return (w == NULL) ? _screen.height : w->top; +} + +static bool _dragging_window; ///< A window is being dragged or resized. + +/** + * Handle dragging/resizing of a window. + * @return State of handling the event. + */ +static EventState HandleWindowDragging() +{ + /* Get out immediately if no window is being dragged at all. */ + if (!_dragging_window) return ES_NOT_HANDLED; + + /* If button still down, but cursor hasn't moved, there is nothing to do. */ + if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; + + /* Otherwise find the window... */ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->flags & WF_DRAGGING) { + /* Stop the dragging if the left mouse button was released */ + if (!_left_button_down) { + w->flags &= ~WF_DRAGGING; + break; + } + + w->SetDirty(); + + int x = _cursor.pos.x + _drag_delta.x; + int y = _cursor.pos.y + _drag_delta.y; + int nx = x; + int ny = y; + + if (_settings_client.gui.window_snap_radius != 0) { + const Window *v; + + int hsnap = _settings_client.gui.window_snap_radius; + int vsnap = _settings_client.gui.window_snap_radius; + int delta; + + FOR_ALL_WINDOWS_FROM_BACK(v) { + if (v == w) continue; // Don't snap at yourself + + if (y + w->height > v->top && y < v->top + v->height) { + /* Your left border <-> other right border */ + delta = abs(v->left + v->width - x); + if (delta <= hsnap) { + nx = v->left + v->width; + hsnap = delta; + } + + /* Your right border <-> other left border */ + delta = abs(v->left - x - w->width); + if (delta <= hsnap) { + nx = v->left - w->width; + hsnap = delta; + } + } + + if (w->top + w->height >= v->top && w->top <= v->top + v->height) { + /* Your left border <-> other left border */ + delta = abs(v->left - x); + if (delta <= hsnap) { + nx = v->left; + hsnap = delta; + } + + /* Your right border <-> other right border */ + delta = abs(v->left + v->width - x - w->width); + if (delta <= hsnap) { + nx = v->left + v->width - w->width; + hsnap = delta; + } + } + + if (x + w->width > v->left && x < v->left + v->width) { + /* Your top border <-> other bottom border */ + delta = abs(v->top + v->height - y); + if (delta <= vsnap) { + ny = v->top + v->height; + vsnap = delta; + } + + /* Your bottom border <-> other top border */ + delta = abs(v->top - y - w->height); + if (delta <= vsnap) { + ny = v->top - w->height; + vsnap = delta; + } + } + + if (w->left + w->width >= v->left && w->left <= v->left + v->width) { + /* Your top border <-> other top border */ + delta = abs(v->top - y); + if (delta <= vsnap) { + ny = v->top; + vsnap = delta; + } + + /* Your bottom border <-> other bottom border */ + delta = abs(v->top + v->height - y - w->height); + if (delta <= vsnap) { + ny = v->top + v->height - w->height; + vsnap = delta; + } + } + } + } + + EnsureVisibleCaption(w, nx, ny); + + w->SetDirty(); + return ES_HANDLED; + } else if (w->flags & WF_SIZING) { + /* Stop the sizing if the left mouse button was released */ + if (!_left_button_down) { + w->flags &= ~WF_SIZING; + w->SetDirty(); + break; + } + + /* Compute difference in pixels between cursor position and reference point in the window. + * If resizing the left edge of the window, moving to the left makes the window bigger not smaller. + */ + int x, y = _cursor.pos.y - _drag_delta.y; + if (w->flags & WF_SIZING_LEFT) { + x = _drag_delta.x - _cursor.pos.x; + } else { + x = _cursor.pos.x - _drag_delta.x; + } + + /* resize.step_width and/or resize.step_height may be 0, which means no resize is possible. */ + if (w->resize.step_width == 0) x = 0; + if (w->resize.step_height == 0) y = 0; + + /* Check the resize button won't go past the bottom of the screen */ + if (w->top + w->height + y > _screen.height) { + y = _screen.height - w->height - w->top; + } + + /* X and Y has to go by step.. calculate it. + * The cast to int is necessary else x/y are implicitly casted to + * unsigned int, which won't work. */ + if (w->resize.step_width > 1) x -= x % (int)w->resize.step_width; + if (w->resize.step_height > 1) y -= y % (int)w->resize.step_height; + + /* Check that we don't go below the minimum set size */ + if ((int)w->width + x < (int)w->nested_root->smallest_x) { + x = w->nested_root->smallest_x - w->width; + } + if ((int)w->height + y < (int)w->nested_root->smallest_y) { + y = w->nested_root->smallest_y - w->height; + } + + /* Window already on size */ + if (x == 0 && y == 0) return ES_HANDLED; + + /* Now find the new cursor pos.. this is NOT _cursor, because we move in steps. */ + _drag_delta.y += y; + if ((w->flags & WF_SIZING_LEFT) && x != 0) { + _drag_delta.x -= x; // x > 0 -> window gets longer -> left-edge moves to left -> subtract x to get new position. + w->SetDirty(); + w->left -= x; // If dragging left edge, move left window edge in opposite direction by the same amount. + /* ResizeWindow() below ensures marking new position as dirty. */ + } else { + _drag_delta.x += x; + } + + /* ResizeWindow sets both pre- and after-size to dirty for redrawal */ + ResizeWindow(w, x, y); + return ES_HANDLED; + } + } + + _dragging_window = false; + return ES_HANDLED; +} + +/** + * Start window dragging + * @param w Window to start dragging + */ +static void StartWindowDrag(Window *w) +{ + w->flags |= WF_DRAGGING; + w->flags &= ~WF_CENTERED; + _dragging_window = true; + + _drag_delta.x = w->left - _cursor.pos.x; + _drag_delta.y = w->top - _cursor.pos.y; + + BringWindowToFront(w); + DeleteWindowById(WC_DROPDOWN_MENU, 0); +} + +/** + * Start resizing a window. + * @param w Window to start resizing. + * @param to_left Whether to drag towards the left or not + */ +static void StartWindowSizing(Window *w, bool to_left) +{ + w->flags |= to_left ? WF_SIZING_LEFT : WF_SIZING_RIGHT; + w->flags &= ~WF_CENTERED; + _dragging_window = true; + + _drag_delta.x = _cursor.pos.x; + _drag_delta.y = _cursor.pos.y; + + BringWindowToFront(w); + DeleteWindowById(WC_DROPDOWN_MENU, 0); +} + +/** + * handle scrollbar scrolling with the mouse. + * @return State of handling the event. + */ +static EventState HandleScrollbarScrolling() +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->scrolling_scrollbar >= 0) { + /* Abort if no button is clicked any more. */ + if (!_left_button_down) { + w->scrolling_scrollbar = -1; + w->SetDirty(); + return ES_HANDLED; + } + + int i; + NWidgetScrollbar *sb = w->GetWidget(w->scrolling_scrollbar); + bool rtl = false; + + if (sb->type == NWID_HSCROLLBAR) { + i = _cursor.pos.x - _cursorpos_drag_start.x; + rtl = _current_text_dir == TD_RTL; + } else { + i = _cursor.pos.y - _cursorpos_drag_start.y; + } + + if (sb->disp_flags & ND_SCROLLBAR_BTN) { + if (_scroller_click_timeout == 1) { + _scroller_click_timeout = 3; + sb->UpdatePosition(rtl == HasBit(sb->disp_flags, NDB_SCROLLBAR_UP) ? 1 : -1); + w->SetDirty(); + } + return ES_HANDLED; + } + + /* Find the item we want to move to and make sure it's inside bounds. */ + int pos = min(max(0, i + _scrollbar_start_pos) * sb->GetCount() / _scrollbar_size, max(0, sb->GetCount() - sb->GetCapacity())); + if (rtl) pos = max(0, sb->GetCount() - sb->GetCapacity() - pos); + if (pos != sb->GetPosition()) { + sb->SetPosition(pos); + w->SetDirty(); + } + return ES_HANDLED; + } + } + + return ES_NOT_HANDLED; +} + +/** + * Handle viewport scrolling with the mouse. + * @return State of handling the event. + */ +static EventState HandleViewportScroll() +{ + bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); + + if (!_scrolling_viewport) return ES_NOT_HANDLED; + + /* When we don't have a last scroll window we are starting to scroll. + * When the last scroll window and this are not the same we went + * outside of the window and should not left-mouse scroll anymore. */ + if (_last_scroll_window == NULL) _last_scroll_window = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); + + + if (_last_scroll_window == NULL || !(_right_button_down || scrollwheel_scrolling || + (_left_button_down && (_move_pressed || _settings_client.gui.left_mouse_btn_scrolling)))) { + _cursor.fix_at = false; + _scrolling_viewport = false; + _last_scroll_window = NULL; + return ES_NOT_HANDLED; + } + + if (_last_scroll_window == FindWindowById(WC_MAIN_WINDOW, 0) && _last_scroll_window->viewport->follow_vehicle != INVALID_VEHICLE) { + /* If the main window is following a vehicle, then first let go of it! */ + const Vehicle *veh = Vehicle::Get(_last_scroll_window->viewport->follow_vehicle); + ScrollMainWindowTo(veh->x_pos, veh->y_pos, veh->z_pos, true); // This also resets follow_vehicle + return ES_NOT_HANDLED; + } + + Point delta; + if (_settings_client.gui.reverse_scroll || (_settings_client.gui.left_mouse_btn_scrolling && _left_button_down)) { + delta.x = -_cursor.delta.x; + delta.y = -_cursor.delta.y; + } else { + delta.x = _cursor.delta.x; + delta.y = _cursor.delta.y; + } + + if (scrollwheel_scrolling) { + /* We are using scrollwheels for scrolling */ + delta.x = _cursor.h_wheel; + delta.y = _cursor.v_wheel; + _cursor.v_wheel = 0; + _cursor.h_wheel = 0; + } + + /* Create a scroll-event and send it to the window */ + if (delta.x != 0 || delta.y != 0) _last_scroll_window->OnScroll(delta); + + _cursor.delta.x = 0; + _cursor.delta.y = 0; + return ES_HANDLED; +} + +/** + * Check if a window can be made relative top-most window, and if so do + * it. If a window does not obscure any other windows, it will not + * be brought to the foreground. Also if the only obscuring windows + * are so-called system-windows, the window will not be moved. + * The function will return false when a child window of this window is a + * modal-popup; function returns a false and child window gets a white border + * @param w Window to bring relatively on-top + * @return false if the window has an active modal child, true otherwise + */ +static bool MaybeBringWindowToFront(Window *w) +{ + bool bring_to_front = false; + + if (w->window_class == WC_MAIN_WINDOW || + IsVitalWindow(w) || + w->window_class == WC_TOOLTIPS || + w->window_class == WC_DROPDOWN_MENU) { + return true; + } + + /* Use unshaded window size rather than current size for shaded windows. */ + int w_width = w->width; + int w_height = w->height; + if (w->IsShaded()) { + w_width = w->unshaded_size.width; + w_height = w->unshaded_size.height; + } + + Window *u; + FOR_ALL_WINDOWS_FROM_BACK_FROM(u, w->z_front) { + /* A modal child will prevent the activation of the parent window */ + if (u->parent == w && (u->window_desc->flags & WDF_MODAL)) { + u->SetWhiteBorder(); + u->SetDirty(); + return false; + } + + if (u->window_class == WC_MAIN_WINDOW || + IsVitalWindow(u) || + u->window_class == WC_TOOLTIPS || + u->window_class == WC_DROPDOWN_MENU) { + continue; + } + + /* Window sizes don't interfere, leave z-order alone */ + if (w->left + w_width <= u->left || + u->left + u->width <= w->left || + w->top + w_height <= u->top || + u->top + u->height <= w->top) { + continue; + } + + bring_to_front = true; + } + + if (bring_to_front) BringWindowToFront(w); + return true; +} + +/** + * Process keypress for editbox widget. + * @param wid Editbox widget. + * @param key the Unicode value of the key. + * @param keycode the untranslated key code including shift state. + * @return #ES_HANDLED if the key press has been handled and no other + * window should receive the event. + */ +EventState Window::HandleEditBoxKey(int wid, WChar key, uint16 keycode) +{ + QueryString *query = this->GetQueryString(wid); + if (query == NULL) return ES_NOT_HANDLED; + + int action = QueryString::ACTION_NOTHING; + + switch (query->text.HandleKeyPress(key, keycode)) { + case HKPR_EDITING: + this->SetWidgetDirty(wid); + this->OnEditboxChanged(wid); + break; + + case HKPR_CURSOR: + this->SetWidgetDirty(wid); + /* For the OSK also invalidate the parent window */ + if (this->window_class == WC_OSK) this->InvalidateData(); + break; + + case HKPR_CONFIRM: + if (this->window_class == WC_OSK) { + this->OnClick(Point(), WID_OSK_OK, 1); + } else if (query->ok_button >= 0) { + this->OnClick(Point(), query->ok_button, 1); + } else { + action = query->ok_button; + } + break; + + case HKPR_CANCEL: + if (this->window_class == WC_OSK) { + this->OnClick(Point(), WID_OSK_CANCEL, 1); + } else if (query->cancel_button >= 0) { + this->OnClick(Point(), query->cancel_button, 1); + } else { + action = query->cancel_button; + } + break; + + case HKPR_NOT_HANDLED: + return ES_NOT_HANDLED; + + default: break; + } + + switch (action) { + case QueryString::ACTION_DESELECT: + this->UnfocusFocusedWidget(); + break; + + case QueryString::ACTION_CLEAR: + if (query->text.bytes <= 1) { + /* If already empty, unfocus instead */ + this->UnfocusFocusedWidget(); + } else { + query->text.DeleteAll(); + this->SetWidgetDirty(wid); + this->OnEditboxChanged(wid); + } + break; + + default: + break; + } + + return ES_HANDLED; +} + +/** + * Handle keyboard input. + * @param keycode Virtual keycode of the key. + * @param key Unicode character of the key. + */ +void HandleKeypress(uint keycode, WChar key) +{ + /* World generation is multithreaded and messes with companies. + * But there is no company related window open anyway, so _current_company is not used. */ + assert(HasModalProgress() || IsLocalCompany()); + + /* + * The Unicode standard defines an area called the private use area. Code points in this + * area are reserved for private use and thus not portable between systems. For instance, + * Apple defines code points for the arrow keys in this area, but these are only printable + * on a system running OS X. We don't want these keys to show up in text fields and such, + * and thus we have to clear the unicode character when we encounter such a key. + */ + if (key >= 0xE000 && key <= 0xF8FF) key = 0; + + /* + * If both key and keycode is zero, we don't bother to process the event. + */ + if (key == 0 && keycode == 0) return; + + /* Check if the focused window has a focused editbox */ + if (EditBoxInGlobalFocus()) { + /* All input will in this case go to the focused editbox */ + if (_focused_window->window_class == WC_CONSOLE) { + if (_focused_window->OnKeyPress(key, keycode) == ES_HANDLED) return; + } else { + if (_focused_window->HandleEditBoxKey(_focused_window->nested_focus->index, key, keycode) == ES_HANDLED) return; + } + } + + /* Call the event, start with the uppermost window, but ignore the toolbar. */ + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if (w->window_class == WC_MAIN_TOOLBAR) continue; + if (w->window_desc->hotkeys != NULL) { + int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); + if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return; + } + if (w->OnKeyPress(key, keycode) == ES_HANDLED) return; + } + + w = FindWindowById(WC_MAIN_TOOLBAR, 0); + /* When there is no toolbar w is null, check for that */ + if (w != NULL) { + if (w->window_desc->hotkeys != NULL) { + int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); + if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return; + } + if (w->OnKeyPress(key, keycode) == ES_HANDLED) return; + } + + HandleGlobalHotkeys(key, keycode); +} + +/** + * State of CONTROL key has changed + */ +void HandleCtrlChanged() +{ + /* Call the event, start with the uppermost window. */ + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if (w->OnCTRLStateChange() == ES_HANDLED) return; + } +} + +/** + * Insert a text string at the cursor position into the edit box widget. + * @param wid Edit box widget. + * @param str Text string to insert. + */ +/* virtual */ void Window::InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) +{ + QueryString *query = this->GetQueryString(wid); + if (query == NULL) return; + + if (query->text.InsertString(str, marked, caret, insert_location, replacement_end) || marked) { + this->SetWidgetDirty(wid); + this->OnEditboxChanged(wid); + } +} + +/** + * Handle text input. + * @param str Text string to input. + * @param marked Is the input a marked composition string from an IME? + * @param caret Move the caret to this point in the insertion string. + */ +void HandleTextInput(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) +{ + if (!EditBoxInGlobalFocus()) return; + + _focused_window->InsertTextString(_focused_window->window_class == WC_CONSOLE ? 0 : _focused_window->nested_focus->index, str, marked, caret, insert_location, replacement_end); +} + +/** + * Local counter that is incremented each time an mouse input event is detected. + * The counter is used to stop auto-scrolling. + * @see HandleAutoscroll() + * @see HandleMouseEvents() + */ +static int _input_events_this_tick = 0; + +/** + * If needed and switched on, perform auto scrolling (automatically + * moving window contents when mouse is near edge of the window). + */ +static void HandleAutoscroll() +{ + if (_game_mode == GM_MENU || HasModalProgress()) return; + if (_settings_client.gui.auto_scrolling == VA_DISABLED) return; + if (_settings_client.gui.auto_scrolling == VA_MAIN_VIEWPORT_FULLSCREEN && !_fullscreen) return; + + int x = _cursor.pos.x; + int y = _cursor.pos.y; + Window *w = FindWindowFromPt(x, y); + if (w == NULL || w->flags & WF_DISABLE_VP_SCROLL) return; + if (_settings_client.gui.auto_scrolling != VA_EVERY_VIEWPORT && w->window_class != WC_MAIN_WINDOW) return; + + ViewPort *vp = IsPtInWindowViewport(w, x, y); + if (vp == NULL) return; + + x -= vp->left; + y -= vp->top; + + /* here allows scrolling in both x and y axis */ +#define scrollspeed 3 + if (x - 15 < 0) { + w->viewport->dest_scrollpos_x += ScaleByZoom((x - 15) * scrollspeed, vp->zoom); + } else if (15 - (vp->width - x) > 0) { + w->viewport->dest_scrollpos_x += ScaleByZoom((15 - (vp->width - x)) * scrollspeed, vp->zoom); + } + if (y - 15 < 0) { + w->viewport->dest_scrollpos_y += ScaleByZoom((y - 15) * scrollspeed, vp->zoom); + } else if (15 - (vp->height - y) > 0) { + w->viewport->dest_scrollpos_y += ScaleByZoom((15 - (vp->height - y)) * scrollspeed, vp->zoom); + } +#undef scrollspeed +} + +enum MouseClick { + MC_NONE = 0, + MC_LEFT, + MC_RIGHT, + MC_DOUBLE_LEFT, + MC_HOVER, + + MAX_OFFSET_DOUBLE_CLICK = 5, ///< How much the mouse is allowed to move to call it a double click + TIME_BETWEEN_DOUBLE_CLICK = 500, ///< Time between 2 left clicks before it becoming a double click, in ms + MAX_OFFSET_HOVER = 5, ///< Maximum mouse movement before stopping a hover event. +}; +extern EventState VpHandlePlaceSizingDrag(); + +static void ScrollMainViewport(int x, int y) +{ + if (_game_mode != GM_MENU) { + Window *w = FindWindowById(WC_MAIN_WINDOW, 0); + assert(w); + + w->viewport->dest_scrollpos_x += ScaleByZoom(x, w->viewport->zoom); + w->viewport->dest_scrollpos_y += ScaleByZoom(y, w->viewport->zoom); + } +} + +/** + * Describes all the different arrow key combinations the game allows + * when it is in scrolling mode. + * The real arrow keys are bitwise numbered as + * 1 = left + * 2 = up + * 4 = right + * 8 = down + */ +static const int8 scrollamt[16][2] = { + { 0, 0}, ///< no key specified + {-2, 0}, ///< 1 : left + { 0, -2}, ///< 2 : up + {-2, -1}, ///< 3 : left + up + { 2, 0}, ///< 4 : right + { 0, 0}, ///< 5 : left + right = nothing + { 2, -1}, ///< 6 : right + up + { 0, -2}, ///< 7 : right + left + up = up + { 0, 2}, ///< 8 : down + {-2, 1}, ///< 9 : down + left + { 0, 0}, ///< 10 : down + up = nothing + {-2, 0}, ///< 11 : left + up + down = left + { 2, 1}, ///< 12 : down + right + { 0, 2}, ///< 13 : left + right + down = down + { 2, 0}, ///< 14 : right + up + down = right + { 0, 0}, ///< 15 : left + up + right + down = nothing +}; + +static void HandleKeyScrolling() +{ + /* + * Check that any of the dirkeys is pressed and that the focused window + * doesn't have an edit-box as focused widget. + */ + if (_dirkeys && !EditBoxInGlobalFocus()) { + int factor = _shift_pressed ? 50 : 10; + ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor); + } +} + +static void MouseLoop(MouseClick click, int mousewheel) +{ + /* World generation is multithreaded and messes with companies. + * But there is no company related window open anyway, so _current_company is not used. */ + assert(HasModalProgress() || IsLocalCompany()); + + int x = _cursor.pos.x; + int y = _cursor.pos.y; + Window *w = FindWindowFromPt(x, y); + if (w == NULL) return; + ViewPort *vp = IsPtInWindowViewport(w, x, y); + + HandlePlacePresize(); + UpdateTileSelection(); + + if (VpHandlePlaceSizingDrag() == ES_HANDLED) return; + if (HandleMouseDragDrop() == ES_HANDLED) return; + if (HandleWindowDragging() == ES_HANDLED) return; + if (HandleScrollbarScrolling() == ES_HANDLED) return; + if (HandleViewportScroll() == ES_HANDLED) return; + + HandleMouseOver(); + + bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); + if (click == MC_NONE && mousewheel == 0 && !scrollwheel_scrolling) return; + + if (w == NULL) return; + + if (click != MC_NONE && click != MC_HOVER && !MaybeBringWindowToFront(w)) return; + + /* Don't allow any action in a viewport if either in menu or when having a modal progress window */ + if (vp != NULL && (_game_mode == GM_MENU || HasModalProgress())) return; + + if (mousewheel != 0) { + /* Send mousewheel event to window */ + w->OnMouseWheel(mousewheel); + + /* Dispatch a MouseWheelEvent for widgets if it is not a viewport */ + if (vp == NULL) DispatchMouseWheelEvent(w, w->nested_root->GetWidgetFromPos(x - w->left, y - w->top), mousewheel); + } + + if (vp != NULL) { + if (scrollwheel_scrolling) click = MC_RIGHT; // we are using the scrollwheel in a viewport, so we emulate right mouse button + switch (click) { + case MC_DOUBLE_LEFT: + case MC_LEFT: + DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite); + if (!HandleViewportClicked(vp, x, y) && + !(w->flags & WF_DISABLE_VP_SCROLL) && + (_settings_client.gui.left_mouse_btn_scrolling || _move_pressed)) { + _scrolling_viewport = true; + _cursor.fix_at = false; + } + break; + + case MC_RIGHT: + if (!(w->flags & WF_DISABLE_VP_SCROLL)) { + _scrolling_viewport = true; + _cursor.fix_at = true; + + /* clear 2D scrolling caches before we start a 2D scroll */ + _cursor.h_wheel = 0; + _cursor.v_wheel = 0; + } + break; + + default: + break; + } + } else { + switch (click) { + case MC_LEFT: + case MC_DOUBLE_LEFT: + DispatchLeftClickEvent(w, x - w->left, y - w->top, click == MC_DOUBLE_LEFT ? 2 : 1); + break; + + default: + if (!scrollwheel_scrolling || w == NULL || w->window_class != WC_SMALLMAP) break; + /* We try to use the scrollwheel to scroll since we didn't touch any of the buttons. + * Simulate a right button click so we can get started. */ + /* FALL THROUGH */ + + case MC_RIGHT: DispatchRightClickEvent(w, x - w->left, y - w->top); break; + + case MC_HOVER: DispatchHoverEvent(w, x - w->left, y - w->top); break; + } + } +} + +/** + * Handle a mouse event from the video driver + */ +void HandleMouseEvents() +{ + /* World generation is multithreaded and messes with companies. + * But there is no company related window open anyway, so _current_company is not used. */ + assert(HasModalProgress() || IsLocalCompany()); + + static int double_click_time = 0; + static Point double_click_pos = {0, 0}; + + /* Mouse event? */ + MouseClick click = MC_NONE; + if (_left_button_down && !_left_button_clicked) { + click = MC_LEFT; + if (double_click_time != 0 && _realtime_tick - double_click_time < TIME_BETWEEN_DOUBLE_CLICK && + double_click_pos.x != 0 && abs(_cursor.pos.x - double_click_pos.x) < MAX_OFFSET_DOUBLE_CLICK && + double_click_pos.y != 0 && abs(_cursor.pos.y - double_click_pos.y) < MAX_OFFSET_DOUBLE_CLICK) { + click = MC_DOUBLE_LEFT; + } + double_click_time = _realtime_tick; + double_click_pos = _cursor.pos; + _left_button_clicked = true; + _input_events_this_tick++; + } else if (_right_button_clicked) { + _right_button_clicked = false; + click = MC_RIGHT; + _input_events_this_tick++; + } + + int mousewheel = 0; + if (_cursor.wheel) { + mousewheel = _cursor.wheel; + _cursor.wheel = 0; + _input_events_this_tick++; + } + + static uint32 hover_time = 0; + static Point hover_pos = {0, 0}; + + if (_settings_client.gui.hover_delay > 0) { + if (!_cursor.in_window || click != MC_NONE || mousewheel != 0 || _left_button_down || _right_button_down || + hover_pos.x == 0 || abs(_cursor.pos.x - hover_pos.x) >= MAX_OFFSET_HOVER || + hover_pos.y == 0 || abs(_cursor.pos.y - hover_pos.y) >= MAX_OFFSET_HOVER) { + hover_pos = _cursor.pos; + hover_time = _realtime_tick; + _mouse_hovering = false; + } else { + if (hover_time != 0 && _realtime_tick > hover_time + _settings_client.gui.hover_delay * 1000) { + click = MC_HOVER; + _input_events_this_tick++; + _mouse_hovering = true; + } + } + } + + /* Handle sprite picker before any GUI interaction */ + if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW && _newgrf_debug_sprite_picker.click_time != _realtime_tick) { + /* Next realtime tick? Then redraw has finished */ + _newgrf_debug_sprite_picker.mode = SPM_NONE; + InvalidateWindowData(WC_SPRITE_ALIGNER, 0, 1); + } + + if (click == MC_LEFT && _newgrf_debug_sprite_picker.mode == SPM_WAIT_CLICK) { + /* Mark whole screen dirty, and wait for the next realtime tick, when drawing is finished. */ + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + _newgrf_debug_sprite_picker.clicked_pixel = blitter->MoveTo(_screen.dst_ptr, _cursor.pos.x, _cursor.pos.y); + _newgrf_debug_sprite_picker.click_time = _realtime_tick; + _newgrf_debug_sprite_picker.sprites.Clear(); + _newgrf_debug_sprite_picker.mode = SPM_REDRAW; + MarkWholeScreenDirty(); + } else { + MouseLoop(click, mousewheel); + } + + /* We have moved the mouse the required distance, + * no need to move it at any later time. */ + _cursor.delta.x = 0; + _cursor.delta.y = 0; +} + +/** + * Check the soft limit of deletable (non vital, non sticky) windows. + */ +static void CheckSoftLimit() +{ + if (_settings_client.gui.window_soft_limit == 0) return; + + for (;;) { + uint deletable_count = 0; + Window *w, *last_deletable = NULL; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if (w->window_class == WC_MAIN_WINDOW || IsVitalWindow(w) || (w->flags & WF_STICKY)) continue; + + last_deletable = w; + deletable_count++; + } + + /* We've not reached the soft limit yet. */ + if (deletable_count <= _settings_client.gui.window_soft_limit) break; + + assert(last_deletable != NULL); + delete last_deletable; + } +} + +/** + * Regular call from the global game loop + */ +void InputLoop() +{ + /* World generation is multithreaded and messes with companies. + * But there is no company related window open anyway, so _current_company is not used. */ + assert(HasModalProgress() || IsLocalCompany()); + + CheckSoftLimit(); + HandleKeyScrolling(); + + /* Do the actual free of the deleted windows. */ + for (Window *v = _z_front_window; v != NULL; /* nothing */) { + Window *w = v; + v = v->z_back; + + if (w->window_class != WC_INVALID) continue; + + RemoveWindowFromZOrdering(w); + free(w); + } + + if (_scroller_click_timeout != 0) _scroller_click_timeout--; + DecreaseWindowCounters(); + + if (_input_events_this_tick != 0) { + /* The input loop is called only once per GameLoop() - so we can clear the counter here */ + _input_events_this_tick = 0; + /* there were some inputs this tick, don't scroll ??? */ + return; + } + + /* HandleMouseEvents was already called for this tick */ + HandleMouseEvents(); + HandleAutoscroll(); +} + +/** + * Update the continuously changing contents of the windows, such as the viewports + */ +void UpdateWindows() +{ + Window *w; + + static int highlight_timer = 1; + if (--highlight_timer == 0) { + highlight_timer = 15; + _window_highlight_colour = !_window_highlight_colour; + } + + FOR_ALL_WINDOWS_FROM_FRONT(w) { + w->ProcessScheduledInvalidations(); + w->ProcessHighlightedInvalidations(); + } + + static int we4_timer = 0; + int t = we4_timer + 1; + + if (t >= 100) { + FOR_ALL_WINDOWS_FROM_FRONT(w) { + w->OnHundredthTick(); + } + t = 0; + } + we4_timer = t; + + FOR_ALL_WINDOWS_FROM_FRONT(w) { + if ((w->flags & WF_WHITE_BORDER) && --w->white_border_timer == 0) { + CLRBITS(w->flags, WF_WHITE_BORDER); + w->SetDirty(); + } + } + + DrawDirtyBlocks(); + + FOR_ALL_WINDOWS_FROM_BACK(w) { + /* Update viewport only if window is not shaded. */ + if (w->viewport != NULL && !w->IsShaded()) UpdateViewportPosition(w); + } + NetworkDrawChatMessage(); + /* Redraw mouse cursor in case it was hidden */ + DrawMouseCursor(); +} + +/** + * Mark window as dirty (in need of repainting) + * @param cls Window class + * @param number Window number in that class + */ +void SetWindowDirty(WindowClass cls, WindowNumber number) +{ + const Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls && w->window_number == number) w->SetDirty(); + } +} + +/** + * Mark a particular widget in a particular window as dirty (in need of repainting) + * @param cls Window class + * @param number Window number in that class + * @param widget_index Index number of the widget that needs repainting + */ +void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index) +{ + const Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls && w->window_number == number) { + w->SetWidgetDirty(widget_index); + } + } +} + +/** + * Mark all windows of a particular class as dirty (in need of repainting) + * @param cls Window class + */ +void SetWindowClassesDirty(WindowClass cls) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls) w->SetDirty(); + } +} + +/** + * Mark this window's data as invalid (in need of re-computing) + * @param data The data to invalidate with + * @param gui_scope Whether the function is called from GUI scope. + */ +void Window::InvalidateData(int data, bool gui_scope) +{ + this->SetDirty(); + if (!gui_scope) { + /* Schedule GUI-scope invalidation for next redraw. */ + *this->scheduled_invalidation_data.Append() = data; + } + this->OnInvalidateData(data, gui_scope); +} + +/** + * Process all scheduled invalidations. + */ +void Window::ProcessScheduledInvalidations() +{ + for (int *data = this->scheduled_invalidation_data.Begin(); this->window_class != WC_INVALID && data != this->scheduled_invalidation_data.End(); data++) { + this->OnInvalidateData(*data, true); + } + this->scheduled_invalidation_data.Clear(); +} + +/** + * Process all invalidation of highlighted widgets. + */ +void Window::ProcessHighlightedInvalidations() +{ + if ((this->flags & WF_HIGHLIGHTED) == 0) return; + + for (uint i = 0; i < this->nested_array_size; i++) { + if (this->IsWidgetHighlighted(i)) this->SetWidgetDirty(i); + } +} + +/** + * Mark window data of the window of a given class and specific window number as invalid (in need of re-computing) + * + * Note that by default the invalidation is not considered to be called from GUI scope. + * That means only a part of invalidation is executed immediately. The rest is scheduled for the next redraw. + * The asynchronous execution is important to prevent GUI code being executed from command scope. + * When not in GUI-scope: + * - OnInvalidateData() may not do test-runs on commands, as they might affect the execution of + * the command which triggered the invalidation. (town rating and such) + * - OnInvalidateData() may not rely on _current_company == _local_company. + * This implies that no NewGRF callbacks may be run. + * + * However, when invalidations are scheduled, then multiple calls may be scheduled before execution starts. Earlier scheduled + * invalidations may be called with invalidation-data, which is already invalid at the point of execution. + * That means some stuff requires to be executed immediately in command scope, while not everything may be executed in command + * scope. While GUI-scope calls have no restrictions on what they may do, they cannot assume the game to still be in the state + * when the invalidation was scheduled; passed IDs may have got invalid in the mean time. + * + * Finally, note that invalidations triggered from commands or the game loop result in OnInvalidateData() being called twice. + * Once in command-scope, once in GUI-scope. So make sure to not process differential-changes twice. + * + * @param cls Window class + * @param number Window number within the class + * @param data The data to invalidate with + * @param gui_scope Whether the call is done from GUI scope + */ +void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls && w->window_number == number) { + w->InvalidateData(data, gui_scope); + } + } +} + +/** + * Mark window data of all windows of a given class as invalid (in need of re-computing) + * Note that by default the invalidation is not considered to be called from GUI scope. + * See InvalidateWindowData() for details on GUI-scope vs. command-scope. + * @param cls Window class + * @param data The data to invalidate with + * @param gui_scope Whether the call is done from GUI scope + */ +void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope) +{ + Window *w; + + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls) { + w->InvalidateData(data, gui_scope); + } + } +} + +/** + * Dispatch WE_TICK event over all windows + */ +void CallWindowTickEvent() +{ + Window *w; + FOR_ALL_WINDOWS_FROM_FRONT(w) { + w->OnTick(); + } +} + +/** + * Try to delete a non-vital window. + * Non-vital windows are windows other than the game selection, main toolbar, + * status bar, toolbar menu, and tooltip windows. Stickied windows are also + * considered vital. + */ +void DeleteNonVitalWindows() +{ + Window *w; + +restart_search: + /* When we find the window to delete, we need to restart the search + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class != WC_MAIN_WINDOW && + w->window_class != WC_SELECT_GAME && + w->window_class != WC_MAIN_TOOLBAR && + w->window_class != WC_STATUS_BAR && + w->window_class != WC_TOOLTIPS && + (w->flags & WF_STICKY) == 0) { // do not delete windows which are 'pinned' + + delete w; + goto restart_search; + } + } +} + +/** + * It is possible that a stickied window gets to a position where the + * 'close' button is outside the gaming area. You cannot close it then; except + * with this function. It closes all windows calling the standard function, + * then, does a little hacked loop of closing all stickied windows. Note + * that standard windows (status bar, etc.) are not stickied, so these aren't affected + */ +void DeleteAllNonVitalWindows() +{ + Window *w; + + /* Delete every window except for stickied ones, then sticky ones as well */ + DeleteNonVitalWindows(); + +restart_search: + /* When we find the window to delete, we need to restart the search + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->flags & WF_STICKY) { + delete w; + goto restart_search; + } + } +} + +/** + * Delete all windows that are used for construction of vehicle etc. + * Once done with that invalidate the others to ensure they get refreshed too. + */ +void DeleteConstructionWindows() +{ + Window *w; + +restart_search: + /* When we find the window to delete, we need to restart the search + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_desc->flags & WDF_CONSTRUCTION) { + delete w; + goto restart_search; + } + } + + FOR_ALL_WINDOWS_FROM_BACK(w) w->SetDirty(); +} + +/** Delete all always on-top windows to get an empty screen */ +void HideVitalWindows() +{ + DeleteWindowById(WC_MAIN_TOOLBAR, 0); + DeleteWindowById(WC_STATUS_BAR, 0); +} + +/** Re-initialize all windows. */ +void ReInitAllWindows() +{ + NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets. + NWidgetScrollbar::InvalidateDimensionCache(); + + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + w->ReInit(); + } +#ifdef ENABLE_NETWORK + void NetworkReInitChatBoxSize(); + NetworkReInitChatBoxSize(); +#endif + + /* Make sure essential parts of all windows are visible */ + RelocateAllWindows(_cur_resolution.width, _cur_resolution.height); + MarkWholeScreenDirty(); +} + +/** + * (Re)position a window at the screen. + * @param w Window structure of the window, may also be \c NULL. + * @param clss The class of the window to position. + * @param setting The actual setting used for the window's position. + * @return X coordinate of left edge of the repositioned window. + */ +static int PositionWindow(Window *w, WindowClass clss, int setting) +{ + if (w == NULL || w->window_class != clss) { + w = FindWindowById(clss, 0); + } + if (w == NULL) return 0; + + int old_left = w->left; + switch (setting) { + case 1: w->left = (_screen.width - w->width) / 2; break; + case 2: w->left = _screen.width - w->width; break; + default: w->left = 0; break; + } + if (w->viewport != NULL) w->viewport->left += w->left - old_left; + SetDirtyBlocks(0, w->top, _screen.width, w->top + w->height); // invalidate the whole row + return w->left; +} + +/** + * (Re)position main toolbar window at the screen. + * @param w Window structure of the main toolbar window, may also be \c NULL. + * @return X coordinate of left edge of the repositioned toolbar window. + */ +int PositionMainToolbar(Window *w) +{ + DEBUG(misc, 5, "Repositioning Main Toolbar..."); + return PositionWindow(w, WC_MAIN_TOOLBAR, _settings_client.gui.toolbar_pos); +} + +/** + * (Re)position statusbar window at the screen. + * @param w Window structure of the statusbar window, may also be \c NULL. + * @return X coordinate of left edge of the repositioned statusbar. + */ +int PositionStatusbar(Window *w) +{ + DEBUG(misc, 5, "Repositioning statusbar..."); + return PositionWindow(w, WC_STATUS_BAR, _settings_client.gui.statusbar_pos); +} + +/** + * (Re)position news message window at the screen. + * @param w Window structure of the news message window, may also be \c NULL. + * @return X coordinate of left edge of the repositioned news message. + */ +int PositionNewsMessage(Window *w) +{ + DEBUG(misc, 5, "Repositioning news message..."); + return PositionWindow(w, WC_NEWS_WINDOW, _settings_client.gui.statusbar_pos); +} + +/** + * (Re)position network chat window at the screen. + * @param w Window structure of the network chat window, may also be \c NULL. + * @return X coordinate of left edge of the repositioned network chat window. + */ +int PositionNetworkChatWindow(Window *w) +{ + DEBUG(misc, 5, "Repositioning network chat window..."); + return PositionWindow(w, WC_SEND_NETWORK_MSG, _settings_client.gui.statusbar_pos); +} + + +/** + * Switches viewports following vehicles, which get autoreplaced + * @param from_index the old vehicle ID + * @param to_index the new vehicle ID + */ +void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index) +{ + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->viewport != NULL && w->viewport->follow_vehicle == from_index) { + w->viewport->follow_vehicle = to_index; + w->SetDirty(); + } + } +} + + +/** + * Relocate all windows to fit the new size of the game application screen + * @param neww New width of the game application screen + * @param newh New height of the game application screen. + */ +void RelocateAllWindows(int neww, int newh) +{ + Window *w; + + FOR_ALL_WINDOWS_FROM_BACK(w) { + int left, top; + /* XXX - this probably needs something more sane. For example specifying + * in a 'backup'-desc that the window should always be centered. */ + switch (w->window_class) { + case WC_MAIN_WINDOW: + case WC_BOOTSTRAP: + ResizeWindow(w, neww, newh); + continue; + + case WC_MAIN_TOOLBAR: + ResizeWindow(w, min(neww, w->window_desc->default_width) - w->width, 0, false); + + top = w->top; + left = PositionMainToolbar(w); // changes toolbar orientation + break; + + case WC_NEWS_WINDOW: + top = newh - w->height; + left = PositionNewsMessage(w); + break; + + case WC_STATUS_BAR: + ResizeWindow(w, min(neww, w->window_desc->default_width) - w->width, 0, false); + + top = newh - w->height; + left = PositionStatusbar(w); + break; + + case WC_SEND_NETWORK_MSG: + ResizeWindow(w, Clamp(neww, 320, 640) - w->width, 0, false); + top = newh - w->height - FindWindowById(WC_STATUS_BAR, 0)->height; + left = PositionNetworkChatWindow(w); + break; + + case WC_CONSOLE: + IConsoleResize(w); + continue; + + default: { + if (w->flags & WF_CENTERED) { + top = (newh - w->height) >> 1; + left = (neww - w->width) >> 1; + break; + } + + left = w->left; + if (left + (w->width >> 1) >= neww) left = neww - w->width; + if (left < 0) left = 0; + + top = w->top; + if (top + (w->height >> 1) >= newh) top = newh - w->height; + break; + } + } + + EnsureVisibleCaption(w, left, top); + } +} + +/** + * Destructor of the base class PickerWindowBase + * Main utility is to stop the base Window destructor from triggering + * a free while the child will already be free, in this case by the ResetObjectToPlace(). + */ +PickerWindowBase::~PickerWindowBase() +{ + this->window_class = WC_INVALID; // stop the ancestor from freeing the already (to be) child + ResetObjectToPlace(); +} From 02caad7c1b3e3e91bb14711fa5ad76ac0ec00080 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sun, 13 Oct 2013 13:46:59 +0000 Subject: [PATCH 061/187] Select the actions that will need confirmation. --- src/bridge_gui.cpp | 2 +- src/company_gui.cpp | 2 +- src/dock_gui.cpp | 12 ++++++------ src/object_gui.cpp | 2 +- src/rail_gui.cpp | 20 ++++++++++---------- src/road_gui.cpp | 10 +++++----- src/station_gui.cpp | 2 +- src/terraform_gui.cpp | 14 +++++++------- src/tree_gui.cpp | 2 +- 9 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp index 9ce304fed8..6834359d7a 100644 --- a/src/bridge_gui.cpp +++ b/src/bridge_gui.cpp @@ -383,7 +383,7 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo default: break; // water ways and air routes don't have bridge types } if (_ctrl_pressed && CheckBridgeAvailability(last_bridge_type, bridge_len).Succeeded()) { - DoCommandP(end, start, type | last_bridge_type, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge); + TouchCommandP(end, start, type | last_bridge_type, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge); return; } diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 3be6dec6be..498d3df51b 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -2366,7 +2366,7 @@ struct CompanyWindow : Window virtual void OnPlaceObject(Point pt, TileIndex tile) { - if (DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS))) { + if (TouchCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS))) { ResetObjectToPlace(); this->RaiseButtons(); } diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index de8016c2e5..bf8c1318d3 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -224,10 +224,10 @@ struct BuildDocksToolbarWindow : Window { GUIPlaceProcDragXY(select_proc, start_tile, end_tile); break; case DDSP_CREATE_WATER: - DoCommandP(end_tile, start_tile, (_game_mode == GM_EDITOR && _ctrl_pressed) ? WATER_CLASS_SEA : WATER_CLASS_CANAL, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_BUILD_CANALS), CcBuildCanal); + TouchCommandP(end_tile, start_tile, (_game_mode == GM_EDITOR && _ctrl_pressed) ? WATER_CLASS_SEA : WATER_CLASS_CANAL, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_BUILD_CANALS), CcBuildCanal); break; case DDSP_CREATE_RIVER: - DoCommandP(end_tile, start_tile, WATER_CLASS_RIVER, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_PLACE_RIVERS), CcBuildCanal); + TouchCommandP(end_tile, start_tile, WATER_CLASS_RIVER, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_PLACE_RIVERS), CcBuildCanal); break; case DDSP_BUILD_STATION: { uint32 p2 = (uint32)INVALID_STATION << 16; // no station to join @@ -242,14 +242,14 @@ struct BuildDocksToolbarWindow : Window { } case DDSP_BUILD_BRIDGE: - DoCommandP(start_tile, GetOtherAqueductEnd(start_tile), TRANSPORT_WATER << 15, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE), CcBuildBridge); + TouchCommandP(start_tile, GetOtherAqueductEnd(start_tile), TRANSPORT_WATER << 15, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE), CcBuildBridge); VpStartPreSizing(); break; case DDSP_REMOVE_TRUCKSTOP: { // Reusing for locks. TileIndex middle_tile = start_tile; if (start_tile != end_tile) middle_tile = TileAddByDiagDir(start_tile, DiagdirBetweenTiles(start_tile, end_tile)); - DoCommandP(middle_tile, 0, 0, CMD_BUILD_LOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_LOCKS), CcBuildDocks); + TouchCommandP(middle_tile, 0, 0, CMD_BUILD_LOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_LOCKS), CcBuildDocks); VpStartPreSizing(); break; } @@ -258,10 +258,10 @@ struct BuildDocksToolbarWindow : Window { assert(start_tile == end_tile); switch (last_clicked_widget) { case WID_DT_BUOY: - DoCommandP(end_tile, 0, 0, CMD_BUILD_BUOY | CMD_MSG(STR_ERROR_CAN_T_POSITION_BUOY_HERE), CcBuildDocks); + TouchCommandP(end_tile, 0, 0, CMD_BUILD_BUOY | CMD_MSG(STR_ERROR_CAN_T_POSITION_BUOY_HERE), CcBuildDocks); break; case WID_DT_DEPOT: // Build depot button - DoCommandP(end_tile, _ship_depot_direction, 0, CMD_BUILD_SHIP_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_SHIP_DEPOT), CcBuildDocks); + TouchCommandP(end_tile, _ship_depot_direction, 0, CMD_BUILD_SHIP_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_SHIP_DEPOT), CcBuildDocks); break; default: NOT_REACHED(); } diff --git a/src/object_gui.cpp b/src/object_gui.cpp index 29a9d0d5ef..ba4e4d07a3 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -499,5 +499,5 @@ void InitializeObjectGui() */ void PlaceProc_Object(TileIndex tile) { - DoCommandP(tile, ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index)->Index(), _selected_object_view, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_OBJECT), CcTerraform); + TouchCommandP(tile, ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index)->Index(), _selected_object_view, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_OBJECT), CcTerraform); } diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index b1eab4f805..2ec5aeddb6 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -91,7 +91,7 @@ void CcPlaySound1E(const CommandCost &result, TileIndex tile, uint32 p1, uint32 static void GenericPlaceRail(TileIndex tile, int cmd) { - DoCommandP(tile, _cur_railtype, cmd, + TouchCommandP(tile, _cur_railtype, cmd, _remove_button_clicked ? CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) : CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), @@ -213,7 +213,7 @@ static void GenericPlaceSignals(TileIndex tile) Track track = FindFirstTrack(trackbits); if (_remove_button_clicked) { - DoCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E); + TouchCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E); } else { const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); @@ -238,7 +238,7 @@ static void GenericPlaceSignals(TileIndex tile) SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]); } - DoCommandP(tile, p1, 0, CMD_BUILD_SIGNALS | + TouchCommandP(tile, p1, 0, CMD_BUILD_SIGNALS | CMD_MSG((w != NULL && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), CcPlaySound1E); } @@ -325,7 +325,7 @@ static void BuildRailClick_Remove(Window *w) static void DoRailroadTrack(int mode) { - DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), + TouchCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), _remove_button_clicked ? CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) : CMD_BUILD_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), @@ -380,7 +380,7 @@ static void HandleAutoSignalPlacement() /* _settings_client.gui.drag_signals_density is given as a parameter such that each user * in a network game can specify his/her own signal density */ - DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, + TouchCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, _remove_button_clicked ? CMD_REMOVE_SIGNAL_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM) : CMD_BUILD_SIGNAL_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), @@ -667,7 +667,7 @@ struct BuildRailToolbarWindow : Window { case WID_RAT_BUILD_TUNNEL: if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); else VpStartPreSizing(); - DoCommandP(end_tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel); + TouchCommandP(end_tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel); break; case WID_RAT_BUILD_BRIDGE: if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); @@ -690,7 +690,7 @@ struct BuildRailToolbarWindow : Window { break; case DDSP_CONVERT_RAIL: - DoCommandP(end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 0x10 : 0), CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound10); + TouchCommandP(end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 0x10 : 0), CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound10); break; case DDSP_BUILD_STATION: @@ -712,14 +712,14 @@ struct BuildRailToolbarWindow : Window { if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) { /* Station */ if (_remove_button_clicked) { - DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION), CcPlaySound1E); + TouchCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION), CcPlaySound1E); } else { HandleStationPlacement(start_tile, end_tile); } } else { /* Waypoint */ if (_remove_button_clicked) { - DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT), CcPlaySound1E); + TouchCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT), CcPlaySound1E); } else { TileArea ta(start_tile, end_tile); uint32 p1 = _cur_railtype | (select_method == VPM_FIX_X ? AXIS_X : AXIS_Y) << 4 | ta.w << 8 | ta.h << 16 | _ctrl_pressed << 24; @@ -734,7 +734,7 @@ struct BuildRailToolbarWindow : Window { case DDSP_SINGLE_TILE: assert(end_tile == start_tile); assert(last_user_action == WID_RAT_BUILD_DEPOT); - DoCommandP(end_tile, _cur_railtype, _build_depot_direction, + TouchCommandP(end_tile, _cur_railtype, _build_depot_direction, CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT), CcRailDepot); break; diff --git a/src/road_gui.cpp b/src/road_gui.cpp index f5266ff9fd..ff8b9c8fea 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -585,7 +585,7 @@ struct BuildRoadToolbarWindow : Window { case WID_ROT_BUILD_TUNNEL: if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); else VpStartPreSizing(); - DoCommandP(end_tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, + TouchCommandP(end_tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRoadTunnel); break; case WID_ROT_BUILD_BRIDGE: @@ -609,7 +609,7 @@ struct BuildRoadToolbarWindow : Window { * not the 3rd bit set) */ _place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3)); - DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), + TouchCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), _remove_button_clicked ? CMD_REMOVE_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) : CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound1D); @@ -625,13 +625,13 @@ struct BuildRoadToolbarWindow : Window { case DDSP_REMOVE_BUSSTOP: { TileArea ta(start_tile, end_tile); - DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound1D); + TouchCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound1D); break; } case DDSP_REMOVE_TRUCKSTOP: { TileArea ta(start_tile, end_tile); - DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound1D); + TouchCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound1D); break; } @@ -639,7 +639,7 @@ struct BuildRoadToolbarWindow : Window { /* Build depot. */ assert(start_tile == end_tile); assert(last_started_action == WID_ROT_DEPOT); - DoCommandP(start_tile, _cur_roadtype << 2 | _road_depot_orientation, 0, + TouchCommandP(start_tile, _cur_roadtype << 2 | _road_depot_orientation, 0, CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot); break; } diff --git a/src/station_gui.cpp b/src/station_gui.cpp index f6b1d1f804..2b77470654 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -2427,7 +2427,7 @@ void ShowSelectBaseStationIfNeeded(const CommandContainer &cmd, TileArea ta) if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); new SelectStationWindow(&_select_station_desc, cmd, ta); } else { - DoCommandP(&cmd); + TouchCommandP(&cmd); } } diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index c711026c56..3bdccf8f24 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -111,16 +111,16 @@ bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_t switch (proc) { case DDSP_DEMOLISH_AREA: - DoCommandP(end_tile, start_tile, _ctrl_pressed ? 1 : 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound10); + TouchCommandP(end_tile, start_tile, _ctrl_pressed ? 1 : 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound10); break; case DDSP_RAISE_AND_LEVEL_AREA: - DoCommandP(end_tile, start_tile, LM_RAISE << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_RAISE_LAND_HERE), CcTerraform); + TouchCommandP(end_tile, start_tile, LM_RAISE << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_RAISE_LAND_HERE), CcTerraform); break; case DDSP_LOWER_AND_LEVEL_AREA: - DoCommandP(end_tile, start_tile, LM_LOWER << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LOWER_LAND_HERE), CcTerraform); + TouchCommandP(end_tile, start_tile, LM_LOWER << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LOWER_LAND_HERE), CcTerraform); break; case DDSP_LEVEL_AREA: - DoCommandP(end_tile, start_tile, LM_LEVEL << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LEVEL_LAND_HERE), CcTerraform); + TouchCommandP(end_tile, start_tile, LM_LEVEL << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LEVEL_LAND_HERE), CcTerraform); break; case DDSP_CREATE_ROCKS: GenerateRockyArea(end_tile, start_tile); @@ -270,7 +270,7 @@ struct TerraformToolbarWindow : Window { assert(start_tile == end_tile); switch (this->last_user_action) { case WID_TT_BUY_LAND: - DoCommandP(end_tile, OBJECT_OWNED_LAND, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_PURCHASE_THIS_LAND), CcPlaySound1E); + TouchCommandP(end_tile, OBJECT_OWNED_LAND, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_PURCHASE_THIS_LAND), CcPlaySound1E); break; case WID_TT_PLACE_SIGN: PlaceProc_Sign(end_tile); @@ -404,7 +404,7 @@ static void CommonRaiseLowerBigLand(TileIndex tile, int mode) StringID msg = mode ? STR_ERROR_CAN_T_RAISE_LAND_HERE : STR_ERROR_CAN_T_LOWER_LAND_HERE; - DoCommandP(tile, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND | CMD_MSG(msg), CcTerraform); + TouchCommandP(tile, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND | CMD_MSG(msg), CcTerraform); } else { assert(_terraform_size != 0); TileArea ta(tile, _terraform_size, _terraform_size); @@ -431,7 +431,7 @@ static void CommonRaiseLowerBigLand(TileIndex tile, int mode) TILE_AREA_LOOP(tile2, ta) { if (TileHeight(tile2) == h) { - DoCommandP(tile2, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND); + TouchCommandP(tile2, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND); } } } diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index 51ed85e7b7..2322e50460 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -160,7 +160,7 @@ public: virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) { if (pt.x != -1 && select_proc == DDSP_PLANT_TREES) { - DoCommandP(end_tile, this->tree_to_plant, start_tile, + TouchCommandP(end_tile, this->tree_to_plant, start_tile, CMD_PLANT_TREE | CMD_MSG(STR_ERROR_CAN_T_PLANT_TREE_HERE)); } } From b164486616a30356da2c1bda87a0a3cd10196d3f Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 14 Oct 2013 17:49:14 +0000 Subject: [PATCH 062/187] Reset queued command when closing windows that can queue them. --- src/airport_gui.cpp | 4 +++- src/dock_gui.cpp | 3 +++ src/rail_gui.cpp | 2 ++ src/road_gui.cpp | 3 +++ src/terraform_gui.cpp | 1 + src/tree_gui.cpp | 1 + 6 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index ddef5249cb..3da2f36ea3 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -28,6 +28,7 @@ #include "hotkeys.h" #include "vehicle_func.h" #include "gui.h" +#include "command_func.h" #include "widgets/airport_widget.h" @@ -142,7 +143,7 @@ struct BuildAirToolbarWindow : Window { DeleteWindowById(WC_BUILD_STATION, TRANSPORT_AIR); DeleteWindowById(WC_SELECT_STATION, 0); - + EraseQueuedTouchCommand(); ResetObjectToPlace(); } @@ -243,6 +244,7 @@ public: virtual ~BuildAirportWindow() { + EraseQueuedTouchCommand(); DeleteWindowById(WC_SELECT_STATION, 0); } diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index bf8c1318d3..59bc306f61 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -103,6 +103,7 @@ struct BuildDocksToolbarWindow : Window { ~BuildDocksToolbarWindow() { + if (_thd.GetCallbackWnd() == this) this->OnPlaceObjectAbort(); if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } @@ -279,6 +280,7 @@ struct BuildDocksToolbarWindow : Window { DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_WATER); DeleteWindowById(WC_SELECT_STATION, 0); DeleteWindowByClass(WC_BUILD_BRIDGE); + EraseQueuedTouchCommand(); } virtual void OnPlacePresize(Point pt, TileIndex tile_from) @@ -551,6 +553,7 @@ public: this->LowerWidget(_ship_depot_direction + WID_BDD_X); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); UpdateDocksDirection(); + EraseQueuedTouchCommand(); this->SetDirty(); break; } diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 2ec5aeddb6..e80ea4c3a4 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -405,6 +405,7 @@ struct BuildRailToolbarWindow : Window { ~BuildRailToolbarWindow() { + if (_thd.GetCallbackWnd() == this) this->OnPlaceObjectAbort(); if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } @@ -754,6 +755,7 @@ struct BuildRailToolbarWindow : Window { DeleteWindowById(WC_BUILD_WAYPOINT, TRANSPORT_RAIL); DeleteWindowById(WC_SELECT_STATION, 0); DeleteWindowByClass(WC_BUILD_BRIDGE); + EraseQueuedTouchCommand(); } virtual void OnPlacePresize(Point pt, TileIndex tile_from) diff --git a/src/road_gui.cpp b/src/road_gui.cpp index ff8b9c8fea..f4c0030133 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -309,6 +309,7 @@ struct BuildRoadToolbarWindow : Window { ~BuildRoadToolbarWindow() { + if (_thd.GetCallbackWnd() == this) this->OnPlaceObjectAbort(); if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } @@ -531,6 +532,7 @@ struct BuildRoadToolbarWindow : Window { DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_ROAD); DeleteWindowById(WC_SELECT_STATION, 0); DeleteWindowByClass(WC_BUILD_BRIDGE); + EraseQueuedTouchCommand(); } virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) @@ -1016,6 +1018,7 @@ struct BuildRoadStationWindow : public PickerWindowBase { if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); DeleteWindowById(WC_SELECT_STATION, 0); + EraseQueuedTouchCommand(); break; case WID_BROS_LT_OFF: diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index 3bdccf8f24..ebc7afdf2c 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -288,6 +288,7 @@ struct TerraformToolbarWindow : Window { { DeleteWindowById(WC_BUILD_OBJECT, 0); this->RaiseButtons(); + EraseQueuedTouchCommand(); ResetObjectToPlace(); } diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index 2322e50460..165635da2f 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -179,6 +179,7 @@ public: this->RaiseButtons(); ResetObjectToPlace(); + EraseQueuedTouchCommand(); } }; From fc248814fe827edffd971ae8b14969d6fa05a0e0 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 14 Oct 2013 17:49:32 +0000 Subject: [PATCH 063/187] Reset queued command when changing CTRL state. --- src/toolbar_gui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 20f66d98a4..0226d61dce 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -2259,6 +2259,7 @@ struct TabletToolbar : Window { this->ToggleWidgetLoweredState(WID_TT_CTRL); HandleCtrlChanged(); this->SetWidgetDirty(WID_TT_CTRL); + EraseQueuedTouchCommand(); break; case WID_TT_MOVE: _move_pressed = !_move_pressed; From 60a7ac9f3c1d4f271f4392859d68df875d612fe7 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 14 Oct 2013 18:10:26 +0000 Subject: [PATCH 064/187] Erase queued command also when depot direction/airport type/station type changes. --- src/airport_gui.cpp | 2 ++ src/dock_gui.cpp | 1 + src/rail_gui.cpp | 3 +++ src/road_gui.cpp | 2 ++ 4 files changed, 8 insertions(+) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 3da2f36ea3..68c0b773cc 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -423,6 +423,8 @@ public: void UpdateSelectSize() { + EraseQueuedTouchCommand(); + if (_selected_airport_index == -1) { SetTileSelectSize(1, 1); this->DisableWidget(WID_AP_LAYOUT_DECREASE); diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index 59bc306f61..4e0c47d0b6 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -474,6 +474,7 @@ public: _settings_client.gui.station_show_coverage = (widget != BDSW_LT_OFF); this->LowerWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + EraseQueuedTouchCommand(); this->SetDirty(); break; } diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index e80ea4c3a4..66facac60b 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1369,6 +1369,8 @@ public: break; } } + + EraseQueuedTouchCommand(); } virtual void OnTick() @@ -1723,6 +1725,7 @@ struct BuildRailDepotWindow : public PickerWindowBase { _build_depot_direction = (DiagDirection)(widget - WID_BRAD_DEPOT_NE); this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + EraseQueuedTouchCommand(); this->SetDirty(); break; } diff --git a/src/road_gui.cpp b/src/road_gui.cpp index f4c0030133..6678407a82 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -881,6 +881,7 @@ struct BuildRoadDepotWindow : public PickerWindowBase { _road_depot_orientation = (DiagDirection)(widget - WID_BROD_DEPOT_NE); this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + EraseQueuedTouchCommand(); this->SetDirty(); break; @@ -1027,6 +1028,7 @@ struct BuildRoadStationWindow : public PickerWindowBase { _settings_client.gui.station_show_coverage = (widget != WID_BROS_LT_OFF); this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + EraseQueuedTouchCommand(); this->SetDirty(); break; From 604205045f393f1b80114da5f7d29ed79d7acc3f Mon Sep 17 00:00:00 2001 From: Juanjo Date: Mon, 14 Oct 2013 19:24:30 +0000 Subject: [PATCH 065/187] Erase queued commands when another command is about to be queued. --- src/airport_gui.cpp | 1 + src/dock_gui.cpp | 1 + src/rail_gui.cpp | 1 + src/road_gui.cpp | 1 + src/terraform_gui.cpp | 1 + src/tree_gui.cpp | 1 + 6 files changed, 6 insertions(+) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 68c0b773cc..604aa0647b 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -103,6 +103,7 @@ struct BuildAirToolbarWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { + EraseQueuedTouchCommand(); switch (this->last_user_action) { case WID_AT_AIRPORT: { VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_BUILD_STATION); diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index 4e0c47d0b6..a968a44823 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -168,6 +168,7 @@ struct BuildDocksToolbarWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { + EraseQueuedTouchCommand(); switch (this->last_clicked_widget) { case WID_DT_CANAL: // Build canal button VpStartPlaceSizing(tile, (_game_mode == GM_EDITOR) ? VPM_X_AND_Y : VPM_X_OR_Y, DDSP_CREATE_WATER); diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 66facac60b..f91d987f4e 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -583,6 +583,7 @@ struct BuildRailToolbarWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { + EraseQueuedTouchCommand(); switch (this->last_user_action) { case WID_RAT_BUILD_NS: VpStartPlaceSizing(tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL); diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 6678407a82..7526216f4b 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -467,6 +467,7 @@ struct BuildRoadToolbarWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { + EraseQueuedTouchCommand(); _remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE); _one_way_button_clicked = this->IsWidgetLowered(WID_ROT_ONE_WAY); switch (this->last_started_action) { diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index ebc7afdf2c..4efce0b131 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -655,6 +655,7 @@ struct ScenarioEditorLandscapeGenerationWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { + EraseQueuedTouchCommand(); switch (this->last_user_action) { case WID_ETT_DEMOLISH: // Demolish aka dynamite button PlaceProc_DemolishArea(tile); diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index 165635da2f..8a9abeb82b 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -149,6 +149,7 @@ public: virtual void OnPlaceObject(Point pt, TileIndex tile) { + EraseQueuedTouchCommand(); VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_PLANT_TREES); } From 7079e675bf60cb708553f7969b353bf37d2e5d0d Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 19 Oct 2013 11:40:00 +0000 Subject: [PATCH 066/187] Align construction windows with main toolbar. --- src/dock_gui.cpp | 2 +- src/industry_gui.cpp | 2 +- src/road_gui.cpp | 2 +- src/terraform_gui.cpp | 2 +- src/town_gui.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index a968a44823..fae125aa9b 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -402,7 +402,7 @@ static const NWidgetPart _nested_build_docks_scen_toolbar_widgets[] = { /** Window definition for the build docks in scenario editor window. */ static WindowDesc _build_docks_scen_toolbar_desc( - WDP_AUTO, "toolbar_water_scen", 0, 0, + WDP_ALIGN_TOOLBAR, "toolbar_water_scen", 0, 0, WC_SCEN_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_docks_scen_toolbar_widgets, lengthof(_nested_build_docks_scen_toolbar_widgets) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 2a0ff6cd30..f919da1ebe 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -189,7 +189,7 @@ static const NWidgetPart _nested_build_industry_widgets[] = { /** Window definition of the dynamic place industries gui */ static WindowDesc _build_industry_desc( - WDP_AUTO, "build_industry", 170, 212, + WDP_ALIGN_TOOLBAR, "build_industry", 170, 212, WC_BUILD_INDUSTRY, WC_NONE, WDF_CONSTRUCTION, _nested_build_industry_widgets, lengthof(_nested_build_industry_widgets) diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 7526216f4b..5d08eede13 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -833,7 +833,7 @@ static const NWidgetPart _nested_build_road_scen_widgets[] = { }; static WindowDesc _build_road_scen_desc( - WDP_AUTO, "toolbar_road_scen", 0, 0, + WDP_ALIGN_TOOLBAR, "toolbar_road_scen", 0, 0, WC_SCEN_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_road_scen_widgets, lengthof(_nested_build_road_scen_widgets), diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index 4efce0b131..9f77cc6dcb 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -748,7 +748,7 @@ static Hotkey terraform_editor_hotkeys[] = { HotkeyList ScenarioEditorLandscapeGenerationWindow::hotkeys("terraform_editor", terraform_editor_hotkeys, TerraformToolbarEditorGlobalHotkeys); static WindowDesc _scen_edit_land_gen_desc( - WDP_AUTO, "toolbar_landscape_scen", 0, 0, + WDP_ALIGN_TOOLBAR, "toolbar_landscape_scen", 0, 0, WC_SCEN_LAND_GEN, WC_NONE, WDF_CONSTRUCTION, _nested_scen_edit_land_gen_widgets, lengthof(_nested_scen_edit_land_gen_widgets), diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 8d6c081af6..93300f15b4 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -1201,7 +1201,7 @@ public: }; static WindowDesc _found_town_desc( - WDP_AUTO, "build_town", 160, 162, + WDP_ALIGN_TOOLBAR, "build_town", 160, 162, WC_FOUND_TOWN, WC_NONE, WDF_CONSTRUCTION, _nested_found_town_widgets, lengthof(_nested_found_town_widgets) From edb6c09c64e2a4f9f4fa3d48c0521e2b2e464101 Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 19 Oct 2013 11:47:55 +0000 Subject: [PATCH 067/187] When in touchscreen modes, windows aligned with main toolbar are aligned to the left/right edge of the screen. --- src/window.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/window.cpp b/src/window.cpp index cad3e3ca31..1b357a5f69 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1655,7 +1655,13 @@ Point GetToolbarAlignedWindowPosition(int window_width) { const Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); assert(w != NULL); - Point pt = { _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width, w->top + w->height }; + Point pt; + pt.y = w->top + w->height; + if (_settings_client.gui.touchscreen_mode != TSC_NONE) { + pt.x = _current_text_dir == TD_RTL ? 0 : (_screen.width - window_width); + } else { + pt.x = _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width; + } return pt; } From 0de2e2a6642343161ff90e8864a9d0018f27291c Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 19 Oct 2013 13:35:17 +0000 Subject: [PATCH 068/187] Add a function for deleting windows linked to main toolbar. --- src/window.cpp | 22 ++++++++++++++++++++++ src/window_func.h | 1 + 2 files changed, 23 insertions(+) diff --git a/src/window.cpp b/src/window.cpp index 1b357a5f69..715c8ca2cd 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -3344,6 +3344,28 @@ restart_search: FOR_ALL_WINDOWS_FROM_BACK(w) w->SetDirty(); } +/** + * Delete all windows that are linked to the main toolbar. + * Once done with that, refresh other windows too. + */ +void DeleteToolbarLinkedWindows() +{ + Window *w; + +restart_search: + /* When we find the window to delete, we need to restart the search + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_desc->default_pos == WDP_ALIGN_TOOLBAR) { + delete w; + goto restart_search; + } + } + + FOR_ALL_WINDOWS_FROM_BACK(w) w->SetDirty(); +} + /** Delete all always on-top windows to get an empty screen */ void HideVitalWindows() { diff --git a/src/window_func.h b/src/window_func.h index a0fff7c098..335ab9eae3 100644 --- a/src/window_func.h +++ b/src/window_func.h @@ -42,6 +42,7 @@ void InvalidateWindowClassesData(WindowClass cls, int data = 0, bool gui_scope = void DeleteNonVitalWindows(); void DeleteAllNonVitalWindows(); void DeleteConstructionWindows(); +void DeleteToolbarLinkedWindows(); void HideVitalWindows(); void ShowVitalWindows(); From 141bb0861e5960b07eab2b0b47d725db4c5897bf Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 19 Oct 2013 19:23:15 +0000 Subject: [PATCH 069/187] Before opening linked to main toolbar windows, delete linked windows. --- src/airport_gui.cpp | 2 +- src/dock_gui.cpp | 3 +- src/industry_gui.cpp | 2 +- src/rail_gui.cpp | 2 +- src/road_gui.cpp | 3 +- src/script/api/game/game_window.hpp.sq.orig | 1334 ------- src/terraform_gui.cpp | 2 + src/town_gui.cpp | 1 + src/window.cpp.orig | 3527 ------------------- 9 files changed, 10 insertions(+), 4866 deletions(-) delete mode 100644 src/script/api/game/game_window.hpp.sq.orig delete mode 100644 src/window.cpp.orig diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 604aa0647b..3eb0d29402 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -203,7 +203,7 @@ Window *ShowBuildAirToolbar() { if (!Company::IsValidID(_local_company)) return NULL; - DeleteWindowByClass(WC_BUILD_TOOLBAR); + DeleteToolbarLinkedWindows(); return AllocateWindowDescFront(&_air_toolbar_desc, TRANSPORT_AIR); } diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index fae125aa9b..2a73ae614b 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -376,7 +376,7 @@ Window *ShowBuildDocksToolbar() { if (!Company::IsValidID(_local_company)) return NULL; - DeleteWindowByClass(WC_BUILD_TOOLBAR); + DeleteToolbarLinkedWindows(); return AllocateWindowDescFront(&_build_docks_toolbar_desc, TRANSPORT_WATER); } @@ -415,6 +415,7 @@ static WindowDesc _build_docks_scen_toolbar_desc( */ Window *ShowBuildDocksScenToolbar() { + DeleteToolbarLinkedWindows(); return AllocateWindowDescFront(&_build_docks_scen_toolbar_desc, TRANSPORT_WATER); } diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index f919da1ebe..5b264e6ffc 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -645,7 +645,7 @@ public: void ShowBuildIndustryWindow() { if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return; - if (BringWindowToFrontById(WC_BUILD_INDUSTRY, 0)) return; + DeleteToolbarLinkedWindows(); new BuildIndustryWindow(); } diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index f91d987f4e..b2439d6ee9 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -882,7 +882,7 @@ Window *ShowBuildRailToolbar(RailType railtype) if (!Company::IsValidID(_local_company)) return NULL; if (!ValParamRailtype(railtype)) return NULL; - DeleteWindowByClass(WC_BUILD_TOOLBAR); + DeleteToolbarLinkedWindows(); _cur_railtype = railtype; _remove_button_clicked = false; return new BuildRailToolbarWindow(&_build_rail_desc, railtype); diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 5d08eede13..d2f82ae43a 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -801,7 +801,7 @@ Window *ShowBuildRoadToolbar(RoadType roadtype) if (!Company::IsValidID(_local_company)) return NULL; _cur_roadtype = roadtype; - DeleteWindowByClass(WC_BUILD_TOOLBAR); + DeleteToolbarLinkedWindows(); return AllocateWindowDescFront(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD); } @@ -846,6 +846,7 @@ static WindowDesc _build_road_scen_desc( */ Window *ShowBuildRoadScenToolbar() { + DeleteToolbarLinkedWindows(); _cur_roadtype = ROADTYPE_ROAD; return AllocateWindowDescFront(&_build_road_scen_desc, TRANSPORT_ROAD); } diff --git a/src/script/api/game/game_window.hpp.sq.orig b/src/script/api/game/game_window.hpp.sq.orig deleted file mode 100644 index 231e29b667..0000000000 --- a/src/script/api/game/game_window.hpp.sq.orig +++ /dev/null @@ -1,1334 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ - -#include "../script_window.hpp" -#include "../template/template_window.hpp.sq" - - -template <> const char *GetClassName() { return "GSWindow"; } - -void SQGSWindow_Register(Squirrel *engine) -{ - DefSQClass SQGSWindow("GSWindow"); - SQGSWindow.PreRegister(engine); - SQGSWindow.AddConstructor(engine, "x"); - - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_AI, "WN_GAME_OPTIONS_AI"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_ABOUT, "WN_GAME_OPTIONS_ABOUT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_NEWGRF_STATE, "WN_GAME_OPTIONS_NEWGRF_STATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_GAME_OPTIONS, "WN_GAME_OPTIONS_GAME_OPTIONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_GAME_SETTINGS, "WN_GAME_OPTIONS_GAME_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_QUERY_STRING, "WN_QUERY_STRING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_QUERY_STRING_SIGN, "WN_QUERY_STRING_SIGN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_CONFIRM_POPUP_QUERY, "WN_CONFIRM_POPUP_QUERY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_CONFIRM_POPUP_QUERY_BOOTSTRAP, "WN_CONFIRM_POPUP_QUERY_BOOTSTRAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_GAME, "WN_NETWORK_WINDOW_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_LOBBY, "WN_NETWORK_WINDOW_LOBBY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_CONTENT_LIST, "WN_NETWORK_WINDOW_CONTENT_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_START, "WN_NETWORK_WINDOW_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_STATUS_WINDOW_JOIN, "WN_NETWORK_STATUS_WINDOW_JOIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD, "WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NONE, "WC_NONE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_WINDOW, "WC_MAIN_WINDOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_TOOLBAR, "WC_MAIN_TOOLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATUS_BAR, "WC_STATUS_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TABLET_BAR, "WC_TABLET_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TOOLBAR, "WC_BUILD_TOOLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_BUILD_TOOLBAR, "WC_SCEN_BUILD_TOOLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TREES, "WC_BUILD_TREES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRANSPARENCY_TOOLBAR, "WC_TRANSPARENCY_TOOLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_SIGNAL, "WC_BUILD_SIGNAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SMALLMAP, "WC_SMALLMAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ERRMSG, "WC_ERRMSG"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOOLTIPS, "WC_TOOLTIPS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_QUERY_STRING, "WC_QUERY_STRING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CONFIRM_POPUP_QUERY, "WC_CONFIRM_POPUP_QUERY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GOAL_QUESTION, "WC_GOAL_QUESTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SAVELOAD, "WC_SAVELOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_LAND_INFO, "WC_LAND_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_DROPDOWN_MENU, "WC_DROPDOWN_MENU"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_OSK, "WC_OSK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SET_DATE, "WC_SET_DATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_SETTINGS, "WC_AI_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GRF_PARAMETERS, "WC_GRF_PARAMETERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TEXTFILE, "WC_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_AUTHORITY, "WC_TOWN_AUTHORITY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_DETAILS, "WC_VEHICLE_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_REFIT, "WC_VEHICLE_REFIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_ORDERS, "WC_VEHICLE_ORDERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_REPLACE_VEHICLE, "WC_REPLACE_VEHICLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_TIMETABLE, "WC_VEHICLE_TIMETABLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_COLOUR, "WC_COMPANY_COLOUR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_MANAGER_FACE, "WC_COMPANY_MANAGER_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_STATION, "WC_SELECT_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NEWS_WINDOW, "WC_NEWS_WINDOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_DIRECTORY, "WC_TOWN_DIRECTORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SUBSIDIES_LIST, "WC_SUBSIDIES_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_DIRECTORY, "WC_INDUSTRY_DIRECTORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MESSAGE_HISTORY, "WC_MESSAGE_HISTORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SIGN_LIST, "WC_SIGN_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_LIST, "WC_AI_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GOALS_LIST, "WC_GOALS_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STORY_BOOK, "WC_STORY_BOOK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATION_LIST, "WC_STATION_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRAINS_LIST, "WC_TRAINS_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ROADVEH_LIST, "WC_ROADVEH_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SHIPS_LIST, "WC_SHIPS_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AIRCRAFT_LIST, "WC_AIRCRAFT_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_VIEW, "WC_TOWN_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_VIEW, "WC_VEHICLE_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATION_VIEW, "WC_STATION_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_DEPOT, "WC_VEHICLE_DEPOT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_WAYPOINT_VIEW, "WC_WAYPOINT_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_VIEW, "WC_INDUSTRY_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY, "WC_COMPANY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_OBJECT, "WC_BUILD_OBJECT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_VEHICLE, "WC_BUILD_VEHICLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_BRIDGE, "WC_BUILD_BRIDGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_STATION, "WC_BUILD_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUS_STATION, "WC_BUS_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRUCK_STATION, "WC_TRUCK_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_DEPOT, "WC_BUILD_DEPOT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_WAYPOINT, "WC_BUILD_WAYPOINT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_FOUND_TOWN, "WC_FOUND_TOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_INDUSTRY, "WC_BUILD_INDUSTRY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_GAME, "WC_SELECT_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_LAND_GEN, "WC_SCEN_LAND_GEN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GENERATE_LANDSCAPE, "WC_GENERATE_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MODAL_PROGRESS, "WC_MODAL_PROGRESS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NETWORK_WINDOW, "WC_NETWORK_WINDOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CLIENT_LIST, "WC_CLIENT_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CLIENT_LIST_POPUP, "WC_CLIENT_LIST_POPUP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NETWORK_STATUS_WINDOW, "WC_NETWORK_STATUS_WINDOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SEND_NETWORK_MSG, "WC_SEND_NETWORK_MSG"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_PASSWORD_WINDOW, "WC_COMPANY_PASSWORD_WINDOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_CARGOES, "WC_INDUSTRY_CARGOES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GRAPH_LEGEND, "WC_GRAPH_LEGEND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_FINANCES, "WC_FINANCES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INCOME_GRAPH, "WC_INCOME_GRAPH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_OPERATING_PROFIT, "WC_OPERATING_PROFIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_DELIVERED_CARGO, "WC_DELIVERED_CARGO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PERFORMANCE_HISTORY, "WC_PERFORMANCE_HISTORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_VALUE, "WC_COMPANY_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_LEAGUE, "WC_COMPANY_LEAGUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PAYMENT_RATES, "WC_PAYMENT_RATES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PERFORMANCE_DETAIL, "WC_PERFORMANCE_DETAIL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_INFRASTRUCTURE, "WC_COMPANY_INFRASTRUCTURE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUY_COMPANY, "WC_BUY_COMPANY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ENGINE_PREVIEW, "WC_ENGINE_PREVIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MUSIC_WINDOW, "WC_MUSIC_WINDOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MUSIC_TRACK_SELECTION, "WC_MUSIC_TRACK_SELECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GAME_OPTIONS, "WC_GAME_OPTIONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CUSTOM_CURRENCY, "WC_CUSTOM_CURRENCY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CHEATS, "WC_CHEATS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_EXTRA_VIEW_PORT, "WC_EXTRA_VIEW_PORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CONSOLE, "WC_CONSOLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BOOTSTRAP, "WC_BOOTSTRAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_HIGHSCORE, "WC_HIGHSCORE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ENDSCREEN, "WC_ENDSCREEN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_DEBUG, "WC_AI_DEBUG"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NEWGRF_INSPECT, "WC_NEWGRF_INSPECT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SPRITE_ALIGNER, "WC_SPRITE_ALIGNER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_LINKGRAPH_LEGEND, "WC_LINKGRAPH_LEGEND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INVALID, "WC_INVALID"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BLUE, "TC_BLUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_SILVER, "TC_SILVER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GOLD, "TC_GOLD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_RED, "TC_RED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_PURPLE, "TC_PURPLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_LIGHT_BROWN, "TC_LIGHT_BROWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_ORANGE, "TC_ORANGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GREEN, "TC_GREEN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_YELLOW, "TC_YELLOW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_DARK_GREEN, "TC_DARK_GREEN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_CREAM, "TC_CREAM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BROWN, "TC_BROWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_WHITE, "TC_WHITE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_LIGHT_BLUE, "TC_LIGHT_BLUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GREY, "TC_GREY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_DARK_BLUE, "TC_DARK_BLUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BLACK, "TC_BLACK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::TC_INVALID, "TC_INVALID"); - SQGSWindow.DefSQConst(engine, ScriptWindow::NUMBER_ALL, "NUMBER_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WIDGET_ALL, "WIDGET_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_CAPTION, "WID_AIL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_LIST, "WID_AIL_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_SCROLLBAR, "WID_AIL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_INFO_BG, "WID_AIL_INFO_BG"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_ACCEPT, "WID_AIL_ACCEPT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_CANCEL, "WID_AIL_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_CAPTION, "WID_AIS_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_BACKGROUND, "WID_AIS_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_SCROLLBAR, "WID_AIS_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_ACCEPT, "WID_AIS_ACCEPT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_RESET, "WID_AIS_RESET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_BACKGROUND, "WID_AIC_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_DECREASE, "WID_AIC_DECREASE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_INCREASE, "WID_AIC_INCREASE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_NUMBER, "WID_AIC_NUMBER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_GAMELIST, "WID_AIC_GAMELIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_LIST, "WID_AIC_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_SCROLLBAR, "WID_AIC_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_MOVE_UP, "WID_AIC_MOVE_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_MOVE_DOWN, "WID_AIC_MOVE_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CHANGE, "WID_AIC_CHANGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CONFIGURE, "WID_AIC_CONFIGURE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CLOSE, "WID_AIC_CLOSE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_TEXTFILE, "WID_AIC_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CONTENT_DOWNLOAD, "WID_AIC_CONTENT_DOWNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_VIEW, "WID_AID_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_NAME_TEXT, "WID_AID_NAME_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SETTINGS, "WID_AID_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SCRIPT_GAME, "WID_AID_SCRIPT_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_RELOAD_TOGGLE, "WID_AID_RELOAD_TOGGLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_LOG_PANEL, "WID_AID_LOG_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SCROLLBAR, "WID_AID_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_COMPANY_BUTTON_START, "WID_AID_COMPANY_BUTTON_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_COMPANY_BUTTON_END, "WID_AID_COMPANY_BUTTON_END"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STRING_WIDGETS, "WID_AID_BREAK_STRING_WIDGETS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STR_ON_OFF_BTN, "WID_AID_BREAK_STR_ON_OFF_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STR_EDIT_BOX, "WID_AID_BREAK_STR_EDIT_BOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_MATCH_CASE_BTN, "WID_AID_MATCH_CASE_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_CONTINUE_BTN, "WID_AID_CONTINUE_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AT_AIRPORT, "WID_AT_AIRPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AT_DEMOLISH, "WID_AT_DEMOLISH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_CLASS_DROPDOWN, "WID_AP_CLASS_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_AIRPORT_LIST, "WID_AP_AIRPORT_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_SCROLLBAR, "WID_AP_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_NUM, "WID_AP_LAYOUT_NUM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_DECREASE, "WID_AP_LAYOUT_DECREASE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_INCREASE, "WID_AP_LAYOUT_INCREASE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_AIRPORT_SPRITE, "WID_AP_AIRPORT_SPRITE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_EXTRA_TEXT, "WID_AP_EXTRA_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BOTTOMPANEL, "WID_AP_BOTTOMPANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_COVERAGE_LABEL, "WID_AP_COVERAGE_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BTN_DONTHILIGHT, "WID_AP_BTN_DONTHILIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BTN_DOHILIGHT, "WID_AP_BTN_DOHILIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_CAPTION, "WID_RV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_MATRIX, "WID_RV_LEFT_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_SCROLLBAR, "WID_RV_LEFT_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_MATRIX, "WID_RV_RIGHT_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_SCROLLBAR, "WID_RV_RIGHT_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_DETAILS, "WID_RV_LEFT_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_DETAILS, "WID_RV_RIGHT_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_START_REPLACE, "WID_RV_START_REPLACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_INFO_TAB, "WID_RV_INFO_TAB"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_STOP_REPLACE, "WID_RV_STOP_REPLACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_ENGINEWAGON_TOGGLE, "WID_RV_TRAIN_ENGINEWAGON_TOGGLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_FLUFF_LEFT, "WID_RV_TRAIN_FLUFF_LEFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_RAILTYPE_DROPDOWN, "WID_RV_TRAIN_RAILTYPE_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_FLUFF_RIGHT, "WID_RV_TRAIN_FLUFF_RIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_WAGONREMOVE_TOGGLE, "WID_RV_TRAIN_WAGONREMOVE_TOGGLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BB_BACKGROUND, "WID_BB_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_QUESTION, "WID_BAFD_QUESTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_YES, "WID_BAFD_YES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_NO, "WID_BAFD_NO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_CAPTION, "WID_BBS_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_DROPDOWN_ORDER, "WID_BBS_DROPDOWN_ORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_DROPDOWN_CRITERIA, "WID_BBS_DROPDOWN_CRITERIA"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_BRIDGE_LIST, "WID_BBS_BRIDGE_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_SCROLLBAR, "WID_BBS_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_CAPTION, "WID_BV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SORT_ASSENDING_DESCENDING, "WID_BV_SORT_ASSENDING_DESCENDING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SORT_DROPDOWN, "WID_BV_SORT_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_CARGO_FILTER_DROPDOWN, "WID_BV_CARGO_FILTER_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_LIST, "WID_BV_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SCROLLBAR, "WID_BV_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_PANEL, "WID_BV_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_BUILD, "WID_BV_BUILD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_BUILD_SEL, "WID_BV_BUILD_SEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_RENAME, "WID_BV_RENAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_PANEL, "WID_C_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_CAPTION, "WID_C_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_FACE, "WID_C_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_FACE_TITLE, "WID_C_FACE_TITLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INAUGURATION, "WID_C_DESC_INAUGURATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COLOUR_SCHEME, "WID_C_DESC_COLOUR_SCHEME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COLOUR_SCHEME_EXAMPLE, "WID_C_DESC_COLOUR_SCHEME_EXAMPLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_VEHICLE, "WID_C_DESC_VEHICLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_VEHICLE_COUNTS, "WID_C_DESC_VEHICLE_COUNTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COMPANY_VALUE, "WID_C_DESC_COMPANY_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INFRASTRUCTURE, "WID_C_DESC_INFRASTRUCTURE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INFRASTRUCTURE_COUNTS, "WID_C_DESC_INFRASTRUCTURE_COUNTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_DESC_OWNERS, "WID_C_SELECT_DESC_OWNERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_OWNERS, "WID_C_DESC_OWNERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_BUTTONS, "WID_C_SELECT_BUTTONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_NEW_FACE, "WID_C_NEW_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COLOUR_SCHEME, "WID_C_COLOUR_SCHEME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_PRESIDENT_NAME, "WID_C_PRESIDENT_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_NAME, "WID_C_COMPANY_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BUY_SHARE, "WID_C_BUY_SHARE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELL_SHARE, "WID_C_SELL_SHARE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_VIEW_BUILD_HQ, "WID_C_SELECT_VIEW_BUILD_HQ"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_VIEW_HQ, "WID_C_VIEW_HQ"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BUILD_HQ, "WID_C_BUILD_HQ"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_RELOCATE, "WID_C_SELECT_RELOCATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_RELOCATE_HQ, "WID_C_RELOCATE_HQ"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_VIEW_INFRASTRUCTURE, "WID_C_VIEW_INFRASTRUCTURE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_HAS_PASSWORD, "WID_C_HAS_PASSWORD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_MULTIPLAYER, "WID_C_SELECT_MULTIPLAYER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_PASSWORD, "WID_C_COMPANY_PASSWORD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_JOIN, "WID_C_COMPANY_JOIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_CAPTION, "WID_CF_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOGGLE_SIZE, "WID_CF_TOGGLE_SIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_PANEL, "WID_CF_SEL_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_CATEGORY, "WID_CF_EXPS_CATEGORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE1, "WID_CF_EXPS_PRICE1"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE2, "WID_CF_EXPS_PRICE2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE3, "WID_CF_EXPS_PRICE3"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOTAL_PANEL, "WID_CF_TOTAL_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_MAXLOAN, "WID_CF_SEL_MAXLOAN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_BALANCE_VALUE, "WID_CF_BALANCE_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_LOAN_VALUE, "WID_CF_LOAN_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_LOAN_LINE, "WID_CF_LOAN_LINE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOTAL_VALUE, "WID_CF_TOTAL_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_MAXLOAN_GAP, "WID_CF_MAXLOAN_GAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_MAXLOAN_VALUE, "WID_CF_MAXLOAN_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_BUTTONS, "WID_CF_SEL_BUTTONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_INCREASE_LOAN, "WID_CF_INCREASE_LOAN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_REPAY_LOAN, "WID_CF_REPAY_LOAN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_INFRASTRUCTURE, "WID_CF_INFRASTRUCTURE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CAPTION, "WID_SCL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_GENERAL, "WID_SCL_CLASS_GENERAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_RAIL, "WID_SCL_CLASS_RAIL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_ROAD, "WID_SCL_CLASS_ROAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_SHIP, "WID_SCL_CLASS_SHIP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_AIRCRAFT, "WID_SCL_CLASS_AIRCRAFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_SPACER_DROPDOWN, "WID_SCL_SPACER_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_PRI_COL_DROPDOWN, "WID_SCL_PRI_COL_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_SEC_COL_DROPDOWN, "WID_SCL_SEC_COL_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_MATRIX, "WID_SCL_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CAPTION, "WID_SCMF_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TOGGLE_LARGE_SMALL, "WID_SCMF_TOGGLE_LARGE_SMALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SELECT_FACE, "WID_SCMF_SELECT_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CANCEL, "WID_SCMF_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ACCEPT, "WID_SCMF_ACCEPT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_MALE, "WID_SCMF_MALE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FEMALE, "WID_SCMF_FEMALE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_MALE2, "WID_SCMF_MALE2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FEMALE2, "WID_SCMF_FEMALE2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_LOADSAVE, "WID_SCMF_SEL_LOADSAVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_MALEFEMALE, "WID_SCMF_SEL_MALEFEMALE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_PARTS, "WID_SCMF_SEL_PARTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_RANDOM_NEW_FACE, "WID_SCMF_RANDOM_NEW_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON, "WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FACE, "WID_SCMF_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LOAD, "WID_SCMF_LOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FACECODE, "WID_SCMF_FACECODE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SAVE, "WID_SCMF_SAVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT, "WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_TEXT, "WID_SCMF_TIE_EARRING_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_TEXT, "WID_SCMF_LIPS_MOUSTACHE_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_GLASSES_TEXT, "WID_SCMF_HAS_GLASSES_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_TEXT, "WID_SCMF_HAIR_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_TEXT, "WID_SCMF_EYEBROWS_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_TEXT, "WID_SCMF_EYECOLOUR_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_TEXT, "WID_SCMF_GLASSES_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_TEXT, "WID_SCMF_NOSE_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_TEXT, "WID_SCMF_CHIN_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_TEXT, "WID_SCMF_JACKET_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_TEXT, "WID_SCMF_COLLAR_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ETHNICITY_EUR, "WID_SCMF_ETHNICITY_EUR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ETHNICITY_AFR, "WID_SCMF_ETHNICITY_AFR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_MOUSTACHE_EARRING, "WID_SCMF_HAS_MOUSTACHE_EARRING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_GLASSES, "WID_SCMF_HAS_GLASSES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_L, "WID_SCMF_EYECOLOUR_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR, "WID_SCMF_EYECOLOUR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_R, "WID_SCMF_EYECOLOUR_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_L, "WID_SCMF_CHIN_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN, "WID_SCMF_CHIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_R, "WID_SCMF_CHIN_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_L, "WID_SCMF_EYEBROWS_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS, "WID_SCMF_EYEBROWS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_R, "WID_SCMF_EYEBROWS_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_L, "WID_SCMF_LIPS_MOUSTACHE_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE, "WID_SCMF_LIPS_MOUSTACHE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_R, "WID_SCMF_LIPS_MOUSTACHE_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_L, "WID_SCMF_NOSE_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE, "WID_SCMF_NOSE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_R, "WID_SCMF_NOSE_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_L, "WID_SCMF_HAIR_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR, "WID_SCMF_HAIR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_R, "WID_SCMF_HAIR_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_L, "WID_SCMF_JACKET_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET, "WID_SCMF_JACKET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_R, "WID_SCMF_JACKET_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_L, "WID_SCMF_COLLAR_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR, "WID_SCMF_COLLAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_R, "WID_SCMF_COLLAR_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_L, "WID_SCMF_TIE_EARRING_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING, "WID_SCMF_TIE_EARRING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_R, "WID_SCMF_TIE_EARRING_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_L, "WID_SCMF_GLASSES_L"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES, "WID_SCMF_GLASSES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_R, "WID_SCMF_GLASSES_R"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_CAPTION, "WID_CI_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_RAIL_DESC, "WID_CI_RAIL_DESC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_RAIL_COUNT, "WID_CI_RAIL_COUNT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_DESC, "WID_CI_ROAD_DESC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_COUNT, "WID_CI_ROAD_COUNT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_DESC, "WID_CI_WATER_DESC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_COUNT, "WID_CI_WATER_COUNT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_STATION_DESC, "WID_CI_STATION_DESC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_STATION_COUNT, "WID_CI_STATION_COUNT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TOTAL_DESC, "WID_CI_TOTAL_DESC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TOTAL, "WID_CI_TOTAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_CAPTION, "WID_BC_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_FACE, "WID_BC_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_QUESTION, "WID_BC_QUESTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_NO, "WID_BC_NO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_YES, "WID_BC_YES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BACKGROUND, "WID_C_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_DAY, "WID_SD_DAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_MONTH, "WID_SD_MONTH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_YEAR, "WID_SD_YEAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_SET_DATE, "WID_SD_SET_DATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_CAPTION, "WID_D_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL, "WID_D_SELL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_SELL_CHAIN, "WID_D_SHOW_SELL_CHAIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL_CHAIN, "WID_D_SELL_CHAIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL_ALL, "WID_D_SELL_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_AUTOREPLACE, "WID_D_AUTOREPLACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_MATRIX, "WID_D_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_V_SCROLL, "WID_D_V_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_H_SCROLL, "WID_D_SHOW_H_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_H_SCROLL, "WID_D_H_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_BUILD, "WID_D_BUILD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_CLONE, "WID_D_CLONE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_LOCATION, "WID_D_LOCATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_RENAME, "WID_D_SHOW_RENAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_RENAME, "WID_D_RENAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_VEHICLE_LIST, "WID_D_VEHICLE_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_STOP_ALL, "WID_D_STOP_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_START_ALL, "WID_D_START_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_BACKGROUND, "WID_BDD_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_X, "WID_BDD_X"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_Y, "WID_BDD_Y"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_CANAL, "WID_DT_CANAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_LOCK, "WID_DT_LOCK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_DEMOLISH, "WID_DT_DEMOLISH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_DEPOT, "WID_DT_DEPOT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_STATION, "WID_DT_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_BUOY, "WID_DT_BUOY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_RIVER, "WID_DT_RIVER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_BUILD_AQUEDUCT, "WID_DT_BUILD_AQUEDUCT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_INVALID, "WID_DT_INVALID"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_ITEMS, "WID_DM_ITEMS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_SHOW_SCROLL, "WID_DM_SHOW_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_SCROLL, "WID_DM_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_QUESTION, "WID_EP_QUESTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_NO, "WID_EP_NO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_YES, "WID_EP_YES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_CAPTION, "WID_EM_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_FACE, "WID_EM_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_MESSAGE, "WID_EM_MESSAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CAPTION, "WID_SL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SORT_BYNAME, "WID_SL_SORT_BYNAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SORT_BYDATE, "WID_SL_SORT_BYDATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_BACKGROUND, "WID_SL_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_FILE_BACKGROUND, "WID_SL_FILE_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_HOME_BUTTON, "WID_SL_HOME_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DRIVES_DIRECTORIES_LIST, "WID_SL_DRIVES_DIRECTORIES_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SCROLLBAR, "WID_SL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CONTENT_DOWNLOAD, "WID_SL_CONTENT_DOWNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SAVE_OSK_TITLE, "WID_SL_SAVE_OSK_TITLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DELETE_SELECTION, "WID_SL_DELETE_SELECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SAVE_GAME, "WID_SL_SAVE_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CONTENT_DOWNLOAD_SEL, "WID_SL_CONTENT_DOWNLOAD_SEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DETAILS, "WID_SL_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_NEWGRF_INFO, "WID_SL_NEWGRF_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_LOAD_BUTTON, "WID_SL_LOAD_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_MISSING_NEWGRFS, "WID_SL_MISSING_NEWGRFS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TEMPERATE, "WID_GL_TEMPERATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_ARCTIC, "WID_GL_ARCTIC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TROPICAL, "WID_GL_TROPICAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TOYLAND, "WID_GL_TOYLAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAPSIZE_X_PULLDOWN, "WID_GL_MAPSIZE_X_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAPSIZE_Y_PULLDOWN, "WID_GL_MAPSIZE_Y_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TOWN_PULLDOWN, "WID_GL_TOWN_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_INDUSTRY_PULLDOWN, "WID_GL_INDUSTRY_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RANDOM_EDITBOX, "WID_GL_RANDOM_EDITBOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RANDOM_BUTTON, "WID_GL_RANDOM_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_GENERATE_BUTTON, "WID_GL_GENERATE_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_DOWN, "WID_GL_START_DATE_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_TEXT, "WID_GL_START_DATE_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_UP, "WID_GL_START_DATE_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_DOWN, "WID_GL_SNOW_LEVEL_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_TEXT, "WID_GL_SNOW_LEVEL_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_UP, "WID_GL_SNOW_LEVEL_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TREE_PULLDOWN, "WID_GL_TREE_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LANDSCAPE_PULLDOWN, "WID_GL_LANDSCAPE_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_NAME_TEXT, "WID_GL_HEIGHTMAP_NAME_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_SIZE_TEXT, "WID_GL_HEIGHTMAP_SIZE_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_ROTATION_PULLDOWN, "WID_GL_HEIGHTMAP_ROTATION_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TERRAIN_PULLDOWN, "WID_GL_TERRAIN_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_PULLDOWN, "WID_GL_WATER_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RIVER_PULLDOWN, "WID_GL_RIVER_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SMOOTHNESS_PULLDOWN, "WID_GL_SMOOTHNESS_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_VARIETY_PULLDOWN, "WID_GL_VARIETY_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_BORDERS_RANDOM, "WID_GL_BORDERS_RANDOM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_NW, "WID_GL_WATER_NW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_NE, "WID_GL_WATER_NE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_SE, "WID_GL_WATER_SE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_SW, "WID_GL_WATER_SW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TEMPERATE, "WID_CS_TEMPERATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_ARCTIC, "WID_CS_ARCTIC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TROPICAL, "WID_CS_TROPICAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TOYLAND, "WID_CS_TOYLAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_EMPTY_WORLD, "WID_CS_EMPTY_WORLD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_RANDOM_WORLD, "WID_CS_RANDOM_WORLD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_MAPSIZE_X_PULLDOWN, "WID_CS_MAPSIZE_X_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_MAPSIZE_Y_PULLDOWN, "WID_CS_MAPSIZE_Y_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_DOWN, "WID_CS_START_DATE_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_TEXT, "WID_CS_START_DATE_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_UP, "WID_CS_START_DATE_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_DOWN, "WID_CS_FLAT_LAND_HEIGHT_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_TEXT, "WID_CS_FLAT_LAND_HEIGHT_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_UP, "WID_CS_FLAT_LAND_HEIGHT_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_PROGRESS_BAR, "WID_GP_PROGRESS_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_PROGRESS_TEXT, "WID_GP_PROGRESS_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_ABORT, "WID_GP_ABORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_CAPTION, "WID_GOAL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_LIST, "WID_GOAL_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_SCROLLBAR, "WID_GOAL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_CAPTION, "WID_GQ_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_QUESTION, "WID_GQ_QUESTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTONS, "WID_GQ_BUTTONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_1, "WID_GQ_BUTTON_1"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_2, "WID_GQ_BUTTON_2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_3, "WID_GQ_BUTTON_3"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_BACKGROUND, "WID_GL_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_FIRST_COMPANY, "WID_GL_FIRST_COMPANY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LAST_COMPANY, "WID_GL_LAST_COMPANY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_KEY_BUTTON, "WID_CV_KEY_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_BACKGROUND, "WID_CV_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_GRAPH, "WID_CV_GRAPH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_RESIZE, "WID_CV_RESIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_KEY, "WID_PHG_KEY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_DETAILED_PERFORMANCE, "WID_PHG_DETAILED_PERFORMANCE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_BACKGROUND, "WID_PHG_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_GRAPH, "WID_PHG_GRAPH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_RESIZE, "WID_PHG_RESIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_BACKGROUND, "WID_CPR_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_HEADER, "WID_CPR_HEADER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_GRAPH, "WID_CPR_GRAPH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_RESIZE, "WID_CPR_RESIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_FOOTER, "WID_CPR_FOOTER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_ENABLE_CARGOES, "WID_CPR_ENABLE_CARGOES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_DISABLE_CARGOES, "WID_CPR_DISABLE_CARGOES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_CARGO_FIRST, "WID_CPR_CARGO_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CL_BACKGROUND, "WID_CL_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_SCORE_FIRST, "WID_PRD_SCORE_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_SCORE_LAST, "WID_PRD_SCORE_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_COMPANY_FIRST, "WID_PRD_COMPANY_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_COMPANY_LAST, "WID_PRD_COMPANY_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_CAPTION, "WID_GL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SORT_BY_ORDER, "WID_GL_SORT_BY_ORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SORT_BY_DROPDOWN, "WID_GL_SORT_BY_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_VEHICLE, "WID_GL_LIST_VEHICLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_VEHICLE_SCROLLBAR, "WID_GL_LIST_VEHICLE_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_AVAILABLE_VEHICLES, "WID_GL_AVAILABLE_VEHICLES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MANAGE_VEHICLES_DROPDOWN, "WID_GL_MANAGE_VEHICLES_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_STOP_ALL, "WID_GL_STOP_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_ALL, "WID_GL_START_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_ALL_VEHICLES, "WID_GL_ALL_VEHICLES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_DEFAULT_VEHICLES, "WID_GL_DEFAULT_VEHICLES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_GROUP, "WID_GL_LIST_GROUP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_GROUP_SCROLLBAR, "WID_GL_LIST_GROUP_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_CREATE_GROUP, "WID_GL_CREATE_GROUP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_DELETE_GROUP, "WID_GL_DELETE_GROUP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RENAME_GROUP, "WID_GL_RENAME_GROUP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_REPLACE_PROTECTION, "WID_GL_REPLACE_PROTECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_H_BACKGROUND, "WID_H_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_MATRIX_WIDGET, "WID_DPI_MATRIX_WIDGET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_SCROLLBAR, "WID_DPI_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_INFOPANEL, "WID_DPI_INFOPANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_DISPLAY_WIDGET, "WID_DPI_DISPLAY_WIDGET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_FUND_WIDGET, "WID_DPI_FUND_WIDGET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_CAPTION, "WID_IV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_VIEWPORT, "WID_IV_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_INFO, "WID_IV_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_GOTO, "WID_IV_GOTO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_DISPLAY, "WID_IV_DISPLAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_DROPDOWN_ORDER, "WID_ID_DROPDOWN_ORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_DROPDOWN_CRITERIA, "WID_ID_DROPDOWN_CRITERIA"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_INDUSTRY_LIST, "WID_ID_INDUSTRY_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_SCROLLBAR, "WID_ID_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_CAPTION, "WID_IC_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_NOTIFY, "WID_IC_NOTIFY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_PANEL, "WID_IC_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_SCROLLBAR, "WID_IC_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_CARGO_DROPDOWN, "WID_IC_CARGO_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_IND_DROPDOWN, "WID_IC_IND_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_GENERATE_GAME, "WID_SGI_GENERATE_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_LOAD_GAME, "WID_SGI_LOAD_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_SCENARIO, "WID_SGI_PLAY_SCENARIO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_HEIGHTMAP, "WID_SGI_PLAY_HEIGHTMAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_EDIT_SCENARIO, "WID_SGI_EDIT_SCENARIO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_NETWORK, "WID_SGI_PLAY_NETWORK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TEMPERATE_LANDSCAPE, "WID_SGI_TEMPERATE_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_ARCTIC_LANDSCAPE, "WID_SGI_ARCTIC_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TROPIC_LANDSCAPE, "WID_SGI_TROPIC_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TOYLAND_LANDSCAPE, "WID_SGI_TOYLAND_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TRANSLATION_SELECTION, "WID_SGI_TRANSLATION_SELECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TRANSLATION, "WID_SGI_TRANSLATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_OPTIONS, "WID_SGI_OPTIONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_HIGHSCORE, "WID_SGI_HIGHSCORE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_SETTINGS_OPTIONS, "WID_SGI_SETTINGS_OPTIONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_GRF_SETTINGS, "WID_SGI_GRF_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_CONTENT_DOWNLOAD, "WID_SGI_CONTENT_DOWNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_AI_SETTINGS, "WID_SGI_AI_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_EXIT, "WID_SGI_EXIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CAPTION, "WID_LGL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION, "WID_LGL_SATURATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION_FIRST, "WID_LGL_SATURATION_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION_LAST, "WID_LGL_SATURATION_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES, "WID_LGL_COMPANIES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANY_FIRST, "WID_LGL_COMPANY_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANY_LAST, "WID_LGL_COMPANY_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES_ALL, "WID_LGL_COMPANIES_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES_NONE, "WID_LGL_COMPANIES_NONE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES, "WID_LGL_CARGOES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGO_FIRST, "WID_LGL_CARGO_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGO_LAST, "WID_LGL_CARGO_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES_ALL, "WID_LGL_CARGOES_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES_NONE, "WID_LGL_CARGOES_NONE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_VIEWPORT, "WID_M_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LI_BACKGROUND, "WID_LI_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BACKGROUND, "WID_TT_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_A_SCROLLING_TEXT, "WID_A_SCROLLING_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_A_WEBSITE, "WID_A_WEBSITE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_CAPTION, "WID_QS_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_TEXT, "WID_QS_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_DEFAULT, "WID_QS_DEFAULT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_CANCEL, "WID_QS_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_OK, "WID_QS_OK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_CAPTION, "WID_Q_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_TEXT, "WID_Q_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_NO, "WID_Q_NO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_YES, "WID_Q_YES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_CAPTION, "WID_TF_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_WRAPTEXT, "WID_TF_WRAPTEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_BACKGROUND, "WID_TF_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_VSCROLLBAR, "WID_TF_VSCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_HSCROLLBAR, "WID_TF_HSCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LIST_LEFT, "WID_MTS_LIST_LEFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LEFT_SCROLLBAR, "WID_MTS_LEFT_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_PLAYLIST, "WID_MTS_PLAYLIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LIST_RIGHT, "WID_MTS_LIST_RIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_RIGHT_SCROLLBAR, "WID_MTS_RIGHT_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_ALL, "WID_MTS_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_OLD, "WID_MTS_OLD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_NEW, "WID_MTS_NEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_EZY, "WID_MTS_EZY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CUSTOM1, "WID_MTS_CUSTOM1"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CUSTOM2, "WID_MTS_CUSTOM2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CLEAR, "WID_MTS_CLEAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PREV, "WID_M_PREV"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_NEXT, "WID_M_NEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_STOP, "WID_M_STOP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PLAY, "WID_M_PLAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_SLIDERS, "WID_M_SLIDERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_MUSIC_VOL, "WID_M_MUSIC_VOL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_EFFECT_VOL, "WID_M_EFFECT_VOL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_BACKGROUND, "WID_M_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK, "WID_M_TRACK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_NR, "WID_M_TRACK_NR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_TITLE, "WID_M_TRACK_TITLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_NAME, "WID_M_TRACK_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_SHUFFLE, "WID_M_SHUFFLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PROGRAMME, "WID_M_PROGRAMME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_ALL, "WID_M_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_OLD, "WID_M_OLD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_NEW, "WID_M_NEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_EZY, "WID_M_EZY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_CUSTOM1, "WID_M_CUSTOM1"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_CUSTOM2, "WID_M_CUSTOM2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_CLOSE, "WID_NC_CLOSE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_BACKGROUND, "WID_NC_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_DESTINATION, "WID_NC_DESTINATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_TEXTBOX, "WID_NC_TEXTBOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_SENDBUTTON, "WID_NC_SENDBUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCDS_BACKGROUND, "WID_NCDS_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCDS_CANCELOK, "WID_NCDS_CANCELOK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_BACKGROUND, "WID_NCL_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_FILTER_CAPT, "WID_NCL_FILTER_CAPT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_FILTER, "WID_NCL_FILTER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_CHECKBOX, "WID_NCL_CHECKBOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_TYPE, "WID_NCL_TYPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_NAME, "WID_NCL_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_MATRIX, "WID_NCL_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SCROLLBAR, "WID_NCL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_DETAILS, "WID_NCL_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_TEXTFILE, "WID_NCL_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SELECT_ALL, "WID_NCL_SELECT_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SELECT_UPDATE, "WID_NCL_SELECT_UPDATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_UNSELECT, "WID_NCL_UNSELECT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_OPEN_URL, "WID_NCL_OPEN_URL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_CANCEL, "WID_NCL_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_DOWNLOAD, "WID_NCL_DOWNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SEL_ALL_UPDATE, "WID_NCL_SEL_ALL_UPDATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SEARCH_EXTERNAL, "WID_NCL_SEARCH_EXTERNAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MAIN, "WID_NG_MAIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CONNECTION, "WID_NG_CONNECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CONN_BTN, "WID_NG_CONN_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENT_LABEL, "WID_NG_CLIENT_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENT, "WID_NG_CLIENT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FILTER_LABEL, "WID_NG_FILTER_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FILTER, "WID_NG_FILTER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_HEADER, "WID_NG_HEADER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NAME, "WID_NG_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENTS, "WID_NG_CLIENTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MAPSIZE, "WID_NG_MAPSIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DATE, "WID_NG_DATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_YEARS, "WID_NG_YEARS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_INFO, "WID_NG_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MATRIX, "WID_NG_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_SCROLLBAR, "WID_NG_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED_LABEL, "WID_NG_LASTJOINED_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED, "WID_NG_LASTJOINED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED_SPACER, "WID_NG_LASTJOINED_SPACER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DETAILS, "WID_NG_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DETAILS_SPACER, "WID_NG_DETAILS_SPACER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_JOIN, "WID_NG_JOIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_REFRESH, "WID_NG_REFRESH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF, "WID_NG_NEWGRF"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_SEL, "WID_NG_NEWGRF_SEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_MISSING, "WID_NG_NEWGRF_MISSING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_MISSING_SEL, "WID_NG_NEWGRF_MISSING_SEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FIND, "WID_NG_FIND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_ADD, "WID_NG_ADD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_START, "WID_NG_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CANCEL, "WID_NG_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_BACKGROUND, "WID_NSS_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GAMENAME_LABEL, "WID_NSS_GAMENAME_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GAMENAME, "WID_NSS_GAMENAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SETPWD, "WID_NSS_SETPWD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CONNTYPE_LABEL, "WID_NSS_CONNTYPE_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CONNTYPE_BTN, "WID_NSS_CONNTYPE_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_LABEL, "WID_NSS_CLIENTS_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_BTND, "WID_NSS_CLIENTS_BTND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_TXT, "WID_NSS_CLIENTS_TXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_BTNU, "WID_NSS_CLIENTS_BTNU"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_LABEL, "WID_NSS_COMPANIES_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_BTND, "WID_NSS_COMPANIES_BTND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_TXT, "WID_NSS_COMPANIES_TXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_BTNU, "WID_NSS_COMPANIES_BTNU"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_LABEL, "WID_NSS_SPECTATORS_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_BTND, "WID_NSS_SPECTATORS_BTND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_TXT, "WID_NSS_SPECTATORS_TXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_BTNU, "WID_NSS_SPECTATORS_BTNU"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LANGUAGE_LABEL, "WID_NSS_LANGUAGE_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LANGUAGE_BTN, "WID_NSS_LANGUAGE_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GENERATE_GAME, "WID_NSS_GENERATE_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LOAD_GAME, "WID_NSS_LOAD_GAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_PLAY_SCENARIO, "WID_NSS_PLAY_SCENARIO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_PLAY_HEIGHTMAP, "WID_NSS_PLAY_HEIGHTMAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CANCEL, "WID_NSS_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_BACKGROUND, "WID_NL_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_TEXT, "WID_NL_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_HEADER, "WID_NL_HEADER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_MATRIX, "WID_NL_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_SCROLLBAR, "WID_NL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_DETAILS, "WID_NL_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_JOIN, "WID_NL_JOIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_NEW, "WID_NL_NEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_SPECTATE, "WID_NL_SPECTATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_REFRESH, "WID_NL_REFRESH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_CANCEL, "WID_NL_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CL_PANEL, "WID_CL_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CLP_PANEL, "WID_CLP_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NJS_BACKGROUND, "WID_NJS_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NJS_CANCELOK, "WID_NJS_CANCELOK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_BACKGROUND, "WID_NCP_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_LABEL, "WID_NCP_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_PASSWORD, "WID_NCP_PASSWORD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_SAVE_AS_DEFAULT_PASSWORD, "WID_NCP_SAVE_AS_DEFAULT_PASSWORD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_CANCEL, "WID_NCP_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_OK, "WID_NCP_OK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_CAPTION, "WID_NGRFI_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_PARENT, "WID_NGRFI_PARENT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_PREV, "WID_NGRFI_VEH_PREV"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_NEXT, "WID_NGRFI_VEH_NEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_CHAIN, "WID_NGRFI_VEH_CHAIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_MAINPANEL, "WID_NGRFI_MAINPANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_SCROLLBAR, "WID_NGRFI_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_CAPTION, "WID_SA_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_PREVIOUS, "WID_SA_PREVIOUS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_GOTO, "WID_SA_GOTO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_NEXT, "WID_SA_NEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_UP, "WID_SA_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_LEFT, "WID_SA_LEFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_RIGHT, "WID_SA_RIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_DOWN, "WID_SA_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_SPRITE, "WID_SA_SPRITE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_OFFSETS, "WID_SA_OFFSETS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_PICKER, "WID_SA_PICKER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_LIST, "WID_SA_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_SCROLLBAR, "WID_SA_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SHOW_NUMPAR, "WID_NP_SHOW_NUMPAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_DEC, "WID_NP_NUMPAR_DEC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_INC, "WID_NP_NUMPAR_INC"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR, "WID_NP_NUMPAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_TEXT, "WID_NP_NUMPAR_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_BACKGROUND, "WID_NP_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SCROLLBAR, "WID_NP_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_ACCEPT, "WID_NP_ACCEPT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_RESET, "WID_NP_RESET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SHOW_DESCRIPTION, "WID_NP_SHOW_DESCRIPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_DESCRIPTION, "WID_NP_DESCRIPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_LIST, "WID_NS_PRESET_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_SAVE, "WID_NS_PRESET_SAVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_DELETE, "WID_NS_PRESET_DELETE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_ADD, "WID_NS_ADD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_REMOVE, "WID_NS_REMOVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_MOVE_UP, "WID_NS_MOVE_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_MOVE_DOWN, "WID_NS_MOVE_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_FILTER, "WID_NS_FILTER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_FILE_LIST, "WID_NS_FILE_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SCROLLBAR, "WID_NS_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_AVAIL_LIST, "WID_NS_AVAIL_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SCROLL2BAR, "WID_NS_SCROLL2BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_INFO_TITLE, "WID_NS_NEWGRF_INFO_TITLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_INFO, "WID_NS_NEWGRF_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_OPEN_URL, "WID_NS_OPEN_URL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_TEXTFILE, "WID_NS_NEWGRF_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SET_PARAMETERS, "WID_NS_SET_PARAMETERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_VIEW_PARAMETERS, "WID_NS_VIEW_PARAMETERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_TOGGLE_PALETTE, "WID_NS_TOGGLE_PALETTE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_APPLY_CHANGES, "WID_NS_APPLY_CHANGES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_RESCAN_FILES, "WID_NS_RESCAN_FILES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_RESCAN_FILES2, "WID_NS_RESCAN_FILES2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_CONTENT_DOWNLOAD, "WID_NS_CONTENT_DOWNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_CONTENT_DOWNLOAD2, "WID_NS_CONTENT_DOWNLOAD2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SHOW_REMOVE, "WID_NS_SHOW_REMOVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SHOW_APPLY, "WID_NS_SHOW_APPLY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SP_PROGRESS_BAR, "WID_SP_PROGRESS_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SP_PROGRESS_TEXT, "WID_SP_PROGRESS_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_PANEL, "WID_N_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_TITLE, "WID_N_TITLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_HEADLINE, "WID_N_HEADLINE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_CLOSEBOX, "WID_N_CLOSEBOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_DATE, "WID_N_DATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_CAPTION, "WID_N_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_INSET, "WID_N_INSET"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VIEWPORT, "WID_N_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_COMPANY_MSG, "WID_N_COMPANY_MSG"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MESSAGE, "WID_N_MESSAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MGR_FACE, "WID_N_MGR_FACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MGR_NAME, "WID_N_MGR_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_TITLE, "WID_N_VEH_TITLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_BKGND, "WID_N_VEH_BKGND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_NAME, "WID_N_VEH_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_SPR, "WID_N_VEH_SPR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_INFO, "WID_N_VEH_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_STICKYBOX, "WID_MH_STICKYBOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_BACKGROUND, "WID_MH_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_SCROLLBAR, "WID_MH_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_CLASS_LIST, "WID_BO_CLASS_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SCROLLBAR, "WID_BO_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_MATRIX, "WID_BO_OBJECT_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_SPRITE, "WID_BO_OBJECT_SPRITE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_NAME, "WID_BO_OBJECT_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_SIZE, "WID_BO_OBJECT_SIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_INFO, "WID_BO_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_MATRIX, "WID_BO_SELECT_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_IMAGE, "WID_BO_SELECT_IMAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_SCROLL, "WID_BO_SELECT_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_CAPTION, "WID_O_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_TIMETABLE_VIEW, "WID_O_TIMETABLE_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_ORDER_LIST, "WID_O_ORDER_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SCROLLBAR, "WID_O_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SKIP, "WID_O_SKIP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_DELETE, "WID_O_DELETE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_STOP_SHARING, "WID_O_STOP_SHARING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_NON_STOP, "WID_O_NON_STOP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_GOTO, "WID_O_GOTO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_FULL_LOAD, "WID_O_FULL_LOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_UNLOAD, "WID_O_UNLOAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_REFIT, "WID_O_REFIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SERVICE, "WID_O_SERVICE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_EMPTY, "WID_O_EMPTY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_REFIT_DROPDOWN, "WID_O_REFIT_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_VARIABLE, "WID_O_COND_VARIABLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_COMPARATOR, "WID_O_COND_COMPARATOR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_VALUE, "WID_O_COND_VALUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_LEFT, "WID_O_SEL_TOP_LEFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_MIDDLE, "WID_O_SEL_TOP_MIDDLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_RIGHT, "WID_O_SEL_TOP_RIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_ROW_GROUNDVEHICLE, "WID_O_SEL_TOP_ROW_GROUNDVEHICLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_ROW, "WID_O_SEL_TOP_ROW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_BOTTOM_MIDDLE, "WID_O_SEL_BOTTOM_MIDDLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SHARED_ORDER_LIST, "WID_O_SHARED_ORDER_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CAPTION, "WID_OSK_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_TEXT, "WID_OSK_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CANCEL, "WID_OSK_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_OK, "WID_OSK_OK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_BACKSPACE, "WID_OSK_BACKSPACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SPECIAL, "WID_OSK_SPECIAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CAPS, "WID_OSK_CAPS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SHIFT, "WID_OSK_SHIFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SPACE, "WID_OSK_SPACE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_LEFT, "WID_OSK_LEFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_RIGHT, "WID_OSK_RIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_LETTERS, "WID_OSK_LETTERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_NUMBERS_FIRST, "WID_OSK_NUMBERS_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_NUMBERS_LAST, "WID_OSK_NUMBERS_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_QWERTY_FIRST, "WID_OSK_QWERTY_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_QWERTY_LAST, "WID_OSK_QWERTY_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ASDFG_FIRST, "WID_OSK_ASDFG_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ASDFG_LAST, "WID_OSK_ASDFG_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ZXCVB_FIRST, "WID_OSK_ZXCVB_FIRST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ZXCVB_LAST, "WID_OSK_ZXCVB_LAST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_CAPTION, "WID_RAT_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_NS, "WID_RAT_BUILD_NS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_X, "WID_RAT_BUILD_X"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_EW, "WID_RAT_BUILD_EW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_Y, "WID_RAT_BUILD_Y"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_AUTORAIL, "WID_RAT_AUTORAIL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_DEMOLISH, "WID_RAT_DEMOLISH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_DEPOT, "WID_RAT_BUILD_DEPOT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_WAYPOINT, "WID_RAT_BUILD_WAYPOINT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_STATION, "WID_RAT_BUILD_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_SIGNALS, "WID_RAT_BUILD_SIGNALS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_BRIDGE, "WID_RAT_BUILD_BRIDGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_TUNNEL, "WID_RAT_BUILD_TUNNEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_REMOVE, "WID_RAT_REMOVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_CONVERT_RAIL, "WID_RAT_CONVERT_RAIL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DIR_X, "WID_BRAS_PLATFORM_DIR_X"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DIR_Y, "WID_BRAS_PLATFORM_DIR_Y"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_1, "WID_BRAS_PLATFORM_NUM_1"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_2, "WID_BRAS_PLATFORM_NUM_2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_3, "WID_BRAS_PLATFORM_NUM_3"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_4, "WID_BRAS_PLATFORM_NUM_4"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_5, "WID_BRAS_PLATFORM_NUM_5"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_6, "WID_BRAS_PLATFORM_NUM_6"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_7, "WID_BRAS_PLATFORM_NUM_7"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_1, "WID_BRAS_PLATFORM_LEN_1"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_2, "WID_BRAS_PLATFORM_LEN_2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_3, "WID_BRAS_PLATFORM_LEN_3"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_4, "WID_BRAS_PLATFORM_LEN_4"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_5, "WID_BRAS_PLATFORM_LEN_5"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_6, "WID_BRAS_PLATFORM_LEN_6"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_7, "WID_BRAS_PLATFORM_LEN_7"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DRAG_N_DROP, "WID_BRAS_PLATFORM_DRAG_N_DROP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_HIGHLIGHT_OFF, "WID_BRAS_HIGHLIGHT_OFF"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_HIGHLIGHT_ON, "WID_BRAS_HIGHLIGHT_ON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_COVERAGE_TEXTS, "WID_BRAS_COVERAGE_TEXTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_MATRIX, "WID_BRAS_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_IMAGE, "WID_BRAS_IMAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_MATRIX_SCROLL, "WID_BRAS_MATRIX_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_DEFSIZE, "WID_BRAS_SHOW_NEWST_DEFSIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_ADDITIONS, "WID_BRAS_SHOW_NEWST_ADDITIONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_MATRIX, "WID_BRAS_SHOW_NEWST_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_RESIZE, "WID_BRAS_SHOW_NEWST_RESIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_TYPE, "WID_BRAS_SHOW_NEWST_TYPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_NEWST_LIST, "WID_BRAS_NEWST_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_NEWST_SCROLL, "WID_BRAS_NEWST_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_BEGIN, "WID_BRAS_PLATFORM_NUM_BEGIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_BEGIN, "WID_BRAS_PLATFORM_LEN_BEGIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_NORM, "WID_BS_SEMAPHORE_NORM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_ENTRY, "WID_BS_SEMAPHORE_ENTRY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_EXIT, "WID_BS_SEMAPHORE_EXIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_COMBO, "WID_BS_SEMAPHORE_COMBO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_PBS, "WID_BS_SEMAPHORE_PBS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_PBS_OWAY, "WID_BS_SEMAPHORE_PBS_OWAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_NORM, "WID_BS_ELECTRIC_NORM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_ENTRY, "WID_BS_ELECTRIC_ENTRY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_EXIT, "WID_BS_ELECTRIC_EXIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_COMBO, "WID_BS_ELECTRIC_COMBO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_PBS, "WID_BS_ELECTRIC_PBS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_PBS_OWAY, "WID_BS_ELECTRIC_PBS_OWAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_CONVERT, "WID_BS_CONVERT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_LABEL, "WID_BS_DRAG_SIGNALS_DENSITY_LABEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, "WID_BS_DRAG_SIGNALS_DENSITY_DECREASE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, "WID_BS_DRAG_SIGNALS_DENSITY_INCREASE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_NE, "WID_BRAD_DEPOT_NE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_SE, "WID_BRAD_DEPOT_SE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_SW, "WID_BRAD_DEPOT_SW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_NW, "WID_BRAD_DEPOT_NW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT_MATRIX, "WID_BRW_WAYPOINT_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT, "WID_BRW_WAYPOINT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_SCROLL, "WID_BRW_SCROLL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_X, "WID_ROT_ROAD_X"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_Y, "WID_ROT_ROAD_Y"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_AUTOROAD, "WID_ROT_AUTOROAD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_DEMOLISH, "WID_ROT_DEMOLISH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_DEPOT, "WID_ROT_DEPOT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUS_STATION, "WID_ROT_BUS_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_TRUCK_STATION, "WID_ROT_TRUCK_STATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ONE_WAY, "WID_ROT_ONE_WAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_BRIDGE, "WID_ROT_BUILD_BRIDGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_TUNNEL, "WID_ROT_BUILD_TUNNEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_REMOVE, "WID_ROT_REMOVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_CAPTION, "WID_BROD_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_NE, "WID_BROD_DEPOT_NE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_SE, "WID_BROD_DEPOT_SE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_SW, "WID_BROD_DEPOT_SW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_NW, "WID_BROD_DEPOT_NW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_CAPTION, "WID_BROS_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_BACKGROUND, "WID_BROS_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_NE, "WID_BROS_STATION_NE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_SE, "WID_BROS_STATION_SE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_SW, "WID_BROS_STATION_SW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_NW, "WID_BROS_STATION_NW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_X, "WID_BROS_STATION_X"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_Y, "WID_BROS_STATION_Y"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_LT_OFF, "WID_BROS_LT_OFF"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_LT_ON, "WID_BROS_LT_ON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_INFO, "WID_BROS_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BACKGROUND, "WID_GO_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_CURRENCY_DROPDOWN, "WID_GO_CURRENCY_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_DISTANCE_DROPDOWN, "WID_GO_DISTANCE_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_ROADSIDE_DROPDOWN, "WID_GO_ROADSIDE_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_TOWNNAME_DROPDOWN, "WID_GO_TOWNNAME_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_AUTOSAVE_DROPDOWN, "WID_GO_AUTOSAVE_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_LANG_DROPDOWN, "WID_GO_LANG_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_RESOLUTION_DROPDOWN, "WID_GO_RESOLUTION_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_FULLSCREEN_BUTTON, "WID_GO_FULLSCREEN_BUTTON"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_SCREENSHOT_DROPDOWN, "WID_GO_SCREENSHOT_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_DROPDOWN, "WID_GO_BASE_GRF_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_STATUS, "WID_GO_BASE_GRF_STATUS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_TEXTFILE, "WID_GO_BASE_GRF_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_DESCRIPTION, "WID_GO_BASE_GRF_DESCRIPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_DROPDOWN, "WID_GO_BASE_SFX_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_TEXTFILE, "WID_GO_BASE_SFX_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_DESCRIPTION, "WID_GO_BASE_SFX_DESCRIPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_DROPDOWN, "WID_GO_BASE_MUSIC_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_STATUS, "WID_GO_BASE_MUSIC_STATUS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_TEXTFILE, "WID_GO_BASE_MUSIC_TEXTFILE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_DESCRIPTION, "WID_GO_BASE_MUSIC_DESCRIPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_FILTER, "WID_GS_FILTER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_OPTIONSPANEL, "WID_GS_OPTIONSPANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_SCROLLBAR, "WID_GS_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_HELP_TEXT, "WID_GS_HELP_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_EXPAND_ALL, "WID_GS_EXPAND_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_COLLAPSE_ALL, "WID_GS_COLLAPSE_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_CATEGORY, "WID_GS_RESTRICT_CATEGORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_TYPE, "WID_GS_RESTRICT_TYPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_DROPDOWN, "WID_GS_RESTRICT_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_TYPE_DROPDOWN, "WID_GS_TYPE_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE_DOWN, "WID_CC_RATE_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE_UP, "WID_CC_RATE_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE, "WID_CC_RATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SEPARATOR_EDIT, "WID_CC_SEPARATOR_EDIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SEPARATOR, "WID_CC_SEPARATOR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREFIX_EDIT, "WID_CC_PREFIX_EDIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREFIX, "WID_CC_PREFIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SUFFIX_EDIT, "WID_CC_SUFFIX_EDIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SUFFIX, "WID_CC_SUFFIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR_DOWN, "WID_CC_YEAR_DOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR_UP, "WID_CC_YEAR_UP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR, "WID_CC_YEAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREVIEW, "WID_CC_PREVIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_CAPTION, "WID_SIL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_LIST, "WID_SIL_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_SCROLLBAR, "WID_SIL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_TEXT, "WID_SIL_FILTER_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_MATCH_CASE_BTN, "WID_SIL_FILTER_MATCH_CASE_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_ENTER_BTN, "WID_SIL_FILTER_ENTER_BTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_CAPTION, "WID_QES_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_TEXT, "WID_QES_TEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_OK, "WID_QES_OK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_CANCEL, "WID_QES_CANCEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_DELETE, "WID_QES_DELETE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_PREVIOUS, "WID_QES_PREVIOUS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_NEXT, "WID_QES_NEXT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CAPTION, "WID_SM_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_MAP_BORDER, "WID_SM_MAP_BORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_MAP, "WID_SM_MAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_LEGEND, "WID_SM_LEGEND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_BLANK, "WID_SM_BLANK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ZOOM_IN, "WID_SM_ZOOM_IN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ZOOM_OUT, "WID_SM_ZOOM_OUT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CONTOUR, "WID_SM_CONTOUR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_VEHICLES, "WID_SM_VEHICLES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_INDUSTRIES, "WID_SM_INDUSTRIES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_LINKSTATS, "WID_SM_LINKSTATS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ROUTES, "WID_SM_ROUTES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_VEGETATION, "WID_SM_VEGETATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_OWNERS, "WID_SM_OWNERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CENTERMAP, "WID_SM_CENTERMAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_TOGGLETOWNNAME, "WID_SM_TOGGLETOWNNAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_SELECT_BUTTONS, "WID_SM_SELECT_BUTTONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ENABLE_ALL, "WID_SM_ENABLE_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_DISABLE_ALL, "WID_SM_DISABLE_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_SHOW_HEIGHT, "WID_SM_SHOW_HEIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_CAPTION, "WID_SV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SORT_ORDER, "WID_SV_SORT_ORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SORT_BY, "WID_SV_SORT_BY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_GROUP, "WID_SV_GROUP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_GROUP_BY, "WID_SV_GROUP_BY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_WAITING, "WID_SV_WAITING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SCROLLBAR, "WID_SV_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ACCEPT_RATING_LIST, "WID_SV_ACCEPT_RATING_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_LOCATION, "WID_SV_LOCATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ACCEPTS_RATINGS, "WID_SV_ACCEPTS_RATINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_RENAME, "WID_SV_RENAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_CLOSE_AIRPORT, "WID_SV_CLOSE_AIRPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_TRAINS, "WID_SV_TRAINS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ROADVEHS, "WID_SV_ROADVEHS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SHIPS, "WID_SV_SHIPS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_PLANES, "WID_SV_PLANES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CAPTION, "WID_STL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_LIST, "WID_STL_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SCROLLBAR, "WID_STL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_TRAIN, "WID_STL_TRAIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_TRUCK, "WID_STL_TRUCK"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_BUS, "WID_STL_BUS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_AIRPLANE, "WID_STL_AIRPLANE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SHIP, "WID_STL_SHIP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_FACILALL, "WID_STL_FACILALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_NOCARGOWAITING, "WID_STL_NOCARGOWAITING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CARGOALL, "WID_STL_CARGOALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SORTBY, "WID_STL_SORTBY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SORTDROPBTN, "WID_STL_SORTDROPBTN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CARGOSTART, "WID_STL_CARGOSTART"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_CAPTION, "WID_JS_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_PANEL, "WID_JS_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_SCROLLBAR, "WID_JS_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_LEFT, "WID_S_LEFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_MIDDLE, "WID_S_MIDDLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_RIGHT, "WID_S_RIGHT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_CAPTION, "WID_SB_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_SEL_PAGE, "WID_SB_SEL_PAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_PAGE_PANEL, "WID_SB_PAGE_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_SCROLLBAR, "WID_SB_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_PREV_PAGE, "WID_SB_PREV_PAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_NEXT_PAGE, "WID_SB_NEXT_PAGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SUL_PANEL, "WID_SUL_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SUL_SCROLLBAR, "WID_SUL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SHOW_PLACE_OBJECT, "WID_TT_SHOW_PLACE_OBJECT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUTTONS_START, "WID_TT_BUTTONS_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LOWER_LAND, "WID_TT_LOWER_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_RAISE_LAND, "WID_TT_RAISE_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LEVEL_LAND, "WID_TT_LEVEL_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_DEMOLISH, "WID_TT_DEMOLISH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUY_LAND, "WID_TT_BUY_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLANT_TREES, "WID_TT_PLANT_TREES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLACE_SIGN, "WID_TT_PLACE_SIGN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLACE_OBJECT, "WID_TT_PLACE_OBJECT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_SHOW_PLACE_DESERT, "WID_ETT_SHOW_PLACE_DESERT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_START, "WID_ETT_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DOTS, "WID_ETT_DOTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_BUTTONS_START, "WID_ETT_BUTTONS_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DEMOLISH, "WID_ETT_DEMOLISH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_LOWER_LAND, "WID_ETT_LOWER_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_RAISE_LAND, "WID_ETT_RAISE_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_LEVEL_LAND, "WID_ETT_LEVEL_LAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_ROCKS, "WID_ETT_PLACE_ROCKS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_DESERT, "WID_ETT_PLACE_DESERT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_OBJECT, "WID_ETT_PLACE_OBJECT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_BUTTONS_END, "WID_ETT_BUTTONS_END"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_INCREASE_SIZE, "WID_ETT_INCREASE_SIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DECREASE_SIZE, "WID_ETT_DECREASE_SIZE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_NEW_SCENARIO, "WID_ETT_NEW_SCENARIO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_RESET_LANDSCAPE, "WID_ETT_RESET_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CAPTION, "WID_VT_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ORDER_VIEW, "WID_VT_ORDER_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_TIMETABLE_PANEL, "WID_VT_TIMETABLE_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ARRIVAL_DEPARTURE_PANEL, "WID_VT_ARRIVAL_DEPARTURE_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SCROLLBAR, "WID_VT_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SUMMARY_PANEL, "WID_VT_SUMMARY_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_START_DATE, "WID_VT_START_DATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CHANGE_TIME, "WID_VT_CHANGE_TIME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CLEAR_TIME, "WID_VT_CLEAR_TIME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_RESET_LATENESS, "WID_VT_RESET_LATENESS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_AUTOFILL, "WID_VT_AUTOFILL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_EXPECTED, "WID_VT_EXPECTED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SHARED_ORDER_LIST, "WID_VT_SHARED_ORDER_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ARRIVAL_DEPARTURE_SELECTION, "WID_VT_ARRIVAL_DEPARTURE_SELECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_EXPECTED_SELECTION, "WID_VT_EXPECTED_SELECTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CHANGE_SPEED, "WID_VT_CHANGE_SPEED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CLEAR_SPEED, "WID_VT_CLEAR_SPEED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_PAUSE, "WID_TN_PAUSE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_FAST_FORWARD, "WID_TN_FAST_FORWARD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SETTINGS, "WID_TN_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SAVE, "WID_TN_SAVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SMALL_MAP, "WID_TN_SMALL_MAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_TOWNS, "WID_TN_TOWNS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SUBSIDIES, "WID_TN_SUBSIDIES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_STATIONS, "WID_TN_STATIONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_FINANCES, "WID_TN_FINANCES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_COMPANIES, "WID_TN_COMPANIES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_STORY, "WID_TN_STORY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_GOAL, "WID_TN_GOAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_GRAPHS, "WID_TN_GRAPHS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_LEAGUE, "WID_TN_LEAGUE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_INDUSTRIES, "WID_TN_INDUSTRIES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_VEHICLE_START, "WID_TN_VEHICLE_START"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_TRAINS, "WID_TN_TRAINS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ROADVEHS, "WID_TN_ROADVEHS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SHIPS, "WID_TN_SHIPS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_AIRCRAFTS, "WID_TN_AIRCRAFTS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ZOOM_IN, "WID_TN_ZOOM_IN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ZOOM_OUT, "WID_TN_ZOOM_OUT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_RAILS, "WID_TN_RAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ROADS, "WID_TN_ROADS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_WATER, "WID_TN_WATER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_AIR, "WID_TN_AIR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_LANDSCAPE, "WID_TN_LANDSCAPE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_MUSIC_SOUND, "WID_TN_MUSIC_SOUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_MESSAGES, "WID_TN_MESSAGES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_HELP, "WID_TN_HELP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SWITCH_BAR, "WID_TN_SWITCH_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_END, "WID_TN_END"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_PAUSE, "WID_TE_PAUSE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_FAST_FORWARD, "WID_TE_FAST_FORWARD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SETTINGS, "WID_TE_SETTINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SAVE, "WID_TE_SAVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SPACER, "WID_TE_SPACER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE, "WID_TE_DATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_BACKWARD, "WID_TE_DATE_BACKWARD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_FORWARD, "WID_TE_DATE_FORWARD"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SMALL_MAP, "WID_TE_SMALL_MAP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ZOOM_IN, "WID_TE_ZOOM_IN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ZOOM_OUT, "WID_TE_ZOOM_OUT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_LAND_GENERATE, "WID_TE_LAND_GENERATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TOWN_GENERATE, "WID_TE_TOWN_GENERATE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_INDUSTRY, "WID_TE_INDUSTRY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ROADS, "WID_TE_ROADS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_WATER, "WID_TE_WATER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TREES, "WID_TE_TREES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SIGNS, "WID_TE_SIGNS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_PANEL, "WID_TE_DATE_PANEL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_MUSIC_SOUND, "WID_TE_MUSIC_SOUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_HELP, "WID_TE_HELP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SWITCH_BAR, "WID_TE_SWITCH_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_X, "WID_TT_X"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_DELETE, "WID_TT_DELETE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SHIFT, "WID_TT_SHIFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_CTRL, "WID_TT_CTRL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_MOVE, "WID_TT_MOVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_ORDER, "WID_TD_SORT_ORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_CRITERIA, "WID_TD_SORT_CRITERIA"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_LIST, "WID_TD_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SCROLLBAR, "WID_TD_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_WORLD_POPULATION, "WID_TD_WORLD_POPULATION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_CAPTION, "WID_TA_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_RATING_INFO, "WID_TA_RATING_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_COMMAND_LIST, "WID_TA_COMMAND_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_SCROLLBAR, "WID_TA_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_ACTION_INFO, "WID_TA_ACTION_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_EXECUTE, "WID_TA_EXECUTE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CAPTION, "WID_TV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_VIEWPORT, "WID_TV_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_INFO, "WID_TV_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CENTER_VIEW, "WID_TV_CENTER_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_SHOW_AUTHORITY, "WID_TV_SHOW_AUTHORITY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CHANGE_NAME, "WID_TV_CHANGE_NAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_EXPAND, "WID_TV_EXPAND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_DELETE, "WID_TV_DELETE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_NEW_TOWN, "WID_TF_NEW_TOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_RANDOM_TOWN, "WID_TF_RANDOM_TOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_MANY_RANDOM_TOWNS, "WID_TF_MANY_RANDOM_TOWNS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_TOWN_NAME_EDITBOX, "WID_TF_TOWN_NAME_EDITBOX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_TOWN_NAME_RANDOM, "WID_TF_TOWN_NAME_RANDOM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_SMALL, "WID_TF_SIZE_SMALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_MEDIUM, "WID_TF_SIZE_MEDIUM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_LARGE, "WID_TF_SIZE_LARGE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_RANDOM, "WID_TF_SIZE_RANDOM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_CITY, "WID_TF_CITY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_ORIGINAL, "WID_TF_LAYOUT_ORIGINAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_BETTER, "WID_TF_LAYOUT_BETTER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_GRID2, "WID_TF_LAYOUT_GRID2"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_GRID3, "WID_TF_LAYOUT_GRID3"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_RANDOM, "WID_TF_LAYOUT_RANDOM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BEGIN, "WID_TT_BEGIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SIGNS, "WID_TT_SIGNS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_TREES, "WID_TT_TREES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_HOUSES, "WID_TT_HOUSES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_INDUSTRIES, "WID_TT_INDUSTRIES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUILDINGS, "WID_TT_BUILDINGS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BRIDGES, "WID_TT_BRIDGES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_STRUCTURES, "WID_TT_STRUCTURES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_CATENARY, "WID_TT_CATENARY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LOADING, "WID_TT_LOADING"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_END, "WID_TT_END"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUTTONS, "WID_TT_BUTTONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_11, "WID_BT_TYPE_11"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_12, "WID_BT_TYPE_12"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_13, "WID_BT_TYPE_13"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_14, "WID_BT_TYPE_14"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_21, "WID_BT_TYPE_21"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_22, "WID_BT_TYPE_22"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_23, "WID_BT_TYPE_23"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_24, "WID_BT_TYPE_24"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_31, "WID_BT_TYPE_31"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_32, "WID_BT_TYPE_32"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_33, "WID_BT_TYPE_33"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_34, "WID_BT_TYPE_34"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_RANDOM, "WID_BT_TYPE_RANDOM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_MANY_RANDOM, "WID_BT_MANY_RANDOM"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CAPTION, "WID_VV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_VIEWPORT, "WID_VV_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_START_STOP, "WID_VV_START_STOP"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CENTER_MAIN_VIEW, "WID_VV_CENTER_MAIN_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_GOTO_DEPOT, "WID_VV_GOTO_DEPOT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_REFIT, "WID_VV_REFIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SHOW_ORDERS, "WID_VV_SHOW_ORDERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SHOW_DETAILS, "WID_VV_SHOW_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CLONE, "WID_VV_CLONE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SELECT_DEPOT_CLONE, "WID_VV_SELECT_DEPOT_CLONE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SELECT_REFIT_TURN, "WID_VV_SELECT_REFIT_TURN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_TURN_AROUND, "WID_VV_TURN_AROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_FORCE_PROCEED, "WID_VV_FORCE_PROCEED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_CAPTION, "WID_VR_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_VEHICLE_PANEL_DISPLAY, "WID_VR_VEHICLE_PANEL_DISPLAY"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SHOW_HSCROLLBAR, "WID_VR_SHOW_HSCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_HSCROLLBAR, "WID_VR_HSCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SELECT_HEADER, "WID_VR_SELECT_HEADER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_MATRIX, "WID_VR_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SCROLLBAR, "WID_VR_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_INFO, "WID_VR_INFO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_REFIT, "WID_VR_REFIT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_CAPTION, "WID_VD_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_RENAME_VEHICLE, "WID_VD_RENAME_VEHICLE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_TOP_DETAILS, "WID_VD_TOP_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_INCREASE_SERVICING_INTERVAL, "WID_VD_INCREASE_SERVICING_INTERVAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DECREASE_SERVICING_INTERVAL, "WID_VD_DECREASE_SERVICING_INTERVAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SERVICE_INTERVAL_DROPDOWN, "WID_VD_SERVICE_INTERVAL_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SERVICING_INTERVAL, "WID_VD_SERVICING_INTERVAL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_MIDDLE_DETAILS, "WID_VD_MIDDLE_DETAILS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_MATRIX, "WID_VD_MATRIX"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SCROLLBAR, "WID_VD_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_CARGO_CARRIED, "WID_VD_DETAILS_CARGO_CARRIED"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_TRAIN_VEHICLES, "WID_VD_DETAILS_TRAIN_VEHICLES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_CAPACITY_OF_EACH, "WID_VD_DETAILS_CAPACITY_OF_EACH"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_TOTAL_CARGO, "WID_VD_DETAILS_TOTAL_CARGO"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_CAPTION, "WID_VL_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SORT_ORDER, "WID_VL_SORT_ORDER"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SORT_BY_PULLDOWN, "WID_VL_SORT_BY_PULLDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_LIST, "WID_VL_LIST"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SCROLLBAR, "WID_VL_SCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_HIDE_BUTTONS, "WID_VL_HIDE_BUTTONS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_AVAILABLE_VEHICLES, "WID_VL_AVAILABLE_VEHICLES"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_MANAGE_VEHICLES_DROPDOWN, "WID_VL_MANAGE_VEHICLES_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_STOP_ALL, "WID_VL_STOP_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_START_ALL, "WID_VL_START_ALL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_CAPTION, "WID_EV_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_VIEWPORT, "WID_EV_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_ZOOM_IN, "WID_EV_ZOOM_IN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_ZOOM_OUT, "WID_EV_ZOOM_OUT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_MAIN_TO_VIEW, "WID_EV_MAIN_TO_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_VIEW_TO_MAIN, "WID_EV_VIEW_TO_MAIN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_CAPTION, "WID_W_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_VIEWPORT, "WID_W_VIEWPORT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_CENTER_VIEW, "WID_W_CENTER_VIEW"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_RENAME, "WID_W_RENAME"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_SHOW_VEHICLES, "WID_W_SHOW_VEHICLES"); - - SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::Close, "Close", 3, ".ii"); - SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::IsOpen, "IsOpen", 3, ".ii"); - SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::Highlight, "Highlight", 5, ".iiii"); - - SQGSWindow.PostRegister(engine); -} diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index 9f77cc6dcb..518b90da88 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -371,6 +371,7 @@ Window *ShowTerraformToolbar(Window *link) Window *w; if (link == NULL) { + DeleteToolbarLinkedWindows(); w = AllocateWindowDescFront(&_terraform_desc, 0); return w; } @@ -761,5 +762,6 @@ static WindowDesc _scen_edit_land_gen_desc( */ Window *ShowEditorTerraformToolbar() { + DeleteToolbarLinkedWindows(); return AllocateWindowDescFront(&_scen_edit_land_gen_desc, 0); } diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 93300f15b4..335ba9a826 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -1210,5 +1210,6 @@ static WindowDesc _found_town_desc( void ShowFoundTownWindow() { if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return; + DeleteToolbarLinkedWindows(); AllocateWindowDescFront(&_found_town_desc, 0); } diff --git a/src/window.cpp.orig b/src/window.cpp.orig deleted file mode 100644 index b9a9651491..0000000000 --- a/src/window.cpp.orig +++ /dev/null @@ -1,3527 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file window.cpp Windowing system, widgets and events */ - -#include "stdafx.h" -#include -#include "company_func.h" -#include "gfx_func.h" -#include "console_func.h" -#include "console_gui.h" -#include "viewport_func.h" -#include "progress.h" -#include "blitter/factory.hpp" -#include "zoom_func.h" -#include "vehicle_base.h" -#include "window_func.h" -#include "tilehighlight_func.h" -#include "network/network.h" -#include "querystring_gui.h" -#include "widgets/dropdown_func.h" -#include "strings_func.h" -#include "settings_type.h" -#include "settings_func.h" -#include "ini_type.h" -#include "newgrf_debug.h" -#include "hotkeys.h" -#include "toolbar_gui.h" -#include "statusbar_gui.h" -#include "error.h" -#include "game/game.hpp" -#include "video/video_driver.hpp" -#include "settings_gui.h" -#include "fontcache.h" -#include "error.h" -#include "station_base.h" -#include "waypoint_base.h" -#include "command_func.h" - -#include "table/strings.h" - -/** Values for _settings_client.gui.auto_scrolling */ -enum ViewportAutoscrolling { - VA_DISABLED, //!< Do not autoscroll when mouse is at edge of viewport. - VA_MAIN_VIEWPORT_FULLSCREEN, //!< Scroll main viewport at edge when using fullscreen. - VA_MAIN_VIEWPORT, //!< Scroll main viewport at edge. - VA_EVERY_VIEWPORT, //!< Scroll all viewports at their edges. -}; - -static Point _drag_delta; ///< delta between mouse cursor and upper left corner of dragged window -static Window *_mouseover_last_w = NULL; ///< Window of the last #MOUSEOVER event. -static Window *_last_scroll_window = NULL; ///< Window of the last scroll event. - -/** List of windows opened at the screen sorted from the front. */ -Window *_z_front_window = NULL; -/** List of windows opened at the screen sorted from the back. */ -Window *_z_back_window = NULL; - -/** If false, highlight is white, otherwise the by the widget defined colour. */ -bool _window_highlight_colour = false; - -/* - * Window that currently has focus. - The main purpose is to generate - * #FocusLost events, not to give next window in z-order focus when a - * window is closed. - */ -Window *_focused_window; - -Point _cursorpos_drag_start; - -int _scrollbar_start_pos; -int _scrollbar_size; -byte _scroller_click_timeout = 0; - -bool _scrolling_viewport; ///< A viewport is being scrolled with the mouse. -bool _mouse_hovering; ///< The mouse is hovering over the same point. - -SpecialMouseMode _special_mouse_mode; ///< Mode of the mouse. - -/** - * List of all WindowDescs. - * This is a pointer to ensure initialisation order with the various static WindowDesc instances. - */ -static SmallVector *_window_descs = NULL; - -/** Config file to store WindowDesc */ -char *_windows_file; - -/** Window description constructor. */ -WindowDesc::WindowDesc(WindowPosition def_pos, const char *ini_key, int16 def_width, int16 def_height, - WindowClass window_class, WindowClass parent_class, uint32 flags, - const NWidgetPart *nwid_parts, int16 nwid_length, HotkeyList *hotkeys) : - default_pos(def_pos), - default_width(def_width), - default_height(def_height), - cls(window_class), - parent_cls(parent_class), - ini_key(ini_key), - flags(flags), - nwid_parts(nwid_parts), - nwid_length(nwid_length), - hotkeys(hotkeys), - pref_sticky(false), - pref_width(0), - pref_height(0) -{ - if (_window_descs == NULL) _window_descs = new SmallVector(); - *_window_descs->Append() = this; -} - -WindowDesc::~WindowDesc() -{ - _window_descs->Erase(_window_descs->Find(this)); -} - -/** - * Load all WindowDesc settings from _windows_file. - */ -void WindowDesc::LoadFromConfig() -{ - IniFile *ini = new IniFile(); - ini->LoadFromDisk(_windows_file, BASE_DIR); - for (WindowDesc **it = _window_descs->Begin(); it != _window_descs->End(); ++it) { - if ((*it)->ini_key == NULL) continue; - IniLoadWindowSettings(ini, (*it)->ini_key, *it); - } - delete ini; -} - -/** - * Sort WindowDesc by ini_key. - */ -static int CDECL DescSorter(WindowDesc * const *a, WindowDesc * const *b) -{ - if ((*a)->ini_key != NULL && (*b)->ini_key != NULL) return strcmp((*a)->ini_key, (*b)->ini_key); - return ((*b)->ini_key != NULL ? 1 : 0) - ((*a)->ini_key != NULL ? 1 : 0); -} - -/** - * Save all WindowDesc settings to _windows_file. - */ -void WindowDesc::SaveToConfig() -{ - /* Sort the stuff to get a nice ini file on first write */ - QSortT(_window_descs->Begin(), _window_descs->Length(), DescSorter); - - IniFile *ini = new IniFile(); - ini->LoadFromDisk(_windows_file, BASE_DIR); - for (WindowDesc **it = _window_descs->Begin(); it != _window_descs->End(); ++it) { - if ((*it)->ini_key == NULL) continue; - IniSaveWindowSettings(ini, (*it)->ini_key, *it); - } - ini->SaveToDisk(_windows_file); - delete ini; -} - -/** - * Read default values from WindowDesc configuration an apply them to the window. - */ -void Window::ApplyDefaults() -{ - if (this->nested_root != NULL && this->nested_root->GetWidgetOfType(WWT_STICKYBOX) != NULL) { - if (this->window_desc->pref_sticky) this->flags |= WF_STICKY; - } else { - /* There is no stickybox; clear the preference in case someone tried to be funny */ - this->window_desc->pref_sticky = false; - } -} - -/** - * Compute the row of a widget that a user clicked in. - * @param clickpos Vertical position of the mouse click. - * @param widget Widget number of the widget clicked in. - * @param padding Amount of empty space between the widget edge and the top of the first row. - * @param line_height Height of a single row. A negative value means using the vertical resize step of the widget. - * @return Row number clicked at. If clicked at a wrong position, #INT_MAX is returned. - * @note The widget does not know where a list printed at the widget ends, so below a list is not a wrong position. - */ -int Window::GetRowFromWidget(int clickpos, int widget, int padding, int line_height) const -{ - const NWidgetBase *wid = this->GetWidget(widget); - if (line_height < 0) line_height = wid->resize_y; - if (clickpos < (int)wid->pos_y + padding) return INT_MAX; - return (clickpos - (int)wid->pos_y - padding) / line_height; -} - -/** - * Disable the highlighted status of all widgets. - */ -void Window::DisableAllWidgetHighlight() -{ - for (uint i = 0; i < this->nested_array_size; i++) { - NWidgetBase *nwid = this->GetWidget(i); - if (nwid == NULL) continue; - - if (nwid->IsHighlighted()) { - nwid->SetHighlighted(TC_INVALID); - this->SetWidgetDirty(i); - } - } - - CLRBITS(this->flags, WF_HIGHLIGHTED); -} - -/** - * Sets the highlighted status of a widget. - * @param widget_index index of this widget in the window - * @param highlighted_colour Colour of highlight, or TC_INVALID to disable. - */ -void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour) -{ - assert(widget_index < this->nested_array_size); - - NWidgetBase *nwid = this->GetWidget(widget_index); - if (nwid == NULL) return; - - nwid->SetHighlighted(highlighted_colour); - this->SetWidgetDirty(widget_index); - - if (highlighted_colour != TC_INVALID) { - /* If we set a highlight, the window has a highlight */ - this->flags |= WF_HIGHLIGHTED; - } else { - /* If we disable a highlight, check all widgets if anyone still has a highlight */ - bool valid = false; - for (uint i = 0; i < this->nested_array_size; i++) { - NWidgetBase *nwid = this->GetWidget(i); - if (nwid == NULL) continue; - if (!nwid->IsHighlighted()) continue; - - valid = true; - } - /* If nobody has a highlight, disable the flag on the window */ - if (!valid) CLRBITS(this->flags, WF_HIGHLIGHTED); - } -} - -/** - * Gets the highlighted status of a widget. - * @param widget_index index of this widget in the window - * @return status of the widget ie: highlighted = true, not highlighted = false - */ -bool Window::IsWidgetHighlighted(byte widget_index) const -{ - assert(widget_index < this->nested_array_size); - - const NWidgetBase *nwid = this->GetWidget(widget_index); - if (nwid == NULL) return false; - - return nwid->IsHighlighted(); -} - -/** - * A dropdown window associated to this window has been closed. - * @param pt the point inside the window the mouse resides on after closure. - * @param widget the widget (button) that the dropdown is associated with. - * @param index the element in the dropdown that is selected. - * @param instant_close whether the dropdown was configured to close on mouse up. - */ -void Window::OnDropdownClose(Point pt, int widget, int index, bool instant_close) -{ - if (widget < 0) return; - - if (instant_close) { - /* Send event for selected option if we're still - * on the parent button of the dropdown (behaviour of the dropdowns in the main toolbar). */ - if (GetWidgetFromPos(this, pt.x, pt.y) == widget) { - this->OnDropdownSelect(widget, index); - } - } - - /* Raise the dropdown button */ - NWidgetCore *nwi2 = this->GetWidget(widget); - if ((nwi2->type & WWT_MASK) == NWID_BUTTON_DROPDOWN) { - nwi2->disp_flags &= ~ND_DROPDOWN_ACTIVE; - } else { - this->RaiseWidget(widget); - } - this->SetWidgetDirty(widget); -} - -/** - * Return the Scrollbar to a widget index. - * @param widnum Scrollbar widget index - * @return Scrollbar to the widget - */ -const Scrollbar *Window::GetScrollbar(uint widnum) const -{ - return this->GetWidget(widnum); -} - -/** - * Return the Scrollbar to a widget index. - * @param widnum Scrollbar widget index - * @return Scrollbar to the widget - */ -Scrollbar *Window::GetScrollbar(uint widnum) -{ - return this->GetWidget(widnum); -} - -/** - * Return the querystring associated to a editbox. - * @param widnum Editbox widget index - * @return QueryString or NULL. - */ -const QueryString *Window::GetQueryString(uint widnum) const -{ - const SmallMap::Pair *query = this->querystrings.Find(widnum); - return query != this->querystrings.End() ? query->second : NULL; -} - -/** - * Return the querystring associated to a editbox. - * @param widnum Editbox widget index - * @return QueryString or NULL. - */ -QueryString *Window::GetQueryString(uint widnum) -{ - SmallMap::Pair *query = this->querystrings.Find(widnum); - return query != this->querystrings.End() ? query->second : NULL; -} - -/** - * Get the current input text if an edit box has the focus. - * @return The currently focused input text or NULL if no input focused. - */ -/* virtual */ const char *Window::GetFocusedText() const -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { - return this->GetQueryString(this->nested_focus->index)->GetText(); - } - - return NULL; -} - -/** - * Get the string at the caret if an edit box has the focus. - * @return The text at the caret or NULL if no edit box is focused. - */ -/* virtual */ const char *Window::GetCaret() const -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { - return this->GetQueryString(this->nested_focus->index)->GetCaret(); - } - - return NULL; -} - -/** - * Get the range of the currently marked input text. - * @param[out] length Length of the marked text. - * @return Pointer to the start of the marked text or NULL if no text is marked. - */ -/* virtual */ const char *Window::GetMarkedText(size_t *length) const -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { - return this->GetQueryString(this->nested_focus->index)->GetMarkedText(length); - } - - return NULL; -} - -/** - * Get the current caret position if an edit box has the focus. - * @return Top-left location of the caret, relative to the window. - */ -/* virtual */ Point Window::GetCaretPosition() const -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { - return this->GetQueryString(this->nested_focus->index)->GetCaretPosition(this, this->nested_focus->index); - } - - Point pt = {0, 0}; - return pt; -} - -/** - * Get the bounding rectangle for a text range if an edit box has the focus. - * @param from Start of the string range. - * @param to End of the string range. - * @return Rectangle encompassing the string range, relative to the window. - */ -/* virtual */ Rect Window::GetTextBoundingRect(const char *from, const char *to) const -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { - return this->GetQueryString(this->nested_focus->index)->GetBoundingRect(this, this->nested_focus->index, from, to); - } - - Rect r = {0, 0, 0, 0}; - return r; -} - -/** - * Get the character that is rendered at a position by the focused edit box. - * @param pt The position to test. - * @return Pointer to the character at the position or NULL if no character is at the position. - */ -/* virtual */ const char *Window::GetTextCharacterAtPosition(const Point &pt) const -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { - return this->GetQueryString(this->nested_focus->index)->GetCharAtPosition(this, this->nested_focus->index, pt); - } - - return NULL; -} - -/** - * Set the window that has the focus - * @param w The window to set the focus on - */ -void SetFocusedWindow(Window *w) -{ - if (_focused_window == w) return; - - /* Invalidate focused widget */ - if (_focused_window != NULL) { - if (_focused_window->nested_focus != NULL) _focused_window->nested_focus->SetDirty(_focused_window); - } - - /* Remember which window was previously focused */ - Window *old_focused = _focused_window; - _focused_window = w; - - /* So we can inform it that it lost focus */ - if (old_focused != NULL) old_focused->OnFocusLost(); - if (_focused_window != NULL) _focused_window->OnFocus(); -} - -/** - * Check if an edit box is in global focus. That is if focused window - * has a edit box as focused widget, or if a console is focused. - * @return returns true if an edit box is in global focus or if the focused window is a console, else false - */ -bool EditBoxInGlobalFocus() -{ - if (_focused_window == NULL) return false; - - /* The console does not have an edit box so a special case is needed. */ - if (_focused_window->window_class == WC_CONSOLE) return true; - - return _focused_window->nested_focus != NULL && _focused_window->nested_focus->type == WWT_EDITBOX; -} - -/** - * Makes no widget on this window have focus. The function however doesn't change which window has focus. - */ -void Window::UnfocusFocusedWidget() -{ - if (this->nested_focus != NULL) { - if (this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus(); - - /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ - this->nested_focus->SetDirty(this); - this->nested_focus = NULL; - } -} - -/** - * Set focus within this window to the given widget. The function however doesn't change which window has focus. - * @param widget_index Index of the widget in the window to set the focus to. - * @return Focus has changed. - */ -bool Window::SetFocusedWidget(int widget_index) -{ - /* Do nothing if widget_index is already focused, or if it wasn't a valid widget. */ - if ((uint)widget_index >= this->nested_array_size) return false; - - assert(this->nested_array[widget_index] != NULL); // Setting focus to a non-existing widget is a bad idea. - if (this->nested_focus != NULL) { - if (this->GetWidget(widget_index) == this->nested_focus) return false; - - /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ - this->nested_focus->SetDirty(this); - if (this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus(); - } - this->nested_focus = this->GetWidget(widget_index); - return true; -} - -/** - * Called when window looses focus - */ -void Window::OnFocusLost() -{ - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus(); -} - -/** - * Sets the enabled/disabled status of a list of widgets. - * By default, widgets are enabled. - * On certain conditions, they have to be disabled. - * @param disab_stat status to use ie: disabled = true, enabled = false - * @param widgets list of widgets ended by WIDGET_LIST_END - */ -void CDECL Window::SetWidgetsDisabledState(bool disab_stat, int widgets, ...) -{ - va_list wdg_list; - - va_start(wdg_list, widgets); - - while (widgets != WIDGET_LIST_END) { - SetWidgetDisabledState(widgets, disab_stat); - widgets = va_arg(wdg_list, int); - } - - va_end(wdg_list); -} - -/** - * Sets the lowered/raised status of a list of widgets. - * @param lowered_stat status to use ie: lowered = true, raised = false - * @param widgets list of widgets ended by WIDGET_LIST_END - */ -void CDECL Window::SetWidgetsLoweredState(bool lowered_stat, int widgets, ...) -{ - va_list wdg_list; - - va_start(wdg_list, widgets); - - while (widgets != WIDGET_LIST_END) { - SetWidgetLoweredState(widgets, lowered_stat); - widgets = va_arg(wdg_list, int); - } - - va_end(wdg_list); -} - -/** - * Raise the buttons of the window. - * @param autoraise Raise only the push buttons of the window. - */ -void Window::RaiseButtons(bool autoraise) -{ - for (uint i = 0; i < this->nested_array_size; i++) { - if (this->nested_array[i] == NULL) continue; - WidgetType type = this->nested_array[i]->type; - if (((type & ~WWB_PUSHBUTTON) < WWT_LAST || type == NWID_PUSHBUTTON_DROPDOWN) && - (!autoraise || (type & WWB_PUSHBUTTON) || type == WWT_EDITBOX) && this->IsWidgetLowered(i)) { - this->RaiseWidget(i); - this->SetWidgetDirty(i); - } - } - - /* Special widgets without widget index */ - NWidgetCore *wid = this->nested_root != NULL ? (NWidgetCore*)this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX) : NULL; - if (wid != NULL) { - wid->SetLowered(false); - wid->SetDirty(this); - } -} - -/** - * Invalidate a widget, i.e. mark it as being changed and in need of redraw. - * @param widget_index the widget to redraw. - */ -void Window::SetWidgetDirty(byte widget_index) const -{ - /* Sometimes this function is called before the window is even fully initialized */ - if (this->nested_array == NULL) return; - - this->nested_array[widget_index]->SetDirty(this); -} - -/** - * A hotkey has been pressed. - * @param hotkey Hotkey index, by default a widget index of a button or editbox. - * @return #ES_HANDLED if the key press has been handled, and the hotkey is not unavailable for some reason. - */ -EventState Window::OnHotkey(int hotkey) -{ - if (hotkey < 0) return ES_NOT_HANDLED; - - NWidgetCore *nw = this->GetWidget(hotkey); - if (nw == NULL || nw->IsDisabled()) return ES_NOT_HANDLED; - - if (nw->type == WWT_EDITBOX) { - if (this->IsShaded()) return ES_NOT_HANDLED; - - /* Focus editbox */ - this->SetFocusedWidget(hotkey); - SetFocusedWindow(this); - } else { - /* Click button */ - this->OnClick(Point(), hotkey, 1); - } - return ES_HANDLED; -} - -/** - * Do all things to make a button look clicked and mark it to be - * unclicked in a few ticks. - * @param widget the widget to "click" - */ -void Window::HandleButtonClick(byte widget) -{ - this->LowerWidget(widget); - this->SetTimeout(); - this->SetWidgetDirty(widget); -} - -static void StartWindowDrag(Window *w); -static void StartWindowSizing(Window *w, bool to_left); - -/** - * Dispatch left mouse-button (possibly double) click in window. - * @param w Window to dispatch event in - * @param x X coordinate of the click - * @param y Y coordinate of the click - * @param click_count Number of fast consecutive clicks at same position - */ -static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count) -{ - NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y); - WidgetType widget_type = (nw != NULL) ? nw->type : WWT_EMPTY; - - bool focused_widget_changed = false; - /* If clicked on a window that previously did dot have focus */ - if (_focused_window != w && // We already have focus, right? - (w->window_desc->flags & WDF_NO_FOCUS) == 0 && // Don't lose focus to toolbars - widget_type != WWT_CLOSEBOX) { // Don't change focused window if 'X' (close button) was clicked - focused_widget_changed = true; - SetFocusedWindow(w); - } - - if (nw == NULL) return; // exit if clicked outside of widgets - - /* don't allow any interaction if the button has been disabled */ - if (nw->IsDisabled()) return; - - int widget_index = nw->index; ///< Index of the widget - - /* Clicked on a widget that is not disabled. - * So unless the clicked widget is the caption bar, change focus to this widget. - * Exception: In the OSK we always want the editbox to stay focussed. */ - if (widget_type != WWT_CAPTION && w->window_class != WC_OSK) { - /* focused_widget_changed is 'now' only true if the window this widget - * is in gained focus. In that case it must remain true, also if the - * local widget focus did not change. As such it's the logical-or of - * both changed states. - * - * If this is not preserved, then the OSK window would be opened when - * a user has the edit box focused and then click on another window and - * then back again on the edit box (to type some text). - */ - focused_widget_changed |= w->SetFocusedWidget(widget_index); - } - - /* Close any child drop down menus. If the button pressed was the drop down - * list's own button, then we should not process the click any further. */ - if (HideDropDownMenu(w) == widget_index && widget_index >= 0) return; - - if ((widget_type & ~WWB_PUSHBUTTON) < WWT_LAST && (widget_type & WWB_PUSHBUTTON)) w->HandleButtonClick(widget_index); - - Point pt = { x, y }; - - switch (widget_type) { - case NWID_VSCROLLBAR: - case NWID_HSCROLLBAR: - ScrollbarClickHandler(w, nw, x, y); - break; - - case WWT_EDITBOX: { - QueryString *query = w->GetQueryString(widget_index); - if (query != NULL) query->ClickEditBox(w, pt, widget_index, click_count, focused_widget_changed); - break; - } - - case WWT_CLOSEBOX: // 'X' - delete w; - return; - - case WWT_CAPTION: // 'Title bar' - StartWindowDrag(w); - return; - - case WWT_RESIZEBOX: - /* When the resize widget is on the left size of the window - * we assume that that button is used to resize to the left. */ - StartWindowSizing(w, (int)nw->pos_x < (w->width / 2)); - nw->SetDirty(w); - return; - - case WWT_DEFSIZEBOX: { - if (_ctrl_pressed) { - w->window_desc->pref_width = w->width; - w->window_desc->pref_height = w->height; - } else { - int16 def_width = max(min(w->window_desc->GetDefaultWidth(), _screen.width), w->nested_root->smallest_x); - int16 def_height = max(min(w->window_desc->GetDefaultHeight(), _screen.height - 50), w->nested_root->smallest_y); - - int dx = (w->resize.step_width == 0) ? 0 : def_width - w->width; - int dy = (w->resize.step_height == 0) ? 0 : def_height - w->height; - /* dx and dy has to go by step.. calculate it. - * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */ - if (w->resize.step_width > 1) dx -= dx % (int)w->resize.step_width; - if (w->resize.step_height > 1) dy -= dy % (int)w->resize.step_height; - ResizeWindow(w, dx, dy, false); - } - - nw->SetLowered(true); - nw->SetDirty(w); - w->SetTimeout(); - break; - } - - case WWT_DEBUGBOX: - w->ShowNewGRFInspectWindow(); - break; - - case WWT_SHADEBOX: - nw->SetDirty(w); - w->SetShaded(!w->IsShaded()); - return; - - case WWT_STICKYBOX: - w->flags ^= WF_STICKY; - nw->SetDirty(w); - if (_ctrl_pressed) w->window_desc->pref_sticky = (w->flags & WF_STICKY) != 0; - return; - - default: - break; - } - - /* Widget has no index, so the window is not interested in it. */ - if (widget_index < 0) return; - - /* Check if the widget is highlighted; if so, disable highlight and dispatch an event to the GameScript */ - if (w->IsWidgetHighlighted(widget_index)) { - w->SetWidgetHighlight(widget_index, TC_INVALID); - Game::NewEvent(new ScriptEventWindowWidgetClick((ScriptWindow::WindowClass)w->window_class, w->window_number, widget_index)); - } - - w->OnClick(pt, widget_index, click_count); -} - -/** - * Dispatch right mouse-button click in window. - * @param w Window to dispatch event in - * @param x X coordinate of the click - * @param y Y coordinate of the click - */ -static void DispatchRightClickEvent(Window *w, int x, int y) -{ - NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y); - if (wid == NULL) return; - - /* No widget to handle, or the window is not interested in it. */ - if (wid->index >= 0) { - Point pt = { x, y }; - if (w->OnRightClick(pt, wid->index)) return; - } - - if (_settings_client.gui.hover_delay == 0 && wid->tool_tip != 0) GuiShowTooltips(w, wid->tool_tip, 0, NULL, TCC_RIGHT_CLICK); -} - -/** - * Dispatch hover of the mouse over a window. - * @param w Window to dispatch event in. - * @param x X coordinate of the click. - * @param y Y coordinate of the click. - */ -static void DispatchHoverEvent(Window *w, int x, int y) -{ - NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y); - - /* No widget to handle */ - if (wid == NULL) return; - - /* Show the tooltip if there is any */ - if (wid->tool_tip != 0) { - GuiShowTooltips(w, wid->tool_tip); - return; - } - - /* Widget has no index, so the window is not interested in it. */ - if (wid->index < 0) return; - - Point pt = { x, y }; - w->OnHover(pt, wid->index); -} - -/** - * Dispatch the mousewheel-action to the window. - * The window will scroll any compatible scrollbars if the mouse is pointed over the bar or its contents - * @param w Window - * @param nwid the widget where the scrollwheel was used - * @param wheel scroll up or down - */ -static void DispatchMouseWheelEvent(Window *w, NWidgetCore *nwid, int wheel) -{ - if (nwid == NULL) return; - - /* Using wheel on caption/shade-box shades or unshades the window. */ - if (nwid->type == WWT_CAPTION || nwid->type == WWT_SHADEBOX) { - w->SetShaded(wheel < 0); - return; - } - - /* Wheeling a vertical scrollbar. */ - if (nwid->type == NWID_VSCROLLBAR) { - NWidgetScrollbar *sb = static_cast(nwid); - if (sb->GetCount() > sb->GetCapacity()) { - sb->UpdatePosition(wheel); - w->SetDirty(); - } - return; - } - - /* Scroll the widget attached to the scrollbar. */ - Scrollbar *sb = (nwid->scrollbar_index >= 0 ? w->GetScrollbar(nwid->scrollbar_index) : NULL); - if (sb != NULL && sb->GetCount() > sb->GetCapacity()) { - sb->UpdatePosition(wheel); - w->SetDirty(); - } -} - -/** - * Returns whether a window may be shown or not. - * @param w The window to consider. - * @return True iff it may be shown, otherwise false. - */ -static bool MayBeShown(const Window *w) -{ - /* If we're not modal, everything is okay. */ - if (!HasModalProgress()) return true; - - switch (w->window_class) { - case WC_MAIN_WINDOW: ///< The background, i.e. the game. - case WC_MODAL_PROGRESS: ///< The actual progress window. - case WC_CONFIRM_POPUP_QUERY: ///< The abort window. - return true; - - default: - return false; - } -} - -/** - * Generate repaint events for the visible part of window w within the rectangle. - * - * The function goes recursively upwards in the window stack, and splits the rectangle - * into multiple pieces at the window edges, so obscured parts are not redrawn. - * - * @param w Window that needs to be repainted - * @param left Left edge of the rectangle that should be repainted - * @param top Top edge of the rectangle that should be repainted - * @param right Right edge of the rectangle that should be repainted - * @param bottom Bottom edge of the rectangle that should be repainted - */ -static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom) -{ - const Window *v; - FOR_ALL_WINDOWS_FROM_BACK_FROM(v, w->z_front) { - if (MayBeShown(v) && - right > v->left && - bottom > v->top && - left < v->left + v->width && - top < v->top + v->height) { - /* v and rectangle intersect with each other */ - int x; - - if (left < (x = v->left)) { - DrawOverlappedWindow(w, left, top, x, bottom); - DrawOverlappedWindow(w, x, top, right, bottom); - return; - } - - if (right > (x = v->left + v->width)) { - DrawOverlappedWindow(w, left, top, x, bottom); - DrawOverlappedWindow(w, x, top, right, bottom); - return; - } - - if (top < (x = v->top)) { - DrawOverlappedWindow(w, left, top, right, x); - DrawOverlappedWindow(w, left, x, right, bottom); - return; - } - - if (bottom > (x = v->top + v->height)) { - DrawOverlappedWindow(w, left, top, right, x); - DrawOverlappedWindow(w, left, x, right, bottom); - return; - } - - return; - } - } - - /* Setup blitter, and dispatch a repaint event to window *wz */ - DrawPixelInfo *dp = _cur_dpi; - dp->width = right - left; - dp->height = bottom - top; - dp->left = left - w->left; - dp->top = top - w->top; - dp->pitch = _screen.pitch; - dp->dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(_screen.dst_ptr, left, top); - dp->zoom = ZOOM_LVL_NORMAL; - w->OnPaint(); -} - -/** - * From a rectangle that needs redrawing, find the windows that intersect with the rectangle. - * These windows should be re-painted. - * @param left Left edge of the rectangle that should be repainted - * @param top Top edge of the rectangle that should be repainted - * @param right Right edge of the rectangle that should be repainted - * @param bottom Bottom edge of the rectangle that should be repainted - */ -void DrawOverlappedWindowForAll(int left, int top, int right, int bottom) -{ - Window *w; - DrawPixelInfo bk; - _cur_dpi = &bk; - - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (MayBeShown(w) && - right > w->left && - bottom > w->top && - left < w->left + w->width && - top < w->top + w->height) { - /* Window w intersects with the rectangle => needs repaint */ - DrawOverlappedWindow(w, left, top, right, bottom); - } - } -} - -/** - * Mark entire window as dirty (in need of re-paint) - * @ingroup dirty - */ -void Window::SetDirty() const -{ - SetDirtyBlocks(this->left, this->top, this->left + this->width, this->top + this->height); -} - -/** - * Re-initialize a window, and optionally change its size. - * @param rx Horizontal resize of the window. - * @param ry Vertical resize of the window. - * @note For just resizing the window, use #ResizeWindow instead. - */ -void Window::ReInit(int rx, int ry) -{ - this->SetDirty(); // Mark whole current window as dirty. - - /* Save current size. */ - int window_width = this->width; - int window_height = this->height; - - this->OnInit(); - /* Re-initialize the window from the ground up. No need to change the nested_array, as all widgets stay where they are. */ - this->nested_root->SetupSmallestSize(this, false); - this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL); - this->width = this->nested_root->smallest_x; - this->height = this->nested_root->smallest_y; - this->resize.step_width = this->nested_root->resize_x; - this->resize.step_height = this->nested_root->resize_y; - - /* Resize as close to the original size + requested resize as possible. */ - window_width = max(window_width + rx, this->width); - window_height = max(window_height + ry, this->height); - int dx = (this->resize.step_width == 0) ? 0 : window_width - this->width; - int dy = (this->resize.step_height == 0) ? 0 : window_height - this->height; - /* dx and dy has to go by step.. calculate it. - * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */ - if (this->resize.step_width > 1) dx -= dx % (int)this->resize.step_width; - if (this->resize.step_height > 1) dy -= dy % (int)this->resize.step_height; - - ResizeWindow(this, dx, dy); - /* ResizeWindow() does this->SetDirty() already, no need to do it again here. */ -} - -/** - * Set the shaded state of the window to \a make_shaded. - * @param make_shaded If \c true, shade the window (roll up until just the title bar is visible), else unshade/unroll the window to its original size. - * @note The method uses #Window::ReInit(), thus after the call, the whole window should be considered changed. - */ -void Window::SetShaded(bool make_shaded) -{ - if (this->shade_select == NULL) return; - - int desired = make_shaded ? SZSP_HORIZONTAL : 0; - if (this->shade_select->shown_plane != desired) { - if (make_shaded) { - if (this->nested_focus != NULL) this->UnfocusFocusedWidget(); - this->unshaded_size.width = this->width; - this->unshaded_size.height = this->height; - this->shade_select->SetDisplayedPlane(desired); - this->ReInit(0, -this->height); - } else { - this->shade_select->SetDisplayedPlane(desired); - int dx = ((int)this->unshaded_size.width > this->width) ? (int)this->unshaded_size.width - this->width : 0; - int dy = ((int)this->unshaded_size.height > this->height) ? (int)this->unshaded_size.height - this->height : 0; - this->ReInit(dx, dy); - } - } -} - -/** - * Find the Window whose parent pointer points to this window - * @param w parent Window to find child of - * @param wc Window class of the window to remove; #WC_INVALID if class does not matter - * @return a Window pointer that is the child of \a w, or \c NULL otherwise - */ -static Window *FindChildWindow(const Window *w, WindowClass wc) -{ - Window *v; - FOR_ALL_WINDOWS_FROM_BACK(v) { - if ((wc == WC_INVALID || wc == v->window_class) && v->parent == w) return v; - } - - return NULL; -} - -/** - * Delete all children a window might have in a head-recursive manner - * @param wc Window class of the window to remove; #WC_INVALID if class does not matter - */ -void Window::DeleteChildWindows(WindowClass wc) const -{ - Window *child = FindChildWindow(this, wc); - while (child != NULL) { - delete child; - child = FindChildWindow(this, wc); - } -} - -/** - * Remove window and all its child windows from the window stack. - */ -Window::~Window() -{ - if (_thd.window_class == this->window_class && - _thd.window_number == this->window_number) { - ResetObjectToPlace(); - } - - /* Prevent Mouseover() from resetting mouse-over coordinates on a non-existing window */ - if (_mouseover_last_w == this) _mouseover_last_w = NULL; - - /* We can't scroll the window when it's closed. */ - if (_last_scroll_window == this) _last_scroll_window = NULL; - - /* Make sure we don't try to access this window as the focused window when it doesn't exist anymore. */ - if (_focused_window == this) { - this->OnFocusLost(); - _focused_window = NULL; - } - - this->DeleteChildWindows(); - - if (this->viewport != NULL) DeleteWindowViewport(this); - - this->SetDirty(); - - free(this->nested_array); // Contents is released through deletion of #nested_root. - delete this->nested_root; - - this->window_class = WC_INVALID; -} - -/** - * Find a window by its class and window number - * @param cls Window class - * @param number Number of the window within the window class - * @return Pointer to the found window, or \c NULL if not available - */ -Window *FindWindowById(WindowClass cls, WindowNumber number) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls && w->window_number == number) return w; - } - - return NULL; -} - -/** - * Find any window by its class. Useful when searching for a window that uses - * the window number as a #WindowType, like #WC_SEND_NETWORK_MSG. - * @param cls Window class - * @return Pointer to the found window, or \c NULL if not available - */ -Window *FindWindowByClass(WindowClass cls) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls) return w; - } - - return NULL; -} - -/** - * Delete a window by its class and window number (if it is open). - * @param cls Window class - * @param number Number of the window within the window class - * @param force force deletion; if false don't delete when stickied - */ -void DeleteWindowById(WindowClass cls, WindowNumber number, bool force) -{ - Window *w = FindWindowById(cls, number); - if (force || w == NULL || - (w->flags & WF_STICKY) == 0) { - delete w; - } -} - -/** - * Delete all windows of a given class - * @param cls Window class of windows to delete - */ -void DeleteWindowByClass(WindowClass cls) -{ - Window *w; - -restart_search: - /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others - * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls) { - delete w; - goto restart_search; - } - } -} - -/** - * Delete all windows of a company. We identify windows of a company - * by looking at the caption colour. If it is equal to the company ID - * then we say the window belongs to the company and should be deleted - * @param id company identifier - */ -void DeleteCompanyWindows(CompanyID id) -{ - Window *w; - -restart_search: - /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others - * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->owner == id) { - delete w; - goto restart_search; - } - } - - /* Also delete the company specific windows that don't have a company-colour. */ - DeleteWindowById(WC_BUY_COMPANY, id); -} - -/** - * Change the owner of all the windows one company can take over from another - * company in the case of a company merger. Do not change ownership of windows - * that need to be deleted once takeover is complete - * @param old_owner original owner of the window - * @param new_owner the new owner of the window - */ -void ChangeWindowOwner(Owner old_owner, Owner new_owner) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->owner != old_owner) continue; - - switch (w->window_class) { - case WC_COMPANY_COLOUR: - case WC_FINANCES: - case WC_STATION_LIST: - case WC_TRAINS_LIST: - case WC_ROADVEH_LIST: - case WC_SHIPS_LIST: - case WC_AIRCRAFT_LIST: - case WC_BUY_COMPANY: - case WC_COMPANY: - case WC_COMPANY_INFRASTRUCTURE: - continue; - - default: - w->owner = new_owner; - break; - } - } -} - -static void BringWindowToFront(Window *w); - -/** - * Find a window and make it the relative top-window on the screen. - * The window gets unshaded if it was shaded, and a white border is drawn at its edges for a brief period of time to visualize its "activation". - * @param cls WindowClass of the window to activate - * @param number WindowNumber of the window to activate - * @return a pointer to the window thus activated - */ -Window *BringWindowToFrontById(WindowClass cls, WindowNumber number) -{ - Window *w = FindWindowById(cls, number); - - if (w != NULL) { - if (w->IsShaded()) w->SetShaded(false); // Restore original window size if it was shaded. - - w->SetWhiteBorder(); - BringWindowToFront(w); - w->SetDirty(); - } - - return w; -} - -static inline bool IsVitalWindow(const Window *w) -{ - switch (w->window_class) { - case WC_MAIN_TOOLBAR: - case WC_STATUS_BAR: - case WC_NEWS_WINDOW: - case WC_SEND_NETWORK_MSG: - return true; - - default: - return false; - } -} - -/** - * Get the z-priority for a given window. This is used in comparison with other z-priority values; - * a window with a given z-priority will appear above other windows with a lower value, and below - * those with a higher one (the ordering within z-priorities is arbitrary). - * @param w The window to get the z-priority for - * @pre w->window_class != WC_INVALID - * @return The window's z-priority - */ -static uint GetWindowZPriority(const Window *w) -{ - assert(w->window_class != WC_INVALID); - - uint z_priority = 0; - - switch (w->window_class) { - case WC_ENDSCREEN: - ++z_priority; - - case WC_HIGHSCORE: - ++z_priority; - - case WC_TOOLTIPS: - ++z_priority; - - case WC_DROPDOWN_MENU: - ++z_priority; - - case WC_MAIN_TOOLBAR: - case WC_STATUS_BAR: - ++z_priority; - - case WC_OSK: - ++z_priority; - - case WC_QUERY_STRING: - case WC_SEND_NETWORK_MSG: - ++z_priority; - - case WC_ERRMSG: - case WC_CONFIRM_POPUP_QUERY: - case WC_MODAL_PROGRESS: - case WC_NETWORK_STATUS_WINDOW: - ++z_priority; - - case WC_GENERATE_LANDSCAPE: - case WC_SAVELOAD: - case WC_GAME_OPTIONS: - case WC_CUSTOM_CURRENCY: - case WC_NETWORK_WINDOW: - case WC_GRF_PARAMETERS: - case WC_AI_LIST: - case WC_AI_SETTINGS: - case WC_TEXTFILE: - ++z_priority; - - case WC_CONSOLE: - ++z_priority; - - case WC_NEWS_WINDOW: - case WC_TABLET_BAR: - ++z_priority; - - default: - ++z_priority; - - case WC_MAIN_WINDOW: - return z_priority; - } -} - -/** - * Adds a window to the z-ordering, according to its z-priority. - * @param w Window to add - */ -static void AddWindowToZOrdering(Window *w) -{ - assert(w->z_front == NULL && w->z_back == NULL); - - if (_z_front_window == NULL) { - /* It's the only window. */ - _z_front_window = _z_back_window = w; - w->z_front = w->z_back = NULL; - } else { - /* Search down the z-ordering for its location. */ - Window *v = _z_front_window; - uint last_z_priority = UINT_MAX; - while (v != NULL && (v->window_class == WC_INVALID || GetWindowZPriority(v) > GetWindowZPriority(w))) { - if (v->window_class != WC_INVALID) { - /* Sanity check z-ordering, while we're at it. */ - assert(last_z_priority >= GetWindowZPriority(v)); - last_z_priority = GetWindowZPriority(v); - } - - v = v->z_back; - } - - if (v == NULL) { - /* It's the new back window. */ - w->z_front = _z_back_window; - w->z_back = NULL; - _z_back_window->z_back = w; - _z_back_window = w; - } else if (v == _z_front_window) { - /* It's the new front window. */ - w->z_front = NULL; - w->z_back = _z_front_window; - _z_front_window->z_front = w; - _z_front_window = w; - } else { - /* It's somewhere else in the z-ordering. */ - w->z_front = v->z_front; - w->z_back = v; - v->z_front->z_back = w; - v->z_front = w; - } - } -} - - -/** - * Removes a window from the z-ordering. - * @param w Window to remove - */ -static void RemoveWindowFromZOrdering(Window *w) -{ - if (w->z_front == NULL) { - assert(_z_front_window == w); - _z_front_window = w->z_back; - } else { - w->z_front->z_back = w->z_back; - } - - if (w->z_back == NULL) { - assert(_z_back_window == w); - _z_back_window = w->z_front; - } else { - w->z_back->z_front = w->z_front; - } - - w->z_front = w->z_back = NULL; -} - -/** - * On clicking on a window, make it the frontmost window of all windows with an equal - * or lower z-priority. The window is marked dirty for a repaint - * @param w window that is put into the relative foreground - */ -static void BringWindowToFront(Window *w) -{ - RemoveWindowFromZOrdering(w); - AddWindowToZOrdering(w); - - w->SetDirty(); -} - -/** - * Initializes the data (except the position and initial size) of a new Window. - * @param desc Window description. - * @param window_number Number being assigned to the new window - * @return Window pointer of the newly created window - * @pre If nested widgets are used (\a widget is \c NULL), #nested_root and #nested_array_size must be initialized. - * In addition, #nested_array is either \c NULL, or already initialized. - */ -void Window::InitializeData(WindowNumber window_number) -{ - /* Set up window properties; some of them are needed to set up smallest size below */ - this->window_class = this->window_desc->cls; - this->SetWhiteBorder(); - if (this->window_desc->default_pos == WDP_CENTER) this->flags |= WF_CENTERED; - this->owner = INVALID_OWNER; - this->nested_focus = NULL; - this->window_number = window_number; - - this->OnInit(); - /* Initialize nested widget tree. */ - if (this->nested_array == NULL) { - this->nested_array = CallocT(this->nested_array_size); - this->nested_root->SetupSmallestSize(this, true); - } else { - this->nested_root->SetupSmallestSize(this, false); - } - /* Initialize to smallest size. */ - this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL); - - /* Further set up window properties, - * this->left, this->top, this->width, this->height, this->resize.width, and this->resize.height are initialized later. */ - this->resize.step_width = this->nested_root->resize_x; - this->resize.step_height = this->nested_root->resize_y; - - /* Give focus to the opened window unless a text box - * of focused window has focus (so we don't interrupt typing). But if the new - * window has a text box, then take focus anyway. */ - if (!EditBoxInGlobalFocus() || this->nested_root->GetWidgetOfType(WWT_EDITBOX) != NULL) SetFocusedWindow(this); - - /* Insert the window into the correct location in the z-ordering. */ - AddWindowToZOrdering(this); -} - -/** - * Set the position and smallest size of the window. - * @param x Offset in pixels from the left of the screen of the new window. - * @param y Offset in pixels from the top of the screen of the new window. - * @param sm_width Smallest width in pixels of the window. - * @param sm_height Smallest height in pixels of the window. - */ -void Window::InitializePositionSize(int x, int y, int sm_width, int sm_height) -{ - this->left = x; - this->top = y; - this->width = sm_width; - this->height = sm_height; -} - -/** - * Resize window towards the default size. - * Prior to construction, a position for the new window (for its default size) - * has been found with LocalGetWindowPlacement(). Initially, the window is - * constructed with minimal size. Resizing the window to its default size is - * done here. - * @param def_width default width in pixels of the window - * @param def_height default height in pixels of the window - * @see Window::Window(), Window::InitializeData(), Window::InitializePositionSize() - */ -void Window::FindWindowPlacementAndResize(int def_width, int def_height) -{ - def_width = max(def_width, this->width); // Don't allow default size to be smaller than smallest size - def_height = max(def_height, this->height); - /* Try to make windows smaller when our window is too small. - * w->(width|height) is normally the same as min_(width|height), - * but this way the GUIs can be made a little more dynamic; - * one can use the same spec for multiple windows and those - * can then determine the real minimum size of the window. */ - if (this->width != def_width || this->height != def_height) { - /* Think about the overlapping toolbars when determining the minimum window size */ - int free_height = _screen.height; - const Window *wt = FindWindowById(WC_STATUS_BAR, 0); - if (wt != NULL) free_height -= wt->height; - wt = FindWindowById(WC_MAIN_TOOLBAR, 0); - if (wt != NULL) free_height -= wt->height; - - int enlarge_x = max(min(def_width - this->width, _screen.width - this->width), 0); - int enlarge_y = max(min(def_height - this->height, free_height - this->height), 0); - - /* X and Y has to go by step.. calculate it. - * The cast to int is necessary else x/y are implicitly casted to - * unsigned int, which won't work. */ - if (this->resize.step_width > 1) enlarge_x -= enlarge_x % (int)this->resize.step_width; - if (this->resize.step_height > 1) enlarge_y -= enlarge_y % (int)this->resize.step_height; - - ResizeWindow(this, enlarge_x, enlarge_y); - /* ResizeWindow() calls this->OnResize(). */ - } else { - /* Always call OnResize; that way the scrollbars and matrices get initialized. */ - this->OnResize(); - } - - int nx = this->left; - int ny = this->top; - - if (nx + this->width > _screen.width) nx -= (nx + this->width - _screen.width); - - const Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0); - ny = max(ny, (wt == NULL || this == wt || this->top == 0) ? 0 : wt->height); - nx = max(nx, 0); - - if (this->viewport != NULL) { - this->viewport->left += nx - this->left; - this->viewport->top += ny - this->top; - } - this->left = nx; - this->top = ny; - - this->SetDirty(); -} - -/** - * Decide whether a given rectangle is a good place to open a completely visible new window. - * The new window should be within screen borders, and not overlap with another already - * existing window (except for the main window in the background). - * @param left Left edge of the rectangle - * @param top Top edge of the rectangle - * @param width Width of the rectangle - * @param height Height of the rectangle - * @param pos If rectangle is good, use this parameter to return the top-left corner of the new window - * @return Boolean indication that the rectangle is a good place for the new window - */ -static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &pos) -{ - int right = width + left; - int bottom = height + top; - - const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); - if (left < 0 || (main_toolbar != NULL && top < main_toolbar->height) || right > _screen.width || bottom > _screen.height) return false; - - /* Make sure it is not obscured by any window. */ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == WC_MAIN_WINDOW) continue; - - if (right > w->left && - w->left + w->width > left && - bottom > w->top && - w->top + w->height > top) { - return false; - } - } - - pos.x = left; - pos.y = top; - return true; -} - -/** - * Decide whether a given rectangle is a good place to open a mostly visible new window. - * The new window should be mostly within screen borders, and not overlap with another already - * existing window (except for the main window in the background). - * @param left Left edge of the rectangle - * @param top Top edge of the rectangle - * @param width Width of the rectangle - * @param height Height of the rectangle - * @param pos If rectangle is good, use this parameter to return the top-left corner of the new window - * @return Boolean indication that the rectangle is a good place for the new window - */ -static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &pos) -{ - /* Left part of the rectangle may be at most 1/4 off-screen, - * right part of the rectangle may be at most 1/2 off-screen - */ - if (left < -(width >> 2) || left > _screen.width - (width >> 1)) return false; - /* Bottom part of the rectangle may be at most 1/4 off-screen */ - if (top < 22 || top > _screen.height - (height >> 2)) return false; - - /* Make sure it is not obscured by any window. */ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == WC_MAIN_WINDOW) continue; - - if (left + width > w->left && - w->left + w->width > left && - top + height > w->top && - w->top + w->height > top) { - return false; - } - } - - pos.x = left; - pos.y = top; - return true; -} - -/** - * Find a good place for opening a new window of a given width and height. - * @param width Width of the new window - * @param height Height of the new window - * @return Top-left coordinate of the new window - */ -static Point GetAutoPlacePosition(int width, int height) -{ - Point pt; - - /* First attempt, try top-left of the screen */ - const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); - if (IsGoodAutoPlace1(0, main_toolbar != NULL ? main_toolbar->height + 2 : 2, width, height, pt)) return pt; - - /* Second attempt, try around all existing windows with a distance of 2 pixels. - * The new window must be entirely on-screen, and not overlap with an existing window. - * Eight starting points are tried, two at each corner. - */ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == WC_MAIN_WINDOW) continue; - - if (IsGoodAutoPlace1(w->left + w->width + 2, w->top, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left - width - 2, w->top, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left, w->top + w->height + 2, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left, w->top - height - 2, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left + w->width + 2, w->top + w->height - height, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left - width - 2, w->top + w->height - height, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left + w->width - width, w->top + w->height + 2, width, height, pt)) return pt; - if (IsGoodAutoPlace1(w->left + w->width - width, w->top - height - 2, width, height, pt)) return pt; - } - - /* Third attempt, try around all existing windows with a distance of 2 pixels. - * The new window may be partly off-screen, and must not overlap with an existing window. - * Only four starting points are tried. - */ - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == WC_MAIN_WINDOW) continue; - - if (IsGoodAutoPlace2(w->left + w->width + 2, w->top, width, height, pt)) return pt; - if (IsGoodAutoPlace2(w->left - width - 2, w->top, width, height, pt)) return pt; - if (IsGoodAutoPlace2(w->left, w->top + w->height + 2, width, height, pt)) return pt; - if (IsGoodAutoPlace2(w->left, w->top - height - 2, width, height, pt)) return pt; - } - - /* Fourth and final attempt, put window at diagonal starting from (0, 24), try multiples - * of (+5, +5) - */ - int left = 0, top = 24; - -restart: - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->left == left && w->top == top) { - left += 5; - top += 5; - goto restart; - } - } - - pt.x = left; - pt.y = top; - return pt; -} - -/** - * Computer the position of the top-left corner of a window to be opened right - * under the toolbar. - * @param window_width the width of the window to get the position for - * @return Coordinate of the top-left corner of the new window. - */ -Point GetToolbarAlignedWindowPosition(int window_width) -{ - const Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); - assert(w != NULL); - Point pt = { _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width, w->top + w->height }; - return pt; -} - -/** - * Compute the position of the top-left corner of a new window that is opened. - * - * By default position a child window at an offset of 10/10 of its parent. - * With the exception of WC_BUILD_TOOLBAR (build railway/roads/ship docks/airports) - * and WC_SCEN_LAND_GEN (landscaping). Whose child window has an offset of 0/toolbar-height of - * its parent. So it's exactly under the parent toolbar and no buttons will be covered. - * However if it falls too extremely outside window positions, reposition - * it to an automatic place. - * - * @param *desc The pointer to the WindowDesc to be created. - * @param sm_width Smallest width of the window. - * @param sm_height Smallest height of the window. - * @param window_number The window number of the new window. - * - * @return Coordinate of the top-left corner of the new window. - */ -static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number) -{ - Point pt; - const Window *w; - - int16 default_width = max(desc->GetDefaultWidth(), sm_width); - int16 default_height = max(desc->GetDefaultHeight(), sm_height); - - if (desc->parent_cls != WC_NONE && - (w = FindWindowById(desc->parent_cls, window_number)) != NULL && - w->left < _screen.width - 20 && w->left > -60 && w->top < _screen.height - 20) { - - if (_settings_client.gui.touchscreen_mode != TSC_NONE) { - pt.x = _current_text_dir == TD_RTL ? 0 : (_screen.width - default_width); - } else { - pt.x = w->left + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? 0 : 10); - if (pt.x > _screen.width + 10 - default_width) { - pt.x = (_screen.width + 10 - default_width) - 20; - } - } - - pt.y = w->top + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? w->height : 10); - return pt; - } - - switch (desc->default_pos) { - case WDP_ALIGN_TOOLBAR: // Align to the toolbar - return GetToolbarAlignedWindowPosition(default_width); - - case WDP_AUTO: // Find a good automatic position for the window - return GetAutoPlacePosition(default_width, default_height); - - case WDP_CENTER: // Centre the window horizontally - pt.x = (_screen.width - default_width) / 2; - pt.y = (_screen.height - default_height) / 2; - break; - - case WDP_MANUAL: - pt.x = 0; - pt.y = 0; - break; - - default: - NOT_REACHED(); - } - - // try to put it to - - return pt; -} - -/* virtual */ Point Window::OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) -{ - return LocalGetWindowPlacement(this->window_desc, sm_width, sm_height, window_number); -} - -/** - * Perform the first part of the initialization of a nested widget tree. - * Construct a nested widget tree in #nested_root, and optionally fill the #nested_array array to provide quick access to the uninitialized widgets. - * This is mainly useful for setting very basic properties. - * @param fill_nested Fill the #nested_array (enabling is expensive!). - * @note Filling the nested array requires an additional traversal through the nested widget tree, and is best performed by #FinishInitNested rather than here. - */ -void Window::CreateNestedTree(bool fill_nested) -{ - int biggest_index = -1; - this->nested_root = MakeWindowNWidgetTree(this->window_desc->nwid_parts, this->window_desc->nwid_length, &biggest_index, &this->shade_select); - this->nested_array_size = (uint)(biggest_index + 1); - - if (fill_nested) { - this->nested_array = CallocT(this->nested_array_size); - this->nested_root->FillNestedArray(this->nested_array, this->nested_array_size); - } -} - -/** - * Perform the second part of the initialization of a nested widget tree. - * @param window_number Number of the new window. - */ -void Window::FinishInitNested(WindowNumber window_number) -{ - this->InitializeData(window_number); - this->ApplyDefaults(); - Point pt = this->OnInitialPosition(this->nested_root->smallest_x, this->nested_root->smallest_y, window_number); - this->InitializePositionSize(pt.x, pt.y, this->nested_root->smallest_x, this->nested_root->smallest_y); - this->FindWindowPlacementAndResize(this->window_desc->GetDefaultWidth(), this->window_desc->GetDefaultHeight()); -} - -/** - * Perform complete initialization of the #Window with nested widgets, to allow use. - * @param window_number Number of the new window. - */ -void Window::InitNested(WindowNumber window_number) -{ - this->CreateNestedTree(false); - this->FinishInitNested(window_number); -} - -/** - * Empty constructor, initialization has been moved to #InitNested() called from the constructor of the derived class. - * @param desc The description of the window. - */ -Window::Window(WindowDesc *desc) : window_desc(desc), scrolling_scrollbar(-1) -{ -} - -/** - * Do a search for a window at specific coordinates. For this we start - * at the topmost window, obviously and work our way down to the bottom - * @param x position x to query - * @param y position y to query - * @return a pointer to the found window if any, NULL otherwise - */ -Window *FindWindowFromPt(int x, int y) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if (MayBeShown(w) && IsInsideBS(x, w->left, w->width) && IsInsideBS(y, w->top, w->height)) { - return w; - } - } - - return NULL; -} - -int SETTING_BUTTON_WIDTH = 20; -int SETTING_BUTTON_HEIGHT = 10; - -/** - * Set button size of settings. If automatic sizing is also enabled, it also sets - * the sizing of buttons, scrollbars and font size (recommend restart). - * @todo Check if it can be moved to another file, so we do not need to include error, string and fontcache headers. - * @todo Fix magic numbers 16/18/20/30/32 - */ -void CheckWindowMinSizings() -{ - if (_settings_client.gui.manage_min_sizing) { - /* Fill the min sizing values for the current resolution. */ - uint swap_x = 32; // in longest border, let main toolbar to have 30 buttons. - uint swap_y = 16; // if short border, let main toolbar have 16/18/20 buttons..) - if (_cur_resolution.width < _cur_resolution.height) Swap(swap_x, swap_y); - _settings_client.gui.min_button = min(_cur_resolution.width / swap_x, _cur_resolution.height / swap_y); - _settings_client.gui.min_step = _settings_client.gui.min_button * 3 / 4; - } - - SETTING_BUTTON_HEIGHT = max(GetMinSizing(NWST_STEP) - 10, 10); - SETTING_BUTTON_WIDTH = 2 * SETTING_BUTTON_HEIGHT; - - extern uint _tooltip_width; - _tooltip_width = max(194, 10 * _settings_client.gui.min_button); - - if (!_settings_client.gui.manage_min_sizing) return; - - _freetype.large.size = _settings_client.gui.min_button; - _freetype.medium.size = max(_settings_client.gui.min_step * 2 / 3, 10U); - _freetype.mono.size = _freetype.medium.size; - _freetype.small.size = max(_freetype.medium.size * 2 / 3, 8U); - - InitFreeType(true); - CheckForMissingGlyphs(); - - if (_z_front_window == NULL) return; - - DeleteAllNonVitalWindows(); - - switch (_game_mode) { - default: break; - case GM_MENU: - DeleteWindowById(WC_SELECT_GAME, 0); - extern void ShowSelectGameWindow(); - ShowSelectGameWindow(); - break; - - case GM_NORMAL: - case GM_EDITOR: { - Station *st; - FOR_ALL_STATIONS(st) { st->UpdateVirtCoord(); } - Waypoint *wp; - FOR_ALL_WAYPOINTS(wp) { wp->UpdateVirtCoord(); } - - HideVitalWindows(); - ShowVitalWindows(); - break; - } - } - - ShowErrorMessage(STR_ERROR_RESET_WINDOWS, STR_ERROR_AUTOMATIC_SIZING, WL_WARNING); -} - -/** - * (re)initialize the windowing system - */ -void InitWindowSystem() -{ - IConsoleClose(); - - _z_back_window = NULL; - _z_front_window = NULL; - _focused_window = NULL; - _mouseover_last_w = NULL; - _last_scroll_window = NULL; - _scrolling_viewport = false; - _mouse_hovering = false; - - NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets. - NWidgetScrollbar::InvalidateDimensionCache(); - - ShowFirstError(); -} - -/** - * Close down the windowing system - */ -void UnInitWindowSystem() -{ - UnshowCriticalError(); - - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) delete w; - - for (w = _z_front_window; w != NULL; /* nothing */) { - Window *to_del = w; - w = w->z_back; - free(to_del); - } - - _z_front_window = NULL; - _z_back_window = NULL; -} - -/** - * Reset the windowing system, by means of shutting it down followed by re-initialization - */ -void ResetWindowSystem() -{ - UnInitWindowSystem(); - InitWindowSystem(); - _thd.Reset(); -} - -static void DecreaseWindowCounters() -{ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if (_scroller_click_timeout == 0) { - /* Unclick scrollbar buttons if they are pressed. */ - for (uint i = 0; i < w->nested_array_size; i++) { - NWidgetBase *nwid = w->nested_array[i]; - if (nwid != NULL && (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR)) { - NWidgetScrollbar *sb = static_cast(nwid); - if (sb->disp_flags & (ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN)) { - sb->disp_flags &= ~(ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN); - w->scrolling_scrollbar = -1; - sb->SetDirty(w); - } - } - } - } - - /* Handle editboxes */ - for (SmallMap::Pair *it = w->querystrings.Begin(); it != w->querystrings.End(); ++it) { - it->second->HandleEditBox(w, it->first); - } - - w->OnMouseLoop(); - } - - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if ((w->flags & WF_TIMEOUT) && --w->timeout_timer == 0) { - CLRBITS(w->flags, WF_TIMEOUT); - - w->OnTimeout(); - w->RaiseButtons(true); - } - } -} - -static void HandlePlacePresize() -{ - if (_special_mouse_mode != WSM_PRESIZE) return; - - Window *w = _thd.GetCallbackWnd(); - if (w == NULL) return; - - Point pt = GetTileBelowCursor(); - if (pt.x == -1) { - _thd.selend.x = -1; - return; - } - - w->OnPlacePresize(pt, TileVirtXY(pt.x, pt.y)); -} - -/** - * Handle dragging and dropping in mouse dragging mode (#WSM_DRAGDROP). - * @return State of handling the event. - */ -static EventState HandleMouseDragDrop() -{ - if (_special_mouse_mode != WSM_DRAGDROP) return ES_NOT_HANDLED; - - if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; // Dragging, but the mouse did not move. - - Window *w = _thd.GetCallbackWnd(); - if (w != NULL) { - /* Send an event in client coordinates. */ - Point pt; - pt.x = _cursor.pos.x - w->left; - pt.y = _cursor.pos.y - w->top; - if (_left_button_down) { - w->OnMouseDrag(pt, GetWidgetFromPos(w, pt.x, pt.y)); - } else { - w->OnDragDrop(pt, GetWidgetFromPos(w, pt.x, pt.y)); - } - } - - if (!_left_button_down) ResetObjectToPlace(); // Button released, finished dragging. - return ES_HANDLED; -} - -/** Report position of the mouse to the underlying window. */ -static void HandleMouseOver() -{ - Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); - - /* We changed window, put a MOUSEOVER event to the last window */ - if (_mouseover_last_w != NULL && _mouseover_last_w != w) { - /* Reset mouse-over coordinates of previous window */ - Point pt = { -1, -1 }; - _mouseover_last_w->OnMouseOver(pt, 0); - } - - /* _mouseover_last_w will get reset when the window is deleted, see DeleteWindow() */ - _mouseover_last_w = w; - - if (w != NULL) { - /* send an event in client coordinates. */ - Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top }; - const NWidgetCore *widget = w->nested_root->GetWidgetFromPos(pt.x, pt.y); - if (widget != NULL) w->OnMouseOver(pt, widget->index); - } -} - -/** The minimum number of pixels of the title bar must be visible in both the X or Y direction */ -static const int MIN_VISIBLE_TITLE_BAR = 13; - -/** Direction for moving the window. */ -enum PreventHideDirection { - PHD_UP, ///< Above v is a safe position. - PHD_DOWN, ///< Below v is a safe position. -}; - -/** - * Do not allow hiding of the rectangle with base coordinates \a nx and \a ny behind window \a v. - * If needed, move the window base coordinates to keep it visible. - * @param nx Base horizontal coordinate of the rectangle. - * @param ny Base vertical coordinate of the rectangle. - * @param rect Rectangle that must stay visible for #MIN_VISIBLE_TITLE_BAR pixels (horizontally, vertically, or both) - * @param v Window lying in front of the rectangle. - * @param px Previous horizontal base coordinate. - * @param dir If no room horizontally, move the rectangle to the indicated position. - */ -static void PreventHiding(int *nx, int *ny, const Rect &rect, const Window *v, int px, PreventHideDirection dir) -{ - if (v == NULL) return; - - int v_bottom = v->top + v->height; - int v_right = v->left + v->width; - int safe_y = (dir == PHD_UP) ? (v->top - MIN_VISIBLE_TITLE_BAR - rect.top) : (v_bottom + MIN_VISIBLE_TITLE_BAR - rect.bottom); // Compute safe vertical position. - - if (*ny + rect.top <= v->top - MIN_VISIBLE_TITLE_BAR) return; // Above v is enough space - if (*ny + rect.bottom >= v_bottom + MIN_VISIBLE_TITLE_BAR) return; // Below v is enough space - - /* Vertically, the rectangle is hidden behind v. */ - if (*nx + rect.left + MIN_VISIBLE_TITLE_BAR < v->left) { // At left of v. - if (v->left < MIN_VISIBLE_TITLE_BAR) *ny = safe_y; // But enough room, force it to a safe position. - return; - } - if (*nx + rect.right - MIN_VISIBLE_TITLE_BAR > v_right) { // At right of v. - if (v_right > _screen.width - MIN_VISIBLE_TITLE_BAR) *ny = safe_y; // Not enough room, force it to a safe position. - return; - } - - /* Horizontally also hidden, force movement to a safe area. */ - if (px + rect.left < v->left && v->left >= MIN_VISIBLE_TITLE_BAR) { // Coming from the left, and enough room there. - *nx = v->left - MIN_VISIBLE_TITLE_BAR - rect.left; - } else if (px + rect.right > v_right && v_right <= _screen.width - MIN_VISIBLE_TITLE_BAR) { // Coming from the right, and enough room there. - *nx = v_right + MIN_VISIBLE_TITLE_BAR - rect.right; - } else { - *ny = safe_y; - } -} - -/** - * Make sure at least a part of the caption bar is still visible by moving - * the window if necessary. - * @param w The window to check. - * @param nx The proposed new x-location of the window. - * @param ny The proposed new y-location of the window. - */ -static void EnsureVisibleCaption(Window *w, int nx, int ny) -{ - /* Search for the title bar rectangle. */ - Rect caption_rect; - const NWidgetBase *caption = w->nested_root->GetWidgetOfType(WWT_CAPTION); - if (caption != NULL) { - caption_rect.left = caption->pos_x; - caption_rect.right = caption->pos_x + caption->current_x; - caption_rect.top = caption->pos_y; - caption_rect.bottom = caption->pos_y + caption->current_y; - - /* Make sure the window doesn't leave the screen */ - nx = Clamp(nx, MIN_VISIBLE_TITLE_BAR - caption_rect.right, _screen.width - MIN_VISIBLE_TITLE_BAR - caption_rect.left); - ny = Clamp(ny, 0, _screen.height - MIN_VISIBLE_TITLE_BAR); - - /* Make sure the title bar isn't hidden behind the main tool bar or the status bar. */ - PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_MAIN_TOOLBAR, 0), w->left, PHD_DOWN); - PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_STATUS_BAR, 0), w->left, PHD_UP); - } - - if (w->viewport != NULL) { - w->viewport->left += nx - w->left; - w->viewport->top += ny - w->top; - } - - w->left = nx; - w->top = ny; -} - -/** - * Resize the window. - * Update all the widgets of a window based on their resize flags - * Both the areas of the old window and the new sized window are set dirty - * ensuring proper redrawal. - * @param w Window to resize - * @param delta_x Delta x-size of changed window (positive if larger, etc.) - * @param delta_y Delta y-size of changed window - * @param clamp_to_screen Whether to make sure the whole window stays visible - */ -void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen) -{ - if (delta_x != 0 || delta_y != 0) { - if (clamp_to_screen) { - /* Determine the new right/bottom position. If that is outside of the bounds of - * the resolution clamp it in such a manner that it stays within the bounds. */ - int new_right = w->left + w->width + delta_x; - int new_bottom = w->top + w->height + delta_y; - if (new_right >= (int)_cur_resolution.width) delta_x -= Ceil(new_right - _cur_resolution.width, max(1U, w->nested_root->resize_x)); - if (new_bottom >= (int)_cur_resolution.height) delta_y -= Ceil(new_bottom - _cur_resolution.height, max(1U, w->nested_root->resize_y)); - } - - w->SetDirty(); - - uint new_xinc = max(0, (w->nested_root->resize_x == 0) ? 0 : (int)(w->nested_root->current_x - w->nested_root->smallest_x) + delta_x); - uint new_yinc = max(0, (w->nested_root->resize_y == 0) ? 0 : (int)(w->nested_root->current_y - w->nested_root->smallest_y) + delta_y); - assert(w->nested_root->resize_x == 0 || new_xinc % w->nested_root->resize_x == 0); - assert(w->nested_root->resize_y == 0 || new_yinc % w->nested_root->resize_y == 0); - - w->nested_root->AssignSizePosition(ST_RESIZE, 0, 0, w->nested_root->smallest_x + new_xinc, w->nested_root->smallest_y + new_yinc, _current_text_dir == TD_RTL); - w->width = w->nested_root->current_x; - w->height = w->nested_root->current_y; - } - - EnsureVisibleCaption(w, w->left, w->top); - - /* Always call OnResize to make sure everything is initialised correctly if it needs to be. */ - w->OnResize(); - w->SetDirty(); -} - -/** - * Return the top of the main view available for general use. - * @return Uppermost vertical coordinate available. - * @note Above the upper y coordinate is often the main toolbar. - */ -int GetMainViewTop() -{ - Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); - return (w == NULL) ? 0 : w->top + w->height; -} - -/** - * Return the bottom of the main view available for general use. - * @return The vertical coordinate of the first unusable row, so 'top + height <= bottom' gives the correct result. - * @note At and below the bottom y coordinate is often the status bar. - */ -int GetMainViewBottom() -{ - Window *w = FindWindowById(WC_STATUS_BAR, 0); - return (w == NULL) ? _screen.height : w->top; -} - -static bool _dragging_window; ///< A window is being dragged or resized. - -/** - * Handle dragging/resizing of a window. - * @return State of handling the event. - */ -static EventState HandleWindowDragging() -{ - /* Get out immediately if no window is being dragged at all. */ - if (!_dragging_window) return ES_NOT_HANDLED; - - /* If button still down, but cursor hasn't moved, there is nothing to do. */ - if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; - - /* Otherwise find the window... */ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->flags & WF_DRAGGING) { - /* Stop the dragging if the left mouse button was released */ - if (!_left_button_down) { - w->flags &= ~WF_DRAGGING; - break; - } - - w->SetDirty(); - - int x = _cursor.pos.x + _drag_delta.x; - int y = _cursor.pos.y + _drag_delta.y; - int nx = x; - int ny = y; - - if (_settings_client.gui.window_snap_radius != 0) { - const Window *v; - - int hsnap = _settings_client.gui.window_snap_radius; - int vsnap = _settings_client.gui.window_snap_radius; - int delta; - - FOR_ALL_WINDOWS_FROM_BACK(v) { - if (v == w) continue; // Don't snap at yourself - - if (y + w->height > v->top && y < v->top + v->height) { - /* Your left border <-> other right border */ - delta = abs(v->left + v->width - x); - if (delta <= hsnap) { - nx = v->left + v->width; - hsnap = delta; - } - - /* Your right border <-> other left border */ - delta = abs(v->left - x - w->width); - if (delta <= hsnap) { - nx = v->left - w->width; - hsnap = delta; - } - } - - if (w->top + w->height >= v->top && w->top <= v->top + v->height) { - /* Your left border <-> other left border */ - delta = abs(v->left - x); - if (delta <= hsnap) { - nx = v->left; - hsnap = delta; - } - - /* Your right border <-> other right border */ - delta = abs(v->left + v->width - x - w->width); - if (delta <= hsnap) { - nx = v->left + v->width - w->width; - hsnap = delta; - } - } - - if (x + w->width > v->left && x < v->left + v->width) { - /* Your top border <-> other bottom border */ - delta = abs(v->top + v->height - y); - if (delta <= vsnap) { - ny = v->top + v->height; - vsnap = delta; - } - - /* Your bottom border <-> other top border */ - delta = abs(v->top - y - w->height); - if (delta <= vsnap) { - ny = v->top - w->height; - vsnap = delta; - } - } - - if (w->left + w->width >= v->left && w->left <= v->left + v->width) { - /* Your top border <-> other top border */ - delta = abs(v->top - y); - if (delta <= vsnap) { - ny = v->top; - vsnap = delta; - } - - /* Your bottom border <-> other bottom border */ - delta = abs(v->top + v->height - y - w->height); - if (delta <= vsnap) { - ny = v->top + v->height - w->height; - vsnap = delta; - } - } - } - } - - EnsureVisibleCaption(w, nx, ny); - - w->SetDirty(); - return ES_HANDLED; - } else if (w->flags & WF_SIZING) { - /* Stop the sizing if the left mouse button was released */ - if (!_left_button_down) { - w->flags &= ~WF_SIZING; - w->SetDirty(); - break; - } - - /* Compute difference in pixels between cursor position and reference point in the window. - * If resizing the left edge of the window, moving to the left makes the window bigger not smaller. - */ - int x, y = _cursor.pos.y - _drag_delta.y; - if (w->flags & WF_SIZING_LEFT) { - x = _drag_delta.x - _cursor.pos.x; - } else { - x = _cursor.pos.x - _drag_delta.x; - } - - /* resize.step_width and/or resize.step_height may be 0, which means no resize is possible. */ - if (w->resize.step_width == 0) x = 0; - if (w->resize.step_height == 0) y = 0; - - /* Check the resize button won't go past the bottom of the screen */ - if (w->top + w->height + y > _screen.height) { - y = _screen.height - w->height - w->top; - } - - /* X and Y has to go by step.. calculate it. - * The cast to int is necessary else x/y are implicitly casted to - * unsigned int, which won't work. */ - if (w->resize.step_width > 1) x -= x % (int)w->resize.step_width; - if (w->resize.step_height > 1) y -= y % (int)w->resize.step_height; - - /* Check that we don't go below the minimum set size */ - if ((int)w->width + x < (int)w->nested_root->smallest_x) { - x = w->nested_root->smallest_x - w->width; - } - if ((int)w->height + y < (int)w->nested_root->smallest_y) { - y = w->nested_root->smallest_y - w->height; - } - - /* Window already on size */ - if (x == 0 && y == 0) return ES_HANDLED; - - /* Now find the new cursor pos.. this is NOT _cursor, because we move in steps. */ - _drag_delta.y += y; - if ((w->flags & WF_SIZING_LEFT) && x != 0) { - _drag_delta.x -= x; // x > 0 -> window gets longer -> left-edge moves to left -> subtract x to get new position. - w->SetDirty(); - w->left -= x; // If dragging left edge, move left window edge in opposite direction by the same amount. - /* ResizeWindow() below ensures marking new position as dirty. */ - } else { - _drag_delta.x += x; - } - - /* ResizeWindow sets both pre- and after-size to dirty for redrawal */ - ResizeWindow(w, x, y); - return ES_HANDLED; - } - } - - _dragging_window = false; - return ES_HANDLED; -} - -/** - * Start window dragging - * @param w Window to start dragging - */ -static void StartWindowDrag(Window *w) -{ - w->flags |= WF_DRAGGING; - w->flags &= ~WF_CENTERED; - _dragging_window = true; - - _drag_delta.x = w->left - _cursor.pos.x; - _drag_delta.y = w->top - _cursor.pos.y; - - BringWindowToFront(w); - DeleteWindowById(WC_DROPDOWN_MENU, 0); -} - -/** - * Start resizing a window. - * @param w Window to start resizing. - * @param to_left Whether to drag towards the left or not - */ -static void StartWindowSizing(Window *w, bool to_left) -{ - w->flags |= to_left ? WF_SIZING_LEFT : WF_SIZING_RIGHT; - w->flags &= ~WF_CENTERED; - _dragging_window = true; - - _drag_delta.x = _cursor.pos.x; - _drag_delta.y = _cursor.pos.y; - - BringWindowToFront(w); - DeleteWindowById(WC_DROPDOWN_MENU, 0); -} - -/** - * handle scrollbar scrolling with the mouse. - * @return State of handling the event. - */ -static EventState HandleScrollbarScrolling() -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->scrolling_scrollbar >= 0) { - /* Abort if no button is clicked any more. */ - if (!_left_button_down) { - w->scrolling_scrollbar = -1; - w->SetDirty(); - return ES_HANDLED; - } - - int i; - NWidgetScrollbar *sb = w->GetWidget(w->scrolling_scrollbar); - bool rtl = false; - - if (sb->type == NWID_HSCROLLBAR) { - i = _cursor.pos.x - _cursorpos_drag_start.x; - rtl = _current_text_dir == TD_RTL; - } else { - i = _cursor.pos.y - _cursorpos_drag_start.y; - } - - if (sb->disp_flags & ND_SCROLLBAR_BTN) { - if (_scroller_click_timeout == 1) { - _scroller_click_timeout = 3; - sb->UpdatePosition(rtl == HasBit(sb->disp_flags, NDB_SCROLLBAR_UP) ? 1 : -1); - w->SetDirty(); - } - return ES_HANDLED; - } - - /* Find the item we want to move to and make sure it's inside bounds. */ - int pos = min(max(0, i + _scrollbar_start_pos) * sb->GetCount() / _scrollbar_size, max(0, sb->GetCount() - sb->GetCapacity())); - if (rtl) pos = max(0, sb->GetCount() - sb->GetCapacity() - pos); - if (pos != sb->GetPosition()) { - sb->SetPosition(pos); - w->SetDirty(); - } - return ES_HANDLED; - } - } - - return ES_NOT_HANDLED; -} - -/** - * Handle viewport scrolling with the mouse. - * @return State of handling the event. - */ -static EventState HandleViewportScroll() -{ - bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); - - if (!_scrolling_viewport) return ES_NOT_HANDLED; - - /* When we don't have a last scroll window we are starting to scroll. - * When the last scroll window and this are not the same we went - * outside of the window and should not left-mouse scroll anymore. */ - if (_last_scroll_window == NULL) _last_scroll_window = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); - - - if (_last_scroll_window == NULL || !(_right_button_down || scrollwheel_scrolling || - (_left_button_down && (_move_pressed || _settings_client.gui.left_mouse_btn_scrolling)))) { - _cursor.fix_at = false; - _scrolling_viewport = false; - _last_scroll_window = NULL; - return ES_NOT_HANDLED; - } - - if (_last_scroll_window == FindWindowById(WC_MAIN_WINDOW, 0) && _last_scroll_window->viewport->follow_vehicle != INVALID_VEHICLE) { - /* If the main window is following a vehicle, then first let go of it! */ - const Vehicle *veh = Vehicle::Get(_last_scroll_window->viewport->follow_vehicle); - ScrollMainWindowTo(veh->x_pos, veh->y_pos, veh->z_pos, true); // This also resets follow_vehicle - return ES_NOT_HANDLED; - } - - Point delta; - if (_settings_client.gui.reverse_scroll || (_settings_client.gui.left_mouse_btn_scrolling && _left_button_down)) { - delta.x = -_cursor.delta.x; - delta.y = -_cursor.delta.y; - } else { - delta.x = _cursor.delta.x; - delta.y = _cursor.delta.y; - } - - if (scrollwheel_scrolling) { - /* We are using scrollwheels for scrolling */ - delta.x = _cursor.h_wheel; - delta.y = _cursor.v_wheel; - _cursor.v_wheel = 0; - _cursor.h_wheel = 0; - } - - /* Create a scroll-event and send it to the window */ - if (delta.x != 0 || delta.y != 0) _last_scroll_window->OnScroll(delta); - - _cursor.delta.x = 0; - _cursor.delta.y = 0; - return ES_HANDLED; -} - -/** - * Check if a window can be made relative top-most window, and if so do - * it. If a window does not obscure any other windows, it will not - * be brought to the foreground. Also if the only obscuring windows - * are so-called system-windows, the window will not be moved. - * The function will return false when a child window of this window is a - * modal-popup; function returns a false and child window gets a white border - * @param w Window to bring relatively on-top - * @return false if the window has an active modal child, true otherwise - */ -static bool MaybeBringWindowToFront(Window *w) -{ - bool bring_to_front = false; - - if (w->window_class == WC_MAIN_WINDOW || - IsVitalWindow(w) || - w->window_class == WC_TOOLTIPS || - w->window_class == WC_DROPDOWN_MENU) { - return true; - } - - /* Use unshaded window size rather than current size for shaded windows. */ - int w_width = w->width; - int w_height = w->height; - if (w->IsShaded()) { - w_width = w->unshaded_size.width; - w_height = w->unshaded_size.height; - } - - Window *u; - FOR_ALL_WINDOWS_FROM_BACK_FROM(u, w->z_front) { - /* A modal child will prevent the activation of the parent window */ - if (u->parent == w && (u->window_desc->flags & WDF_MODAL)) { - u->SetWhiteBorder(); - u->SetDirty(); - return false; - } - - if (u->window_class == WC_MAIN_WINDOW || - IsVitalWindow(u) || - u->window_class == WC_TOOLTIPS || - u->window_class == WC_DROPDOWN_MENU) { - continue; - } - - /* Window sizes don't interfere, leave z-order alone */ - if (w->left + w_width <= u->left || - u->left + u->width <= w->left || - w->top + w_height <= u->top || - u->top + u->height <= w->top) { - continue; - } - - bring_to_front = true; - } - - if (bring_to_front) BringWindowToFront(w); - return true; -} - -/** - * Process keypress for editbox widget. - * @param wid Editbox widget. - * @param key the Unicode value of the key. - * @param keycode the untranslated key code including shift state. - * @return #ES_HANDLED if the key press has been handled and no other - * window should receive the event. - */ -EventState Window::HandleEditBoxKey(int wid, WChar key, uint16 keycode) -{ - QueryString *query = this->GetQueryString(wid); - if (query == NULL) return ES_NOT_HANDLED; - - int action = QueryString::ACTION_NOTHING; - - switch (query->text.HandleKeyPress(key, keycode)) { - case HKPR_EDITING: - this->SetWidgetDirty(wid); - this->OnEditboxChanged(wid); - break; - - case HKPR_CURSOR: - this->SetWidgetDirty(wid); - /* For the OSK also invalidate the parent window */ - if (this->window_class == WC_OSK) this->InvalidateData(); - break; - - case HKPR_CONFIRM: - if (this->window_class == WC_OSK) { - this->OnClick(Point(), WID_OSK_OK, 1); - } else if (query->ok_button >= 0) { - this->OnClick(Point(), query->ok_button, 1); - } else { - action = query->ok_button; - } - break; - - case HKPR_CANCEL: - if (this->window_class == WC_OSK) { - this->OnClick(Point(), WID_OSK_CANCEL, 1); - } else if (query->cancel_button >= 0) { - this->OnClick(Point(), query->cancel_button, 1); - } else { - action = query->cancel_button; - } - break; - - case HKPR_NOT_HANDLED: - return ES_NOT_HANDLED; - - default: break; - } - - switch (action) { - case QueryString::ACTION_DESELECT: - this->UnfocusFocusedWidget(); - break; - - case QueryString::ACTION_CLEAR: - if (query->text.bytes <= 1) { - /* If already empty, unfocus instead */ - this->UnfocusFocusedWidget(); - } else { - query->text.DeleteAll(); - this->SetWidgetDirty(wid); - this->OnEditboxChanged(wid); - } - break; - - default: - break; - } - - return ES_HANDLED; -} - -/** - * Handle keyboard input. - * @param keycode Virtual keycode of the key. - * @param key Unicode character of the key. - */ -void HandleKeypress(uint keycode, WChar key) -{ - /* World generation is multithreaded and messes with companies. - * But there is no company related window open anyway, so _current_company is not used. */ - assert(HasModalProgress() || IsLocalCompany()); - - /* - * The Unicode standard defines an area called the private use area. Code points in this - * area are reserved for private use and thus not portable between systems. For instance, - * Apple defines code points for the arrow keys in this area, but these are only printable - * on a system running OS X. We don't want these keys to show up in text fields and such, - * and thus we have to clear the unicode character when we encounter such a key. - */ - if (key >= 0xE000 && key <= 0xF8FF) key = 0; - - /* - * If both key and keycode is zero, we don't bother to process the event. - */ - if (key == 0 && keycode == 0) return; - - /* Check if the focused window has a focused editbox */ - if (EditBoxInGlobalFocus()) { - /* All input will in this case go to the focused editbox */ - if (_focused_window->window_class == WC_CONSOLE) { - if (_focused_window->OnKeyPress(key, keycode) == ES_HANDLED) return; - } else { - if (_focused_window->HandleEditBoxKey(_focused_window->nested_focus->index, key, keycode) == ES_HANDLED) return; - } - } - - /* Call the event, start with the uppermost window, but ignore the toolbar. */ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if (w->window_class == WC_MAIN_TOOLBAR) continue; - if (w->window_desc->hotkeys != NULL) { - int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); - if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return; - } - if (w->OnKeyPress(key, keycode) == ES_HANDLED) return; - } - - w = FindWindowById(WC_MAIN_TOOLBAR, 0); - /* When there is no toolbar w is null, check for that */ - if (w != NULL) { - if (w->window_desc->hotkeys != NULL) { - int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); - if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return; - } - if (w->OnKeyPress(key, keycode) == ES_HANDLED) return; - } - - HandleGlobalHotkeys(key, keycode); -} - -/** - * State of CONTROL key has changed - */ -void HandleCtrlChanged() -{ - /* Call the event, start with the uppermost window. */ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if (w->OnCTRLStateChange() == ES_HANDLED) return; - } -} - -/** - * Insert a text string at the cursor position into the edit box widget. - * @param wid Edit box widget. - * @param str Text string to insert. - */ -/* virtual */ void Window::InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) -{ - QueryString *query = this->GetQueryString(wid); - if (query == NULL) return; - - if (query->text.InsertString(str, marked, caret, insert_location, replacement_end) || marked) { - this->SetWidgetDirty(wid); - this->OnEditboxChanged(wid); - } -} - -/** - * Handle text input. - * @param str Text string to input. - * @param marked Is the input a marked composition string from an IME? - * @param caret Move the caret to this point in the insertion string. - */ -void HandleTextInput(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) -{ - if (!EditBoxInGlobalFocus()) return; - - _focused_window->InsertTextString(_focused_window->window_class == WC_CONSOLE ? 0 : _focused_window->nested_focus->index, str, marked, caret, insert_location, replacement_end); -} - -/** - * Local counter that is incremented each time an mouse input event is detected. - * The counter is used to stop auto-scrolling. - * @see HandleAutoscroll() - * @see HandleMouseEvents() - */ -static int _input_events_this_tick = 0; - -/** - * If needed and switched on, perform auto scrolling (automatically - * moving window contents when mouse is near edge of the window). - */ -static void HandleAutoscroll() -{ - if (_game_mode == GM_MENU || HasModalProgress()) return; - if (_settings_client.gui.auto_scrolling == VA_DISABLED) return; - if (_settings_client.gui.auto_scrolling == VA_MAIN_VIEWPORT_FULLSCREEN && !_fullscreen) return; - - int x = _cursor.pos.x; - int y = _cursor.pos.y; - Window *w = FindWindowFromPt(x, y); - if (w == NULL || w->flags & WF_DISABLE_VP_SCROLL) return; - if (_settings_client.gui.auto_scrolling != VA_EVERY_VIEWPORT && w->window_class != WC_MAIN_WINDOW) return; - - ViewPort *vp = IsPtInWindowViewport(w, x, y); - if (vp == NULL) return; - - x -= vp->left; - y -= vp->top; - - /* here allows scrolling in both x and y axis */ -#define scrollspeed 3 - if (x - 15 < 0) { - w->viewport->dest_scrollpos_x += ScaleByZoom((x - 15) * scrollspeed, vp->zoom); - } else if (15 - (vp->width - x) > 0) { - w->viewport->dest_scrollpos_x += ScaleByZoom((15 - (vp->width - x)) * scrollspeed, vp->zoom); - } - if (y - 15 < 0) { - w->viewport->dest_scrollpos_y += ScaleByZoom((y - 15) * scrollspeed, vp->zoom); - } else if (15 - (vp->height - y) > 0) { - w->viewport->dest_scrollpos_y += ScaleByZoom((15 - (vp->height - y)) * scrollspeed, vp->zoom); - } -#undef scrollspeed -} - -enum MouseClick { - MC_NONE = 0, - MC_LEFT, - MC_RIGHT, - MC_DOUBLE_LEFT, - MC_HOVER, - - MAX_OFFSET_DOUBLE_CLICK = 5, ///< How much the mouse is allowed to move to call it a double click - TIME_BETWEEN_DOUBLE_CLICK = 500, ///< Time between 2 left clicks before it becoming a double click, in ms - MAX_OFFSET_HOVER = 5, ///< Maximum mouse movement before stopping a hover event. -}; -extern EventState VpHandlePlaceSizingDrag(); - -static void ScrollMainViewport(int x, int y) -{ - if (_game_mode != GM_MENU) { - Window *w = FindWindowById(WC_MAIN_WINDOW, 0); - assert(w); - - w->viewport->dest_scrollpos_x += ScaleByZoom(x, w->viewport->zoom); - w->viewport->dest_scrollpos_y += ScaleByZoom(y, w->viewport->zoom); - } -} - -/** - * Describes all the different arrow key combinations the game allows - * when it is in scrolling mode. - * The real arrow keys are bitwise numbered as - * 1 = left - * 2 = up - * 4 = right - * 8 = down - */ -static const int8 scrollamt[16][2] = { - { 0, 0}, ///< no key specified - {-2, 0}, ///< 1 : left - { 0, -2}, ///< 2 : up - {-2, -1}, ///< 3 : left + up - { 2, 0}, ///< 4 : right - { 0, 0}, ///< 5 : left + right = nothing - { 2, -1}, ///< 6 : right + up - { 0, -2}, ///< 7 : right + left + up = up - { 0, 2}, ///< 8 : down - {-2, 1}, ///< 9 : down + left - { 0, 0}, ///< 10 : down + up = nothing - {-2, 0}, ///< 11 : left + up + down = left - { 2, 1}, ///< 12 : down + right - { 0, 2}, ///< 13 : left + right + down = down - { 2, 0}, ///< 14 : right + up + down = right - { 0, 0}, ///< 15 : left + up + right + down = nothing -}; - -static void HandleKeyScrolling() -{ - /* - * Check that any of the dirkeys is pressed and that the focused window - * doesn't have an edit-box as focused widget. - */ - if (_dirkeys && !EditBoxInGlobalFocus()) { - int factor = _shift_pressed ? 50 : 10; - ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor); - } -} - -static void MouseLoop(MouseClick click, int mousewheel) -{ - /* World generation is multithreaded and messes with companies. - * But there is no company related window open anyway, so _current_company is not used. */ - assert(HasModalProgress() || IsLocalCompany()); - - int x = _cursor.pos.x; - int y = _cursor.pos.y; - Window *w = FindWindowFromPt(x, y); - if (w == NULL) return; - ViewPort *vp = IsPtInWindowViewport(w, x, y); - - HandlePlacePresize(); - UpdateTileSelection(); - - if (VpHandlePlaceSizingDrag() == ES_HANDLED) return; - if (HandleMouseDragDrop() == ES_HANDLED) return; - if (HandleWindowDragging() == ES_HANDLED) return; - if (HandleScrollbarScrolling() == ES_HANDLED) return; - if (HandleViewportScroll() == ES_HANDLED) return; - - HandleMouseOver(); - - bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); - if (click == MC_NONE && mousewheel == 0 && !scrollwheel_scrolling) return; - - if (w == NULL) return; - - if (click != MC_NONE && click != MC_HOVER && !MaybeBringWindowToFront(w)) return; - - /* Don't allow any action in a viewport if either in menu or when having a modal progress window */ - if (vp != NULL && (_game_mode == GM_MENU || HasModalProgress())) return; - - if (mousewheel != 0) { - /* Send mousewheel event to window */ - w->OnMouseWheel(mousewheel); - - /* Dispatch a MouseWheelEvent for widgets if it is not a viewport */ - if (vp == NULL) DispatchMouseWheelEvent(w, w->nested_root->GetWidgetFromPos(x - w->left, y - w->top), mousewheel); - } - - if (vp != NULL) { - if (scrollwheel_scrolling) click = MC_RIGHT; // we are using the scrollwheel in a viewport, so we emulate right mouse button - switch (click) { - case MC_DOUBLE_LEFT: - case MC_LEFT: - DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite); - if (!HandleViewportClicked(vp, x, y) && - !(w->flags & WF_DISABLE_VP_SCROLL) && - (_settings_client.gui.left_mouse_btn_scrolling || _move_pressed)) { - _scrolling_viewport = true; - _cursor.fix_at = false; - } - break; - - case MC_RIGHT: - if (!(w->flags & WF_DISABLE_VP_SCROLL)) { - _scrolling_viewport = true; - _cursor.fix_at = true; - - /* clear 2D scrolling caches before we start a 2D scroll */ - _cursor.h_wheel = 0; - _cursor.v_wheel = 0; - } - break; - - default: - break; - } - } else { - switch (click) { - case MC_LEFT: - case MC_DOUBLE_LEFT: - DispatchLeftClickEvent(w, x - w->left, y - w->top, click == MC_DOUBLE_LEFT ? 2 : 1); - break; - - default: - if (!scrollwheel_scrolling || w == NULL || w->window_class != WC_SMALLMAP) break; - /* We try to use the scrollwheel to scroll since we didn't touch any of the buttons. - * Simulate a right button click so we can get started. */ - /* FALL THROUGH */ - - case MC_RIGHT: DispatchRightClickEvent(w, x - w->left, y - w->top); break; - - case MC_HOVER: DispatchHoverEvent(w, x - w->left, y - w->top); break; - } - } -} - -/** - * Handle a mouse event from the video driver - */ -void HandleMouseEvents() -{ - /* World generation is multithreaded and messes with companies. - * But there is no company related window open anyway, so _current_company is not used. */ - assert(HasModalProgress() || IsLocalCompany()); - - static int double_click_time = 0; - static Point double_click_pos = {0, 0}; - - /* Mouse event? */ - MouseClick click = MC_NONE; - if (_left_button_down && !_left_button_clicked) { - click = MC_LEFT; - if (double_click_time != 0 && _realtime_tick - double_click_time < TIME_BETWEEN_DOUBLE_CLICK && - double_click_pos.x != 0 && abs(_cursor.pos.x - double_click_pos.x) < MAX_OFFSET_DOUBLE_CLICK && - double_click_pos.y != 0 && abs(_cursor.pos.y - double_click_pos.y) < MAX_OFFSET_DOUBLE_CLICK) { - click = MC_DOUBLE_LEFT; - } - double_click_time = _realtime_tick; - double_click_pos = _cursor.pos; - _left_button_clicked = true; - _input_events_this_tick++; - } else if (_right_button_clicked) { - _right_button_clicked = false; - click = MC_RIGHT; - _input_events_this_tick++; - } - - int mousewheel = 0; - if (_cursor.wheel) { - mousewheel = _cursor.wheel; - _cursor.wheel = 0; - _input_events_this_tick++; - } - - static uint32 hover_time = 0; - static Point hover_pos = {0, 0}; - - if (_settings_client.gui.hover_delay > 0) { - if (!_cursor.in_window || click != MC_NONE || mousewheel != 0 || _left_button_down || _right_button_down || - hover_pos.x == 0 || abs(_cursor.pos.x - hover_pos.x) >= MAX_OFFSET_HOVER || - hover_pos.y == 0 || abs(_cursor.pos.y - hover_pos.y) >= MAX_OFFSET_HOVER) { - hover_pos = _cursor.pos; - hover_time = _realtime_tick; - _mouse_hovering = false; - } else { - if (hover_time != 0 && _realtime_tick > hover_time + _settings_client.gui.hover_delay * 1000) { - click = MC_HOVER; - _input_events_this_tick++; - _mouse_hovering = true; - } - } - } - - /* Handle sprite picker before any GUI interaction */ - if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW && _newgrf_debug_sprite_picker.click_time != _realtime_tick) { - /* Next realtime tick? Then redraw has finished */ - _newgrf_debug_sprite_picker.mode = SPM_NONE; - InvalidateWindowData(WC_SPRITE_ALIGNER, 0, 1); - } - - if (click == MC_LEFT && _newgrf_debug_sprite_picker.mode == SPM_WAIT_CLICK) { - /* Mark whole screen dirty, and wait for the next realtime tick, when drawing is finished. */ - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - _newgrf_debug_sprite_picker.clicked_pixel = blitter->MoveTo(_screen.dst_ptr, _cursor.pos.x, _cursor.pos.y); - _newgrf_debug_sprite_picker.click_time = _realtime_tick; - _newgrf_debug_sprite_picker.sprites.Clear(); - _newgrf_debug_sprite_picker.mode = SPM_REDRAW; - MarkWholeScreenDirty(); - } else { - MouseLoop(click, mousewheel); - } - - /* We have moved the mouse the required distance, - * no need to move it at any later time. */ - _cursor.delta.x = 0; - _cursor.delta.y = 0; -} - -/** - * Check the soft limit of deletable (non vital, non sticky) windows. - */ -static void CheckSoftLimit() -{ - if (_settings_client.gui.window_soft_limit == 0) return; - - for (;;) { - uint deletable_count = 0; - Window *w, *last_deletable = NULL; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if (w->window_class == WC_MAIN_WINDOW || IsVitalWindow(w) || (w->flags & WF_STICKY)) continue; - - last_deletable = w; - deletable_count++; - } - - /* We've not reached the soft limit yet. */ - if (deletable_count <= _settings_client.gui.window_soft_limit) break; - - assert(last_deletable != NULL); - delete last_deletable; - } -} - -/** - * Regular call from the global game loop - */ -void InputLoop() -{ - /* World generation is multithreaded and messes with companies. - * But there is no company related window open anyway, so _current_company is not used. */ - assert(HasModalProgress() || IsLocalCompany()); - - CheckSoftLimit(); - HandleKeyScrolling(); - - /* Do the actual free of the deleted windows. */ - for (Window *v = _z_front_window; v != NULL; /* nothing */) { - Window *w = v; - v = v->z_back; - - if (w->window_class != WC_INVALID) continue; - - RemoveWindowFromZOrdering(w); - free(w); - } - - if (_scroller_click_timeout != 0) _scroller_click_timeout--; - DecreaseWindowCounters(); - - if (_input_events_this_tick != 0) { - /* The input loop is called only once per GameLoop() - so we can clear the counter here */ - _input_events_this_tick = 0; - /* there were some inputs this tick, don't scroll ??? */ - return; - } - - /* HandleMouseEvents was already called for this tick */ - HandleMouseEvents(); - HandleAutoscroll(); -} - -/** - * Update the continuously changing contents of the windows, such as the viewports - */ -void UpdateWindows() -{ - Window *w; - - static int highlight_timer = 1; - if (--highlight_timer == 0) { - highlight_timer = 15; - _window_highlight_colour = !_window_highlight_colour; - } - - FOR_ALL_WINDOWS_FROM_FRONT(w) { - w->ProcessScheduledInvalidations(); - w->ProcessHighlightedInvalidations(); - } - - static int we4_timer = 0; - int t = we4_timer + 1; - - if (t >= 100) { - FOR_ALL_WINDOWS_FROM_FRONT(w) { - w->OnHundredthTick(); - } - t = 0; - } - we4_timer = t; - - FOR_ALL_WINDOWS_FROM_FRONT(w) { - if ((w->flags & WF_WHITE_BORDER) && --w->white_border_timer == 0) { - CLRBITS(w->flags, WF_WHITE_BORDER); - w->SetDirty(); - } - } - - DrawDirtyBlocks(); - - FOR_ALL_WINDOWS_FROM_BACK(w) { - /* Update viewport only if window is not shaded. */ - if (w->viewport != NULL && !w->IsShaded()) UpdateViewportPosition(w); - } - NetworkDrawChatMessage(); - /* Redraw mouse cursor in case it was hidden */ - DrawMouseCursor(); -} - -/** - * Mark window as dirty (in need of repainting) - * @param cls Window class - * @param number Window number in that class - */ -void SetWindowDirty(WindowClass cls, WindowNumber number) -{ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls && w->window_number == number) w->SetDirty(); - } -} - -/** - * Mark a particular widget in a particular window as dirty (in need of repainting) - * @param cls Window class - * @param number Window number in that class - * @param widget_index Index number of the widget that needs repainting - */ -void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index) -{ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls && w->window_number == number) { - w->SetWidgetDirty(widget_index); - } - } -} - -/** - * Mark all windows of a particular class as dirty (in need of repainting) - * @param cls Window class - */ -void SetWindowClassesDirty(WindowClass cls) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls) w->SetDirty(); - } -} - -/** - * Mark this window's data as invalid (in need of re-computing) - * @param data The data to invalidate with - * @param gui_scope Whether the function is called from GUI scope. - */ -void Window::InvalidateData(int data, bool gui_scope) -{ - this->SetDirty(); - if (!gui_scope) { - /* Schedule GUI-scope invalidation for next redraw. */ - *this->scheduled_invalidation_data.Append() = data; - } - this->OnInvalidateData(data, gui_scope); -} - -/** - * Process all scheduled invalidations. - */ -void Window::ProcessScheduledInvalidations() -{ - for (int *data = this->scheduled_invalidation_data.Begin(); this->window_class != WC_INVALID && data != this->scheduled_invalidation_data.End(); data++) { - this->OnInvalidateData(*data, true); - } - this->scheduled_invalidation_data.Clear(); -} - -/** - * Process all invalidation of highlighted widgets. - */ -void Window::ProcessHighlightedInvalidations() -{ - if ((this->flags & WF_HIGHLIGHTED) == 0) return; - - for (uint i = 0; i < this->nested_array_size; i++) { - if (this->IsWidgetHighlighted(i)) this->SetWidgetDirty(i); - } -} - -/** - * Mark window data of the window of a given class and specific window number as invalid (in need of re-computing) - * - * Note that by default the invalidation is not considered to be called from GUI scope. - * That means only a part of invalidation is executed immediately. The rest is scheduled for the next redraw. - * The asynchronous execution is important to prevent GUI code being executed from command scope. - * When not in GUI-scope: - * - OnInvalidateData() may not do test-runs on commands, as they might affect the execution of - * the command which triggered the invalidation. (town rating and such) - * - OnInvalidateData() may not rely on _current_company == _local_company. - * This implies that no NewGRF callbacks may be run. - * - * However, when invalidations are scheduled, then multiple calls may be scheduled before execution starts. Earlier scheduled - * invalidations may be called with invalidation-data, which is already invalid at the point of execution. - * That means some stuff requires to be executed immediately in command scope, while not everything may be executed in command - * scope. While GUI-scope calls have no restrictions on what they may do, they cannot assume the game to still be in the state - * when the invalidation was scheduled; passed IDs may have got invalid in the mean time. - * - * Finally, note that invalidations triggered from commands or the game loop result in OnInvalidateData() being called twice. - * Once in command-scope, once in GUI-scope. So make sure to not process differential-changes twice. - * - * @param cls Window class - * @param number Window number within the class - * @param data The data to invalidate with - * @param gui_scope Whether the call is done from GUI scope - */ -void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls && w->window_number == number) { - w->InvalidateData(data, gui_scope); - } - } -} - -/** - * Mark window data of all windows of a given class as invalid (in need of re-computing) - * Note that by default the invalidation is not considered to be called from GUI scope. - * See InvalidateWindowData() for details on GUI-scope vs. command-scope. - * @param cls Window class - * @param data The data to invalidate with - * @param gui_scope Whether the call is done from GUI scope - */ -void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope) -{ - Window *w; - - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class == cls) { - w->InvalidateData(data, gui_scope); - } - } -} - -/** - * Dispatch WE_TICK event over all windows - */ -void CallWindowTickEvent() -{ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { - w->OnTick(); - } -} - -/** - * Try to delete a non-vital window. - * Non-vital windows are windows other than the game selection, main toolbar, - * status bar, toolbar menu, and tooltip windows. Stickied windows are also - * considered vital. - */ -void DeleteNonVitalWindows() -{ - Window *w; - -restart_search: - /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others - * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_class != WC_MAIN_WINDOW && - w->window_class != WC_SELECT_GAME && - w->window_class != WC_MAIN_TOOLBAR && - w->window_class != WC_STATUS_BAR && - w->window_class != WC_TOOLTIPS && - (w->flags & WF_STICKY) == 0) { // do not delete windows which are 'pinned' - - delete w; - goto restart_search; - } - } -} - -/** - * It is possible that a stickied window gets to a position where the - * 'close' button is outside the gaming area. You cannot close it then; except - * with this function. It closes all windows calling the standard function, - * then, does a little hacked loop of closing all stickied windows. Note - * that standard windows (status bar, etc.) are not stickied, so these aren't affected - */ -void DeleteAllNonVitalWindows() -{ - Window *w; - - /* Delete every window except for stickied ones, then sticky ones as well */ - DeleteNonVitalWindows(); - -restart_search: - /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others - * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->flags & WF_STICKY) { - delete w; - goto restart_search; - } - } -} - -/** - * Delete all windows that are used for construction of vehicle etc. - * Once done with that invalidate the others to ensure they get refreshed too. - */ -void DeleteConstructionWindows() -{ - Window *w; - -restart_search: - /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others - * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->window_desc->flags & WDF_CONSTRUCTION) { - delete w; - goto restart_search; - } - } - - FOR_ALL_WINDOWS_FROM_BACK(w) w->SetDirty(); -} - -/** Delete all always on-top windows to get an empty screen */ -void HideVitalWindows() -{ - DeleteWindowById(WC_MAIN_TOOLBAR, 0); - DeleteWindowById(WC_STATUS_BAR, 0); -} - -/** Re-initialize all windows. */ -void ReInitAllWindows() -{ - NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets. - NWidgetScrollbar::InvalidateDimensionCache(); - - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - w->ReInit(); - } -#ifdef ENABLE_NETWORK - void NetworkReInitChatBoxSize(); - NetworkReInitChatBoxSize(); -#endif - - /* Make sure essential parts of all windows are visible */ - RelocateAllWindows(_cur_resolution.width, _cur_resolution.height); - MarkWholeScreenDirty(); -} - -/** - * (Re)position a window at the screen. - * @param w Window structure of the window, may also be \c NULL. - * @param clss The class of the window to position. - * @param setting The actual setting used for the window's position. - * @return X coordinate of left edge of the repositioned window. - */ -static int PositionWindow(Window *w, WindowClass clss, int setting) -{ - if (w == NULL || w->window_class != clss) { - w = FindWindowById(clss, 0); - } - if (w == NULL) return 0; - - int old_left = w->left; - switch (setting) { - case 1: w->left = (_screen.width - w->width) / 2; break; - case 2: w->left = _screen.width - w->width; break; - default: w->left = 0; break; - } - if (w->viewport != NULL) w->viewport->left += w->left - old_left; - SetDirtyBlocks(0, w->top, _screen.width, w->top + w->height); // invalidate the whole row - return w->left; -} - -/** - * (Re)position main toolbar window at the screen. - * @param w Window structure of the main toolbar window, may also be \c NULL. - * @return X coordinate of left edge of the repositioned toolbar window. - */ -int PositionMainToolbar(Window *w) -{ - DEBUG(misc, 5, "Repositioning Main Toolbar..."); - return PositionWindow(w, WC_MAIN_TOOLBAR, _settings_client.gui.toolbar_pos); -} - -/** - * (Re)position statusbar window at the screen. - * @param w Window structure of the statusbar window, may also be \c NULL. - * @return X coordinate of left edge of the repositioned statusbar. - */ -int PositionStatusbar(Window *w) -{ - DEBUG(misc, 5, "Repositioning statusbar..."); - return PositionWindow(w, WC_STATUS_BAR, _settings_client.gui.statusbar_pos); -} - -/** - * (Re)position news message window at the screen. - * @param w Window structure of the news message window, may also be \c NULL. - * @return X coordinate of left edge of the repositioned news message. - */ -int PositionNewsMessage(Window *w) -{ - DEBUG(misc, 5, "Repositioning news message..."); - return PositionWindow(w, WC_NEWS_WINDOW, _settings_client.gui.statusbar_pos); -} - -/** - * (Re)position network chat window at the screen. - * @param w Window structure of the network chat window, may also be \c NULL. - * @return X coordinate of left edge of the repositioned network chat window. - */ -int PositionNetworkChatWindow(Window *w) -{ - DEBUG(misc, 5, "Repositioning network chat window..."); - return PositionWindow(w, WC_SEND_NETWORK_MSG, _settings_client.gui.statusbar_pos); -} - - -/** - * Switches viewports following vehicles, which get autoreplaced - * @param from_index the old vehicle ID - * @param to_index the new vehicle ID - */ -void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index) -{ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->viewport != NULL && w->viewport->follow_vehicle == from_index) { - w->viewport->follow_vehicle = to_index; - w->SetDirty(); - } - } -} - - -/** - * Relocate all windows to fit the new size of the game application screen - * @param neww New width of the game application screen - * @param newh New height of the game application screen. - */ -void RelocateAllWindows(int neww, int newh) -{ - Window *w; - - FOR_ALL_WINDOWS_FROM_BACK(w) { - int left, top; - /* XXX - this probably needs something more sane. For example specifying - * in a 'backup'-desc that the window should always be centered. */ - switch (w->window_class) { - case WC_MAIN_WINDOW: - case WC_BOOTSTRAP: - ResizeWindow(w, neww, newh); - continue; - - case WC_MAIN_TOOLBAR: - ResizeWindow(w, min(neww, w->window_desc->default_width) - w->width, 0, false); - - top = w->top; - left = PositionMainToolbar(w); // changes toolbar orientation - break; - - case WC_NEWS_WINDOW: - top = newh - w->height; - left = PositionNewsMessage(w); - break; - - case WC_STATUS_BAR: - ResizeWindow(w, min(neww, w->window_desc->default_width) - w->width, 0, false); - - top = newh - w->height; - left = PositionStatusbar(w); - break; - - case WC_SEND_NETWORK_MSG: - ResizeWindow(w, Clamp(neww, 320, 640) - w->width, 0, false); - top = newh - w->height - FindWindowById(WC_STATUS_BAR, 0)->height; - left = PositionNetworkChatWindow(w); - break; - - case WC_CONSOLE: - IConsoleResize(w); - continue; - - default: { - if (w->flags & WF_CENTERED) { - top = (newh - w->height) >> 1; - left = (neww - w->width) >> 1; - break; - } - - left = w->left; - if (left + (w->width >> 1) >= neww) left = neww - w->width; - if (left < 0) left = 0; - - top = w->top; - if (top + (w->height >> 1) >= newh) top = newh - w->height; - break; - } - } - - EnsureVisibleCaption(w, left, top); - } -} - -/** - * Destructor of the base class PickerWindowBase - * Main utility is to stop the base Window destructor from triggering - * a free while the child will already be free, in this case by the ResetObjectToPlace(). - */ -PickerWindowBase::~PickerWindowBase() -{ - this->window_class = WC_INVALID; // stop the ancestor from freeing the already (to be) child - ResetObjectToPlace(); -} From e9621fbcc73055af87c34c841d31e485bb78f463 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 15 Mar 2014 23:52:37 +0200 Subject: [PATCH 070/187] Fixed compilation --- src/build_vehicle_gui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 1e6468f359..1816e28f3f 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -908,8 +908,8 @@ void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList * const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine); SetDParam(0, engine); - DrawString(text_left, text_right, Center(y, step_size), STR_ENGINE_NAME, text_colour); - DrawVehicleEngine(l, r, sprite_x, Center(y, step_size, sprite_y_offsets[type]), engine, palette_crash ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); + DrawString(text_left, text_right, Center(y, step_size), STR_ENGINE_NAME, engine == selected_id ? TC_WHITE : TC_BLACK); + DrawVehicleEngine(l, r, sprite_x, Center(y, step_size, sprite_y_offsets[type]), engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); if (show_count) { SetDParam(0, num_engines); DrawString(count_left, count_right, Center(y, step_size, FONT_HEIGHT_SMALL), STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); From b2bc55613742b8911acd9aa434986f5685c680e4 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 15 Mar 2014 23:53:18 +0200 Subject: [PATCH 071/187] Revert "Settings in three columns for tablets." This reverts commit 94abe055a222133ba2eab446fd53ed847ebd141e. --- src/settings_gui.cpp | 89 ++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index bd02004e7b..bf1af26cc0 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -570,6 +570,16 @@ static const NWidgetPart _nested_game_options_widgets[] = { NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_AUTOSAVE_FRAME, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_AUTOSAVE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP), SetFill(1, 0), EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_RESOLUTION, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_RESOLUTION_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_RESOLUTION_TOOLTIP), SetFill(1, 0), SetPadding(0, 0, 3, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_FULLSCREEN, STR_NULL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_FULLSCREEN_BUTTON), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP), + EndContainer(), + EndContainer(), + EndContainer(), + + NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_TOWN_NAMES_FRAME, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_TOWNNAME_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP), SetFill(1, 0), EndContainer(), @@ -581,55 +591,44 @@ static const NWidgetPart _nested_game_options_widgets[] = { EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 0), SetFill(0, 1), EndContainer(), + EndContainer(), - NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_RESOLUTION, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_RESOLUTION_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_RESOLUTION_TOOLTIP), SetFill(1, 0), SetPadding(0, 0, 3, 0), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_FULLSCREEN, STR_NULL), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_FULLSCREEN_BUTTON), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP), - EndContainer(), - EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_GRF, STR_NULL), - NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_GRF_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_GRF_TOOLTIP), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), - EndContainer(), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), - EndContainer(), - EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_GRF, STR_NULL), SetPadding(0, 10, 0, 10), + NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_GRF_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_GRF_TOOLTIP), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + EndContainer(), - NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_SFX, STR_NULL), SetPadding(0, 10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_SFX_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_SFX_TOOLTIP), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_SFX_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), - EndContainer(), - EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_SFX, STR_NULL), SetPadding(0, 10, 0, 10), + NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_SFX_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_SFX_TOOLTIP), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_SFX_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_MUSIC, STR_NULL), SetPadding(0, 10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_MUSIC_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), - EndContainer(), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), - EndContainer(), - EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_MUSIC, STR_NULL), SetPadding(0, 10, 0, 10), + NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_MUSIC_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), EndContainer(), EndContainer(), EndContainer(), From b17015932c33e39ce9b4a6b2808dc7d7d1813858 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 16 Mar 2014 00:15:36 +0200 Subject: [PATCH 072/187] Stacked game options dialog in two columns --- src/settings_gui.cpp | 72 +++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index bf1af26cc0..841060556d 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -591,44 +591,46 @@ static const NWidgetPart _nested_game_options_widgets[] = { EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 0), SetFill(0, 1), EndContainer(), - EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_GRF, STR_NULL), SetPadding(0, 10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_GRF_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_GRF_TOOLTIP), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), - EndContainer(), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), - EndContainer(), - EndContainer(), + NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_GRF, STR_NULL), SetPadding(0, 10, 0, 10), + NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_GRF_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_GRF_TOOLTIP), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_SFX, STR_NULL), SetPadding(0, 10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_SFX_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_SFX_TOOLTIP), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_SFX_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), - EndContainer(), - EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_SFX, STR_NULL), SetPadding(0, 10, 0, 10), + NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_SFX_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_SFX_TOOLTIP), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_SFX_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_MUSIC, STR_NULL), SetPadding(0, 10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_MUSIC_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), - EndContainer(), - NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_MUSIC, STR_NULL), SetPadding(0, 10, 0, 10), + NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_MUSIC_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + EndContainer(), EndContainer(), EndContainer(), EndContainer(), From 06e4a922d6a46612a3ffb179594498804a77f222 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 16 Mar 2014 21:29:46 +0200 Subject: [PATCH 073/187] Renamed buttons on tablet toolbar, and removed "Move" button - it is not needed with left_mouse_btn_scrolling --- src/lang/english.txt | 4 ++-- src/toolbar_gui.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index ad4759305a..231d386712 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2446,9 +2446,9 @@ STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Level an STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Purchase land for future use. Shift toggles building/showing cost estimate # Tablet toolbar -STR_TABLET_X :{BLACK}X +STR_TABLET_X :{BLACK}Trans STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP :{BLACK}Toggle transparency -STR_TABLET_CLOSE :{BLACK}Supr +STR_TABLET_CLOSE :{BLACK}X STR_TABLET_CLOSE_TOOLTIP :{BLACK}Close all opened windows (except pinned ones) STR_TABLET_SHIFT :{BLACK}Shift STR_TABLET_SHIFT_TOOLTIP :{BLACK}Press it for getting an estimated cost of executing an action diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 0226d61dce..91518203e1 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -2296,11 +2296,11 @@ struct TabletToolbar : Window { static const NWidgetPart _nested_tablet_simple_widgets[] = { NWidget(NWID_VERTICAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), + //NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), EndContainer(), }; From 1c2c15795c08030648541ec802eb5898d5d84774 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 16 Mar 2014 22:37:01 +0200 Subject: [PATCH 074/187] Separate option for toolbar buttons size, force to split toolbar on Android --- src/settings_type.h | 1 + src/toolbar_gui.cpp | 66 ++++++++++++++++++++++++--------------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/settings_type.h b/src/settings_type.h index cb9d95bb0f..77971e2c6c 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -81,6 +81,7 @@ struct GUISettings { TouchscreenModeByte touchscreen_mode; ///< touchscreen mode for toolbars uint min_button; ///< min size of most button widgets uint min_step; ///< min size of scrollbar/dropdown elements + uint min_game_toolbar; ///< min size of in-game toolbar buttons bool manage_min_sizing; ///< automatically set min_button and min_step bool show_finances; ///< show finances at end of year bool sg_new_nonstop; ///< ttdpatch compatible nonstop handling read from pre v93 savegames diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 91518203e1..76a261b472 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1494,6 +1494,10 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */ uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT); +#ifdef __ANDROID__ + full_buttons = SMALLEST_ARRANGEMENT + 2; // On Andorid there are lot of pixels, but the screen is still small +#endif + if (full_buttons > BIGGEST_ARRANGEMENT) { button_count = arrangable_count = lengthof(arrange_all); spacer_count = this->spacers; @@ -2166,37 +2170,37 @@ static Hotkey scenedit_maintoolbar_hotkeys[] = { HotkeyList ScenarioEditorToolbarWindow::hotkeys("scenedit_maintoolbar", scenedit_maintoolbar_hotkeys); static const NWidgetPart _nested_toolb_scen_inner_widgets[] = { - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS), - NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), NWidget(NWID_SPACER), NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(), NWidget(NWID_SPACER), NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL), NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), EndContainer(), EndContainer(), NWidget(NWID_SPACER), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), NWidget(NWID_SPACER), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), NWidget(NWID_SPACER), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), NWidget(NWID_SPACER), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), }; static NWidgetBase *MakeScenarioToolbar(int *biggest_index) @@ -2296,22 +2300,22 @@ struct TabletToolbar : Window { static const NWidgetPart _nested_tablet_simple_widgets[] = { NWidget(NWID_VERTICAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), - //NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + //NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), EndContainer(), }; static const NWidgetPart _nested_tablet_confirm_widgets[] = { NWidget(NWID_VERTICAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_CONFIRM), SetDataTip(STR_TABLET_CONFIRM, STR_TABLET_CONFIRM_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_CONFIRM), SetDataTip(STR_TABLET_CONFIRM, STR_TABLET_CONFIRM_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), EndContainer(), }; From 13b855f128c93a2ddc98ba960fff1ba19bf4bcf6 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 16 Mar 2014 22:38:10 +0200 Subject: [PATCH 075/187] Disabled Android text input button --- src/video/sdl_v.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index 23508fceff..d49f80ee50 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -353,15 +353,6 @@ bool VideoDriver_SDL::CreateMainSurface(uint w, uint h) * surface, for example). */ _requested_hwpalette = want_hwpalette; -#ifdef __ANDROID__ - SDL_Rect r; - r.h = SDL_ListModes(NULL, 0)[0]->h / 10; - r.w = r.h; - r.x = SDL_ListModes(NULL, 0)[0]->w - r.w; - r.y = SDL_ListModes(NULL, 0)[0]->h - r.h; - SDL_ANDROID_SetScreenKeyboardButtonPos(SDL_ANDROID_SCREENKEYBOARD_BUTTON_TEXT, &r); -#endif - /* DO NOT CHANGE TO HWSURFACE, IT DOES NOT WORK */ newscreen = SDL_CALL SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE | (want_hwpalette ? SDL_HWPALETTE : 0) | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE)); if (newscreen == NULL) { From 7eed04c77448ff49f1d13dd53f7d634dc3a3e44a Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 16 Mar 2014 23:03:08 +0200 Subject: [PATCH 076/187] Fixed big oolbar mode, fixed my sloppy coding --- src/settings_type.h | 1 - src/toolbar_gui.cpp | 74 ++++++++++++++++++++++++--------------------- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/settings_type.h b/src/settings_type.h index 77971e2c6c..cb9d95bb0f 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -81,7 +81,6 @@ struct GUISettings { TouchscreenModeByte touchscreen_mode; ///< touchscreen mode for toolbars uint min_button; ///< min size of most button widgets uint min_step; ///< min size of scrollbar/dropdown elements - uint min_game_toolbar; ///< min size of in-game toolbar buttons bool manage_min_sizing; ///< automatically set min_button and min_step bool show_finances; ///< show finances at end of year bool sg_new_nonstop; ///< ttdpatch compatible nonstop handling read from pre v93 savegames diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 76a261b472..4da14dfbd8 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1459,7 +1459,7 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const { static const uint SMALLEST_ARRANGEMENT = 14; - static const uint BIGGEST_ARRANGEMENT = 20; + static const uint BIGGEST_ARRANGEMENT = 21; static const byte arrange14[] = { 0, 1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 29, 2, 3, 4, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29, @@ -1488,6 +1488,10 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { 0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 11, 19, 20, 29, 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29, }; + static const byte arrange21[] = { + 0, 1, 2, 3, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 11, 19, 20, 29, + 0, 1, 2, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29, + }; static const byte arrange_all[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 }; @@ -1495,7 +1499,7 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */ uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT); #ifdef __ANDROID__ - full_buttons = SMALLEST_ARRANGEMENT + 2; // On Andorid there are lot of pixels, but the screen is still small + full_buttons = BIGGEST_ARRANGEMENT; // On Android there are lot of pixels, but the screen is still small #endif if (full_buttons > BIGGEST_ARRANGEMENT) { @@ -1505,7 +1509,7 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { } /* Introduce the split toolbar */ - static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 }; + static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20, arrange21 }; button_count = arrangable_count = full_buttons; spacer_count = this->spacers; @@ -1888,7 +1892,7 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index) NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer(); for (uint i = 0; i < WID_TN_END; i++) { switch (i) { - case 4: case 8: case 15: case 19: case 21: case 26: hor->Add(new NWidgetSpacer(0, 0)); break; + case 4: case 8: case 15: case 19: case 21: /*case 26:*/ hor->Add(new NWidgetSpacer(0, 0)); break; } hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); } @@ -2170,37 +2174,37 @@ static Hotkey scenedit_maintoolbar_hotkeys[] = { HotkeyList ScenarioEditorToolbarWindow::hotkeys("scenedit_maintoolbar", scenedit_maintoolbar_hotkeys); static const NWidgetPart _nested_toolb_scen_inner_widgets[] = { - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS), + NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO), NWidget(NWID_SPACER), NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(), NWidget(NWID_SPACER), NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL), NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD), EndContainer(), EndContainer(), NWidget(NWID_SPACER), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY), NWidget(NWID_SPACER), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), NWidget(NWID_SPACER), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), NWidget(NWID_SPACER), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR), }; static NWidgetBase *MakeScenarioToolbar(int *biggest_index) @@ -2300,22 +2304,22 @@ struct TabletToolbar : Window { static const NWidgetPart _nested_tablet_simple_widgets[] = { NWidget(NWID_VERTICAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - //NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), + //NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), EndContainer(), }; static const NWidgetPart _nested_tablet_confirm_widgets[] = { NWidget(NWID_VERTICAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_CONFIRM), SetDataTip(STR_TABLET_CONFIRM, STR_TABLET_CONFIRM_TOOLTIP), SetMinimalSize(_settings_client.gui.min_game_toolbar, _settings_client.gui.min_game_toolbar), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_CONFIRM), SetDataTip(STR_TABLET_CONFIRM, STR_TABLET_CONFIRM_TOOLTIP), EndContainer(), }; From 661b4615678c57dae2022c5cce89e9be983f72fb Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 19 Mar 2014 21:44:52 +0200 Subject: [PATCH 077/187] Fixed save/load dialog too tall --- src/fios_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 287d98d4b4..c8a0d64867 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -474,7 +474,7 @@ public: case WID_SL_DRIVES_DIRECTORIES_LIST: resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - size->height = resize->height * 10 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + size->height = resize->height * 5 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; break; case WID_SL_SORT_BYNAME: case WID_SL_SORT_BYDATE: { From 00be451e28d00c6224db684becce024a089dae95 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 19 Mar 2014 21:58:42 +0200 Subject: [PATCH 078/187] Fixed close box and scrollbar images not centered --- src/widget.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/widget.cpp b/src/widget.cpp index 40e531b678..04fa4c3ba4 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -343,10 +343,10 @@ static inline void DrawVerticalScrollbar(const Rect &r, Colours colour, bool up_ /* draw up/down buttons */ DrawFrameRect(r.left, r.top, r.right, r.top + height - 1, colour, (up_clicked) ? FR_LOWERED : FR_NONE); - DrawString(r.left + up_clicked, r.right + up_clicked, r.top + up_clicked, UPARROW, TC_BLACK, SA_HOR_CENTER); + DrawString(r.left + up_clicked, r.right + up_clicked, r.top + height / 2 + up_clicked, UPARROW, TC_BLACK, SA_CENTER); DrawFrameRect(r.left, r.bottom - (height - 1), r.right, r.bottom, colour, (down_clicked) ? FR_LOWERED : FR_NONE); - DrawString(r.left + down_clicked, r.right + down_clicked, r.bottom - (height - 1) + down_clicked, DOWNARROW, TC_BLACK, SA_HOR_CENTER); + DrawString(r.left + down_clicked, r.right + down_clicked, r.bottom - height / 2 + down_clicked, DOWNARROW, TC_BLACK, SA_CENTER); int c1 = _colour_gradient[colour & 0xF][3]; int c2 = _colour_gradient[colour & 0xF][7]; @@ -483,7 +483,7 @@ static inline void DrawCloseBox(const Rect &r, Colours colour, StringID str) { assert(str == STR_BLACK_CROSS || str == STR_SILVER_CROSS); // black or silver cross DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_NONE); - DrawString(r.left, r.right, r.top + WD_CLOSEBOX_TOP, str, TC_FROMSTRING, SA_HOR_CENTER); + DrawString(r.left, r.right, (r.top + r.bottom) / 2 - WD_CLOSEBOX_TOP, str, TC_FROMSTRING, SA_CENTER); } /** @@ -528,12 +528,12 @@ static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicke if (_current_text_dir == TD_LTR) { DrawFrameRect(r.left, r.top, r.right - dd_width, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); DrawFrameRect(r.right + 1 - dd_width, r.top, r.right, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE); - DrawString(r.right - dd_width + (clicked_dropdown ? 2 : 1), r.right, r.top + (clicked_dropdown ? 2 : 1), DOWNARROW, TC_BLACK, SA_HOR_CENTER); + DrawString(r.right - dd_width + (clicked_dropdown ? 2 : 1), r.right, (r.top + r.bottom) / 2 + (clicked_dropdown ? 2 : 1), DOWNARROW, TC_BLACK, SA_CENTER); if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - dd_width - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK); } else { DrawFrameRect(r.left + dd_width, r.top, r.right, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); DrawFrameRect(r.left, r.top, r.left + dd_width - 1, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE); - DrawString(r.left + (clicked_dropdown ? 2 : 1), r.left + dd_width, r.top + (clicked_dropdown ? 2 : 1), DOWNARROW, TC_BLACK, SA_HOR_CENTER); + DrawString(r.left + (clicked_dropdown ? 2 : 1), r.left + dd_width, (r.top + r.bottom) / 2 + (clicked_dropdown ? 2 : 1), DOWNARROW, TC_BLACK, SA_CENTER); if (str != STR_NULL) DrawString(r.left + dd_width + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK); } } From d8832c2ad601ea8ffc5a7244addad78d7b4c9e4d Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 19 Mar 2014 21:59:02 +0200 Subject: [PATCH 079/187] Fixed Android text input --- src/misc_gui.cpp | 13 +++++++++++++ src/osk_gui.cpp | 13 ------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 8fbffbda92..4092dcb6dc 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -30,6 +30,10 @@ #include "table/strings.h" +#ifdef __ANDROID__ +#include +#endif + /** Method to open the OSK. */ enum OskActivation { OSKA_DISABLED, ///< The OSK shall not be activated at all. @@ -924,6 +928,15 @@ void QueryString::ClickEditBox(Window *w, Point pt, int wid, int click_count, bo /* Open the OSK window */ ShowOnScreenKeyboard(w, wid); } +#ifdef __ANDROID__ + char text[512]; + strncpy(text, this->text.buf, sizeof(text) - 1); + text[sizeof(text) - 1] = 0; + this->text.DeleteAll(); + SDL_ANDROID_GetScreenKeyboardTextInput(text, sizeof(text) - 1); /* Invoke Android built-in screen keyboard */ + this->text.Assign(text); + w->OnEditboxChanged(wid); +#endif } /** Class for the string query window. */ diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp index 104f6f4921..52d0d2d7e7 100644 --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -22,9 +22,6 @@ #include "table/sprites.h" #include "table/strings.h" -#ifdef __ANDROID__ -#include -#endif char _keyboard_opt[2][OSK_KEYBOARD_ENTRIES * 4 + 1]; static WChar _keyboard[2][OSK_KEYBOARD_ENTRIES]; @@ -417,16 +414,6 @@ void ShowOnScreenKeyboard(Window *parent, int button) GetKeyboardLayout(); new OskWindow(&_osk_desc, parent, button); -#ifdef __ANDROID__ - char text[256]; - SDL_ANDROID_GetScreenKeyboardTextInput(text, sizeof(text) - 1); /* Invoke Android built-in screen keyboard */ - OskWindow *osk = dynamic_cast(FindWindowById(WC_OSK, 0)); - osk->qs->text.Assign(text); - free(osk->orig_str_buf); - osk->orig_str_buf = strdup(osk->qs->text.buf); - - osk->SetDirty(); -#endif } /** From 9a173be4368effd6481add3fd6d349142e6f2224 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 19 Mar 2014 22:31:51 +0200 Subject: [PATCH 080/187] Fixed "New Game" dialog --- src/genworld_gui.cpp | 66 ++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 42 deletions(-) diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index 902f47a097..bc5bc80c85 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -61,20 +61,20 @@ static const NWidgetPart _nested_generate_landscape_widgets[] = { EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(NWID_SPACER), SetMinimalSize(0, 10), - /* Landscape selection. */ - NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 10), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_TEMPERATE), SetDataTip(SPR_SELECT_TEMPERATE, STR_INTRO_TOOLTIP_TEMPERATE), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_ARCTIC), SetDataTip(SPR_SELECT_SUB_ARCTIC, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_TROPICAL), SetDataTip(SPR_SELECT_SUB_TROPICAL, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_TOYLAND), SetDataTip(SPR_SELECT_TOYLAND, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 11), NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10), + /* Landscape selection. */ + NWidget(NWID_VERTICAL), SetPIP(10, 0, 10), + NWidget(NWID_SPACER), SetFill(1, 1), + NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_TEMPERATE), SetDataTip(SPR_SELECT_TEMPERATE, STR_INTRO_TOOLTIP_TEMPERATE), + NWidget(NWID_SPACER), SetFill(1, 1), + NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_ARCTIC), SetDataTip(SPR_SELECT_SUB_ARCTIC, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE), + NWidget(NWID_SPACER), SetFill(1, 1), + NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_TROPICAL), SetDataTip(SPR_SELECT_SUB_TROPICAL, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE), + NWidget(NWID_SPACER), SetFill(1, 1), + NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_TOYLAND), SetDataTip(SPR_SELECT_TOYLAND, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE), + NWidget(NWID_SPACER), SetFill(1, 1), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(20, 0), NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0), /* Left column with labels. */ NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 4, 0), @@ -136,37 +136,19 @@ static const NWidgetPart _nested_generate_landscape_widgets[] = { NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_QUANTITY_OF_RIVERS, STR_NULL), SetFill(1, 1), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_RIVER_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), EndContainer(), - NWidget(NWID_SPACER), SetFill(1, 1), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_GL_GENERATE_BUTTON), SetMinimalSize(84, 30), SetDataTip(STR_MAPGEN_GENERATE, STR_NULL), SetFill(1, 0), + /* Map borders buttons for each edge. */ + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_NW), SetDataTip(STR_JUST_STRING, STR_MAPGEN_NORTHWEST), SetFill(1, 1), + NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_NE), SetDataTip(STR_JUST_STRING, STR_MAPGEN_NORTHEAST), SetFill(1, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_SW), SetDataTip(STR_JUST_STRING, STR_MAPGEN_SOUTHWEST), SetFill(1, 1), + NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_SE), SetDataTip(STR_JUST_STRING, STR_MAPGEN_SOUTHEAST), SetFill(1, 1), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_GL_GENERATE_BUTTON), SetDataTip(STR_MAPGEN_GENERATE, STR_NULL), SetFill(1, 0), EndContainer(), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 4), - /* Map borders buttons for each edge. */ - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 0, 3), - NWidget(NWID_SPACER), SetFill(1, 1), - NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_NORTHWEST, STR_NULL), SetPadding(1, 0, 0, 0), SetFill(0, 1), - EndContainer(), - NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_NW), SetDataTip(STR_JUST_STRING, STR_MAPGEN_NORTHWEST), SetFill(1, 1), - NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_NE), SetDataTip(STR_JUST_STRING, STR_MAPGEN_NORTHEAST), SetFill(1, 1), - NWidget(NWID_HORIZONTAL), SetPIP(3, 0, 0), - NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_NORTHEAST, STR_NULL), SetPadding(1, 0, 0, 0), SetFill(0, 1), - NWidget(NWID_SPACER), SetFill(1, 1), - EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 0, 10), - NWidget(NWID_HORIZONTAL), SetPIP(0, 0, 3), - NWidget(NWID_SPACER), SetFill(1, 1), - NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_SOUTHWEST, STR_NULL), SetPadding(1, 0, 0, 0), SetFill(0, 1), - EndContainer(), - NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_SW), SetDataTip(STR_JUST_STRING, STR_MAPGEN_SOUTHWEST), SetFill(1, 1), - NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_SE), SetDataTip(STR_JUST_STRING, STR_MAPGEN_SOUTHEAST), SetFill(1, 1), - NWidget(NWID_HORIZONTAL), SetPIP(3, 0, 0), - NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_SOUTHEAST, STR_NULL), SetPadding(1, 0, 0, 0), SetFill(0, 1), - NWidget(NWID_SPACER), SetFill(1, 1), - EndContainer(), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 9), SetFill(1, 1), + NWidget(NWID_SPACER), SetMinimalSize(0, 10), EndContainer(), }; From 383826139ceb38883b0cd1ec235952225297bb25 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 19 Mar 2014 22:32:19 +0200 Subject: [PATCH 081/187] Centered strings in file lists and in dropdowns --- src/fios_gui.cpp | 2 +- src/widgets/dropdown.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index c8a0d64867..ced9e722d8 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -355,7 +355,7 @@ public: case WID_SL_DRIVES_DIRECTORIES_LIST: { GfxFillRect(r.left + 1, r.top + 1, r.right, r.bottom, PC_BLACK); - uint y = r.top + WD_FRAMERECT_TOP; + uint y = r.top + WD_FRAMERECT_TOP + this->resize.step_height / 2; for (uint pos = this->vscroll->GetPosition(); pos < _fios_items.Length(); pos++) { const FiosItem *item = _fios_items.Get(pos); diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 6603dd588a..174bf95f69 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -228,12 +228,12 @@ struct DropdownWindow : Window { if (y + item_height < r.bottom) { bool selected = (this->selected_index == item->result); - if (selected) GfxFillRect(r.left + 2, y, r.right - 1, y + item_height - 1, PC_BLACK); + if (selected) GfxFillRect(r.left + 2, y + item_height / 2, r.right - 1, y + item_height * 3 / 2 - 1, PC_BLACK); - item->Draw(r.left, r.right, y, y + item_height, selected, colour); + item->Draw(r.left, r.right, y + item_height / 2, y + item_height * 3 / 2, selected, colour); if (item->masked) { - GfxFillRect(r.left + 1, y, r.right - 1, y + item_height - 1, _colour_gradient[colour][5], FILLRECT_CHECKER); + GfxFillRect(r.left + 1, y + item_height / 2, r.right - 1, y + item_height * 3 / 2 - 1, _colour_gradient[colour][5], FILLRECT_CHECKER); } } y += item_height; From 31904e34d62429e4afa0fca76220d821a022c7d3 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 19 Mar 2014 22:32:19 +0200 Subject: [PATCH 082/187] Centered strings in file lists --- src/fios_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index c8a0d64867..ced9e722d8 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -355,7 +355,7 @@ public: case WID_SL_DRIVES_DIRECTORIES_LIST: { GfxFillRect(r.left + 1, r.top + 1, r.right, r.bottom, PC_BLACK); - uint y = r.top + WD_FRAMERECT_TOP; + uint y = r.top + WD_FRAMERECT_TOP + this->resize.step_height / 2; for (uint pos = this->vscroll->GetPosition(); pos < _fios_items.Length(); pos++) { const FiosItem *item = _fios_items.Get(pos); From 7d41950f73a97e9b31112876aa6ad49928e1a0ae Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 19 Mar 2014 23:01:16 +0200 Subject: [PATCH 083/187] Centered strings in in-game options pull-down menu --- src/toolbar_gui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 4da14dfbd8..c9c93be4bb 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -97,9 +97,9 @@ public: { bool rtl = _current_text_dir == TD_RTL; if (this->checked) { - DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK); + DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, Center(top, bottom - top), STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK); } - DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : this->checkmark_width), right - WD_FRAMERECT_RIGHT - (rtl ? this->checkmark_width : 0), top, this->String(), sel ? TC_WHITE : TC_BLACK); + DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : this->checkmark_width), right - WD_FRAMERECT_RIGHT - (rtl ? this->checkmark_width : 0), Center(top, bottom - top), this->String(), sel ? TC_WHITE : TC_BLACK); } }; From 88c1d5f29c52027f304ad2df986a4cb648626881 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 19 Mar 2014 23:01:45 +0200 Subject: [PATCH 084/187] Added todo --- todo.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 todo.txt diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000000..9e4a566ec1 --- /dev/null +++ b/todo.txt @@ -0,0 +1,6 @@ +- Move 'mobile' toolbar buttons to the main toolbar +- Fix NewGRF dialog +- Fix Advanced Settings dialog +- Fix Online Content dialog +- Fix AI dialog +- Fix Multiplayer dialog From 25630ab4c72c67a942a421c029b102d1cd39fb17 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 19 Mar 2014 23:49:08 +0200 Subject: [PATCH 085/187] Moved touchscrren buttons to main toolbar, now it crashes --- src/command.cpp | 4 - src/script/api/game/game_window.hpp.sq | 9 +- src/script/api/script_window.hpp | 13 +- .../api/template/template_window.hpp.sq | 2 - src/toolbar_gui.cpp | 202 +++++------------- src/widgets/toolbar_widget.h | 13 +- 6 files changed, 57 insertions(+), 186 deletions(-) diff --git a/src/command.cpp b/src/command.cpp index 7dfc7529f2..fc827449f3 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -555,8 +555,6 @@ bool TouchCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCall if (text != NULL) ttd_strlcpy(_queued_command.text, text, 32 * MAX_CHAR_LENGTH); _my_cmd = my_cmd; _is_queued_command = true; - extern void UpdateTouchscreenBar(); - UpdateTouchscreenBar(); return true; } else { return DoCommandP(tile, p1, p2, cmd, callback, text, my_cmd); @@ -595,8 +593,6 @@ void EraseQueuedTouchCommand() { if (!IsQueuedTouchCommand()) return; _is_queued_command = false; - extern void UpdateTouchscreenBar(); - UpdateTouchscreenBar(); SetSelectionTilesDirty(); _thd.Reset(); } diff --git a/src/script/api/game/game_window.hpp.sq b/src/script/api/game/game_window.hpp.sq index f25359e344..dfccacf1b2 100644 --- a/src/script/api/game/game_window.hpp.sq +++ b/src/script/api/game/game_window.hpp.sq @@ -1180,6 +1180,9 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_MESSAGES, "WID_TN_MESSAGES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_HELP, "WID_TN_HELP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SWITCH_BAR, "WID_TN_SWITCH_BAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_CTRL, "WID_TN_CTRL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SHIFT, "WID_TN_SHIFT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_DELETE, "WID_TN_DELETE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_END, "WID_TN_END"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_PAUSE, "WID_TE_PAUSE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_FAST_FORWARD, "WID_TE_FAST_FORWARD"); @@ -1203,12 +1206,6 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_MUSIC_SOUND, "WID_TE_MUSIC_SOUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_HELP, "WID_TE_HELP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SWITCH_BAR, "WID_TE_SWITCH_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_X, "WID_TT_X"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_DELETE, "WID_TT_DELETE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SHIFT, "WID_TT_SHIFT"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_CTRL, "WID_TT_CTRL"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_MOVE, "WID_TT_MOVE"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_CONFIRM, "WID_TT_CONFIRM"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_ORDER, "WID_TD_SORT_ORDER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_CRITERIA, "WID_TD_SORT_CRITERIA"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_LIST, "WID_TD_LIST"); diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp index 62570aa6fa..680c3f2d85 100644 --- a/src/script/api/script_window.hpp +++ b/src/script/api/script_window.hpp @@ -2375,6 +2375,9 @@ public: WID_TN_MESSAGES = ::WID_TN_MESSAGES, ///< Messages menu. WID_TN_HELP = ::WID_TN_HELP, ///< Help menu. WID_TN_SWITCH_BAR = ::WID_TN_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. + WID_TN_CTRL = ::WID_TN_CTRL, ///< On-screen Ctrl key + WID_TN_SHIFT = ::WID_TN_SHIFT, ///< On-screen Sgift key + WID_TN_DELETE = ::WID_TN_DELETE, ///< Close all windows WID_TN_END = ::WID_TN_END, ///< Helper for knowing the amount of widgets. }; @@ -2405,16 +2408,6 @@ public: WID_TE_SWITCH_BAR = ::WID_TE_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. }; - /** Widgets of the TabletToolbar class. */ - enum ToolbarTabletWidgets { - WID_TT_X = ::WID_TT_X, ///< Press X (toggle transparency). - WID_TT_DELETE = ::WID_TT_DELETE, ///< Press DELETE. - WID_TT_SHIFT = ::WID_TT_SHIFT, ///< Press SHIFT. - WID_TT_CTRL = ::WID_TT_CTRL, ///< Press CTRL. - WID_TT_MOVE = ::WID_TT_MOVE, ///< Click for moving around viewports. - WID_TT_CONFIRM = ::WID_TT_CONFIRM, ///< Confirm action. - }; - /* automatically generated from ../../widgets/town_widget.h */ /** Widgets of the #TownDirectoryWindow class. */ enum TownDirectoryWidgets { diff --git a/src/script/api/template/template_window.hpp.sq b/src/script/api/template/template_window.hpp.sq index 931c37d283..9f01e42d5a 100644 --- a/src/script/api/template/template_window.hpp.sq +++ b/src/script/api/template/template_window.hpp.sq @@ -223,8 +223,6 @@ namespace SQConvert { template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolbarNormalWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ToolbarEditorWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolbarEditorWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolbarEditorWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::ToolbarTabletWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolbarTabletWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolbarTabletWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TownDirectoryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownDirectoryWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownDirectoryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TownAuthorityWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownAuthorityWidgets)tmp; } diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index c9c93be4bb..9892a62ed3 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1162,6 +1162,30 @@ static CallBackFunction ToolbarSwitchClick(Window *w) return CBF_NONE; } +static CallBackFunction ToolbarCtrlClick(Window *w) +{ + _ctrl_pressed = !_ctrl_pressed; + w->ToggleWidgetLoweredState(WID_TN_CTRL); + HandleCtrlChanged(); + w->SetWidgetDirty(WID_TN_CTRL); + EraseQueuedTouchCommand(); + return CBF_NONE; +} + +static CallBackFunction ToolbarShiftClick(Window *w) +{ + _shift_pressed = !_shift_pressed; + w->ToggleWidgetLoweredState(WID_TN_SHIFT); + w->SetWidgetDirty(WID_TN_SHIFT); + return CBF_NONE; +} + +static CallBackFunction ToolbarDeleteClick(Window *w) +{ + DeleteNonVitalWindows(); + return CBF_NONE; +} + /* --- Scenario editor specific handlers. */ /** @@ -1459,7 +1483,7 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const { static const uint SMALLEST_ARRANGEMENT = 14; - static const uint BIGGEST_ARRANGEMENT = 21; + static const uint BIGGEST_ARRANGEMENT = 20; static const byte arrange14[] = { 0, 1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 29, 2, 3, 4, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29, @@ -1488,19 +1512,23 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { 0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 11, 19, 20, 29, 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29, }; - static const byte arrange21[] = { - 0, 1, 2, 3, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 11, 19, 20, 29, - 0, 1, 2, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29, - }; static const byte arrange_all[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 }; +#ifdef __ANDROID__ + static const byte arrange_android[] = { + 0, 1, 2, 4, 5, 6, 7, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29, 30, 31, 32, + 0, 1, 3, 4, 5, 6, 7, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29, 30, 31, 32, + }; + + button_count = arrangable_count = lengthof(arrange_android) / 2; + spacer_count = this->spacers; + return arrange_android; +#else + /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */ uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT); -#ifdef __ANDROID__ - full_buttons = BIGGEST_ARRANGEMENT; // On Android there are lot of pixels, but the screen is still small -#endif if (full_buttons > BIGGEST_ARRANGEMENT) { button_count = arrangable_count = lengthof(arrange_all); @@ -1509,11 +1537,12 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { } /* Introduce the split toolbar */ - static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20, arrange21 }; + static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 }; button_count = arrangable_count = full_buttons; spacer_count = this->spacers; return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0); +#endif } }; @@ -1613,6 +1642,9 @@ static ToolbarButtonProc * const _toolbar_button_procs[] = { ToolbarNewspaperClick, ToolbarHelpClick, ToolbarSwitchClick, + ToolbarCtrlClick, + ToolbarShiftClick, + ToolbarDeleteClick, }; enum MainToolbarHotkeys { @@ -1890,14 +1922,19 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index) }; NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer(); - for (uint i = 0; i < WID_TN_END; i++) { + for (uint i = 0; i <= SPR_IMG_SWITCH_TOOLBAR; i++) { switch (i) { case 4: case 8: case 15: case 19: case 21: /*case 26:*/ hor->Add(new NWidgetSpacer(0, 0)); break; } hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); } - *biggest_index = max(*biggest_index, WID_TN_SWITCH_BAR); + hor->Add(new NWidgetSpacer(0, 0)); + hor->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TN_CTRL, STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP)); + hor->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TN_SHIFT, STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP)); + hor->Add(new NWidgetLeaf(WWT_TEXTBTN, COLOUR_GREY, WID_TN_DELETE, STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP)); + + *biggest_index = max(*biggest_index, WID_TN_DELETE); return hor; } @@ -2224,142 +2261,6 @@ static WindowDesc _toolb_scen_desc( &ScenarioEditorToolbarWindow::hotkeys ); - -/** Tablet toolbar. */ -struct TabletToolbar : Window { - - TabletToolbar(WindowDesc *desc) : Window(desc) - { - this->InitNested(0); - this->flags |= WF_STICKY; - ResetObjectToPlace(); - this->OnInvalidateData(1 << 2); // Disable widgets. - if (_current_text_dir == TD_RTL) { this->left = _screen.width - this->width; } - } - - ~TabletToolbar() { - _shift_pressed = false; - _move_pressed = false; - - if (_ctrl_pressed) { - _ctrl_pressed = false; - HandleCtrlChanged(); - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch (widget) { - case WID_TT_X: - extern void ResetRestoreAllTransparency(); - ResetRestoreAllTransparency(); - break; - case WID_TT_DELETE: - DeleteNonVitalWindows(); - break; - case WID_TT_SHIFT: - _shift_pressed = !_shift_pressed; - this->ToggleWidgetLoweredState(WID_TT_SHIFT); - this->SetWidgetDirty(WID_TT_SHIFT); - break; - case WID_TT_CTRL: - _ctrl_pressed = !_ctrl_pressed; - this->ToggleWidgetLoweredState(WID_TT_CTRL); - HandleCtrlChanged(); - this->SetWidgetDirty(WID_TT_CTRL); - EraseQueuedTouchCommand(); - break; - case WID_TT_MOVE: - _move_pressed = !_move_pressed; - this->ToggleWidgetLoweredState(WID_TT_MOVE); - this->SetWidgetDirty(WID_TT_MOVE); - break; - case WID_TT_CONFIRM: - DoQueuedTouchCommand(); - break; - default: - NOT_REACHED(); - } - } - - /** - * 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. - * @note bit 2 -> Update tile selection. - * bit 3 -> Set window dirty. - */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) - { - /* Selection has changed. */ - if (HasBit(data, 2)) { UpdateTileSelection(); } - - /* This window is dirty. */ - if (HasBit(data, 3)) { - SetWidgetDisabledState(WID_TT_CONFIRM, !IsQueuedTouchCommand()); - this->SetWidgetDirty(WID_TT_CONFIRM); - } - } -}; - -static const NWidgetPart _nested_tablet_simple_widgets[] = { - NWidget(NWID_VERTICAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), - //NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), - EndContainer(), -}; - -static const NWidgetPart _nested_tablet_confirm_widgets[] = { - NWidget(NWID_VERTICAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_X), SetDataTip(STR_TABLET_X, STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_DELETE), SetDataTip(STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_SHIFT), SetDataTip(STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_CTRL), SetDataTip(STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TT_MOVE), SetDataTip(STR_TABLET_MOVE, STR_TABLET_MOVE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TT_CONFIRM), SetDataTip(STR_TABLET_CONFIRM, STR_TABLET_CONFIRM_TOOLTIP), - EndContainer(), -}; - -static WindowDesc _toolbar_tablet_simple_desc( - WDP_AUTO, NULL, 0, 0, - WC_TABLET_BAR, WC_NONE, - WDF_NO_FOCUS, - _nested_tablet_simple_widgets, lengthof(_nested_tablet_simple_widgets) -); - -static WindowDesc _toolbar_tablet_confirm_desc( - WDP_AUTO, NULL, 0, 0, - WC_TABLET_BAR, WC_NONE, - WDF_NO_FOCUS, - _nested_tablet_confirm_widgets, lengthof(_nested_tablet_confirm_widgets) -); - -void ResetTabletWindow() -{ - if (_game_mode == GM_MENU) return; - - DeleteWindowByClass(WC_TABLET_BAR); - EraseQueuedTouchCommand(); - - switch (_settings_client.gui.touchscreen_mode) { - case TSC_NONE: - break; - case TSC_SIMPLE: - new TabletToolbar(&_toolbar_tablet_simple_desc); - break; - case TSC_CONFIRM: - new TabletToolbar(&_toolbar_tablet_confirm_desc); - InvalidateWindowData(WC_TABLET_BAR, 0, 1 << 3); - break; - default: NOT_REACHED(); - } - - MarkWholeScreenDirty(); -} - /** Allocate the toolbar. */ void AllocateToolbar() { @@ -2371,11 +2272,4 @@ void AllocateToolbar() } else { new MainToolbarWindow(&_toolb_normal_desc); } - - ResetTabletWindow(); -} - -void UpdateTouchscreenBar() -{ - InvalidateWindowData(WC_TABLET_BAR, 0, 1 << 3); } diff --git a/src/widgets/toolbar_widget.h b/src/widgets/toolbar_widget.h index 4399b5d10c..172564b883 100644 --- a/src/widgets/toolbar_widget.h +++ b/src/widgets/toolbar_widget.h @@ -45,6 +45,9 @@ enum ToolbarNormalWidgets { WID_TN_MESSAGES, ///< Messages menu. WID_TN_HELP, ///< Help menu. WID_TN_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. + WID_TN_CTRL, ///< Press CTRL. + WID_TN_SHIFT, ///< Press SHIFT. + WID_TN_DELETE, ///< Press DELETE. WID_TN_END, ///< Helper for knowing the amount of widgets. }; @@ -75,14 +78,4 @@ enum ToolbarEditorWidgets { WID_TE_SWITCH_BAR = WID_TN_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. }; -/** Widgets of the TabletToolbar class. */ -enum ToolbarTabletWidgets { - WID_TT_X, ///< Press X (toggle transparency). - WID_TT_DELETE, ///< Press DELETE. - WID_TT_SHIFT, ///< Press SHIFT. - WID_TT_CTRL, ///< Press CTRL. - WID_TT_MOVE, ///< Click for moving around viewports. - WID_TT_CONFIRM, ///< Confirm action. -}; - #endif /* WIDGETS_TOOLBAR_WIDGET_H */ From 53c5f2bae376e6e8358f38d628bc5f0849437237 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 19 Mar 2014 23:50:56 +0200 Subject: [PATCH 086/187] Revert "Centered strings in file lists and in dropdowns" This reverts commit 383826139ceb38883b0cd1ec235952225297bb25. --- src/fios_gui.cpp | 2 +- src/widgets/dropdown.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index ced9e722d8..c8a0d64867 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -355,7 +355,7 @@ public: case WID_SL_DRIVES_DIRECTORIES_LIST: { GfxFillRect(r.left + 1, r.top + 1, r.right, r.bottom, PC_BLACK); - uint y = r.top + WD_FRAMERECT_TOP + this->resize.step_height / 2; + uint y = r.top + WD_FRAMERECT_TOP; for (uint pos = this->vscroll->GetPosition(); pos < _fios_items.Length(); pos++) { const FiosItem *item = _fios_items.Get(pos); diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 174bf95f69..6603dd588a 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -228,12 +228,12 @@ struct DropdownWindow : Window { if (y + item_height < r.bottom) { bool selected = (this->selected_index == item->result); - if (selected) GfxFillRect(r.left + 2, y + item_height / 2, r.right - 1, y + item_height * 3 / 2 - 1, PC_BLACK); + if (selected) GfxFillRect(r.left + 2, y, r.right - 1, y + item_height - 1, PC_BLACK); - item->Draw(r.left, r.right, y + item_height / 2, y + item_height * 3 / 2, selected, colour); + item->Draw(r.left, r.right, y, y + item_height, selected, colour); if (item->masked) { - GfxFillRect(r.left + 1, y + item_height / 2, r.right - 1, y + item_height * 3 / 2 - 1, _colour_gradient[colour][5], FILLRECT_CHECKER); + GfxFillRect(r.left + 1, y, r.right - 1, y + item_height - 1, _colour_gradient[colour][5], FILLRECT_CHECKER); } } y += item_height; From 390776ea07679e5c971ce6ed7ce5bdeb6b102255 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 19 Mar 2014 22:32:19 +0200 Subject: [PATCH 087/187] Centered strings in file lists --- src/fios_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index c8a0d64867..ced9e722d8 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -355,7 +355,7 @@ public: case WID_SL_DRIVES_DIRECTORIES_LIST: { GfxFillRect(r.left + 1, r.top + 1, r.right, r.bottom, PC_BLACK); - uint y = r.top + WD_FRAMERECT_TOP; + uint y = r.top + WD_FRAMERECT_TOP + this->resize.step_height / 2; for (uint pos = this->vscroll->GetPosition(); pos < _fios_items.Length(); pos++) { const FiosItem *item = _fios_items.Get(pos); From 571b244680cd61b607928a6cffbb16cc20a39ca5 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Thu, 20 Mar 2014 17:18:47 +0200 Subject: [PATCH 088/187] Updated todo --- todo.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/todo.txt b/todo.txt index 9e4a566ec1..c0bb672060 100644 --- a/todo.txt +++ b/todo.txt @@ -4,3 +4,4 @@ - Fix Online Content dialog - Fix AI dialog - Fix Multiplayer dialog +- Fix missing sprites error From 8602c3f8f8793efe7ef4e802e814d3755db2d82a Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Thu, 20 Mar 2014 18:15:06 +0200 Subject: [PATCH 089/187] Fixed crash in my prev commit --- src/toolbar_gui.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 9892a62ed3..f1d1ceba88 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1165,7 +1165,7 @@ static CallBackFunction ToolbarSwitchClick(Window *w) static CallBackFunction ToolbarCtrlClick(Window *w) { _ctrl_pressed = !_ctrl_pressed; - w->ToggleWidgetLoweredState(WID_TN_CTRL); + w->SetWidgetLoweredState(WID_TN_CTRL, _ctrl_pressed); HandleCtrlChanged(); w->SetWidgetDirty(WID_TN_CTRL); EraseQueuedTouchCommand(); @@ -1175,7 +1175,7 @@ static CallBackFunction ToolbarCtrlClick(Window *w) static CallBackFunction ToolbarShiftClick(Window *w) { _shift_pressed = !_shift_pressed; - w->ToggleWidgetLoweredState(WID_TN_SHIFT); + w->SetWidgetLoweredState(WID_TN_SHIFT, _shift_pressed); w->SetWidgetDirty(WID_TN_SHIFT); return CBF_NONE; } @@ -1524,7 +1524,7 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { button_count = arrangable_count = lengthof(arrange_android) / 2; spacer_count = this->spacers; - return arrange_android; + return &arrange_android[((_toolbar_mode == TB_LOWER) ? button_count : 0)]; #else /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */ @@ -1544,6 +1544,14 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0); #endif } + public: + int getWidgetCount() const + { + int count = 0; + for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) + count++; + return count; + } }; /** Container for the scenario editor's toolbar */ @@ -1922,9 +1930,9 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index) }; NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer(); - for (uint i = 0; i <= SPR_IMG_SWITCH_TOOLBAR; i++) { + for (uint i = 0; i <= WID_TN_SWITCH_BAR; i++) { switch (i) { - case 4: case 8: case 15: case 19: case 21: /*case 26:*/ hor->Add(new NWidgetSpacer(0, 0)); break; + case 4: case 8: case 15: case 19: case 21: case 26: hor->Add(new NWidgetSpacer(0, 0)); break; } hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); } From dac6ac71dab2c00cc9b994e75fc28c3b3bf24137 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Thu, 20 Mar 2014 20:07:41 +0200 Subject: [PATCH 090/187] Fixed Ctrl/Shift buttons not lowering when clicked --- src/toolbar_gui.cpp | 41 ++++++++++++++++++----------------------- todo.txt | 1 - 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index f1d1ceba88..5771ae6a11 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1339,7 +1339,7 @@ public: */ bool IsButton(WidgetType type) const { - return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN; + return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN || type == WWT_PUSHTXTBTN || type == WWT_TEXTBTN; } void SetupSmallestSize(Window *w, bool init_array) @@ -1482,6 +1482,19 @@ public: class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const { +#ifdef __ANDROID__ + + static const byte arrange_android[] = { + 0, 1, 2, 4, 5, 6, 7, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29, 30, 31, 32, + 0, 1, 3, 4, 5, 6, 7, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29, 30, 31, 32, + }; + + button_count = arrangable_count = lengthof(arrange_android) / 2; + spacer_count = this->spacers; + return &arrange_android[((_toolbar_mode == TB_LOWER) ? button_count : 0)]; + +#else + static const uint SMALLEST_ARRANGEMENT = 14; static const uint BIGGEST_ARRANGEMENT = 20; static const byte arrange14[] = { @@ -1516,17 +1529,6 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 }; -#ifdef __ANDROID__ - static const byte arrange_android[] = { - 0, 1, 2, 4, 5, 6, 7, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29, 30, 31, 32, - 0, 1, 3, 4, 5, 6, 7, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29, 30, 31, 32, - }; - - button_count = arrangable_count = lengthof(arrange_android) / 2; - spacer_count = this->spacers; - return &arrange_android[((_toolbar_mode == TB_LOWER) ? button_count : 0)]; -#else - /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */ uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT); @@ -1542,16 +1544,9 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { button_count = arrangable_count = full_buttons; spacer_count = this->spacers; return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0); + #endif } - public: - int getWidgetCount() const - { - int count = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) - count++; - return count; - } }; /** Container for the scenario editor's toolbar */ @@ -1938,9 +1933,9 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index) } hor->Add(new NWidgetSpacer(0, 0)); - hor->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TN_CTRL, STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP)); - hor->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TN_SHIFT, STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP)); - hor->Add(new NWidgetLeaf(WWT_TEXTBTN, COLOUR_GREY, WID_TN_DELETE, STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP)); + hor->Add(new NWidgetLeaf(WWT_TEXTBTN, COLOUR_GREY, WID_TN_CTRL, STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP)); + hor->Add(new NWidgetLeaf(WWT_TEXTBTN, COLOUR_GREY, WID_TN_SHIFT, STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP)); + hor->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TN_DELETE, STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP)); *biggest_index = max(*biggest_index, WID_TN_DELETE); return hor; diff --git a/todo.txt b/todo.txt index c0bb672060..d45e8e25c0 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,3 @@ -- Move 'mobile' toolbar buttons to the main toolbar - Fix NewGRF dialog - Fix Advanced Settings dialog - Fix Online Content dialog From c0462a53e0d30ca83da61096427aa4953ced63cc Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Thu, 20 Mar 2014 20:24:35 +0200 Subject: [PATCH 091/187] Updated todo --- todo.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/todo.txt b/todo.txt index d45e8e25c0..885d13f3cb 100644 --- a/todo.txt +++ b/todo.txt @@ -3,4 +3,3 @@ - Fix Online Content dialog - Fix AI dialog - Fix Multiplayer dialog -- Fix missing sprites error From 6a81df3ecb06377f6e7e8ff6ac6020f079b4ae14 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Thu, 20 Mar 2014 23:42:14 +0200 Subject: [PATCH 092/187] Updated todo --- todo.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/todo.txt b/todo.txt index 885d13f3cb..946c6d5998 100644 --- a/todo.txt +++ b/todo.txt @@ -3,3 +3,4 @@ - Fix Online Content dialog - Fix AI dialog - Fix Multiplayer dialog +- Scrollbar slider may become too narrow From 7bbd2dfeee9d09c03a3f707b14af2bd6ba98bbbe Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 22 Mar 2014 00:51:07 +0200 Subject: [PATCH 093/187] Fixed scrollbar slider getting too small, cenetered sort marks and horizontal scrollbar arrows --- src/widget.cpp | 17 +++++++++++------ todo.txt | 1 - 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/widget.cpp b/src/widget.cpp index 04fa4c3ba4..5905d1c77e 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -48,6 +48,8 @@ static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom, bo } top += button_size; // top points to just below the up-button bottom -= button_size; // bottom points to top of the down-button + if (bottom > top + button_size) + bottom -= button_size; // Slider should be no smaller than a regular button, reserve some size from bottom int height = (bottom - top); int pos = sb->GetPosition(); @@ -57,11 +59,11 @@ static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom, bo if (count != 0) top += height * pos / count; if (cap > count) cap = count; - if (count != 0) bottom -= (count - pos - cap) * height / count; + if (count != 0) bottom -= (count - pos - cap) * height / count - button_size; Point pt; if (horizontal && _current_text_dir == TD_RTL) { - pt.x = rev_base - bottom; + pt.x = rev_base - bottom - button_size; pt.y = rev_base - top; } else { pt.x = top; @@ -119,7 +121,9 @@ static void ScrollbarClickPositioning(Window *w, NWidgetScrollbar *sb, int x, in sb->UpdatePosition(rtl ? -1 : 1, Scrollbar::SS_BIG); } else { _scrollbar_start_pos = pt.x - mi - button_size; - _scrollbar_size = ma - mi - button_size * 2; + _scrollbar_size = ma - mi - button_size * 3; + if (_scrollbar_size <= 0) + _scrollbar_size = 1; w->scrolling_scrollbar = sb->index; _cursorpos_drag_start = _cursor.pos; } @@ -378,12 +382,13 @@ static inline void DrawHorizontalScrollbar(const Rect &r, Colours colour, bool l { int centre = (r.bottom - r.top) / 2; int width = NWidgetScrollbar::GetHorizontalDimension().width; + int height = NWidgetScrollbar::GetVerticalDimension().height; DrawFrameRect(r.left, r.top, r.left + width - 1, r.bottom, colour, left_clicked ? FR_LOWERED : FR_NONE); - DrawSprite(SPR_ARROW_LEFT, PAL_NONE, r.left + 1 + left_clicked, r.top + 1 + left_clicked); + DrawSprite(SPR_ARROW_LEFT, PAL_NONE, r.left + 1 + left_clicked, r.top + height / 2 + 1 + left_clicked); DrawFrameRect(r.right - (width - 1), r.top, r.right, r.bottom, colour, right_clicked ? FR_LOWERED : FR_NONE); - DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, r.right - (width - 2) + right_clicked, r.top + 1 + right_clicked); + DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, r.right - (width - 2) + right_clicked, r.top + height / 2 + 1 + right_clicked); int c1 = _colour_gradient[colour & 0xF][3]; int c2 = _colour_gradient[colour & 0xF][7]; @@ -598,7 +603,7 @@ void Window::DrawSortButtonState(int widget, SortButtonState state) const int base = offset + nwid->pos_x + (_current_text_dir == TD_LTR ? nwid->current_x - WD_SORTBUTTON_ARROW_WIDTH : 0); int top = nwid->pos_y; - DrawString(base, base + WD_SORTBUTTON_ARROW_WIDTH, top + 1 + offset, state == SBS_DOWN ? DOWNARROW : UPARROW, TC_BLACK, SA_HOR_CENTER); + DrawString(base, base + WD_SORTBUTTON_ARROW_WIDTH, top + nwid->current_y / 2 + 1 + offset, state == SBS_DOWN ? DOWNARROW : UPARROW, TC_BLACK, SA_HOR_CENTER); } diff --git a/todo.txt b/todo.txt index 946c6d5998..885d13f3cb 100644 --- a/todo.txt +++ b/todo.txt @@ -3,4 +3,3 @@ - Fix Online Content dialog - Fix AI dialog - Fix Multiplayer dialog -- Scrollbar slider may become too narrow From d9e237211a5130987dce52f9f2d706988aca2039 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 22 Mar 2014 01:14:35 +0200 Subject: [PATCH 094/187] Fixed 'Check online content' dialog --- src/network/network_content_gui.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index 6988be2055..31783f99a5 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -23,6 +23,7 @@ #include "../querystring_gui.h" #include "../core/geometry_func.hpp" #include "../textfile_gui.h" +#include "../settings_type.h" #include "network_content_gui.h" @@ -524,8 +525,8 @@ public: } case WID_NCL_MATRIX: - resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); - size->height = 10 * resize->height; + resize->height = GetMinSizing(NWST_STEP, _settings_client.gui.min_step + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); + size->height = 6 * resize->height; break; } } @@ -966,14 +967,7 @@ static const NWidgetPart _nested_network_content_list_widgets[] = { NWidget(WWT_DEFSIZEBOX, COLOUR_LIGHT_BLUE), EndContainer(), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_BACKGROUND), - NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8), - /* Top */ - NWidget(WWT_EMPTY, COLOUR_LIGHT_BLUE, WID_NCL_FILTER_CAPT), SetFill(1, 0), SetResize(1, 0), - NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NCL_FILTER), SetFill(1, 0), SetResize(1, 0), - SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0), + NWidget(NWID_SPACER), SetMinimalSize(0, 3), SetResize(1, 0), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8), /* Left side. */ NWidget(NWID_VERTICAL), SetPIP(0, 4, 0), @@ -1003,6 +997,13 @@ static const NWidgetPart _nested_network_content_list_widgets[] = { EndContainer(), /* Right side. */ NWidget(NWID_VERTICAL), SetPIP(0, 4, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8), + /* Top */ + NWidget(WWT_EMPTY, COLOUR_LIGHT_BLUE, WID_NCL_FILTER_CAPT), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NCL_FILTER), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 3), SetResize(1, 0), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_DETAILS), SetResize(1, 1), SetFill(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), From 80bb1cb1494a165e7c1ee1f3d383c20e59bbe517 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 22 Mar 2014 01:38:28 +0200 Subject: [PATCH 095/187] Fixed AI dialog --- src/ai/ai_gui.cpp | 66 ++++++++++++++++++++++++----------------------- todo.txt | 4 +-- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index 1fec5ff746..ea67a280cc 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -658,39 +658,41 @@ static const NWidgetPart _nested_ai_config_widgets[] = { NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_MAUVE, WID_AIC_BACKGROUND), - NWidget(NWID_VERTICAL), SetPIP(4, 4, 4), - NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7), - NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_DECREASE), SetFill(0, 1), SetDataTip(AWV_DECREASE, STR_NULL), - NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_INCREASE), SetFill(0, 1), SetDataTip(AWV_INCREASE, STR_NULL), - NWidget(NWID_SPACER), SetMinimalSize(6, 0), - NWidget(WWT_TEXT, COLOUR_MAUVE, WID_AIC_NUMBER), SetDataTip(STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS, STR_NULL), SetFill(1, 0), SetPadding(1, 0, 0, 0), + NWidget(NWID_HORIZONTAL), SetPIP(7, 7, 7), + NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_AI, STR_NULL), SetPadding(0, 5, 0, 5), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_LIST), SetMinimalSize(288, 112), SetFill(1, 0), SetMatrixDataTip(1, 8, STR_AI_CONFIG_AILIST_TOOLTIP), SetScrollbar(WID_AIC_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_AIC_SCROLLBAR), + EndContainer(), EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_UP), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_UP, STR_AI_CONFIG_MOVE_UP_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_DOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_DOWN, STR_AI_CONFIG_MOVE_DOWN_TOOLTIP), + NWidget(NWID_VERTICAL), SetPIP(4, 4, 4), + NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7), + NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_DECREASE), SetFill(0, 1), SetDataTip(AWV_DECREASE, STR_NULL), + NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_INCREASE), SetFill(0, 1), SetDataTip(AWV_INCREASE, STR_NULL), + NWidget(NWID_SPACER), SetMinimalSize(6, 0), + NWidget(WWT_TEXT, COLOUR_MAUVE, WID_AIC_NUMBER), SetDataTip(STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS, STR_NULL), SetFill(1, 0), SetPadding(1, 0, 0, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_UP), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_UP, STR_AI_CONFIG_MOVE_UP_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_DOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_DOWN, STR_AI_CONFIG_MOVE_DOWN_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 9), + NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_GAMESCRIPT, STR_NULL), SetPadding(0, 5, 4, 5), + NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_GAMELIST), SetSizingType(NWST_STEP), SetMinimalSize(288, 14), SetFill(1, 0), SetMatrixDataTip(1, 1, STR_AI_CONFIG_GAMELIST_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CHANGE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_CONFIG_CHANGE, STR_AI_CONFIG_CHANGE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONFIGURE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_CONFIG_CONFIGURE, STR_AI_CONFIG_CONFIGURE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CLOSE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_SETTINGS_CLOSE, STR_NULL), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONTENT_DOWNLOAD), SetFill(1, 0), SetMinimalSize(279, 12), SetPadding(0, 7, 9, 7), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), EndContainer(), EndContainer(), - NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_AI, STR_NULL), SetPadding(0, 5, 0, 5), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_LIST), SetMinimalSize(288, 112), SetFill(1, 0), SetMatrixDataTip(1, 8, STR_AI_CONFIG_AILIST_TOOLTIP), SetScrollbar(WID_AIC_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_AIC_SCROLLBAR), - EndContainer(), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 9), - NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_GAMESCRIPT, STR_NULL), SetPadding(0, 5, 4, 5), - NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_GAMELIST), SetSizingType(NWST_STEP), SetMinimalSize(288, 14), SetFill(1, 0), SetMatrixDataTip(1, 1, STR_AI_CONFIG_GAMELIST_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CHANGE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_CONFIG_CHANGE, STR_AI_CONFIG_CHANGE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONFIGURE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_CONFIG_CONFIGURE, STR_AI_CONFIG_CONFIGURE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CLOSE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_SETTINGS_CLOSE, STR_NULL), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), - EndContainer(), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONTENT_DOWNLOAD), SetFill(1, 0), SetMinimalSize(279, 12), SetPadding(0, 7, 9, 7), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), EndContainer(), }; @@ -755,12 +757,12 @@ struct AIConfigWindow : public Window { { switch (widget) { case WID_AIC_GAMELIST: - this->line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); + this->line_height = GetMinSizing(NWST_STEP, _settings_client.gui.min_step + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); size->height = this->line_height; break; case WID_AIC_LIST: - this->line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); + this->line_height = GetMinSizing(NWST_STEP, _settings_client.gui.min_step + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); size->height = 8 * this->line_height; break; } diff --git a/todo.txt b/todo.txt index 885d13f3cb..7489554f25 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,5 @@ - Fix NewGRF dialog - Fix Advanced Settings dialog -- Fix Online Content dialog -- Fix AI dialog - Fix Multiplayer dialog +- Add Load button to Play Heightmap dialog +- Fix heightmaps not loading From 6bdb30fea581ac5ddcf5d20018be7baa600799c6 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 22 Mar 2014 01:44:41 +0200 Subject: [PATCH 096/187] Fix to file selector GUI --- src/fios_gui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index ced9e722d8..795a177575 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -355,14 +355,14 @@ public: case WID_SL_DRIVES_DIRECTORIES_LIST: { GfxFillRect(r.left + 1, r.top + 1, r.right, r.bottom, PC_BLACK); - uint y = r.top + WD_FRAMERECT_TOP + this->resize.step_height / 2; + uint y = r.top + WD_FRAMERECT_TOP; for (uint pos = this->vscroll->GetPosition(); pos < _fios_items.Length(); pos++) { const FiosItem *item = _fios_items.Get(pos); if (item == this->selected) { GfxFillRect(r.left + 1, y, r.right, y + this->resize.step_height, PC_DARK_BLUE); } - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, item->title, _fios_colours[item->type]); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y + this->resize.step_height / 2, item->title, _fios_colours[item->type]); y += this->resize.step_height; if (y >= this->vscroll->GetCapacity() * this->resize.step_height + r.top + WD_FRAMERECT_TOP) break; } From c6f20c52b89fdf5593ee786c7cf26963a069311f Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 22 Mar 2014 02:24:04 +0200 Subject: [PATCH 097/187] Fixed multiplayer join dialog --- src/network/network_gui.cpp | 7 ++----- todo.txt | 3 +-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index e324a58442..12597ec4b0 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -500,7 +500,7 @@ public: case WID_NG_MATRIX: resize->height = GetMinSizing(NWST_STEP, WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM); - size->height = 10 * resize->height; + size->height = 5 * resize->height; break; case WID_NG_LASTJOINED: @@ -539,7 +539,7 @@ public: break; case WID_NG_DETAILS_SPACER: - size->height = 20 + 12 * FONT_HEIGHT_NORMAL; + size->height = 20 + 10 * FONT_HEIGHT_NORMAL; break; } } @@ -934,9 +934,6 @@ static const NWidgetPart _nested_network_game_widgets[] = { NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CONNECTION), SetSizingType(NWST_STEP), SetDataTip(STR_NETWORK_SERVER_LIST_ADVERTISED, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NG_CONN_BTN), SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP), - NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_FILTER_LABEL), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_FILTER), SetMinimalSize(251, 12), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), diff --git a/todo.txt b/todo.txt index 7489554f25..c76a598ac9 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,4 @@ - Fix NewGRF dialog - Fix Advanced Settings dialog -- Fix Multiplayer dialog - Add Load button to Play Heightmap dialog -- Fix heightmaps not loading +- Fix heightmaps failing to load From 9f48f8fab621a603fe7f6da9c5abc6c21ec51b26 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 22 Mar 2014 02:32:54 +0200 Subject: [PATCH 098/187] Fixed file selector GUI once again --- src/fios_gui.cpp | 2 +- todo.txt | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 795a177575..1aa46c3a11 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -362,7 +362,7 @@ public: if (item == this->selected) { GfxFillRect(r.left + 1, y, r.right, y + this->resize.step_height, PC_DARK_BLUE); } - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y + this->resize.step_height / 2, item->title, _fios_colours[item->type]); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(y, this->resize.step_height), item->title, _fios_colours[item->type]); y += this->resize.step_height; if (y >= this->vscroll->GetCapacity() * this->resize.step_height + r.top + WD_FRAMERECT_TOP) break; } diff --git a/todo.txt b/todo.txt index c76a598ac9..ae711782eb 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,2 @@ - Fix NewGRF dialog -- Fix Advanced Settings dialog - Add Load button to Play Heightmap dialog -- Fix heightmaps failing to load From ea4e46dda45de340ec8d01d0fe88c0dd13ce3e1a Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 22 Mar 2014 02:55:47 +0200 Subject: [PATCH 099/187] Fixed NewGRF GUI --- src/newgrf_gui.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index a46aa79b26..887d53bf4b 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -211,7 +211,7 @@ struct NewGRFParametersWindow : public Window { } case WID_NP_BACKGROUND: - this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + this->line_height = _settings_client.gui.min_step + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; resize->width = 1; resize->height = this->line_height; @@ -299,7 +299,7 @@ struct NewGRFParametersWindow : public Window { SetDParam(1, i + 1); } - DrawString(text_left, text_right, y + WD_MATRIX_TOP, STR_NEWGRF_PARAMETERS_SETTING, selected ? TC_WHITE : TC_LIGHT_BLUE); + DrawString(text_left, text_right, Center(y + WD_MATRIX_TOP, this->line_height), STR_NEWGRF_PARAMETERS_SETTING, selected ? TC_WHITE : TC_LIGHT_BLUE); y += this->line_height; } } @@ -1566,8 +1566,8 @@ public: uint min_inf_height = this->inf->smallest_y + this->inf->padding_top + this->inf->padding_bottom; /* Smallest window is in two column mode. */ - this->smallest_x = max(min_avs_width, min_acs_width) + INTER_COLUMN_SPACING + min_inf_width; - this->smallest_y = max(min_inf_height, min_acs_height + INTER_LIST_SPACING + min_avs_height); + this->smallest_x = min_avs_width + min_acs_width + min_inf_width + INTER_COLUMN_SPACING * 2; + this->smallest_y = max(max(min_inf_height, min_acs_height), min_avs_height); /* Filling. */ this->fill_x = LeastCommonMultiple(this->avs->fill_x, this->acs->fill_x); @@ -1605,6 +1605,9 @@ public: uint min_three_columns = min_avs_width + min_acs_width + min_inf_width + 2 * INTER_COLUMN_SPACING; uint min_two_columns = min_list_width + min_inf_width + INTER_COLUMN_SPACING; bool use_three_columns = this->editable && (min_three_columns + MIN_EXTRA_FOR_3_COLUMNS <= given_width); +#ifdef __ANDROID__ + use_three_columns = true; +#endif /* Info panel is a separate column in both modes. Compute its width first. */ uint extra_width, inf_width; From 5b75bcffbf076fdcf616500531f6b0e84d4c1e2a Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 22 Mar 2014 03:10:48 +0200 Subject: [PATCH 100/187] Updated TODO --- todo.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/todo.txt b/todo.txt index ae711782eb..36c93f49af 100644 --- a/todo.txt +++ b/todo.txt @@ -1,2 +1 @@ -- Fix NewGRF dialog - Add Load button to Play Heightmap dialog From c7ed03ded90a8d329d8cd9433e61bea3a46d668a Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 22 Mar 2014 23:28:07 +0200 Subject: [PATCH 101/187] Lowmem version of OpenTTD - copy savegames from regular OpenTTD on start --- src/fileio.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/fileio.cpp b/src/fileio.cpp index f88d8deeaf..5eff63027a 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -1304,6 +1304,18 @@ void DeterminePaths(const char *exe) _searchpaths[SP_AUTODOWNLOAD_DIR] = NULL; } #endif /* ENABLE_NETWORK */ + +#ifdef __ANDROID__ + // Copy savegames from "full" OpenTTD to "lite" save directory + char curdir[PATH_MAX]; + if (getcwd(curdir, sizeof(BUF)) && strstr(curdir, "org.openttd.sdl.lowmem")) { + // No, I won't implement file copying in C, shell script is just fine for this job + system("cd ../../org.openttd.sdl/files/.openttd/save && " + "for F in *.sav ; do ls \"../../../../org.openttd.sdl/files/.openttd/save/$F\" || " + "cat \"$F\" > \"../../../../org.openttd.sdl/files/.openttd/save/$F\" ; done"); + chdir(curdir); + } +#endif } /** From 4773b09d13d9ac19f24c5e22d78e4bd901c249fd Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 22 Mar 2014 23:33:05 +0200 Subject: [PATCH 102/187] Oops, fixerd compilation --- src/fileio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 5eff63027a..cb750b614b 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -1308,7 +1308,7 @@ void DeterminePaths(const char *exe) #ifdef __ANDROID__ // Copy savegames from "full" OpenTTD to "lite" save directory char curdir[PATH_MAX]; - if (getcwd(curdir, sizeof(BUF)) && strstr(curdir, "org.openttd.sdl.lowmem")) { + if (getcwd(curdir, sizeof(curdir)) && strstr(curdir, "org.openttd.sdl.lowmem")) { // No, I won't implement file copying in C, shell script is just fine for this job system("cd ../../org.openttd.sdl/files/.openttd/save && " "for F in *.sav ; do ls \"../../../../org.openttd.sdl/files/.openttd/save/$F\" || " From f4612e40316f9fffd551ec055acc5ac560659bef Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 22 Mar 2014 23:51:45 +0200 Subject: [PATCH 103/187] Oops x2 - I've copied stuff to the wrong directory --- src/fileio.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index cb750b614b..707eae5c56 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -1310,9 +1310,12 @@ void DeterminePaths(const char *exe) char curdir[PATH_MAX]; if (getcwd(curdir, sizeof(curdir)) && strstr(curdir, "org.openttd.sdl.lowmem")) { // No, I won't implement file copying in C, shell script is just fine for this job + DEBUG(misc, 1, "Copying savegames from ../../org.openttd.sdl/files/.openttd/save to %s", curdir); system("cd ../../org.openttd.sdl/files/.openttd/save && " - "for F in *.sav ; do ls \"../../../../org.openttd.sdl/files/.openttd/save/$F\" || " - "cat \"$F\" > \"../../../../org.openttd.sdl/files/.openttd/save/$F\" ; done"); + "for F in *.sav ; do " + "ls \"../../../../org.openttd.sdl.lowmem/files/.openttd/save/$F\" || " + "cat \"$F\" > \"../../../../org.openttd.sdl.lowmem/files/.openttd/save/$F\" ; " + "done"); chdir(curdir); } #endif From 253ccf43e884a9cf0997dda711fdd8c8b24218a9 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 23 Mar 2014 14:33:43 +0200 Subject: [PATCH 104/187] Fixed broken Ctrl and Shift toolbar buttons --- src/toolbar_gui.cpp | 13 ++++++++++++- src/video/sdl_v.cpp | 2 ++ todo.txt | 4 ++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 5771ae6a11..2827e6c4d5 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1165,24 +1165,35 @@ static CallBackFunction ToolbarSwitchClick(Window *w) static CallBackFunction ToolbarCtrlClick(Window *w) { _ctrl_pressed = !_ctrl_pressed; + //DEBUG(misc, 1, "ToolbarCtrlClick: pressed %d", _ctrl_pressed); w->SetWidgetLoweredState(WID_TN_CTRL, _ctrl_pressed); - HandleCtrlChanged(); w->SetWidgetDirty(WID_TN_CTRL); + HandleCtrlChanged(); EraseQueuedTouchCommand(); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } static CallBackFunction ToolbarShiftClick(Window *w) { _shift_pressed = !_shift_pressed; + //DEBUG(misc, 1, "ToolbarShiftClick: pressed %d", _shift_pressed); w->SetWidgetLoweredState(WID_TN_SHIFT, _shift_pressed); w->SetWidgetDirty(WID_TN_SHIFT); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } static CallBackFunction ToolbarDeleteClick(Window *w) { DeleteNonVitalWindows(); + _ctrl_pressed = false; + w->SetWidgetLoweredState(WID_TN_CTRL, _ctrl_pressed); + w->SetWidgetDirty(WID_TN_CTRL); + _shift_pressed = false; + w->SetWidgetLoweredState(WID_TN_SHIFT, _shift_pressed); + w->SetWidgetDirty(WID_TN_SHIFT); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index d49f80ee50..64ce2911be 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -761,10 +761,12 @@ void VideoDriver_SDL::MainLoop() bool old_ctrl_pressed = _ctrl_pressed; +#ifndef __ANDROID__ if (_settings_client.gui.touchscreen_mode == TSC_NONE) { _ctrl_pressed = !!(mod & KMOD_CTRL); _shift_pressed = !!(mod & KMOD_SHIFT); } +#endif /* determine which directional keys are down */ _dirkeys = diff --git a/todo.txt b/todo.txt index 36c93f49af..2b4e64e5d0 100644 --- a/todo.txt +++ b/todo.txt @@ -1 +1,5 @@ +- Resize Aircraft window +- Resize Ship window +- Resize Music Program Selection window +- Resize all buttons and fonts when screen resolution changes - Add Load button to Play Heightmap dialog From 386261656dbfdfb9de9507cab8960dac072777ee Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 23 Mar 2014 15:37:10 +0200 Subject: [PATCH 105/187] Fixed scrollbar slider when the scrollbar is too small --- src/widget.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/widget.cpp b/src/widget.cpp index 5905d1c77e..dda9491198 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -48,8 +48,11 @@ static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom, bo } top += button_size; // top points to just below the up-button bottom -= button_size; // bottom points to top of the down-button - if (bottom > top + button_size) + bool wide_enough = false; + if (bottom > top + button_size * 2) { bottom -= button_size; // Slider should be no smaller than a regular button, reserve some size from bottom + wide_enough = true; + } int height = (bottom - top); int pos = sb->GetPosition(); @@ -59,7 +62,8 @@ static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom, bo if (count != 0) top += height * pos / count; if (cap > count) cap = count; - if (count != 0) bottom -= (count - pos - cap) * height / count - button_size; + if (count != 0) bottom -= (count - pos - cap) * height / count; + if (wide_enough) bottom += button_size; Point pt; if (horizontal && _current_text_dir == TD_RTL) { @@ -121,9 +125,9 @@ static void ScrollbarClickPositioning(Window *w, NWidgetScrollbar *sb, int x, in sb->UpdatePosition(rtl ? -1 : 1, Scrollbar::SS_BIG); } else { _scrollbar_start_pos = pt.x - mi - button_size; - _scrollbar_size = ma - mi - button_size * 3; - if (_scrollbar_size <= 0) - _scrollbar_size = 1; + _scrollbar_size = ma - mi - button_size * 2; + if (_scrollbar_size > button_size * 2) + _scrollbar_size -= button_size; w->scrolling_scrollbar = sb->index; _cursorpos_drag_start = _cursor.pos; } From 982c84b3eed91cd70b3e0db1f75348ceacf2d986 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 23 Mar 2014 15:39:18 +0200 Subject: [PATCH 106/187] Removed unused variable --- src/settings_type.h | 1 - src/table/misc_settings.ini | 5 ---- src/vehicle_gui.cpp | 4 ++-- src/window.cpp | 46 ------------------------------------- 4 files changed, 2 insertions(+), 54 deletions(-) diff --git a/src/settings_type.h b/src/settings_type.h index cb9d95bb0f..b38aab3781 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -81,7 +81,6 @@ struct GUISettings { TouchscreenModeByte touchscreen_mode; ///< touchscreen mode for toolbars uint min_button; ///< min size of most button widgets uint min_step; ///< min size of scrollbar/dropdown elements - bool manage_min_sizing; ///< automatically set min_button and min_step bool show_finances; ///< show finances at end of year bool sg_new_nonstop; ///< ttdpatch compatible nonstop handling read from pre v93 savegames bool new_nonstop; ///< ttdpatch compatible nonstop handling diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini index fd0207c4f3..0b02e69b8d 100644 --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -228,11 +228,6 @@ min = 0 max = 100 cat = SC_EXPERT -[SDTG_BOOL] -name = ""manage_min_sizing"" -var = _settings_client.gui.manage_min_sizing -def = false - [SDTG_VAR] name = ""min_step_size"" type = SLE_UINT diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 387976596e..537c0a3e7f 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -1474,11 +1474,11 @@ public: switch (this->vli.vtype) { case VEH_TRAIN: case VEH_ROAD: - size->height = 6 * resize->height; + size->height = 7 * resize->height; break; case VEH_SHIP: case VEH_AIRCRAFT: - size->height = 4 * resize->height; + size->height = 3 * resize->height; break; default: NOT_REACHED(); } diff --git a/src/window.cpp b/src/window.cpp index 715c8ca2cd..8dc3c400a7 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1818,57 +1818,11 @@ int SETTING_BUTTON_HEIGHT = 10; */ void CheckWindowMinSizings() { - if (_settings_client.gui.manage_min_sizing) { - /* Fill the min sizing values for the current resolution. */ - uint swap_x = 32; // in longest border, let main toolbar to have 30 buttons. - uint swap_y = 16; // if short border, let main toolbar have 16/18/20 buttons..) - if (_cur_resolution.width < _cur_resolution.height) Swap(swap_x, swap_y); - _settings_client.gui.min_button = min(_cur_resolution.width / swap_x, _cur_resolution.height / swap_y); - _settings_client.gui.min_step = _settings_client.gui.min_button * 3 / 4; - } - SETTING_BUTTON_HEIGHT = max(GetMinSizing(NWST_STEP) - 10, 10); SETTING_BUTTON_WIDTH = 2 * SETTING_BUTTON_HEIGHT; extern uint _tooltip_width; _tooltip_width = max(194, 10 * _settings_client.gui.min_button); - - if (!_settings_client.gui.manage_min_sizing) return; - - _freetype.large.size = _settings_client.gui.min_button; - _freetype.medium.size = max(_settings_client.gui.min_step * 2 / 3, 10U); - _freetype.mono.size = _freetype.medium.size; - _freetype.small.size = max(_freetype.medium.size * 2 / 3, 8U); - - InitFreeType(true); - CheckForMissingGlyphs(); - - if (_z_front_window == NULL) return; - - DeleteAllNonVitalWindows(); - - switch (_game_mode) { - default: break; - case GM_MENU: - DeleteWindowById(WC_SELECT_GAME, 0); - extern void ShowSelectGameWindow(); - ShowSelectGameWindow(); - break; - - case GM_NORMAL: - case GM_EDITOR: { - Station *st; - FOR_ALL_STATIONS(st) { st->UpdateVirtCoord(); } - Waypoint *wp; - FOR_ALL_WAYPOINTS(wp) { wp->UpdateVirtCoord(); } - - HideVitalWindows(); - ShowVitalWindows(); - break; - } - } - - ShowErrorMessage(STR_ERROR_RESET_WINDOWS, STR_ERROR_AUTOMATIC_SIZING, WL_WARNING); } /** From 313e3b73b3acec1dcf1553f52b90bcfa592e804e Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 23 Mar 2014 17:19:30 +0200 Subject: [PATCH 107/187] Auto-resize all buttons and fonts, when screen resoluition changes --- src/ai/ai_gui.cpp | 4 ++-- src/fontcache.cpp | 2 +- src/gfx_func.h | 11 +++++++++++ src/network/network_content_gui.cpp | 2 +- src/newgrf_gui.cpp | 2 +- src/settings_gui.cpp | 24 ++++++++++++++++++++++++ src/widget.cpp | 2 ++ src/window.cpp | 2 +- 8 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index ea67a280cc..d75324a5d3 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -757,12 +757,12 @@ struct AIConfigWindow : public Window { { switch (widget) { case WID_AIC_GAMELIST: - this->line_height = GetMinSizing(NWST_STEP, _settings_client.gui.min_step + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); + this->line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); size->height = this->line_height; break; case WID_AIC_LIST: - this->line_height = GetMinSizing(NWST_STEP, _settings_client.gui.min_step + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); + this->line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); size->height = 8 * this->line_height; break; } diff --git a/src/fontcache.cpp b/src/fontcache.cpp index 4d369ad51f..975643cca5 100644 --- a/src/fontcache.cpp +++ b/src/fontcache.cpp @@ -374,7 +374,7 @@ static void LoadFreeTypeFont(FontSize fs) return; found_face: - new FreeTypeFontCache(fs, face, settings->size); + new FreeTypeFontCache(fs, face, RescaleFrom854x480(settings->size)); } diff --git a/src/gfx_func.h b/src/gfx_func.h index 211fb97d04..eff0930b16 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -45,6 +45,7 @@ #include "gfx_type.h" #include "strings_type.h" #include "string_type.h" +#include "core/math_func.hpp" void GameLoop(); @@ -196,6 +197,16 @@ static inline int Center(int top, int height, uint size = FONT_HEIGHT_NORMAL) return top + (height - size) / 2; } +/** + * Returns fint/button size, rescaled to current screen resolution from the base Android resolution, which is 854x480 + * @param value The value to rescale + * @return Rescaled value, using lesser of the curret screen coordinates + */ +static inline int RescaleFrom854x480(int value) +{ + return min(value * _cur_resolution.width / 854, value * _cur_resolution.height / 480); +} + extern DrawPixelInfo *_cur_dpi; TextColour GetContrastColour(uint8 background); diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index 31783f99a5..77ab4cfa5d 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -525,7 +525,7 @@ public: } case WID_NCL_MATRIX: - resize->height = GetMinSizing(NWST_STEP, _settings_client.gui.min_step + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); + resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); size->height = 6 * resize->height; break; } diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 887d53bf4b..4d42754502 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -211,7 +211,7 @@ struct NewGRFParametersWindow : public Window { } case WID_NP_BACKGROUND: - this->line_height = _settings_client.gui.min_step + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; resize->width = 1; resize->height = this->line_height; diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 841060556d..ed1caf81c6 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -37,6 +37,7 @@ #include "textfile_gui.h" #include "stringfilter_type.h" #include "querystring_gui.h" +#include "fontcache.h" static const StringID _driveside_dropdown[] = { @@ -506,6 +507,29 @@ struct GameOptionsWindow : Window { case WID_GO_RESOLUTION_DROPDOWN: // Change resolution if (index < _num_resolutions && ChangeResInGame(_resolutions[index].width, _resolutions[index].height)) { + // Reinit all GUI elements and fonts, so they will rescale + InitFreeType(true); + CheckForMissingGlyphs(); + + DeleteAllNonVitalWindows(); + + switch (_game_mode) { + case GM_MENU: + DeleteWindowById(WC_SELECT_GAME, 0); + extern void ShowSelectGameWindow(); + ShowSelectGameWindow(); + break; + + case GM_NORMAL: + case GM_EDITOR: + HideVitalWindows(); + ShowVitalWindows(); + break; + + default: + break; + } + this->SetDirty(); } break; diff --git a/src/widget.cpp b/src/widget.cpp index dda9491198..7a939abb06 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -784,6 +784,7 @@ void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y) break; default: NOT_REACHED(); } + min_size = RescaleFrom854x480(min_size); this->min_x = max(min_x, min_size); this->min_y = max(min_y, min_size); @@ -2942,6 +2943,7 @@ uint GetMinSizing(NWidSizingType type, uint min_1) break; default: NOT_REACHED(); } + min_sizing = RescaleFrom854x480(min_sizing); return max(min_sizing, min_1); } diff --git a/src/window.cpp b/src/window.cpp index 8dc3c400a7..b9041801be 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1822,7 +1822,7 @@ void CheckWindowMinSizings() SETTING_BUTTON_WIDTH = 2 * SETTING_BUTTON_HEIGHT; extern uint _tooltip_width; - _tooltip_width = max(194, 10 * _settings_client.gui.min_button); + _tooltip_width = max(194, 10 * RescaleFrom854x480(_settings_client.gui.min_button)); } /** From 61e8275ebfe9b9ffbf8e4c8493e7797728493455 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 23 Mar 2014 18:47:49 +0200 Subject: [PATCH 108/187] Fixed vehicle and music dialog size --- src/build_vehicle_gui.cpp | 8 +++----- src/group_gui.cpp | 4 ++-- src/music_gui.cpp | 2 +- src/vehicle_gui.cpp | 4 ++-- todo.txt | 4 ---- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 1816e28f3f..95d20e7515 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -57,15 +57,13 @@ static const NWidgetPart _nested_build_vehicle_widgets[] = { NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_VERTICAL), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASSENDING_DESCENDING), SetSizingType(NWST_STEP), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), - NWidget(NWID_SPACER), SetFill(1, 1), - EndContainer(), - NWidget(NWID_VERTICAL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN), SetSizingType(NWST_STEP), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetSizingType(NWST_STEP), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), EndContainer(), + NWidget(NWID_SPACER), SetFill(1, 1), EndContainer(), EndContainer(), /* Vehicle list. */ diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 6889d6eb16..551697d601 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -342,7 +342,7 @@ public: resize->height = this->tiny_step_height; /* Minimum height is the height of the list widget minus all and default vehicles... */ - size->height = 4 * GetVehicleListHeight(this->vli.vtype, this->tiny_step_height) - 2 * this->tiny_step_height; + size->height = (this->vli.vtype >= VEH_SHIP ? 3 : 6) * GetVehicleListHeight(this->vli.vtype, this->tiny_step_height) - 2 * this->tiny_step_height; /* Get a multiple of tiny_step_height of that amount */ size->height = Ceil(size->height, tiny_step_height); @@ -366,7 +366,7 @@ public: case WID_GL_LIST_VEHICLE: this->ComputeGroupInfoSize(); resize->height = GetVehicleListHeight(this->vli.vtype, this->tiny_step_height); - size->height = 4 * resize->height; + size->height = (this->vli.vtype >= VEH_SHIP ? 3 : 6) * resize->height; break; case WID_GL_MANAGE_VEHICLES_DROPDOWN: { diff --git a/src/music_gui.cpp b/src/music_gui.cpp index 26910e952b..cf48cf2193 100644 --- a/src/music_gui.cpp +++ b/src/music_gui.cpp @@ -374,7 +374,7 @@ struct MusicTrackSelectionWindow : public Window { } resize->height = GetMinSizing(NWST_STEP, d.height); d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - d.height = 10 * resize->height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + d.height = 7 * resize->height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); break; } diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 537c0a3e7f..0fdc623301 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -649,7 +649,7 @@ struct RefitWindow : public Window { switch (widget) { case WID_VR_MATRIX: resize->height = GetMinSizing(NWST_STEP, WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM); - size->height = resize->height * 8; + size->height = resize->height * 6; break; case WID_VR_VEHICLE_PANEL_DISPLAY: @@ -1474,7 +1474,7 @@ public: switch (this->vli.vtype) { case VEH_TRAIN: case VEH_ROAD: - size->height = 7 * resize->height; + size->height = 6 * resize->height; break; case VEH_SHIP: case VEH_AIRCRAFT: diff --git a/todo.txt b/todo.txt index 2b4e64e5d0..36c93f49af 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1 @@ -- Resize Aircraft window -- Resize Ship window -- Resize Music Program Selection window -- Resize all buttons and fonts when screen resolution changes - Add Load button to Play Heightmap dialog From f30d497cc15fa750949fabfccc94d5b14fcf1a5a Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 2 Apr 2014 22:57:38 +0300 Subject: [PATCH 109/187] Modified 'release' bit in sources, and added a patch for future references --- release.patch | 13 +++++++++++++ src/rev.cpp.in | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 release.patch diff --git a/release.patch b/release.patch new file mode 100644 index 0000000000..aaecde1e88 --- /dev/null +++ b/release.patch @@ -0,0 +1,13 @@ +diff --git a/src/rev.cpp.in b/src/rev.cpp.in +index 506e641..3300664 100644 +--- a/src/rev.cpp.in ++++ b/src/rev.cpp.in +@@ -70,7 +70,7 @@ const byte _openttd_revision_modified = !!MODIFIED!!; + * final release will always have a lower version number than the released + * version, thus making comparisons on specific revisions easy. + */ +-const uint32 _openttd_newgrf_version = 1 << 28 | 5 << 24 | 0 << 20 | 0 << 19 | (!!REVISION!! & ((1 << 19) - 1)); ++const uint32 _openttd_newgrf_version = 1 << 28 | 5 << 24 | 0 << 20 | 1 << 19 | (!!REVISION!! & ((1 << 19) - 1)); + + #ifdef __MORPHOS__ + /** diff --git a/src/rev.cpp.in b/src/rev.cpp.in index 506e641d73..330066464a 100644 --- a/src/rev.cpp.in +++ b/src/rev.cpp.in @@ -70,7 +70,7 @@ const byte _openttd_revision_modified = !!MODIFIED!!; * final release will always have a lower version number than the released * version, thus making comparisons on specific revisions easy. */ -const uint32 _openttd_newgrf_version = 1 << 28 | 5 << 24 | 0 << 20 | 0 << 19 | (!!REVISION!! & ((1 << 19) - 1)); +const uint32 _openttd_newgrf_version = 1 << 28 | 5 << 24 | 0 << 20 | 1 << 19 | (!!REVISION!! & ((1 << 19) - 1)); #ifdef __MORPHOS__ /** From 15b9ab4c088e0a2ec859f93ba4aa79ad77fa2b72 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 6 Apr 2014 18:17:19 +0300 Subject: [PATCH 110/187] Override version number, so Andorid OpenTTD can connect to official servers --- findversion.sh | 6 ++++++ version-override | 1 + 2 files changed, 7 insertions(+) create mode 100644 version-override diff --git a/findversion.sh b/findversion.sh index 6f11113e64..9d8a5ae5a1 100755 --- a/findversion.sh +++ b/findversion.sh @@ -58,6 +58,12 @@ EOF exit 1; fi +# Override version number, to allow OpenTTD with Android modifications to connect to official servers +if [ -e version-override ]; then + cat version-override + exit +fi + # Allow awk to be provided by the caller. if [ -z "$AWK" ]; then AWK=awk diff --git a/version-override b/version-override new file mode 100644 index 0000000000..f31dc5e020 --- /dev/null +++ b/version-override @@ -0,0 +1 @@ +1.4.0 26440 0 1.4.0 From 1daf79985a706432ea7da40ec5733f80450bf8d2 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 6 Apr 2014 22:40:18 +0300 Subject: [PATCH 111/187] Resized in-game NewGRF dialog, with lots of hacks --- src/newgrf_gui.cpp | 131 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 104 insertions(+), 27 deletions(-) diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 4d42754502..5aa3211aed 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -211,7 +211,7 @@ struct NewGRFParametersWindow : public Window { } case WID_NP_BACKGROUND: - this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + this->line_height = _settings_client.gui.min_step + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; resize->width = 1; resize->height = this->line_height; @@ -636,10 +636,9 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_NS_SCROLLBAR); - this->vscroll2 = this->GetScrollbar(WID_NS_SCROLL2BAR); + this->vscroll2 = this->editable ? this->GetScrollbar(WID_NS_SCROLL2BAR) : NULL; this->GetWidget(WID_NS_SHOW_REMOVE)->SetDisplayedPlane(this->editable ? 0 : 1); - this->GetWidget(WID_NS_SHOW_APPLY)->SetDisplayedPlane(this->editable ? 0 : this->show_params ? 1 : SZSP_HORIZONTAL); this->FinishInitNested(WN_GAME_OPTIONS_NEWGRF_STATE); this->querystrings[WID_NS_FILTER] = &this->filter_editbox; @@ -731,7 +730,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_NS_FILE_LIST); - this->vscroll2->SetCapacityFromWidget(this, WID_NS_AVAIL_LIST); + if (this->vscroll2) this->vscroll2->SetCapacityFromWidget(this, WID_NS_AVAIL_LIST); } virtual void SetStringParameters(int widget) const @@ -1232,8 +1231,10 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { widget_data = STR_INTRO_ONLINE_CONTENT; tool_tip = STR_INTRO_TOOLTIP_ONLINE_CONTENT; } - this->GetWidget(WID_NS_CONTENT_DOWNLOAD)->widget_data = widget_data; - this->GetWidget(WID_NS_CONTENT_DOWNLOAD)->tool_tip = tool_tip; + if (this->editable) { + this->GetWidget(WID_NS_CONTENT_DOWNLOAD)->widget_data = widget_data; + this->GetWidget(WID_NS_CONTENT_DOWNLOAD)->tool_tip = tool_tip; + } this->GetWidget(WID_NS_CONTENT_DOWNLOAD2)->widget_data = widget_data; this->GetWidget(WID_NS_CONTENT_DOWNLOAD2)->tool_tip = tool_tip; @@ -1431,7 +1432,7 @@ private: if (this->avail_pos < 0) this->avail_sel = NULL; } - this->vscroll2->SetCount(this->avails.Length()); // Update the scrollbar + if (this->vscroll2) this->vscroll2->SetCount(this->avails.Length()); // Update the scrollbar } /** @@ -1604,10 +1605,7 @@ public: /* Use 2 or 3 columns? */ uint min_three_columns = min_avs_width + min_acs_width + min_inf_width + 2 * INTER_COLUMN_SPACING; uint min_two_columns = min_list_width + min_inf_width + INTER_COLUMN_SPACING; - bool use_three_columns = this->editable && (min_three_columns + MIN_EXTRA_FOR_3_COLUMNS <= given_width); -#ifdef __ANDROID__ - use_three_columns = true; -#endif + bool use_three_columns = true; // this->editable; /* Info panel is a separate column in both modes. Compute its width first. */ uint extra_width, inf_width; @@ -1715,7 +1713,7 @@ public: { if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; - NWidgetCore *nw = (this->editable) ? this->avs->GetWidgetFromPos(x, y) : NULL; + NWidgetCore *nw = this->avs->GetWidgetFromPos(x, y); if (nw == NULL) nw = this->acs->GetWidgetFromPos(x, y); if (nw == NULL) nw = this->inf->GetWidgetFromPos(x, y); return nw; @@ -1723,7 +1721,7 @@ public: virtual void Draw(const Window *w) { - if (this->editable) this->avs->Draw(w); + this->avs->Draw(w); this->acs->Draw(w); this->inf->Draw(w); } @@ -1837,33 +1835,111 @@ static const NWidgetPart _nested_newgrf_infopanel_widgets[] = { SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), EndContainer(), EndContainer(), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NS_SHOW_APPLY), - /* Right side, buttons. */ - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, WD_RESIZEBOX_WIDTH, 0), - NWidget(NWID_VERTICAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_SET_PARAMETERS), SetFill(1, 0), SetResize(1, 0), - SetDataTip(STR_NEWGRF_SETTINGS_SET_PARAMETERS, STR_NULL), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_TOGGLE_PALETTE), SetFill(1, 0), SetResize(1, 0), - SetDataTip(STR_NEWGRF_SETTINGS_TOGGLE_PALETTE, STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP), - EndContainer(), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_APPLY_CHANGES), SetFill(1, 0), SetResize(1, 0), - SetDataTip(STR_NEWGRF_SETTINGS_APPLY_CHANGES, STR_NULL), + /* Right side, buttons. */ + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, WD_RESIZEBOX_WIDTH, 0), + NWidget(NWID_VERTICAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_SET_PARAMETERS), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_NEWGRF_SETTINGS_SET_PARAMETERS, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_TOGGLE_PALETTE), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_NEWGRF_SETTINGS_TOGGLE_PALETTE, STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_APPLY_CHANGES), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_NEWGRF_SETTINGS_APPLY_CHANGES, STR_NULL), + EndContainer(), +}; + +static const NWidgetPart _nested_newgrf_actives_wide_widgets[] = { + /* Left side, presets. */ + NWidget(NWID_VERTICAL), + NWidget(WWT_LABEL, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_ACTIVE_LIST, STR_NULL), + SetFill(1, 0), SetResize(1, 0), SetPadding(3, WD_FRAMETEXT_RIGHT, 0, WD_FRAMETEXT_LEFT), + /* Left side, active grfs. */ + NWidget(NWID_HORIZONTAL), SetPadding(0, 2, 0, 2), + NWidget(WWT_PANEL, COLOUR_MAUVE), + NWidget(WWT_INSET, COLOUR_MAUVE, WID_NS_FILE_LIST), SetMinimalSize(100, 1), SetPadding(2, 2, 2, 2), + SetFill(1, 1), SetResize(1, 1), SetScrollbar(WID_NS_SCROLLBAR), SetDataTip(STR_NULL, STR_NEWGRF_SETTINGS_FILE_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_NS_SCROLLBAR), + EndContainer(), + EndContainer(), +}; + +static const NWidgetPart _nested_newgrf_buttons_wide_widgets[] = { + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_SELECT_PRESET, STR_NULL), + SetPadding(0, WD_FRAMETEXT_RIGHT, 0, 0), + NWidget(WWT_DROPDOWN, COLOUR_YELLOW, WID_NS_PRESET_LIST), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_JUST_STRING, STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_PRESET_SAVE), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_NEWGRF_SETTINGS_PRESET_SAVE, STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_PRESET_DELETE), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_NEWGRF_SETTINGS_PRESET_DELETE, STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP), + EndContainer(), + + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NS_SHOW_REMOVE), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPadding(0, 2, 0, 2), SetPIP(0, WD_RESIZEBOX_WIDTH, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_REMOVE), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_NEWGRF_SETTINGS_REMOVE, STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP), + NWidget(NWID_VERTICAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_MOVE_UP), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_NEWGRF_SETTINGS_MOVEUP, STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_MOVE_DOWN), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_NEWGRF_SETTINGS_MOVEDOWN, STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPadding(0, 0, 0, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_RESCAN_FILES2), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_NEWGRF_SETTINGS_RESCAN_FILES, STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_CONTENT_DOWNLOAD2), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), + EndContainer(), + EndContainer(), + + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_OPEN_URL), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_NEWGRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_NEWGRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_NEWGRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_VIEW_PARAMETERS), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_SHOW_PARAMETERS, STR_NULL), EndContainer(), }; +static const NWidgetPart _nested_newgrf_infopanel_wide_widgets[] = { + /* Right side, info panel. */ + NWidget(WWT_PANEL, COLOUR_MAUVE), + NWidget(WWT_EMPTY, COLOUR_MAUVE, WID_NS_NEWGRF_INFO_TITLE), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_EMPTY, COLOUR_MAUVE, WID_NS_NEWGRF_INFO), SetFill(1, 1), SetResize(1, 1), SetMinimalSize(100, 100), + EndContainer(), +}; + /** Construct nested container widget for managing the lists and the info panel of the NewGRF GUI. */ +static bool _newgrf_display_editable = false; // Quick hack NWidgetBase* NewGRFDisplay(int *biggest_index) { - NWidgetBase *avs = MakeNWidgets(_nested_newgrf_availables_widgets, lengthof(_nested_newgrf_availables_widgets), biggest_index, NULL); + NWidgetBase *avs = _newgrf_display_editable ? + MakeNWidgets(_nested_newgrf_availables_widgets, lengthof(_nested_newgrf_availables_widgets), biggest_index, NULL) : + MakeNWidgets(_nested_newgrf_actives_wide_widgets, lengthof(_nested_newgrf_actives_wide_widgets), biggest_index, NULL); int biggest2; - NWidgetBase *acs = MakeNWidgets(_nested_newgrf_actives_widgets, lengthof(_nested_newgrf_actives_widgets), &biggest2, NULL); + NWidgetBase *acs = _newgrf_display_editable ? + MakeNWidgets(_nested_newgrf_actives_widgets, lengthof(_nested_newgrf_actives_widgets), &biggest2, NULL) : + MakeNWidgets(_nested_newgrf_buttons_wide_widgets, lengthof(_nested_newgrf_buttons_wide_widgets), &biggest2, NULL); *biggest_index = max(*biggest_index, biggest2); - NWidgetBase *inf = MakeNWidgets(_nested_newgrf_infopanel_widgets, lengthof(_nested_newgrf_infopanel_widgets), &biggest2, NULL); + NWidgetBase *inf = _newgrf_display_editable ? + MakeNWidgets(_nested_newgrf_infopanel_widgets, lengthof(_nested_newgrf_infopanel_widgets), &biggest2, NULL) : + MakeNWidgets(_nested_newgrf_infopanel_wide_widgets, lengthof(_nested_newgrf_infopanel_wide_widgets), &biggest2, NULL); *biggest_index = max(*biggest_index, biggest2); return new NWidgetNewGRFDisplay(avs, acs, inf); @@ -1940,6 +2016,7 @@ static void NewGRFConfirmationCallback(Window *w, bool confirmed) void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config) { DeleteWindowByClass(WC_GAME_OPTIONS); + _newgrf_display_editable = editable; new NewGRFWindow(&_newgrf_desc, editable, show_params, exec_changes, config); } From 589aad0990fa6ed7d3343c1e167f044020881ece Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 6 Apr 2014 22:58:59 +0300 Subject: [PATCH 112/187] More fixes to version string to match official release. Why did they made it so complicated? --- findversion.sh | 12 ++++++------ src/rev.cpp.in | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/findversion.sh b/findversion.sh index 9d8a5ae5a1..5c0da20382 100755 --- a/findversion.sh +++ b/findversion.sh @@ -58,12 +58,6 @@ EOF exit 1; fi -# Override version number, to allow OpenTTD with Android modifications to connect to official servers -if [ -e version-override ]; then - cat version-override - exit -fi - # Allow awk to be provided by the caller. if [ -z "$AWK" ]; then AWK=awk @@ -73,6 +67,12 @@ fi cd `dirname "$0"` ROOT_DIR=`pwd` +# Override version number, to allow OpenTTD with Android modifications to connect to official servers +if [ -e $ROOT_DIR/version-override ]; then + cat $ROOT_DIR/version-override + exit +fi + # Determine if we are using a modified version # Assume the dir is not modified MODIFIED="0" diff --git a/src/rev.cpp.in b/src/rev.cpp.in index 330066464a..f2c5d505d4 100644 --- a/src/rev.cpp.in +++ b/src/rev.cpp.in @@ -1,4 +1,4 @@ -/* $Id$ */ +/* $Id: rev.cpp.in 26440 2014-04-01 18:33:16Z frosch $ */ /* * This file is part of OpenTTD. @@ -70,7 +70,7 @@ const byte _openttd_revision_modified = !!MODIFIED!!; * final release will always have a lower version number than the released * version, thus making comparisons on specific revisions easy. */ -const uint32 _openttd_newgrf_version = 1 << 28 | 5 << 24 | 0 << 20 | 1 << 19 | (!!REVISION!! & ((1 << 19) - 1)); +const uint32 _openttd_newgrf_version = 1 << 28 | 4 << 24 | 0 << 20 | 1 << 19 | (!!REVISION!! & ((1 << 19) - 1)); #ifdef __MORPHOS__ /** From 19d76ddbbd21bde7c8e3af43a17e8c1059836e91 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 6 Apr 2014 23:23:10 +0300 Subject: [PATCH 113/187] Adopted "move when clicking near edge" setting for touchscreen --- src/window.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/window.cpp b/src/window.cpp index b9041801be..4279f80786 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2695,12 +2695,14 @@ static int _input_events_this_tick = 0; */ static void HandleAutoscroll() { + _move_pressed = false; if (_game_mode == GM_MENU || HasModalProgress()) return; if (_settings_client.gui.auto_scrolling == VA_DISABLED) return; if (_settings_client.gui.auto_scrolling == VA_MAIN_VIEWPORT_FULLSCREEN && !_fullscreen) return; int x = _cursor.pos.x; int y = _cursor.pos.y; + int border = RescaleFrom854x480(_settings_client.gui.min_button); Window *w = FindWindowFromPt(x, y); if (w == NULL || w->flags & WF_DISABLE_VP_SCROLL) return; if (_settings_client.gui.auto_scrolling != VA_EVERY_VIEWPORT && w->window_class != WC_MAIN_WINDOW) return; @@ -2712,16 +2714,20 @@ static void HandleAutoscroll() y -= vp->top; /* here allows scrolling in both x and y axis */ -#define scrollspeed 3 - if (x - 15 < 0) { - w->viewport->dest_scrollpos_x += ScaleByZoom((x - 15) * scrollspeed, vp->zoom); - } else if (15 - (vp->width - x) > 0) { - w->viewport->dest_scrollpos_x += ScaleByZoom((15 - (vp->width - x)) * scrollspeed, vp->zoom); +#define scrollspeed 15 + if (x - border < 0) { + _move_pressed = true; + w->viewport->dest_scrollpos_x += ScaleByZoom(-scrollspeed, vp->zoom); + } else if (border - (vp->width - x) > 0) { + _move_pressed = true; + w->viewport->dest_scrollpos_x += ScaleByZoom(scrollspeed, vp->zoom); } - if (y - 15 < 0) { - w->viewport->dest_scrollpos_y += ScaleByZoom((y - 15) * scrollspeed, vp->zoom); - } else if (15 - (vp->height - y) > 0) { - w->viewport->dest_scrollpos_y += ScaleByZoom((15 - (vp->height - y)) * scrollspeed, vp->zoom); + if (y - border * 2 < 0) { // Border twice thicker, to accomodate top toolbar + _move_pressed = true; + w->viewport->dest_scrollpos_y += ScaleByZoom(-scrollspeed, vp->zoom); + } else if (border - (vp->height - y) > 0) { // Same thickness, because bottom toolbar does not cover whole screen width + _move_pressed = true; + w->viewport->dest_scrollpos_y += ScaleByZoom(scrollspeed, vp->zoom); } #undef scrollspeed } From fed40b76ff3533462aaaff943ee9d5e687d7e714 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Mon, 7 Apr 2014 22:36:22 +0300 Subject: [PATCH 114/187] Change butto nsize and font size in game options --- src/lang/english.txt | 4 ++ src/settings_gui.cpp | 92 +++++++++++++++++++++++++---------- src/widgets/settings_widget.h | 2 + 3 files changed, 73 insertions(+), 25 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index bd933a2eb6..31fefff068 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1189,6 +1189,10 @@ STR_CONFIG_SETTING_TOUCHSCREEN_MODE_HELPTEXT :If playing with STR_CONFIG_SETTING_TOUCHSCREEN_NONE :no adaptation STR_CONFIG_SETTING_TOUCHSCREEN_SIMPLE :simple STR_CONFIG_SETTING_TOUCHSCREEN_CONFIRM :confirm +STR_CONFIG_SETTING_BUTTON_SIZE :{BLACK}Button size +STR_CONFIG_SETTING_BUTTON_SIZE_TOOLTIP :{BLACK}Size of all user interface elements +STR_CONFIG_SETTING_FONT_SIZE :{BLACK}Font size +STR_CONFIG_SETTING_FONT_SIZE_TOOLTIP :{BLACK}Size of all game fonts STR_CONFIG_SETTING_SHOWFINANCES :Show finances window at the end of the year: {STRING2} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :If enabled, the finances window pops up at the end of each year to allow easy inspection of the financial status of the company STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :New orders are 'non-stop' by default: {STRING2} diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index ed1caf81c6..07b51d6afe 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -39,6 +39,7 @@ #include "querystring_gui.h" #include "fontcache.h" +enum { MIN_BUTTON_SIZE = 10, MAX_BUTTON_SIZE = 40 }; static const StringID _driveside_dropdown[] = { STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT, @@ -102,6 +103,8 @@ static int GetCurRes() static void ShowCustCurrency(); +static void ReconstructUserInterface(); + template static DropDownList *BuiltSetDropDownList(int *selected_index) { @@ -282,6 +285,19 @@ struct GameOptionsWindow : Window { } break; + case WID_GO_BUTTON_SIZE_DROPDOWN: // Setup screenshot format dropdown + case WID_GO_TEXT_SIZE_DROPDOWN: // Setup screenshot format dropdown + list = new DropDownList(); + *selected_index = (widget == WID_GO_BUTTON_SIZE_DROPDOWN) ? + _settings_client.gui.min_button : + _freetype.medium.size; + for (uint i = MIN_BUTTON_SIZE; i <= MAX_BUTTON_SIZE; i++) { + DropDownListParamStringItem *item = new DropDownListParamStringItem(STR_JUST_INT, i, false); + item->SetParam(0, i); + *list->Append() = item; + } + break; + case WID_GO_BASE_GRF_DROPDOWN: list = BuiltSetDropDownList(selected_index); break; @@ -311,6 +327,8 @@ struct GameOptionsWindow : Window { case WID_GO_LANG_DROPDOWN: SetDParamStr(0, _current_language->own_name); break; case WID_GO_RESOLUTION_DROPDOWN: SetDParam(0, GetCurRes() == _num_resolutions ? STR_GAME_OPTIONS_RESOLUTION_OTHER : SPECSTR_RESOLUTION_START + GetCurRes()); break; case WID_GO_SCREENSHOT_DROPDOWN: SetDParam(0, SPECSTR_SCREENSHOT_START + _cur_screenshot_format); break; + case WID_GO_BUTTON_SIZE_DROPDOWN:SetDParam(0, _settings_client.gui.min_button); break; + case WID_GO_TEXT_SIZE_DROPDOWN: SetDParam(0, _freetype.medium.size); break; case WID_GO_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->name); break; case WID_GO_BASE_GRF_STATUS: SetDParam(0, BaseGraphics::GetUsedSet()->GetNumInvalid()); break; case WID_GO_BASE_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->name); break; @@ -507,29 +525,7 @@ struct GameOptionsWindow : Window { case WID_GO_RESOLUTION_DROPDOWN: // Change resolution if (index < _num_resolutions && ChangeResInGame(_resolutions[index].width, _resolutions[index].height)) { - // Reinit all GUI elements and fonts, so they will rescale - InitFreeType(true); - CheckForMissingGlyphs(); - - DeleteAllNonVitalWindows(); - - switch (_game_mode) { - case GM_MENU: - DeleteWindowById(WC_SELECT_GAME, 0); - extern void ShowSelectGameWindow(); - ShowSelectGameWindow(); - break; - - case GM_NORMAL: - case GM_EDITOR: - HideVitalWindows(); - ShowVitalWindows(); - break; - - default: - break; - } - + ReconstructUserInterface(); this->SetDirty(); } break; @@ -539,6 +535,20 @@ struct GameOptionsWindow : Window { this->SetDirty(); break; + case WID_GO_BUTTON_SIZE_DROPDOWN: // Setup screenshot format dropdown + _settings_client.gui.min_button = index; + _settings_client.gui.min_step = index; + ReconstructUserInterface(); + break; + + case WID_GO_TEXT_SIZE_DROPDOWN: // Setup screenshot format dropdown + _freetype.medium.size = index; + _freetype.small.size = _freetype.medium.size * 10 / 12; + _freetype.large.size = _freetype.medium.size * 16 / 12; + _freetype.mono.size = _freetype.medium.size; + ReconstructUserInterface(); + break; + case WID_GO_BASE_GRF_DROPDOWN: this->SetMediaSet(index); break; @@ -610,8 +620,11 @@ static const NWidgetPart _nested_game_options_widgets[] = { NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_LANGUAGE, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_LANG_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_LANGUAGE_TOOLTIP), SetFill(1, 0), EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_SCREENSHOT_FORMAT, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_SCREENSHOT_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_SCREENSHOT_FORMAT_TOOLTIP), SetFill(1, 0), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_CONFIG_SETTING_BUTTON_SIZE, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BUTTON_SIZE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_JUST_INT, STR_CONFIG_SETTING_BUTTON_SIZE_TOOLTIP), SetFill(1, 0), + EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_CONFIG_SETTING_FONT_SIZE, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_TEXT_SIZE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_JUST_INT, STR_CONFIG_SETTING_FONT_SIZE_TOOLTIP), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 0), SetFill(0, 1), EndContainer(), @@ -2677,3 +2690,32 @@ static void ShowCustCurrency() DeleteWindowById(WC_CUSTOM_CURRENCY, 0); new CustomCurrencyWindow(&_cust_currency_desc); } + +void ReconstructUserInterface() +{ + // Reinit all GUI elements and fonts, so they will rescale + InitFreeType(true); + CheckForMissingGlyphs(); + + DeleteAllNonVitalWindows(); + + switch (_game_mode) { + case GM_MENU: + DeleteWindowById(WC_SELECT_GAME, 0); + extern void ShowSelectGameWindow(); + ShowSelectGameWindow(); + break; + + case GM_NORMAL: + case GM_EDITOR: + HideVitalWindows(); + ShowVitalWindows(); + break; + + default: + break; + } + + ReInitAllWindows(); + ShowGameOptions(); +} diff --git a/src/widgets/settings_widget.h b/src/widgets/settings_widget.h index 6f045a2a25..1bb18185a2 100644 --- a/src/widgets/settings_widget.h +++ b/src/widgets/settings_widget.h @@ -24,6 +24,8 @@ enum GameOptionsWidgets { WID_GO_RESOLUTION_DROPDOWN, ///< Dropdown for the resolution. WID_GO_FULLSCREEN_BUTTON, ///< Toggle fullscreen. WID_GO_SCREENSHOT_DROPDOWN, ///< Select the screenshot type... please use PNG!. + WID_GO_BUTTON_SIZE_DROPDOWN, ///< Size of in-game UI elements, such as buttons. + WID_GO_TEXT_SIZE_DROPDOWN, ///< Size of medium font, sizes of other fonts are derived from it. WID_GO_BASE_GRF_DROPDOWN, ///< Use to select a base GRF. WID_GO_BASE_GRF_STATUS, ///< Info about missing files etc. WID_GO_BASE_GRF_TEXTFILE, ///< Open base GRF readme, changelog (+1) or license (+2). From e4e3db8a850a76fb1f085bf6043d8883f29c4ad5 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 27 May 2014 20:42:23 +0300 Subject: [PATCH 115/187] Simple but fast 16bpp renderer --- source.list | 6 + src/blitter/16bpp_base.cpp | 147 +++++++++++++++++++++++++ src/blitter/16bpp_base.hpp | 208 +++++++++++++++++++++++++++++++++++ src/blitter/16bpp_simple.cpp | 146 ++++++++++++++++++++++++ src/blitter/16bpp_simple.hpp | 35 ++++++ 5 files changed, 542 insertions(+) create mode 100644 src/blitter/16bpp_base.cpp create mode 100644 src/blitter/16bpp_base.hpp create mode 100644 src/blitter/16bpp_simple.cpp create mode 100644 src/blitter/16bpp_simple.hpp diff --git a/source.list b/source.list index 3e29ab45fe..7a500c3d97 100644 --- a/source.list +++ b/source.list @@ -904,6 +904,12 @@ script/api/script_window.cpp # Blitters #if DEDICATED #else +blitter/16bpp_base.cpp +blitter/16bpp_base.hpp +# blitter/16bpp_anim.cpp +# blitter/16bpp_anim.hpp +blitter/16bpp_simple.cpp +blitter/16bpp_simple.hpp blitter/32bpp_anim.cpp blitter/32bpp_anim.hpp #if SSE diff --git a/src/blitter/16bpp_base.cpp b/src/blitter/16bpp_base.cpp new file mode 100644 index 0000000000..69424fad4d --- /dev/null +++ b/src/blitter/16bpp_base.cpp @@ -0,0 +1,147 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file 16bpp_base.cpp Implementation of base for 32 bpp blitters. */ + +#include "../stdafx.h" +#include "16bpp_base.hpp" + +void *Blitter_16bppBase::MoveTo(void *video, int x, int y) +{ + return (uint16 *)video + x + y * _screen.pitch; +} + +void Blitter_16bppBase::SetPixel(void *video, int x, int y, uint8 colour) +{ + *((Colour16 *)video + x + y * _screen.pitch) = LookupColourInPalette(colour); +} + +void Blitter_16bppBase::DrawRect(void *video, int width, int height, uint8 colour) +{ + Colour16 target = LookupColourInPalette(colour); + + do { + Colour16 *dst = (Colour16 *)video; + for (int i = width; i > 0; i--) { + *dst = target; + dst++; + } + video = (uint16 *)video + _screen.pitch; + } while (--height); +} + +void Blitter_16bppBase::CopyFromBuffer(void *video, const void *src, int width, int height) +{ + uint16 *dst = (uint16 *)video; + const uint16 *usrc = (const uint16 *)src; + + for (; height > 0; height--) { + memcpy(dst, usrc, width * sizeof(uint16)); + usrc += width; + dst += _screen.pitch; + } +} + +void Blitter_16bppBase::CopyToBuffer(const void *video, void *dst, int width, int height) +{ + uint16 *udst = (uint16 *)dst; + const uint16 *src = (const uint16 *)video; + + for (; height > 0; height--) { + memcpy(udst, src, width * sizeof(uint16)); + src += _screen.pitch; + udst += width; + } +} + +void Blitter_16bppBase::CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) +{ + uint16 *udst = (uint16 *)dst; + const uint16 *src = (const uint16 *)video; + + for (; height > 0; height--) { + memcpy(udst, src, width * sizeof(uint16)); + src += _screen.pitch; + udst += dst_pitch; + } +} + +void Blitter_16bppBase::ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) +{ + const uint16 *src; + uint16 *dst; + + if (scroll_y > 0) { + /* Calculate pointers */ + dst = (uint16 *)video + left + (top + height - 1) * _screen.pitch; + src = dst - scroll_y * _screen.pitch; + + /* Decrease height and increase top */ + top += scroll_y; + height -= scroll_y; + assert(height > 0); + + /* Adjust left & width */ + if (scroll_x >= 0) { + dst += scroll_x; + left += scroll_x; + width -= scroll_x; + } else { + src -= scroll_x; + width += scroll_x; + } + + for (int h = height; h > 0; h--) { + memcpy(dst, src, width * sizeof(uint16)); + src -= _screen.pitch; + dst -= _screen.pitch; + } + } else { + /* Calculate pointers */ + dst = (uint16 *)video + left + top * _screen.pitch; + src = dst - scroll_y * _screen.pitch; + + /* Decrease height. (scroll_y is <=0). */ + height += scroll_y; + assert(height > 0); + + /* Adjust left & width */ + if (scroll_x >= 0) { + dst += scroll_x; + left += scroll_x; + width -= scroll_x; + } else { + src -= scroll_x; + width += scroll_x; + } + + /* the y-displacement may be 0 therefore we have to use memmove, + * because source and destination may overlap */ + for (int h = height; h > 0; h--) { + memmove(dst, src, width * sizeof(uint16)); + src += _screen.pitch; + dst += _screen.pitch; + } + } +} + +int Blitter_16bppBase::BufferSize(int width, int height) +{ + return width * height * sizeof(uint16); +} + +void Blitter_16bppBase::PaletteAnimate(const Palette &palette) +{ + /* By default, 16bpp doesn't have palette animation */ +} + +Blitter::PaletteAnimation Blitter_16bppBase::UsePaletteAnimation() +{ + return Blitter::PALETTE_ANIMATION_NONE; +} diff --git a/src/blitter/16bpp_base.hpp b/src/blitter/16bpp_base.hpp new file mode 100644 index 0000000000..e5425d809f --- /dev/null +++ b/src/blitter/16bpp_base.hpp @@ -0,0 +1,208 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file 16bpp_base.hpp Base for all 16 bits blitters. */ + +#ifndef BLITTER_16BPP_BASE_HPP +#define BLITTER_16BPP_BASE_HPP + +#include "base.hpp" +#include "../core/bitmath_func.hpp" +#include "../core/math_func.hpp" +#include "../gfx_func.h" + +/** Base for all 16bpp blitters. */ +class Blitter_16bppBase : public Blitter { +public: + + // TODO: GCC-specific attributes + struct Colour16 { + unsigned b : 5 __attribute__((packed)); ///< Blue-channel, packed 5 bits + unsigned g : 6 __attribute__((packed)); ///< Green-channel, packed 6 bits + unsigned r : 5 __attribute__((packed)); ///< Red-channel, packed 5 bits + Colour16(uint8 r, uint8 g, uint8 b): + b(b), g(g), r(r) + { + } + }; + + struct Pixel { + Colour16 c; + unsigned a : 4 __attribute__((packed)); ///< Alpha-channel, packed 4 bits + unsigned v : 4 __attribute__((packed)); ///< Brightness-channel, packed 4 bits + unsigned m : 8 __attribute__((packed)); ///< Remap-channel, cannot pack it, because it's palette lookup index, so it must be in range 0-255 + }; + + /* virtual */ uint8 GetScreenDepth() { return 16; } + /* virtual */ void *MoveTo(void *video, int x, int y); + /* virtual */ void SetPixel(void *video, int x, int y, uint8 colour); + /* virtual */ void DrawRect(void *video, int width, int height, uint8 colour); + /* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height); + /* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height); + /* virtual */ void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch); + /* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y); + /* virtual */ int BufferSize(int width, int height); + /* virtual */ void PaletteAnimate(const Palette &palette); + /* virtual */ Blitter::PaletteAnimation UsePaletteAnimation(); + /* virtual */ int GetBytesPerPixel() { return 2; } + + + /** + * Convert from rgb values to screen native 16bpp colour + */ + static inline Colour16 To16(uint8 r, uint8 g, uint8 b) + { + return Colour16(r >> 3, g >> 2, b >> 3); + } + + /** + * Convert from 32bpp colour to screen native 16bpp colour + */ + static inline Colour16 To16(Colour c) + { + return To16(c.r, c.g, c.b); + } + + /** + * Look up the colour in the current palette. + */ + static inline Colour LookupColourInPalette32(uint index) + { + return _cur_palette.palette[index]; + } + + /** + * Look up the colour in the current palette. + */ + static inline Colour16 LookupColourInPalette(uint index) + { + return To16(LookupColourInPalette32(index)); + } + + /** + * Compose a colour based on RGBA values and the current pixel value. + * @param r range is from 0 to 31. + * @param g range is from 0 to 63. + * @param b range is from 0 to 31. + * @param a range is from 0 to 15. + */ + static inline Colour16 ComposeColourRGBANoCheck(uint8 r, uint8 g, uint8 b, uint8 a, Colour16 current) + { + /* The 16 is wrong, it should be 15, but 16 is much faster... */ + return Colour16 ( ((int)(r - current.r) * a) / 16 + current.r, + ((int)(g - current.g) * a) / 16 + current.g, + ((int)(b - current.b) * a) / 16 + current.b ); + } + + /** + * Compose a colour based on RGBA values and the current pixel value. + * Handles fully transparent and solid pixels in a special (faster) way. + * @param r range is from 0 to 31. + * @param g range is from 0 to 63. + * @param b range is from 0 to 31. + * @param a range is from 0 to 15. + */ + static inline Colour16 ComposeColourRGBA(uint8 r, uint8 g, uint8 b, uint8 a, Colour16 current) + { + if (a == 0) return current; + if (a >= 15) return Colour16(r, g, b); + + return ComposeColourRGBANoCheck(r, g, b, a, current); + } + + /** + * Compose a colour based on Pixel value, alpha value, and the current pixel value. + * @param a range is from 0 to 16. + */ + static inline Colour16 ComposeColourPANoCheck(Colour16 colour, uint8 a, Colour16 current) + { + return ComposeColourRGBANoCheck(colour.r, colour.g, colour.b, a, current); + } + + /** + * Compose a colour based on Pixel value, alpha value, and the current pixel value. + * Handles fully transparent and solid pixels in a special (faster) way. + * @param a range is from 0 to 15. + */ + static inline Colour16 ComposeColourPA(Colour16 colour, uint8 a, Colour16 current) + { + if (a == 0) return current; + if (a >= 15) return colour; + + return ComposeColourPANoCheck(colour, a, current); + } + + /** + * Make a pixel looks like it is transparent. + * @param colour the colour already on the screen. + * @param nom the amount of transparency, nominator, makes colour lighter. + * @param denom denominator, makes colour darker. + * @return the new colour for the screen. + */ + static inline Colour16 MakeTransparent(Colour16 colour, uint nom, uint denom = 256) + { + uint r = colour.r; + uint g = colour.g; + uint b = colour.b; + + return Colour16( r * nom / denom, + g * nom / denom, + b * nom / denom ); + } + + /** + * Make a colour grey - based. + * @param colour the colour to make grey. + * @return the new colour, now grey. + */ + static inline Colour16 MakeGrey(Colour16 colour) + { + uint r = colour.r; + uint g = colour.g; + uint b = colour.b; + + /* To avoid doubles and stuff, multiple it with a total of 65536 (16bits), then + * divide by it to normalize the value to a byte again. See heightmap.cpp for + * information about the formula. */ + uint grey = (((r << 3) * 19595) + ((g << 2) * 38470) + ((b << 3) * 7471)) / 65536; + + return To16(grey, grey, grey); + } + + enum { DEFAULT_BRIGHTNESS = 8 }; + + /** + * @param brightness range is from 0 to 15. + */ + static inline Colour16 AdjustBrightness(Colour16 colour, uint8 brightness) + { + /* Shortcut for normal brightness */ + if (brightness == DEFAULT_BRIGHTNESS) return colour; + + uint16 ob = 0; + uint16 r = colour.r * brightness / DEFAULT_BRIGHTNESS; + uint16 g = colour.g * brightness / DEFAULT_BRIGHTNESS; + uint16 b = colour.b * brightness / DEFAULT_BRIGHTNESS; + + /* Sum overbright */ + if (r > 31) ob += r - 31; + if (g > 63) ob += g - 63; + if (b > 31) ob += b - 31; + + if (ob == 0) return Colour16(r, g, b); + + /* Reduce overbright strength */ + ob /= 2; + return Colour16( r >= 31 ? 31 : min(r + ob * (31 - r) / 32, 31), + g >= 63 ? 63 : min(g + ob * (63 - g) / 64, 63), + b >= 31 ? 31 : min(b + ob * (31 - b) / 32, 31) ); + } +}; + +#endif /* BLITTER_16BPP_BASE_HPP */ diff --git a/src/blitter/16bpp_simple.cpp b/src/blitter/16bpp_simple.cpp new file mode 100644 index 0000000000..a3e1f4d0ed --- /dev/null +++ b/src/blitter/16bpp_simple.cpp @@ -0,0 +1,146 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file 32bpp_simple.cpp Implementation of the simple 32 bpp blitter. */ + +#include "../stdafx.h" +#include "../zoom_func.h" +#include "16bpp_simple.hpp" +#include "32bpp_base.hpp" + +#include "../table/sprites.h" + +#include + +/** Instantiation of the simple 16bpp blitter factory. */ +static FBlitter_16bppSimple iFBlitter_16bppSimple; + +void Blitter_16bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +{ + const Pixel *src, *src_line; + Colour16 *dst, *dst_line; + + /* Find where to start reading in the source sprite */ + src_line = (const Pixel *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom); + dst_line = (Colour16 *)bp->dst + bp->top * bp->pitch + bp->left; + + for (int y = 0; y < bp->height; y++) { + dst = dst_line; + dst_line += bp->pitch; + + src = src_line; + src_line += bp->sprite_width * ScaleByZoom(1, zoom); + + for (int x = 0; x < bp->width; x++) { + switch (mode) { + case BM_COLOUR_REMAP: + /* In case the m-channel is zero, do not remap this pixel in any way */ + if (src->m == 0) { + if (src->a != 0) *dst = ComposeColourPA(src->c, src->a, *dst); + } else { + if (bp->remap[src->m] != 0) *dst = ComposeColourPA(this->AdjustBrightness(this->LookupColourInPalette(bp->remap[src->m]), src->v), src->a, *dst); + } + break; + + case BM_TRANSPARENT: + /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour. + * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: + * we produce a result the newgrf maker didn't expect ;) */ + + /* Make the current colour a bit more black, so it looks like this image is transparent */ + if (src->a != 0) *dst = MakeTransparent(*dst, 192); + break; + + default: + if (src->a != 0) *dst = ComposeColourPA(src->c, src->a, *dst); + break; + } + dst++; + src += ScaleByZoom(1, zoom); + } + } +} + +void Blitter_16bppSimple::DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) +{ + Colour16 *udst = (Colour16 *)dst; + + if (pal == PALETTE_TO_TRANSPARENT) { + do { + for (int i = 0; i != width; i++) { + *udst = MakeTransparent(*udst, 154); + udst++; + } + udst = udst - width + _screen.pitch; + } while (--height); + return; + } + if (pal == PALETTE_NEWSPAPER) { + do { + for (int i = 0; i != width; i++) { + *udst = MakeGrey(*udst); + udst++; + } + udst = udst - width + _screen.pitch; + } while (--height); + return; + } + + DEBUG(misc, 0, "16bpp blitter doesn't know how to draw this colour table ('%d')", pal); +} + +Sprite *Blitter_16bppSimple::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) +{ + Pixel *dst; + Sprite *dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + (size_t)sprite->height * (size_t)sprite->width * sizeof(Pixel)); + + dest_sprite->height = sprite->height; + dest_sprite->width = sprite->width; + dest_sprite->x_offs = sprite->x_offs; + dest_sprite->y_offs = sprite->y_offs; + + dst = (Pixel *)dest_sprite->data; + SpriteLoader::CommonPixel *src = (SpriteLoader::CommonPixel *)sprite->data; + + for (int i = 0; i < sprite->height * sprite->width; i++) { + if (src->m == 0) { + dst[i].c = To16(src->r, src->g, src->b); + dst[i].a = src->a / 16; + dst[i].m = 0; + dst[i].v = 0; + } else { + /* Get brightest value */ + uint8 rgb_max = max(src->r, max(src->g, src->b)); +#if 0 + /* Pre-convert the mapping channel to a RGB value, + use 32bpp AdjustBrightness() variant for better colors, + because this function is not called each frame */ + if (rgb_max == 0) rgb_max = Blitter_32bppBase::DEFAULT_BRIGHTNESS; + dst[i].c = To16(Blitter_32bppBase::AdjustBrightness(this->LookupColourInPalette32(src->m), rgb_max)); + dst[i].v = rgb_max / 16; +#endif + rgb_max /= 16; + + /* Black pixel (8bpp or old 16bpp image), so use default value */ + if (rgb_max == 0) rgb_max = DEFAULT_BRIGHTNESS; + + /* Pre-convert the mapping channel to a RGB value, + use 32bpp AdjustBrightness() variant for better colors, + because this function is not called each frame */ + dst[i].c = AdjustBrightness(this->LookupColourInPalette(src->m), rgb_max); + dst[i].v = rgb_max; + + dst[i].a = src->a / 16; + dst[i].m = src->m; + } + src++; + } + + return dest_sprite; +} diff --git a/src/blitter/16bpp_simple.hpp b/src/blitter/16bpp_simple.hpp new file mode 100644 index 0000000000..e708ce9a93 --- /dev/null +++ b/src/blitter/16bpp_simple.hpp @@ -0,0 +1,35 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file 16bpp_simple.hpp Simple 16 bpp blitter. */ + +#ifndef BLITTER_16BPP_SIMPLE_HPP +#define BLITTER_16BPP_SIMPLE_HPP + +#include "16bpp_base.hpp" +#include "factory.hpp" + +/** The most trivial 32 bpp blitter (without palette animation). */ +class Blitter_16bppSimple : public Blitter_16bppBase { +public: + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + /* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal); + /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); + + /* virtual */ const char *GetName() { return "16bpp-simple"; } +}; + +/** Factory for the simple 16 bpp blitter. */ +class FBlitter_16bppSimple : public BlitterFactory { +public: + FBlitter_16bppSimple() : BlitterFactory("16bpp-simple", "16bpp Simple Blitter (no palette animation)") {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_16bppSimple(); } +}; + +#endif /* BLITTER_32BPP_SIMPLE_HPP */ From ba809d1b211deaec09c1b2c4c8292004db507341 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 27 May 2014 21:07:36 +0300 Subject: [PATCH 116/187] Removed todo, it's not needed anymore --- todo.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 todo.txt diff --git a/todo.txt b/todo.txt deleted file mode 100644 index 36c93f49af..0000000000 --- a/todo.txt +++ /dev/null @@ -1 +0,0 @@ -- Add Load button to Play Heightmap dialog From 7748f7cbf1bc3c26e0fcb9b04ff20966d00aa6a0 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 27 May 2014 22:15:25 +0300 Subject: [PATCH 117/187] Auto-switch to full toolbar if enough space --- src/lang/english.txt | 10 +++++----- src/toolbar_gui.cpp | 27 ++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 31fefff068..b5a81a7093 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2450,17 +2450,17 @@ STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Level an STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Purchase land for future use. Shift toggles building/showing cost estimate # Tablet toolbar -STR_TABLET_X :{BLACK}Trans +STR_TABLET_X :{BLACK}{TINY_FONT}Trans STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP :{BLACK}Toggle transparency STR_TABLET_CLOSE :{BLACK}X STR_TABLET_CLOSE_TOOLTIP :{BLACK}Close all opened windows (except pinned ones) -STR_TABLET_SHIFT :{BLACK}Shift +STR_TABLET_SHIFT :{BLACK}{TINY_FONT}Shft STR_TABLET_SHIFT_TOOLTIP :{BLACK}Press it for getting an estimated cost of executing an action -STR_TABLET_CTRL :{BLACK}Ctrl +STR_TABLET_CTRL :{BLACK}{TINY_FONT}Ctrl STR_TABLET_CTRL_TOOLTIP :{BLACK}Use it for actions that use the "CTRL" key -STR_TABLET_MOVE :{BLACK}Move +STR_TABLET_MOVE :{BLACK}{TINY_FONT}Move STR_TABLET_MOVE_TOOLTIP :{BLACK}Press it to move around viewports. No action will be executed on viewports while this is active -STR_TABLET_CONFIRM :{BLACK}Do +STR_TABLET_CONFIRM :{BLACK}{TINY_FONT}Do STR_TABLET_CONFIRM_TOOLTIP :{BLACK}Press it to confirm an action # Object construction window diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 2827e6c4d5..22d58990d7 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1495,14 +1495,31 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { { #ifdef __ANDROID__ - static const byte arrange_android[] = { - 0, 1, 2, 4, 5, 6, 7, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29, 30, 31, 32, - 0, 1, 3, 4, 5, 6, 7, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29, 30, 31, 32, + static const uint BIGGEST_ARRANGEMENT = 28; + static const uint ARRANGEMENT_30 = 24; + static const byte arrange_android_28[] = { + 0, 1, 3, 4, 5, 6, 7, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29, 30, 31, 32, + 0, 1, 2, 4, 5, 10, 11, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29, 30, 31, 32, + }; + static const byte arrange_android_30[] = { + 0, 1, 3, 4, 5, 6, 7, 12, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29, 30, 31, 32, + 0, 1, 2, 4, 5, 10, 11, 12, 13, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29, 30, 31, 32, + }; + static const byte arrange_android_all[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32 }; - button_count = arrangable_count = lengthof(arrange_android) / 2; spacer_count = this->spacers; - return &arrange_android[((_toolbar_mode == TB_LOWER) ? button_count : 0)]; + if (width > BIGGEST_ARRANGEMENT * this->smallest_x) { + button_count = arrangable_count = lengthof(arrange_android_all); + return arrange_android_all; + } + if (width > ARRANGEMENT_30 * this->smallest_x) { + button_count = arrangable_count = lengthof(arrange_android_30) / 2; + return &arrange_android_30[((_toolbar_mode == TB_LOWER) ? button_count : 0)]; + } + button_count = arrangable_count = lengthof(arrange_android_28) / 2; + return &arrange_android_28[((_toolbar_mode == TB_LOWER) ? button_count : 0)]; #else From 617d04eccd88d71a18e33667abc7d5d590e25013 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 27 May 2014 22:43:31 +0300 Subject: [PATCH 118/187] Toggle Android text input when invoking console --- src/console_gui.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/console_gui.cpp b/src/console_gui.cpp index 031a4900ad..dbf194d163 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -28,6 +28,10 @@ #include "table/strings.h" +#ifdef __ANDROID__ +#include +#endif + static const uint ICON_HISTORY_SIZE = 20; static const uint ICON_LINE_SPACING = 2; static const uint ICON_RIGHT_BORDERWIDTH = 10; @@ -447,9 +451,25 @@ void IConsoleSwitch() { switch (_iconsole_mode) { case ICONSOLE_CLOSED: - new IConsoleWindow(); +#ifdef __ANDROID__ + { + char buf[1024] = ""; + for (const IConsoleLine *print = IConsoleLine::Get(0); print != NULL; print = print->previous) { + if (print->buffer && print->buffer[0]) { + strncat(buf, print->buffer, sizeof(buf)-strlen(buf)-1); + strncat(buf, "\n", sizeof(buf)-strlen(buf)-1); + } + } + strncat(buf, "\n\n\n\n\n\n\n\n", sizeof(buf)-strlen(buf)-1); // Move all text to top + SDL_ANDROID_SetScreenKeyboardHintMesage(buf); + char text[512] = ""; + SDL_ANDROID_GetScreenKeyboardTextInput(text, sizeof(text) - 1); /* Invoke Android built-in screen keyboard */ + IConsoleCmdExec(text); + } +#else + new IConsoleWindow(); +#endif break; - case ICONSOLE_OPENED: case ICONSOLE_FULL: DeleteWindowById(WC_CONSOLE, 0); break; From 1d82f579450fac1aa1807419b63de07d5fd8e487 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 27 May 2014 23:10:56 +0300 Subject: [PATCH 119/187] Fixed multiplayer join menu --- src/network/network_gui.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 12597ec4b0..ac0ac94626 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -548,7 +548,7 @@ public: { switch (widget) { case WID_NG_MATRIX: { - uint16 y = r.top + WD_MATRIX_TOP; + uint16 y = r.top + WD_MATRIX_TOP + this->resize.step_height / 4; const int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (int)this->servers.Length()); @@ -1373,7 +1373,7 @@ struct NetworkLobbyWindow : public Window { case WID_NL_MATRIX: resize->height = GetMinSizing(NWST_STEP, WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM); - size->height = 10 * resize->height; + size->height = 6 * resize->height; break; case WID_NL_DETAILS: @@ -1440,7 +1440,7 @@ struct NetworkLobbyWindow : public Window { uint profit_left = rtl ? left : right - profit_width; uint lock_left = rtl ? left + profit_width + 2 : right - profit_width - lock_width - 2; - int y = r.top + WD_MATRIX_TOP; + int y = r.top + WD_MATRIX_TOP + this->resize.step_height / 4; /* Draw company list */ int pos = this->vscroll->GetPosition(); while (pos < this->server->info.companies_on) { From 657e563f7c2e1e31091b34c82f59af9ff54a1954 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 28 May 2014 15:41:53 +0300 Subject: [PATCH 120/187] Fixed no sound when playing music, fixed music volume reverted on new track --- src/music/libtimidity.cpp | 5 ++++- src/music/libtimidity.h | 1 + src/music_gui.cpp | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/music/libtimidity.cpp b/src/music/libtimidity.cpp index 96534b6204..6377507d2e 100644 --- a/src/music/libtimidity.cpp +++ b/src/music/libtimidity.cpp @@ -62,7 +62,7 @@ void Android_MidiMixMusic(Sint16 *stream, int len) while( len > 0 ) { int minlen = min(sizeof(buf), len); - mid_song_read_wave(_midi.song, stream, min(sizeof(buf), len*2)); + mid_song_read_wave(_midi.song, buf, min(sizeof(buf), len*2)); for( Uint16 i = 0; i < minlen; i++ ) stream[i] += buf[i]; stream += minlen; @@ -79,6 +79,7 @@ const char *MusicDriver_LibTimidity::Start(const char * const *param) { _midi.status = MIDI_STOPPED; _midi.song = NULL; + volume = 99; // Avoid clipping if (mid_init(param == NULL ? NULL : const_cast(param[0])) < 0) { /* If init fails, it can be because no configuration was found. @@ -133,6 +134,7 @@ void MusicDriver_LibTimidity::PlaySong(const char *filename) return; } + mid_song_set_volume(_midi.song, volume); mid_song_start(_midi.song); _midi.status = MIDI_PLAYING; } @@ -160,5 +162,6 @@ bool MusicDriver_LibTimidity::IsSongPlaying() void MusicDriver_LibTimidity::SetVolume(byte vol) { + volume = vol * 99 / 127; // I'm not sure about that value if (_midi.song != NULL) mid_song_set_volume(_midi.song, vol); } diff --git a/src/music/libtimidity.h b/src/music/libtimidity.h index abe17e7703..0a0686499f 100644 --- a/src/music/libtimidity.h +++ b/src/music/libtimidity.h @@ -16,6 +16,7 @@ /** Music driver making use of libtimidity. */ class MusicDriver_LibTimidity : public MusicDriver { + int volume; public: /* virtual */ const char *Start(const char * const *param); diff --git a/src/music_gui.cpp b/src/music_gui.cpp index cf48cf2193..307ad0c6c7 100644 --- a/src/music_gui.cpp +++ b/src/music_gui.cpp @@ -689,7 +689,7 @@ struct MusicWindow : public Window { if (_current_text_dir == TD_RTL) new_vol = 127 - new_vol; if (new_vol != *vol) { *vol = new_vol; - if (widget == WID_M_MUSIC_VOL) MusicVolumeChanged(new_vol); + if (widget == WID_M_MUSIC_VOL) MusicVolumeChanged((new_vol * new_vol) / 127); // Kinda logarithmic scale this->SetDirty(); } From 1362aaab60d448a2301483418e159a7de8a1da3c Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 28 May 2014 22:41:25 +0300 Subject: [PATCH 121/187] Fixed 'build waypoint' button building a train station. --- src/rail_gui.cpp | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index df7f8fc1ab..0c4477ac90 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -695,28 +695,26 @@ struct BuildRailToolbarWindow : Window { TouchCommandP(end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 0x10 : 0), CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound10); break; - case DDSP_BUILD_STATION: - if (!_remove_button_clicked && !_settings_client.gui.station_dragdrop) { - uint32 p1 = _cur_railtype | _railstation.orientation << 4 | _settings_client.gui.station_numtracks << 8 | _settings_client.gui.station_platlength << 16 | _ctrl_pressed << 24; - uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16; - - int w = _settings_client.gui.station_numtracks; - int h = _settings_client.gui.station_platlength; - if (!_railstation.orientation) Swap(w, h); - - CommandContainer cmdcont = { end_tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" }; - ShowSelectStationIfNeeded(cmdcont, TileArea(end_tile, w, h)); - break; - } - /* Fall through. */ - case DDSP_REMOVE_STATION: + case DDSP_BUILD_STATION: if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) { /* Station */ if (_remove_button_clicked) { TouchCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION), CcPlaySound1E); } else { - HandleStationPlacement(start_tile, end_tile); + if (!_settings_client.gui.station_dragdrop) { + uint32 p1 = _cur_railtype | _railstation.orientation << 4 | _settings_client.gui.station_numtracks << 8 | _settings_client.gui.station_platlength << 16 | _ctrl_pressed << 24; + uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16; + + int w = _settings_client.gui.station_numtracks; + int h = _settings_client.gui.station_platlength; + if (!_railstation.orientation) Swap(w, h); + + CommandContainer cmdcont = { end_tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" }; + ShowSelectStationIfNeeded(cmdcont, TileArea(end_tile, w, h)); + } else { + HandleStationPlacement(start_tile, end_tile); + } } } else { /* Waypoint */ From 318ff9d373a9eb3f33f6c0afaebef8c6d3fffabd Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Wed, 28 May 2014 22:52:11 +0300 Subject: [PATCH 122/187] Fixed airport construction dialog too tall --- src/airport_gui.cpp | 58 +++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 58f7d54916..9eeeae950f 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -540,35 +540,41 @@ static const NWidgetPart _nested_build_airport_widgets[] = { NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 0), SetPIP(2, 0, 2), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetSizingType(NWST_STEP), SetDataTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL, STR_NULL), SetFill(1, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_AP_CLASS_DROPDOWN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_STATION_BUILD_AIRPORT_TOOLTIP), - NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_AIRPORT_SPRITE), SetFill(1, 0), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_GREY, WID_AP_AIRPORT_LIST), SetFill(1, 0), SetMatrixDataTip(1, 5, STR_STATION_BUILD_AIRPORT_TOOLTIP), SetScrollbar(WID_AP_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AP_SCROLLBAR), + NWidget(NWID_HORIZONTAL), + /* Airport dropdown selector and picture. */ + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 0), SetPIP(2, 0, 2), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetSizingType(NWST_STEP), SetDataTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL, STR_NULL), SetFill(1, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_AP_CLASS_DROPDOWN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_STATION_BUILD_AIRPORT_TOOLTIP), + NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_AIRPORT_SPRITE), SetFill(1, 0), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_DECREASE), SetSizingType(NWST_STEP), SetMinimalSize(12, 0), SetDataTip(AWV_DECREASE, STR_NULL), - NWidget(WWT_LABEL, COLOUR_GREY, WID_AP_LAYOUT_NUM), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NULL), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_INCREASE), SetSizingType(NWST_STEP), SetMinimalSize(12, 0), SetDataTip(AWV_INCREASE, STR_NULL), - EndContainer(), - NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_EXTRA_TEXT), SetFill(1, 0), SetMinimalSize(150, 0), - EndContainer(), - /* Bottom panel. */ - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_AP_BOTTOMPANEL), SetPIP(2, 2, 2), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetFill(1, 0), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DONTHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), - SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DOHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), - SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), + /* Airport parameters and info. */ + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 0), SetPIP(2, 0, 2), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_AP_AIRPORT_LIST), SetFill(1, 0), SetMatrixDataTip(1, 5, STR_STATION_BUILD_AIRPORT_TOOLTIP), SetScrollbar(WID_AP_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AP_SCROLLBAR), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_DECREASE), SetSizingType(NWST_STEP), SetMinimalSize(12, 0), SetDataTip(AWV_DECREASE, STR_NULL), + NWidget(WWT_LABEL, COLOUR_GREY, WID_AP_LAYOUT_NUM), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NULL), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_INCREASE), SetSizingType(NWST_STEP), SetMinimalSize(12, 0), SetDataTip(AWV_INCREASE, STR_NULL), + EndContainer(), + NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_EXTRA_TEXT), SetFill(1, 0), SetMinimalSize(150, 0), + EndContainer(), + /* Bottom panel. */ + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_AP_BOTTOMPANEL), SetPIP(2, 2, 2), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DONTHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), + SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DOHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), + SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1), SetFill(1, 0), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1), SetFill(1, 0), EndContainer(), }; From ac10a8c8cf35e197ef8d943daf35c0cabe297924 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 31 May 2014 23:30:20 +0300 Subject: [PATCH 123/187] Added broken 16bpp animated blitter --- source.list | 4 +- src/blitter/16bpp_anim.cpp | 386 +++++++++++++++++++++++++++++++++++ src/blitter/16bpp_anim.hpp | 75 +++++++ src/blitter/16bpp_base.cpp | 14 +- src/blitter/16bpp_base.hpp | 2 +- src/blitter/16bpp_simple.cpp | 24 ++- src/blitter/16bpp_simple.hpp | 3 +- 7 files changed, 489 insertions(+), 19 deletions(-) create mode 100644 src/blitter/16bpp_anim.cpp create mode 100644 src/blitter/16bpp_anim.hpp diff --git a/source.list b/source.list index 7a500c3d97..83144a9b2b 100644 --- a/source.list +++ b/source.list @@ -906,8 +906,8 @@ script/api/script_window.cpp #else blitter/16bpp_base.cpp blitter/16bpp_base.hpp -# blitter/16bpp_anim.cpp -# blitter/16bpp_anim.hpp +blitter/16bpp_anim.cpp +blitter/16bpp_anim.hpp blitter/16bpp_simple.cpp blitter/16bpp_simple.hpp blitter/32bpp_anim.cpp diff --git a/src/blitter/16bpp_anim.cpp b/src/blitter/16bpp_anim.cpp new file mode 100644 index 0000000000..2b077ef475 --- /dev/null +++ b/src/blitter/16bpp_anim.cpp @@ -0,0 +1,386 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file 16bpp_anim.cpp Implementation of the optimized 32 bpp blitter with animation support. */ + +#include "../stdafx.h" +#include "../video/video_driver.hpp" +#include "../zoom_func.h" +#include "16bpp_anim.hpp" + +#include "../table/sprites.h" + +/** Instantiation of the 16bpp with animation blitter factory. */ +static FBlitter_16bppAnim iFBlitter_16bppAnim; + +template +void Blitter_16bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) +{ + const Pixel *src, *src_line; + Colour16 *dst, *dst_line; + Anim *anim, *anim_line; + + /* Find where to start reading in the source sprite */ + src_line = (const Pixel *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom); + dst_line = (Colour16 *)bp->dst + bp->top * bp->pitch + bp->left; + anim_line = this->anim_buf + ((Colour16 *)bp->dst - (Colour16 *)_screen.dst_ptr) + bp->top * this->anim_buf_width + bp->left; + + for (int y = 0; y < bp->height; y++) { + dst = dst_line; + dst_line += bp->pitch; + + src = src_line; + src_line += bp->sprite_width * ScaleByZoom(1, zoom); + + anim = anim_line; + anim_line += this->anim_buf_width; + + for (int x = 0; x < bp->width; x++) { + switch (mode) { + case BM_COLOUR_REMAP: + /* In case the m-channel is zero, do not remap this pixel in any way */ + anim->m = 0; + anim->v = 0; + if (src->m == 0) { + if (src->a != 0) *dst = ComposeColourPA(src->c, src->a, *dst); + } else { + uint8 r = bp->remap[src->m]; + if (r != 0) { + *dst = ComposeColourPA(AdjustBrightness(LookupColourInPalette(r), src->v), src->a, *dst); + if (src->a == 15 && r >= PALETTE_ANIM_START) { + anim->m = r - PALETTE_ANIM_START + 1; + anim->v = src->v >> 1; + } + } + } + break; + + case BM_TRANSPARENT: + /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour. + * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: + * we produce a result the newgrf maker didn't expect ;) */ + + /* Make the current colour a bit more black, so it looks like this image is transparent */ + if (src->a != 0) *dst = MakeTransparent(*dst, 192); + anim->m = 0; + anim->v = 0; + break; + + default: + if (src->a == 15 && src->m >= PALETTE_ANIM_START) { + *dst = AdjustBrightness(LookupColourInPalette(src->m), src->v); + anim->m = src->m - PALETTE_ANIM_START + 1; + anim->v = src->v >> 1; + } else { + if (src->a != 0) { + if (src->m >= PALETTE_ANIM_START) { + *dst = ComposeColourPANoCheck(AdjustBrightness(LookupColourInPalette(src->m), src->v), src->a, *dst); + } else { + *dst = ComposeColourPA(src->c, src->a, *dst); + } + } + anim->m = 0; + anim->v = 0; + } + break; + } + dst++; + src += ScaleByZoom(1, zoom); + } + } +} + +void Blitter_16bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +{ + if (_screen_disable_anim) { + /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent Draw() */ + Blitter_16bppOptimized::Draw(bp, mode, zoom); + return; + } + + switch (mode) { + default: NOT_REACHED(); + case BM_NORMAL: Draw (bp, zoom); return; + case BM_COLOUR_REMAP: Draw(bp, zoom); return; + case BM_TRANSPARENT: Draw (bp, zoom); return; + } +} + +void Blitter_16bppAnim::DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) +{ + if (_screen_disable_anim) { + /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawColourMappingRect() */ + Blitter_16bppOptimized::DrawColourMappingRect(dst, width, height, pal); + return; + } + + Colour16 *udst = (Colour16 *)dst; + Anim *anim; + + anim = this->anim_buf + ((Colour16 *)dst - (Colour16 *)_screen.dst_ptr); + + if (pal == PALETTE_TO_TRANSPARENT) { + do { + for (int i = 0; i != width; i++) { + *udst = MakeTransparent(*udst, 154); + anim->m = 0; + anim->v = 0; + udst++; + anim++; + } + udst = udst - width + _screen.pitch; + anim = anim - width + this->anim_buf_width; + } while (--height); + return; + } + if (pal == PALETTE_NEWSPAPER) { + do { + for (int i = 0; i != width; i++) { + *udst = MakeGrey(*udst); + anim->m = 0; + anim->v = 0; + udst++; + anim++; + } + udst = udst - width + _screen.pitch; + anim = anim - width + this->anim_buf_width; + } while (--height); + return; + } + + DEBUG(misc, 0, "16bpp blitter doesn't know how to draw this colour table ('%d')", pal); +} + +void Blitter_16bppAnim::SetPixel(void *video, int x, int y, uint8 colour) +{ + *((Colour16 *)video + x + y * _screen.pitch) = LookupColourInPalette(colour); + + /* Set the colour in the anim-buffer too, if we are rendering to the screen */ + if (_screen_disable_anim) return; + Anim *anim = this->anim_buf + ((Colour16 *)video - (Colour16 *)_screen.dst_ptr) + x + y * this->anim_buf_width; + if (colour >= PALETTE_ANIM_START) { + anim->m = colour - PALETTE_ANIM_START + 1; + anim->v = DEFAULT_BRIGHTNESS >> 1; + } else { + anim->m = 0; + anim->v = 0; + } +} + +void Blitter_16bppAnim::DrawRect(void *video, int width, int height, uint8 colour) +{ + if (_screen_disable_anim) { + /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */ + Blitter_16bppOptimized::DrawRect(video, width, height, colour); + return; + } + + Colour16 colour16 = LookupColourInPalette(colour); + Anim *anim_line = this->anim_buf + ((Colour16 *)video - (Colour16 *)_screen.dst_ptr); + + do { + Colour16 *dst = (Colour16 *)video; + Anim *anim = anim_line; + + for (int i = width; i > 0; i--) { + *dst = colour16; + /* Set the colour in the anim-buffer too */ + if (colour >= PALETTE_ANIM_START) { + anim->m = colour - PALETTE_ANIM_START + 1; + anim->v = DEFAULT_BRIGHTNESS >> 1; + } else { + anim->m = 0; + anim->v = 0; + } + dst++; + anim++; + } + video = (Colour16 *)video + _screen.pitch; + anim_line += this->anim_buf_width; + } while (--height); +} + +void Blitter_16bppAnim::CopyFromBuffer(void *video, const void *src, int width, int height) +{ + assert(!_screen_disable_anim); + assert(video >= _screen.dst_ptr && video <= (Colour16 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch); + Colour16 *dst = (Colour16 *)video; + const uint8 *usrc = (const uint8 *)src; + Anim *anim_line = this->anim_buf + ((Colour16 *)video - (Colour16 *)_screen.dst_ptr); + + for (; height > 0; height--) { + /* We need to keep those for palette animation. */ + Colour16 *dst_pal = dst; + Anim *anim_pal = anim_line; + + memcpy(dst, usrc, width * sizeof(Colour16)); + usrc += width * sizeof(Colour16); + dst += _screen.pitch; + /* Copy back the anim-buffer */ + memcpy(anim_line, usrc, width * sizeof(Anim)); + usrc += width * sizeof(Anim); + anim_line += this->anim_buf_width; + + /* Okay, it is *very* likely that the image we stored is using + * the wrong palette animated colours. There are two things we + * can do to fix this. The first is simply reviewing the whole + * screen after we copied the buffer, i.e. run PaletteAnimate, + * however that forces a full screen redraw which is expensive + * for just the cursor. This just copies the implementation of + * palette animation, much cheaper though slightly nastier. */ + for (int i = 0; i < width; i++) { + uint8 colour = anim_pal->m; + if (colour) { + /* Update this pixel */ + *dst_pal = AdjustBrightness(LookupColourInPalette(colour + PALETTE_ANIM_START - 1), anim_pal->v << 1); + } + dst_pal++; + anim_pal++; + } + } +} + +void Blitter_16bppAnim::CopyToBuffer(const void *video, void *dst, int width, int height) +{ + assert(!_screen_disable_anim); + assert(video >= _screen.dst_ptr && video <= (Colour16 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch); + uint8 *udst = (uint8 *)dst; + const Colour16 *src = (const Colour16 *)video; + const Anim *anim_line = this->anim_buf + ((const Colour16 *)video - (Colour16 *)_screen.dst_ptr); + + for (; height > 0; height--) { + memcpy(udst, src, width * sizeof(Colour16)); + src += _screen.pitch; + udst += width * sizeof(Colour16); + /* Copy the anim-buffer */ + memcpy(udst, anim_line, width * sizeof(Anim)); + udst += width * sizeof(Anim); + anim_line += this->anim_buf_width; + } +} + +void Blitter_16bppAnim::ScrollBuffer(void *video, int &left_ref, int &top_ref, int &width_ref, int &height_ref, int scroll_x, int scroll_y) +{ + assert(!_screen_disable_anim); + assert(video >= _screen.dst_ptr && video <= (Colour16 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch); + const Anim *src; + Anim *dst; + int left = left_ref, top = top_ref, width = width_ref, height = height_ref; + + /* We need to scroll the anim-buffer too */ + if (scroll_y > 0) { + /* Calculate pointers */ + dst = this->anim_buf + left + (top + height - 1) * this->anim_buf_width; + src = dst - scroll_y * this->anim_buf_width; + + /* Decrease height and increase top */ + top += scroll_y; + height -= scroll_y; + assert(height > 0); + + /* Adjust left & width */ + if (scroll_x >= 0) { + dst += scroll_x; + left += scroll_x; + width -= scroll_x; + } else { + src -= scroll_x; + width += scroll_x; + } + + for (int h = height; h > 0; h--) { + memcpy(dst, src, width * sizeof(Anim)); + src -= this->anim_buf_width; + dst -= this->anim_buf_width; + } + } else { + /* Calculate pointers */ + dst = this->anim_buf + left + top * this->anim_buf_width; + src = dst - scroll_y * this->anim_buf_width; + + /* Decrease height. (scroll_y is <=0). */ + height += scroll_y; + assert(height > 0); + + /* Adjust left & width */ + if (scroll_x >= 0) { + dst += scroll_x; + left += scroll_x; + width -= scroll_x; + } else { + src -= scroll_x; + width += scroll_x; + } + + /* the y-displacement may be 0 therefore we have to use memmove, + * because source and destination may overlap */ + for (int h = height; h > 0; h--) { + memmove(dst, src, width * sizeof(Anim)); + src += _screen.pitch; + dst += _screen.pitch; + } + } + + Blitter_16bppOptimized::ScrollBuffer(video, left_ref, top_ref, width_ref, height_ref, scroll_x, scroll_y); +} + +int Blitter_16bppAnim::BufferSize(int width, int height) +{ + return width * height * (sizeof(Anim) + sizeof(Colour16)); +} + +void Blitter_16bppAnim::PaletteAnimate(const Palette &palette) +{ + assert(!_screen_disable_anim); + + /* If first_dirty is 0, it is for 8bpp indication to send the new + * palette. However, only the animation colours might possibly change. + * Especially when going between toyland and non-toyland. */ + assert(palette.first_dirty == PALETTE_ANIM_START || palette.first_dirty == 0); + + for (int i = 0; i < 256; i++) { + this->palette[i] = To16(palette.palette[i]); + } + + const Anim *anim = this->anim_buf; + Colour16 *dst = (Colour16 *)_screen.dst_ptr; + + /* Let's walk the anim buffer and try to find the pixels */ + for (int y = this->anim_buf_height; y != 0 ; y--) { + for (int x = this->anim_buf_width; x != 0 ; x--) { + uint8 colour = anim->m; + if (colour) { + /* Update this pixel */ + *dst = AdjustBrightness(LookupColourInPalette(colour + PALETTE_ANIM_START - 1), anim->v << 1); + } + dst++; + anim++; + } + dst += _screen.pitch - this->anim_buf_width; + } + + /* Make sure the backend redraws the whole screen */ + _video_driver->MakeDirty(0, 0, _screen.width, _screen.height); +} + +Blitter::PaletteAnimation Blitter_16bppAnim::UsePaletteAnimation() +{ + return Blitter::PALETTE_ANIMATION_BLITTER; +} + +void Blitter_16bppAnim::PostResize() +{ + if (_screen.width != this->anim_buf_width || _screen.height != this->anim_buf_height) { + /* The size of the screen changed; we can assume we can wipe all data from our buffer */ + free(this->anim_buf); + this->anim_buf = CallocT(_screen.width * _screen.height); + this->anim_buf_width = _screen.width; + this->anim_buf_height = _screen.height; + } +} diff --git a/src/blitter/16bpp_anim.hpp b/src/blitter/16bpp_anim.hpp new file mode 100644 index 0000000000..80bf6e5df5 --- /dev/null +++ b/src/blitter/16bpp_anim.hpp @@ -0,0 +1,75 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file 16bpp_anim.hpp A 16 bpp blitter with animation support. */ + +#ifndef BLITTER_16BPP_ANIM_HPP +#define BLITTER_16BPP_ANIM_HPP + +#include "16bpp_simple.hpp" + +class Blitter_16bppOptimized: public Blitter_16bppSimple { + // TODO: implement that +}; + +/** The optimised 16 bpp blitter with palette animation. */ +class Blitter_16bppAnim : public Blitter_16bppOptimized { +protected: + // PALETTE_ANIM_SIZE is less than 32, so we'll use 5 bits for color index, and 3 bits for brightness, losing 1 bit compared to struct Pixel + struct Anim { + unsigned m : 5 __attribute__((packed)); ///< Color index channel, packed 5 bits, 0 = no animation, 1 = PALETTE_ANIM_START + unsigned v : 3 __attribute__((packed)); ///< Brightness-channel, packed 3 bits + }; + + Anim *anim_buf; ///< In this buffer we keep track of the 8bpp indexes so we can do palette animation + int anim_buf_width; ///< The width of the animation buffer. + int anim_buf_height; ///< The height of the animation buffer. + Colour16 palette[256]; ///< The current palette. + +public: + Blitter_16bppAnim() : + anim_buf(NULL), + anim_buf_width(0), + anim_buf_height(0) + {} + + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + /* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal); + /* virtual */ void SetPixel(void *video, int x, int y, uint8 colour); + /* virtual */ void DrawRect(void *video, int width, int height, uint8 colour); + /* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height); + /* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height); + /* virtual */ void ScrollBuffer(void *video, int &left_ref, int &top_ref, int &width_ref, int &height_ref, int scroll_x, int scroll_y); + /* virtual */ int BufferSize(int width, int height); + /* virtual */ void PaletteAnimate(const Palette &palette); + /* virtual */ Blitter::PaletteAnimation UsePaletteAnimation(); + /* virtual */ int GetBytesPerPixel() { return 3; } + + /* virtual */ const char *GetName() { return "16bpp-anim"; } + /* virtual */ void PostResize(); + + /** + * Look up the colour in the current palette. + */ + inline Colour16 LookupColourInPalette(uint8 index) + { + return this->palette[index]; + } + + template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); +}; + +/** Factory for the 16bpp blitter with animation. */ +class FBlitter_16bppAnim : public BlitterFactory { +public: + FBlitter_16bppAnim() : BlitterFactory("16bpp-anim-broken", "16bpp Animation Blitter, currently broken (palette animation)") {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_16bppAnim(); } +}; + +#endif /* BLITTER_16BPP_ANIM_HPP */ diff --git a/src/blitter/16bpp_base.cpp b/src/blitter/16bpp_base.cpp index 69424fad4d..9161ce92c4 100644 --- a/src/blitter/16bpp_base.cpp +++ b/src/blitter/16bpp_base.cpp @@ -74,12 +74,12 @@ void Blitter_16bppBase::CopyImageToBuffer(const void *video, void *dst, int widt void Blitter_16bppBase::ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) { - const uint16 *src; - uint16 *dst; + const Colour16 *src; + Colour16 *dst; if (scroll_y > 0) { /* Calculate pointers */ - dst = (uint16 *)video + left + (top + height - 1) * _screen.pitch; + dst = (Colour16 *)video + left + (top + height - 1) * _screen.pitch; src = dst - scroll_y * _screen.pitch; /* Decrease height and increase top */ @@ -98,13 +98,13 @@ void Blitter_16bppBase::ScrollBuffer(void *video, int &left, int &top, int &widt } for (int h = height; h > 0; h--) { - memcpy(dst, src, width * sizeof(uint16)); + memcpy(dst, src, width * sizeof(Colour16)); src -= _screen.pitch; dst -= _screen.pitch; } } else { /* Calculate pointers */ - dst = (uint16 *)video + left + top * _screen.pitch; + dst = (Colour16 *)video + left + top * _screen.pitch; src = dst - scroll_y * _screen.pitch; /* Decrease height. (scroll_y is <=0). */ @@ -124,7 +124,7 @@ void Blitter_16bppBase::ScrollBuffer(void *video, int &left, int &top, int &widt /* the y-displacement may be 0 therefore we have to use memmove, * because source and destination may overlap */ for (int h = height; h > 0; h--) { - memmove(dst, src, width * sizeof(uint16)); + memmove(dst, src, width * sizeof(Colour16)); src += _screen.pitch; dst += _screen.pitch; } @@ -133,7 +133,7 @@ void Blitter_16bppBase::ScrollBuffer(void *video, int &left, int &top, int &widt int Blitter_16bppBase::BufferSize(int width, int height) { - return width * height * sizeof(uint16); + return width * height * sizeof(Colour16); } void Blitter_16bppBase::PaletteAnimate(const Palette &palette) diff --git a/src/blitter/16bpp_base.hpp b/src/blitter/16bpp_base.hpp index e5425d809f..e7a5b5e7a9 100644 --- a/src/blitter/16bpp_base.hpp +++ b/src/blitter/16bpp_base.hpp @@ -26,7 +26,7 @@ public: unsigned b : 5 __attribute__((packed)); ///< Blue-channel, packed 5 bits unsigned g : 6 __attribute__((packed)); ///< Green-channel, packed 6 bits unsigned r : 5 __attribute__((packed)); ///< Red-channel, packed 5 bits - Colour16(uint8 r, uint8 g, uint8 b): + Colour16(uint8 r = 0, uint8 g = 0, uint8 b = 0): b(b), g(g), r(r) { } diff --git a/src/blitter/16bpp_simple.cpp b/src/blitter/16bpp_simple.cpp index a3e1f4d0ed..36f90f17b6 100644 --- a/src/blitter/16bpp_simple.cpp +++ b/src/blitter/16bpp_simple.cpp @@ -12,16 +12,14 @@ #include "../stdafx.h" #include "../zoom_func.h" #include "16bpp_simple.hpp" -#include "32bpp_base.hpp" #include "../table/sprites.h" -#include - /** Instantiation of the simple 16bpp blitter factory. */ static FBlitter_16bppSimple iFBlitter_16bppSimple; -void Blitter_16bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +template +void Blitter_16bppSimple::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) { const Pixel *src, *src_line; Colour16 *dst, *dst_line; @@ -44,7 +42,7 @@ void Blitter_16bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoo if (src->m == 0) { if (src->a != 0) *dst = ComposeColourPA(src->c, src->a, *dst); } else { - if (bp->remap[src->m] != 0) *dst = ComposeColourPA(this->AdjustBrightness(this->LookupColourInPalette(bp->remap[src->m]), src->v), src->a, *dst); + if (bp->remap[src->m] != 0) *dst = ComposeColourPA(AdjustBrightness(LookupColourInPalette(bp->remap[src->m]), src->v), src->a, *dst); } break; @@ -67,6 +65,16 @@ void Blitter_16bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoo } } +void Blitter_16bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +{ + switch (mode) { + default: NOT_REACHED(); + case BM_NORMAL: Draw (bp, zoom); return; + case BM_COLOUR_REMAP: Draw(bp, zoom); return; + case BM_TRANSPARENT: Draw (bp, zoom); return; + } +} + void Blitter_16bppSimple::DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) { Colour16 *udst = (Colour16 *)dst; @@ -122,18 +130,18 @@ Sprite *Blitter_16bppSimple::Encode(const SpriteLoader::Sprite *sprite, Allocato use 32bpp AdjustBrightness() variant for better colors, because this function is not called each frame */ if (rgb_max == 0) rgb_max = Blitter_32bppBase::DEFAULT_BRIGHTNESS; - dst[i].c = To16(Blitter_32bppBase::AdjustBrightness(this->LookupColourInPalette32(src->m), rgb_max)); + dst[i].c = To16(Blitter_32bppBase::AdjustBrightness(LookupColourInPalette32(src->m), rgb_max)); dst[i].v = rgb_max / 16; #endif rgb_max /= 16; - /* Black pixel (8bpp or old 16bpp image), so use default value */ + /* Black pixel (8bpp or old 32bpp image), so use default value */ if (rgb_max == 0) rgb_max = DEFAULT_BRIGHTNESS; /* Pre-convert the mapping channel to a RGB value, use 32bpp AdjustBrightness() variant for better colors, because this function is not called each frame */ - dst[i].c = AdjustBrightness(this->LookupColourInPalette(src->m), rgb_max); + dst[i].c = AdjustBrightness(LookupColourInPalette(src->m), rgb_max); dst[i].v = rgb_max; dst[i].a = src->a / 16; diff --git a/src/blitter/16bpp_simple.hpp b/src/blitter/16bpp_simple.hpp index e708ce9a93..9feb934062 100644 --- a/src/blitter/16bpp_simple.hpp +++ b/src/blitter/16bpp_simple.hpp @@ -21,6 +21,7 @@ public: /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); /* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal); /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); + template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); /* virtual */ const char *GetName() { return "16bpp-simple"; } }; @@ -32,4 +33,4 @@ public: /* virtual */ Blitter *CreateInstance() { return new Blitter_16bppSimple(); } }; -#endif /* BLITTER_32BPP_SIMPLE_HPP */ +#endif /* BLITTER_16BPP_SIMPLE_HPP */ From 7fb35a10ab9e704d64a4c65632eabd6ec3bc862e Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 31 May 2014 23:57:32 +0300 Subject: [PATCH 124/187] Fixed right mouse click scrolling --- src/video/sdl_v.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index 64ce2911be..c5d505a1f6 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -549,7 +549,12 @@ int VideoDriver_SDL::PollEvent() switch (ev.type) { case SDL_MOUSEMOTION: +#ifdef __ANDROID__ + // No mouse warping on Android, mouse strictly follows finger + if (false) { +#else if (_cursor.fix_at) { +#endif int dx = ev.motion.x - _cursor.pos.x; int dy = ev.motion.y - _cursor.pos.y; if (dx != 0 || dy != 0) { From d2feaa93166a55305576e83ad8feb309e78fa53d Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 1 Jun 2014 00:29:56 +0300 Subject: [PATCH 125/187] Two-finger scrolling will cancel whatever action that was currently selected --- src/video/sdl_v.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index c5d505a1f6..c20cac2cfa 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -24,6 +24,7 @@ #include "../core/math_func.hpp" #include "../fileio_func.h" #include "../settings_type.h" +#include "../tilehighlight_func.h" #include "sdl_v.h" #include #ifdef __ANDROID__ @@ -603,6 +604,13 @@ int VideoDriver_SDL::PollEvent() } else if (ev.button.button == SDL_BUTTON_LEFT) { _left_button_down = false; _left_button_clicked = false; +#ifdef __ANDROID__ + if (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_RMASK) { + // Two-finger click - hacky way to determine if the right mouse button is already pressed without processing the left button event + // Cancel whatewer action we were doing, to allow two finger scrolling + ResetObjectToPlace(); + } +#endif } else if (ev.button.button == SDL_BUTTON_RIGHT) { _right_button_down = false; } From f469e7f57bdbf9deafd6bc4b954ecf3f68ae1fac Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 1 Jun 2014 01:23:34 +0300 Subject: [PATCH 126/187] Show info about facility/station/vehicle on mouse up instead of mouse down, to allow better map dragging. --- src/viewport.cpp | 18 ++++++++++++------ src/viewport_func.h | 1 + src/window.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/viewport.cpp b/src/viewport.cpp index 84aa495469..de4577d962 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1953,18 +1953,24 @@ bool HandleViewportClicked(const ViewPort *vp, int x, int y) { if (_move_pressed) return false; + if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) { + PlaceObject(); + return true; + } + + return false; +} + +bool HandleViewportMouseUp(const ViewPort *vp, int x, int y) +{ + if (_move_pressed) return false; + const Vehicle *v = CheckClickOnVehicle(vp, x, y); if (_thd.place_mode & HT_VEHICLE) { if (v != NULL && VehicleClicked(v)) return true; } - /* Vehicle placement mode already handled above. */ - if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) { - PlaceObject(); - return true; - } - if (CheckClickOnTown(vp, x, y)) return true; if (CheckClickOnStation(vp, x, y)) return true; if (CheckClickOnSign(vp, x, y)) return true; diff --git a/src/viewport_func.h b/src/viewport_func.h index 7d86dda989..baa06e48ca 100644 --- a/src/viewport_func.h +++ b/src/viewport_func.h @@ -59,6 +59,7 @@ void StartSpriteCombine(); void EndSpriteCombine(); bool HandleViewportClicked(const ViewPort *vp, int x, int y); +bool HandleViewportMouseUp(const ViewPort *vp, int x, int y); void SetRedErrorSquare(TileIndex tile); void SetTileSelectSize(int w, int h); void SetTileSelectBigSize(int ox, int oy, int sx, int sy); diff --git a/src/window.cpp b/src/window.cpp index 4279f80786..c4c4f7e3a6 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -80,6 +80,7 @@ byte _scroller_click_timeout = 0; bool _scrolling_viewport; ///< A viewport is being scrolled with the mouse. bool _mouse_hovering; ///< The mouse is hovering over the same point. +static bool _left_button_dragged; SpecialMouseMode _special_mouse_mode; ///< Mode of the mouse. @@ -2397,6 +2398,21 @@ static EventState HandleViewportScroll() { bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); + if (_settings_client.gui.left_mouse_btn_scrolling) { + // Do not open vehicle/town info window while scrolling with left mouse button + static int oldDx = 0, oldDy = 0; + if (_left_button_down) { + oldDx += _cursor.delta.x; + oldDy += _cursor.delta.y; + if (!_left_button_dragged && abs(oldDx) + abs(oldDy) > 20) { + _left_button_dragged = true; + } + } else { + oldDx = 0; + oldDy = 0; + } + } + if (!_scrolling_viewport) return ES_NOT_HANDLED; /* When we don't have a last scroll window we are starting to scroll. @@ -2735,6 +2751,7 @@ static void HandleAutoscroll() enum MouseClick { MC_NONE = 0, MC_LEFT, + MC_LEFT_UP, MC_RIGHT, MC_DOUBLE_LEFT, MC_HOVER, @@ -2857,6 +2874,13 @@ static void MouseLoop(MouseClick click, int mousewheel) } break; + case MC_LEFT_UP: + if (!_left_button_dragged) { + HandleViewportMouseUp(vp, x, y); + } + _left_button_dragged = false; + break; + case MC_RIGHT: if (!(w->flags & WF_DISABLE_VP_SCROLL)) { _scrolling_viewport = true; @@ -2873,6 +2897,9 @@ static void MouseLoop(MouseClick click, int mousewheel) } } else { switch (click) { + case MC_LEFT_UP: + break; + case MC_LEFT: case MC_DOUBLE_LEFT: DispatchLeftClickEvent(w, x - w->left, y - w->top, click == MC_DOUBLE_LEFT ? 2 : 1); @@ -2902,6 +2929,7 @@ void HandleMouseEvents() static int double_click_time = 0; static Point double_click_pos = {0, 0}; + static bool left_button_released = false; /* Mouse event? */ MouseClick click = MC_NONE; @@ -2915,11 +2943,17 @@ void HandleMouseEvents() double_click_time = _realtime_tick; double_click_pos = _cursor.pos; _left_button_clicked = true; + left_button_released = false; _input_events_this_tick++; } else if (_right_button_clicked) { _right_button_clicked = false; click = MC_RIGHT; _input_events_this_tick++; + } else if(!_left_button_down && !left_button_released) { + click = MC_LEFT_UP; + left_button_released = true; + _left_button_clicked = false; + _input_events_this_tick++; } int mousewheel = 0; From 7dd42939ae6e285629964d4046a393fbc3ad2912 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 1 Jun 2014 01:32:30 +0300 Subject: [PATCH 127/187] Align opened windows with toolbar --- src/window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.cpp b/src/window.cpp index c4c4f7e3a6..ad63eb343f 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1594,7 +1594,7 @@ static Point GetAutoPlacePosition(int width, int height) /* First attempt, try top-left of the screen */ const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); - if (IsGoodAutoPlace1(0, main_toolbar != NULL ? main_toolbar->height + 2 : 2, width, height, pt)) return pt; + if (IsGoodAutoPlace1(0, main_toolbar != NULL ? main_toolbar->height : 0, width, height, pt)) return pt; /* Second attempt, try around all existing windows with a distance of 2 pixels. * The new window must be entirely on-screen, and not overlap with an existing window. From 9f780643ed36179934b0b31873b18378bb866e6f Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 1 Jun 2014 13:45:45 +0300 Subject: [PATCH 128/187] WIP do not compile - split toolbar into two vertical toolbars --- src/lang/english.txt | 2 + src/settings.cpp | 6 ++ src/settings_type.h | 1 + src/table/settings.ini | 9 +++ src/toolbar_gui.cpp | 128 +++++++++++++++++++++++++++++------------ src/window.cpp | 6 +- 6 files changed, 114 insertions(+), 38 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index b5a81a7093..601a929e2c 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1184,6 +1184,8 @@ STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :Select on which STR_CONFIG_SETTING_SIGNALSIDE_LEFT :On the left STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :On the driving side STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :On the right +STR_CONFIG_SETTING_VERTICAL_TOOLBAR :Vertical toolbar +STR_CONFIG_SETTING_VERTICAL_TOOLBAR_HELPTEXT :Main toolbar is split into two vertical toolbars on the sides of the screen STR_CONFIG_SETTING_TOUCHSCREEN_MODE :Control mode for touchscreen devices: {STRING2} STR_CONFIG_SETTING_TOUCHSCREEN_MODE_HELPTEXT :If playing with a mouse, choose no adaptation. Other modes are for touchscreen devices. Associated hotkey: N STR_CONFIG_SETTING_TOUCHSCREEN_NONE :no adaptation diff --git a/src/settings.cpp b/src/settings.cpp index 16f8f5d15b..51db18d4b0 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1070,6 +1070,12 @@ static bool ZoomMinMaxChanged(int32 p1) return true; } +static bool VerticalToolbarChanged(int32 p1) +{ + + return true; +} + static bool TouchscreenModeChanged(int32 p1) { //ResetTabletWindow(); diff --git a/src/settings_type.h b/src/settings_type.h index b38aab3781..84ec1ab559 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -78,6 +78,7 @@ struct GUISettings { bool lost_vehicle_warn; ///< if a vehicle can't find its destination, show a warning uint8 order_review_system; ///< perform order reviews on vehicles bool vehicle_income_warn; ///< if a vehicle isn't generating income, show a warning + bool vertical_toolbar; ///< main toolbar is split into two vertical toolbars TouchscreenModeByte touchscreen_mode; ///< touchscreen mode for toolbars uint min_button; ///< min size of most button widgets uint min_step; ///< min size of scrollbar/dropdown elements diff --git a/src/table/settings.ini b/src/table/settings.ini index c742c0f657..9c74ff99a1 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -2497,6 +2497,15 @@ str = STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES strhelp = STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT strval = STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG +[SDTC_BOOL] +var = gui.vertical_toolbar +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = true +str = STR_CONFIG_SETTING_VERTICAL_TOOLBAR +strhelp = STR_CONFIG_SETTING_VERTICAL_TOOLBAR_HELPTEXT +proc = VerticalToolbarChanged +cat = SC_BASIC + [SDTC_VAR] var = gui.touchscreen_mode flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 22d58990d7..11033c7380 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1339,7 +1339,7 @@ protected: uint spacers; ///< Number of spacer widgets in this toolbar public: - NWidgetToolbarContainer() : NWidgetContainer(NWID_HORIZONTAL) + NWidgetToolbarContainer(enum widgetType = NWID_HORIZONTAL) : NWidgetContainer(widgetType) { } @@ -1916,48 +1916,48 @@ static Hotkey maintoolbar_hotkeys[] = { }; HotkeyList MainToolbarWindow::hotkeys("maintoolbar", maintoolbar_hotkeys); +/** Sprites to use for the different toolbar buttons */ +static const SpriteID _toolbar_button_sprites[] = { + SPR_IMG_PAUSE, // WID_TN_PAUSE + SPR_IMG_FASTFORWARD, // WID_TN_FAST_FORWARD + SPR_IMG_SETTINGS, // WID_TN_SETTINGS + SPR_IMG_SAVE, // WID_TN_SAVE + SPR_IMG_SMALLMAP, // WID_TN_SMALL_MAP + SPR_IMG_TOWN, // WID_TN_TOWNS + SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES + SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS + SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES + SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES + SPR_IMG_STORY_BOOK, // WID_TN_STORY + SPR_IMG_GOAL, // WID_TN_GOAL + SPR_IMG_GRAPHS, // WID_TN_GRAPHS + SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE + SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES + SPR_IMG_TRAINLIST, // WID_TN_TRAINS + SPR_IMG_TRUCKLIST, // WID_TN_ROADVEHS + SPR_IMG_SHIPLIST, // WID_TN_SHIPS + SPR_IMG_AIRPLANESLIST, // WID_TN_AIRCRAFT + SPR_IMG_ZOOMIN, // WID_TN_ZOOMIN + SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT + SPR_IMG_BUILDRAIL, // WID_TN_RAILS + SPR_IMG_BUILDROAD, // WID_TN_ROADS + SPR_IMG_BUILDWATER, // WID_TN_WATER + SPR_IMG_BUILDAIR, // WID_TN_AIR + SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE + SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND + SPR_IMG_MESSAGES, // WID_TN_MESSAGES + SPR_IMG_QUERY, // WID_TN_HELP + SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR +}; + static NWidgetBase *MakeMainToolbar(int *biggest_index) { - /** Sprites to use for the different toolbar buttons */ - static const SpriteID toolbar_button_sprites[] = { - SPR_IMG_PAUSE, // WID_TN_PAUSE - SPR_IMG_FASTFORWARD, // WID_TN_FAST_FORWARD - SPR_IMG_SETTINGS, // WID_TN_SETTINGS - SPR_IMG_SAVE, // WID_TN_SAVE - SPR_IMG_SMALLMAP, // WID_TN_SMALL_MAP - SPR_IMG_TOWN, // WID_TN_TOWNS - SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES - SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS - SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES - SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES - SPR_IMG_STORY_BOOK, // WID_TN_STORY - SPR_IMG_GOAL, // WID_TN_GOAL - SPR_IMG_GRAPHS, // WID_TN_GRAPHS - SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE - SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES - SPR_IMG_TRAINLIST, // WID_TN_TRAINS - SPR_IMG_TRUCKLIST, // WID_TN_ROADVEHS - SPR_IMG_SHIPLIST, // WID_TN_SHIPS - SPR_IMG_AIRPLANESLIST, // WID_TN_AIRCRAFT - SPR_IMG_ZOOMIN, // WID_TN_ZOOMIN - SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT - SPR_IMG_BUILDRAIL, // WID_TN_RAILS - SPR_IMG_BUILDROAD, // WID_TN_ROADS - SPR_IMG_BUILDWATER, // WID_TN_WATER - SPR_IMG_BUILDAIR, // WID_TN_AIR - SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE - SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND - SPR_IMG_MESSAGES, // WID_TN_MESSAGES - SPR_IMG_QUERY, // WID_TN_HELP - SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR - }; - NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer(); for (uint i = 0; i <= WID_TN_SWITCH_BAR; i++) { switch (i) { case 4: case 8: case 15: case 19: case 21: case 26: hor->Add(new NWidgetSpacer(0, 0)); break; } - hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); + hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, _toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); } hor->Add(new NWidgetSpacer(0, 0)); @@ -1981,6 +1981,55 @@ static WindowDesc _toolb_normal_desc( &MainToolbarWindow::hotkeys ); +static NWidgetBase *MakeVerticalLeftToolbar(int *biggest_index) +{ + NWidgetVerticalToolbarContainer *tb = new NWidgetVerticalToolbarContainer(0); + for (uint i = 0; i <= WID_TN_SWITCH_BAR; i++) { + tb->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, _toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); + } + + tb->Add(new NWidgetLeaf(WWT_TEXTBTN, COLOUR_GREY, WID_TN_CTRL, STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP)); + tb->Add(new NWidgetLeaf(WWT_TEXTBTN, COLOUR_GREY, WID_TN_SHIFT, STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP)); + tb->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TN_DELETE, STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP)); + + *biggest_index = max(*biggest_index, WID_TN_DELETE); + return tb; +} + +static NWidgetBase *MakeVerticalRigthToolbar(int *biggest_index) +{ + NWidgetVerticalToolbarContainer *tb = new NWidgetVerticalToolbarContainer(1); + for (uint i = 0; i <= WID_TN_SWITCH_BAR; i++) { + tb->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, _toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); + } + + *biggest_index = max(*biggest_index, WID_TN_DELETE); + return tb; +} + +static const NWidgetPart _nested_toolbar_vertical_left_widgets[] = { + NWidgetFunction(MakeVerticalLeftToolbar), +}; + +static WindowDesc _toolb_vertical_left_desc( + WDP_MANUAL, NULL, 22, 480, + WC_MAIN_TOOLBAR, WC_NONE, + WDF_NO_FOCUS, + _nested_toolbar_vertical1_widgets, lengthof(_nested_toolbar_vertical_left_widgets), + &MainToolbarWindow::hotkeys +); + +static const NWidgetPart _nested_toolbar_vertical_right_widgets[] = { + NWidgetFunction(MakeVerticalRightToolbar), +}; + +static WindowDesc _toolb_vertical_right_desc( + WDP_MANUAL, NULL, 22, 480, + WC_MAIN_TOOLBAR, WC_NONE, + WDF_NO_FOCUS, + _nested_toolbar_vertical_right_widgets, lengthof(_nested_toolbar_vertical_right_widgets), + &MainToolbarWindow::hotkeys +); /* --- Toolbar handling for the scenario editor */ @@ -2301,6 +2350,11 @@ void AllocateToolbar() if (_game_mode == GM_EDITOR) { new ScenarioEditorToolbarWindow(&_toolb_scen_desc); } else { - new MainToolbarWindow(&_toolb_normal_desc); + if (_settings_client.gui.vertical_toolbar) { + new MainToolbarWindow(&_toolb_vertical_left_desc); + new MainToolbarWindow(&_toolb_vertical_right_desc); + } else { + new MainToolbarWindow(&_toolb_normal_desc); + } } } diff --git a/src/window.cpp b/src/window.cpp index ad63eb343f..7b652ac396 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1594,7 +1594,11 @@ static Point GetAutoPlacePosition(int width, int height) /* First attempt, try top-left of the screen */ const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); - if (IsGoodAutoPlace1(0, main_toolbar != NULL ? main_toolbar->height : 0, width, height, pt)) return pt; + if (_settings_client.gui.vertical_toolbar) { + if (IsGoodAutoPlace1(main_toolbar != NULL ? main_toolbar->width : 0, 0, width, height, pt)) return pt; + } else { + if (IsGoodAutoPlace1(0, main_toolbar != NULL ? main_toolbar->height : 0, width, height, pt)) return pt; + } /* Second attempt, try around all existing windows with a distance of 2 pixels. * The new window must be entirely on-screen, and not overlap with an existing window. From 9923ecfed03346126f542a3165729f2e88160e55 Mon Sep 17 00:00:00 2001 From: pelya Date: Mon, 2 Jun 2014 00:15:15 +0300 Subject: [PATCH 129/187] Vertical toolbar is drawn okay, but does not work --- src/settings.cpp | 7 ++- src/table/settings.ini | 1 + src/toolbar_gui.cpp | 135 ++++++++++++++++++++++++++++++++--------- src/window.cpp | 16 +++-- 4 files changed, 124 insertions(+), 35 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index 51db18d4b0..0142d502b0 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -54,6 +54,7 @@ #include "base_media_base.h" #include "gamelog.h" #include "settings_func.h" +#include "settings_gui.h" #include "ini_type.h" #include "ai/ai_config.hpp" #include "ai/ai.hpp" @@ -1072,7 +1073,11 @@ static bool ZoomMinMaxChanged(int32 p1) static bool VerticalToolbarChanged(int32 p1) { - + if (FindWindowByClass(WC_MAIN_TOOLBAR)) { + HideVitalWindows(); + ShowVitalWindows(); + ReInitAllWindows(); + } return true; } diff --git a/src/table/settings.ini b/src/table/settings.ini index 9c74ff99a1..4d9577b220 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -40,6 +40,7 @@ static bool RedrawTownAuthority(int32 p1); static bool InvalidateCompanyInfrastructureWindow(int32 p1); static bool InvalidateCompanyWindow(int32 p1); static bool ZoomMinMaxChanged(int32 p1); +static bool VerticalToolbarChanged(int32 p1); static bool TouchscreenModeChanged(int32 p1); #ifdef ENABLE_NETWORK diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 11033c7380..794a4e6edc 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1339,7 +1339,7 @@ protected: uint spacers; ///< Number of spacer widgets in this toolbar public: - NWidgetToolbarContainer(enum widgetType = NWID_HORIZONTAL) : NWidgetContainer(widgetType) + NWidgetToolbarContainer(WidgetType widgetType = NWID_HORIZONTAL) : NWidgetContainer(widgetType) { } @@ -1357,20 +1357,28 @@ public: { this->smallest_x = 0; // Biggest child this->smallest_y = 0; // Biggest child - this->fill_x = 1; - this->fill_y = 0; - this->resize_x = 1; // We only resize in this direction - this->resize_y = 0; // We never resize in this direction + this->fill_x = (type == NWID_HORIZONTAL); + this->fill_y = (type == NWID_VERTICAL); + this->resize_x = (type == NWID_HORIZONTAL); // We only resize in this direction + this->resize_y = (type == NWID_VERTICAL); // We never resize in this direction this->spacers = 0; uint nbuttons = 0; /* First initialise some variables... */ for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { child_wid->SetupSmallestSize(w, init_array); - this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); + if (type == NWID_HORIZONTAL) { + this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); + } else { + this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); + } if (this->IsButton(child_wid->type)) { nbuttons++; - this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); + if (type == NWID_HORIZONTAL) { + this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); + } else { + this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); + } } else if (child_wid->type == NWID_SPACER) { this->spacers++; } @@ -1378,12 +1386,23 @@ public: /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */ for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - child_wid->current_y = this->smallest_y; - if (!this->IsButton(child_wid->type)) { - child_wid->current_x = child_wid->smallest_x; + if (type == NWID_HORIZONTAL) { + child_wid->current_y = this->smallest_y; + if (!this->IsButton(child_wid->type)) { + child_wid->current_x = child_wid->smallest_x; + } + } else { + child_wid->current_x = this->smallest_x; + if (!this->IsButton(child_wid->type)) { + child_wid->current_y = child_wid->smallest_y; + } } } - w->window_desc->default_width = nbuttons * this->smallest_x; + if (type == NWID_HORIZONTAL) { + w->window_desc->default_width = nbuttons * this->smallest_x; + } else { + w->window_desc->default_height = nbuttons * this->smallest_y; + } } void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) @@ -1414,6 +1433,10 @@ public: uint position = 0; // Place to put next child relative to origin of the container. uint spacer_space = max(0, (int)given_width - (int)(button_count * this->smallest_x)); // Remaining spacing for 'spacer' widgets uint button_space = given_width - spacer_space; // Remaining spacing for the buttons + if (type == NWID_VERTICAL) { + spacer_space = max(0, (int)given_height - (int)(button_count * this->smallest_y)); + button_space = given_height - spacer_space; + } uint spacer_i = 0; uint button_i = 0; @@ -1434,12 +1457,22 @@ public: /* Buttons can be scaled, the others not. */ if (this->IsButton(child_wid->type)) { - child_wid->current_x = button_space / (button_count - button_i); - button_space -= child_wid->current_x; + if (type == NWID_HORIZONTAL) { + child_wid->current_x = button_space / (button_count - button_i); + button_space -= child_wid->current_x; + } else { + child_wid->current_y = button_space / (button_count - button_i); + button_space -= child_wid->current_y; + } button_i++; } - child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl); - position += child_wid->current_x; + if (type == NWID_HORIZONTAL) { + child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl); + position += child_wid->current_x; + } else { + child_wid->AssignSizePosition(sizing, x, y + position, this->current_x, child_wid->current_y, rtl); + position += child_wid->current_y; + } if (rtl) { cur_wid--; @@ -1577,6 +1610,47 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { } }; +/** Container for the 'normal' main toolbar */ +class NWidgetVerticalToolbarContainer : public NWidgetToolbarContainer { + int side; + + public: + NWidgetVerticalToolbarContainer(int side) : NWidgetToolbarContainer(NWID_VERTICAL), side(side) + { + } + + /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const + { + static const byte arrange_left[] = { + 32, 30, 31, 19, 20, 0, 1, 2, 3, 4, 5, 6, + }; + // Some rather artistic button arrangement, I'm proud of myself + static const byte arrange_right[] = { + 29, 21, 22, 23, 24, 25, 7, 8, 9, 12, 14, 28, + 29, 15, 16, 17, 18, 13, 7, 10, 11, 26, 27, 28, + }; + + spacer_count = 0; + + if (side == 0) { + button_count = arrangable_count = lengthof(arrange_left); + return arrange_left; + } + button_count = arrangable_count = lengthof(arrange_right) / 2; + return &arrange_right[((_toolbar_mode == TB_LOWER) ? button_count : 0)]; + } + + /* + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) + { + if (side == 0) x = 0; + else x = _screen.width - this->smallest_x; + y = 0; + NWidgetToolbarContainer::AssignSizePosition(sizing, x, y, given_width, given_height, rtl); + } + */ +}; + /** Container for the scenario editor's toolbar */ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { uint panel_widths[2]; ///< The width of the two panels (the text panel and date panel) @@ -1996,17 +2070,6 @@ static NWidgetBase *MakeVerticalLeftToolbar(int *biggest_index) return tb; } -static NWidgetBase *MakeVerticalRigthToolbar(int *biggest_index) -{ - NWidgetVerticalToolbarContainer *tb = new NWidgetVerticalToolbarContainer(1); - for (uint i = 0; i <= WID_TN_SWITCH_BAR; i++) { - tb->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, _toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); - } - - *biggest_index = max(*biggest_index, WID_TN_DELETE); - return tb; -} - static const NWidgetPart _nested_toolbar_vertical_left_widgets[] = { NWidgetFunction(MakeVerticalLeftToolbar), }; @@ -2015,10 +2078,21 @@ static WindowDesc _toolb_vertical_left_desc( WDP_MANUAL, NULL, 22, 480, WC_MAIN_TOOLBAR, WC_NONE, WDF_NO_FOCUS, - _nested_toolbar_vertical1_widgets, lengthof(_nested_toolbar_vertical_left_widgets), + _nested_toolbar_vertical_left_widgets, lengthof(_nested_toolbar_vertical_left_widgets), &MainToolbarWindow::hotkeys ); +static NWidgetBase *MakeVerticalRightToolbar(int *biggest_index) +{ + NWidgetVerticalToolbarContainer *tb = new NWidgetVerticalToolbarContainer(1); + for (uint i = 0; i <= WID_TN_SWITCH_BAR; i++) { + tb->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, _toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); + } + + *biggest_index = max(*biggest_index, WID_TN_SWITCH_BAR); + return tb; +} + static const NWidgetPart _nested_toolbar_vertical_right_widgets[] = { NWidgetFunction(MakeVerticalRightToolbar), }; @@ -2351,8 +2425,11 @@ void AllocateToolbar() new ScenarioEditorToolbarWindow(&_toolb_scen_desc); } else { if (_settings_client.gui.vertical_toolbar) { - new MainToolbarWindow(&_toolb_vertical_left_desc); - new MainToolbarWindow(&_toolb_vertical_right_desc); + MainToolbarWindow *w = new MainToolbarWindow(&_toolb_vertical_left_desc); + w->left = 0; + w = new MainToolbarWindow(&_toolb_vertical_right_desc); + w->left = _screen.width - w->width; + SetDirtyBlocks(0, w->top, _screen.width, w->top + w->height); } else { new MainToolbarWindow(&_toolb_normal_desc); } diff --git a/src/window.cpp b/src/window.cpp index 7b652ac396..1c48892e04 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1470,7 +1470,7 @@ void Window::FindWindowPlacementAndResize(int def_width, int def_height) const Window *wt = FindWindowById(WC_STATUS_BAR, 0); if (wt != NULL) free_height -= wt->height; wt = FindWindowById(WC_MAIN_TOOLBAR, 0); - if (wt != NULL) free_height -= wt->height; + if (wt != NULL && !_settings_client.gui.vertical_toolbar) free_height -= wt->height; int enlarge_x = max(min(def_width - this->width, _screen.width - this->width), 0); int enlarge_y = max(min(def_height - this->height, free_height - this->height), 0); @@ -1661,11 +1661,16 @@ Point GetToolbarAlignedWindowPosition(int window_width) const Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); assert(w != NULL); Point pt; - pt.y = w->top + w->height; - if (_settings_client.gui.touchscreen_mode != TSC_NONE) { - pt.x = _current_text_dir == TD_RTL ? 0 : (_screen.width - window_width); + if (_settings_client.gui.vertical_toolbar) { + pt.x = _current_text_dir == TD_RTL ? w->left + w->width : _screen.width - window_width - w->width; + pt.y = w->top; } else { - pt.x = _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width; + pt.y = w->top + w->height; + if (_settings_client.gui.touchscreen_mode != TSC_NONE) { + pt.x = _current_text_dir == TD_RTL ? 0 : (_screen.width - window_width); + } else { + pt.x = _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width; + } } return pt; } @@ -3423,6 +3428,7 @@ static int PositionWindow(Window *w, WindowClass clss, int setting) */ int PositionMainToolbar(Window *w) { + if (_settings_client.gui.vertical_toolbar) return 0; DEBUG(misc, 5, "Repositioning Main Toolbar..."); return PositionWindow(w, WC_MAIN_TOOLBAR, _settings_client.gui.toolbar_pos); } From 9bdda2756b9c9ed88f88aec9fdf69734387ccc36 Mon Sep 17 00:00:00 2001 From: pelya Date: Mon, 2 Jun 2014 01:58:58 +0300 Subject: [PATCH 130/187] Fixes to split toolbar --- src/toolbar_gui.cpp | 4 ++-- src/window.cpp | 2 ++ src/window_type.h | 7 +++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 794a4e6edc..fde6ed284c 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1897,7 +1897,7 @@ struct MainToolbarWindow : Window { ShowLandInfo(tile); break; - default: NOT_REACHED(); + default: return; //NOT_REACHED(); } } @@ -2099,7 +2099,7 @@ static const NWidgetPart _nested_toolbar_vertical_right_widgets[] = { static WindowDesc _toolb_vertical_right_desc( WDP_MANUAL, NULL, 22, 480, - WC_MAIN_TOOLBAR, WC_NONE, + WC_MAIN_TOOLBAR_RIGHT, WC_NONE, WDF_NO_FOCUS, _nested_toolbar_vertical_right_widgets, lengthof(_nested_toolbar_vertical_right_widgets), &MainToolbarWindow::hotkeys diff --git a/src/window.cpp b/src/window.cpp index 1c48892e04..77a94da937 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1222,6 +1222,7 @@ static inline bool IsVitalWindow(const Window *w) { switch (w->window_class) { case WC_MAIN_TOOLBAR: + case WC_MAIN_TOOLBAR_RIGHT: case WC_STATUS_BAR: case WC_NEWS_WINDOW: case WC_SEND_NETWORK_MSG: @@ -3373,6 +3374,7 @@ restart_search: void HideVitalWindows() { DeleteWindowById(WC_MAIN_TOOLBAR, 0); + DeleteWindowById(WC_MAIN_TOOLBAR_RIGHT, 0); DeleteWindowById(WC_STATUS_BAR, 0); } diff --git a/src/window_type.h b/src/window_type.h index 9ad14702b4..d0fa1ad946 100644 --- a/src/window_type.h +++ b/src/window_type.h @@ -52,6 +52,13 @@ enum WindowClass { */ WC_MAIN_TOOLBAR, + /** + * Right part of split main toolbar; %Window numbers: + * - 0 = #ToolbarNormalWidgets + * - 0 = #ToolbarEditorWidgets + */ + WC_MAIN_TOOLBAR_RIGHT, + /** * Statusbar (at the bottom of your screen); %Window numbers: * - 0 = #StatusbarWidgets From 7e6e95c34c2647dcc0597ab3b71cb1db0eb6e1f7 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Mon, 2 Jun 2014 23:25:47 +0300 Subject: [PATCH 131/187] Some fixes to window placement --- src/company_cmd.cpp | 5 ++++- src/main_gui.cpp | 1 + src/script/api/script_window.hpp | 7 ++++++ src/toolbar_gui.cpp | 25 +++++++++++++++++---- src/toolbar_gui.h | 2 ++ src/window.cpp | 38 ++++++++++++++++++++------------ 6 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 0357e337ea..9d4a15e426 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -937,7 +937,10 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 Game::NewEvent(new ScriptEventCompanyBankrupt(c_index)); CompanyAdminRemove(c_index, (CompanyRemoveReason)reason); - if (StoryPage::GetNumItems() == 0 || Goal::GetNumItems() == 0) InvalidateWindowData(WC_MAIN_TOOLBAR, 0); + if (StoryPage::GetNumItems() == 0 || Goal::GetNumItems() == 0) { + InvalidateWindowData(WC_MAIN_TOOLBAR, 0); + InvalidateWindowData(WC_MAIN_TOOLBAR_RIGHT, 0); + } break; } diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 9d13deef66..113ce8a864 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -461,6 +461,7 @@ struct MainWindow : Window if (!gui_scope) return; /* Forward the message to the appropriate toolbar (ingame or scenario editor) */ InvalidateWindowData(WC_MAIN_TOOLBAR, 0, data, true); + InvalidateWindowData(WC_MAIN_TOOLBAR_RIGHT, 0, data, true); } static HotkeyList hotkeys; diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp index 680c3f2d85..e61fa1a532 100644 --- a/src/script/api/script_window.hpp +++ b/src/script/api/script_window.hpp @@ -135,6 +135,13 @@ public: */ WC_MAIN_TOOLBAR = ::WC_MAIN_TOOLBAR, + /** + * Main toolbar (the long bar at the top); %Window numbers: + * - 0 = #ToolbarNormalWidgets + * - 0 = #ToolbarEditorWidgets + */ + WC_MAIN_TOOLBAR_RIGHT = ::WC_MAIN_TOOLBAR_RIGHT, + /** * Statusbar (at the bottom of your screen); %Window numbers: * - 0 = #StatusbarWidgets diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index fde6ed284c..edacf68c64 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -58,6 +58,7 @@ RailType _last_built_railtype; RoadType _last_built_roadtype; static ScreenshotType _confirmed_screenshot_type; ///< Screenshot type the current query is about to confirm. +int _last_clicked_toolbar_idx = 0; /** Toobar modes */ enum ToolbarMode { @@ -170,7 +171,17 @@ public: */ static void PopupMainToolbMenu(Window *w, int widget, DropDownList *list, int def) { - ShowDropDownList(w, list, def, widget, 0, true, true); + if (!_settings_client.gui.vertical_toolbar) { + ShowDropDownList(w, list, def, widget, 0, true, true); + } else { + Rect wi_rect; + NWidgetCore *nwi = w->GetWidget(widget); + wi_rect.left = ((int)nwi->pos_x < _screen.width / 2) ? nwi->pos_x + nwi->current_x - 1 : nwi->pos_x - nwi->current_x; + wi_rect.right = ((int)nwi->pos_x < _screen.width / 2) ? nwi->pos_x + nwi->current_x * 2 : nwi->pos_x - 1; + wi_rect.top = nwi->pos_y; + wi_rect.bottom = nwi->pos_y + nwi->current_y - 1; + ShowDropDownListAt(w, list, def, widget, wi_rect, nwi->colour, true, true); + } if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); } @@ -1796,8 +1807,10 @@ enum MainToolbarHotkeys { /** Main toolbar. */ struct MainToolbarWindow : Window { CallBackFunction last_started_action; ///< Last started user action. + int *clickedFlag; + int clickedValue; - MainToolbarWindow(WindowDesc *desc) : Window(desc) + MainToolbarWindow(WindowDesc *desc, int *clickedFlag = NULL, int clickedValue = 0) : Window(desc), clickedFlag(clickedFlag), clickedValue(clickedValue) { this->InitNested(0); @@ -1829,11 +1842,15 @@ struct MainToolbarWindow : Window { virtual void OnClick(Point pt, int widget, int click_count) { + if (clickedFlag) + *clickedFlag = clickedValue; if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this); } virtual void OnDropdownSelect(int widget, int index) { + if (clickedFlag) + *clickedFlag = clickedValue; CallBackFunction cbf = _menu_clicked_procs[widget](index); if (cbf != CBF_NONE) this->last_started_action = cbf; } @@ -2425,9 +2442,9 @@ void AllocateToolbar() new ScenarioEditorToolbarWindow(&_toolb_scen_desc); } else { if (_settings_client.gui.vertical_toolbar) { - MainToolbarWindow *w = new MainToolbarWindow(&_toolb_vertical_left_desc); + MainToolbarWindow *w = new MainToolbarWindow(&_toolb_vertical_left_desc, &_last_clicked_toolbar_idx, 0); w->left = 0; - w = new MainToolbarWindow(&_toolb_vertical_right_desc); + w = new MainToolbarWindow(&_toolb_vertical_right_desc, &_last_clicked_toolbar_idx, 1); w->left = _screen.width - w->width; SetDirtyBlocks(0, w->top, _screen.width, w->top + w->height); } else { diff --git a/src/toolbar_gui.h b/src/toolbar_gui.h index acfe0ed418..3461c22902 100644 --- a/src/toolbar_gui.h +++ b/src/toolbar_gui.h @@ -18,4 +18,6 @@ void ToggleDirtyBlocks(); void ResetTabletWindow(); +extern int _last_clicked_toolbar_idx; + #endif /* TOOLBAR_GUI_H */ diff --git a/src/window.cpp b/src/window.cpp index 77a94da937..f7590fc25b 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1261,6 +1261,7 @@ static uint GetWindowZPriority(const Window *w) ++z_priority; case WC_MAIN_TOOLBAR: + case WC_MAIN_TOOLBAR_RIGHT: case WC_STATUS_BAR: ++z_priority; @@ -1475,6 +1476,10 @@ void Window::FindWindowPlacementAndResize(int def_width, int def_height) int enlarge_x = max(min(def_width - this->width, _screen.width - this->width), 0); int enlarge_y = max(min(def_height - this->height, free_height - this->height), 0); + if (wt && _settings_client.gui.vertical_toolbar && + enlarge_x > _screen.width - wt->width * 2) { + //enlarge_x = _screen.width - wt->width * 2; + } /* X and Y has to go by step.. calculate it. * The cast to int is necessary else x/y are implicitly casted to @@ -1525,7 +1530,11 @@ static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &po int bottom = height + top; const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); - if (left < 0 || (main_toolbar != NULL && top < main_toolbar->height) || right > _screen.width || bottom > _screen.height) return false; + if (!_settings_client.gui.vertical_toolbar || !main_toolbar) { + if (left < 0 || (main_toolbar != NULL && top < main_toolbar->height) || right > _screen.width || bottom > _screen.height) return false; + } else { + if (left < main_toolbar->width || top < 0 || right > _screen.width - main_toolbar->width * 2 || bottom > _screen.height) return false; + } /* Make sure it is not obscured by any window. */ const Window *w; @@ -1636,6 +1645,10 @@ static Point GetAutoPlacePosition(int width, int height) * of (+5, +5) */ int left = 0, top = 24; + if (_settings_client.gui.vertical_toolbar) { + left = main_toolbar != NULL ? main_toolbar->width : 0; + top = 0; + } restart: FOR_ALL_WINDOWS_FROM_BACK(w) { @@ -1663,15 +1676,12 @@ Point GetToolbarAlignedWindowPosition(int window_width) assert(w != NULL); Point pt; if (_settings_client.gui.vertical_toolbar) { - pt.x = _current_text_dir == TD_RTL ? w->left + w->width : _screen.width - window_width - w->width; + // Retermine if the window was opened from the left or the right toolbar + pt.x = (_last_clicked_toolbar_idx == 0) ? w->left + w->width : _screen.width - w->width - window_width - 1; pt.y = w->top; } else { + pt.x = _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width; pt.y = w->top + w->height; - if (_settings_client.gui.touchscreen_mode != TSC_NONE) { - pt.x = _current_text_dir == TD_RTL ? 0 : (_screen.width - window_width); - } else { - pt.x = _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width; - } } return pt; } @@ -1705,13 +1715,9 @@ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int (w = FindWindowById(desc->parent_cls, window_number)) != NULL && w->left < _screen.width - 20 && w->left > -60 && w->top < _screen.height - 20) { - if (_settings_client.gui.touchscreen_mode != TSC_NONE) { - pt.x = _current_text_dir == TD_RTL ? 0 : (_screen.width - default_width); - } else { - pt.x = w->left + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? 0 : 10); - if (pt.x > _screen.width + 10 - default_width) { - pt.x = (_screen.width + 10 - default_width) - 20; - } + pt.x = w->left + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? 0 : 10); + if (pt.x > _screen.width + 10 - default_width) { + pt.x = (_screen.width + 10 - default_width) - 20; } pt.y = w->top + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? w->height : 10); @@ -2064,6 +2070,7 @@ static void EnsureVisibleCaption(Window *w, int nx, int ny) /* Make sure the title bar isn't hidden behind the main tool bar or the status bar. */ PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_MAIN_TOOLBAR, 0), w->left, PHD_DOWN); + PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_MAIN_TOOLBAR_RIGHT, 0), w->left, PHD_DOWN); PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_STATUS_BAR, 0), w->left, PHD_UP); } @@ -2124,6 +2131,7 @@ void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen) */ int GetMainViewTop() { + if (_settings_client.gui.vertical_toolbar) return 0; Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); return (w == NULL) ? 0 : w->top + w->height; } @@ -3290,6 +3298,7 @@ restart_search: if (w->window_class != WC_MAIN_WINDOW && w->window_class != WC_SELECT_GAME && w->window_class != WC_MAIN_TOOLBAR && + w->window_class != WC_MAIN_TOOLBAR_RIGHT && w->window_class != WC_STATUS_BAR && w->window_class != WC_TOOLTIPS && (w->flags & WF_STICKY) == 0) { // do not delete windows which are 'pinned' @@ -3506,6 +3515,7 @@ void RelocateAllWindows(int neww, int newh) continue; case WC_MAIN_TOOLBAR: + case WC_MAIN_TOOLBAR_RIGHT: ResizeWindow(w, min(neww, w->window_desc->default_width) - w->width, 0, false); top = w->top; From a0581f42bd743b2c1a115d1336891160e17935b7 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 3 Jun 2014 18:14:15 +0300 Subject: [PATCH 132/187] Revert "Select the actions that will need confirmation." This reverts commit 02caad7c1b3e3e91bb14711fa5ad76ac0ec00080. --- src/bridge_gui.cpp | 2 +- src/company_gui.cpp | 2 +- src/dock_gui.cpp | 12 ++++++------ src/object_gui.cpp | 2 +- src/rail_gui.cpp | 20 ++++++++++---------- src/road_gui.cpp | 10 +++++----- src/station_gui.cpp | 2 +- src/terraform_gui.cpp | 14 +++++++------- src/tree_gui.cpp | 2 +- 9 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp index 6834359d7a..9ce304fed8 100644 --- a/src/bridge_gui.cpp +++ b/src/bridge_gui.cpp @@ -383,7 +383,7 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo default: break; // water ways and air routes don't have bridge types } if (_ctrl_pressed && CheckBridgeAvailability(last_bridge_type, bridge_len).Succeeded()) { - TouchCommandP(end, start, type | last_bridge_type, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge); + DoCommandP(end, start, type | last_bridge_type, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge); return; } diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 356ccd59c9..dabaa3e695 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -2366,7 +2366,7 @@ struct CompanyWindow : Window virtual void OnPlaceObject(Point pt, TileIndex tile) { - if (TouchCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS))) { + if (DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS))) { ResetObjectToPlace(); this->RaiseButtons(); } diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index 070d6e328b..6a669d7f8a 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -226,10 +226,10 @@ struct BuildDocksToolbarWindow : Window { GUIPlaceProcDragXY(select_proc, start_tile, end_tile); break; case DDSP_CREATE_WATER: - TouchCommandP(end_tile, start_tile, (_game_mode == GM_EDITOR && _ctrl_pressed) ? WATER_CLASS_SEA : WATER_CLASS_CANAL, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_BUILD_CANALS), CcBuildCanal); + DoCommandP(end_tile, start_tile, (_game_mode == GM_EDITOR && _ctrl_pressed) ? WATER_CLASS_SEA : WATER_CLASS_CANAL, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_BUILD_CANALS), CcBuildCanal); break; case DDSP_CREATE_RIVER: - TouchCommandP(end_tile, start_tile, WATER_CLASS_RIVER, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_PLACE_RIVERS), CcBuildCanal); + DoCommandP(end_tile, start_tile, WATER_CLASS_RIVER, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_PLACE_RIVERS), CcBuildCanal); break; case DDSP_BUILD_STATION: { uint32 p2 = (uint32)INVALID_STATION << 16; // no station to join @@ -244,14 +244,14 @@ struct BuildDocksToolbarWindow : Window { } case DDSP_BUILD_BRIDGE: - TouchCommandP(start_tile, GetOtherAqueductEnd(start_tile), TRANSPORT_WATER << 15, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE), CcBuildBridge); + DoCommandP(start_tile, GetOtherAqueductEnd(start_tile), TRANSPORT_WATER << 15, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE), CcBuildBridge); VpStartPreSizing(); break; case DDSP_REMOVE_TRUCKSTOP: { // Reusing for locks. TileIndex middle_tile = start_tile; if (start_tile != end_tile) middle_tile = TileAddByDiagDir(start_tile, DiagdirBetweenTiles(start_tile, end_tile)); - TouchCommandP(middle_tile, 0, 0, CMD_BUILD_LOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_LOCKS), CcBuildDocks); + DoCommandP(middle_tile, 0, 0, CMD_BUILD_LOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_LOCKS), CcBuildDocks); VpStartPreSizing(); break; } @@ -260,10 +260,10 @@ struct BuildDocksToolbarWindow : Window { assert(start_tile == end_tile); switch (last_clicked_widget) { case WID_DT_BUOY: - TouchCommandP(end_tile, 0, 0, CMD_BUILD_BUOY | CMD_MSG(STR_ERROR_CAN_T_POSITION_BUOY_HERE), CcBuildDocks); + DoCommandP(end_tile, 0, 0, CMD_BUILD_BUOY | CMD_MSG(STR_ERROR_CAN_T_POSITION_BUOY_HERE), CcBuildDocks); break; case WID_DT_DEPOT: // Build depot button - TouchCommandP(end_tile, _ship_depot_direction, 0, CMD_BUILD_SHIP_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_SHIP_DEPOT), CcBuildDocks); + DoCommandP(end_tile, _ship_depot_direction, 0, CMD_BUILD_SHIP_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_SHIP_DEPOT), CcBuildDocks); break; default: NOT_REACHED(); } diff --git a/src/object_gui.cpp b/src/object_gui.cpp index ba4e4d07a3..29a9d0d5ef 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -499,5 +499,5 @@ void InitializeObjectGui() */ void PlaceProc_Object(TileIndex tile) { - TouchCommandP(tile, ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index)->Index(), _selected_object_view, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_OBJECT), CcTerraform); + DoCommandP(tile, ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index)->Index(), _selected_object_view, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_OBJECT), CcTerraform); } diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 0c4477ac90..b02be76df0 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -91,7 +91,7 @@ void CcPlaySound1E(const CommandCost &result, TileIndex tile, uint32 p1, uint32 static void GenericPlaceRail(TileIndex tile, int cmd) { - TouchCommandP(tile, _cur_railtype, cmd, + DoCommandP(tile, _cur_railtype, cmd, _remove_button_clicked ? CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) : CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), @@ -213,7 +213,7 @@ static void GenericPlaceSignals(TileIndex tile) Track track = FindFirstTrack(trackbits); if (_remove_button_clicked) { - TouchCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E); + DoCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E); } else { const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); @@ -238,7 +238,7 @@ static void GenericPlaceSignals(TileIndex tile) SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]); } - TouchCommandP(tile, p1, 0, CMD_BUILD_SIGNALS | + DoCommandP(tile, p1, 0, CMD_BUILD_SIGNALS | CMD_MSG((w != NULL && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), CcPlaySound1E); } @@ -325,7 +325,7 @@ static void BuildRailClick_Remove(Window *w) static void DoRailroadTrack(int mode) { - TouchCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), + DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), _remove_button_clicked ? CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) : CMD_BUILD_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), @@ -380,7 +380,7 @@ static void HandleAutoSignalPlacement() /* _settings_client.gui.drag_signals_density is given as a parameter such that each user * in a network game can specify his/her own signal density */ - TouchCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, + DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, _remove_button_clicked ? CMD_REMOVE_SIGNAL_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM) : CMD_BUILD_SIGNAL_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), @@ -669,7 +669,7 @@ struct BuildRailToolbarWindow : Window { case WID_RAT_BUILD_TUNNEL: if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); else VpStartPreSizing(); - TouchCommandP(end_tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel); + DoCommandP(end_tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel); break; case WID_RAT_BUILD_BRIDGE: if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); @@ -692,7 +692,7 @@ struct BuildRailToolbarWindow : Window { break; case DDSP_CONVERT_RAIL: - TouchCommandP(end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 0x10 : 0), CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound10); + DoCommandP(end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 0x10 : 0), CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound10); break; case DDSP_REMOVE_STATION: @@ -700,7 +700,7 @@ struct BuildRailToolbarWindow : Window { if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) { /* Station */ if (_remove_button_clicked) { - TouchCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION), CcPlaySound1E); + DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION), CcPlaySound1E); } else { if (!_settings_client.gui.station_dragdrop) { uint32 p1 = _cur_railtype | _railstation.orientation << 4 | _settings_client.gui.station_numtracks << 8 | _settings_client.gui.station_platlength << 16 | _ctrl_pressed << 24; @@ -719,7 +719,7 @@ struct BuildRailToolbarWindow : Window { } else { /* Waypoint */ if (_remove_button_clicked) { - TouchCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT), CcPlaySound1E); + DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT), CcPlaySound1E); } else { TileArea ta(start_tile, end_tile); uint32 p1 = _cur_railtype | (select_method == VPM_FIX_X ? AXIS_X : AXIS_Y) << 4 | ta.w << 8 | ta.h << 16 | _ctrl_pressed << 24; @@ -734,7 +734,7 @@ struct BuildRailToolbarWindow : Window { case DDSP_SINGLE_TILE: assert(end_tile == start_tile); assert(last_user_action == WID_RAT_BUILD_DEPOT); - TouchCommandP(end_tile, _cur_railtype, _build_depot_direction, + DoCommandP(end_tile, _cur_railtype, _build_depot_direction, CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT), CcRailDepot); break; diff --git a/src/road_gui.cpp b/src/road_gui.cpp index ffed5de233..904089d3ae 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -588,7 +588,7 @@ struct BuildRoadToolbarWindow : Window { case WID_ROT_BUILD_TUNNEL: if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); else VpStartPreSizing(); - TouchCommandP(end_tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, + DoCommandP(end_tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRoadTunnel); break; case WID_ROT_BUILD_BRIDGE: @@ -612,7 +612,7 @@ struct BuildRoadToolbarWindow : Window { * not the 3rd bit set) */ _place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3)); - TouchCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), + DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), _remove_button_clicked ? CMD_REMOVE_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) : CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound1D); @@ -628,13 +628,13 @@ struct BuildRoadToolbarWindow : Window { case DDSP_REMOVE_BUSSTOP: { TileArea ta(start_tile, end_tile); - TouchCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound1D); + DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound1D); break; } case DDSP_REMOVE_TRUCKSTOP: { TileArea ta(start_tile, end_tile); - TouchCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound1D); + DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound1D); break; } @@ -642,7 +642,7 @@ struct BuildRoadToolbarWindow : Window { /* Build depot. */ assert(start_tile == end_tile); assert(last_started_action == WID_ROT_DEPOT); - TouchCommandP(start_tile, _cur_roadtype << 2 | _road_depot_orientation, 0, + DoCommandP(start_tile, _cur_roadtype << 2 | _road_depot_orientation, 0, CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot); break; } diff --git a/src/station_gui.cpp b/src/station_gui.cpp index 2b77470654..f6b1d1f804 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -2427,7 +2427,7 @@ void ShowSelectBaseStationIfNeeded(const CommandContainer &cmd, TileArea ta) if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); new SelectStationWindow(&_select_station_desc, cmd, ta); } else { - TouchCommandP(&cmd); + DoCommandP(&cmd); } } diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index 77c5fda01f..e328a4ad19 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -111,16 +111,16 @@ bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_t switch (proc) { case DDSP_DEMOLISH_AREA: - TouchCommandP(end_tile, start_tile, _ctrl_pressed ? 1 : 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound10); + DoCommandP(end_tile, start_tile, _ctrl_pressed ? 1 : 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound10); break; case DDSP_RAISE_AND_LEVEL_AREA: - TouchCommandP(end_tile, start_tile, LM_RAISE << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_RAISE_LAND_HERE), CcTerraform); + DoCommandP(end_tile, start_tile, LM_RAISE << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_RAISE_LAND_HERE), CcTerraform); break; case DDSP_LOWER_AND_LEVEL_AREA: - TouchCommandP(end_tile, start_tile, LM_LOWER << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LOWER_LAND_HERE), CcTerraform); + DoCommandP(end_tile, start_tile, LM_LOWER << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LOWER_LAND_HERE), CcTerraform); break; case DDSP_LEVEL_AREA: - TouchCommandP(end_tile, start_tile, LM_LEVEL << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LEVEL_LAND_HERE), CcTerraform); + DoCommandP(end_tile, start_tile, LM_LEVEL << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LEVEL_LAND_HERE), CcTerraform); break; case DDSP_CREATE_ROCKS: GenerateRockyArea(end_tile, start_tile); @@ -270,7 +270,7 @@ struct TerraformToolbarWindow : Window { assert(start_tile == end_tile); switch (this->last_user_action) { case WID_TT_BUY_LAND: - TouchCommandP(end_tile, OBJECT_OWNED_LAND, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_PURCHASE_THIS_LAND), CcPlaySound1E); + DoCommandP(end_tile, OBJECT_OWNED_LAND, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_PURCHASE_THIS_LAND), CcPlaySound1E); break; case WID_TT_PLACE_SIGN: PlaceProc_Sign(end_tile); @@ -406,7 +406,7 @@ static void CommonRaiseLowerBigLand(TileIndex tile, int mode) StringID msg = mode ? STR_ERROR_CAN_T_RAISE_LAND_HERE : STR_ERROR_CAN_T_LOWER_LAND_HERE; - TouchCommandP(tile, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND | CMD_MSG(msg), CcTerraform); + DoCommandP(tile, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND | CMD_MSG(msg), CcTerraform); } else { assert(_terraform_size != 0); TileArea ta(tile, _terraform_size, _terraform_size); @@ -433,7 +433,7 @@ static void CommonRaiseLowerBigLand(TileIndex tile, int mode) TILE_AREA_LOOP(tile2, ta) { if (TileHeight(tile2) == h) { - TouchCommandP(tile2, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND); + DoCommandP(tile2, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND); } } } diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index f57d67a30e..1e1883ece1 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -156,7 +156,7 @@ public: virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) { if (pt.x != -1 && select_proc == DDSP_PLANT_TREES) { - TouchCommandP(end_tile, this->tree_to_plant, start_tile, + DoCommandP(end_tile, this->tree_to_plant, start_tile, CMD_PLANT_TREE | CMD_MSG(STR_ERROR_CAN_T_PLANT_TREE_HERE)); } } From b2bfcf6816879df05a98cee2b0a302028f4c4ba4 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 3 Jun 2014 18:44:16 +0300 Subject: [PATCH 133/187] Revert "Erase queued commands when another command is about to be queued." This reverts commit 604205045f393f1b80114da5f7d29ed79d7acc3f. --- src/airport_gui.cpp | 1 - src/dock_gui.cpp | 1 - src/rail_gui.cpp | 1 - src/road_gui.cpp | 1 - src/terraform_gui.cpp | 1 - src/tree_gui.cpp | 1 - 6 files changed, 6 deletions(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 9eeeae950f..8b49b998ce 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -103,7 +103,6 @@ struct BuildAirToolbarWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { - EraseQueuedTouchCommand(); switch (this->last_user_action) { case WID_AT_AIRPORT: { VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_BUILD_STATION); diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index 6a669d7f8a..4e6ed21402 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -168,7 +168,6 @@ struct BuildDocksToolbarWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { - EraseQueuedTouchCommand(); switch (this->last_clicked_widget) { case WID_DT_CANAL: // Build canal button VpStartPlaceSizing(tile, (_game_mode == GM_EDITOR) ? VPM_X_AND_Y : VPM_X_OR_Y, DDSP_CREATE_WATER); diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index b02be76df0..05b8bc4e7e 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -583,7 +583,6 @@ struct BuildRailToolbarWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { - EraseQueuedTouchCommand(); switch (this->last_user_action) { case WID_RAT_BUILD_NS: VpStartPlaceSizing(tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL); diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 904089d3ae..341d15cbfc 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -467,7 +467,6 @@ struct BuildRoadToolbarWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { - EraseQueuedTouchCommand(); _remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE); _one_way_button_clicked = this->IsWidgetLowered(WID_ROT_ONE_WAY); switch (this->last_started_action) { diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index e328a4ad19..51fb0d773c 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -656,7 +656,6 @@ struct ScenarioEditorLandscapeGenerationWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { - EraseQueuedTouchCommand(); switch (this->last_user_action) { case WID_ETT_DEMOLISH: // Demolish aka dynamite button PlaceProc_DemolishArea(tile); diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index 1e1883ece1..e12ec7606b 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -144,7 +144,6 @@ public: virtual void OnPlaceObject(Point pt, TileIndex tile) { - EraseQueuedTouchCommand(); VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_PLANT_TREES); } From 742f20fcc31065fb9b35e40a1815dd91ea1148e4 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 3 Jun 2014 18:44:34 +0300 Subject: [PATCH 134/187] Revert "Erase queued command also when depot direction/airport type/station type changes." This reverts commit 60a7ac9f3c1d4f271f4392859d68df875d612fe7. --- src/airport_gui.cpp | 2 -- src/dock_gui.cpp | 1 - src/rail_gui.cpp | 3 --- src/road_gui.cpp | 2 -- 4 files changed, 8 deletions(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 8b49b998ce..aa57562241 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -423,8 +423,6 @@ public: void UpdateSelectSize() { - EraseQueuedTouchCommand(); - if (_selected_airport_index == -1) { SetTileSelectSize(1, 1); this->DisableWidget(WID_AP_LAYOUT_DECREASE); diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index 4e6ed21402..1d2b2e8abc 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -475,7 +475,6 @@ public: _settings_client.gui.station_show_coverage = (widget != BDSW_LT_OFF); this->LowerWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - EraseQueuedTouchCommand(); this->SetDirty(); break; } diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 05b8bc4e7e..7071ccc849 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1367,8 +1367,6 @@ public: break; } } - - EraseQueuedTouchCommand(); } virtual void OnTick() @@ -1723,7 +1721,6 @@ struct BuildRailDepotWindow : public PickerWindowBase { _build_depot_direction = (DiagDirection)(widget - WID_BRAD_DEPOT_NE); this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - EraseQueuedTouchCommand(); this->SetDirty(); break; } diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 341d15cbfc..890eafed48 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -882,7 +882,6 @@ struct BuildRoadDepotWindow : public PickerWindowBase { _road_depot_orientation = (DiagDirection)(widget - WID_BROD_DEPOT_NE); this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - EraseQueuedTouchCommand(); this->SetDirty(); break; @@ -1029,7 +1028,6 @@ struct BuildRoadStationWindow : public PickerWindowBase { _settings_client.gui.station_show_coverage = (widget != WID_BROS_LT_OFF); this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - EraseQueuedTouchCommand(); this->SetDirty(); break; From e465c8db4d0b011cbceaa7fcfd84596167bf9424 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 3 Jun 2014 20:27:10 +0300 Subject: [PATCH 135/187] Added vertical toolbar option to game settings --- src/settings_gui.cpp | 16 +++++++++++++++- src/widgets/settings_widget.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 07b51d6afe..bf03f98dbf 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -454,6 +454,13 @@ struct GameOptionsWindow : Window { this->SetDirty(); break; + case WID_GO_VERTICAL_TOOLBAR: + _settings_client.gui.vertical_toolbar = !_settings_client.gui.vertical_toolbar; + this->SetWidgetLoweredState(WID_GO_VERTICAL_TOOLBAR, _settings_client.gui.vertical_toolbar); + this->SetDirty(); + ReconstructUserInterface(); + break; + default: { int selected; DropDownList *list = this->BuildDropDownList(widget, &selected); @@ -572,6 +579,7 @@ struct GameOptionsWindow : Window { { if (!gui_scope) return; this->SetWidgetLoweredState(WID_GO_FULLSCREEN_BUTTON, _fullscreen); + this->SetWidgetLoweredState(WID_GO_VERTICAL_TOOLBAR, _settings_client.gui.vertical_toolbar); bool missing_files = BaseGraphics::GetUsedSet()->GetNumMissing() == 0; this->GetWidget(WID_GO_BASE_GRF_STATUS)->SetDataTip(missing_files ? STR_EMPTY : STR_GAME_OPTIONS_BASE_GRF_STATUS, STR_NULL); @@ -626,6 +634,12 @@ static const NWidgetPart _nested_game_options_widgets[] = { NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_CONFIG_SETTING_FONT_SIZE, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_TEXT_SIZE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_JUST_INT, STR_CONFIG_SETTING_FONT_SIZE_TOOLTIP), SetFill(1, 0), EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_CONFIG_SETTING_VERTICAL_TOOLBAR, STR_NULL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_VERTICAL_TOOLBAR), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_CONFIG_SETTING_VERTICAL_TOOLBAR_HELPTEXT), + EndContainer(), + EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 0), SetFill(0, 1), EndContainer(), @@ -1526,7 +1540,7 @@ static SettingEntry _settings_ui[] = { SettingEntry(&_settings_ui_interaction_page, STR_CONFIG_SETTING_INTERACTION), SettingEntry(&_settings_ui_sound_page, STR_CONFIG_SETTING_SOUND), SettingEntry(&_settings_ui_news_page, STR_CONFIG_SETTING_NEWS), - SettingEntry("gui.touchscreen_mode"), + SettingEntry("gui.vertical_toolbar"), SettingEntry("gui.show_finances"), SettingEntry("gui.errmsg_duration"), SettingEntry("gui.hover_delay"), diff --git a/src/widgets/settings_widget.h b/src/widgets/settings_widget.h index 1bb18185a2..6e7575eda8 100644 --- a/src/widgets/settings_widget.h +++ b/src/widgets/settings_widget.h @@ -26,6 +26,7 @@ enum GameOptionsWidgets { WID_GO_SCREENSHOT_DROPDOWN, ///< Select the screenshot type... please use PNG!. WID_GO_BUTTON_SIZE_DROPDOWN, ///< Size of in-game UI elements, such as buttons. WID_GO_TEXT_SIZE_DROPDOWN, ///< Size of medium font, sizes of other fonts are derived from it. + WID_GO_VERTICAL_TOOLBAR, ///< Enable vertical toolbar. WID_GO_BASE_GRF_DROPDOWN, ///< Use to select a base GRF. WID_GO_BASE_GRF_STATUS, ///< Info about missing files etc. WID_GO_BASE_GRF_TEXTFILE, ///< Open base GRF readme, changelog (+1) or license (+2). From 41da4be66b919ebaa7a882f61580815c381524e2 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 3 Jun 2014 20:27:45 +0300 Subject: [PATCH 136/187] Removed remainder of the 'touchscreen mode' code --- src/airport_gui.cpp | 2 -- src/command.cpp | 70 ------------------------------------------ src/command_func.h | 6 ---- src/console_gui.cpp | 8 ----- src/dock_gui.cpp | 2 -- src/gfx.cpp | 2 -- src/lang/english.txt | 9 ++---- src/rail_gui.cpp | 1 - src/road_gui.cpp | 2 -- src/settings_type.h | 1 - src/table/settings.ini | 15 --------- src/terraform_gui.cpp | 1 - src/toolbar_gui.cpp | 1 - src/tree_gui.cpp | 1 - src/video/sdl_v.cpp | 6 ++-- src/window.cpp | 3 +- 16 files changed, 5 insertions(+), 125 deletions(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index aa57562241..225a95e5b9 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -143,7 +143,6 @@ struct BuildAirToolbarWindow : Window { DeleteWindowById(WC_BUILD_STATION, TRANSPORT_AIR); DeleteWindowById(WC_SELECT_STATION, 0); - EraseQueuedTouchCommand(); ResetObjectToPlace(); } @@ -244,7 +243,6 @@ public: virtual ~BuildAirportWindow() { - EraseQueuedTouchCommand(); DeleteWindowById(WC_SELECT_STATION, 0); } diff --git a/src/command.cpp b/src/command.cpp index fc827449f3..777eb4107c 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -527,76 +527,6 @@ bool DoCommandP(const CommandContainer *container, bool my_cmd) return DoCommandP(container->tile, container->p1, container->p2, container->cmd, container->callback, container->text, my_cmd); } -/* Stored data for a command that is waiting for user confirmation. */ -bool _is_queued_command; -bool _my_cmd; -CommandContainer _queued_command; - -/** - * Store a command that needs user confirmation. - * If current mode doesn't need confirmation, execute it immediately via DoCommandP. - * @param tile The tile to perform a command on (see #CommandProc) - * @param p1 Additional data for the command (see #CommandProc) - * @param p2 Additional data for the command (see #CommandProc) - * @param cmd The command to execute (a CMD_* value) - * @param callback A callback function to call after the command is finished - * @param text The text to pass - * @param my_cmd indicator if the command is from a company or server (to display error messages for a user) - * @return \c true if the command succeeded or is stored, else \c false. - */ -bool TouchCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd) -{ - if (_settings_client.gui.touchscreen_mode == TSC_CONFIRM && !_shift_pressed) { - _queued_command.tile = tile; - _queued_command.p1 = p1; - _queued_command.p2 = p2; - _queued_command.cmd = cmd; - _queued_command.callback = callback; - if (text != NULL) ttd_strlcpy(_queued_command.text, text, 32 * MAX_CHAR_LENGTH); - _my_cmd = my_cmd; - _is_queued_command = true; - return true; - } else { - return DoCommandP(tile, p1, p2, cmd, callback, text, my_cmd); - } -} - -/** - * Shortcut for the long TouchCommandP when having a container with the data. - * Store a command that needs user confirmation. - * If current mode doesn't need confirmation, execute it immediately via DoCommandP. - * @param container the container with information. - * @param my_cmd indicator if the command is from a company or server (to display error messages for a user) - * @return true if the command succeeded or when it is stored, else false - */ -bool TouchCommandP(const CommandContainer *container, bool my_cmd) -{ - return TouchCommandP(container->tile, container->p1, container->p2, container->cmd, container->callback, container->text, my_cmd); -} - -/** Return whether there is a command stored waiting for confirmation. */ -bool IsQueuedTouchCommand() -{ - return _is_queued_command; -} - -/** Execute a stored command. Keep it when asking for estimated cost. */ -bool DoQueuedTouchCommand() -{ - bool result = DoCommandP(&_queued_command, _my_cmd); - if (!_shift_pressed && result) EraseQueuedTouchCommand(); - return result; -} - -/** Erase a stored command and update viewport and touchscreen bar. */ -void EraseQueuedTouchCommand() -{ - if (!IsQueuedTouchCommand()) return; - _is_queued_command = false; - SetSelectionTilesDirty(); - _thd.Reset(); -} - /*! * Toplevel network safe docommand function for the current company. Must not be called recursively. * The callback is called when the command succeeded or failed. The parameters diff --git a/src/command_func.h b/src/command_func.h index ab9fb05d42..c4cc51e3da 100644 --- a/src/command_func.h +++ b/src/command_func.h @@ -40,12 +40,6 @@ CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags); bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = NULL, const char *text = NULL, bool my_cmd = true); bool DoCommandP(const CommandContainer *container, bool my_cmd = true); -bool TouchCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = NULL, const char *text = NULL, bool my_cmd = true); -bool TouchCommandP(const CommandContainer *container, bool my_cmd = true); -bool IsQueuedTouchCommand(); -bool DoQueuedTouchCommand(); -void EraseQueuedTouchCommand(); - CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only); #ifdef ENABLE_NETWORK diff --git a/src/console_gui.cpp b/src/console_gui.cpp index dbf194d163..3f5fe45302 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -232,14 +232,6 @@ struct IConsoleWindow : Window } } - virtual void OnClick(Point pt, int widget, int click_count) - { - if (_settings_client.gui.touchscreen_mode == 0) return; - - ShowQueryString(STR_EMPTY, STR_CONSOLE_QUERY_STRING, ICON_CMDLN_SIZE, - this, CS_ALPHANUMERAL, QSF_NONE); - } - virtual void OnQueryTextFinished(char *str) { _focused_window = this; diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index 1d2b2e8abc..9dcb3c40d8 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -280,7 +280,6 @@ struct BuildDocksToolbarWindow : Window { DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_WATER); DeleteWindowById(WC_SELECT_STATION, 0); DeleteWindowByClass(WC_BUILD_BRIDGE); - EraseQueuedTouchCommand(); } virtual void OnPlacePresize(Point pt, TileIndex tile_from) @@ -554,7 +553,6 @@ public: this->LowerWidget(_ship_depot_direction + WID_BDD_X); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); UpdateDocksDirection(); - EraseQueuedTouchCommand(); this->SetDirty(); break; } diff --git a/src/gfx.cpp b/src/gfx.cpp index e489bae363..10af016469 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -1187,8 +1187,6 @@ void UndrawMouseCursor() void DrawMouseCursor() { - if (_settings_client.gui.touchscreen_mode != 0) return; - /* Don't draw the mouse cursor if the screen is not ready */ if (_screen.dst_ptr == NULL) return; diff --git a/src/lang/english.txt b/src/lang/english.txt index 601a929e2c..1617b0c538 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1184,13 +1184,8 @@ STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :Select on which STR_CONFIG_SETTING_SIGNALSIDE_LEFT :On the left STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :On the driving side STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :On the right -STR_CONFIG_SETTING_VERTICAL_TOOLBAR :Vertical toolbar -STR_CONFIG_SETTING_VERTICAL_TOOLBAR_HELPTEXT :Main toolbar is split into two vertical toolbars on the sides of the screen -STR_CONFIG_SETTING_TOUCHSCREEN_MODE :Control mode for touchscreen devices: {STRING2} -STR_CONFIG_SETTING_TOUCHSCREEN_MODE_HELPTEXT :If playing with a mouse, choose no adaptation. Other modes are for touchscreen devices. Associated hotkey: N -STR_CONFIG_SETTING_TOUCHSCREEN_NONE :no adaptation -STR_CONFIG_SETTING_TOUCHSCREEN_SIMPLE :simple -STR_CONFIG_SETTING_TOUCHSCREEN_CONFIRM :confirm +STR_CONFIG_SETTING_VERTICAL_TOOLBAR :{BLACK}Vertical toolbar +STR_CONFIG_SETTING_VERTICAL_TOOLBAR_HELPTEXT :{BLACK}Main toolbar is split into two vertical toolbars on the sides of the screen STR_CONFIG_SETTING_BUTTON_SIZE :{BLACK}Button size STR_CONFIG_SETTING_BUTTON_SIZE_TOOLTIP :{BLACK}Size of all user interface elements STR_CONFIG_SETTING_FONT_SIZE :{BLACK}Font size diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 7071ccc849..082d169314 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -753,7 +753,6 @@ struct BuildRailToolbarWindow : Window { DeleteWindowById(WC_BUILD_WAYPOINT, TRANSPORT_RAIL); DeleteWindowById(WC_SELECT_STATION, 0); DeleteWindowByClass(WC_BUILD_BRIDGE); - EraseQueuedTouchCommand(); } virtual void OnPlacePresize(Point pt, TileIndex tile_from) diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 890eafed48..8058ed5668 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -532,7 +532,6 @@ struct BuildRoadToolbarWindow : Window { DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_ROAD); DeleteWindowById(WC_SELECT_STATION, 0); DeleteWindowByClass(WC_BUILD_BRIDGE); - EraseQueuedTouchCommand(); } virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) @@ -1019,7 +1018,6 @@ struct BuildRoadStationWindow : public PickerWindowBase { if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); DeleteWindowById(WC_SELECT_STATION, 0); - EraseQueuedTouchCommand(); break; case WID_BROS_LT_OFF: diff --git a/src/settings_type.h b/src/settings_type.h index 84ec1ab559..6a9752c991 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -79,7 +79,6 @@ struct GUISettings { uint8 order_review_system; ///< perform order reviews on vehicles bool vehicle_income_warn; ///< if a vehicle isn't generating income, show a warning bool vertical_toolbar; ///< main toolbar is split into two vertical toolbars - TouchscreenModeByte touchscreen_mode; ///< touchscreen mode for toolbars uint min_button; ///< min size of most button widgets uint min_step; ///< min size of scrollbar/dropdown elements bool show_finances; ///< show finances at end of year diff --git a/src/table/settings.ini b/src/table/settings.ini index 4d9577b220..4a1036aea4 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -2507,21 +2507,6 @@ strhelp = STR_CONFIG_SETTING_VERTICAL_TOOLBAR_HELPTEXT proc = VerticalToolbarChanged cat = SC_BASIC -[SDTC_VAR] -var = gui.touchscreen_mode -flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -type = SLE_UINT8 -guiflags = SGF_MULTISTRING -def = 0 -min = 0 -max = 2 -interval = 1 -str = STR_CONFIG_SETTING_TOUCHSCREEN_MODE -strval = STR_CONFIG_SETTING_TOUCHSCREEN_NONE -strhelp = STR_CONFIG_SETTING_TOUCHSCREEN_MODE_HELPTEXT -proc = TouchscreenModeChanged -cat = SC_BASIC - [SDTC_BOOL] var = gui.show_finances flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index 51fb0d773c..f2c56063fd 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -288,7 +288,6 @@ struct TerraformToolbarWindow : Window { { DeleteWindowById(WC_BUILD_OBJECT, 0); this->RaiseButtons(); - EraseQueuedTouchCommand(); ResetObjectToPlace(); } diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index edacf68c64..96aafb7b79 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1180,7 +1180,6 @@ static CallBackFunction ToolbarCtrlClick(Window *w) w->SetWidgetLoweredState(WID_TN_CTRL, _ctrl_pressed); w->SetWidgetDirty(WID_TN_CTRL); HandleCtrlChanged(); - EraseQueuedTouchCommand(); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index e12ec7606b..34c3862da2 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -174,7 +174,6 @@ public: this->RaiseButtons(); ResetObjectToPlace(); - EraseQueuedTouchCommand(); } }; diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index c20cac2cfa..42671c1985 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -775,10 +775,8 @@ void VideoDriver_SDL::MainLoop() bool old_ctrl_pressed = _ctrl_pressed; #ifndef __ANDROID__ - if (_settings_client.gui.touchscreen_mode == TSC_NONE) { - _ctrl_pressed = !!(mod & KMOD_CTRL); - _shift_pressed = !!(mod & KMOD_SHIFT); - } + _ctrl_pressed = !!(mod & KMOD_CTRL); + _shift_pressed = !!(mod & KMOD_SHIFT); #endif /* determine which directional keys are down */ diff --git a/src/window.cpp b/src/window.cpp index f7590fc25b..a037d6d19a 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2842,13 +2842,12 @@ static void MouseLoop(MouseClick click, int mousewheel) Window *w = FindWindowFromPt(x, y); if (w == NULL) return; ViewPort *vp = IsPtInWindowViewport(w, x, y); - bool confirm = (_settings_client.gui.touchscreen_mode == TSC_CONFIRM); /* Don't allow any action in a viewport if either in menu or when having a modal progress window */ if (vp != NULL && (_game_mode == GM_MENU || HasModalProgress())) return; /* On confirm mode do not update tile selection unless we are clicking on a viewport. */ - if (!confirm || (vp != NULL && _left_button_down && !_move_pressed)) { + if (vp != NULL && _left_button_down && !_move_pressed) { HandlePlacePresize(); UpdateTileSelection(); } else { From 15db61be6912f57c4dcb320bb840df9c4e7bf0fb Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 3 Jun 2014 20:32:39 +0300 Subject: [PATCH 137/187] Fixed mouse click passed down to map after closing a window. --- src/window.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/window.cpp b/src/window.cpp index a037d6d19a..88f8165325 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2837,6 +2837,7 @@ static void MouseLoop(MouseClick click, int mousewheel) * But there is no company related window open anyway, so _current_company is not used. */ assert(HasModalProgress() || IsLocalCompany()); + static bool mouse_down_on_viewport = false; int x = _cursor.pos.x; int y = _cursor.pos.y; Window *w = FindWindowFromPt(x, y); @@ -2889,13 +2890,15 @@ static void MouseLoop(MouseClick click, int mousewheel) _scrolling_viewport = true; _cursor.fix_at = false; } + mouse_down_on_viewport = true; break; case MC_LEFT_UP: - if (!_left_button_dragged) { + if (!_left_button_dragged && mouse_down_on_viewport) { HandleViewportMouseUp(vp, x, y); } _left_button_dragged = false; + mouse_down_on_viewport = false; break; case MC_RIGHT: From c323eb1c8afd1466d3979280b60d8a33afe1123e Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 3 Jun 2014 21:42:33 +0300 Subject: [PATCH 138/187] Fixed dropdown lists in main toolbar --- src/toolbar_gui.cpp | 6 +++--- src/widgets/dropdown.cpp | 12 +++++++----- src/window.cpp | 31 +++++++++++++++++++++++++------ 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 96aafb7b79..bc314eb67f 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -176,10 +176,10 @@ static void PopupMainToolbMenu(Window *w, int widget, DropDownList *list, int de } else { Rect wi_rect; NWidgetCore *nwi = w->GetWidget(widget); - wi_rect.left = ((int)nwi->pos_x < _screen.width / 2) ? nwi->pos_x + nwi->current_x - 1 : nwi->pos_x - nwi->current_x; - wi_rect.right = ((int)nwi->pos_x < _screen.width / 2) ? nwi->pos_x + nwi->current_x * 2 : nwi->pos_x - 1; + wi_rect.left = nwi->pos_x; + wi_rect.right = nwi->pos_x + nwi->current_x; wi_rect.top = nwi->pos_y; - wi_rect.bottom = nwi->pos_y + nwi->current_y - 1; + wi_rect.bottom = nwi->pos_y + nwi->current_y; ShowDropDownListAt(w, list, def, widget, wi_rect, nwi->colour, true, true); } if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 6603dd588a..a5b7be1ea1 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -365,12 +365,14 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b int screen_bottom = GetMainViewBottom(); bool scroll = false; + enum { DISPLAY_BORDER = 20 }; + /* Check if the dropdown will fully fit below the widget. */ - if (top + height + 4 >= screen_bottom) { + if (top + height + DISPLAY_BORDER >= screen_bottom) { /* If not, check if it will fit above the widget. */ int screen_top = GetMainViewTop(); if (w->top + wi_rect.top > screen_top + height) { - top = w->top + wi_rect.top - height - 4; + top = w->top + wi_rect.top - height; } else { /* If it doesn't fit above the widget, we need to enable a scrollbar... */ int avg_height = list_height / (int)list->Length(); @@ -378,10 +380,10 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b /* ... and choose whether to put the list above or below the widget. */ bool put_above = false; - int available_height = screen_bottom - w->top - wi_rect.bottom; + int available_height = screen_bottom - w->top - wi_rect.bottom - DISPLAY_BORDER; if (w->top + wi_rect.top - screen_top > available_height) { // Put it above. - available_height = w->top + wi_rect.top - screen_top; + available_height = w->top + wi_rect.top - screen_top - DISPLAY_BORDER; put_above = true; } @@ -397,7 +399,7 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b /* ... and set the top position if needed. */ if (put_above) { - top = w->top + wi_rect.top - height - 4; + top = w->top + wi_rect.top - height; } } } diff --git a/src/window.cpp b/src/window.cpp index 88f8165325..9558e92572 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1476,9 +1476,8 @@ void Window::FindWindowPlacementAndResize(int def_width, int def_height) int enlarge_x = max(min(def_width - this->width, _screen.width - this->width), 0); int enlarge_y = max(min(def_height - this->height, free_height - this->height), 0); - if (wt && _settings_client.gui.vertical_toolbar && - enlarge_x > _screen.width - wt->width * 2) { - //enlarge_x = _screen.width - wt->width * 2; + if (wt && _settings_client.gui.vertical_toolbar && enlarge_x > _screen.width - wt->width * 2) { + enlarge_x = _screen.width - wt->width * 2; } /* X and Y has to go by step.. calculate it. @@ -1500,8 +1499,13 @@ void Window::FindWindowPlacementAndResize(int def_width, int def_height) if (nx + this->width > _screen.width) nx -= (nx + this->width - _screen.width); const Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0); - ny = max(ny, (wt == NULL || this == wt || this->top == 0) ? 0 : wt->height); - nx = max(nx, 0); + if (!_settings_client.gui.vertical_toolbar) { + ny = max(ny, (wt == NULL || this == wt || this->top == 0) ? 0 : wt->height); + nx = max(nx, 0); + } else { + nx = max(nx, (wt == NULL || this == wt || this == FindWindowById(WC_MAIN_TOOLBAR_RIGHT, 0) || this->left == 0) ? 0 : wt->width); + ny = max(ny, 0); + } if (this->viewport != NULL) { this->viewport->left += nx - this->left; @@ -1510,6 +1514,8 @@ void Window::FindWindowPlacementAndResize(int def_width, int def_height) this->left = nx; this->top = ny; + DEBUG(misc, 0, "%s: %d:%d+%d+%d", __func__, this->left, this->top, this->width, this->height); + this->SetDirty(); } @@ -1528,6 +1534,7 @@ static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &po { int right = width + left; int bottom = height + top; + DEBUG(misc, 0, "%s: %d:%d+%d+%d", __func__, left, top, width, height); const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); if (!_settings_client.gui.vertical_toolbar || !main_toolbar) { @@ -1551,6 +1558,7 @@ static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &po pos.x = left; pos.y = top; + DEBUG(misc, 0, "%s: pos %d:%d", __func__, pos.x, pos.y); return true; } @@ -1567,6 +1575,8 @@ static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &po */ static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &pos) { + DEBUG(misc, 0, "%s: %d:%d+%d+%d", __func__, left, top, width, height); + /* Left part of the rectangle may be at most 1/4 off-screen, * right part of the rectangle may be at most 1/2 off-screen */ @@ -1589,6 +1599,7 @@ static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &po pos.x = left; pos.y = top; + DEBUG(misc, 0, "%s: pos %d:%d", __func__, pos.x, pos.y); return true; } @@ -1601,6 +1612,7 @@ static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &po static Point GetAutoPlacePosition(int width, int height) { Point pt; + DEBUG(misc, 0, "%s: +%d+%d", __func__, width, height); /* First attempt, try top-left of the screen */ const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); @@ -1661,6 +1673,7 @@ restart: pt.x = left; pt.y = top; + DEBUG(misc, 0, "%s: pos %d:%d", __func__, pt.x, pt.y); return pt; } @@ -1719,6 +1732,10 @@ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int if (pt.x > _screen.width + 10 - default_width) { pt.x = (_screen.width + 10 - default_width) - 20; } + const Window *w = FindWindowById(WC_MAIN_TOOLBAR_RIGHT, 0); + if (w && pt.x + default_width > _screen.width - w->width ) { + pt.x = _screen.width - w->width - default_width; + } pt.y = w->top + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? w->height : 10); return pt; @@ -1752,7 +1769,9 @@ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int /* virtual */ Point Window::OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { - return LocalGetWindowPlacement(this->window_desc, sm_width, sm_height, window_number); + Point pt = LocalGetWindowPlacement(this->window_desc, sm_width, sm_height, window_number); + DEBUG(misc, 0, "%s: %d:%d+%d+%d", __func__, pt.x, pt.y, sm_width, sm_height); + return pt; } /** From 75c376a23eed621210fd98ade079f00b7edabffd Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 3 Jun 2014 21:48:28 +0300 Subject: [PATCH 139/187] Removed debug --- src/window.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/window.cpp b/src/window.cpp index 9558e92572..6a619edae5 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1514,8 +1514,6 @@ void Window::FindWindowPlacementAndResize(int def_width, int def_height) this->left = nx; this->top = ny; - DEBUG(misc, 0, "%s: %d:%d+%d+%d", __func__, this->left, this->top, this->width, this->height); - this->SetDirty(); } @@ -1534,7 +1532,6 @@ static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &po { int right = width + left; int bottom = height + top; - DEBUG(misc, 0, "%s: %d:%d+%d+%d", __func__, left, top, width, height); const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); if (!_settings_client.gui.vertical_toolbar || !main_toolbar) { @@ -1558,7 +1555,6 @@ static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &po pos.x = left; pos.y = top; - DEBUG(misc, 0, "%s: pos %d:%d", __func__, pos.x, pos.y); return true; } @@ -1575,8 +1571,6 @@ static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &po */ static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &pos) { - DEBUG(misc, 0, "%s: %d:%d+%d+%d", __func__, left, top, width, height); - /* Left part of the rectangle may be at most 1/4 off-screen, * right part of the rectangle may be at most 1/2 off-screen */ @@ -1599,7 +1593,6 @@ static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &po pos.x = left; pos.y = top; - DEBUG(misc, 0, "%s: pos %d:%d", __func__, pos.x, pos.y); return true; } @@ -1612,7 +1605,6 @@ static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &po static Point GetAutoPlacePosition(int width, int height) { Point pt; - DEBUG(misc, 0, "%s: +%d+%d", __func__, width, height); /* First attempt, try top-left of the screen */ const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); @@ -1673,7 +1665,6 @@ restart: pt.x = left; pt.y = top; - DEBUG(misc, 0, "%s: pos %d:%d", __func__, pt.x, pt.y); return pt; } @@ -1769,9 +1760,7 @@ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int /* virtual */ Point Window::OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { - Point pt = LocalGetWindowPlacement(this->window_desc, sm_width, sm_height, window_number); - DEBUG(misc, 0, "%s: %d:%d+%d+%d", __func__, pt.x, pt.y, sm_width, sm_height); - return pt; + return LocalGetWindowPlacement(this->window_desc, sm_width, sm_height, window_number); } /** @@ -2902,7 +2891,7 @@ static void MouseLoop(MouseClick click, int mousewheel) switch (click) { case MC_DOUBLE_LEFT: case MC_LEFT: - DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite); + //DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite); if (!HandleViewportClicked(vp, x, y) && !(w->flags & WF_DISABLE_VP_SCROLL) && (_settings_client.gui.left_mouse_btn_scrolling || _move_pressed)) { From 3cb6c7d5ee882627e9c1eb5fcccf5759f221577e Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 3 Jun 2014 21:55:41 +0300 Subject: [PATCH 140/187] Fixed right toolbar moving to the left, removed remainder of 'touchscreen mode' stuff --- src/settings.cpp | 6 ------ src/settings_type.h | 1 - src/table/settings.ini | 1 - src/toolbar_gui.h | 2 -- src/toolbar_type.h | 24 ------------------------ src/window.cpp | 10 ++++++++-- 6 files changed, 8 insertions(+), 36 deletions(-) delete mode 100644 src/toolbar_type.h diff --git a/src/settings.cpp b/src/settings.cpp index 0142d502b0..5d65795107 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1081,12 +1081,6 @@ static bool VerticalToolbarChanged(int32 p1) return true; } -static bool TouchscreenModeChanged(int32 p1) -{ - //ResetTabletWindow(); - return true; -} - /** * Update any possible saveload window and delete any newgrf dialogue as * its widget parts might change. Reinit all windows as it allows access to the diff --git a/src/settings_type.h b/src/settings_type.h index 6a9752c991..235b7bebc7 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -21,7 +21,6 @@ #include "linkgraph/linkgraph_type.h" #include "zoom_type.h" #include "openttd.h" -#include "toolbar_type.h" /** Settings profiles and highscore tables. */ diff --git a/src/table/settings.ini b/src/table/settings.ini index 4a1036aea4..478f6abf9e 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -41,7 +41,6 @@ static bool InvalidateCompanyInfrastructureWindow(int32 p1); static bool InvalidateCompanyWindow(int32 p1); static bool ZoomMinMaxChanged(int32 p1); static bool VerticalToolbarChanged(int32 p1); -static bool TouchscreenModeChanged(int32 p1); #ifdef ENABLE_NETWORK static bool UpdateClientName(int32 p1); diff --git a/src/toolbar_gui.h b/src/toolbar_gui.h index 3461c22902..1ad147b3f2 100644 --- a/src/toolbar_gui.h +++ b/src/toolbar_gui.h @@ -16,8 +16,6 @@ void AllocateToolbar(); void ToggleBoundingBoxes(); void ToggleDirtyBlocks(); -void ResetTabletWindow(); - extern int _last_clicked_toolbar_idx; #endif /* TOOLBAR_GUI_H */ diff --git a/src/toolbar_type.h b/src/toolbar_type.h deleted file mode 100644 index 682cf2f568..0000000000 --- a/src/toolbar_type.h +++ /dev/null @@ -1,24 +0,0 @@ -/* $Id$ */ - -/* - * 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 . - */ - -/** @file toolbar_type.h Types related to toolbars. */ - -#ifndef TOOLBAR_TYPE_H -#define TOOLBAR_TYPE_H - -/** Types of touchscreen modes. */ -enum TouchscreenMode { - TSC_NONE = 0, - TSC_SIMPLE, - TSC_CONFIRM, -}; -DECLARE_CYCLE(TouchscreenMode, TSC_NONE, TSC_CONFIRM) -typedef SimpleTinyEnumT TouchscreenModeByte; - -#endif /* TOOLBAR_TYPE_H */ diff --git a/src/window.cpp b/src/window.cpp index 6a619edae5..67cc604332 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -3449,7 +3449,7 @@ static int PositionWindow(Window *w, WindowClass clss, int setting) */ int PositionMainToolbar(Window *w) { - if (_settings_client.gui.vertical_toolbar) return 0; + if (_settings_client.gui.vertical_toolbar) return 0; /* Always at the left */ DEBUG(misc, 5, "Repositioning Main Toolbar..."); return PositionWindow(w, WC_MAIN_TOOLBAR, _settings_client.gui.toolbar_pos); } @@ -3525,13 +3525,19 @@ void RelocateAllWindows(int neww, int newh) continue; case WC_MAIN_TOOLBAR: - case WC_MAIN_TOOLBAR_RIGHT: ResizeWindow(w, min(neww, w->window_desc->default_width) - w->width, 0, false); top = w->top; left = PositionMainToolbar(w); // changes toolbar orientation break; + case WC_MAIN_TOOLBAR_RIGHT: + ResizeWindow(w, min(neww, w->window_desc->default_width) - w->width, 0, false); + + top = w->top; + left = neww - w->width; + break; + case WC_NEWS_WINDOW: top = newh - w->height; left = PositionNewsMessage(w); From 8ca0bf745a06ea49f36d9f12d6c144e113a63568 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 3 Jun 2014 22:36:38 +0300 Subject: [PATCH 141/187] Fixed bug in my previous commit --- src/toolbar_gui.cpp | 2 +- src/window.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index bc314eb67f..23fb21e5f8 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1040,7 +1040,7 @@ static CallBackFunction PlaceLandBlockInfo() ResetObjectToPlace(); return CBF_NONE; } else { - SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0); + SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, _settings_client.gui.vertical_toolbar ? WC_MAIN_TOOLBAR_RIGHT : WC_MAIN_TOOLBAR, 0); return CBF_PLACE_LANDINFO; } } diff --git a/src/window.cpp b/src/window.cpp index 67cc604332..4cc7e1b963 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1723,9 +1723,9 @@ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int if (pt.x > _screen.width + 10 - default_width) { pt.x = (_screen.width + 10 - default_width) - 20; } - const Window *w = FindWindowById(WC_MAIN_TOOLBAR_RIGHT, 0); - if (w && pt.x + default_width > _screen.width - w->width ) { - pt.x = _screen.width - w->width - default_width; + const Window *wt = FindWindowById(WC_MAIN_TOOLBAR_RIGHT, 0); + if (wt && pt.x + default_width > _screen.width - wt->width) { + pt.x = _screen.width - wt->width - default_width; } pt.y = w->top + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? w->height : 10); @@ -2897,6 +2897,8 @@ static void MouseLoop(MouseClick click, int mousewheel) (_settings_client.gui.left_mouse_btn_scrolling || _move_pressed)) { _scrolling_viewport = true; _cursor.fix_at = false; + } else { + _left_button_dragged = true; } mouse_down_on_viewport = true; break; From 19472fd0d2263871beff730f81ed40f232d1f5f9 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 3 Jun 2014 23:35:05 +0300 Subject: [PATCH 142/187] Fixed screenshot action, broken by 16bpp blitter --- src/fileio.cpp | 4 ++++ src/screenshot.cpp | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 707eae5c56..9c400634ef 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -290,7 +290,11 @@ static const char * const _subdirs[] = { "ai" PATHSEP "library" PATHSEP, "game" PATHSEP, "game" PATHSEP "library" PATHSEP, +#ifdef __ANDROID__ + "../../../../../../Pictures/", +#else "screenshot" PATHSEP, +#endif }; assert_compile(lengthof(_subdirs) == NUM_SUBDIRS); diff --git a/src/screenshot.cpp b/src/screenshot.cpp index 6e72dd520c..8e125dc85a 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -25,6 +25,7 @@ #include "window_func.h" #include "tile_map.h" #include "landscape.h" +#include "blitter/16bpp_base.hpp" #include "table/strings.h" @@ -34,7 +35,7 @@ static const char * const HEIGHTMAP_NAME = "heightmap"; ///< Default filename char _screenshot_format_name[8]; ///< Extension of the current screenshot format (corresponds with #_cur_screenshot_format). uint _num_screenshot_formats; ///< Number of available screenshot formats. uint _cur_screenshot_format; ///< Index of the currently selected screenshot format in #_screenshot_formats. -static char _screenshot_name[128]; ///< Filename of the screenshot file. +static char _screenshot_name[256]; ///< Filename of the screenshot file. char _full_screenshot_name[MAX_PATH]; ///< Pathname of the screenshot file. /** @@ -272,7 +273,8 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user png_infop info_ptr; /* only implemented for 8bit and 32bit images so far. */ - if (pixelformat != 8 && pixelformat != 32) return false; + if (pixelformat != 8 && pixelformat != 32 && pixelformat != 16) return false; + if (pixelformat == 16) bpp = 3; f = fopen(name, "wb"); if (f == NULL) return false; @@ -386,6 +388,17 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user /* render the pixels into the buffer */ callb(userdata, buff, y, w, n); y += n; + if (pixelformat == 16) { + // Convert to 24bpp + Blitter_16bppBase::Colour16 *inp = (Blitter_16bppBase::Colour16 *)buff; + uint8 *outp = (uint8 *)buff; + for (i = 1; i <= w * n; i++) { + outp[(w * n - i) * 3 ] = inp[w * n - i].r << 3; + outp[(w * n - i) * 3 + 1] = inp[w * n - i].g << 2; + outp[(w * n - i) * 3 + 2] = inp[w * n - i].b << 3; + //outp[(w * n - i) * 3] = 0xff; + } + } /* write them to png */ for (i = 0; i != n; i++) { From 2b7b42f09e8118a58b7d6fa12bee5e5506db0c53 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 1 Jul 2014 22:01:22 +0300 Subject: [PATCH 143/187] Fixed 32bpp base graphics set not working on 16bpp videomode --- src/fontcache.cpp | 2 +- src/spritecache.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/fontcache.cpp b/src/fontcache.cpp index f1a2ac7775..41754a7755 100644 --- a/src/fontcache.cpp +++ b/src/fontcache.cpp @@ -453,7 +453,7 @@ static void *AllocateFont(size_t size) static bool GetFontAAState(FontSize size) { /* AA is only supported for 32 bpp */ - if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false; + if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32 && BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 16) return false; switch (size) { default: NOT_REACHED(); diff --git a/src/spritecache.cpp b/src/spritecache.cpp index c41b8f51cb..e2ae84f0e0 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -400,6 +400,10 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty /* Try for 32bpp sprites first. */ sprite_avail = sprite_loader.LoadSprite(sprite, file_slot, file_pos, sprite_type, true); } + if (sprite_type != ST_MAPGEN && BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 16) { + /* 32bpp sprites for 16bpp videomode. */ + sprite_avail = sprite_loader.LoadSprite(sprite, file_slot, file_pos, sprite_type, true); + } if (sprite_avail == 0) { sprite_avail = sprite_loader.LoadSprite(sprite, file_slot, file_pos, sprite_type, false); } From e0166f471aa2a2c8bcd81fa4d12b76a0700a2da2 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 19 Jul 2014 21:18:35 +0300 Subject: [PATCH 144/187] Increased height of 'Buy vehicle' window, so more info would fit the screen --- src/build_vehicle_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 4e5fdb4684..5d3e91b874 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1313,7 +1313,7 @@ struct BuildVehicleWindow : Window { switch (widget) { case WID_BV_LIST: resize->height = GetEngineListHeight(this->vehicle_type); - size->height = 3 * resize->height; + size->height = 4 * resize->height; break; case WID_BV_PANEL: From 3fe4a7846eadc2899bdb71415e997a9eae8fe2ff Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 19 Jul 2014 21:21:19 +0300 Subject: [PATCH 145/187] Added shorter command 'cheats' to open cheats window --- src/console_cmds.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 0b5a5d46e8..80352031d5 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -1943,6 +1943,7 @@ void IConsoleStdLibRegister() IConsoleCmdRegister("saveconfig", ConSaveConfig); IConsoleCmdRegister("ls", ConListFiles); IConsoleCmdRegister("open_cheats", ConOpenCheats); + IConsoleCmdRegister("cheats", ConOpenCheats); IConsoleCmdRegister("cd", ConChangeDirectory); IConsoleCmdRegister("pwd", ConPrintWorkingDirectory); IConsoleCmdRegister("clear", ConClearBuffer); From f377302cbf400e454fadd9bca84d5fa056bd61e0 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 19 Jul 2014 22:16:18 +0300 Subject: [PATCH 146/187] Switch to full vertical toolbar, if enough screen height --- src/toolbar_gui.cpp | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 9b389ae9ce..0afa8727b8 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1622,7 +1622,7 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { } }; -/** Container for the 'normal' main toolbar */ +/** Container for the vertical main toolbar */ class NWidgetVerticalToolbarContainer : public NWidgetToolbarContainer { int side; @@ -1641,9 +1641,25 @@ class NWidgetVerticalToolbarContainer : public NWidgetToolbarContainer { 29, 21, 22, 23, 24, 25, 7, 8, 9, 12, 14, 28, 29, 15, 16, 17, 18, 13, 7, 10, 11, 26, 27, 28, }; + // Full-length toolbar without switch button, if enough space + static const byte arrange_left_all[] = { + 32, 30, 31, 19, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + }; + static const byte arrange_right_all[] = { + 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, + }; spacer_count = 0; + if (_screen.height / this->smallest_y >= lengthof(arrange_left_all)) + { + button_count = arrangable_count = lengthof(arrange_left_all); + if (side == 0) { + return arrange_left_all; + } + return arrange_right_all; + } + if (side == 0) { button_count = arrangable_count = lengthof(arrange_left); return arrange_left; @@ -1651,16 +1667,6 @@ class NWidgetVerticalToolbarContainer : public NWidgetToolbarContainer { button_count = arrangable_count = lengthof(arrange_right) / 2; return &arrange_right[((_toolbar_mode == TB_LOWER) ? button_count : 0)]; } - - /* - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) - { - if (side == 0) x = 0; - else x = _screen.width - this->smallest_x; - y = 0; - NWidgetToolbarContainer::AssignSizePosition(sizing, x, y, given_width, given_height, rtl); - } - */ }; /** Container for the scenario editor's toolbar */ @@ -2107,7 +2113,11 @@ static NWidgetBase *MakeVerticalRightToolbar(int *biggest_index) tb->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, _toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); } - *biggest_index = max(*biggest_index, WID_TN_SWITCH_BAR); + tb->Add(new NWidgetLeaf(WWT_TEXTBTN, COLOUR_GREY, WID_TN_CTRL, STR_TABLET_CTRL, STR_TABLET_CTRL_TOOLTIP)); + tb->Add(new NWidgetLeaf(WWT_TEXTBTN, COLOUR_GREY, WID_TN_SHIFT, STR_TABLET_SHIFT, STR_TABLET_SHIFT_TOOLTIP)); + tb->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TN_DELETE, STR_TABLET_CLOSE, STR_TABLET_CLOSE_TOOLTIP)); + + *biggest_index = max(*biggest_index, WID_TN_DELETE); return tb; } From c0d262b572ad466a13bd8c862ed4dfe6460a8b27 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 19 Jul 2014 22:21:29 +0300 Subject: [PATCH 147/187] Re-arranged buttons a bit --- src/toolbar_gui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 0afa8727b8..9a8641ad7f 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1643,10 +1643,10 @@ class NWidgetVerticalToolbarContainer : public NWidgetToolbarContainer { }; // Full-length toolbar without switch button, if enough space static const byte arrange_left_all[] = { - 32, 30, 31, 19, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 32, 30, 31, 19, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, }; static const byte arrange_right_all[] = { - 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, + 10, 11, 12, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, }; spacer_count = 0; From b6991a304487e726141fdbffad0913ed9dd91ef5 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 19 Jul 2014 22:49:10 +0300 Subject: [PATCH 148/187] Fixed more mousic clipping --- src/music/libtimidity.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/music/libtimidity.cpp b/src/music/libtimidity.cpp index 798f02dda4..02542fc9b9 100644 --- a/src/music/libtimidity.cpp +++ b/src/music/libtimidity.cpp @@ -77,11 +77,12 @@ void Android_MidiMixMusic(Sint16 *stream, int len) /** Factory for the libtimidity driver. */ static FMusicDriver_LibTimidity iFMusicDriver_LibTimidity; +enum { TIMIDITY_MAX_VOLUME = 50 }; const char *MusicDriver_LibTimidity::Start(const char * const *param) { _midi.status = MIDI_STOPPED; _midi.song = NULL; - volume = 99; // Avoid clipping + volume = TIMIDITY_MAX_VOLUME; // Avoid clipping if (mid_init(param == NULL ? NULL : const_cast(param[0])) < 0) { /* If init fails, it can be because no configuration was found. @@ -164,6 +165,6 @@ bool MusicDriver_LibTimidity::IsSongPlaying() void MusicDriver_LibTimidity::SetVolume(byte vol) { - volume = vol * 99 / 127; // I'm not sure about that value + volume = vol * TIMIDITY_MAX_VOLUME / 127; // I'm not sure about that value if (_midi.song != NULL) mid_song_set_volume(_midi.song, vol); } From 5236d0f75fdb32b252a099901dee83ea8ae9325e Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 19 Jul 2014 23:29:30 +0300 Subject: [PATCH 149/187] Fixed build area not highlighted on mouse-over or stylus hover --- src/window.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/window.cpp b/src/window.cpp index 24774a931d..f766710111 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2858,13 +2858,8 @@ static void MouseLoop(MouseClick click, int mousewheel) /* Don't allow any action in a viewport if either in menu or when having a modal progress window */ if (vp != NULL && (_game_mode == GM_MENU || HasModalProgress())) return; - /* On confirm mode do not update tile selection unless we are clicking on a viewport. */ - if (vp != NULL && _left_button_down && !_move_pressed) { - HandlePlacePresize(); - UpdateTileSelection(); - } else { - //if presize, show tooltip if needed - } + HandlePlacePresize(); + UpdateTileSelection(); if (VpHandlePlaceSizingDrag() == ES_HANDLED) return; if (HandleMouseDragDrop() == ES_HANDLED) return; From b4cfc84fc7c0e28ae02885a1cd6fc3141ffc385e Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 19 Jul 2014 23:39:41 +0300 Subject: [PATCH 150/187] Fixed 'Replace vehicles' window too tall --- src/autoreplace_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp index 79d8b43712..4310f341a4 100644 --- a/src/autoreplace_gui.cpp +++ b/src/autoreplace_gui.cpp @@ -245,7 +245,7 @@ public: case WID_RV_LEFT_MATRIX: case WID_RV_RIGHT_MATRIX: resize->height = GetEngineListHeight((VehicleType)this->window_number); - size->height = (this->window_number <= VEH_ROAD ? 8 : 4) * resize->height; + size->height = 4 * resize->height; break; case WID_RV_LEFT_DETAILS: From c938b99716f437b0747ec6a428709a4a117be2b1 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 19 Jul 2014 23:53:30 +0300 Subject: [PATCH 151/187] Fixed company face selection dialog too tall --- src/company_gui.cpp | 164 +++++++++++++++++++++++--------------------- 1 file changed, 84 insertions(+), 80 deletions(-) diff --git a/src/company_gui.cpp b/src/company_gui.cpp index f2dbff8abc..a2ad852027 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -939,89 +939,93 @@ static const NWidgetPart _nested_select_company_manager_face_widgets[] = { EndContainer(), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_PARTS), // Advanced face parts setting. - NWidget(NWID_VERTICAL), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE2), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE2), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE2), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE2), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_EUR), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN, STR_FACE_SELECT_EUROPEAN), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_AFR), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN, STR_FACE_SELECT_AFRICAN), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 4), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP), + EndContainer(), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_EUR), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN, STR_FACE_SELECT_EUROPEAN), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_AFR), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN, STR_FACE_SELECT_AFRICAN), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP), + EndContainer(), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 4), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), + NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetFill(1, 0), From 21e577c7d4a65b7a1502a7ee54c0909509db3b22 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 20 Jul 2014 00:05:53 +0300 Subject: [PATCH 152/187] 'Visit website' button from online content menu was not working --- src/os/unix/unix.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/os/unix/unix.cpp b/src/os/unix/unix.cpp index ac1d406d0c..596a0e6746 100644 --- a/src/os/unix/unix.cpp +++ b/src/os/unix/unix.cpp @@ -372,10 +372,23 @@ void OSOpenBrowser(const char *url) pid_t child_pid = fork(); if (child_pid != 0) return; +#ifdef __ANDROID__ + const char *args[9]; + args[0] = "/system/bin/am"; + args[1] = "start"; + args[2] = "-a"; + args[3] = "android.intent.action.VIEW"; + args[4] = "--user"; + args[5] = "0"; + args[6] = "-d"; + args[7] = url; + args[8] = NULL; +#else const char *args[3]; args[0] = "/usr/bin/xdg-open"; args[1] = url; args[2] = NULL; +#endif execv(args[0], const_cast(args)); DEBUG(misc, 0, "Failed to open url: %s", url); exit(0); From 6c9fffd545714e6b2631b8c16e483e4fa1f4fdd9 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 20 Jul 2014 00:16:43 +0300 Subject: [PATCH 153/187] Frameskip when pressing fast forward button --- src/video/sdl_v.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index a2ac87dff7..f3ed94d5e8 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -155,6 +155,16 @@ static void DrawSurfaceToScreen() { int n = _num_dirty_rects; if (n == 0) return; + static int frameskip = 0; + +#ifdef __ANDROID__ + if (_fast_forward) { + frameskip++; + if (frameskip < 5) + return; + frameskip = 0; + } +#endif _num_dirty_rects = 0; if (n > MAX_DIRTY_RECTS) { From 17f0f3d650a515759c42cc65d542d8149e80264e Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 20 Jul 2014 00:35:07 +0300 Subject: [PATCH 154/187] Slower scrolling for dropdown lists and scrollbars --- src/widget.cpp | 4 ++-- src/widgets/dropdown.cpp | 7 +++++-- src/window.cpp | 2 +- src/window_gui.h | 3 +++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/widget.cpp b/src/widget.cpp index 033180d241..d5735c3f85 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -105,7 +105,7 @@ static void ScrollbarClickPositioning(Window *w, NWidgetScrollbar *sb, int x, in /* Pressing the upper button? */ SetBit(sb->disp_flags, NDB_SCROLLBAR_UP); if (_scroller_click_timeout <= 1) { - _scroller_click_timeout = 3; + _scroller_click_timeout = SCROLLER_CLICK_DELAY; sb->UpdatePosition(rtl ? 1 : -1); } w->scrolling_scrollbar = sb->index; @@ -114,7 +114,7 @@ static void ScrollbarClickPositioning(Window *w, NWidgetScrollbar *sb, int x, in SetBit(sb->disp_flags, NDB_SCROLLBAR_DOWN); if (_scroller_click_timeout <= 1) { - _scroller_click_timeout = 3; + _scroller_click_timeout = SCROLLER_CLICK_DELAY; sb->UpdatePosition(rtl ? -1 : 1); } w->scrolling_scrollbar = sb->index; diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 900a24a29f..aa893fccd9 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -260,8 +260,11 @@ struct DropdownWindow : Window { if (this->scrolling != 0) { int pos = this->vscroll->GetPosition(); - this->vscroll->UpdatePosition(this->scrolling); - this->scrolling = 0; + if (_scroller_click_timeout <= 1) { + _scroller_click_timeout = SCROLLER_CLICK_DELAY; + this->vscroll->UpdatePosition(this->scrolling); + this->scrolling = 0; + } if (pos != this->vscroll->GetPosition()) { this->SetDirty(); diff --git a/src/window.cpp b/src/window.cpp index f766710111..57bf8df49a 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2398,7 +2398,7 @@ static EventState HandleScrollbarScrolling() if (sb->disp_flags & ND_SCROLLBAR_BTN) { if (_scroller_click_timeout == 1) { - _scroller_click_timeout = 3; + _scroller_click_timeout = SCROLLER_CLICK_DELAY; sb->UpdatePosition(rtl == HasBit(sb->disp_flags, NDB_SCROLLBAR_UP) ? 1 : -1); w->SetDirty(); } diff --git a/src/window_gui.h b/src/window_gui.h index bf8500f0f3..e03912b12d 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -885,6 +885,9 @@ extern Point _cursorpos_drag_start; extern int _scrollbar_start_pos; extern int _scrollbar_size; extern byte _scroller_click_timeout; +enum { + SCROLLER_CLICK_DELAY = 6 ///< Delay in video frames between scrollbar doing scroll, we don't want to get to the bottom of the list in an instant +}; extern bool _scrolling_viewport; extern bool _mouse_hovering; From 9916f1e361571403eb5b8be688b75449cfd6ca1f Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 20 Jul 2014 00:38:20 +0300 Subject: [PATCH 155/187] Added back todo.txt --- todo.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 todo.txt diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000000..88b5fa450e --- /dev/null +++ b/todo.txt @@ -0,0 +1,10 @@ +Minor bugs, which I'm too lazy to fix - serious bugs go to https://github.com/pelya/commandergenius/blob/sdl_android/todo.txt +============================================================================================================================= + +- OpenTTD: All menus in the scenario editor are out of the screen. + +- OpenTTD: 16bpp blitter with palette animation support. + +- OpenTTD: screen navigation buttons bug on Moto G - not reproduced on Nexus 7. + +- OpenTTD: Cheats menu closes itself randomly. From 8835c7826187a99caaf1be6934b5cff8f7eeefa4 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 19 Aug 2014 19:34:01 +0300 Subject: [PATCH 156/187] Updated release version Conflicts: .ottdrev --- .ottdrev | 1 + 1 file changed, 1 insertion(+) create mode 100644 .ottdrev diff --git a/.ottdrev b/.ottdrev new file mode 100644 index 0000000000..38c021e62b --- /dev/null +++ b/.ottdrev @@ -0,0 +1 @@ +1.4.2 26740 0 1.4.2 From fa594403297ac7753dcf59deb2682be02994126f Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 19 Aug 2014 22:15:48 +0300 Subject: [PATCH 157/187] Updated version in another file, argh Conflicts: src/rev.cpp.in --- src/rev.cpp.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rev.cpp.in b/src/rev.cpp.in index 46508dd8b6..756da35753 100644 --- a/src/rev.cpp.in +++ b/src/rev.cpp.in @@ -1,4 +1,4 @@ -/* $Id: rev.cpp.in 26440 2014-04-01 18:33:16Z frosch $ */ +/* $Id: rev.cpp.in 26740 2014-08-16 18:32:17Z frosch $ */ /* * This file is part of OpenTTD. @@ -72,7 +72,7 @@ const byte _openttd_revision_modified = !!MODIFIED!!; * final release will always have a lower version number than the released * version, thus making comparisons on specific revisions easy. */ -const uint32 _openttd_newgrf_version = 1 << 28 | 4 << 24 | 0 << 20 | 1 << 19 | (!!REVISION!! & ((1 << 19) - 1)); +const uint32 _openttd_newgrf_version = 1 << 28 | 4 << 24 | 2 << 20 | 1 << 19 | (!!REVISION!! & ((1 << 19) - 1)); #ifdef __MORPHOS__ /** From 9a3b8e89694d71a66f2cc570335032040a378a67 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 24 Aug 2014 22:26:05 +0300 Subject: [PATCH 158/187] Fixed town aythority window and new town dialog too tall --- src/town_gui.cpp | 112 ++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 0595ccf4f3..de601792bd 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -243,7 +243,7 @@ public: case WID_TA_COMMAND_LIST: resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; + size->height = WD_FRAMERECT_TOP + 3 * resize->height + WD_FRAMERECT_BOTTOM; size->width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width; for (uint i = 0; i < TACT_COUNT; i++ ) { size->width = max(size->width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i).width); @@ -980,61 +980,65 @@ static const NWidgetPart _nested_found_town_widgets[] = { NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), /* Construct new town(s) buttons. */ - NWidget(WWT_PANEL, COLOUR_DARK_GREEN), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_NEW_TOWN), SetMinimalSize(156, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_NEW_TOWN_BUTTON, STR_FOUND_TOWN_NEW_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_RANDOM_TOWN), SetMinimalSize(156, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_RANDOM_TOWN_BUTTON, STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_MANY_RANDOM_TOWNS), SetMinimalSize(156, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetPadding(0, 2, 0, 2), - /* Town name selection. */ - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(156, 14), SetPadding(0, 2, 0, 2), SetDataTip(STR_FOUND_TOWN_NAME_TITLE, STR_NULL), - NWidget(WWT_EDITBOX, COLOUR_GREY, WID_TF_TOWN_NAME_EDITBOX), SetMinimalSize(156, 12), SetPadding(0, 2, 3, 2), - SetDataTip(STR_FOUND_TOWN_NAME_EDITOR_TITLE, STR_FOUND_TOWN_NAME_EDITOR_HELP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_TOWN_NAME_RANDOM), SetMinimalSize(78, 12), SetPadding(0, 2, 0, 2), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_NAME_RANDOM_BUTTON, STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP), - /* Town size selection. */ - NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_TITLE, STR_NULL), - NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_NEW_TOWN), SetMinimalSize(156, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_NEW_TOWN_BUTTON, STR_FOUND_TOWN_NEW_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_RANDOM_TOWN), SetMinimalSize(156, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_RANDOM_TOWN_BUTTON, STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_MANY_RANDOM_TOWNS), SetMinimalSize(156, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetPadding(0, 2, 0, 2), + /* Town name selection. */ + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(156, 14), SetPadding(0, 2, 0, 2), SetDataTip(STR_FOUND_TOWN_NAME_TITLE, STR_NULL), + NWidget(WWT_EDITBOX, COLOUR_GREY, WID_TF_TOWN_NAME_EDITBOX), SetMinimalSize(156, 12), SetPadding(0, 2, 3, 2), + SetDataTip(STR_FOUND_TOWN_NAME_EDITOR_TITLE, STR_FOUND_TOWN_NAME_EDITOR_HELP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_TOWN_NAME_RANDOM), SetMinimalSize(78, 12), SetPadding(0, 2, 0, 2), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_NAME_RANDOM_BUTTON, STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP), + /* Town size selection. */ + NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_TITLE, STR_NULL), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_SMALL), SetMinimalSize(78, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_MEDIUM), SetMinimalSize(78, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 1), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_LARGE), SetMinimalSize(78, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_RANDOM), SetMinimalSize(78, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_SIZE_RANDOM, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 3), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_CITY), SetPadding(0, 2, 0, 2), SetMinimalSize(156, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_CITY, STR_FOUND_TOWN_CITY_TOOLTIP), SetFill(1, 0), EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_SMALL), SetMinimalSize(78, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_MEDIUM), SetMinimalSize(78, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), + /* Town roads selection. */ + NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_ROAD_LAYOUT, STR_NULL), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_ORIGINAL), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_BETTER), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 1), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID2), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID3), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_RANDOM), SetPadding(0, 2, 0, 2), SetMinimalSize(0, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), SetFill(1, 0), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 1), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_LARGE), SetMinimalSize(78, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_RANDOM), SetMinimalSize(78, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_SIZE_RANDOM, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 3), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_CITY), SetPadding(0, 2, 0, 2), SetMinimalSize(156, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_CITY, STR_FOUND_TOWN_CITY_TOOLTIP), SetFill(1, 0), - /* Town roads selection. */ - NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_ROAD_LAYOUT, STR_NULL), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_ORIGINAL), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_BETTER), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 1), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID2), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID3), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_RANDOM), SetPadding(0, 2, 0, 2), SetMinimalSize(0, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), SetFill(1, 0), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), EndContainer(), }; From 4d4f707638dce03477738f7b72c701a180e8a4b4 Mon Sep 17 00:00:00 2001 From: pelya Date: Mon, 25 Aug 2014 00:37:48 +0300 Subject: [PATCH 159/187] Removed #ifdef ANDROID from where it's not needed --- src/toolbar_gui.cpp | 56 --------------------------------------------- 1 file changed, 56 deletions(-) diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 9a8641ad7f..c2d9dff9b3 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1538,8 +1538,6 @@ public: class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const { -#ifdef __ANDROID__ - static const uint BIGGEST_ARRANGEMENT = 28; static const uint ARRANGEMENT_30 = 24; static const byte arrange_android_28[] = { @@ -1565,60 +1563,6 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { } button_count = arrangable_count = lengthof(arrange_android_28) / 2; return &arrange_android_28[((_toolbar_mode == TB_LOWER) ? button_count : 0)]; - -#else - - static const uint SMALLEST_ARRANGEMENT = 14; - static const uint BIGGEST_ARRANGEMENT = 20; - static const byte arrange14[] = { - 0, 1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 29, - 2, 3, 4, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29, - }; - static const byte arrange15[] = { - 0, 1, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, - 0, 2, 4, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29, - }; - static const byte arrange16[] = { - 0, 1, 2, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, - 0, 1, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29, - }; - static const byte arrange17[] = { - 0, 1, 2, 4, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, - 0, 1, 3, 4, 6, 5, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29, - }; - static const byte arrange18[] = { - 0, 1, 2, 4, 5, 6, 7, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29, - 0, 1, 3, 4, 5, 6, 7, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29, - }; - static const byte arrange19[] = { - 0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 19, 20, 29, - 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 28, 19, 20, 29, - }; - static const byte arrange20[] = { - 0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 11, 19, 20, 29, - 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29, - }; - static const byte arrange_all[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 - }; - - /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */ - uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT); - - if (full_buttons > BIGGEST_ARRANGEMENT) { - button_count = arrangable_count = lengthof(arrange_all); - spacer_count = this->spacers; - return arrange_all; - } - - /* Introduce the split toolbar */ - static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 }; - - button_count = arrangable_count = full_buttons; - spacer_count = this->spacers; - return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0); - -#endif } }; From 024daa1225840ccbbb14a19319d565b5d90db55e Mon Sep 17 00:00:00 2001 From: pelya Date: Mon, 25 Aug 2014 00:58:35 +0300 Subject: [PATCH 160/187] Smallmap legend can be hidden --- src/lang/english.txt | 1 + src/smallmap_gui.cpp | 32 +++++++++++++++++++------------- src/smallmap_gui.h | 9 +++++---- src/widgets/smallmap_widget.h | 1 + 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 7c8f1e6281..607794bf69 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -706,6 +706,7 @@ STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Show lan STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}Click on an industry type to toggle displaying it. Ctrl+Click disables all types except the selected one. Ctrl+Click on it again to enable all industry types STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}Click on a company to toggle displaying its property. Ctrl+Click disables all companies except the selected one. Ctrl+Click on it again to enable all companies STR_SMALLMAP_TOOLTIP_CARGO_SELECTION :{BLACK}Click on a cargo to toggle displaying its property. Ctrl+Click disables all cargoes except the selected one. Ctrl+Click on it again to enable all cargoes +STR_SMALLMAP_TOOLTIP_SHOW_LEGEND :{BLACK}Show map legend / description of map symbols STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}Roads STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}Railways diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 4e94450850..97d9c34924 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -1050,7 +1050,8 @@ void SmallMapWindow::SetupWidgetData() SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : Window(desc), - row_height(GetMinSizing(NWST_STEP, FONT_HEIGHT_SMALL)), + show_legend(false), + row_height(max(GetMinSizing(NWST_STEP, FONT_HEIGHT_SMALL) * 2 / 3, uint(FONT_HEIGHT_SMALL))), // Default spacing makes legend too tall - shrink it by 1/3 refresh(FORCE_REFRESH_PERIOD) { _smallmap_industry_highlight = INVALID_INDUSTRYTYPE; @@ -1419,6 +1420,14 @@ int SmallMapWindow::GetPositionOnLegend(Point pt) if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); break; + case WID_SM_SHOW_LEGEND: { + int oldHeight = this->GetLegendHeight(this->min_number_of_columns); + this->show_legend = !this->show_legend; + this->SetWidgetLoweredState(WID_SM_SHOW_LEGEND, this->show_legend); + this->ReInit(0, this->GetLegendHeight(this->min_number_of_columns) - oldHeight); + break; + } + case WID_SM_LEGEND: // Legend if (this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER) { int click_pos = this->GetPositionOnLegend(pt); @@ -1656,7 +1665,7 @@ public: this->smallmap_window = dynamic_cast(w); assert(this->smallmap_window != NULL); - this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth()); + this->smallest_x = max(display->smallest_x, max(bar->smallest_x, smallmap_window->GetMinLegendWidth())); this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetLegendHeight(smallmap_window->min_number_of_columns)); this->fill_x = max(display->fill_x, bar->fill_x); this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y); @@ -1707,7 +1716,7 @@ public: /** Widget parts of the smallmap display. */ static const NWidgetPart _nested_smallmap_display[] = { NWidget(WWT_PANEL, COLOUR_BROWN, WID_SM_MAP_BORDER), - NWidget(WWT_INSET, COLOUR_BROWN, WID_SM_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(), + NWidget(WWT_INSET, COLOUR_BROWN, WID_SM_MAP), SetMinimalSize(140, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(), EndContainer(), }; @@ -1715,27 +1724,23 @@ static const NWidgetPart _nested_smallmap_display[] = { static const NWidgetPart _nested_smallmap_bar[] = { NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SM_LEGEND), SetResize(1, 1), - NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), /* Top button row. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_SHOW_LEGEND), + SetDataTip(SPR_IMG_QUERY, STR_SMALLMAP_TOOLTIP_SHOW_LEGEND), SetFill(1, 1), NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetFill(1, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_OUT), + SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1), NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_CENTERMAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER), SetFill(1, 1), - NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_BLANK), - SetDataTip(SPR_DOT_SMALL, STR_NULL), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_CONTOUR), SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_VEHICLES), SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_INDUSTRIES), SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), SetFill(1, 1), - EndContainer(), - /* Bottom button row. */ - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_OUT), - SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_TOGGLETOWNNAME), SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_LINKSTATS), @@ -1750,6 +1755,7 @@ static const NWidgetPart _nested_smallmap_bar[] = { NWidget(NWID_SPACER), SetResize(0, 1), EndContainer(), EndContainer(), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SM_LEGEND), SetResize(1, 1), EndContainer(), }; @@ -1792,7 +1798,7 @@ static const NWidgetPart _nested_smallmap_widgets[] = { }; static WindowDesc _smallmap_desc( - WDP_AUTO, "smallmap", 484, 314, + WDP_AUTO, "smallmap", 180, 180, WC_SMALLMAP, WC_NONE, 0, _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets) diff --git a/src/smallmap_gui.h b/src/smallmap_gui.h index d54969d915..03769d45d0 100644 --- a/src/smallmap_gui.h +++ b/src/smallmap_gui.h @@ -69,6 +69,7 @@ protected: static const uint FORCE_REFRESH_PERIOD = 0x1F; ///< map is redrawn after that many ticks static const uint BLINK_PERIOD = 0x0F; ///< highlight blinking interval + bool show_legend; ///< Display legend. uint min_number_of_columns; ///< Minimal number of columns in legends. uint min_number_of_fixed_rows; ///< Minimal number of rows in the legends for the fixed layouts only (all except #SMT_INDUSTRY). uint column_width; ///< Width of a column in the #WID_SM_LEGEND widget. @@ -114,7 +115,7 @@ protected: */ inline uint GetMinLegendWidth() const { - return WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width; + return show_legend ? WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width : 0; } /** @@ -123,7 +124,7 @@ protected: */ inline uint GetNumberColumnsLegend(uint width) const { - return width / this->column_width; + return max(2u, width / this->column_width); } /** @@ -133,8 +134,8 @@ protected: */ inline uint GetLegendHeight(uint num_columns) const { - return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + - this->GetNumberRowsLegend(num_columns) * this->row_height; + return show_legend ? WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + + this->GetNumberRowsLegend(num_columns) * this->row_height : 0; } /** diff --git a/src/widgets/smallmap_widget.h b/src/widgets/smallmap_widget.h index 0b1daea03f..753dcb74e3 100644 --- a/src/widgets/smallmap_widget.h +++ b/src/widgets/smallmap_widget.h @@ -34,6 +34,7 @@ enum SmallMapWidgets { WID_SM_ENABLE_ALL, ///< Button to enable display of all legend entries. WID_SM_DISABLE_ALL, ///< Button to disable display of all legend entries. WID_SM_SHOW_HEIGHT, ///< Show heightmap toggle button. + WID_SM_SHOW_LEGEND, ///< Show/hide legend area. }; #endif /* WIDGETS_SMALLMAP_WIDGET_H */ From 7fa4e7bbc379006be79bbec4d5d3263d228dcdf0 Mon Sep 17 00:00:00 2001 From: pelya Date: Mon, 25 Aug 2014 01:49:35 +0300 Subject: [PATCH 161/187] WIP backup savegames to network --- src/fios_gui.cpp | 3 ++- src/lang/english.txt | 4 ++++ src/settings_type.h | 1 + src/table/gameopt_settings.ini | 10 ++++++++++ src/widgets/fios_widget.h | 2 ++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 3306677e42..a4f6175858 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -109,6 +109,7 @@ static const NWidgetPart _nested_load_dialog_widgets[] = { EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_LOAD_NETWORK_BUTTON), SetDataTip(STR_SAVELOAD_LOAD_NETWORK_BUTTON, STR_SAVELOAD_LOAD_NETWORK_TOOLTIP), SetFill(1, 0), SetResize(1, 0), EndContainer(), EndContainer(), }; @@ -180,7 +181,7 @@ static const NWidgetPart _nested_save_dialog_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SL_DETAILS), SetResize(1, 1), SetFill(1, 1), NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetResize(1, 0), SetFill(1, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SL_SAVE_NETWORK_BUTTON), SetDataTip(STR_SAVELOAD_SAVE_NETWORK_BUTTON, STR_SAVELOAD_SAVE_NETWORK_TOOLTIP), SetFill(1, 1), SetResize(1, 0), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), EndContainer(), diff --git a/src/lang/english.txt b/src/lang/english.txt index 607794bf69..bb3349d017 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2712,6 +2712,10 @@ STR_SAVELOAD_SAVE_TOOLTIP :{BLACK}Save the STR_SAVELOAD_LOAD_BUTTON :{BLACK}Load STR_SAVELOAD_LOAD_TOOLTIP :{BLACK}Load the selected game STR_SAVELOAD_LOAD_HEIGHTMAP_TOOLTIP :{BLACK}Load the selected heightmap +STR_SAVELOAD_LOAD_NETWORK_BUTTON :{BLACK}Load from network +STR_SAVELOAD_LOAD_NETWORK_TOOLTIP :{BLACK}Load a game from the network storage +STR_SAVELOAD_SAVE_NETWORK_BUTTON :{BLACK}Save to network +STR_SAVELOAD_SAVE_NETWORK_TOOLTIP :{BLACK}Back up the game to the network storage STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Game Details STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}No information available STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING1} diff --git a/src/settings_type.h b/src/settings_type.h index 235b7bebc7..3936aa0694 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -105,6 +105,7 @@ struct GUISettings { ZoomLevelByte zoom_max; ///< maximum zoom out level bool disable_unsuitable_building; ///< disable infrastructure building when no suitable vehicles are available byte autosave; ///< how often should we do autosaves? + byte save_to_network; ///< backup all savegames to network bool threaded_saves; ///< should we do threaded saves? bool keep_all_autosave; ///< name the autosave in a different way bool autosave_on_exit; ///< save an autosave when you quit the game, but do not ask "Do you really want to quit?" diff --git a/src/table/gameopt_settings.ini b/src/table/gameopt_settings.ini index 3a47c09e33..30b5f667a2 100644 --- a/src/table/gameopt_settings.ini +++ b/src/table/gameopt_settings.ini @@ -19,6 +19,7 @@ static const char *_locale_units = "imperial|metric|si"; static const char *_town_names = "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovak|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan"; static const char *_climates = "temperate|arctic|tropic|toyland"; static const char *_autosave_interval = "off|monthly|quarterly|half year|yearly"; +static const char *_save_to_network = "ask|enabled|disabled"; static const char *_roadsides = "left|right"; static const char *_savegame_date = "long|short|iso"; #ifdef ENABLE_NETWORK @@ -173,6 +174,15 @@ max = 4 full = _autosave_interval cat = SC_BASIC +[SDTC_OMANY] +var = gui.save_to_network +type = SLE_UINT8 +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = 0 +max = 2 +full = _save_to_network +cat = SC_BASIC + [SDT_OMANY] base = GameSettings var = vehicle.road_side diff --git a/src/widgets/fios_widget.h b/src/widgets/fios_widget.h index c94655d767..3f4b49fbee 100644 --- a/src/widgets/fios_widget.h +++ b/src/widgets/fios_widget.h @@ -31,6 +31,8 @@ enum SaveLoadWidgets { WID_SL_NEWGRF_INFO, ///< Button to open NewGgrf configuration. WID_SL_LOAD_BUTTON, ///< Button to load game/scenario. WID_SL_MISSING_NEWGRFS, ///< Button to find missing NewGRFs online. + WID_SL_SAVE_NETWORK_BUTTON, ///< Toggle button to back up savegame to the network storage. + WID_SL_LOAD_NETWORK_BUTTON, ///< Button to load game from the network storage. }; #endif /* WIDGETS_FIOS_WIDGET_H */ From 69a31cde7bd7936e4eaaaf353e90e7244f743bb4 Mon Sep 17 00:00:00 2001 From: pelya Date: Mon, 25 Aug 2014 01:51:44 +0300 Subject: [PATCH 162/187] WIP save to network - fixed UI --- src/fios_gui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index a4f6175858..5d4ef0a6de 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -107,9 +107,11 @@ static const NWidgetPart _nested_load_dialog_widgets[] = { NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_NEWGRF_INFO), SetDataTip(STR_INTRO_NEWGRF_SETTINGS, STR_NULL), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_LOAD_BUTTON), SetDataTip(STR_SAVELOAD_LOAD_BUTTON, STR_SAVELOAD_LOAD_TOOLTIP), SetFill(1, 0), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_LOAD_NETWORK_BUTTON), SetDataTip(STR_SAVELOAD_LOAD_NETWORK_BUTTON, STR_SAVELOAD_LOAD_NETWORK_TOOLTIP), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_LOAD_NETWORK_BUTTON), SetDataTip(STR_SAVELOAD_LOAD_NETWORK_BUTTON, STR_SAVELOAD_LOAD_NETWORK_TOOLTIP), SetFill(1, 0), SetResize(1, 0), EndContainer(), EndContainer(), }; From be3f236eafbb1990f6db3aa57d244a9c5621c291 Mon Sep 17 00:00:00 2001 From: pelya Date: Tue, 26 Aug 2014 02:04:54 +0300 Subject: [PATCH 163/187] Cloudsave support --- src/fileio.cpp | 2 +- src/fios_gui.cpp | 31 +++++++++++++++++++++++++++++++ src/openttd.cpp | 22 ++++++++++++++++++++++ src/screenshot.cpp | 2 +- src/table/gameopt_settings.ini | 4 ++-- 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 94c6adcbad..467ea0fb92 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -293,7 +293,7 @@ static const char * const _subdirs[] = { "game" PATHSEP, "game" PATHSEP "library" PATHSEP, #ifdef __ANDROID__ - "../../../../../../Pictures/", + "screenshot" PATHSEP, #else "screenshot" PATHSEP, #endif diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 5d4ef0a6de..758268749f 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -35,12 +35,16 @@ #include "table/strings.h" #include "safeguards.h" +#ifdef __ANDROID__ +#include +#endif SaveLoadDialogMode _saveload_mode; LoadCheckData _load_check_data; ///< Data loaded from save during SL_LOAD_CHECK. static bool _fios_path_changed; static bool _savegame_sort_dirty; +static const char *NETWORK_SAVE_FILENAME = "network-save.sav"; /** @@ -285,6 +289,7 @@ public: this->FinishInitNested(0); this->LowerWidget(WID_SL_DRIVES_DIRECTORIES_LIST); + if (mode == SLD_SAVE_GAME) this->SetWidgetLoweredState(WID_SL_SAVE_NETWORK_BUTTON, _settings_client.gui.save_to_network); /* pause is only used in single-player, non-editor mode, non-menu mode. It * will be unpaused in the WE_DESTROY event handler. */ @@ -627,6 +632,32 @@ public: /* Note, this is also called via the OSK; and we need to lower the button. */ this->HandleButtonClick(WID_SL_SAVE_GAME); break; + + case WID_SL_SAVE_NETWORK_BUTTON: + _settings_client.gui.save_to_network = !_settings_client.gui.save_to_network; + this->SetWidgetLoweredState(WID_SL_SAVE_NETWORK_BUTTON, _settings_client.gui.save_to_network); + this->SetDirty(); + break; + + case WID_SL_LOAD_NETWORK_BUTTON: { + char savePath[PATH_MAX]; + FiosMakeSavegameName(savePath, NETWORK_SAVE_FILENAME, sizeof(savePath)); +#ifdef __ANDROID__ + if (!SDL_ANDROID_CloudLoad(savePath, NULL, "OpenTTD")) { + break; + } +#endif + _load_check_data.Clear(); + SaveOrLoadResult res = SaveOrLoad(savePath, SL_LOAD_CHECK, SAVE_DIR, false); + if (res == SL_OK && !_load_check_data.HasErrors()) { + strecpy(_file_to_saveload.name, savePath, lastof(_file_to_saveload.name)); + strecpy(_file_to_saveload.title, "", lastof(_file_to_saveload.title)); + if (!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs()) { + _switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_SCENARIO : SM_LOAD_GAME; + } + } + break; + } } } diff --git a/src/openttd.cpp b/src/openttd.cpp index c430cf67e3..bc5b8cbb82 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -69,6 +69,9 @@ #include #include "safeguards.h" +#ifdef __ANDROID__ +#include +#endif void CallLandscapeTick(); void IncreaseDate(); @@ -81,6 +84,8 @@ bool HandleBootstrap(); extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY); extern void ShowOSErrorBox(const char *buf, bool system); extern char *_config_file; +const char *NETWORK_SAVE_SCREENSHOT_FILE = "OpenTTD-network-save"; +const char *NETWORK_SAVE_SCREENSHOT_FILE_PNG = "OpenTTD-network-save.png"; /** * Error handling for fatal user errors. @@ -1161,6 +1166,23 @@ void SwitchToMode(SwitchMode new_mode) ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR); } else { DeleteWindowById(WC_SAVELOAD, 0); +#ifdef __ANDROID__ + if (_settings_client.gui.save_to_network) { + char screenshotFile[PATH_MAX] = ""; + const char* lastPart = strrchr(_file_to_saveload.name, PATHSEPCHAR); + if (!lastPart) { + lastPart = _file_to_saveload.name; + } else { + lastPart++; + } + MakeScreenshot(SC_VIEWPORT, NETWORK_SAVE_SCREENSHOT_FILE); + FioFindFullPath(screenshotFile, sizeof(screenshotFile), SCREENSHOT_DIR, NETWORK_SAVE_SCREENSHOT_FILE_PNG); + int ret = SDL_ANDROID_CloudSave(_file_to_saveload.name, lastPart, "OpenTTD", lastPart, screenshotFile, _date); + if (_settings_client.gui.save_to_network == 2) { + _settings_client.gui.save_to_network = ret ? 1 : 0; + } + } +#endif } break; diff --git a/src/screenshot.cpp b/src/screenshot.cpp index 0974de62b5..2022dca461 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -871,7 +871,7 @@ bool MakeScreenshot(ScreenshotType t, const char *name) if (ret) { SetDParamStr(0, _screenshot_name); - ShowErrorMessage(STR_MESSAGE_SCREENSHOT_SUCCESSFULLY, INVALID_STRING_ID, WL_WARNING); + //ShowErrorMessage(STR_MESSAGE_SCREENSHOT_SUCCESSFULLY, INVALID_STRING_ID, WL_WARNING); // No need for message when we're doing cloudsave } else { ShowErrorMessage(STR_ERROR_SCREENSHOT_FAILED, INVALID_STRING_ID, WL_ERROR); } diff --git a/src/table/gameopt_settings.ini b/src/table/gameopt_settings.ini index 30b5f667a2..762ccaa3f2 100644 --- a/src/table/gameopt_settings.ini +++ b/src/table/gameopt_settings.ini @@ -19,7 +19,7 @@ static const char *_locale_units = "imperial|metric|si"; static const char *_town_names = "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovak|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan"; static const char *_climates = "temperate|arctic|tropic|toyland"; static const char *_autosave_interval = "off|monthly|quarterly|half year|yearly"; -static const char *_save_to_network = "ask|enabled|disabled"; +static const char *_save_to_network = "disabled|enabled|ask"; static const char *_roadsides = "left|right"; static const char *_savegame_date = "long|short|iso"; #ifdef ENABLE_NETWORK @@ -178,7 +178,7 @@ cat = SC_BASIC var = gui.save_to_network type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -def = 0 +def = 2 max = 2 full = _save_to_network cat = SC_BASIC From e0efbfbd75a507f74c60dce9ca6e111b113005d0 Mon Sep 17 00:00:00 2001 From: pelya Date: Tue, 26 Aug 2014 02:10:35 +0300 Subject: [PATCH 164/187] Fixed network save setting not saved to config file --- src/table/settings.ini | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/table/settings.ini b/src/table/settings.ini index 164ab06d59..dc50b3d108 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -2489,6 +2489,15 @@ strhelp = STR_CONFIG_SETTING_AUTOSAVE_HELPTEXT strval = STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF cat = SC_BASIC +[SDTC_OMANY] +var = gui.save_to_network +type = SLE_UINT8 +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = 2 +max = 2 +full = _save_to_network +cat = SC_BASIC + [SDTC_BOOL] var = gui.threaded_saves flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC From 396aebaa987254b0be07ac12d9dabdb5a3ab982f Mon Sep 17 00:00:00 2001 From: pelya Date: Mon, 10 Nov 2014 17:19:15 +0200 Subject: [PATCH 165/187] Shorter rail station construction window --- src/rail_gui.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index c315d3f927..04cb8005c0 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1428,19 +1428,24 @@ static const NWidgetPart _nested_station_builder_widgets[] = { EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_DRAG_N_DROP), SetMinimalSize(75, 12), SetDataTip(STR_STATION_BUILD_DRAG_DROP, STR_STATION_BUILD_DRAG_DROP_TOOLTIP), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), - EndContainer(), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetPadding(3, 2, 0, 2), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_HIGHLIGHT_OFF), SetMinimalSize(60, 12), - SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_HIGHLIGHT_ON), SetMinimalSize(60, 12), - SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_DRAG_N_DROP), SetMinimalSize(75, 12), SetDataTip(STR_STATION_BUILD_DRAG_DROP, STR_STATION_BUILD_DRAG_DROP_TOOLTIP), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetPadding(3, 2, 0, 2), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_HIGHLIGHT_OFF), SetMinimalSize(60, 12), + SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_HIGHLIGHT_ON), SetMinimalSize(60, 12), + SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), + NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), + EndContainer(), + EndContainer(), EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_MATRIX), /* We need an additional background for the matrix, as the matrix cannot handle the scrollbar due to not being an NWidgetCore. */ From 55d31f06fb16c00d7b3fe6fbb0f7db0ed19ebe37 Mon Sep 17 00:00:00 2001 From: pelya Date: Mon, 10 Nov 2014 17:57:43 +0200 Subject: [PATCH 166/187] Continuously scroll map with two fingers --- src/gfx.cpp | 1 + src/gfx_func.h | 1 + src/video/sdl_v.cpp | 2 ++ src/window.cpp | 19 +++++++++++++++++++ 4 files changed, 23 insertions(+) diff --git a/src/gfx.cpp b/src/gfx.cpp index 615a48bf62..515552ddfd 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -41,6 +41,7 @@ bool _left_button_down; ///< Is left mouse button pressed? bool _left_button_clicked; ///< Is left mouse button clicked? bool _right_button_down; ///< Is right mouse button pressed? bool _right_button_clicked; ///< Is right mouse button clicked? +Point _right_button_down_pos; ///< Pos of right mouse button click, for drag and drop DrawPixelInfo _screen; bool _screen_disable_anim = false; ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot) diff --git a/src/gfx_func.h b/src/gfx_func.h index ccb27a3fed..f48e3610b3 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -65,6 +65,7 @@ extern bool _left_button_down; extern bool _left_button_clicked; extern bool _right_button_down; extern bool _right_button_clicked; +extern Point _right_button_down_pos; extern DrawPixelInfo _screen; extern bool _screen_disable_anim; ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot) diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index f3ed94d5e8..c197ec9141 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -598,6 +598,8 @@ int VideoDriver_SDL::PollEvent() case SDL_BUTTON_RIGHT: _right_button_down = true; _right_button_clicked = true; + _right_button_down_pos.x = ev.motion.x; + _right_button_down_pos.y = ev.motion.y; break; case SDL_BUTTON_WHEELUP: _cursor.wheel--; break; diff --git a/src/window.cpp b/src/window.cpp index 57bf8df49a..53bdc601f5 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2777,6 +2777,24 @@ static void HandleAutoscroll() #undef scrollspeed } +/** + * Perform small continuous scrolling with right button press and drag. + */ +static void HandleContinuousScroll() +{ +#define scrollspeed 0.05f + if (_scrolling_viewport && _right_button_down) { + Window *w = FindWindowFromPt(_right_button_down_pos.x, _right_button_down_pos.y); + if (w == NULL || w->flags & WF_DISABLE_VP_SCROLL) return; + ViewPort *vp = IsPtInWindowViewport(w, _right_button_down_pos.x, _right_button_down_pos.y); + if (vp == NULL) return; + + w->viewport->dest_scrollpos_x += ScaleByZoom(scrollspeed * (_right_button_down_pos.x - _cursor.pos.x), vp->zoom); + w->viewport->dest_scrollpos_y += ScaleByZoom(scrollspeed * (_right_button_down_pos.y - _cursor.pos.y), vp->zoom); + } +#undef scrollspeed +} + enum MouseClick { MC_NONE = 0, MC_LEFT, @@ -3096,6 +3114,7 @@ void InputLoop() /* HandleMouseEvents was already called for this tick */ HandleMouseEvents(); HandleAutoscroll(); + HandleContinuousScroll(); } /** From 5934a69f679ad732336487f478e1187273371365 Mon Sep 17 00:00:00 2001 From: pelya Date: Wed, 12 Nov 2014 01:15:33 +0200 Subject: [PATCH 167/187] Fixed played time display for cloud saves --- src/openttd.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openttd.cpp b/src/openttd.cpp index bc5b8cbb82..b7a58b041b 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1177,7 +1177,8 @@ void SwitchToMode(SwitchMode new_mode) } MakeScreenshot(SC_VIEWPORT, NETWORK_SAVE_SCREENSHOT_FILE); FioFindFullPath(screenshotFile, sizeof(screenshotFile), SCREENSHOT_DIR, NETWORK_SAVE_SCREENSHOT_FILE_PNG); - int ret = SDL_ANDROID_CloudSave(_file_to_saveload.name, lastPart, "OpenTTD", lastPart, screenshotFile, _date); + uint64_t playedTime = abs(_date - DAYS_TILL(_settings_newgame.game_creation.starting_year)) * 1000; + int ret = SDL_ANDROID_CloudSave(_file_to_saveload.name, lastPart, "OpenTTD", lastPart, screenshotFile, playedTime); if (_settings_client.gui.save_to_network == 2) { _settings_client.gui.save_to_network = ret ? 1 : 0; } From fdddd873dd749efe4a3a5bc8945263386cea0460 Mon Sep 17 00:00:00 2001 From: pelya Date: Wed, 12 Nov 2014 03:25:09 +0200 Subject: [PATCH 168/187] Auto-select last used tool when user cancels build action, only for roads now --- src/main_gui.cpp | 2 +- src/road_gui.cpp | 10 ++++++++++ src/video/sdl_v.cpp | 1 + src/viewport.cpp | 14 ++++++++++++++ src/viewport_func.h | 2 ++ src/window_gui.h | 4 ++++ 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 4df8fe7ca5..0988d8c828 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -340,7 +340,7 @@ struct MainWindow : Window break; } - case GHK_RESET_OBJECT_TO_PLACE: ResetObjectToPlace(); break; + case GHK_RESET_OBJECT_TO_PLACE: ResetObjectToPlace(); ToolbarSelectLastTool(); break; case GHK_DELETE_WINDOWS: DeleteNonVitalWindows(); break; case GHK_DELETE_NONVITAL_WINDOWS: DeleteAllNonVitalWindows(); break; case GHK_REFRESH_SCREEN: MarkWholeScreenDirty(); break; diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 5d321b91aa..0a022505fb 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -536,6 +536,16 @@ struct BuildRoadToolbarWindow : Window { DeleteWindowByClass(WC_BUILD_BRIDGE); } + virtual void SelectLastTool() + { + // User misplaced something - activate last selected tool again + if (this->last_started_action == WIDGET_LIST_END) + return; + Point dummy = {0, 0}; + this->RaiseWidget(this->last_started_action); + this->OnClick(dummy, this->last_started_action, 0); + } + virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) { /* Here we update the end tile flags diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index c197ec9141..669c3114c2 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -623,6 +623,7 @@ int VideoDriver_SDL::PollEvent() // Two-finger click - hacky way to determine if the right mouse button is already pressed without processing the left button event // Cancel whatewer action we were doing, to allow two finger scrolling ResetObjectToPlace(); + SelectLastTool(); } #endif } else if (ev.button.button == SDL_BUTTON_RIGHT) { diff --git a/src/viewport.cpp b/src/viewport.cpp index 82315d75bf..d4af6ff456 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -2943,6 +2943,9 @@ void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Wind #include "table/animcursors.h" +static WindowClass _last_selected_window_class; +static WindowNumber _last_selected_window_number; + void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num) { if (_thd.window_class != WC_INVALID) { @@ -2989,9 +2992,20 @@ void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowC void ResetObjectToPlace() { + if (_thd.window_class != WC_INVALID) { + _last_selected_window_class = _thd.window_class; + _last_selected_window_number = _thd.window_number; + } SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0); } +void ToolbarSelectLastTool() +{ + Window *w = FindWindowById(_last_selected_window_class, _last_selected_window_number); + if (w != NULL) w->SelectLastTool(); + _last_selected_window_class = WC_INVALID; +} + Point GetViewportStationMiddle(const ViewPort *vp, const Station *st) { int x = TileX(st->xy) * TILE_SIZE; diff --git a/src/viewport_func.h b/src/viewport_func.h index baa06e48ca..7250c6fa37 100644 --- a/src/viewport_func.h +++ b/src/viewport_func.h @@ -82,4 +82,6 @@ void MarkTileDirtyByTile(TileIndex tile); Point GetViewportStationMiddle(const ViewPort *vp, const Station *st); +void ToolbarSelectLastTool(); + #endif /* VIEWPORT_FUNC_H */ diff --git a/src/window_gui.h b/src/window_gui.h index e03912b12d..a92b0be869 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -747,6 +747,10 @@ public: */ virtual void OnPlaceObjectAbort() {} + /** + * Select the cancelled tool again, this is called after OnPlaceObjectAbort() + */ + virtual void SelectLastTool() {} /** * The user is dragging over the map when the tile highlight mode From 400b6daad01586ae16332b70033a6fdd65e96fef Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Fri, 14 Nov 2014 20:27:58 +0200 Subject: [PATCH 169/187] Auto-select last used tool for railroad --- src/rail_gui.cpp | 10 ++++++++++ src/video/sdl_v.cpp | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 04cb8005c0..e848790c59 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -757,6 +757,16 @@ struct BuildRailToolbarWindow : Window { DeleteWindowByClass(WC_BUILD_BRIDGE); } + virtual void SelectLastTool() + { + // User misplaced something - activate last selected tool again + if (this->last_user_action == WIDGET_LIST_END) + return; + Point dummy = {0, 0}; + this->RaiseWidget(this->last_user_action); + this->OnClick(dummy, this->last_user_action, 0); + } + virtual void OnPlacePresize(Point pt, TileIndex tile_from) { TileIndex tile_to = tile_from; diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index 669c3114c2..613b664476 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -25,6 +25,7 @@ #include "../fileio_func.h" #include "../settings_type.h" #include "../tilehighlight_func.h" +#include "../viewport_func.h" #include "sdl_v.h" #include #ifdef __ANDROID__ @@ -623,7 +624,7 @@ int VideoDriver_SDL::PollEvent() // Two-finger click - hacky way to determine if the right mouse button is already pressed without processing the left button event // Cancel whatewer action we were doing, to allow two finger scrolling ResetObjectToPlace(); - SelectLastTool(); + ToolbarSelectLastTool(); } #endif } else if (ev.button.button == SDL_BUTTON_RIGHT) { From 60f12ed588fc9b965c4cd261ed9ff1492381cbf0 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Fri, 14 Nov 2014 20:56:06 +0200 Subject: [PATCH 170/187] Select last tool for waterways and terraform toolbars --- src/dock_gui.cpp | 10 ++++++++++ src/terraform_gui.cpp | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index a12c5e0d10..4704b060cd 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -284,6 +284,16 @@ struct BuildDocksToolbarWindow : Window { DeleteWindowByClass(WC_BUILD_BRIDGE); } + virtual void SelectLastTool() + { + // User misplaced something - activate last selected tool again + if (this->last_clicked_widget == WIDGET_LIST_END) + return; + Point dummy = {0, 0}; + this->RaiseWidget(this->last_clicked_widget); + this->OnClick(dummy, this->last_clicked_widget, 0); + } + virtual void OnPlacePresize(Point pt, TileIndex tile_from) { if (!IsValidTile(tile_from)) return; diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index db8bf210c3..0b7d4a415a 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -293,6 +293,16 @@ struct TerraformToolbarWindow : Window { ResetObjectToPlace(); } + virtual void SelectLastTool() + { + // User misplaced something - activate last selected tool again + if (this->last_user_action == WIDGET_LIST_END) + return; + Point dummy = {0, 0}; + this->RaiseWidget(this->last_user_action); + this->OnClick(dummy, this->last_user_action, 0); + } + static HotkeyList hotkeys; }; From bde4cdebc1e39a7cc128f2ca158e1af67ac6bbea Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 15 Nov 2014 22:30:38 +0200 Subject: [PATCH 171/187] Fixed too wide buttons in the railroad semaphore dialog --- src/rail_gui.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index e848790c59..c311de5516 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1673,6 +1673,9 @@ static const NWidgetPart _nested_signal_builder_widgets[] = { NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_CONVERT), SetDataTip(SPR_IMG_SIGNAL_CONVERT, STR_BUILD_SIGNAL_CONVERT_TOOLTIP), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BS_DRAG_SIGNALS_DENSITY_LABEL), SetDataTip(STR_ORANGE_INT, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), + EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP), EndContainer(), SetFill(1, 1), @@ -1682,14 +1685,10 @@ static const NWidgetPart _nested_signal_builder_widgets[] = { NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BS_DRAG_SIGNALS_DENSITY_LABEL), SetDataTip(STR_ORANGE_INT, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), - NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_DECREASE), SetSizingType(NWST_STEP), SetMinimalSize(9, 12), SetDataTip(AWV_DECREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_INCREASE), SetSizingType(NWST_STEP), SetMinimalSize(9, 12), SetDataTip(AWV_INCREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP), - NWidget(NWID_SPACER), SetFill(1, 0), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_DECREASE), SetSizingType(NWST_STEP), SetMinimalSize(9, 12), SetDataTip(AWV_DECREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_INCREASE), SetSizingType(NWST_STEP), SetMinimalSize(9, 12), SetDataTip(AWV_INCREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP), EndContainer(), EndContainer(), EndContainer(), From ac76047f546a0d221c10fdf45011108285e28f67 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 15 Nov 2014 23:35:25 +0200 Subject: [PATCH 172/187] Off-by-pixel toolbar placement, arrgh --- src/window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.cpp b/src/window.cpp index 53bdc601f5..414c35f1b4 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1684,7 +1684,7 @@ Point GetToolbarAlignedWindowPosition(int window_width) Point pt; if (_settings_client.gui.vertical_toolbar) { // Retermine if the window was opened from the left or the right toolbar - pt.x = (_last_clicked_toolbar_idx == 0) ? w->left + w->width : _screen.width - w->width - window_width - 1; + pt.x = (_last_clicked_toolbar_idx == 0) ? w->left + w->width : _screen.width - w->width - window_width; pt.y = w->top; } else { pt.x = _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width; From 6f9c0181c1692f22119cf09cfe45fc1bdaea96c4 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 16 Nov 2014 00:06:43 +0200 Subject: [PATCH 173/187] Align all construction windows to the left, to make more space at the center of the screen --- src/rail_gui.cpp | 2 +- src/window.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index c311de5516..1126a5f1db 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1485,7 +1485,7 @@ static const NWidgetPart _nested_station_builder_widgets[] = { /** High level window description of the station-build window (default & newGRF) */ static WindowDesc _station_builder_desc( - WDP_AUTO, "build_station_rail", 350, 0, + WDP_AUTO, "build_station_rail", 0, 0, WC_BUILD_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_station_builder_widgets, lengthof(_nested_station_builder_widgets) diff --git a/src/window.cpp b/src/window.cpp index 414c35f1b4..c288a000fb 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1727,7 +1727,9 @@ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int pt.x = (_screen.width + 10 - default_width) - 20; } const Window *wt = FindWindowById(WC_MAIN_TOOLBAR_RIGHT, 0); - if (wt && pt.x + default_width > _screen.width - wt->width) { + if (wt && (pt.x + default_width > _screen.width - wt->width || + desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN)) { + // Move all build toolbar windows to the right, because all build toolbars are always at the right part of the screen pt.x = _screen.width - wt->width - default_width; } From 0d3412d064ef9593236aa8be16893745f17b71fd Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 16 Nov 2014 01:44:32 +0200 Subject: [PATCH 174/187] Hide all windows when selecting vehicle destination station --- src/order_gui.cpp | 3 +++ src/viewport.cpp | 1 + src/window.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++++++ src/window_gui.h | 2 ++ 4 files changed, 65 insertions(+) diff --git a/src/order_gui.cpp b/src/order_gui.cpp index d4feae35ca..a814986427 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -562,6 +562,9 @@ private: SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, goto_place_style[type - 1], this); this->goto_type = type; this->SetWidgetDirty(WID_O_GOTO); + if (type == OPOS_GOTO) { + MoveAllWindowsOffScreen(); + } } /** diff --git a/src/viewport.cpp b/src/viewport.cpp index d4af6ff456..7f2aa022d9 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -2997,6 +2997,7 @@ void ResetObjectToPlace() _last_selected_window_number = _thd.window_number; } SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0); + MoveAllHiddenWindowsBackToScreen(); } void ToolbarSelectLastTool() diff --git a/src/window.cpp b/src/window.cpp index c288a000fb..ffd620b282 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2924,6 +2924,7 @@ static void MouseLoop(MouseClick click, int mousewheel) case MC_LEFT_UP: if (!_left_button_dragged && mouse_down_on_viewport) { HandleViewportMouseUp(vp, x, y); + MoveAllHiddenWindowsBackToScreen(); } _left_button_dragged = false; mouse_down_on_viewport = false; @@ -3602,6 +3603,64 @@ void RelocateAllWindows(int neww, int newh) } } +static void MoveAllWindowsOffScreen(bool moveOffScreen) +{ + Window *w; + bool updateScreen = false; + + FOR_ALL_WINDOWS_FROM_BACK(w) { + switch (w->window_class) { + case WC_MAIN_WINDOW: + case WC_BOOTSTRAP: + case WC_MAIN_TOOLBAR: + case WC_MAIN_TOOLBAR_RIGHT: + case WC_NEWS_WINDOW: + case WC_STATUS_BAR: + case WC_SEND_NETWORK_MSG: + case WC_CONSOLE: + continue; + + default: + if (moveOffScreen) { + if (w->left < _screen.width) { + w->left += _screen.width; + if (w->viewport != NULL) { + w->viewport->left += _screen.width; + } + //w->SetDirty(); + updateScreen = true; + } + } else { + if (w->left >= _screen.width) { + w->left -= _screen.width; + if (w->viewport != NULL) { + w->viewport->left -= _screen.width; + } + w->SetDirty(); + //updateScreen = true; + } + } + break; + } + } + if (updateScreen) { + w = FindWindowById(WC_MAIN_WINDOW, 0); + if (w) { + w->SetDirty(); + } + } +} + +void MoveAllWindowsOffScreen() +{ + MoveAllWindowsOffScreen(true); +} + +void MoveAllHiddenWindowsBackToScreen() +{ + MoveAllWindowsOffScreen(false); +} + /** * Destructor of the base class PickerWindowBase * Main utility is to stop the base Window destructor from triggering diff --git a/src/window_gui.h b/src/window_gui.h index a92b0be869..e2b5e6c451 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -865,6 +865,8 @@ Wcls *AllocateWindowDescFront(WindowDesc *desc, int window_number) } void RelocateAllWindows(int neww, int newh); +void MoveAllWindowsOffScreen(); +void MoveAllHiddenWindowsBackToScreen(); /* misc_gui.cpp */ enum TooltipCloseCondition { From 9875c976616f4d7b32e96304ecc625dc57e5a5a0 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 16 Nov 2014 01:59:32 +0200 Subject: [PATCH 175/187] Do not change windows focus on mouse-up action --- src/window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.cpp b/src/window.cpp index ffd620b282..e965f7d321 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2894,7 +2894,7 @@ static void MouseLoop(MouseClick click, int mousewheel) if (w == NULL) return; - if (click != MC_NONE && click != MC_HOVER && !MaybeBringWindowToFront(w)) return; + if (click != MC_NONE && click != MC_HOVER && click != MC_LEFT_UP && !MaybeBringWindowToFront(w)) return; if (mousewheel != 0) { /* Send mousewheel event to window */ From 8f7e444f4f503928d7134d6395243ae37eca35eb Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 16 Nov 2014 03:38:40 +0200 Subject: [PATCH 176/187] Allow scrolling when selecting destination station or building single-tile objects --- src/airport_gui.cpp | 2 +- src/dock_gui.cpp | 4 ++-- src/order_gui.cpp | 4 ++-- src/rail_gui.cpp | 4 ++-- src/road_gui.cpp | 2 +- src/tilehighlight_type.h | 1 + src/viewport.cpp | 9 ++++++++- src/window.cpp | 1 + 8 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 8448f8574e..a6afc641eb 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -88,7 +88,7 @@ struct BuildAirToolbarWindow : Window { { switch (widget) { case WID_AT_AIRPORT: - if (HandlePlacePushButton(this, WID_AT_AIRPORT, SPR_CURSOR_AIRPORT, HT_RECT)) { + if (HandlePlacePushButton(this, WID_AT_AIRPORT, SPR_CURSOR_AIRPORT, HT_RECT | HT_SCROLL_VIEWPORT)) { ShowBuildAirportPicker(this); this->last_user_action = widget; } diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index 4704b060cd..aef33082d9 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -141,7 +141,7 @@ struct BuildDocksToolbarWindow : Window { case WID_DT_DEPOT: // Build depot button if (!CanBuildVehicleInfrastructure(VEH_SHIP)) return; - if (HandlePlacePushButton(this, WID_DT_DEPOT, SPR_CURSOR_SHIP_DEPOT, HT_RECT)) ShowBuildDocksDepotPicker(this); + if (HandlePlacePushButton(this, WID_DT_DEPOT, SPR_CURSOR_SHIP_DEPOT, HT_RECT | HT_SCROLL_VIEWPORT)) ShowBuildDocksDepotPicker(this); break; case WID_DT_STATION: // Build station button @@ -151,7 +151,7 @@ struct BuildDocksToolbarWindow : Window { case WID_DT_BUOY: // Build buoy button if (!CanBuildVehicleInfrastructure(VEH_SHIP)) return; - HandlePlacePushButton(this, WID_DT_BUOY, SPR_CURSOR_BUOY, HT_RECT); + HandlePlacePushButton(this, WID_DT_BUOY, SPR_CURSOR_BUOY, HT_RECT | HT_SCROLL_VIEWPORT); break; case WID_DT_RIVER: // Build river button (in scenario editor) diff --git a/src/order_gui.cpp b/src/order_gui.cpp index a814986427..b01c47ea2e 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -555,9 +555,9 @@ private: assert(type > OPOS_NONE && type < OPOS_END); static const HighLightStyle goto_place_style[OPOS_END - 1] = { - HT_RECT | HT_VEHICLE, // OPOS_GOTO + HT_RECT | HT_VEHICLE | HT_SCROLL_VIEWPORT, // OPOS_GOTO HT_NONE, // OPOS_CONDITIONAL - HT_VEHICLE, // OPOS_SHARE + HT_VEHICLE | HT_SCROLL_VIEWPORT, // OPOS_SHARE }; SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, goto_place_style[type - 1], this); this->goto_type = type; diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 1126a5f1db..b1a50bdf74 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -522,7 +522,7 @@ struct BuildRailToolbarWindow : Window { break; case WID_RAT_BUILD_DEPOT: - if (HandlePlacePushButton(this, WID_RAT_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, HT_RECT)) { + if (HandlePlacePushButton(this, WID_RAT_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, HT_RECT | HT_SCROLL_VIEWPORT)) { ShowBuildTrainDepotPicker(this); this->last_user_action = widget; } @@ -531,7 +531,7 @@ struct BuildRailToolbarWindow : Window { case WID_RAT_BUILD_WAYPOINT: this->last_user_action = widget; _waypoint_count = StationClass::Get(STAT_CLASS_WAYP)->GetSpecCount(); - if (HandlePlacePushButton(this, WID_RAT_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, HT_RECT) && _waypoint_count > 1) { + if (HandlePlacePushButton(this, WID_RAT_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, HT_RECT | HT_SCROLL_VIEWPORT) && _waypoint_count > 1) { ShowBuildWaypointPicker(this); } break; diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 0a022505fb..9cf52681fa 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -408,7 +408,7 @@ struct BuildRoadToolbarWindow : Window { case WID_ROT_DEPOT: if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; - if (HandlePlacePushButton(this, WID_ROT_DEPOT, SPR_CURSOR_ROAD_DEPOT, HT_RECT)) { + if (HandlePlacePushButton(this, WID_ROT_DEPOT, SPR_CURSOR_ROAD_DEPOT, HT_RECT | HT_SCROLL_VIEWPORT)) { ShowRoadDepotPicker(this); this->last_started_action = widget; } diff --git a/src/tilehighlight_type.h b/src/tilehighlight_type.h index 3d64248dff..207f865a35 100644 --- a/src/tilehighlight_type.h +++ b/src/tilehighlight_type.h @@ -28,6 +28,7 @@ enum HighLightStyle { HT_RAIL = 0x080, ///< autorail (one piece), lower bits: direction HT_VEHICLE = 0x100, ///< vehicle is accepted as target as well (bitmask) HT_DIAGONAL = 0x200, ///< Also allow 'diagonal rectangles'. Only usable in combination with #HT_RECT or #HT_POINT. + HT_SCROLL_VIEWPORT = 0x400, ///< Allow scrolling viewport with left mouse button, this disables drag&drop, use only when selection cannot grow. HT_DRAG_MASK = 0x0F8, ///< Mask for the tile drag-type modes. /* lower bits (used with HT_LINE and HT_RAIL): diff --git a/src/viewport.cpp b/src/viewport.cpp index 7f2aa022d9..4c0f07da8c 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1955,7 +1955,9 @@ bool HandleViewportClicked(const ViewPort *vp, int x, int y) { if (_move_pressed) return false; - if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) { + // Allow scrolling viewport with mouse even in selection mode, + // unless we select line or area, or perform drag&drop + if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE && !(_thd.place_mode & HT_SCROLL_VIEWPORT)) { PlaceObject(); return true; } @@ -1973,6 +1975,11 @@ bool HandleViewportMouseUp(const ViewPort *vp, int x, int y) if (v != NULL && VehicleClicked(v)) return true; } + if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) { + PlaceObject(); + return true; + } + if (CheckClickOnTown(vp, x, y)) return true; if (CheckClickOnStation(vp, x, y)) return true; if (CheckClickOnSign(vp, x, y)) return true; diff --git a/src/window.cpp b/src/window.cpp index e965f7d321..54ee3d268f 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2916,6 +2916,7 @@ static void MouseLoop(MouseClick click, int mousewheel) _scrolling_viewport = true; _cursor.fix_at = false; } else { + // Viewport already clicked, prevent sending same event on mouse-up _left_button_dragged = true; } mouse_down_on_viewport = true; From d9f14a5b790c87b036f77736f55533bd15d4a9c5 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 16 Nov 2014 03:53:59 +0200 Subject: [PATCH 177/187] Hide all windows when placing airport --- src/airport_gui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index a6afc641eb..aaa7188071 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -88,7 +88,7 @@ struct BuildAirToolbarWindow : Window { { switch (widget) { case WID_AT_AIRPORT: - if (HandlePlacePushButton(this, WID_AT_AIRPORT, SPR_CURSOR_AIRPORT, HT_RECT | HT_SCROLL_VIEWPORT)) { + if (HandlePlacePushButton(this, WID_AT_AIRPORT, SPR_CURSOR_AIRPORT, HT_RECT)) { ShowBuildAirportPicker(this); this->last_user_action = widget; } @@ -108,6 +108,7 @@ struct BuildAirToolbarWindow : Window { switch (this->last_user_action) { case WID_AT_AIRPORT: { VpStartPlaceSizing(tile, VPM_SINGLE_TILE, DDSP_BUILD_STATION); + MoveAllWindowsOffScreen(); break; } @@ -130,6 +131,7 @@ struct BuildAirToolbarWindow : Window { switch (select_proc) { case DDSP_BUILD_STATION: assert(start_tile == end_tile); + MoveAllHiddenWindowsBackToScreen(); PlaceAirport(end_tile); break; case DDSP_DEMOLISH_AREA: From 5b874adee868c7ef283d4eabc03598849e4ac9f8 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 16 Nov 2014 04:46:17 +0200 Subject: [PATCH 178/187] Do not auto-close main toolbar menus, disabled autoscroll for dropdown lists --- src/toolbar_gui.cpp | 10 +++++----- src/widgets/dropdown.cpp | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index c2d9dff9b3..b97b6c99bf 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -174,7 +174,7 @@ public: static void PopupMainToolbMenu(Window *w, int widget, DropDownList *list, int def) { if (!_settings_client.gui.vertical_toolbar) { - ShowDropDownList(w, list, def, widget, 0, true, true); + ShowDropDownList(w, list, def, widget, 0, true, list->Length() <= 1); } else { Rect wi_rect; NWidgetCore *nwi = w->GetWidget(widget); @@ -182,7 +182,7 @@ static void PopupMainToolbMenu(Window *w, int widget, DropDownList *list, int de wi_rect.right = nwi->pos_x + nwi->current_x; wi_rect.top = nwi->pos_y; wi_rect.bottom = nwi->pos_y + nwi->current_y; - ShowDropDownListAt(w, list, def, widget, wi_rect, nwi->colour, true, true); + ShowDropDownListAt(w, list, def, widget, wi_rect, nwi->colour, true, list->Length() <= 1); } if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); } @@ -336,7 +336,7 @@ static CallBackFunction ToolbarOptionsClick(Window *w) *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS, OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES)); *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS)); - ShowDropDownList(w, list, 0, WID_TN_SETTINGS, 140, true, true); + ShowDropDownList(w, list, 0, WID_TN_SETTINGS, 140, true); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } @@ -872,7 +872,7 @@ static CallBackFunction ToolbarZoomOutClick(Window *w) static CallBackFunction ToolbarBuildRailClick(Window *w) { - ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true, true); + ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } @@ -909,7 +909,7 @@ static CallBackFunction ToolbarBuildRoadClick(Window *w) *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_TRAM_CONSTRUCTION, ROADTYPE_TRAM, !HasBit(c->avail_roadtypes, ROADTYPE_TRAM)); break; } - ShowDropDownList(w, list, _last_built_roadtype, WID_TN_ROADS, 140, true, true); + ShowDropDownList(w, list, _last_built_roadtype, WID_TN_ROADS, 140, true, list->Length() <= 1); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index e3ca1325d3..8073e63504 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -154,7 +154,7 @@ struct DropdownWindow : Window { this->list = list; this->selected_index = selected; this->click_delay = 0; - this->drag_mode = true; + this->drag_mode = instant_close; this->instant_close = instant_close; } @@ -341,10 +341,10 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b { DeleteWindowById(WC_DROPDOWN_MENU, 0); - /* The preferred position is just below the dropdown calling widget. */ + /* The preferred position is just below the dropdown calling widget */ int top = w->top + wi_rect.bottom + 1; - /* The preferred width equals the calling widget. */ + /* The preferred width equals the calling widget */ uint width = wi_rect.right - wi_rect.left + 1; /* Longest item in the list, if auto_width is enabled */ @@ -371,14 +371,14 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b int screen_bottom = GetMainViewBottom(); bool scroll = false; - enum { DISPLAY_BORDER = 20 }; + enum { DISPLAY_BORDER = 20, TOP_BORDER = 4 }; /* Check if the dropdown will fully fit below the widget. */ if (top + height + DISPLAY_BORDER >= screen_bottom) { /* If not, check if it will fit above the widget. */ int screen_top = GetMainViewTop(); - if (w->top + wi_rect.top > screen_top + height) { - top = w->top + wi_rect.top - height; + if (w->top + wi_rect.top - TOP_BORDER > screen_top + height) { + top = w->top + wi_rect.top - height - TOP_BORDER; } else { /* ... and lastly if it won't, enable the scroll bar and fit the * list in below the widget */ @@ -389,10 +389,10 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b /* ... and choose whether to put the list above or below the widget. */ bool put_above = false; - int available_height = screen_bottom - w->top - wi_rect.bottom - DISPLAY_BORDER; + int available_height = screen_bottom - w->top - wi_rect.bottom; if (w->top + wi_rect.top - screen_top > available_height) { // Put it above. - available_height = w->top + wi_rect.top - screen_top - DISPLAY_BORDER; + available_height = w->top + wi_rect.top - screen_top - DISPLAY_BORDER - TOP_BORDER; put_above = true; } @@ -408,7 +408,7 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b /* ... and set the top position if needed. */ if (put_above) { - top = w->top + wi_rect.top - height; + top = w->top + wi_rect.top - height - TOP_BORDER; } } } From d260038aac12353d5718a9d5944b57f1281a8b13 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 16 Nov 2014 17:12:12 +0200 Subject: [PATCH 179/187] Fixed road tunnel preview not shown when dragging mouse --- src/road_gui.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 9cf52681fa..9399b066b1 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -548,6 +548,11 @@ struct BuildRoadToolbarWindow : Window { virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) { + if (this->last_started_action == WID_ROT_BUILD_TUNNEL) { + this->OnPlacePresize(pt, TileVirtXY(pt.x, pt.y)); + return; + } + /* Here we update the end tile flags * of the road placement actions. * At first we reset the end halfroad From 49d814d5d328328d36093c01fe9de7333a825b02 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 10 Mar 2015 23:31:19 +0200 Subject: [PATCH 180/187] Fixed scenario editor GUI messed by vertical toolbar --- src/window.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/window.cpp b/src/window.cpp index 54ee3d268f..93a4736855 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1464,6 +1464,7 @@ void Window::FindWindowPlacementAndResize(int def_width, int def_height) { def_width = max(def_width, this->width); // Don't allow default size to be smaller than smallest size def_height = max(def_height, this->height); + bool vertical_toolbar = _settings_client.gui.vertical_toolbar && _game_mode != GM_EDITOR; /* Try to make windows smaller when our window is too small. * w->(width|height) is normally the same as min_(width|height), * but this way the GUIs can be made a little more dynamic; @@ -1475,11 +1476,11 @@ void Window::FindWindowPlacementAndResize(int def_width, int def_height) const Window *wt = FindWindowById(WC_STATUS_BAR, 0); if (wt != NULL) free_height -= wt->height; wt = FindWindowById(WC_MAIN_TOOLBAR, 0); - if (wt != NULL && !_settings_client.gui.vertical_toolbar) free_height -= wt->height; + if (wt != NULL && !vertical_toolbar) free_height -= wt->height; int enlarge_x = max(min(def_width - this->width, _screen.width - this->width), 0); int enlarge_y = max(min(def_height - this->height, free_height - this->height), 0); - if (wt && _settings_client.gui.vertical_toolbar && enlarge_x > _screen.width - wt->width * 2) { + if (wt && vertical_toolbar && enlarge_x > _screen.width - wt->width * 2) { enlarge_x = _screen.width - wt->width * 2; } @@ -1502,7 +1503,7 @@ void Window::FindWindowPlacementAndResize(int def_width, int def_height) if (nx + this->width > _screen.width) nx -= (nx + this->width - _screen.width); const Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0); - if (!_settings_client.gui.vertical_toolbar) { + if (!vertical_toolbar) { ny = max(ny, (wt == NULL || this == wt || this->top == 0) ? 0 : wt->height); nx = max(nx, 0); } else { @@ -1537,7 +1538,7 @@ static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &po int bottom = height + top; const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); - if (!_settings_client.gui.vertical_toolbar || !main_toolbar) { + if (!vertical_toolbar || !main_toolbar) { if (left < 0 || (main_toolbar != NULL && top < main_toolbar->height) || right > _screen.width || bottom > _screen.height) return false; } else { if (left < main_toolbar->width || top < 0 || right > _screen.width - main_toolbar->width * 2 || bottom > _screen.height) return false; @@ -1608,10 +1609,11 @@ static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &po static Point GetAutoPlacePosition(int width, int height) { Point pt; + bool vertical_toolbar = _settings_client.gui.vertical_toolbar && _game_mode != GM_EDITOR; /* First attempt, try top-left of the screen */ const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); - if (_settings_client.gui.vertical_toolbar) { + if (vertical_toolbar) { if (IsGoodAutoPlace1(main_toolbar != NULL ? main_toolbar->width : 0, 0, width, height, pt)) return pt; } else { if (IsGoodAutoPlace1(0, main_toolbar != NULL ? main_toolbar->height : 0, width, height, pt)) return pt; @@ -1652,7 +1654,7 @@ static Point GetAutoPlacePosition(int width, int height) * of (+5, +5) */ int left = 0, top = 24; - if (_settings_client.gui.vertical_toolbar) { + if (vertical_toolbar) { left = main_toolbar != NULL ? main_toolbar->width : 0; top = 0; } @@ -1682,7 +1684,7 @@ Point GetToolbarAlignedWindowPosition(int window_width) const Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); assert(w != NULL); Point pt; - if (_settings_client.gui.vertical_toolbar) { + if (_settings_client.gui.vertical_toolbar && _game_mode != GM_EDITOR) { // Retermine if the window was opened from the left or the right toolbar pt.x = (_last_clicked_toolbar_idx == 0) ? w->left + w->width : _screen.width - w->width - window_width; pt.y = w->top; @@ -2144,7 +2146,7 @@ void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen) */ int GetMainViewTop() { - if (_settings_client.gui.vertical_toolbar) return 0; + if (_settings_client.gui.vertical_toolbar && _game_mode != GM_EDITOR) return 0; Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); return (w == NULL) ? 0 : w->top + w->height; } @@ -3472,7 +3474,7 @@ static int PositionWindow(Window *w, WindowClass clss, int setting) */ int PositionMainToolbar(Window *w) { - if (_settings_client.gui.vertical_toolbar) return 0; /* Always at the left */ + if (_settings_client.gui.vertical_toolbar && _game_mode != GM_EDITOR) return 0; /* Always at the left */ DEBUG(misc, 5, "Repositioning Main Toolbar..."); return PositionWindow(w, WC_MAIN_TOOLBAR, _settings_client.gui.toolbar_pos); } From dce1a08117dbebd0402d595af28c0ab5bc6b86c3 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Tue, 10 Mar 2015 23:34:53 +0200 Subject: [PATCH 181/187] Oops --- src/window.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/window.cpp b/src/window.cpp index 93a4736855..4f078611d1 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1538,6 +1538,7 @@ static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &po int bottom = height + top; const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); + bool vertical_toolbar = _settings_client.gui.vertical_toolbar && _game_mode != GM_EDITOR; if (!vertical_toolbar || !main_toolbar) { if (left < 0 || (main_toolbar != NULL && top < main_toolbar->height) || right > _screen.width || bottom > _screen.height) return false; } else { From ab0e3a8bef7832e8d7658b690885e5faa4b27f29 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Thu, 12 Mar 2015 21:43:35 +0200 Subject: [PATCH 182/187] Removed references to tablet bar, it's not needed anymore --- src/script/api/game/game_window.hpp.sq | 1 - src/script/api/script_window.hpp | 6 ------ src/window.cpp | 1 - src/window_type.h | 6 ------ 4 files changed, 14 deletions(-) diff --git a/src/script/api/game/game_window.hpp.sq b/src/script/api/game/game_window.hpp.sq index 2646403f38..ca48a82dff 100644 --- a/src/script/api/game/game_window.hpp.sq +++ b/src/script/api/game/game_window.hpp.sq @@ -40,7 +40,6 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_WINDOW, "WC_MAIN_WINDOW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_TOOLBAR, "WC_MAIN_TOOLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATUS_BAR, "WC_STATUS_BAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TABLET_BAR, "WC_TABLET_BAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TOOLBAR, "WC_BUILD_TOOLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_BUILD_TOOLBAR, "WC_SCEN_BUILD_TOOLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TREES, "WC_BUILD_TREES"); diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp index db918744c9..c58b83a09c 100644 --- a/src/script/api/script_window.hpp +++ b/src/script/api/script_window.hpp @@ -148,12 +148,6 @@ public: */ WC_STATUS_BAR = ::WC_STATUS_BAR, - /** - * Tablet bar; %Window numbers: - * - 0 = #StatusbarWidgets - */ - WC_TABLET_BAR = ::WC_TABLET_BAR, - /** * Build toolbar; %Window numbers: * - #TRANSPORT_RAIL = #RailToolbarWidgets diff --git a/src/window.cpp b/src/window.cpp index 4f078611d1..03e0045ea0 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1296,7 +1296,6 @@ static uint GetWindowZPriority(const Window *w) ++z_priority; case WC_NEWS_WINDOW: - case WC_TABLET_BAR: ++z_priority; default: diff --git a/src/window_type.h b/src/window_type.h index 7dd6882ed3..7386f6e809 100644 --- a/src/window_type.h +++ b/src/window_type.h @@ -65,12 +65,6 @@ enum WindowClass { */ WC_STATUS_BAR, - /** - * Tablet bar; %Window numbers: - * - 0 = #StatusbarWidgets - */ - WC_TABLET_BAR, - /** * Build toolbar; %Window numbers: * - #TRANSPORT_RAIL = #RailToolbarWidgets From eb6626d24757372c22a6a9fba864aaf7504074dd Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Thu, 12 Mar 2015 22:12:16 +0200 Subject: [PATCH 183/187] Tap anywhere to close popup dropdown menu --- src/widgets/dropdown.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 8073e63504..a480245d7c 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -96,6 +96,7 @@ struct DropdownWindow : Window { byte click_delay; ///< Timer to delay selection. bool drag_mode; bool instant_close; ///< Close the window when the mouse button is raised. + bool left_button_state; ///< Close the window when the mouse button is clicked outside the window. int scrolling; ///< If non-zero, auto-scroll the item list (one time). Point position; ///< Position of the topleft corner of the window. Scrollbar *vscroll; @@ -156,6 +157,7 @@ struct DropdownWindow : Window { this->click_delay = 0; this->drag_mode = instant_close; this->instant_close = instant_close; + this->left_button_state = _left_button_down; } ~DropdownWindow() @@ -320,6 +322,16 @@ struct DropdownWindow : Window { this->SetDirty(); } } + + // Close dropdown if user clicks outside of it + if (_left_button_down && !this->left_button_state && ( + _cursor.pos.x < this->left || _cursor.pos.x > this->left + this->width || + _cursor.pos.y < this->top || _cursor.pos.y > this->top + this->height)) { + delete this; + return; + } else { + this->left_button_state = _left_button_down; + } } }; From cdde92950020596374c92aa4d34680af91d94c97 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Thu, 12 Mar 2015 22:49:48 +0200 Subject: [PATCH 184/187] Better support for hardware Ctrl/Shift keys and hardware mouse --- src/video/sdl_v.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index 613b664476..63c7755dfb 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -601,6 +601,11 @@ int VideoDriver_SDL::PollEvent() _right_button_clicked = true; _right_button_down_pos.x = ev.motion.x; _right_button_down_pos.y = ev.motion.y; +#ifdef __ANDROID__ + // Right button click on Android - cancel whatever action we were doing + ResetObjectToPlace(); + ToolbarSelectLastTool(); +#endif break; case SDL_BUTTON_WHEELUP: _cursor.wheel--; break; @@ -622,7 +627,7 @@ int VideoDriver_SDL::PollEvent() #ifdef __ANDROID__ if (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_RMASK) { // Two-finger click - hacky way to determine if the right mouse button is already pressed without processing the left button event - // Cancel whatewer action we were doing, to allow two finger scrolling + // Cancel whatever action we were doing, to allow two finger scrolling ResetObjectToPlace(); ToolbarSelectLastTool(); } @@ -656,8 +661,22 @@ int VideoDriver_SDL::PollEvent() WChar character; uint keycode = ConvertSdlKeyIntoMy(&ev.key.keysym, &character); HandleKeypress(keycode, character); +#ifdef __ANDROID__ + if (ev.key.keysym.sym == SDLK_LCTRL || ev.key.keysym.sym == SDLK_RCTRL) + _ctrl_pressed = true; + if (ev.key.keysym.sym == SDLK_LSHIFT || ev.key.keysym.sym == SDLK_RSHIFT) + _shift_pressed = true; +#endif } break; + case SDL_KEYUP: +#ifdef __ANDROID__ + if (ev.key.keysym.sym == SDLK_LCTRL || ev.key.keysym.sym == SDLK_RCTRL) + _ctrl_pressed = false; + if (ev.key.keysym.sym == SDLK_LSHIFT || ev.key.keysym.sym == SDLK_RSHIFT) + _shift_pressed = false; +#endif + break; #ifndef __ANDROID__ case SDL_VIDEORESIZE: { int w = max(ev.resize.w, 64); From 1e5fb9290c6680c362326c155b864603a9eb8ad2 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 15 Mar 2015 23:00:51 +0200 Subject: [PATCH 185/187] Video tutorial dialog, only one bus tutorial for now --- source.list | 1 + src/intro_gui.cpp | 12 ++- src/lang/english.txt | 7 +- src/main_gui.cpp | 2 + src/toolbar_gui.cpp | 2 + src/tutorial_gui.cpp | 191 +++++++++++++++++++++++++++++++++++++ src/tutorial_gui.h | 18 ++++ src/widgets/intro_widget.h | 1 + 8 files changed, 228 insertions(+), 6 deletions(-) create mode 100644 src/tutorial_gui.cpp create mode 100644 src/tutorial_gui.h diff --git a/source.list b/source.list index 208d9b8e86..814a475602 100644 --- a/source.list +++ b/source.list @@ -92,6 +92,7 @@ tgp.cpp tile_map.cpp tilearea.cpp townname.cpp +tutorial_gui.cpp #if WIN32 #else #if WINCE diff --git a/src/intro_gui.cpp b/src/intro_gui.cpp index eaf67fb971..37bff8c5a1 100644 --- a/src/intro_gui.cpp +++ b/src/intro_gui.cpp @@ -27,6 +27,7 @@ #include "language.h" #include "rev.h" #include "highscore.h" +#include "tutorial_gui.h" #include "widgets/intro_widget.h" @@ -141,6 +142,7 @@ struct SelectGameWindow : public Window { } break; case WID_SGI_AI_SETTINGS: ShowAIConfigWindow(); break; + case WID_SGI_TUTORIAL: ShowTutorialWindow(); break; case WID_SGI_EXIT: HandleExitGameRequest(); break; } } @@ -236,11 +238,11 @@ static const NWidgetPart _nested_select_game_widgets[] = { NWidget(NWID_SPACER), SetMinimalSize(0, 6), /* 'exit program' button */ - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_EXIT), SetMinimalSize(128, 12), - SetDataTip(STR_INTRO_QUIT, STR_INTRO_TOOLTIP_QUIT), - NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_TUTORIAL), SetMinimalSize(158, 12), + SetDataTip(STR_ABOUT_MENU_TUTORIAL, STR_TUTORIAL_WINDOW_TOOLTIP), SetPadding(0, 0, 0, 10), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_EXIT), SetMinimalSize(158, 12), + SetDataTip(STR_INTRO_QUIT, STR_INTRO_TOOLTIP_QUIT), SetPadding(0, 10, 0, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 8), diff --git a/src/lang/english.txt b/src/lang/english.txt index bb3349d017..58971ddc39 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -457,7 +457,7 @@ STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Message history ############ range for about menu starts STR_ABOUT_MENU_LAND_BLOCK_INFO :Land area information -STR_ABOUT_MENU_SEPARATOR : +STR_ABOUT_MENU_TUTORIAL :{BLACK}Tutorial STR_ABOUT_MENU_TOGGLE_CONSOLE :Toggle console STR_ABOUT_MENU_AI_DEBUG :AI/Game script debug STR_ABOUT_MENU_SCREENSHOT :Screenshot @@ -468,6 +468,7 @@ STR_ABOUT_MENU_ABOUT_OPENTTD :About 'OpenTTD' STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite aligner STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Toggle bounding boxes STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Toggle colouring of dirty blocks +STR_ABOUT_MENU_SEPARATOR : ############ range ends here ############ range for ordinal numbers used for the place in the highscore window @@ -2694,6 +2695,10 @@ STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Original STR_ABOUT_VERSION :{BLACK}OpenTTD version {REV} STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT} 2002-2014 The OpenTTD team +#Tutorial window +STR_TUTORIAL_WINDOW_TITLE :{BLACK}Tutorial videos +STR_TUTORIAL_WINDOW_TOOLTIP :{BLACK}Open a video player to watch tutorial videos + # Save/load game/scenario STR_SAVELOAD_SAVE_CAPTION :{WHITE}Save Game STR_SAVELOAD_LOAD_CAPTION :{WHITE}Load Game diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 0988d8c828..820a48623f 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -32,6 +32,7 @@ #include "linkgraph/linkgraph_gui.h" #include "tilehighlight_func.h" #include "hotkeys.h" +#include "tutorial_gui.h" #include "saveload/saveload.h" @@ -563,6 +564,7 @@ void SetupColoursAndInitialWindow() default: NOT_REACHED(); case GM_MENU: ShowSelectGameWindow(); + ShowTutorialWindowOnceAfterInstall(); break; case GM_NORMAL: diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index b97b6c99bf..e0d92b38b2 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -46,6 +46,7 @@ #include "game/game.hpp" #include "goal_base.h" #include "story_base.h" +#include "tutorial_gui.h" #include "widgets/toolbar_widget.h" @@ -1145,6 +1146,7 @@ static CallBackFunction MenuClickHelp(int index) { switch (index) { case 0: return PlaceLandBlockInfo(); + case 1: ShowTutorialWindow(); break; case 2: IConsoleSwitch(); break; case 3: ShowAIDebugWindow(); break; case 4: MenuClickSmallScreenshot(); break; diff --git a/src/tutorial_gui.cpp b/src/tutorial_gui.cpp new file mode 100644 index 0000000000..530a600737 --- /dev/null +++ b/src/tutorial_gui.cpp @@ -0,0 +1,191 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** + * @file tutorial_gui.cpp + * Links to video tutorials on Youtube. + */ + +#include "stdafx.h" + +#include + +#include "tutorial_gui.h" +#include "debug.h" +#include "strings_func.h" +#include "window_func.h" +#include "fios.h" +#include "string_func.h" +#include "language.h" +#include "widget_type.h" +#include "window_type.h" +#include "window_func.h" +#include "window_gui.h" +#include "widgets/station_widget.h" +#include "table/strings.h" +#include "table/sprites.h" + + +static const char * ANY_LANG = "ANY_LANG"; + +struct VideoLink_t { + const char *lang; + const char *video; +}; + +static VideoLink_t busTutorial[] = { + { "en", "https://www.youtube.com/watch?v=EULXRMR4PyE" }, + { ANY_LANG, "https://www.youtube.com/watch?v=EULXRMR4PyE" }, + { NULL, NULL } +}; + +void OpenExternTutorialVideo(VideoLink_t *tutorial) +{ + const char *link = NULL; + for (; tutorial->lang != NULL; tutorial++) { + if (strcmp(tutorial->lang, _current_language->isocode) == 0) { + link = tutorial->video; + break; + } + if (strcmp(tutorial->lang, ANY_LANG) == 0) { + link = tutorial->video; + break; + } + } + if (!link) { + return; + } + SDL_ANDROID_OpenExternalWebBrowser(link); +} + +static const NWidgetPart _nested_tutorial_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_TUTORIAL_WINDOW_TITLE, STR_TUTORIAL_WINDOW_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(6, 0, 6), + NWidget(WWT_PANEL, COLOUR_GREY), SetPIP(8, 2, 6), + // TODO: make different button IDs + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_BUS_STATION, STR_SMALLMAP_LEGENDA_BUS_STATION), SetFill(1, 1), + NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_ROAD_VEHICLES, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY), SetFill(1, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_BUS), SetMinimalSize(120, 20), SetDataTip(SPR_VEH_BUS_SW_VIEW, STR_SMALLMAP_LEGENDA_BUS_STATION), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_TRUCK), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_TRUCKLIST, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY), SetFill(1, 1), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetFill(1, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_RAILROADS, STR_SMALLMAP_LEGENDA_RAILROAD_STATION), SetFill(1, 1), + NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_SHIPS, STR_SMALLMAP_LEGENDA_DOCK), SetFill(1, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_TRAIN), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_TRAINLIST, STR_SMALLMAP_LEGENDA_RAILROAD_STATION), SetFill(0, 1), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_SHIP), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_SHIPLIST, STR_SMALLMAP_LEGENDA_DOCK), SetFill(0, 1), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetFill(1, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_AIRCRAFT, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT), SetFill(1, 1), + NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_INDUSTRIES, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES), SetFill(1, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_AIRPLANESLIST, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT), SetFill(0, 1), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_COMPANY_FINANCE, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES), SetFill(0, 1), + EndContainer(), + EndContainer(), + EndContainer(), +}; + +static WindowDesc _tutorial_desc( + WDP_CENTER, NULL, 0, 0, + WC_GAME_OPTIONS, WC_NONE, + 0, + _nested_tutorial_widgets, lengthof(_nested_tutorial_widgets) +); + + +struct TutorialWindow : public Window { + VideoLink_t *video; + int counter; + TutorialWindow() : Window(&_tutorial_desc) + { + this->InitNested(WN_GAME_OPTIONS_ABOUT); + this->SetWidgetDisabledState(WID_STL_TRUCK, true); + this->SetWidgetDisabledState(WID_STL_TRAIN, true); + this->SetWidgetDisabledState(WID_STL_SHIP, true); + this->SetWidgetDisabledState(WID_STL_AIRPLANE, true); + this->SetWidgetDisabledState(WID_STL_FACILALL, true); + video = NULL; + counter = 0; + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + counter = 5; + this->LowerWidget(widget); + this->SetDirty(); + switch (widget) { + case WID_STL_BUS: + video = busTutorial; + break; + case WID_STL_TRUCK: + break; + case WID_STL_TRAIN: + break; + case WID_STL_SHIP: + break; + case WID_STL_AIRPLANE: + break; + case WID_STL_FACILALL: + break; + } + } + + virtual void OnTick() + { + // Open video with delay, to make visual feedback of button pressing, + // because youtube app freezes a screen for a second before launching. + if (counter > 0) { + counter--; + if (counter == 0) { + if (video) { + OpenExternTutorialVideo(video); + } + video = NULL; + this->RaiseWidget(WID_STL_BUS); + this->RaiseWidget(WID_STL_TRUCK); + this->RaiseWidget(WID_STL_TRAIN); + this->RaiseWidget(WID_STL_SHIP); + this->RaiseWidget(WID_STL_AIRPLANE); + this->RaiseWidget(WID_STL_FACILALL); + this->SetDirty(); + } + } + } +}; + +void ShowTutorialWindow() +{ + DeleteWindowByClass(WC_GAME_OPTIONS); + new TutorialWindow(); +} + +void ShowTutorialWindowOnceAfterInstall() +{ + static const char * TUTORIAL_SHOWN_FLAG = ".tutorial-shown-1.flag"; + FILE *ff = fopen(TUTORIAL_SHOWN_FLAG, "r"); + if (ff) { + fclose(ff); + return; + } + ff = fopen(TUTORIAL_SHOWN_FLAG, "w"); + fprintf(ff, "Tutorial shown"); + fclose(ff); + ShowTutorialWindow(); +} diff --git a/src/tutorial_gui.h b/src/tutorial_gui.h new file mode 100644 index 0000000000..04840ee2c6 --- /dev/null +++ b/src/tutorial_gui.h @@ -0,0 +1,18 @@ +/* $Id$ */ + +/* + * 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 . + */ + +/** @file tutorial_gui.h Links to video tutorials. */ + +#ifndef TUTORIAL_GUI_H +#define TUTORIAL_GUI_H + +void ShowTutorialWindow(); +void ShowTutorialWindowOnceAfterInstall(); + +#endif /* TUTORIAL_GUI_H */ diff --git a/src/widgets/intro_widget.h b/src/widgets/intro_widget.h index 6a67fe64ca..7447fbdb5f 100644 --- a/src/widgets/intro_widget.h +++ b/src/widgets/intro_widget.h @@ -32,6 +32,7 @@ enum SelectGameIntroWidgets { WID_SGI_GRF_SETTINGS, ///< NewGRF button. WID_SGI_CONTENT_DOWNLOAD, ///< Content Download button. WID_SGI_AI_SETTINGS, ///< AI button. + WID_SGI_TUTORIAL, ///< Tutorial button. WID_SGI_EXIT, ///< Exit button. }; From fc4ae3a627a0f6d8e3643a7d45e7cc8c361dc3a1 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 15 Mar 2015 23:23:46 +0200 Subject: [PATCH 186/187] Fixes to tutorial dialog --- src/tutorial_gui.cpp | 68 +++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/src/tutorial_gui.cpp b/src/tutorial_gui.cpp index 530a600737..26d3dfb1e0 100644 --- a/src/tutorial_gui.cpp +++ b/src/tutorial_gui.cpp @@ -32,6 +32,8 @@ #include "table/sprites.h" +static bool showTutorialMainMenu = false; + static const char * ANY_LANG = "ANY_LANG"; struct VideoLink_t { @@ -69,35 +71,39 @@ static const NWidgetPart _nested_tutorial_widgets[] = { NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_TUTORIAL_WINDOW_TITLE, STR_TUTORIAL_WINDOW_TOOLTIP), EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(6, 0, 6), - NWidget(WWT_PANEL, COLOUR_GREY), SetPIP(8, 2, 6), - // TODO: make different button IDs - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_BUS_STATION, STR_SMALLMAP_LEGENDA_BUS_STATION), SetFill(1, 1), - NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_ROAD_VEHICLES, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY), SetFill(1, 1), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_BUS), SetMinimalSize(120, 20), SetDataTip(SPR_VEH_BUS_SW_VIEW, STR_SMALLMAP_LEGENDA_BUS_STATION), SetFill(1, 1), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_TRUCK), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_TRUCKLIST, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY), SetFill(1, 1), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetFill(1, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_RAILROADS, STR_SMALLMAP_LEGENDA_RAILROAD_STATION), SetFill(1, 1), - NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_SHIPS, STR_SMALLMAP_LEGENDA_DOCK), SetFill(1, 1), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_TRAIN), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_TRAINLIST, STR_SMALLMAP_LEGENDA_RAILROAD_STATION), SetFill(0, 1), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_SHIP), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_SHIPLIST, STR_SMALLMAP_LEGENDA_DOCK), SetFill(0, 1), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetFill(1, 0), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_AIRCRAFT, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT), SetFill(1, 1), - NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_INDUSTRIES, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES), SetFill(1, 1), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_AIRPLANESLIST, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT), SetFill(0, 1), - NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_COMPANY_FINANCE, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES), SetFill(0, 1), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetMinimalSize(6, 0), SetFill(1, 0), + NWidget(NWID_VERTICAL), SetPIP(16, 2, 6), + // TODO: make different button IDs + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_BUS_STATION, STR_SMALLMAP_LEGENDA_BUS_STATION), SetFill(1, 1), + NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_ROAD_VEHICLES, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY), SetFill(1, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_BUS), SetMinimalSize(120, 20), SetDataTip(SPR_VEH_BUS_SW_VIEW, STR_SMALLMAP_LEGENDA_BUS_STATION), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_TRUCK), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_TRUCKLIST, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY), SetFill(1, 1), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetFill(1, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_RAILROADS, STR_SMALLMAP_LEGENDA_RAILROAD_STATION), SetFill(1, 1), + NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_SHIPS, STR_SMALLMAP_LEGENDA_DOCK), SetFill(1, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_TRAIN), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_TRAINLIST, STR_SMALLMAP_LEGENDA_RAILROAD_STATION), SetFill(0, 1), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_SHIP), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_SHIPLIST, STR_SMALLMAP_LEGENDA_DOCK), SetFill(0, 1), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetFill(1, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_AIRCRAFT, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT), SetFill(1, 1), + NWidget(WWT_LABEL, COLOUR_GREY), SetMinimalSize(120, 12), SetDataTip(STR_SMALLMAP_LEGENDA_INDUSTRIES, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES), SetFill(1, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_AIRPLANESLIST, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT), SetFill(0, 1), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(120, 20), SetDataTip(SPR_IMG_COMPANY_FINANCE, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES), SetFill(0, 1), + EndContainer(), EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(6, 0), SetFill(1, 0), EndContainer(), EndContainer(), }; @@ -127,6 +133,7 @@ struct TutorialWindow : public Window { virtual void OnClick(Point pt, int widget, int click_count) { + showTutorialMainMenu = false; counter = 5; this->LowerWidget(widget); this->SetDirty(); @@ -179,11 +186,14 @@ void ShowTutorialWindow() void ShowTutorialWindowOnceAfterInstall() { static const char * TUTORIAL_SHOWN_FLAG = ".tutorial-shown-1.flag"; + FILE *ff = fopen(TUTORIAL_SHOWN_FLAG, "r"); if (ff) { fclose(ff); - return; + if (!showTutorialMainMenu) + return; } + showTutorialMainMenu = true; ff = fopen(TUTORIAL_SHOWN_FLAG, "w"); fprintf(ff, "Tutorial shown"); fclose(ff); From 6977514ff1837b5b616fa3594230b9af9e3c3dbc Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 15 Mar 2015 23:34:38 +0200 Subject: [PATCH 187/187] Removed some unused Android-specific strings --- src/lang/english.txt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 58971ddc39..a4ab88ac22 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -991,8 +991,6 @@ STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Addition STR_ERROR_RESOLUTION_LIST_FAILED :{WHITE}Failed to retrieve a list of supported resolutions STR_ERROR_FULLSCREEN_FAILED :{WHITE}Fullscreen mode failed -STR_ERROR_RESET_WINDOWS :{WHITE}All windows have been reseted... -STR_ERROR_AUTOMATIC_SIZING :{WHITE}Sizes of buttons and fonts have changed # Custom currency window @@ -2465,18 +2463,12 @@ STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Level an STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Purchase land for future use. Shift toggles building/showing cost estimate # Tablet toolbar -STR_TABLET_X :{BLACK}{TINY_FONT}Trans -STR_TABLET_TOGGLE_TRANSPARENCY_TOOLTIP :{BLACK}Toggle transparency STR_TABLET_CLOSE :{BLACK}X STR_TABLET_CLOSE_TOOLTIP :{BLACK}Close all opened windows (except pinned ones) STR_TABLET_SHIFT :{BLACK}{TINY_FONT}Shft STR_TABLET_SHIFT_TOOLTIP :{BLACK}Press it for getting an estimated cost of executing an action STR_TABLET_CTRL :{BLACK}{TINY_FONT}Ctrl STR_TABLET_CTRL_TOOLTIP :{BLACK}Use it for actions that use the "CTRL" key -STR_TABLET_MOVE :{BLACK}{TINY_FONT}Move -STR_TABLET_MOVE_TOOLTIP :{BLACK}Press it to move around viewports. No action will be executed on viewports while this is active -STR_TABLET_CONFIRM :{BLACK}{TINY_FONT}Do -STR_TABLET_CONFIRM_TOOLTIP :{BLACK}Press it to confirm an action # Object construction window STR_OBJECT_BUILD_CAPTION :{WHITE}Object Selection @@ -2685,10 +2677,6 @@ STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE :Lighthouse STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS :Company headquarters STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :Company-owned land -# Console - -STR_CONSOLE_QUERY_STRING :Enter a console command - # About OpenTTD window STR_ABOUT_OPENTTD :{WHITE}About OpenTTD STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Original copyright {COPYRIGHT} 1995 Chris Sawyer, All rights reserved