From 010d977b16cd73955fa9aa128b7a92450d930dc3 Mon Sep 17 00:00:00 2001 From: translators Date: Thu, 15 Apr 2021 17:52:17 +0000 Subject: [PATCH 1/9] Update: Translations from eints hungarian: 5 changes by nemesbala catalan: 2 changes by J0anJosep tamil: 3 changes by Saran-S-Menon --- src/lang/catalan.txt | 2 ++ src/lang/hungarian.txt | 5 +++++ src/lang/tamil.txt | 3 +++ 3 files changed, 10 insertions(+) diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index 65f17997bd..e8b0892d42 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -1007,6 +1007,8 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Accelera STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Seleccioneu aquesta opció per permetre que l'OpenTTD provi d'usar acceleració per maquinari. Si es canvia l'opció, s'aplicarà quan es reiniciï el programa. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}La configuració tindrà efecte quan es reiniciï el programa. +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Selecciona aquesta casella per activar la sincronització vertical de la pantalla. Els canvis s'aplicaran quan es reiniciï el programa. Només funciona si s'activa l'acceleració per maquinari. STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Mida de la interfície STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Escull la mida dels elements de la interfície diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt index f9c689f7f8..ca6483c5b3 100644 --- a/src/lang/hungarian.txt +++ b/src/lang/hungarian.txt @@ -1070,6 +1070,8 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hardvere STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Bekapcsolásával az OpenTTD hardveres gyorsítást próbál alkalmazni. A beállítás csak a játék újraindítása után lép érvénybe. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Ez a beállítás csak a játék újraindítása után lép érvénybe +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync (Vertikális Szinkronizáció) +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Jelöld be ezt a négyzetet hogy engedélyezd a v-sync-et. A változtatás csak a játék újraindítása után fog érvényesülni. Kizárólag hardware gyorsítással működik! STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Felület mérete STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Használni kívánt felületméret kiválasztása @@ -1203,6 +1205,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Beállí STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Szűrő kifejezés: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Összes szétnyitása STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Összes összecsukása +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Visszaállítja az összes értéket STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(leírás nem elérhető) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Alapértelmezett érték: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Beállítás típusa: {ORANGE}{STRING} @@ -1211,6 +1214,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Játék beáll STR_CONFIG_SETTING_TYPE_GAME_INGAME :Játék beállítás (mentésben tárolva; csak a jelenlegi játékot befolyásolja) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Vállalat beállítás (mentésben tárolva; csak az új játékokat befolyásolja) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Vállalat beállítás (mentésben tárolva; csak a jelenlegi vállalatot befolyásolja) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Figyelem! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Ez a művelet minden játékbeállítást visszaállít.{}Biztos, hogy folytatni akarja a műveletet? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Kategória: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Típus: diff --git a/src/lang/tamil.txt b/src/lang/tamil.txt index a919a195aa..99b2384e73 100644 --- a/src/lang/tamil.txt +++ b/src/lang/tamil.txt @@ -962,6 +962,7 @@ STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}OpenTTD- STR_GAME_OPTIONS_RESOLUTION :{BLACK}திரையின் அளவு STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}திரை அளவினைத் தேர்ந்தெடுக்கவும் STR_GAME_OPTIONS_RESOLUTION_OTHER :மற்றவை +STR_GAME_OPTIONS_RESOLUTION_ITEM :{NUM}x{NUM} @@ -1697,6 +1698,7 @@ STR_FACE_LOAD :{BLACK}ஏற STR_FACE_LOAD_TOOLTIP :{BLACK}பிடித்த முகத்தினை பதிவேற்று STR_FACE_LOAD_DONE :{WHITE}உங்களுடைய பிடித்த முகம் OpenTTD உள்ளமைவு கோப்பிலிருந்து ஏற்றப்பட்டுள்ளது STR_FACE_FACECODE :{BLACK}விளையாடுபவர் முக எண் +STR_FACE_FACECODE_TOOLTIP :{BLACK}நிறுவனரின் முக எண்னை பார் மற்றும்/அல்லது அமை STR_FACE_FACECODE_CAPTION :{WHITE}நிறுவனரின் முக எண்னை பார் அல்லது அமை STR_FACE_FACECODE_SET :{WHITE}புதிய முக எண் குறி அமைக்கப்பட்டது STR_FACE_SAVE :{BLACK}சேமி @@ -2118,6 +2120,7 @@ STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :மேக்ல STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}இரயில்வே இருப்புப் பாதையினை கட்டவும். Shift அழுத்தினால் கட்டுமான/செலவு மதிப்பீடு காட்டப்படும் STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}இரயில் பணிமனையினைக் (இரயில்களை வாங்க மற்றும் பழுதுபார்க்க) கட்டவும். Shift அழுத்தினால் கட்டுமான/செலவு மதிப்பீடு காட்டப்படும் +STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}இரயில் தடத்தை வழிப்புள்ளியாக மாற்றும். வழிப்புள்ளிகளை இணைக்க Ctrl-ஐ அழுத்தவும். கட்டுமான/செலவு மதிப்பீட்டினை காட்டShift-ஐ அழுத்தவும். STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}இரயில் நிலையத்தினை கட்டவும். Ctrl அழுத்தினால் நிலையங்களினை இணைக்கலாம். Shift அழுத்தினால் கட்டுமான/செலவு மதிப்பீடு காட்டப்படும் STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}இரயில்வே சிக்னல்களைக் கட்டவும். Ctrl அழுத்தினால் சிக்னல் வகைகளை மாற்றலாம்{}இரயில் தடத்தின்மேல் இழுத்தினால் சிக்னல்களை அமைக்கலாம். Ctrl அழுத்தினால் அடுத்த எணைப்பு வரை சிக்னல்கள் அமைக்கப்படும்{}Ctrl+Click அழுத்தினால் சிக்னல் தேர்ந்தெடுக்கும் திரை தெரியும்/மரையும். Shift அழுத்தினால் கட்டுமான/செலவு மதிப்பீடு காட்டப்படும் STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}இரயில்வே பாலத்தினை கட்டவும். Shift அழுத்தினால் கட்டுமான/செலவு மதிப்பீடு காட்டப்படும் From a4db7c844d761a68b19ad88c9bfee8fcf5dc71b5 Mon Sep 17 00:00:00 2001 From: translators Date: Fri, 16 Apr 2021 17:52:24 +0000 Subject: [PATCH 2/9] Update: Translations from eints korean: 6 changes by telk5093 portuguese (brazilian): 2 changes by Greavez --- src/lang/brazilian_portuguese.txt | 2 ++ src/lang/korean.txt | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index 3d902f7234..89d8f32043 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -1007,6 +1007,8 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Acelera STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Marque esta caixa para permitir que o OpenTTD tente usar a aceleração de hardware. Qualquer mudança nesta configuração só será aplicada após reiniciar o jogo. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}A configuração só terá efeito após reiniciar o jogo +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Marque esta caixa para habilitar o v-sync na tela. Qualquer mudança nesta configuração só será aplicada após reiniciar o jogo. Só funciona com a aceleração de hardware habilitada STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Tamanho da interface STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Selecione o tamanho de elemento de interface a ser usado diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 2f8d593cde..d6efaa457f 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -1729,38 +1729,38 @@ STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :종종 두 역 STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :속력 단위: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :속력를 표시할 때 선택한 단위를 사용하여 나타냅니다. -STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :임페리얼법 (mph) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :야드파운드법 (mph) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :미터법 (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :국제표준규격 (m/s) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_GAMEUNITS :게임 단위 (칸/일) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :차량의 힘 단위: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :출력할 차량의 힘 단위를 선택합니다. -STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :임페리얼법 (마력) +STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :야드파운드법 (마력) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :미터법 (마력) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :국제표준규격 (kW) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :무게 단위: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :무게를 표시할 때 선택한 단위를 사용하여 나타냅니다. -STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :임페리얼법 (미국 톤) +STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :야드파운드법 (미국 톤) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :미터법 (톤) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :국제표준규격 (kg) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :부피 단위: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :부피를 표시할 때 선택한 단위를 사용하여 나타냅니다. -STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :임페리얼법 (갤런) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :야드파운드법 (갤런) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :미터법 (리터) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :국제표준규격 (m³) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :견인 효과 단위: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :견인 효과(견인력)를 표시할 때 선택한 단위를 사용하여 나타냅니다. -STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :임페리얼법 (파운드중) +STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :야드파운드법 (파운드중) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :미터법 (kgf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :국제표준규격 (kN) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :높이 단위: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :높이를 표시할 때 선택한 단위를 사용하여 나타냅니다. -STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :임페리얼법 (ft) +STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :야드파운드법 (ft) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :미터법 (m) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :국제표준규격 (m) From 837994034d1836e30658b9e38d5ce1b2df1e2846 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 15 Apr 2021 23:58:49 +0100 Subject: [PATCH 3/9] Fix: Sizing of Multiplayer server list incorrect when GUI zoom doesn't match Font zoom. The server information panel was scaled by GUI scale, which could result in a panel that is longer than the server list. This height difference is then maintained when the window is resized to fill the screen. Instead, specify the minimum size by number of text lines and (summed total) padding. --- src/network/network_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index ae263cf00c..c1f11e84e3 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -954,7 +954,7 @@ static const NWidgetPart _nested_network_game_widgets[] = { EndContainer(), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_DETAILS), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(5, 5, 5), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_DETAILS_SPACER), SetMinimalSize(140, 155), SetResize(0, 1), SetFill(1, 1), // Make sure it's at least this wide + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_DETAILS_SPACER), SetMinimalSize(140, 0), SetMinimalTextLines(15, 24 + WD_PAR_VSEP_NORMAL), SetResize(0, 1), SetFill(1, 1), // Make sure it's at least this wide NWidget(NWID_HORIZONTAL, NC_NONE), SetPIP(5, 5, 5), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_MISSING_SEL), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF_MISSING), SetFill(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON, STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP), From fbef63822c9bcc3b2bb26988cd14a6767eba5fd8 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 11 Apr 2021 23:02:59 +0100 Subject: [PATCH 4/9] Codechange: Use std::deque for chat history instead of fixed array --- src/network/network_chat_gui.cpp | 60 +++++++++----------------------- 1 file changed, 16 insertions(+), 44 deletions(-) diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index 80a0b78695..a1157e2615 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -8,6 +8,7 @@ /** @file network_chat_gui.cpp GUI for handling chat messages. */ #include /* va_list */ +#include #include "../stdafx.h" #include "../strings_func.h" @@ -44,7 +45,7 @@ struct ChatMessage { }; /* used for chat window */ -static ChatMessage *_chatmsg_list = nullptr; ///< The actual chat message list. +static std::deque _chatmsg_list; ///< The actual chat message list. static bool _chatmessage_dirty = false; ///< Does the chat message need repainting? static bool _chatmessage_visible = false; ///< Is a chat message visible. static bool _chat_tab_completion_active; ///< Whether tab completion is active. @@ -57,20 +58,6 @@ static uint MAX_CHAT_MESSAGES = 0; ///< The limit of chat messages to sho static PointDimension _chatmsg_box; static uint8 *_chatmessage_backup = nullptr; ///< Backup in case text is moved. -/** - * Count the chat messages. - * @return The number of chat messages. - */ -static inline uint GetChatMessageCount() -{ - uint i = 0; - for (; i < MAX_CHAT_MESSAGES; i++) { - if (_chatmsg_list[i].message[0] == '\0') break; - } - - return i; -} - /** * Add a text message to the 'chat window' to be shown * @param colour The colour this message is to be shown in @@ -88,13 +75,11 @@ void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const char *m Utf8TrimString(buf, DRAW_STRING_BUFFER); - uint msg_count = GetChatMessageCount(); - if (MAX_CHAT_MESSAGES == msg_count) { - memmove(&_chatmsg_list[0], &_chatmsg_list[1], sizeof(_chatmsg_list[0]) * (msg_count - 1)); - msg_count = MAX_CHAT_MESSAGES - 1; + if (_chatmsg_list.size() == MAX_CHAT_MESSAGES) { + _chatmsg_list.pop_back(); } - ChatMessage *cmsg = &_chatmsg_list[msg_count++]; + ChatMessage *cmsg = &_chatmsg_list.emplace_front(); strecpy(cmsg->message, buf, lastof(cmsg->message)); cmsg->colour = (colour & TC_IS_PALETTE_COLOUR) ? colour : TC_WHITE; cmsg->remove_time = std::chrono::steady_clock::now() + std::chrono::seconds(duration); @@ -115,15 +100,11 @@ void NetworkInitChatMessage() { MAX_CHAT_MESSAGES = _settings_client.gui.network_chat_box_height; - _chatmsg_list = ReallocT(_chatmsg_list, _settings_client.gui.network_chat_box_height); + _chatmsg_list.clear(); _chatmsg_box.x = 10; _chatmsg_box.width = _settings_client.gui.network_chat_box_width_pct * _screen.width / 100; NetworkReInitChatBoxSize(); _chatmessage_visible = false; - - for (uint i = 0; i < MAX_CHAT_MESSAGES; i++) { - _chatmsg_list[i].message[0] = '\0'; - } } /** Hide the chatbox */ @@ -175,21 +156,13 @@ void NetworkUndrawChatMessage() /** Check if a message is expired. */ void NetworkChatMessageLoop() { - for (uint i = 0; i < MAX_CHAT_MESSAGES; i++) { - ChatMessage *cmsg = &_chatmsg_list[i]; - if (cmsg->message[0] == '\0') continue; - + for (auto it = _chatmsg_list.begin(); it != _chatmsg_list.end();) { /* Message has expired, remove from the list */ - if (std::chrono::steady_clock::now() > cmsg->remove_time) { - /* Move the remaining messages over the current message */ - if (i != MAX_CHAT_MESSAGES - 1) memmove(cmsg, cmsg + 1, sizeof(*cmsg) * (MAX_CHAT_MESSAGES - i - 1)); - - /* Mark the last item as empty */ - _chatmsg_list[MAX_CHAT_MESSAGES - 1].message[0] = '\0'; + if (std::chrono::steady_clock::now() > it->remove_time) { + it = _chatmsg_list.erase(it); _chatmessage_dirty = true; - - /* Go one item back, because we moved the array 1 to the left */ - i--; + } else { + it++; } } } @@ -206,8 +179,7 @@ void NetworkDrawChatMessage() if (_iconsole_mode == ICONSOLE_FULL) return; /* Check if we have anything to draw at all */ - uint count = GetChatMessageCount(); - if (count == 0) return; + if (_chatmsg_list.size() == 0) return; int x = _chatmsg_box.x; int y = _screen.height - _chatmsg_box.y - _chatmsg_box.height; @@ -230,8 +202,8 @@ void NetworkDrawChatMessage() _cur_dpi = &_screen; // switch to _screen painting int string_height = 0; - for (uint i = 0; i < count; i++) { - SetDParamStr(0, _chatmsg_list[i].message); + for (auto &cmsg : _chatmsg_list) { + SetDParamStr(0, cmsg.message); string_height += GetStringLineCount(STR_JUST_RAW_STRING, width - 1) * FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING; } @@ -247,8 +219,8 @@ void NetworkDrawChatMessage() /* Paint the chat messages starting with the lowest at the bottom */ int ypos = bottom - 2; - for (int i = count - 1; i >= 0; i--) { - ypos = DrawStringMultiLine(_chatmsg_box.x + 3, _chatmsg_box.x + _chatmsg_box.width - 1, top, ypos, _chatmsg_list[i].message, _chatmsg_list[i].colour, SA_LEFT | SA_BOTTOM | SA_FORCE) - NETWORK_CHAT_LINE_SPACING; + for (auto &cmsg : _chatmsg_list) { + ypos = DrawStringMultiLine(_chatmsg_box.x + 3, _chatmsg_box.x + _chatmsg_box.width - 1, top, ypos, cmsg.message, cmsg.colour, SA_LEFT | SA_BOTTOM | SA_FORCE) - NETWORK_CHAT_LINE_SPACING; if (ypos < top) break; } From cb9f56df0c8eb6e711402e9f840bc78f23614bca Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 11 Apr 2021 23:26:57 +0100 Subject: [PATCH 5/9] Feature: Show previous chat history when the chat message box is open --- src/network/network_chat_gui.cpp | 43 +++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index a1157e2615..5a92ef0db6 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -51,6 +51,12 @@ static bool _chatmessage_visible = false; ///< Is a chat message visible. static bool _chat_tab_completion_active; ///< Whether tab completion is active. static uint MAX_CHAT_MESSAGES = 0; ///< The limit of chat messages to show. +/** + * Time the chat history was marked dirty. This is used to determine if expired + * messages have recently expired and should cause a redraw to hide them. + */ +static std::chrono::steady_clock::time_point _chatmessage_dirty_time; + /** * The chatbox grows from the bottom so the coordinates are pixels from * the left and pixels from the bottom. The height is the maximum height. @@ -58,6 +64,23 @@ static uint MAX_CHAT_MESSAGES = 0; ///< The limit of chat messages to sho static PointDimension _chatmsg_box; static uint8 *_chatmessage_backup = nullptr; ///< Backup in case text is moved. +/** + * Test if there are any chat messages to display. + * @param show_all Set if all messages should be included, instead of unexpired only. + * @return True iff there are chat messages to display. + */ +static inline bool HaveChatMessages(bool show_all) +{ + if (show_all) return _chatmsg_list.size() != 0; + + auto now = std::chrono::steady_clock::now(); + for (auto &cmsg : _chatmsg_list) { + if (cmsg.remove_time >= now) return true; + } + + return false; +} + /** * Add a text message to the 'chat window' to be shown * @param colour The colour this message is to be shown in @@ -84,6 +107,7 @@ void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const char *m cmsg->colour = (colour & TC_IS_PALETTE_COLOUR) ? colour : TC_WHITE; cmsg->remove_time = std::chrono::steady_clock::now() + std::chrono::seconds(duration); + _chatmessage_dirty_time = std::chrono::steady_clock::now(); _chatmessage_dirty = true; } @@ -149,6 +173,7 @@ void NetworkUndrawChatMessage() /* And make sure it is updated next time */ VideoDriver::GetInstance()->MakeDirty(x, y, width, height); + _chatmessage_dirty_time = std::chrono::steady_clock::now(); _chatmessage_dirty = true; } } @@ -156,13 +181,13 @@ void NetworkUndrawChatMessage() /** Check if a message is expired. */ void NetworkChatMessageLoop() { - for (auto it = _chatmsg_list.begin(); it != _chatmsg_list.end();) { + auto now = std::chrono::steady_clock::now(); + for (auto &cmsg : _chatmsg_list) { /* Message has expired, remove from the list */ - if (std::chrono::steady_clock::now() > it->remove_time) { - it = _chatmsg_list.erase(it); + if (now > cmsg.remove_time && _chatmessage_dirty_time < cmsg.remove_time) { + _chatmessage_dirty_time = now; _chatmessage_dirty = true; - } else { - it++; + break; } } } @@ -173,13 +198,16 @@ void NetworkDrawChatMessage() Blitter *blitter = BlitterFactory::GetCurrentBlitter(); if (!_chatmessage_dirty) return; + const Window *w = FindWindowByClass(WC_SEND_NETWORK_MSG); + bool show_all = (w != nullptr); + /* First undraw if needed */ NetworkUndrawChatMessage(); if (_iconsole_mode == ICONSOLE_FULL) return; /* Check if we have anything to draw at all */ - if (_chatmsg_list.size() == 0) return; + if (!HaveChatMessages(show_all)) return; int x = _chatmsg_box.x; int y = _screen.height - _chatmsg_box.y - _chatmsg_box.height; @@ -201,8 +229,10 @@ void NetworkDrawChatMessage() _cur_dpi = &_screen; // switch to _screen painting + auto now = std::chrono::steady_clock::now(); int string_height = 0; for (auto &cmsg : _chatmsg_list) { + if (!show_all && cmsg.remove_time < now) continue; SetDParamStr(0, cmsg.message); string_height += GetStringLineCount(STR_JUST_RAW_STRING, width - 1) * FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING; } @@ -220,6 +250,7 @@ void NetworkDrawChatMessage() int ypos = bottom - 2; for (auto &cmsg : _chatmsg_list) { + if (!show_all && cmsg.remove_time < now) continue; ypos = DrawStringMultiLine(_chatmsg_box.x + 3, _chatmsg_box.x + _chatmsg_box.width - 1, top, ypos, cmsg.message, cmsg.colour, SA_LEFT | SA_BOTTOM | SA_FORCE) - NETWORK_CHAT_LINE_SPACING; if (ypos < top) break; } From 6c49ae9cd7612a0e7a4542cc49d7361889d0f345 Mon Sep 17 00:00:00 2001 From: translators Date: Sat, 17 Apr 2021 17:50:40 +0000 Subject: [PATCH 6/9] Update: Translations from eints chinese (simplified): 3 changes by clzls spanish: 1 change by MontyMontana polish: 6 changes by Milek7 --- src/lang/polish.txt | 7 ++++++- src/lang/simplified_chinese.txt | 6 +++--- src/lang/spanish.txt | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 38c132732f..09d44f2fc1 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -1386,6 +1386,8 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Przyspie STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Zaznacz to pole, aby zezwolić OpenTTD na użycie przyspieszenia sprzętowego. Ustawienia zostaną zastosowane dopiero po ponownym uruchomieniu gry. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Ustawienie to zacznie obowiązywać dopiero po ponownym uruchomieniu gry. +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}Synchronizacja pionowa +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Zaznacz to pole aby włączyć synchronizację pionową. Zmiany zostaną zastosowane po restarcie gry. Działa tylko z włączoną akceleracją sprzętową. STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Rozmiar interfejsu STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Wybierz rozmiar elementów interfejsu @@ -1519,6 +1521,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Ustawien STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtrowanie po frazie: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Otwórz wszystko STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Zamknij wszystko +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Zresetuj wszystkie ustawienia STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(wyjaśnienie niedostępne) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Domyślna wartość: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Typ ustawienia: {ORANGE}{STRING} @@ -1527,6 +1530,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Ustawienie gry STR_CONFIG_SETTING_TYPE_GAME_INGAME :Ustawienie gry (przechowywane w pliku zapisu; ma wpływ tylko na aktualną grę) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Ustawienie firmy (przechowywane w plikach zapisu; ma wpływ tylko na nowe gry) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Ustawienie firmy (przechowywane w pliku zapisu; ma wpływ tylko na aktualną firmę) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Uwaga! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Wszystkie ustawienia zostaną przywrócone do wartości domyślnych.{}Jesteś pewien czy chcesz kontynuować? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Kategoria: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Typ: @@ -2912,7 +2917,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Zbuduj p STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Ustaw boję, która może być użyta jako pkt. orientacyjny. Shift przełącza pomiędzy trybem budowania a szacowaniem jego kosztów STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Zbuduj akwedukt. Shift przełącza pomiędzy trybem budowania a szacowaniem jego kosztów STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Stwórz akwen wodny.{}Tworzy kanał, chyba że przyrzymany jest CTRL na poziomie morza, wtedy pobliski teren zostanie zatopiony -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Umieszczanie rzek +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Umieszczanie rzek. Ctrl zaznacza obszar po przekątnej. # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Ukierunkowanie stoczni diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index 4f7aa144bc..891c597f75 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -3965,8 +3965,8 @@ STR_ORDERS_END_OF_SHARED_ORDERS :- - 共享调 STR_ORDER_NON_STOP :{BLACK}不停车 STR_ORDER_GO_TO :前往 STR_ORDER_GO_NON_STOP_TO :不停车前往 -STR_ORDER_GO_VIA :通过 -STR_ORDER_GO_NON_STOP_VIA :前往不停车 +STR_ORDER_GO_VIA :经由 +STR_ORDER_GO_NON_STOP_VIA :经由(不停车) STR_ORDER_TOOLTIP_NON_STOP :{BLACK}改变当前选中车站停车时的执行动作 STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}装满任意货物 @@ -4659,7 +4659,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}在{DATE # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}不能让列车冒险通过信号... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}不能命令列车调头... -STR_ERROR_TRAIN_START_NO_POWER :木有接触网! +STR_ERROR_TRAIN_START_NO_POWER :没有接触网! STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN :{WHITE}车辆无法调头... diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index 292d32426f..95630e6d31 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -315,7 +315,7 @@ STR_SORT_BY_RANGE :Alcance STR_SORT_BY_POPULATION :Población STR_SORT_BY_RATING :Calificación STR_SORT_BY_NUM_VEHICLES :Número de vehículos -STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :Beneficios total del último año +STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :Beneficio total del último año STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR :Beneficio total este año STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :Beneficio medio el año pasado STR_SORT_BY_AVERAGE_PROFIT_THIS_YEAR :Beneficio medio este año From 47a99bb67632b6c05b70024f0639c767d057c6ae Mon Sep 17 00:00:00 2001 From: Rubidium Date: Thu, 15 Apr 2021 18:47:41 +0200 Subject: [PATCH 7/9] Fix #7513: recursive garbage collection caused stack overflow --- src/3rdparty/squirrel/squirrel/sqarray.h | 2 +- src/3rdparty/squirrel/squirrel/sqclass.h | 4 +- src/3rdparty/squirrel/squirrel/sqclosure.h | 6 +- src/3rdparty/squirrel/squirrel/sqobject.cpp | 131 ++++++++------------ src/3rdparty/squirrel/squirrel/sqobject.h | 38 +++++- src/3rdparty/squirrel/squirrel/sqstate.cpp | 65 +++++----- src/3rdparty/squirrel/squirrel/sqstate.h | 4 +- src/3rdparty/squirrel/squirrel/sqtable.h | 2 +- src/3rdparty/squirrel/squirrel/squserdata.h | 2 +- src/3rdparty/squirrel/squirrel/sqvm.h | 2 +- 10 files changed, 139 insertions(+), 117 deletions(-) diff --git a/src/3rdparty/squirrel/squirrel/sqarray.h b/src/3rdparty/squirrel/squirrel/sqarray.h index 5c26352079..37d91bc4e1 100644 --- a/src/3rdparty/squirrel/squirrel/sqarray.h +++ b/src/3rdparty/squirrel/squirrel/sqarray.h @@ -17,7 +17,7 @@ public: return newarray; } #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); #endif void Finalize(){ _values.resize(0); diff --git a/src/3rdparty/squirrel/squirrel/sqclass.h b/src/3rdparty/squirrel/squirrel/sqclass.h index 895c053c24..cb0973bbee 100644 --- a/src/3rdparty/squirrel/squirrel/sqclass.h +++ b/src/3rdparty/squirrel/squirrel/sqclass.h @@ -59,7 +59,7 @@ public: } void Finalize(); #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable ** ); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); #endif SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); SQInstance *CreateInstance(); @@ -147,7 +147,7 @@ public: } void Finalize(); #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable ** ); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); #endif bool InstanceOf(SQClass *trg); bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); diff --git a/src/3rdparty/squirrel/squirrel/sqclosure.h b/src/3rdparty/squirrel/squirrel/sqclosure.h index a42dcd575a..8480fb8af2 100644 --- a/src/3rdparty/squirrel/squirrel/sqclosure.h +++ b/src/3rdparty/squirrel/squirrel/sqclosure.h @@ -32,7 +32,7 @@ public: bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret); #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); void Finalize(){_outervalues.resize(0); } #endif SQObjectPtr _env; @@ -66,7 +66,7 @@ public: bool Yield(SQVM *v); bool Resume(SQVM *v,SQInteger target); #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); void Finalize(){_stack.resize(0);_closure=_null_;} #endif SQObjectPtr _closure; @@ -106,7 +106,7 @@ public: sq_delete(this,SQNativeClosure); } #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); void Finalize(){_outervalues.resize(0);} #endif SQInteger _nparamscheck; diff --git a/src/3rdparty/squirrel/squirrel/sqobject.cpp b/src/3rdparty/squirrel/squirrel/sqobject.cpp index d48baca1e9..a113f316de 100644 --- a/src/3rdparty/squirrel/squirrel/sqobject.cpp +++ b/src/3rdparty/squirrel/squirrel/sqobject.cpp @@ -486,104 +486,81 @@ bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr #ifndef NO_GARBAGE_COLLECTOR -#define START_MARK() if(!(_uiRef&MARK_FLAG)){ \ - _uiRef|=MARK_FLAG; - -#define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \ - AddToChain(chain, this); } - -void SQVM::Mark(SQCollectable **chain) +void SQVM::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - SQSharedState::MarkObject(_lasterror,chain); - SQSharedState::MarkObject(_errorhandler,chain); - SQSharedState::MarkObject(_debughook,chain); - SQSharedState::MarkObject(_roottable, chain); - SQSharedState::MarkObject(temp_reg, chain); - for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); - for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); - for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::MarkObject(_callsstack[k]._closure, chain); - END_MARK() + SQSharedState::EnqueueMarkObject(_lasterror,queue); + SQSharedState::EnqueueMarkObject(_errorhandler,queue); + SQSharedState::EnqueueMarkObject(_debughook,queue); + SQSharedState::EnqueueMarkObject(_roottable, queue); + SQSharedState::EnqueueMarkObject(temp_reg, queue); + for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::EnqueueMarkObject(_stack[i], queue); + for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::EnqueueMarkObject(_vargsstack[j], queue); + for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::EnqueueMarkObject(_callsstack[k]._closure, queue); } -void SQArray::Mark(SQCollectable **chain) +void SQArray::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - SQInteger len = _values.size(); - for(SQInteger i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain); - END_MARK() -} -void SQTable::Mark(SQCollectable **chain) -{ - START_MARK() - if(_delegate) _delegate->Mark(chain); - SQInteger len = _numofnodes; - for(SQInteger i = 0; i < len; i++){ - SQSharedState::MarkObject(_nodes[i].key, chain); - SQSharedState::MarkObject(_nodes[i].val, chain); - } - END_MARK() + SQInteger len = _values.size(); + for(SQInteger i = 0;i < len; i++) SQSharedState::EnqueueMarkObject(_values[i], queue); } -void SQClass::Mark(SQCollectable **chain) +void SQTable::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - _members->Mark(chain); - if(_base) _base->Mark(chain); - SQSharedState::MarkObject(_attributes, chain); - for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) { - SQSharedState::MarkObject(_defaultvalues[i].val, chain); - SQSharedState::MarkObject(_defaultvalues[i].attrs, chain); - } - for(SQUnsignedInteger j =0; j< _methods.size(); j++) { - SQSharedState::MarkObject(_methods[j].val, chain); - SQSharedState::MarkObject(_methods[j].attrs, chain); - } - for(SQUnsignedInteger k =0; k< _metamethods.size(); k++) { - SQSharedState::MarkObject(_metamethods[k], chain); - } - END_MARK() + if(_delegate) queue.Enqueue(_delegate); + SQInteger len = _numofnodes; + for(SQInteger i = 0; i < len; i++){ + SQSharedState::EnqueueMarkObject(_nodes[i].key, queue); + SQSharedState::EnqueueMarkObject(_nodes[i].val, queue); + } } -void SQInstance::Mark(SQCollectable **chain) +void SQClass::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - _class->Mark(chain); - SQUnsignedInteger nvalues = _class->_defaultvalues.size(); - for(SQUnsignedInteger i =0; i< nvalues; i++) { - SQSharedState::MarkObject(_values[i], chain); - } - END_MARK() + queue.Enqueue(_members); + if(_base) queue.Enqueue(_base); + SQSharedState::EnqueueMarkObject(_attributes, queue); + for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) { + SQSharedState::EnqueueMarkObject(_defaultvalues[i].val, queue); + SQSharedState::EnqueueMarkObject(_defaultvalues[i].attrs, queue); + } + for(SQUnsignedInteger j =0; j< _methods.size(); j++) { + SQSharedState::EnqueueMarkObject(_methods[j].val, queue); + SQSharedState::EnqueueMarkObject(_methods[j].attrs, queue); + } + for(SQUnsignedInteger k =0; k< _metamethods.size(); k++) { + SQSharedState::EnqueueMarkObject(_metamethods[k], queue); + } } -void SQGenerator::Mark(SQCollectable **chain) +void SQInstance::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); - for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); - SQSharedState::MarkObject(_closure, chain); - END_MARK() + queue.Enqueue(_class); + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + for(SQUnsignedInteger i =0; i< nvalues; i++) { + SQSharedState::EnqueueMarkObject(_values[i], queue); + } } -void SQClosure::Mark(SQCollectable **chain) +void SQGenerator::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); - for(SQUnsignedInteger i = 0; i < _defaultparams.size(); i++) SQSharedState::MarkObject(_defaultparams[i], chain); - END_MARK() + for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::EnqueueMarkObject(_stack[i], queue); + for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::EnqueueMarkObject(_vargsstack[j], queue); + SQSharedState::EnqueueMarkObject(_closure, queue); } -void SQNativeClosure::Mark(SQCollectable **chain) +void SQClosure::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); - END_MARK() + for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::EnqueueMarkObject(_outervalues[i], queue); + for(SQUnsignedInteger i = 0; i < _defaultparams.size(); i++) SQSharedState::EnqueueMarkObject(_defaultparams[i], queue); } -void SQUserData::Mark(SQCollectable **chain){ - START_MARK() - if(_delegate) _delegate->Mark(chain); - END_MARK() +void SQNativeClosure::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) +{ + for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::EnqueueMarkObject(_outervalues[i], queue); +} + +void SQUserData::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue){ + if(_delegate) queue.Enqueue(_delegate); } void SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; } diff --git a/src/3rdparty/squirrel/squirrel/sqobject.h b/src/3rdparty/squirrel/squirrel/sqobject.h index d71e515a8d..ed4f31fcbb 100644 --- a/src/3rdparty/squirrel/squirrel/sqobject.h +++ b/src/3rdparty/squirrel/squirrel/sqobject.h @@ -2,6 +2,7 @@ #ifndef _SQOBJECT_H_ #define _SQOBJECT_H_ +#include #include "squtils.h" #define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R')) @@ -344,13 +345,48 @@ struct SQCollectable : public SQRefCounted { SQCollectable *_prev; SQSharedState *_sharedstate; virtual void Release()=0; - virtual void Mark(SQCollectable **chain)=0; + virtual void EnqueueMarkObjectForChildren(class SQGCMarkerQueue &queue)=0; void UnMark(); virtual void Finalize()=0; static void AddToChain(SQCollectable **chain,SQCollectable *c); static void RemoveFromChain(SQCollectable **chain,SQCollectable *c); }; +/** + * Helper container for state to change the garbage collection from a recursive to an iterative approach. + * The iterative approach provides effectively a depth first search approach. + */ +class SQGCMarkerQueue { + std::forward_list queue; ///< The queue of elements to still process. +public: + /** Whether there are any elements left to process. */ + bool IsEmpty() { return this->queue.empty(); } + + /** + * Remove the first element from the queue. + * Removal when the queue is empty results in undefined behaviour. + */ + SQCollectable *Pop() + { + SQCollectable *collectable = this->queue.front(); + this->queue.pop_front(); + return collectable; + } + + /** + * Add a collectable to the queue, but only when it has not been marked yet. + * When adding it to the queue, the collectable will be marked, so subsequent calls + * will not add it again. + */ + void Enqueue(SQCollectable *collectable) + { + if ((collectable->_uiRef & MARK_FLAG) == 0) { + collectable->_uiRef |= MARK_FLAG; + this->queue.push_front(collectable); + } + } +}; + #define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj) #define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG))RemoveFromChain(chain,obj);} diff --git a/src/3rdparty/squirrel/squirrel/sqstate.cpp b/src/3rdparty/squirrel/squirrel/sqstate.cpp index 8233ad1789..9d91c78996 100644 --- a/src/3rdparty/squirrel/squirrel/sqstate.cpp +++ b/src/3rdparty/squirrel/squirrel/sqstate.cpp @@ -228,18 +228,18 @@ SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name) #ifndef NO_GARBAGE_COLLECTOR -void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) +void SQSharedState::EnqueueMarkObject(SQObjectPtr &o,SQGCMarkerQueue &queue) { switch(type(o)){ - case OT_TABLE:_table(o)->Mark(chain);break; - case OT_ARRAY:_array(o)->Mark(chain);break; - case OT_USERDATA:_userdata(o)->Mark(chain);break; - case OT_CLOSURE:_closure(o)->Mark(chain);break; - case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break; - case OT_GENERATOR:_generator(o)->Mark(chain);break; - case OT_THREAD:_thread(o)->Mark(chain);break; - case OT_CLASS:_class(o)->Mark(chain);break; - case OT_INSTANCE:_instance(o)->Mark(chain);break; + case OT_TABLE:queue.Enqueue(_table(o));break; + case OT_ARRAY:queue.Enqueue(_array(o));break; + case OT_USERDATA:queue.Enqueue(_userdata(o));break; + case OT_CLOSURE:queue.Enqueue(_closure(o));break; + case OT_NATIVECLOSURE:queue.Enqueue(_nativeclosure(o));break; + case OT_GENERATOR:queue.Enqueue(_generator(o));break; + case OT_THREAD:queue.Enqueue(_thread(o));break; + case OT_CLASS:queue.Enqueue(_class(o));break; + case OT_INSTANCE:queue.Enqueue(_instance(o));break; default: break; //shutup compiler } } @@ -248,27 +248,36 @@ void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) SQInteger SQSharedState::CollectGarbage(SQVM *vm) { SQInteger n=0; - SQCollectable *tchain=NULL; SQVM *vms = _thread(_root_vm); - vms->Mark(&tchain); + SQGCMarkerQueue queue; + queue.Enqueue(vms); #ifdef WITH_ASSERT SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed(); #endif - _refs_table.Mark(&tchain); - MarkObject(_registry,&tchain); - MarkObject(_consts,&tchain); - MarkObject(_metamethodsmap,&tchain); - MarkObject(_table_default_delegate,&tchain); - MarkObject(_array_default_delegate,&tchain); - MarkObject(_string_default_delegate,&tchain); - MarkObject(_number_default_delegate,&tchain); - MarkObject(_generator_default_delegate,&tchain); - MarkObject(_thread_default_delegate,&tchain); - MarkObject(_closure_default_delegate,&tchain); - MarkObject(_class_default_delegate,&tchain); - MarkObject(_instance_default_delegate,&tchain); - MarkObject(_weakref_default_delegate,&tchain); + _refs_table.EnqueueMarkObject(queue); + EnqueueMarkObject(_registry,queue); + EnqueueMarkObject(_consts,queue); + EnqueueMarkObject(_metamethodsmap,queue); + EnqueueMarkObject(_table_default_delegate,queue); + EnqueueMarkObject(_array_default_delegate,queue); + EnqueueMarkObject(_string_default_delegate,queue); + EnqueueMarkObject(_number_default_delegate,queue); + EnqueueMarkObject(_generator_default_delegate,queue); + EnqueueMarkObject(_thread_default_delegate,queue); + EnqueueMarkObject(_closure_default_delegate,queue); + EnqueueMarkObject(_class_default_delegate,queue); + EnqueueMarkObject(_instance_default_delegate,queue); + EnqueueMarkObject(_weakref_default_delegate,queue); + + SQCollectable *tchain=NULL; + + while (!queue.IsEmpty()) { + SQCollectable *q = queue.Pop(); + q->EnqueueMarkObjectForChildren(queue); + SQCollectable::RemoveFromChain(&_gc_chain, q); + SQCollectable::AddToChain(&tchain, q); + } SQCollectable *t = _gc_chain; SQCollectable *nx = NULL; @@ -357,12 +366,12 @@ RefTable::~RefTable() } #ifndef NO_GARBAGE_COLLECTOR -void RefTable::Mark(SQCollectable **chain) +void RefTable::EnqueueMarkObject(SQGCMarkerQueue &queue) { RefNode *nodes = (RefNode *)_nodes; for(SQUnsignedInteger n = 0; n < _numofslots; n++) { if(type(nodes->obj) != OT_NULL) { - SQSharedState::MarkObject(nodes->obj,chain); + SQSharedState::EnqueueMarkObject(nodes->obj,queue); } nodes++; } diff --git a/src/3rdparty/squirrel/squirrel/sqstate.h b/src/3rdparty/squirrel/squirrel/sqstate.h index da6bf9ae64..d1a1f8dd63 100644 --- a/src/3rdparty/squirrel/squirrel/sqstate.h +++ b/src/3rdparty/squirrel/squirrel/sqstate.h @@ -34,7 +34,7 @@ struct RefTable { void AddRef(SQObject &obj); SQBool Release(SQObject &obj); #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObject(SQGCMarkerQueue &queue); #endif void Finalize(); private: @@ -63,7 +63,7 @@ public: SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name); #ifndef NO_GARBAGE_COLLECTOR SQInteger CollectGarbage(SQVM *vm); - static void MarkObject(SQObjectPtr &o,SQCollectable **chain); + static void EnqueueMarkObject(SQObjectPtr &o,SQGCMarkerQueue &queue); #endif SQObjectPtrVec *_metamethods; SQObjectPtr _metamethodsmap; diff --git a/src/3rdparty/squirrel/squirrel/sqtable.h b/src/3rdparty/squirrel/squirrel/sqtable.h index 52d9ba41ab..0083a90a9d 100644 --- a/src/3rdparty/squirrel/squirrel/sqtable.h +++ b/src/3rdparty/squirrel/squirrel/sqtable.h @@ -60,7 +60,7 @@ public: SQ_FREE(_nodes, _numofnodes * sizeof(_HashNode)); } #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); #endif inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash) { diff --git a/src/3rdparty/squirrel/squirrel/squserdata.h b/src/3rdparty/squirrel/squirrel/squserdata.h index 3bf1a9dbad..ca4933de2d 100644 --- a/src/3rdparty/squirrel/squirrel/squserdata.h +++ b/src/3rdparty/squirrel/squirrel/squserdata.h @@ -18,7 +18,7 @@ struct SQUserData : SQDelegable return ud; } #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); void Finalize(){SetDelegate(NULL);} #endif void Release() { diff --git a/src/3rdparty/squirrel/squirrel/sqvm.h b/src/3rdparty/squirrel/squirrel/sqvm.h index 9c8e986fbc..dbfe2309c7 100644 --- a/src/3rdparty/squirrel/squirrel/sqvm.h +++ b/src/3rdparty/squirrel/squirrel/sqvm.h @@ -113,7 +113,7 @@ public: #endif #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); #endif void Finalize(); void GrowCallStack() { From 44d1b964bf1c87324b82b1793218b5f79a9be9eb Mon Sep 17 00:00:00 2001 From: Rubidium Date: Thu, 15 Apr 2021 19:44:43 +0200 Subject: [PATCH 8/9] Fix #7513: recursive array/class/table release caused stack overflow --- src/3rdparty/squirrel/squirrel/sqarray.h | 12 ++++++--- src/3rdparty/squirrel/squirrel/sqclass.h | 16 ++++++------ src/3rdparty/squirrel/squirrel/sqobject.h | 22 ++++++++++------ src/3rdparty/squirrel/squirrel/sqstate.cpp | 29 ++++++++++++++++++++++ src/3rdparty/squirrel/squirrel/sqstate.h | 5 ++++ src/3rdparty/squirrel/squirrel/sqtable.h | 10 +++++--- 6 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/3rdparty/squirrel/squirrel/sqarray.h b/src/3rdparty/squirrel/squirrel/sqarray.h index 37d91bc4e1..13ae11619c 100644 --- a/src/3rdparty/squirrel/squirrel/sqarray.h +++ b/src/3rdparty/squirrel/squirrel/sqarray.h @@ -17,9 +17,9 @@ public: return newarray; } #ifndef NO_GARBAGE_COLLECTOR - void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override; #endif - void Finalize(){ + void Finalize() override { _values.resize(0); } bool Get(const SQInteger nidx,SQObjectPtr &val) @@ -78,9 +78,13 @@ public: ShrinkIfNeeded(); return true; } - void Release() + void Release() override { - sq_delete(this,SQArray); + this->_sharedstate->DelayFinalFree(this); + } + void FinalFree() override + { + sq_delete(this, SQArray); } SQObjectPtrVec _values; }; diff --git a/src/3rdparty/squirrel/squirrel/sqclass.h b/src/3rdparty/squirrel/squirrel/sqclass.h index cb0973bbee..4fb6ecbd97 100644 --- a/src/3rdparty/squirrel/squirrel/sqclass.h +++ b/src/3rdparty/squirrel/squirrel/sqclass.h @@ -126,31 +126,33 @@ public: } return false; } - void Release() { + void Release() override { _uiRef++; try { if (_hook) { _hook(_userpointer,0);} } catch (...) { _uiRef--; if (_uiRef == 0) { - SQInteger size = _memsize; - this->~SQInstance(); - SQ_FREE(this, size); + this->_sharedstate->DelayFinalFree(this); } throw; } _uiRef--; if(_uiRef > 0) return; + this->_sharedstate->DelayFinalFree(this); + } + void FinalFree() override + { SQInteger size = _memsize; this->~SQInstance(); SQ_FREE(this, size); } - void Finalize(); + void Finalize() override; #ifndef NO_GARBAGE_COLLECTOR - void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override; #endif bool InstanceOf(SQClass *trg); - bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); + bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) override; SQClass *_class; SQUserPointer _userpointer; diff --git a/src/3rdparty/squirrel/squirrel/sqobject.h b/src/3rdparty/squirrel/squirrel/sqobject.h index ed4f31fcbb..9212766eef 100644 --- a/src/3rdparty/squirrel/squirrel/sqobject.h +++ b/src/3rdparty/squirrel/squirrel/sqobject.h @@ -2,7 +2,7 @@ #ifndef _SQOBJECT_H_ #define _SQOBJECT_H_ -#include +#include #include "squtils.h" #define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R')) @@ -350,6 +350,14 @@ struct SQCollectable : public SQRefCounted { virtual void Finalize()=0; static void AddToChain(SQCollectable **chain,SQCollectable *c); static void RemoveFromChain(SQCollectable **chain,SQCollectable *c); + + /** + * Helper to perform the final memory freeing of this instance. Since the destructor might + * release more objects, this can cause a very deep recursion. As such, the calls to this + * are to be done via _sharedstate->DelayFinalFree which ensures the calls to this method + * are done in an iterative instead of recursive approach. + */ + virtual void FinalFree() {} }; /** @@ -357,19 +365,19 @@ struct SQCollectable : public SQRefCounted { * The iterative approach provides effectively a depth first search approach. */ class SQGCMarkerQueue { - std::forward_list queue; ///< The queue of elements to still process. + std::vector stack; ///< The elements to still process, with the most recent elements at the back. public: /** Whether there are any elements left to process. */ - bool IsEmpty() { return this->queue.empty(); } + bool IsEmpty() { return this->stack.empty(); } /** - * Remove the first element from the queue. + * Remove the most recently added element from the queue. * Removal when the queue is empty results in undefined behaviour. */ SQCollectable *Pop() { - SQCollectable *collectable = this->queue.front(); - this->queue.pop_front(); + SQCollectable *collectable = this->stack.back(); + this->stack.pop_back(); return collectable; } @@ -382,7 +390,7 @@ public: { if ((collectable->_uiRef & MARK_FLAG) == 0) { collectable->_uiRef |= MARK_FLAG; - this->queue.push_front(collectable); + this->stack.push_back(collectable); } } }; diff --git a/src/3rdparty/squirrel/squirrel/sqstate.cpp b/src/3rdparty/squirrel/squirrel/sqstate.cpp index 9d91c78996..31345d6640 100644 --- a/src/3rdparty/squirrel/squirrel/sqstate.cpp +++ b/src/3rdparty/squirrel/squirrel/sqstate.cpp @@ -99,6 +99,7 @@ SQSharedState::SQSharedState() _notifyallexceptions = false; _scratchpad=NULL; _scratchpadsize=0; + _collectable_free_processing = false; #ifndef NO_GARBAGE_COLLECTOR _gc_chain=NULL; #endif @@ -226,6 +227,34 @@ SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name) return -1; } +/** + * Helper function that is to be used instead of calling FinalFree directly on the instance, + * so the frees can happen iteratively. This as in the FinalFree the references to any other + * objects are released, which can cause those object to be freed yielding a potentially + * very deep stack in case of for example a link list. + * + * This is done internally by a vector onto which the to be freed instances are pushed. When + * this is called when not already processing, this method will actually call the FinalFree + * function which might cause more elements to end up in the queue which this method then + * picks up continueing until it has processed all instances in that queue. + * @param collectable The collectable to (eventually) free. + */ +void SQSharedState::DelayFinalFree(SQCollectable *collectable) +{ + this->_collectable_free_queue.push_back(collectable); + + if (!this->_collectable_free_processing) { + this->_collectable_free_processing = true; + while (!this->_collectable_free_queue.empty()) { + SQCollectable *collectable = this->_collectable_free_queue.back(); + this->_collectable_free_queue.pop_back(); + collectable->FinalFree(); + } + this->_collectable_free_processing = false; + } +} + + #ifndef NO_GARBAGE_COLLECTOR void SQSharedState::EnqueueMarkObject(SQObjectPtr &o,SQGCMarkerQueue &queue) diff --git a/src/3rdparty/squirrel/squirrel/sqstate.h b/src/3rdparty/squirrel/squirrel/sqstate.h index d1a1f8dd63..547e6de47d 100644 --- a/src/3rdparty/squirrel/squirrel/sqstate.h +++ b/src/3rdparty/squirrel/squirrel/sqstate.h @@ -61,6 +61,7 @@ struct SQSharedState public: SQChar* GetScratchPad(SQInteger size); SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name); + void DelayFinalFree(SQCollectable *collectable); #ifndef NO_GARBAGE_COLLECTOR SQInteger CollectGarbage(SQVM *vm); static void EnqueueMarkObject(SQObjectPtr &o,SQGCMarkerQueue &queue); @@ -74,6 +75,10 @@ public: SQObjectPtr _registry; SQObjectPtr _consts; SQObjectPtr _constructoridx; + /** Queue to make freeing of collectables iterative. */ + std::vector _collectable_free_queue; + /** Whether someone is already processing the _collectable_free_queue. */ + bool _collectable_free_processing; #ifndef NO_GARBAGE_COLLECTOR SQCollectable *_gc_chain; #endif diff --git a/src/3rdparty/squirrel/squirrel/sqtable.h b/src/3rdparty/squirrel/squirrel/sqtable.h index 0083a90a9d..fad2fdc605 100644 --- a/src/3rdparty/squirrel/squirrel/sqtable.h +++ b/src/3rdparty/squirrel/squirrel/sqtable.h @@ -50,7 +50,7 @@ public: newtable->_delegate = NULL; return newtable; } - void Finalize(); + void Finalize() override; SQTable *Clone(); ~SQTable() { @@ -60,7 +60,7 @@ public: SQ_FREE(_nodes, _numofnodes * sizeof(_HashNode)); } #ifndef NO_GARBAGE_COLLECTOR - void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override; #endif inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash) { @@ -81,7 +81,11 @@ public: SQInteger CountUsed(){ return _usednodes;} void Clear(); - void Release() + void Release() override + { + this->_sharedstate->DelayFinalFree(this); + } + void FinalFree() override { sq_delete(this, SQTable); } From 8e539ce293def7d307743282721a6e7174bf0350 Mon Sep 17 00:00:00 2001 From: PeterN Date: Sat, 17 Apr 2021 19:19:06 +0100 Subject: [PATCH 9/9] Change: Improve layout and spacing of vehicle group widgets. (#9041) Existing layout included a blank widget above the group list to align with the vehicle list, however since then an additional sort-by row was added. Group list size tweaks to match normal row size (at least with normal gui and text size.) Removed reduction of 2 rows in the group list <- main culprit of odd sizing. Removed fill attribute on buttons which gave strange sizes, and put it on the group info widget instead. Tweaked various soft-padding values to line up (centreing text with a 1px offset does not make centred text.) --- src/group_gui.cpp | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 0573837688..a8b4c5f17e 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -46,7 +46,6 @@ static const NWidgetPart _nested_group_widgets[] = { 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), @@ -54,18 +53,18 @@ static const NWidgetPart _nested_group_widgets[] = { SetFill(1, 0), SetResize(0, 1), SetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_GL_LIST_GROUP_SCROLLBAR), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_INFO), SetFill(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_INFO), SetFill(1, 1), SetMinimalTextLines(3, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_CREATE_GROUP), SetFill(0, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_CREATE_GROUP), SetDataTip(SPR_GROUP_CREATE_TRAIN, STR_GROUP_CREATE_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_DELETE_GROUP), SetFill(0, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_DELETE_GROUP), SetDataTip(SPR_GROUP_DELETE_TRAIN, STR_GROUP_DELETE_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_RENAME_GROUP), SetFill(0, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_RENAME_GROUP), SetDataTip(SPR_GROUP_RENAME_TRAIN, STR_GROUP_RENAME_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_LIVERY_GROUP), SetFill(0, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_LIVERY_GROUP), SetDataTip(SPR_GROUP_LIVERY_TRAIN, STR_GROUP_LIVERY_TOOLTIP), - NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), EndContainer(), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_REPLACE_PROTECTION), SetFill(0, 1), + NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 0), EndContainer(), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_REPLACE_PROTECTION), SetDataTip(SPR_GROUP_REPLACE_OFF_TRAIN, STR_GROUP_REPLACE_PROTECTION_TOOLTIP), EndContainer(), EndContainer(), @@ -87,14 +86,14 @@ static const NWidgetPart _nested_group_widgets[] = { 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), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_AVAILABLE_VEHICLES), SetMinimalSize(106, 12), 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), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetResize(1, 0), EndContainer(), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_MANAGE_VEHICLES_DROPDOWN), SetMinimalSize(118, 12), 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), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_STOP_ALL), SetMinimalSize(12, 12), 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), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_START_ALL), SetMinimalSize(12, 12), SetDataTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), @@ -229,7 +228,7 @@ private: this->column_size[VGC_NUMBER] = GetStringBoundingBox(STR_GROUP_COUNT_WITH_SUBGROUP); this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_NUMBER].height); - this->tiny_step_height += WD_MATRIX_TOP; + this->tiny_step_height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; return WD_FRAMERECT_LEFT + 8 + this->column_size[VGC_FOLD].width + 2 + @@ -255,7 +254,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 + 1, right - WD_FRAMERECT_RIGHT, y + this->tiny_step_height - WD_FRAMERECT_BOTTOM - 1, _colour_gradient[COLOUR_GREY][7]); } if (g_id == NEW_GROUP) return; @@ -386,7 +385,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 = 4 * GetVehicleListHeight(this->vli.vtype, this->tiny_step_height); /* ... minus the buttons at the bottom ... */ uint max_icon_height = GetSpriteSize(this->GetWidget(WID_GL_CREATE_GROUP)->widget_data).height; @@ -429,11 +428,6 @@ public: *size = maxdim(*size, d); break; } - - case WID_GL_INFO: { - size->height = (FONT_HEIGHT_NORMAL * 3) + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - break; - } } } @@ -555,11 +549,11 @@ 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_INFO: { @@ -600,7 +594,7 @@ public: } case WID_GL_LIST_GROUP: { - int y1 = r.top + WD_FRAMERECT_TOP; + int y1 = r.top; int max = std::min(this->group_sb->GetPosition() + this->group_sb->GetCapacity(), this->groups.size()); for (int i = this->group_sb->GetPosition(); i < max; ++i) { const Group *g = this->groups[i];