vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
--[[ KLH Threatmeter KLHTM_Gui.lua

local version -> to be integrated into kenco files

Lukon Mod 2: The replacement for Gui.lua and Tables.lua. Controls the GUI 
for KLH ThreatMeter, along with KTM_Frame.xml, KTM_RaidGui.lua, 
KTM_SelfGui.lua, KTM_TitleGui.lua.

There is a single main frame, which shows either raid threat data 
(KTM_RaidGui.lua) or personal threat details (KTM_SelfGui.lua). Each of 
these two frames contains column headers, data rows and a bottom bar. 
Additionally there is a title bar frame (KTM_TitleGui). The GUI elements are
contained in a table "KLHTM_Gui", populated by the CreateGuiTable(). This 
also contains some properties not set in the XML file, such as some 
dimensions and colours.

The appearance of the GUI can be customised via the "KLHTM_GuiOptions" table.
This determines the visibility of command buttons and data columns, the way 
data is displayed in the main tables, and other settings. User access to
these settings is via the options gui (KTM_OptionsFrame.xml, 
KTM_OptionsGui.lua).

The visibility and some properties of the frame as a whole are kept in the
"state" table.

NB the indexes in the tables "gui", "options", and elsewhere shouldn't be
changed. They are assumed to match by various methods.
--]]

-- ken
local mod = klhtm
local me = { }
mod.gui = me

-- The minimum period, in seconds, between data table redrawing
local Min_Redraw_Period = 0.2;

-- When the table was last redrawn
local lastRedraw = 0;
KLHTM_LastRedraw = lastRedraw;

-- Set to true when a redraw has been requested but not yet performed
local needsRedraw = false;
KLHTM_NeedsRedraw = needsRedraw;

-- Contains settings describing the way raid and self data should displayed. 
-- Loaded from saved variables or initialised by _CreateDefaultOptions()
local options = {};
KLHTM_GuiOptions = options;

-- Contains window state information. Loaded from saved variables or 
-- initialised by _CreateDefaultState().
local state = {};
KLHTM_GuiState = state;

-- Contains references to the GUI components and some additional properties
-- not specified in the XML file. Initialised by _CreateGuiTable()
local gui = {};
KLHTM_Gui = gui;

-- true if initialisation (SetupGui) has finished, and rendering is possible
local isInitialised = false;
KLHTM_IsLoaded = false;

-- the maximum change in string width allowed by KLHTM_LocaliseStringWidth()
local Max_Localisation_Factor = 2;

-- frame scale constants
KLHTM_Scale = {["min"] = 0.6, ["max"] = 1.3, ["tick"] = 0.02, ["default"] = 1.0};

-- the current dimensions of the frame and subframes. These are filled by the various
-- UpdateXFrame and Redraw methods.
local sizes = { ["raid"] = {},          ["self"] = {},  ["but"] = {}, 
                                ["string"] = {},        ["title"] = {}, ["frame"] = {}, };
KLHTM_GuiSizes = sizes;

-- The heights of some sizes
KLHTM_GuiHeights = {["button"] = 15, ["string"] = 12, ["header"] = 14, ["data"] = 12};

-- The texture gradient colours used by the main frame and options frame's title bar
KLHTM_TitleBarColours = {
        -- purple
        ["raid"] = {["minR"] = 0.2, ["minG"] = 0.0, ["minB"] = 0.2, ["minA"] = 0.5,
                                ["maxR"] = 1.0, ["maxG"] = 0.0, ["maxB"] = 1.0, ["maxA"] = 0.5, },
        -- dark green
        ["self"] = {["minR"] = 0.0, ["minG"] = 0.2, ["minB"] = 0.0, ["minA"] = 0.5,
                                ["maxR"] = 0.0, ["maxG"] = 0.7, ["maxB"] = 0.0, ["maxA"] = 0.5, },
        -- blue
        ["gen"] =  {["minR"] = 0.0, ["minG"] = 0.2, ["minB"] = 0.2, ["minA"] = 0.5,
                                ["maxR"] = 0.0, ["maxG"] = 1.0, ["maxB"] = 1.0, ["maxA"] = 0.5, }, };
        
------------------------------------------------------------------------------
-- Prepares the GUI for use. Called after the Variables Loaded event is
-- received (see KLHTM_Frame <OnLoad>, <OnEvent>).
--
-- some patches to official KLHTM: (a) removed setupaftervariablesloaded
-- method, and its reference in ktmMain. (b) events now come from the update
-- frame. The main frame only sends the variables loaded event.
------------------------------------------------------------------------------

me.myevents = { "ADDON_LOADED" }

me.onevent = function()
        
        KLHTM_SetupGui()
        
end

me.onupdate = function()

        KLHTM_Redraw()

end

function KLHTM_SetupGui()
        
        if (isInitialised) then
                -- will this ever happen? who knows...
                return; 
        end
        
        KLHTM_LoadVariables();
        KLHTM_CreateGuiTable();
        KLHTM_SetupGuiComponents();
        
        -- apply state and options
        KLHTM_UpdateSelfFrame();
        KLHTM_UpdateRaidFrame();
        KLHTM_UpdateTitleButtons();
        KLHTM_UpdateTitleStrings();
        
        isInitialised = true;
        
        -- probably going to cause some dumb error...
        KLHTM_Redraw(true);
        
        KLHTM_UpdateFrame();
        KLHTM_SetGuiScale(options.scale);
        
        if (state.closed ~= true) then
                gui.frame:Show();
        end
end


------------------------------------------------------------------------------
-- Loads data from saved variables. If the required data is not found, default
-- settings are used instead.
------------------------------------------------------------------------------
function KLHTM_LoadVariables()
        
        if (KLHTM_SavedVariables == nil) then
                KLHTM_SavedVariables = {};
        end

        if (KLHTM_SavedVariables.gui) then
                
                if mod.out.checktrace("info", me, "savedvariables") then
                        mod.out.printtrace("Loading KTM saved variables");
                end
                
                -- nb byval copies to preserve external references to KLHTM_GuiState and
                -- KLHTM_GuiOptions. Todo: more robust format
                for index, value in KLHTM_SavedVariables.gui.state do
                        state[index] = value;
                end
                for index, value in KLHTM_SavedVariables.gui.options do
                        options[index] = value;
                end
                
                -- todo: better saved variables upgrading
                if (options.buttonVis.min.targ == nil) then
                        options.buttonVis.min.targ = false;
                        options.buttonVis.max.targ = true;
                end
                if (options.buttonVis.min.clear == nil) then
                        options.buttonVis.min.clear = false;
                        options.buttonVis.max.clear = false;
                end
        else
                if mod.out.checktrace("info", me, "savedvariables") then
                        mod.out.printtrace("Performing fresh install of KTM")
                end
                
                KLHTM_SetDefaultOptions();
                KLHTM_SetDefaultState();
        end
        
        KLHTM_SavedVariables.gui = {};
        KLHTM_SavedVariables.gui.version = mod.build;
        KLHTM_SavedVariables.gui.options = options;
        KLHTM_SavedVariables.gui.state = state;
end


------------------------------------------------------------------------------
-- Sets up the variable "KLHTM_Gui". It contains (a) references to the gui
-- components, (b) visibility data, (c) string widths, (d) some colours.
------------------------------------------------------------------------------
function KLHTM_CreateGuiTable()
        
        gui.frame = KLHTM_Frame;
        gui.topdiv = KLHTM_FrameTopDivider;
        gui.bottomdiv = KLHTM_FrameBottomDivider;
        
        KLHTM_CreateTitleTable();
        KLHTM_CreateRaidTable();
        KLHTM_CreateSelfTable();
        KLHTM_CreateOptionsTable();
end


------------------------------------------------------------------------------
-- Applies Gui component properties that are not specified in the XML.
------------------------------------------------------------------------------
function KLHTM_SetupGuiComponents()
        
        KLHTM_SetupTitleGui();
        KLHTM_SetupRaidGui();
        KLHTM_SetupSelfGui();
        KLHTM_SetupOptionsGui();
        
        -- frame
        gui.frame:RegisterForDrag("LeftButton");
        gui.frame:SetMovable(true);
        gui.frame:SetUserPlaced(true);
        gui.frame:SetBackdropColor(0.1, 0.1, 0.1);
        gui.frame:SetBackdropBorderColor(1, 1, 1);
end


------------------------------------------------------------------------------
-- Initialises the local variable "options". It contains settings describing
-- how the self and data windows and the title bar should be displayed.
------------------------------------------------------------------------------
function KLHTM_SetDefaultOptions()
        
        options.scale = KLHTM_Scale.default;
        
        KLHTM_SetDefaultRaidOptions();
        KLHTM_SetDefaultSelfOptions();
        KLHTM_SetDefaultTitleOptions();
end


------------------------------------------------------------------------------
-- Initialises the local variable "state", containing GUI display properties
------------------------------------------------------------------------------
function KLHTM_SetDefaultState()
        
        state.min = false;
        state.max = true;
        state.minmax = "max";
        
        state.raid = true;
        state.self = false;
        state.view = "raid";
        
        state.pinned = false;
        state.closed = false;
end


------------------------------------------------------------------------------
-- Changes the raid \ self view.
--
-- [newView] - either "self" or "raid"
------------------------------------------------------------------------------
function KLHTM_SetView(newView)
        
        if ((newView ~= "self") and (newView ~= "raid")) then
                if mod.out.checktrace("warning", me, "invalidargument") then
                        mod.out.printtrace(string.format("The argument '%s' to SetView is not recognised.", tostring(newView)))
                end
                return;
        end
        
        state.view = newView;
        state.raid = not state.raid;
        state.self = not state.self;
        
        KLHTM_Redraw(true);
        
        local col = KLHTM_TitleBarColours[state.view];  
        gui.title.back:SetGradientAlpha("VERTICAL", col.minR, col.minG, col.minB, col.minA, col.maxR, col.maxG, col.maxB, col.maxA);
        
        KLHTM_UpdateTitleButtons();
        KLHTM_UpdateTitleStrings();
        KLHTM_UpdateFrame();
end


------------------------------------------------------------------------------
-- Changes the minimised \ maximised state.
--
-- [newMinMax] - either "min" or "max"
------------------------------------------------------------------------------
function KLHTM_SetMinMax(newMinMax)
        
        if ((newMinMax ~= "min") and (newMinMax ~= "max")) then
                if mod.out.checktrace("warning", me, "invalidargument") then
                        mod.out.printtrace(string.format("The argument '%s' to SetMinMax is not recognised.", tostring(newMinMax)))
                end
                return;
        end
        
        state.minmax = newMinMax;
        state.min = not state.min;
        state.max = not state.max;
        
        KLHTM_Redraw(true);
        
        KLHTM_UpdateTitleButtons();
        KLHTM_UpdateTitleStrings();
        KLHTM_UpdateFrame();
end


------------------------------------------------------------------------------
-- Sets the frame visibility. Should this method even exist?
--
-- [newVisible] - set to true to show the frame
------------------------------------------------------------------------------
function KLHTM_SetVisible(newVisible)
        
        if ((newVisible ~= false) and (newVisible ~= true)) then
                if mod.out.checktrace("warning", me, "invalidargument") then
                        mod.out.printtrace(string.format("The argument to '%s' to SetVisible is not recognised.", tostring(newVisible)))
                end
        end
        
        state.closed = not newVisible;
        
        if (newVisible) then
                KLHTM_Redraw(true);
                gui.frame:Show();
        else
                gui.frame:Hide();
        end
end


------------------------------------------------------------------------------
-- Changes the global scale of the main frame.
--
-- [newScale] - a value between 0.5 and 1.2
------------------------------------------------------------------------------
function KLHTM_SetGuiScale(newScale)
        
        local argument = newScale
        newScale = tonumber(newScale);
        
        if (newScale == nil) then
                if mod.out.checktrace("warning", me, "invalidargument") then
                        mod.out.printtrace(string.format("The argument '%s' to SetGuiScale is not a number.", tostring(argument)))
                end
                return;
        end
        
        if ((newScale < KLHTM_Scale.min) or (newScale > KLHTM_Scale.max)) then
                if mod.out.checktrace("warning", me, "invalidargument") then
                        mod.out.printtrace(string.format("The argument '%s' to SetGuiScale is outside the valid bounds.", newScale))
                end
                return;
        end
        
        -- maintain the top-right corner when resizing
        local right = gui.frame:GetRight();
        local top = gui.frame:GetTop();
        
        gui.frame:SetScale(newScale);
        
        if ((top ~= nil) and (right ~= nil)) then
                top = top * options.scale / newScale;
                right = right * options.scale / newScale;
                gui.frame:ClearAllPoints();
                gui.frame:SetPoint("TOPRIGHT", UIParent, "BOTTOMLEFT", right, top);
        else
                -- should occur the first time the mod is loaded
                gui.frame:ClearAllPoints();
                gui.frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0);
        end
        
        options.scale = newScale;
end


------------------------------------------------------------------------------
-- Add an black outline to the specified FontString. This increases its 
-- legibility when viewed on a light background, eg the self view bars. It is
-- normally able to be specified via the XML, but this is not possible due to 
-- compatibility reasons with some localisations. The default minimim ouline is
-- very dark and overpowering, so the shadow's alpha is reduced (to 0, but there
-- seems to be a minimum value).
--
-- [fontstring] - a GUI FontString object
------------------------------------------------------------------------------
function KLHTM_AddOutline(fontstring)
        
        local path, height;
        path, height = fontstring:GetFont();
        
        fontstring:SetFont(path, height, "OUTLINE");
        fontstring:SetShadowColor(0,0,0,0.3);
end


------------------------------------------------------------------------------
-- Increases the space allocated to the specified string to match the localised
-- string width.
--
-- [stringData] - a table containing a [width] element and a [text] element.
-- the latter should be a FontString whose text has been set.
------------------------------------------------------------------------------
function KLHTM_LocaliseStringWidth(stringData)
        
        local width = math.ceil(stringData.text:GetStringWidth());
        
        if (width > stringData.width) then
                
                local newValue = math.min(width, stringData.width * Max_Localisation_Factor);
                
                if mod.out.checktrace("info", me, "resizing") then
                        mod.out.printtrace(string.format("Extending the width of %s from %s to %s.", stringData.frame:GetName(), stringData.width, newValue))
                end
                
                stringData.width = newValue;
        end
end

------------------------------------------------------------------------------
-- Repositions the frame in the center of the screen and shows it.
------------------------------------------------------------------------------
function KLHTM_ResetFrame()
        
        local scale = options.scale;
        
        gui.frame:SetScale(1);
        gui.frame:ClearAllPoints();
        gui.frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0);
        
        KLHTM_SetGuiScale(scale);
        KLHTM_SetVisible(true);
end

------------------------------------------------------------------------------
-- Updates the visibility of the data tables, and recalculates the frame bounds.
-- Should be called whenever the sizes of the subframes changes. ie:
--
-- a) view changes
-- b) minmax changes
-- c) column visibility changes
-- d) command button visibility changes
--
-- This method uses the widths calculated by the other methods such as 
-- Update...Table(), UpdateTitleButtons() and UpdateTitleStrings() which
-- should be called prior to this method when the affected gui components are 
-- changed.
--
-- When the frame is maximised, its width is determined by the visible data frame.
-- If it is smaller than the title bar's preferred width, then overlap can
-- occur between the title bar strings and buttons. In this case the default
-- string is replaced by the short version.
------------------------------------------------------------------------------
function KLHTM_UpdateFrame()
        
        -- raid frame
        if (state.max and state.raid) then
                sizes.frame.x = sizes.raid.x;
                gui.raid.frame:Show();
                -- height is set by the redraw method
        else
                gui.raid.frame:Hide();
        end
        
        -- self frame
        if (state.max and state.self) then
                sizes.frame.x = sizes.self.x;
                gui.self.frame:Show();
                -- height is set by the redraw method
        else
                gui.self.frame:Hide();
        end
        
        -- title frame
        sizes.title.x = sizes.string.x + sizes.but.x;
        sizes.title.y = math.max(sizes.string.y, sizes.but.y);
        gui.title.frame:SetHeight(sizes.title.y);
        
        if (state.min) then
                sizes.frame.y = sizes.title.y;
                sizes.frame.x = sizes.title.x;
                gui.frame:SetHeight(sizes.frame.y + 10); -- 10?
        end
        
        -- maintain the top-right corner when resizing
        local right = gui.frame:GetRight();
        local top = gui.frame:GetTop();
        
        gui.frame:SetWidth(sizes.frame.x + 12); -- 12: 5 inset + 1 gap * 2 for each side.
        
        if ((top ~= nil) and (right ~= nil)) then
                gui.frame:ClearAllPoints();
                gui.frame:SetPoint("TOPRIGHT", UIParent, "BOTTOMLEFT", right, top);
        else
                -- harmless, occurs once at startup
        end
        
        -- check for lack of horizontal space in the title bar
        if (state.max) then
                if (sizes.title.x > sizes.frame.x) then
                        gui.title.string.short.frame:SetWidth(gui.title.string.short.width);
                        gui.title.string.short.frame:Show();
                        gui.title.string.long.frame:SetWidth(0.1);
                        gui.title.string.long.frame:Hide();
                else
                        gui.title.string.short.frame:SetWidth(0.1);
                        gui.title.string.short.frame:Hide();
                        gui.title.string.long.frame:SetWidth(gui.title.string.long.width);
                        gui.title.string.long.frame:Show();
                end
                -- sometimes the anchors aren't reapplied. Not sure if this is needed now
                -- that the raid and self titles have been replaced
                gui.title.string.short.frame:GetLeft();
                gui.title.string.long.frame:GetLeft();
        end
        
end


------------------------------------------------------------------------------
-- Notifies the GUI that the frame should be updated. The frame will be redrawn
-- within Min_Redraw_Period seconds. Should be called by data-receiving modules,
-- eg networking and combat. 
--
-- [view] - set to "raid" or "self" to prevent redraw if it does not match
--                      [state.view]. Ignored if nil.
------------------------------------------------------------------------------
function KLHTM_RequestRedraw(view)
        
        if ((view ~= nil) and (view ~= state.view)) then
                return;
        end
        if (state.closed) then
                needsRedraw = false;
                return;
        end
        
        needsRedraw = true;
end


KLHTM_RedrawDebug = {0,0,0,0,0,0,0,0,0,0};
_redrawindex = 1;
------------------------------------------------------------------------------
-- Redraws the data table contents, if needed. The redraw will only occur if:
--
-- a) [needsRedraw] is true. This is set by data-receiving modules via
-- KLHTM_RequestRedraw()
-- b) The last update was at least Min_Redraw_Period seconds ago
-- c) the frame is visible and initialised
--
-- This method is automatically called via KLHTM_GuiOnUpdate in order to track
-- processor usage. It should not be called externally; use KLHTM_RequestRedraw()
-- instead.
--
-- [forceRedraw] - if true, bypasses conditions (a) and (b) above. Use this 
-- before updating GUI element visibility to prevent flickering.
------------------------------------------------------------------------------
function KLHTM_Redraw(forceRedraw)
        
        if (not isInitialised) then
                return;
        end
        
        if (forceRedraw ~= true) then
                if ((GetTime() - lastRedraw) < Min_Redraw_Period) then
                        return;
                end
                if (needsRedraw == false) then
                        return;
                end
        end
        
        -- some debugging to check frequency of redraws
        KLHTM_RedrawDebug[_redrawindex] = GetTime() - lastRedraw;
        _redrawindex = _redrawindex + 1;
        if (_redrawindex == 11) then
                _redrawindex = 1;
        end
        
        lastRedraw = GetTime();
        needsRedraw = false;
        
        -- draw stuff... ? NO!
        if (state.raid) then
                KLHTM_DrawRaidFrame();
        else
                KLHTM_DrawSelfFrame();
        end
end

------------------------------------------------------------------------------
-- Abbreviates large number with the "k" suffix. Works on positive and negative
-- numbers. Non-numbers are returned as is.
------------------------------------------------------------------------------
function KLHTM_Abbreviate(input)
        
        if (type(input) ~= "number") then
                return input;
        end
        
        local isNegative = false;
        if (input < 0) then
                isNegative = true;
                input = -1 * input;
        end
        
        local answer;
        if (input < 10000) then
                answer = input;
        elseif (input < 100000) then
                answer = math.floor(input / 100 + 0.5) / 10;
                if (math.mod(answer, 1) == 0) then
                        answer = answer .. ".0";
                end
                answer = answer .. "k";
        else
                answer = math.floor(input / 1000 + 0.5) .. "k";
        end
        
        if (isNegative) then
                answer = "-" .. answer;
        end
        return answer;
end


------------------------------------------------------------------------------
-- Frame dragging
------------------------------------------------------------------------------
function KLHTM_Frame_OnDragStart()
        if (gui.frame:IsMovable() and (state.pinned == false)) then 
                gui.frame:StartMoving();
        end
end
function KLHTM_Frame_OnDragStop()
        gui.frame:StopMovingOrSizing();
end