vanilla-wow-addons – Rev 1
?pathlinks?
--[[ 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