Index: ps/trunk/binaries/data/mods/public/gui/common/OverlayCounterManager.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/common/OverlayCounterManager.js +++ ps/trunk/binaries/data/mods/public/gui/common/OverlayCounterManager.js @@ -14,7 +14,6 @@ this.lastTick = undefined; this.resizeHandlers = []; this.lastHeight = undefined; - this.initSize = this.dataCounter.size; for (let name of this.availableCounterNames()) { @@ -72,45 +71,32 @@ onTick() { - // Don't rebuild the caption every frame - let now = Date.now(); + // Don't rebuild the caption every frame. + const now = Date.now(); if (now < this.lastTick + this.Delay) return; this.lastTick = now; - let lineCount = 0; let txt = ""; for (let counter of this.enabledCounters) { - let newTxt = counter.get(); - if (!newTxt) - continue; - - ++lineCount; - txt += newTxt + "\n"; + const newTxt = counter.get(); + if (newTxt) + txt += newTxt + "\n"; } let height; - if (lineCount) + if (txt) { this.dataCounter.caption = txt; - // Just using the previous size for getting the size of the new text - // could lead to unneeded linebreaks. - // Therefore we set the overlay to the maximum size before reading the text size. - this.dataCounter.size = this.initSize; - let textSize = this.dataCounter.getTextSize(); - let size = this.dataCounter.size; - size.bottom = size.top + textSize.height; - size.left = size.right - textSize.width; - this.dataCounter.size = size; - height = textSize.height; + height = resizeGUIObjectToCaption(this.dataCounter, { "horizontal": "left", "vertical": "bottom" }, { "vertical": -2 }).height; } else height = 0; - this.dataCounter.hidden = !lineCount; + this.dataCounter.hidden = !txt; if (this.lastHeight != height) { Index: ps/trunk/binaries/data/mods/public/gui/common/functions_utility.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/common/functions_utility.js +++ ps/trunk/binaries/data/mods/public/gui/common/functions_utility.js @@ -222,25 +222,46 @@ /** * Change the width of a GUIObject to make the caption fits nicely. - * @param object - The GUIObject to consider. - * @param direction - Direction to change the side either "left" or "right". - * @param margin - Margin to be added to the width (can be negative). + * @param {Object} object - The GUIObject to consider. + * @param {Object} align - Directions to change the side either "left" or "right" for horizontal and "top" or "bottom" for vertical. + * @param {Object} margin - Margins to be added to the width and height (can be negative). */ -function resizeGUIObjectToCaption(object, align, margin = 0) +function resizeGUIObjectToCaption(object, align, margin = {}) { const objectSize = object.size; - const width = Engine.GetTextWidth(object.font, object.caption) + margin; - switch (align) + const textSize = Engine.GetTextSize(object.font, object.caption); + if (align.horizontal) { - case "right": - objectSize.right = object.size.left + width; - break; - case "left": - objectSize.left = object.size.right - width; - break; - default: + const width = textSize.width + 2 * object.buffer_zone + (margin.horizontal || 0); + switch (align.horizontal) + { + case "right": + objectSize.right = object.size.left + width; + break; + case "left": + objectSize.left = object.size.right - width; + break; + default: + } + } + + if (align.vertical) + { + const height = textSize.height + (margin.vertical || 0); + switch (align.vertical) + { + case "bottom": + objectSize.bottom = object.size.top + height; + break; + case "top": + objectSize.top = object.size.bottom - height; + break; + default: + } } + object.size = objectSize; + return objectSize; } /** Index: ps/trunk/binaries/data/mods/public/gui/session/chat/ChatAddressees.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/chat/ChatAddressees.js +++ ps/trunk/binaries/data/mods/public/gui/session/chat/ChatAddressees.js @@ -8,7 +8,7 @@ this.selectionChangeHandlers = []; this.chatAddresseeCaption = Engine.GetGUIObjectByName("chatAddresseeCaption"); - resizeGUIObjectToCaption(this.chatAddresseeCaption, "right", this.CaptionMargin); + resizeGUIObjectToCaption(this.chatAddresseeCaption, { "horizontal": "right" }); this.chatAddressee = Engine.GetGUIObjectByName("chatAddressee"); this.chatAddressee.onSelectionChange = this.onSelectionChange.bind(this); @@ -131,5 +131,4 @@ } ]; -ChatAddressees.prototype.CaptionMargin = 10; ChatAddressees.prototype.DropdownMargin = 5; Index: ps/trunk/binaries/data/mods/public/gui/session/chat/ChatHistory.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/chat/ChatHistory.js +++ ps/trunk/binaries/data/mods/public/gui/session/chat/ChatHistory.js @@ -14,7 +14,7 @@ this.selectionChangeHandlers = []; this.chatHistoryFilterCaption = Engine.GetGUIObjectByName("chatHistoryFilterCaption"); - resizeGUIObjectToCaption(this.chatHistoryFilterCaption, "right", this.CaptionMargin); + resizeGUIObjectToCaption(this.chatHistoryFilterCaption, { "horizontal": "right" }); this.chatHistoryFilter = Engine.GetGUIObjectByName("chatHistoryFilter"); let filters = prepareForDropdown(this.Filters.filter(chatFilter => !chatFilter.hidden)); @@ -140,5 +140,4 @@ } ]; -ChatHistory.prototype.CaptionMargin = 10; ChatHistory.prototype.FilterMargin = 5; Index: ps/trunk/binaries/data/mods/public/gui/session/chat/ChatInput.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/chat/ChatInput.js +++ ps/trunk/binaries/data/mods/public/gui/session/chat/ChatInput.js @@ -10,7 +10,7 @@ this.chatSubmittedHandlers = []; this.chatInputCaption = Engine.GetGUIObjectByName("chatInputCaption"); - resizeGUIObjectToCaption(this.chatInputCaption, "right", this.CaptionMargin); + resizeGUIObjectToCaption(this.chatInputCaption, { "horizontal": "right" }); this.chatInput = Engine.GetGUIObjectByName("chatInput"); this.chatInput.onPress = this.submitChatInput.bind(this); @@ -94,5 +94,4 @@ } } -ChatInput.prototype.CaptionMargin = 10; ChatInput.prototype.InputMargin = 5; Index: ps/trunk/source/graphics/Font.cpp =================================================================== --- ps/trunk/source/graphics/Font.cpp +++ ps/trunk/source/graphics/Font.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -63,6 +63,8 @@ width = 0; height = m_Height; + // Compute the width as the width of the longest line. + int lineWidth = 0; for (const wchar_t* c = string; *c != '\0'; c++) { const GlyphData* g = m_Glyphs.get(*c); @@ -71,6 +73,14 @@ g = m_Glyphs.get(0xFFFD); // Use the missing glyph symbol if (g) - width += g->xadvance; // Add the character's advance distance + lineWidth += g->xadvance; // Add the character's advance distance + + if (*c == L'\n') + { + height += m_LineSpacing; + width = std::max(width, lineWidth); + lineWidth = 0; + } } + width = std::max(width, lineWidth); } Index: ps/trunk/source/gui/SettingTypes/CGUIString.cpp =================================================================== --- ps/trunk/source/gui/SettingTypes/CGUIString.cpp +++ ps/trunk/source/gui/SettingTypes/CGUIString.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -206,18 +206,19 @@ } } - // Calculate the size of the font + // Calculate the size of the font. CSize2D size; int cx, cy; CFontMetrics font (TextCall.m_Font); font.CalculateStringSize(TextCall.m_String.c_str(), cx, cy); - // For anything other than the first line, the line spacing - // needs to be considered rather than just the height of the text - if (!FirstLine) - cy = font.GetLineSpacing(); - size.Width = (float)cx; - size.Height = (float)cy; + size.Width = static_cast(cx); + // For anything other than the first line, the line spacing + // needs to be considered rather than just the height of the text. + if (FirstLine) + size.Height = static_cast(font.GetHeight()); + else + size.Height = static_cast(font.GetLineSpacing()); // Append width, and make maximum height the height. Feedback.m_Size.Width += size.Width; Index: ps/trunk/source/ps/scripting/JSInterface_Main.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_Main.cpp +++ ps/trunk/source/ps/scripting/JSInterface_Main.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,6 +23,7 @@ #include "graphics/MapReader.h" #include "lib/sysdep/sysdep.h" #include "lib/utf8.h" +#include "maths/Size2D.h" #include "maths/MD5.h" #include "ps/CStrIntern.h" #include "ps/GUID.h" @@ -97,14 +98,19 @@ return g_frequencyFilter->StableFrequency(); } -int GetTextWidth(const std::string& fontName, const std::wstring& text) +CSize2D GetTextSize(const std::string& fontName, const std::wstring& text) { int width = 0; int height = 0; CStrIntern _fontName(fontName); CFontMetrics fontMetrics(_fontName); fontMetrics.CalculateStringSize(text.c_str(), width, height); - return width; + return CSize2D(width, height); +} + +int GetTextWidth(const std::string& fontName, const std::wstring& text) +{ + return GetTextSize(fontName, text).Width; } std::string CalculateMD5(const std::string& input) @@ -129,6 +135,7 @@ ScriptFunction::Register<&GetMatchID>(rq, "GetMatchID"); ScriptFunction::Register<&LoadMapSettings>(rq, "LoadMapSettings"); ScriptFunction::Register<&GetFps>(rq, "GetFPS"); + ScriptFunction::Register<&GetTextSize>(rq, "GetTextSize"); ScriptFunction::Register<&GetTextWidth>(rq, "GetTextWidth"); ScriptFunction::Register<&CalculateMD5>(rq, "CalculateMD5"); }