lotrointerface.com
Search Downloads

LoTROInterface SVN Reminders

[/] [trunk/] [Thurallor/] [Common/] [Utils/] [AutoSizing_8.lua] - Rev 8

Compare with Previous | Blame | View Log

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

Compare with Previous | Blame


All times are GMT -5. The time now is 12:16 PM.


Our Network
EQInterface | EQ2Interface | Minion | WoWInterface | ESOUI | LoTROInterface | MMOUI | Swtorui