/trunk
-- Handler for factions. |
local PXP = ProgressionXP -- save finger-leather |
PXP.TYPE_FACTION = 'faction' -- Reputation bar |
local repstatemax = { |
36000, -- 1=hated |
3000, -- 2=hostile |
3000, -- 3=unfriendly |
3000, -- 4=neutral |
6000, -- 5=friendly |
12000, -- 6=honored |
21000, -- 7=revered |
999 -- 8=exalted |
} |
-- Looks up a faction by id. If it doesn't exist, creates it. |
local function LookupFaction(faction, skipsort) |
local id = "rep_" .. faction |
if not PXP.modes[id] then -- Reputation not found. Initialize it. |
PXP.Mode:New(id, { |
name = faction, |
type = PXP.TYPE_FACTION, |
state = PXP.STATE_NOTFOUND, |
submenu = 'Faction' |
}) |
if not skipsort then PXP.Menu.Resort() end |
if PXP.modes['special_rep_ALL'] then |
for bar, _ in pairs(PXP.modes['special_rep_ALL'].watchers.secondary) do |
bar:AddMode(PXP.modes[id], true) |
end |
end |
end |
return PXP.modes[id] |
end |
-- Add/subtract reputation |
function PXP.ModifyFactionRep(faction, amount) |
local id = "rep_" .. faction |
local m = LookupFaction(faction) |
assert(m.type == PXP.TYPE_FACTION, "Mode " .. id .. " is not a faction?") |
m.gain = amount |
m.value = m.value + amount |
if m.state < 1 then return id end -- Unknown faction state, do nothing else. |
-- Handle negative values (aka faction standing went down) |
while m.state >= 1 and m.value < 0 do |
m.state = m.state - 1 |
m.value = m.value - repstatemax[m.state] |
end |
-- And overmax values (faction standing went up) |
while m.state <= 8 and m.value > repstatemax[m.state] do |
m.value = m.value - repstatemax[m.state] |
m.state = m.state + 1 |
end |
-- Caps. |
if m.value < 0 then -- Really, really, REALLY hated. |
m.value = 0 |
elseif m.value > repstatemax[m.state] then -- Such a nice guy |
m.value = repstatemax[m.state] |
end |
return m |
end |
for i, _ in pairs(repstatemax) do |
PXP.translates.states[i] = getglobal("FACTION_STANDING_LABEL" .. i) |
end |
-- Load reputation data. |
function PXP.ReloadFactionData() |
-- Factions |
local factionname, description, standingID, barMin, barMax, barValue, atWarWith, canToggleAtWar, isHeader, isCollapsed, hasRep, isWatched, isChild |
local id, t |
for i = 1, GetNumFactions() do |
factionname, description, standingId, barMin, barMax, barValue, atWarWith, canToggleAtWar, isHeader, isCollapsed, hasRep, isWatched, isChild = GetFactionInfo(i) |
if not isHeader or (isHeader and hasRep) then |
id = 'rep_' .. factionname |
t = LookupFaction(factionname, true) |
t.rawValue = barValue |
t.state = standingId |
t.value = barValue - barMin |
t.max = barMax - barMin |
end |
end |
PXP.Menu.Resort() |
end |
PXP.initializeCallbacks['faction'] = PXP.ReloadFactionData |
PXP.profileLoadCallbacks['faction'] = function() |
if not PXP.profile.defaultStyles[PXP.TYPE_FACTION] then PXP.profile.defaultStyles[PXP.TYPE_FACTION] = {} end |
local ds = PXP.profile.defaultStyles[PXP.TYPE_FACTION] |
if not ds[PXP.STATE_NORMAL] then |
ds[PXP.STATE_NORMAL] = { |
bg = PXP.Color(0.25, 0.25, 0.25), |
fill = PXP.Color(0.50, 0.50, 0.50), |
bonus = PXP.Color(1.00, 0.00, 0.00), |
text = PXP.Color(1.00, 1.00, 0.00), |
} |
end |
for state, color in pairs(FACTION_BAR_COLORS) do |
local b = PXP.Color(color.r, color.g, color.b) |
if not ds[state] then |
ds[state] = { |
text = PXP.Color(1.0, 1.0, 1.0), |
fill = PXP.MultiplyColor(b, 0.9), |
bg = PXP.MultiplyColor(b, 0.4), |
alternate = { |
fill = PXP.Color(color.r, color.g, color.b, 0.8), |
bg = PXP.Color(color.r, color.g, color.b, 0.3), |
} |
} |
end |
end |
end |
PXP.Mode:New('special_rep_ALL', { |
name = "All Factions", |
virtual = true, |
submenu = 'Faction', |
priority = -1, |
NotifyAdd = function(self, bar) |
for modeId, mode in pairs(PXP.modes) do |
if mode.type == PXP.TYPE_FACTION then bar:AddMode(mode, true) end |
end |
end, |
NotifyRemove = function(self, bar) |
for modeId, mode in pairs(PXP.modes) do |
if mode.type == PXP.TYPE_FACTION then bar:RemoveMode(mode, true) end |
end |
end, |
}) |
if not PXP.events["COMBAT_TEXT_UPDATE"] then PXP.events["COMBAT_TEXT_UPDATE"] = {} end |
PXP.events["COMBAT_TEXT_UPDATE"]['faction'] = function(event, type, faction, gain, ...) |
if type ~= 'FACTION' then return end |
local m = PXP.ModifyFactionRep(faction, gain) |
m:Notify() |
end |
-- PXP.Bar represents one set of frames and other support functions for displaying one XP/faction/etc bar. |
local alignments = { "LEFT", "CENTER", "RIGHT" } |
local PXP = ProgressionXP |
PXP.Bar = {} |
function PXP.Bar.SetBackgroundColor(self, color) |
self.backgroundTexture:SetTexture(color.r, color.g, color.b, color.a) |
end |
function PXP.Bar.SetFillColor(self, color) |
self.fillTexture:SetTexture(color.r, color.g, color.b, color.a) |
end |
function PXP.Bar.SetBonusColor(self, color) |
self.bonusTexture:SetTexture(color.r, color.g, color.b, color.a) |
end |
function PXP.Bar.SetTextColor(self, color) |
for _, align in pairs(alignments) do |
self.text[align]:SetTextColor(color.r, color.g, color.b, color.a) |
end |
end |
function PXP.Bar.IsVisible(self) |
return self.baseFrame:IsShown() |
end |
function PXP.Bar.New(self, o) |
o = o or {} |
setmetatable(o, self) |
self.__index = self |
-- Create the frames. |
o.baseFrame = CreateFrame("StatusBar") -- This is the background frame, and shows rested XP. |
o.overlayFrame = CreateFrame("StatusBar", nil, o.baseFrame) -- This is the foreground frame with a see-thru background, and shows base XP or rep. |
o.overlayFrame:SetAllPoints(o.baseFrame) |
o.baseFrame:EnableMouse(true) |
o.baseFrame:SetClampedToScreen(true) |
o.baseFrame:SetMovable(true) |
o.baseFrame:SetResizable(true) |
o.backgroundTexture = o.baseFrame:CreateTexture(nil, 'BACKGROUND') |
o.backgroundTexture:SetAllPoints(o.baseFrame) |
o.fillTexture = o.overlayFrame:CreateTexture(nil, "ARTWORK") |
o.fillTexture:SetTexture(1,1,1,1) |
o.fillTexture:SetAllPoints(o.overlayFrame) |
o.overlayFrame:SetStatusBarTexture(o.fillTexture) |
o.bonusTexture = o.baseFrame:CreateTexture(nil, "ARTWORK") |
o.bonusTexture:SetTexture(1,1,1,1) |
o.bonusTexture:SetAllPoints(o.baseFrame) |
o.baseFrame:SetStatusBarTexture(o.bonusTexture) |
o.baseFrame.PXPParent = o |
o.visible = false |
-- New way of locking things |
o.visLocks = 1 --defaults to 1, group attachment removes one lock, group removal adds one. |
o.text = {} |
for _, align in pairs(alignments) do |
local text |
text = o.overlayFrame:CreateFontString(nil, "OVERLAY") |
text:SetFontObject("TextStatusBarText") |
text:SetTextColor(1.0, 1.0, 1.0, 1.0) |
--text:SetShadowColor(0.0, 0.0, 0.0, 1.0) -- black |
--text:SetShadowOffset(-1.0, -1.0) |
--text:SetText(align) |
text:SetJustifyH(align) |
text:SetJustifyV("MIDDLE") |
text:SetAllPoints(o.overlayFrame) |
o.text[align] = text |
end |
o.textPatterns = { |
["LEFT"] = "%n", |
["CENTER"] = "%c/%x %B (%P%)", |
["RIGHT"] = "%g %s", |
} |
o.modes = {} -- Modes we are subscribed to. |
o.currentMode = nil -- Current mode we are displaying |
o.autoUpdate = false -- Whether we change modes upon receiving change event or not |
o.lastState = nil -- Last state we were in. Set to nil when changing modes to force updates |
o.lastUpdate = GetTime() -- When was the last time we were updated by a mode change event? |
o.currentActivityLevel = PXP.ACTIVITY_ACTIVE -- Current activity level. |
o.canIdle = true -- Can we enter the IDLE state? |
o.canInactive = false -- Can we enter the INACTIVE state? |
o.fadeStartTime = nil -- When did we start the current alpha fade? |
o.fadeStartAlpha = nil -- What was the starting alpha for the current alpha fade? |
o.hasMouse = false -- Is the mouse currently over our frame? Used for determining the correct activity level |
o:SetMax(1) -- for now |
o:SetValue(0) -- for now |
o.baseFrame:SetScript("OnEnter", PXP.Frame.OnEnter) |
o.baseFrame:SetScript("OnLeave", PXP.Frame.OnLeave) |
o.baseFrame:SetScript("OnMouseDown", PXP.Frame.OnMouseDown) |
o.baseFrame:SetScript("OnMouseUp", PXP.Frame.OnMouseUp) |
o.isAlternateStyle = false |
o.prev = nil |
o.next = nil |
o.parent = nil |
o:SetMode(nil) |
o:Update() |
return o |
end |
function PXP.Bar.VisLock(self) |
if self.visLocks == 0 then |
self.baseFrame:SetScript("OnUpdate", nil) |
if self.baseFrame:IsShown() then |
self.baseFrame:SetAlpha(1.0) |
else |
self.baseFrame:SetAlpha(0.0) |
end |
end |
self.visLocks = self.visLocks + 1 |
return true |
end |
function PXP.Bar.VisUnlock(self) |
assert(self.visLocks > 0) |
self.visLocks = self.visLocks - 1 |
if self.visLocks > 0 then return true end |
self:SetActivityLevel(self.currentActivityLevel, true) -- Force refresh of the current activity level. |
self.baseFrame:SetScript("OnUpdate", PXP.Frame.OnUpdate) |
return false |
end |
function PXP.Bar.Clone(self, bar) |
bar = PXP.Bar:New(bar) |
bar.canIdle = self.canIdle |
bar.canInactive = self.canInactive |
bar.autoUpdate = self.autoUpdate |
for _, align in pairs(alignments) do |
bar.textPatterns[align] = self.textPatterns[align] |
end |
for mode, data in pairs(self.modes) do |
if data.explicit then |
bar:AddMode(mode) |
end |
end |
bar:SetMode(self.currentMode) |
return bar |
end |
function PXP.Bar.SetIsAlternateStyle(self, v) |
self.isAlternateStyle = v |
self:UpdateStyle() |
end |
function PXP.Bar.ToggleAlternateStyle(self) |
self.isAlternateStyle = not self.isAlternateStyle |
self:UpdateStyle() |
end |
-- Add a new mode we're interested in, and set it as active if it's the first mode. |
function PXP.Bar.AddMode(self, mode, isInherit) |
assert(mode) |
mode.watchers.secondary[self] = true |
if not self.modes[mode] then self.modes[mode] = { prev = nil, next = nil, explicit = false, inherit = 0 } end |
local n = self.modes[mode] |
if isInherit then |
n.inherit = n.inherit + 1 |
else |
n.explicit = true |
end |
if not mode.virtual and not mode.next then |
local last, first |
if self.modes then |
for k, v in pairs(self.modes) do |
if v.next then |
if not first or k.id < first then first = k end |
if not last or k.id > last then last = k end |
if k.id < mode.id and (n.prev == nil or k.id > n.prev) then n.prev = k end |
if k.id > modeId and (n.next == nil or k.id < n.next) then n.next = k end |
end |
end |
end |
if not first then |
n.prev = mode |
n.next = mode |
else |
if not n.prev then n.prev = last end |
if not n.next then n.next = first end |
self.modes[n.prev].next = mode |
self.modes[n.next].prev = mode |
end |
end |
if not mode.virtual and self.currentMode == nil then |
self:SetMode(mode) |
end |
mode:NotifyAdd(self, isInherit) |
return true |
end |
-- Remove a mode from our interest list, and make another mode active. |
function PXP.Bar.RemoveMode(self, mode, isInherit) |
assert(mode) |
if not self.modes then |
return nil |
end |
if not self.modes[mode] then |
return nil |
end |
local n = self.modes[mode] |
if isInherit then |
assert(n.inherit > 0, "Too many removes on an inherited node!") |
n.inherit = n.inherit - 1 |
else |
assert(n.explicit, "Mode is not explicitly added.") |
n.explicit = false |
end |
if n.inherit == 0 and not n.explicit then |
if not mode.virtual then |
self.modes[n.prev].next = n.next |
self.modes[n.next].prev = n.prev |
if self.currentMode == modeId then |
if n.next ~= modeId then |
self:SetMode(n.next) |
else |
self:SetMode(nil) |
end |
end |
end |
self.modes[modeId] = nil |
end |
mode.watchers.primary[self] = nil |
mode.watchers.secondary[self] = nil |
mode:NotifyRemove(self, isInherit) |
end |
-- Changes our currently-active mode |
function PXP.Bar.SetMode(self, mode) |
if mode then |
assert(self.modes[mode], "New mode " .. mode.id .. " not assigned.") |
assert(not mode.virtual, "Mode " .. mode.id .. " is virtual.") |
end |
if self.currentMode then |
self.currentMode.watchers.primary[self] = nil |
end |
self.lastState = nil |
self.currentMode = mode |
self:Update() |
if mode then |
mode.watchers.primary[self] = true |
end |
end |
-- Toggle automatic mode switching |
function PXP.Bar.SetautoUpdate(self, v) |
if v then v = true else v = nil end |
self.autoUpdate = v |
local modeId, mode |
return v |
end |
-- Maximum bar value.. Minimum is always 0. |
function PXP.Bar.SetMax(self, v) |
self.baseFrame:SetMinMaxValues(0, v) |
self.overlayFrame:SetMinMaxValues(0, v) |
self:SetValue(0) |
self:SetBonus(0) |
end |
-- Current (and possibly bonus aka rested) bar value |
function PXP.Bar.SetValue(self, v, bonus) |
self.overlayFrame:SetValue(v) |
if bonus ~= nil then self:SetBonus(bonus) end |
end |
-- Bonus bar value. |
function PXP.Bar.SetBonus(self, v) |
self.baseFrame:SetValue(v) |
end |
function PXP.Bar.UpdateStyle(self) |
if not self.currentMode then |
self:SetTextColor({r = 1.0, g = 0.2, b = 0.2, a = 1.0}) |
self:SetBackgroundColor({r = 0.3, g = 0.0, b = 0.0, a = 1.0}) |
self:SetFillColor({r = 0.5, g = 0.0, b = 0.0, a = 1.0}) |
return |
end |
self:SetTextColor(self.currentMode:GetStyle('text')) |
self:SetBackgroundColor(self.currentMode:GetStyle('bg')) |
self:SetFillColor(self.currentMode:GetStyle('fill')) |
self:SetBonusColor(self.currentMode:GetStyle('bonus')) |
end |
-- Signals an update to the currently watched mode. |
function PXP.Bar.Update(self) |
if not self.currentMode then |
self:UpdateStyle() |
self:SetMax(1) |
self:SetValue(0.5) |
self.text["LEFT"]:SetText("***") |
self.text["RIGHT"]:SetText("***") |
self.text["CENTER"]:SetText("NOT CONFIGURED") |
self:SetActivityLevel(PXP.ACTIVITY_ACTIVE) |
return |
end |
local mode = self.currentMode |
assert(mode, "Current mode not found!") |
self.lastUpdate = GetTime() |
if self.lastState ~= mode.state then |
self.lastState = mode.state |
self:UpdateStyle() |
end |
self:SetMax(mode.max) |
self:SetValue(mode.value, mode.bonus) |
local replacements = { |
["%n"] = mode.name, -- Name |
["%a"] = mode:GetAbbv(), -- Abbv |
["%c"] = mode.value, -- value (C)urrent amount) |
["%v"] = mode.value, -- value |
["%r"] = mode.max - mode.value, -- R)emaining |
["%x"] = mode.max, -- Max |
["%b"] = mode.bonus, -- Bonus w/ different formatting (defined later) |
["%B"] = '', -- Bonus w/ different formatting (defined later) |
["%g"] = '', -- Amount of last gain |
["%p"] = '', -- x% |
["%P"] = '', -- x.y% |
["%s"] = PXP.translates.states[mode.state] |
} |
if not replacements["%s"] then replacements["%s"] = "S:" .. mode.state end |
if mode.state == 0 then |
replacements["%S"] = '' |
else |
replacements["%S"] = replacements["%s"] |
end |
if mode.max then |
replacements["%p"] = string.format("%d", 100 * mode.value/mode.max) |
replacements["%P"] = string.format("%0.1f", 100 * mode.value/mode.max) |
end |
if mode.gain ~= nil and mode.gain ~= 0 then |
if mode.gain > 0 then |
replacements["%g"] = '+' .. mode.gain |
else |
replacements["%g"] = mode.gain |
end |
end |
if mode.bonus ~= nil and mode.bonus ~= 0 then |
if mode.bonus > 0 then |
replacements["%B"] = '+' .. mode.bonus |
else |
replacements["%B"] = mode.bonus |
end |
end |
for _, align in pairs(alignments) do |
self.text[align]:SetText(string.gsub(self.textPatterns[align], "%%%a", replacements)) |
end |
self:SetActivityLevel(PXP.ACTIVITY_ACTIVE) |
end |
function PXP.Bar.Hide(self) |
if not self:IsVisible() then return nil end |
self.visible = false |
self.baseFrame:Hide() |
self:Reposition() |
if self.parent then self.parent:ToggleAlternateStyle(self) end |
end |
function PXP.Bar.Show(self) |
if self:IsVisible() then return nil end |
self.visible = true |
self.baseFrame:Show() |
self:Reposition() |
if self.parent then self.parent:ToggleAlternateStyle(self) end |
end |
function PXP.Bar.SetActivityLevel(self, newlevel, refresh) |
if newlevel == PXP.ACTIVITY_INACTIVE and not self.canInactive then newlevel = PXP.ACTIVITY_IDLE end |
if newlevel == PXP.ACTIVITY_IDLE and not self.canIdle then newlevel = PXP.ACTIVITY_ACTIVE end |
if self.currentActivityLevel == newlevel and not refresh then return end -- No need to change. |
self.currentActivityLevel = newlevel |
if self.visLocks > 0 then return false end |
local settings = PXP.profile.activity[newlevel] |
assert(settings, "No settings for activity level " .. newlevel) |
-- Start a fade transition if there's a nonzero fade time and the alpha isn't already correct. |
if settings.fade and settings.alpha ~= self.baseFrame:GetAlpha() then |
self.fadeStartTime = GetTime() |
self.fadeStartAlpha = self.baseFrame:GetAlpha() |
else |
-- Otherwise, clear any fade state information and set the alpha immediately. |
self.fadeStartTime = nil |
self.fadeStartAlpha = nil |
self.baseFrame:SetAlpha(settings.alpha) |
if newlevel == PXP.ACTIVITY_INACTIVE then |
self:Hide() |
else |
self:Show() |
end |
end |
end |
function PXP.Bar.Reposition(self) |
if not self.parent then |
self.baseFrame:ClearAllPoints() |
return nil |
end |
local b = self.baseFrame |
local g = self.parent.growDirectionInfo[self.parent.growDirection] |
b:ClearAllPoints() |
b:SetParent(self.parent.frame) |
if self:IsVisible() then |
b:SetWidth(self.parent.width) |
b:SetHeight(self.parent.height) |
else |
b:SetWidth(self.parent.width * g.multiplyHiddenWidth) |
b:SetHeight(self.parent.height * g.multiplyHiddenHeight) |
end |
if not self.prev then |
b:SetPoint(g.attachAfter, self.parent.frame, g.attachAfter) |
return true |
end |
b:SetPoint(g.attachAfter, self.prev.baseFrame, g.attachBefore) |
return true |
end |
function PXP.Bar.NextMode(self) |
if not self.currentMode then return end |
self:SetMode(self.modes[self.currentMode].next) |
end |
function PXP.Bar.PreviousMode(self) |
if not self.currentMode then return end |
self:SetMode(self.modes[self.currentMode].prev) |
end |
PXP.Frame = {} |
function PXP.Frame.OnEnter(self, ...) |
self.PXPParent.hasMouse = true |
self.PXPParent:SetActivityLevel(PXP.ACTIVITY_MOUSEOVER) |
end |
function PXP.Frame.OnLeave(self, ...) |
self.PXPParent.hasMouse = false |
--self.PXPParent:SetActivityLevel(PXP.ACTIVITY_ACTIVE) |
PXP.Frame.OnUpdate(self) -- Don't know if 'self' is really truly self. Let's not risk it. |
end |
function PXP.Frame.OnUpdate(self, ...) |
local p = self.PXPParent |
local t = GetTime() |
-- Are we fading? |
if p.fadeStartTime then |
local settings = PXP.profile.activity[p.currentActivityLevel] |
-- Let's not divide by zero |
if settings.fade <= 0 then |
self:SetAlpha(settings.alpha) |
p.fadeStartTime = nil |
p.fadeStartAlpha = nil |
else |
-- How far % through the fade |
local pct = (t - p.fadeStartTime) / settings.fade |
-- if pct >= 100, then end the fade |
if pct >= 1 then |
self:SetAlpha(settings.alpha) |
p.fadeStartTime = nil |
p.fadeStartAlpha = nil |
-- If we're inactive, hide us |
if p.currentActivityLevel == PXP.ACTIVITY_INACTIVE then |
p:Hide() |
end |
else -- Otherwise, Will It Blend?! |
self:SetAlpha(((1.0 - pct) * p.fadeStartAlpha) + (pct * settings.alpha)) |
end |
end |
end |
-- Do we need to change activity levels? |
if not p.hasMouse then |
if p.canInactive == true and t > p.lastUpdate + PXP.profile.activity[PXP.ACTIVITY_INACTIVE].wait then |
p:SetActivityLevel(PXP.ACTIVITY_INACTIVE) |
elseif p.canIdle == true and t > p.lastUpdate + PXP.profile.activity[PXP.ACTIVITY_IDLE].wait then |
p:SetActivityLevel(PXP.ACTIVITY_IDLE) |
end |
end |
end |
function PXP.Frame.OnMouseUp(self, button) |
if button == "LeftButton" and self.PXPParent.parent then |
self.PXPParent.parent:StopMovingOrSizing() |
end |
end |
function PXP.Frame.OnMouseDown(self, button) |
if button == "LeftButton" then |
if IsControlKeyDown() and self.PXPParent.parent then |
self.PXPParent.parent:StartSizing() |
elseif IsAltKeyDown() and self.PXPParent.parent then |
self.PXPParent.parent:StartMoving() |
elseif IsShiftKeyDown() then |
self.PXPParent:PreviousMode() |
else |
self.PXPParent:NextMode() |
end |
return |
end |
if button == "RightButton" then |
PXP.Menu.ForBar(self.PXPParent) |
end |
end |
local PXP = ProgressionXP -- save finger-leather |
PXP.EventFrame = CreateFrame('Frame', "ProgressionEventsFrame") |
for eventid, handlers in pairs(PXP.events) do |
PXP.EventFrame:RegisterEvent(eventid) |
end |
PXP.EventFrame:SetScript('OnEvent', function(frame, event, ...) |
assert(PXP.events[event], "I don't know what to do with this event!") |
for _, func in pairs(PXP.events[event]) do func(event, ...) end |
end) |
local PXP = ProgressionXP |
local TR = PXP.translates |
PXP.Menu = {} |
PXP.Menu.SortData = {} |
local function menusorter(a,b) |
-- Same submenu level? |
if a.submenu or b.submenu then |
if not a.submenu then return true end |
if not b.submenu then return false end |
if a.submenu < b.submenu then return true end |
if b.submenu > a.submenu then return false end |
end |
-- Check priority level |
local av = a.priority or 0 |
local bv = b.priority or 0 |
if av < bv then return true end |
if av > bv then return false end |
-- Check name. |
if a.name < b.name then return true end |
return false |
end |
function PXP.Menu.Resort() |
PXP.Menu.SortData = {} |
-- Build menu structure |
for _, mode in pairs(PXP.modes) do |
table.insert(PXP.Menu.SortData, mode) |
end |
-- Sort it. FUN!(?) |
table.sort(PXP.Menu.SortData, menusorter) |
end |
PXP.Menu.Frame = CreateFrame("Frame", "ProgressionXPMenuFrame", UIParent, "UIDropDownMenuTemplate"); |
function PXP.Menu.ActionShow(self, bar, mode) |
CloseDropDownMenus() |
bar:SetMode(mode) |
end |
function PXP.Menu.ActionAddRemove(self, bar, mode, checked) |
CloseDropDownMenus() |
if checked then |
bar:RemoveMode(mode) |
else |
bar:AddMode(mode) |
end |
end |
function PXP.Menu.ActionAddRemoveAll(self, bar, isAdd, checked) |
CloseDropDownMenus() |
if isAdd then |
for _, mode in pairs(PXP.modes) do |
bar:AddMode(mode) |
end |
return |
end |
for mode, data in pairs(bar.modes) do |
if data.explicit then |
bar:RemoveMode(mode) |
end |
end |
end |
function PXP.Menu.ActionDeleteBar(self, bar) |
CloseDropDownMenus() |
bar.parent:Remove(bar) |
end |
function PXP.Menu.ActionCreateBar(self, base, clone) |
CloseDropDownMenus() |
local bar |
if clone then |
bar = base:Clone() |
else |
bar = PXP.Bar:New() |
end |
base.parent:Insert(bar, base.next) |
bar:Show() |
bar:Update() |
end |
function PXP.Menu.ActionMoveBar(self, barToMove, moveBefore) |
CloseDropDownMenus() |
barToMove.parent:Move(barToMove, moveBefore) |
end |
local MenuSep = { text = '', isTitle = true, } |
function PXP.Menu.ForBar(bar) |
assert(bar) |
local scale = UIParent:GetEffectiveScale() |
local x, y = GetCursorPosition() |
local rootMenu = {} |
if bar.currentMode then |
assert(PXP.modes[bar.currentMode]) |
table.insert(rootMenu, {text = PXP.modes[bar.currentMode].name, isTitle = true}) |
else |
table.insert(rootMenu, {text = TR.NOT_CONFIGURED, isTitle = true}) |
end |
local showMenu = { |
text = TR.SHOW, |
menuList = {}, |
hasArrow = true, |
} |
if not bar.currentMode then showMenu.disabled = true end |
table.insert(rootMenu, showMenu) |
local arMenu = { |
text = TR.ADD_REMOVE, |
menuList = {}, |
hasArrow = true, |
} |
table.insert(rootMenu, arMenu) |
local subMenus = {} |
local arItem, showItem |
for menuidx, mode in ipairs(PXP.Menu.SortData) do |
arItem = { |
text = mode.name, |
arg1 = bar, |
arg2 = mode, |
checked = nil, |
func = PXP.Menu.ActionAddRemove |
} |
if mode.submenu then |
if not subMenus[mode.submenu] then |
subMenus[mode.submenu] = { |
text = mode.submenu, |
hasArrow = true, |
menuList = {}, |
} |
table.insert(arMenu.menuList, subMenus[mode.submenu]) |
end |
table.insert(subMenus[mode.submenu].menuList, arItem) |
else |
table.insert(arMenu.menuList, arItem) |
end |
if bar.modes[mode] then |
if bar.modes[mode].explicit then arItem.checked = true end |
if not mode.virtual then -- Add to the 'Show' menu, if it's not virtual. |
showItem = { |
text = mode.name, |
arg1 = bar, |
arg2 = mode, |
func = PXP.Menu.ActionShow |
} |
if mode == bar.currentMode then showItem.checked = true end |
table.insert(showMenu.menuList, showItem) |
end |
end |
end |
table.insert(arMenu.menuList, MenuSep) |
table.insert(arMenu.menuList, { |
text = TR.ADD_ALL, |
func = PXP.Menu.ActionAddRemoveAll, |
arg1 = bar, |
arg2 = true, |
}) |
table.insert(arMenu.menuList, { |
text = TR.REMOVE_ALL, |
func = PXP.Menu.ActionAddRemoveAll, |
arg1 = bar, |
arg2 = false, |
}) |
table.insert(rootMenu, MenuSep) |
local item |
item = { |
text = TR.DELETE_BAR, |
func = PXP.Menu.ActionDeleteBar, |
arg1 = bar |
} |
if not bar.next and not bar.prev then item.disabled = true end -- is the only bar, don't let it be deleted |
table.insert(rootMenu, item) |
table.insert(rootMenu, { |
text = TR.CREATE_BAR, |
func = PXP.Menu.ActionCreateBar, |
arg1 = bar, arg2 = false |
}) |
table.insert(rootMenu, { |
text = TR.CLONE_BAR, |
func = PXP.Menu.ActionCreateBar, |
arg1 = bar, arg2 = true |
}) |
table.insert(rootMenu, MenuSep) |
item = { |
text = string.format(TR.MOVE, PXP.Group.growDirectionInfo[bar.parent.growDirection].nextDirection), |
func = PXP.Menu.ActionMoveBar, |
arg1 = bar.next, arg2 = bar |
} |
if not bar.next then item.disabled = true end |
table.insert(rootMenu, item) |
item = { |
text = string.format(TR.MOVE, PXP.Group.growDirectionInfo[bar.parent.growDirection].previousDirection), |
func = PXP.Menu.ActionMoveBar, |
arg1 = bar, arg2 = bar.prev, |
} |
if not bar.prev then item.disabled = true end |
table.insert(rootMenu, item) |
table.insert(rootMenu, MenuSep) |
table.insert(rootMenu, { |
text = TR.AUTOUPDATE, |
tooltipText = TR.AUTOUPDATE_TT, |
func = function(...) bar.parent:SetForceVisible(not bar.parent.forceVisible) end, |
checked = bar.parent.forceVisible, |
}) |
table.insert(rootMenu, MenuSep) |
table.insert(rootMenu, { |
text = string.format(TR.CANIDLE, PXP.profile.activity[PXP.ACTIVITY_IDLE].wait), |
tooltipText = string.format(TR.CANIDLE_TT, PXP.profile.activity[PXP.ACTIVITY_IDLE].wait), |
func = function(...) CloseDropDownMenus(); bar.canIdle = not bar.canIdle end, |
checked = bar.canIdle, |
}) |
table.insert(rootMenu, { |
text = string.format(TR.CANINACTIVE, PXP.profile.activity[PXP.ACTIVITY_INACTIVE].wait), |
tooltipText = string.format(TR.CANINACTIVE_TT, PXP.profile.activity[PXP.ACTIVITY_INACTIVE].wait), |
func = function(...) CloseDropDownMenus(); bar.canInactive = not bar.canInactive end, |
checked = bar.canInactive, |
}) |
table.insert(rootMenu, { |
text = TR.AUTOUPDATE, |
tooltipText = TR.AUTOUPDATE_TT, |
func = function(...) CloseDropDownMenus(); bar.autoSwitchModes = not bar.autoSwitchModes end, |
checked = bar.autoSwitchModes, |
}) |
EasyMenu(rootMenu, PXP.Menu.Frame, UIParent, x/scale, y/scale, "MENU", 10) |
end |
local PXP = ProgressionXP |
PXP.Mode = { |
gain = 0, |
value = 0, |
max= 1, |
type = nil, |
name = 'NAME ME', |
watchers = { primary={}, secondary={} }, |
state = 0, |
} |
function PXP.Mode.Notify(self) |
local handledPrimary = nil |
for bar, _ in pairs(self.watchers.primary) do |
handledPrimary = true |
bar:Update() |
end |
if handledPrimary then return true end |
local oldestbar = nil |
-- No bar currently set to this mode would handle it. |
-- Find the oldest bar (based on lastupdate time) that is set to this mode. |
for bar, _ in pairs(self.watchers.secondary) do |
if bar.autoUpdate then |
if not oldestbar or bar.lastUpdate < oldestbar.lastUpdate then |
oldestbar = bar |
end |
end |
end |
if oldestbar then |
oldestbar:SetMode(self) |
return true |
end |
return false |
end |
function PXP.Mode.New(self, id, o) |
o = o or {} |
setmetatable(o, self) |
self.__index = self |
o.id = id |
PXP.modes[id] = o |
if not o.gain then o.gain = 0 end |
if not o.value then o.value = 0 end |
if not o.max then o.max= 1 end |
if not o.state then o.state = 0 end |
if not o.watchers then o.watchers = { primary={}, secondary={} } end |
if not o.style then o.style = {} end |
if not o.altstyle then o.altstyle = {} end |
return o |
end |
function PXP.Mode.NotifyAdd(self, bar, isInherit) |
end |
function PXP.Mode.NotifyRemove(self, bar, isInherit) |
end |
function PXP.Mode.GetStyle(self, attr, usealt) |
assert(PXP.profile.defaultStyles[self.type], "No default style set up for this type") |
local d = PXP.profile.defaultStyles[self.type] |
local da = d.alternate |
local c = PXP.profile.customStyles[self.id] |
local ca = c and c.alternate |
local rv = |
(usealt and ca and ( |
(ca[self.state] and ca[self.state][attr]) |
or (ca[0] and ca[0][attr]) |
)) or (c and ( |
(c[self.state] and c[self.state][attr]) |
or (c[0] and c[0][attr]) |
)) or (usealt and da and ( |
(da[self.state] and da[self.state][attr]) |
or (da[0] and da[0][attr]) |
)) or (d and ( |
(d[self.state] and d[self.state][attr]) |
or (d[0] and d[0][attr]) |
)) |
assert(rv or "Attribute value not found") |
return rv |
end |
function PXP.Mode.GetAbbv(self, noFallback) |
if noFallback then |
return PXP.profile.abbv[self.id] or self.abbv |
end |
return PXP.profile.abbv[self.id] or self.abbv or self.name |
end |
-- Handler for XP |
local PXP = ProgressionXP -- save finger-leather |
PXP.TYPE_XP = "xp" -- XP bar |
PXP.Mode:New('xp', { |
name = "Experience", |
abbv = "XP", |
type = PXP.TYPE_XP, |
}) |
-- Refreshes the current XP mode, possibly with an XP gain. |
local function UpdateXP(...) |
local gain = nil |
local t = PXP.modes.xp |
local oldxp = t.value |
local oldmax = t.max |
local oldlevel = t.level |
t.value = UnitXP("player") |
t.max = UnitXPMax("player") |
t.level = UnitLevel("player") |
t.bonus = GetXPExhaustion() |
if gain == nil then gain = PXP.GetGain(oldxp, oldmax, oldlevel, t.value, t.level) end |
t.gain = gain |
if t.level >= MAX_PLAYER_LEVEL then |
t.state = PXP.STATE_CAPPED |
elseif t.bonus ~= nil then |
t.state = PXP.STATE_RESTED |
else |
t.state = PXP.STATE_NORMAL |
end |
t:Notify() |
end |
PXP.profileLoadCallbacks['xp'] = function() |
if not PXP.profile.defaultStyles[PXP.TYPE_XP] then |
PXP.profile.defaultStyles[PXP.TYPE_XP] = { |
[PXP.STATE_NORMAL] = { |
bg = PXP.Color(0.20, 0.00, 0.20), |
fill = PXP.Color(0.50, 0.00, 0.50), |
bonus = PXP.Color(0.25, 0.25, 1.00), |
text = PXP.Color(1.00, 1.00, 1.00), |
}, |
[PXP.STATE_RESTED] = { |
text = PXP.Color(0.25, 1.00, 0.25), |
}, |
[PXP.STATE_CAPPED] = { |
text = PXP.Color(1.00, 1.00, 0.00), |
}, |
} |
end |
end |
PXP.initializeCallbacks['xp'] = UpdateXP |
if not PXP.events["PLAYER_XP_UPDATE"] then PXP.events["PLAYER_XP_UPDATE"] = {} end |
PXP.events["PLAYER_XP_UPDATE"]['xp'] = UpdateXP |
PXP.Menu.Resort() |
ProgressionXP = {} |
local PXP = ProgressionXP -- save finger-leather |
-- Constants |
-- Current 'activity' level |
PXP.ACTIVITY_MOUSEOVER = 3 |
PXP.ACTIVITY_ACTIVE = 2 |
PXP.ACTIVITY_IDLE = 1 |
PXP.ACTIVITY_INACTIVE = 0 |
-- Progress states |
PXP.STATE_NORMAL = 0 |
PXP.STATE_RESTED = -1 |
PXP.STATE_NOPET = -2 -- No pet |
PXP.STATE_TRAINABLE = -3 -- tradeskills |
PXP.STATE_NOTFOUND = -4 -- Selected item was not found |
PXP.STATE_CAPPED = -5 |
function PXP.Color(r,g,b,a) |
if a == nil then a = 1.0 end |
return {r=r,g=g,b=b,a=a} |
end |
function PXP.MultiplyColor(color, mult) |
return {r=color.r*mult, g=color.g*mult, b=color.b*mult, a=color.a} |
end |
function PXP.DeepTableCopy(from, to) |
to = to or {} |
for k,v in pairs(from) do |
if type(v) == 'table' then v = PXP.DeepTableCopy(v) end |
to[k] = v |
end |
end |
PXP.modes = {} |
PXP.initializeCallbacks = {} |
PXP.profileLoadCallbacks = {} |
PXP.events = {} |
PXP.groups = {} |
PXP.profileName = nil |
PXP.profile = nil |
PXP.translates = {} |
function PXP.ResetProfile(profileId) |
profileId = profileId or 'default' |
if not PXP.globalData.profiles or #PXP.globalData.profiles == 0 then PXP.globalData.profiles = {} end |
PXP.globalData.profiles[profileId] = { |
groups = { |
{ |
width = 512, height = 16, |
originY = 0.5, originX= 0.5, |
growDirection = "up", |
bars = { |
{ |
modes = { "xp" }, |
canIdle = true, canInactive = false, autoUpdate = false, |
}, |
{ |
modes = { "special_rep_ALL" }, |
canIdle = true, canInactive = false, autoUpdate = true, |
}, |
}, |
} |
}, |
activity = { |
[PXP.ACTIVITY_MOUSEOVER] = { alpha = 1.0, fade = 0.5, }, |
[PXP.ACTIVITY_ACTIVE] = { alpha = 0.9, fade = 0.1, }, |
[PXP.ACTIVITY_IDLE] = { alpha = 0.6, fade = 1.0, wait = 10.0, }, |
[PXP.ACTIVITY_INACTIVE] = { alpha = 0.0, fade = 5.0, wait = 60.0, }, |
}, |
abbv = {}, |
defaultStyles = {}, |
customStyles = {}, |
} |
end |
function PXP.LoadProfile(profile) |
assert(PXP.globalData.profiles[profile], "Profile not found") |
for group, _ in pairs(PXP.groups) do group:Delete() end |
PXP.profileName = profile |
PXP.profile = PXP.globalData.profiles[profile] |
local p = PXP.profile |
local group, bar |
for _, groupSettings in pairs(PXP.profile.groups) do |
group = PXP.Group:New() |
group:SetOrigin(groupSettings.originX, groupSettings.originY) |
group.width = groupSettings.width |
group.height = groupSettings.height |
for _, barSettings in pairs(groupSettings.bars) do |
bar = group:Insert() |
bar.canIdle = barSettings.canIdle |
bar.canInactive = barSettings.canInactive |
bar.autoUpdate = barSettings.autoUpdate |
for _, modeId in pairs(barSettings.modes) do |
if not PXP.modes[modeId] then |
if PXP.globalData.modeCache[modeId] then |
PXP.Mode:New(modeId, PXP.globalData.modeCache[modeId]) |
PXP.modes[modeId].state = PXP.STATE_NOTFOUND |
end |
end |
if PXP.modes[modeId] then |
bar:AddMode(PXP.modes[modeId]) |
if modeId == barSettings.currentMode then bar:SetMode(PXP.modes[modeId]) end |
end |
end |
end |
end |
for modename, initproc in pairs(PXP.profileLoadCallbacks) do initproc() end |
end |
function PXP.SaveProfile(profile) |
profile = profile or PXP.profileName |
if not PXP.globalData.profiles[profile] then PXP.globalData.profiles[profile] = {} end |
local p = PXP.globalData.profiles[profile] |
p.groups = {} |
local groupSettings, barSettings |
local bar |
for group, _ in pairs(PXP.groups) do |
groupSettings = {} |
table.insert(p.groups, groupSettings) |
groupSettings.originX , groupSettings.originY = group:GetOrigin() |
groupSettings.width = group.width |
groupSettings.height = group.height |
groupSettings.growDirection = group.growDirection |
bar = group.firstbar |
while bar do |
barSettings = {} |
table.insert(groupSettings.bars, barSettings) |
barSettings.canIdle = bar.canIdle |
barSettings.canInactive = bar.canInactive |
barSettings.autoUpdate = bar.autoUpdate |
if bar.currentMode then |
barSettings.currentMode = bar.currentMode.id |
else |
barSettings.currentMode = nil |
end |
barSettings.modes = {} |
for modeId, modeData in pairs(bar.modes) do |
if modeData.explicit then |
table.insert(barSettings.modes, modeId) |
if not PXP.globalData.modeCache[modeId] then |
PXP.globalData.modeCache[modeId] = { |
name = PXP.modes[modeId].name, |
type = PXP.modes[modeId].type, |
} |
end |
end |
end |
bar = bar.next |
end |
end |
if profile ~= PXP.profileName then -- We don't need to do this if this is the current profile, because we've already done it. |
profile.abbv = PXP.DeepTableCopy(PXP.profile.abbv) |
profile.activity = PXP.DeepTableCopy(PXP.profile.activity) |
profile.defaultStyles = PXP.DeepTableCopy(PXP.profile.defaultStyles) |
profile.customStyles = PXP.DeepTableCopy(PXP.profile.customStyles) |
end |
end |
function PXP.Initialize() |
-- Deal with saved variables. |
if not ProgressionGlobalData then ProgressionGlobalData = {} end |
PXP.globalData = ProgressionGlobalData |
if not PXP.globalData.modeCache then PXP.globalData.modeCache = {} end |
if not PXP.globalData.profiles then PXP.globalData.profiles = {} end |
if not PXP.globalData.profiles.default then PXP.ResetProfile('default') end |
if not ProgressionCharacterData then ProgressionCharacterData = {} end |
PXP.characterData = ProgressionCharacterData |
if not PXP.characterData.profile or not PXP.globalData.profiles[PXP.characterData.profile] then |
PXP.characterData.profile = 'default' |
end |
-- Call mode initializers. |
for modename, initproc in pairs(PXP.initializeCallbacks) do initproc() end |
-- Load a profile |
PXP.LoadProfile(PXP.characterData.profile) |
-- Resort menus, in case they haven't been yet for some reason |
PXP.Menu.Resort() |
end |
-- Helper function for XP/PetXP handlers. |
function PXP.GetGain(oldxp, oldmax, oldlevel, newxp, newlevel) |
if oldxp == nil or oldmax == nil or oldlevel == nil then |
return 0 |
end |
if oldlevel == newlevel then |
return newxp - oldxp |
end |
return newxp + oldmax - oldlevel |
end |
if not PXP.events["PLAYER_LOGIN"] then PXP.events["PLAYER_LOGIN"] = {} end |
PXP.events["PLAYER_LOGIN"]['core'] = function(...) |
PXP.Initialize() |
end |
-- Defines a group of PXP.Bars, settings that are common to them, etc. |
local PXP = ProgressionXP -- save finger-leather |
local TR = PXP.translates |
PXP.Group = { |
growDirectionInfo = { |
up = { |
attachBefore = "TOPLEFT", |
attachAfter = "BOTTOMLEFT", |
multiplyHiddenWidth = 1, |
multiplyHiddenHeight = 0, |
previousDirection = TR.DIRECTION_DOWN, |
nextDirection = TR.DIRECTION_UP, |
}, |
down = { |
attachBefore = "BOTTOMLEFT", |
attachAfter = "TOPLEFT", |
multiplyHiddenWidth = 1, |
multiplyHiddenHeight = 0, |
previousDirection = TR.DIRECTION_UP, |
nextDirection = TR.DIRECTION_DOWN, |
}, |
left = { |
attachBefore = "TOPLEFT", |
attachAfter = "TOPRIGHT", |
multiplyHiddenWidth = 0, |
multiplyHiddenHeight = 1, |
previousDirection = TR.DIRECTION_RIGHT, |
nextDirection = TR.DIRECTION_LEFT, |
}, |
right = { |
attachBefore = "TOPRIGHT", |
attachAfter = "TOPLEFT", |
multiplyHiddenWidth = 0, |
multiplyHiddenHeight = 1, |
previousDirection = TR.DIRECTION_LEFT, |
nextDirection = TR.DIRECTION_RIGHT, |
}, |
} |
} |
function PXP.Group.New(self, obj, frameId) |
if not obj then obj = {} end |
setmetatable(obj, self) |
self.__index = self |
obj.bars = {} |
obj.firstbar = nil |
obj.lastbar = nil |
obj.growDirection = 'up' |
obj.frame = CreateFrame('Frame', frameId) |
obj.width = 512 |
obj.height = 16 |
obj.frame:SetWidth(obj.width) |
obj.frame:SetHeight(obj.height) |
obj:SetOrigin(0.5, 0.5) |
obj.frame.PXPParent = obj |
obj.frame:SetMovable(true) |
obj.frame:SetResizable(true) |
obj.frame:SetMinResize(64,4) |
obj.isMoving = false |
obj.isSizing = false |
obj.visLocks = 0 |
obj.forceVisible = false |
return obj |
end |
function PXP.Group.SetOrigin(self, x, y) |
assert(x and y) |
self.frame:ClearAllPoints() |
self.frame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", x * UIParent:GetWidth(), y * UIParent:GetHeight()) |
end |
function PXP.Group.GetOrigin(self) |
return self.frame:GetLeft() / UIParent:GetWidth(), self.frame:GetBottom() / UIParent:GetHeight() |
end |
function PXP.Group.Link(self, obj, before) |
if not before then |
if self.lastbar then |
self.lastbar.next = obj |
obj.prev = self.lastbar |
obj:SetIsAlternateStyle(not self.lastbar.isAlternateStyle) |
if(not obj:IsVisible()) then obj:ToggleAlternateStyle() end |
else |
obj:SetIsAlternateStyle(not obj:IsVisible()) -- is the first ever object |
self.firstbar = obj |
end |
self.lastbar = obj |
obj:Reposition() |
return obj |
end |
assert(self.bars[before], "Cannot insert before this object. 'Before' object was not found or does not belong to me.") |
obj.next = before |
obj.prev = before.prev |
if before.prev then before.prev.next = obj end |
before.prev = obj |
if before == self.firstbar then self.firstbar = obj end |
self:ToggleAlternateStyle(obj.next) |
obj:Reposition() |
obj.next:Reposition() |
end |
function PXP.Group.Insert(self, obj, before) |
if not obj then |
obj = PXP.Bar:New() |
end |
assert(not obj.parent, "Object already inserted elsewhere.") |
obj.parent = self |
self.bars[obj] = true |
obj.visLocks = obj.visLocks + self.visLocks |
self:Link(obj, before) |
obj:Show() |
obj:VisUnlock() |
return obj |
end |
function PXP.Group.Unlink(self, obj) |
if obj:IsVisible() and obj.next then |
self:ToggleAlternateStyle(obj.next) |
end |
if obj.prev then obj.prev.next = obj.next end |
if obj.next then |
obj.next.prev = obj.prev |
obj.next:Reposition() |
end |
if obj == self.firstbar then self.firstbar = obj.next end |
if obj == self.lastbar then self.lastbar = obj.prev end |
obj.prev = nil |
obj.next = nil |
obj:Reposition() |
end |
function PXP.Group.Remove(self, obj) |
assert(self.bars[obj], "Cannot remove this object. Object not found or does not belong to me.") |
self:Unlink(obj) |
self.bars[obj] = nil |
obj.parent = nil |
obj:Hide() |
obj:VisLock() |
end |
function PXP.Group.Move(self, obj, moveBefore) |
assert(obj, "No object") |
assert(obj.parent == self, "Object not parented to me") |
assert(not moveBefore or moveBefore.parent == self, "Movebefore object not parented to me") |
self:Unlink(obj) |
self:Link(obj, moveBefore) |
end |
function PXP.Group.ToggleAlternateStyle(self, obj) |
return self:CallRecursive(obj, 'ToggleAlternateStyle') |
end |
function PXP.Group.Reposition(self) |
return self:CallRecursive(nil, 'Reposition') |
end |
function PXP.Group.SetGrowDirection(self, direction) |
assert(self.growDirectionInfo[direction], "Invalid direction") |
self.growDirection = direction |
self:Reposition() |
end |
function PXP.Group.StopMovingOrSizing(self) |
if self.isMoving then self:StopMoving() end |
if self.isSizing then self:StopSizing() end |
end |
function PXP.Group.StartMoving(self) |
self:StopMovingOrSizing() |
self:VisLock() |
self.isMoving = true |
self.frame:StartMoving() |
end |
function PXP.Group.StopMoving(self) |
if not self.isMoving then return end |
self.isMoving = false |
self.frame:StopMovingOrSizing() |
self:VisUnlock() |
end |
function PXP.Group.StopSizing(self) |
if not self.isSizing then return end |
self.frame:StopMovingOrSizing() |
self.isSizing = false |
self:VisUnlock() |
end |
function PXP.Group.StartSizing(self) |
if not self.lastbar then return end -- Needed for calculations |
local numVisibleBars = 0 |
for b, _ in pairs(self.bars) do |
if b:IsVisible() then numVisibleBars = numVisibleBars + 1 end |
end |
if numVisibleBars == 0 then return end -- Can't divide by zero later. |
self:StopMovingOrSizing() |
self:VisLock() |
self.isSizing = true |
local f = self.frame |
local ff = self.firstbar.baseFrame |
local lf = self.lastbar.baseFrame |
local left = min(ff:GetLeft(), lf:GetLeft()) |
local bottom = min(ff:GetBottom(), lf:GetBottom()) |
local top = max(ff:GetTop(), lf:GetTop()) |
local right = max(ff:GetRight(), lf:GetRight()) |
f:ClearAllPoints() |
f:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) |
f:SetWidth(right-left) |
f:SetHeight(top-bottom) |
local g = self.growDirectionInfo[self.growDirection] |
local divideWidthBy = (1*g.multiplyHiddenWidth) + ((1-g.multiplyHiddenWidth)*numVisibleBars) |
local divideHeightBy = (1*g.multiplyHiddenHeight) + ((1-g.multiplyHiddenHeight)*numVisibleBars) |
f:SetScript("OnSizeChanged", function(_, width, height) |
self.width = width / divideWidthBy |
self.height = height / divideHeightBy |
self:CallRecursive(nil, 'Reposition') |
end) |
f:StartSizing() |
end |
function PXP.Group.VisLock(self) |
self.visLocks = self.visLocks + 1 |
self:CallRecursive(nil, 'VisLock') |
end |
function PXP.Group.VisUnlock(self) |
assert(self.visLocks > 0) |
self.visLocks = self.visLocks - 1 |
self:CallRecursive(nil, 'VisUnlock') |
end |
function PXP.Group.SetForceVisible(self, forceVisible) |
if forceVisible == self.forceVisible then return nil end |
self.forceVisible = forceVisible |
if forceVisible then |
self:CallRecursive(nil, "Show") |
self:VisLock() |
else |
self:VisUnlock() |
end |
end |
-- Helper function |
function PXP.Group.CallRecursive(self, bar, func, ...) |
if not bar then bar = self.firstbar end |
while bar do |
assert(bar[func], "Function " .. func .. " does not exist") |
bar[func](bar, ...) |
bar = bar.next |
end |
end |
## Interface: 30000 |
## Title: Progression |
## Notes: Experience, reputation and tradeskill bars with intelligence. |
## Author: Dewin |
## X-Credits: Dewin |
## SavedVariables: ProgressionGlobalData |
## SavedVariablesPerCharacter: ProgressionCharacterData |
## Dependencies: |
## Version: 30000.1 |
## OptionalDeps: |
## X-Embeds: |
## X-Category: |
## X-Website: |
## X-Email: |
base.lua |
localization.enUS.lua |
mode.lua |
menu.lua |
xp.lua |
petxp.lua |
faction.lua |
bar.lua |
group.lua |
events.lua |
# main.lua |
# Progression.lua |
-- Handler for Pet XP |
local PXP = ProgressionXP -- save finger-leather |
PXP.TYPE_PETXP = 'petxp' -- Pet XP bar |
PXP.Mode:New('petxp', { |
name = "Pet Experience", |
abbv = "PetXP", |
type = PXP.TYPE_PETXP, |
}) |
-- Refreshes the current pet XP handler, possibly with an XP gain. |
local function UpdatePetXP(...) |
local gain = nil |
local t = PXP.modes.petxp |
local oldxp = t.value |
local oldmax = t.max |
local oldlevel = t.level |
t.level = UnitLevel("pet") |
local oldxp = t.value |
local oldmax = t.max |
local curXP, maxXP = GetPetExperience(); |
if curXP == nil or not t.level or t.level == 0 or maxXP == 0 then |
t.state = PXP.STATE_NOPET |
t.gain = 0 |
t.value = 0 |
t.max = 1 |
else |
t.value = curXP |
t.max = maxXP |
if t.level < UnitLevel("player") then |
t.state = PXP.STATE_NORMAL |
else |
t.state = PXP.STATE_CAPPED |
end |
if gain == nil then gain = PXP.GetGain(oldxp, oldmax, oldlevel, t.value, t.level) end |
t.gain = gain |
end |
t:Notify() |
end |
PXP.profileLoadCallbacks['petxp'] = function() |
assert(PXP) |
assert(PXP.profile) |
assert(PXP.profile.defaultStyles) |
if not PXP.profile.defaultStyles[PXP.TYPE_PETXP] then |
PXP.profile.defaultStyles[PXP.TYPE_PETXP] = { |
[PXP.STATE_NORMAL] = { |
bg = PXP.Color(0.00, 0.30, 0.30), |
fill = PXP.Color(0.00, 0.60, 0.60), |
bonus = PXP.Color(1.00, 0.00, 0.00), |
text = PXP.Color(1.00, 1.00, 1.00), |
}, |
[PXP.STATE_NOPET] = { |
bg = PXP.Color(0.25, 0.25, 0.25), |
fill = PXP.Color(0.50, 0.50, 0.50), |
bonus = PXP.Color(1.00, 0.00, 0.00), |
text = PXP.Color(1.00, 0.10, 0.10), |
}, |
[PXP.STATE_CAPPED] = { |
text = PXP.Color(1.00, 1.00, 0.00) |
} |
} |
end |
end |
PXP.initializeCallbacks['petxp'] = UpdatePetXP |
if not PXP.events["UNIT_PET_EXPERIENCE"] then PXP.events["UNIT_PET_EXPERIENCE"] = {} end |
PXP.events["UNIT_PET_EXPERIENCE"]['petxp'] =UpdatePetXP |
PXP.Menu.Resort() |
local PXP = ProgressionXP |
local t = PXP.translates |
if not t.states then t.states = {} end |
t.states[PXP.STATE_NORMAL] = "Normal" |
t.states[PXP.STATE_RESTED] = "Rested" |
t.states[PXP.STATE_NOPET] = "No Pet" |
t.states[PXP.STATE_TRAINABLE] = "Trainable" |
t.states[PXP.STATE_NOTFOUND] = "Not Found" |
t.states[PXP.STATE_CAPPED] = "Capped" |
t.NOT_CONFIGURED = "NOT CONFIGURED" |
t.SHOW = "Show" |
t.ADD_REMOVE = "Add/Remove" |
t.ADD_ALL = "Add all" |
t.REMOVE_ALL = "Remove all" |
t.DELETE_BAR = "Delete bar" |
t.CREATE_BAR = "Create new bar" |
t.CLONE_BAR = "Clone this bar" |
t.MOVE = "Move %s" |
t.DIRECTION_UP = "up" |
t.DIRECTION_DOWN = "down" |
t.DIRECTION_LEFT = "left" |
t.DIRECTION_RIGHT = "right" |
t.EDITMODE = "Enable Edit Mode" |
t.EDITMODE_TT = "Forces all bars to be visible so you can configure them." |
t.CANIDLE = "Fade when no recent activity" |
t.CANIDLE_TT = "Partially fades the bar after %d seconds without changes" |
t.CANINACTIVE = "Hide when no activity" |
t.CANINACTIVE_TT = "Hides the bar after %d seconds without changes" |
t.AUTOUPDATE = "Follow Changes" |
t.AUTOUPDATE_TT = "Causes the bar to automatically change display based on the most recently changed reputation/etc." |