import "Turbine.UI";
import "Turbine.UI.Lotro";
-- Adds AutoSize() function to Turbine.UI.Label
-- It works for single or multiline strings.
-- Not yet tested with inline markup.
-- Adds AutoSize() function to Turbine.UI.Window and Turbine.UI.Lotro.Window.
-- Adds AutoSize() function to Turbine.UI.Control, to set the size according to the background image size.
-- Get font heights from enumeration strings
local FontHeight = {};
for key, value in pairs(Turbine.UI.Lotro.Font) do
FontHeight[value] = tonumber(string.match(key, "[0-9]+$", -3));
end
-- Override SetMultiLine() because the built-in IsMultiline() function doesn't work and we need to fix it
Turbine.UI.Label._SetMultiline = Turbine.UI.Label.SetMultiline;
function Turbine.UI.Label:SetMultiline(enable)
Turbine.UI.Label._SetMultiline(self, enable);
self.multiline = enable;
end
function Turbine.UI.Label:IsMultiline()
return ((self.multiline == true) or (self.multiline == nil));
end
function Turbine.UI.Label:AutoSize()
-- Save this to restore afterwards
local text = self:GetText();
local userScrollBar = self:GetHorizontalScrollBar();
self:SetHorizontalScrollBar(nil);
self:_SetMultiline(false);
-- Add extra width for the outline, if any
local outline = 0;
if (self:GetFontStyle() == Turbine.UI.FontStyle.Outline) then
outline = 1; -- to do: is this bigger for larger fonts?
end
-- We can set the height based on the selected font and the number of '\n' characters present
local lineHeight = FontHeight[self:GetFont()];
self:SetHeight(lineHeight + outline);
-- Make a temporary scrollbar whose visibility will indicate text width
local tempScrollBar = Turbine.UI.Lotro.ScrollBar();
tempScrollBar:SetParent(self);
self:SetHorizontalScrollBar(tempScrollBar);
-- Magic function call that is necessary to make the ScrollBar:IsVisible() function work
self:SetText(text);
local function autoSizeLine()
self:SetWidth(64);
-- Rapidly find lower and upper bounds for the possible widths.
local lower_bound, upper_bound = 0, 64;
local visible = tempScrollBar:IsVisible();
while (visible) do
--Puts("\"" .. tostring(self:GetText()) .. "\" is wider than " .. upper_bound);
lower_bound = upper_bound;
upper_bound = 2 * upper_bound;
self:SetWidth(upper_bound);
visible = tempScrollBar:IsVisible();
end
-- Binary search for the precise width. Fractions are OK; they are handled by the API.
local width, distance = self:GetWidth();
repeat
if (tempScrollBar:IsVisible()) then
--Puts("\"" .. tostring(self:GetText()) .. "\" is wider than " .. width);
lower_bound = width;
else
--Puts("\"" .. tostring(self:GetText()) .. "\" is narrower than " .. width);
upper_bound = width;
end
distance = upper_bound - lower_bound;
width = lower_bound + math.floor(0.5 + distance / 2);
self:SetWidth(width);
until (distance <= 1);
return width + outline;
end
if (not self:IsMultiline()) then
self:SetWidth(autoSizeLine());
else
-- If multiline, run once for each line and use the widest line to set the overall width.
local numLines, maxWidth, _ = 0, 0;
for line in string.gmatch(self:GetText(), "[^\n]+") do
numLines = numLines + 1;
self:SetText(line);
maxWidth = math.max(maxWidth, autoSizeLine());
end
maxWidth = maxWidth + lineHeight; -- fudge that seems necessary to account for phantom width of "\n" character
self:_SetMultiline(true);
self:SetSize(maxWidth, numLines * lineHeight + outline);
self:SetText(text);
end
tempScrollBar:SetParent(nil);
-- Restore user's scrollbar (if any)
self:SetHorizontalScrollBar(userScrollBar);
return self;
end
-- Override SetMultiLine() because the built-in IsMultiline() function doesn't work and we need to fix it
Turbine.UI.Lotro.CheckBox._SetMultiline = Turbine.UI.Lotro.CheckBox.SetMultiline;
function Turbine.UI.Lotro.CheckBox:SetMultiline(enable)
Turbine.UI.Lotro.CheckBox._SetMultiline(self, enable);
self.multiline = enable;
end
function Turbine.UI.Lotro.CheckBox:IsMultiline()
return ((self.multiline == true) or (self.multiline == nil));
end
function Turbine.UI.Lotro.CheckBox:AutoSize()
-- We will reuse the Turbine.UI.Label.AutoSize function (above), so we first
-- need to create a temporary Label and copy the relevant properties to it.
local label = Turbine.UI.Label();
label:SetMultiline(self:IsMultiline());
label:SetFont(self:GetFont());
label:SetFontStyle(self:GetFontStyle());
label:SetText(self:GetText());
label:AutoSize();
-- CheckBox will be the same size, but with the added size of the checkbox itself (16 x 16 pixels).
self:SetWidth(label:GetWidth() + 16);
self:SetHeight(math.max(16, label:GetHeight()));
end
-- Returns the coordinates (left, top, width, height) of a bounding box that contains all of the control's children.
local function GetBoundsOfChildren(control)
local xmin, ymin = control:GetSize();
local xmax, ymax = 0, 0;
local children = control:GetControls();
for c = 1, children:GetCount() do
local child = children:Get(c);
local left, top = child:GetPosition();
local width, height = child:GetSize();
xmin = math.min(xmin, left);
ymin = math.min(ymin, top);
xmax = math.max(xmax, left + width);
ymax = math.max(ymax, top + height);
end
return xmin, ymin, xmax - xmin, ymax - ymin;
end
-- Figures x-margin from the leftmost child control's position.
-- Figures y-margin from the topmost child control's position.
-- Sets the window width to the right of the rightmost child control, plus the x-margin.
-- Sets the window height to the bottom of the bottom-most child control, plus the y-margin.
function Turbine.UI.Window.AutoSize(self)
local left, top, width, height = GetBoundsOfChildren(self);
self:SetSize(left + width + left, top + height + top);
end
-- Lotro window has the title at the top, so for symmetry, we need to reduce the y-margin on the bottom.
function Turbine.UI.Lotro.Window.AutoSize(self)
Turbine.UI.Window.AutoSize(self);
self:SetHeight(self:GetHeight() - 13);
end
-- Function for determining text size by creating a temporary label
function _G.GetTextWidth(font, text)
local label = Turbine.UI.Label();
label:SetMultiline(false);
label:SetFont(font);
label:SetText(text);
label:AutoSize();
return label:GetWidth();
end
-- Automatically sizes a Control based on one of two methods:
-- If 'useChildControls' is false, it sizes the control to the native size of its background image.
-- If 'useChildControls' is true, it sizes the control to the minimum size that can contain all of its children.
function Turbine.UI.Control.AutoSize(self, useChildControls)
if (useChildControls) then
local left, top, width, height = GetBoundsOfChildren(self);
self:SetSize(left + width, top + height);
else
self:SetStretchMode(2); -- resize to image's native size
self:SetStretchMode(0);
end
end
function Turbine.UI.Lotro.Button.AutoSize(self)
local label = Turbine.UI.Label();
label:SetMultiline(false);
label:SetFont(self:GetFont() or Turbine.UI.Lotro.Font.TrajanPro14);
label:SetText(self:GetText());
label:AutoSize();
self:SetWidth(label:GetWidth() + 20);
end