WoWInterface SVN ChatIcons

[/] [trunk/] [ChatIcons/] [ChatIcons.lua] - Rev 6

Go to most recent revision | Compare with Previous | Blame | View Log

local addon = CreateFrame("Frame","ChatIcons")

local TEXTURE_LINK_FORMAT_FORMAT = "|T%%s:%d:%d:0:%d|t"
local TEXTURE_LINK_FORMAT
local ITEM_LINK_PATTERN = "|c%x%x%x%x%x%x%x%x|Hitem:(%d+):%-?%d+:%-?%d+:%-?%d+:%-?%d+:%-?%d+:%-?%d+:%-?%d+:?-?%d*|h"
local SPELL_LINK_PATTERN = "|c%x%x%x%x%x%x%x%x|Hspell:(%d+)|h"
local PLAYER_LINK_PATTERN = "|Hplayer:([^|:]+)"
local ACHIEVEMENT_LINK_PATTERN = "|Hachievement:(%d+):[%x:-]+|h" -- lazy, I know.  Shoot me.
local classIcons, raceIcons
local EXAMPLE_TEXT = "|Hplayer:CHAT_ICONS_FAKE_NAME_LINK|h[Medihv]|h says: I farmed |cff1eff00|Hitem:21884:0:0:0:0:0:0:0|h[Primal Fire]|h|r for weeks to make my " ..
                     "\124cffa335ee\124Hitem:21848:0:0:0:0:0:0:0\124h[Spellfire Robe]\124h\124r.  Man, I thought my |cff71d5ff|Hspell:133|h[Fireball]|h|r hit *so* " ..
                                         "hard back then."

function addon:OnEvent(event,...)
        local h = self[event]
        if type(h) == "function" then
                h(self,event,...)
        end
end

function addon:PLAYER_LOGIN()
        self:HookChatFrames()
        self.db = ChatIconsDB
        self.name = "ChatIcons"
        self.okay = function() self:ApplyTempOptions() end
        self.cancel = function() self:ResetTempOptions() end
        self.default = function() self:ResetOptions() self:ResetTempOptions()  if self:IsVisible() then self:Hide() self:Show() end end
        
        InterfaceOptions_AddCategory(self)
        InterfaceOptionsFrame:HookScript("OnHide",self.cancel)
        self:UpdateTextureLinkFormat()
end

local function addmsg(...) addon:AddMsgHook(...) end

function addon:HookChatFrames()
        if not self.hooks then self.hooks = {} end
        local n = "ChatFrame"
        for i=1,7 do
                local cf = getglobal(n..i)
                self.hooks[cf] = cf.AddMessage
                cf.AddMessage = addmsg
        end
end

local function parseMessage(s,iconFormat,pattern,geticon)
        local matchStart,matchEnd,match = s:find(pattern)
        while match do
                local icon = geticon(match)
                local iconlength = 0
                if icon then
                        local iconstring = iconFormat:format(icon)
                        iconlength = #iconstring
                        s = s:sub(1,matchStart - 1) .. iconstring .. s:sub(matchStart)
                end
                matchStart,matchEnd,match = s:find(pattern,matchEnd + iconlength)
        end
        return s
end

local function getSpellIcon(id)
        local _,_,icon = GetSpellInfo(id)
        return icon
end

local function getPlayerInfo(name)
        if name == "CHAT_ICONS_FAKE_NAME_LINK" then
                return "HUMAN_MALE","MAGE"
        else
                if UnitName(name) then
                        local _,race = UnitRace(name)
                        local gender = UnitSex(name) == 3 and "FEMALE" or "MALE"
                        local _,class = UnitClass(name)
                        return race:upper().."_"..gender,class
                else
                        for i=1,GetNumGuildMembers(true) do
                                local n,_,_,_,_,_,_,_,_,_,class = GetGuildRosterInfo(i)
                                if name == n then
                                        return "UNKNOWN",class
                                end
                        end
                end
        end
end

local function getPlayerClassIcon(name)
        local _,class = getPlayerInfo(name)
        return classIcons[class]
end

local function getPlayerRaceIcon(name)
        return raceIcons[(getPlayerInfo(name))]
end

local function getAchievementIcon(id)
        return select(10,GetAchievementInfo(id))
end

function addon:ProcessMessage(msg,textureFormat,example)
        local db = example and self.tempDB or self.db
        if db.items then msg = parseMessage(msg,textureFormat,ITEM_LINK_PATTERN,GetItemIcon) end
        if db.spells then msg = parseMessage(msg,textureFormat,SPELL_LINK_PATTERN,getSpellIcon) end
        if db.achievements then msg = parseMessage(msg,textureFormat,ACHIEVEMENT_LINK_PATTERN,getAchievementIcon) end
        if example or event == "CHAT_MSG_PARTY" or event == "CHAT_MSG_RAID" or event == "CHAT_MSG_GUILD" then
                --if db.race then msg = parseMessage(msg,textureFormat,PLAYER_LINK_PATTERN,getPlayerRaceIcon) end
                if db.class then msg = parseMessage(msg,textureFormat,PLAYER_LINK_PATTERN,getPlayerClassIcon) end
        end
        return msg
end

function addon:AddMsgHook(frame,s,...)
        if s then
                s = self:ProcessMessage(s,TEXTURE_LINK_FORMAT)
        end
        self.hooks[frame](frame,s,...)
end

function addon:OnShow()
        self:ResetTempOptions()
        if not self.builtGui then
                self:BuildWidgetMethods()
                self:BuildGuiOptions()
        end
end

function addon:UpdateTextureLinkFormat()
        local db = self.db
        local size = db.autosize and 0 or db.size
        TEXTURE_LINK_FORMAT = TEXTURE_LINK_FORMAT_FORMAT:format(size,size,db.offset)
end

function addon:ResetTempOptions()
        if not self.tempDB then self.tempDB = {} end
        for k,v in pairs(self.db) do
                self.tempDB[k] = v
        end
end

function addon:ResetOptions()
        ChatIconsDB = {
                items = true,
                spells = true,
--              race = false,
                class = false,
                size = 12,
                offset = -3,
                autosize = true,
                exampleFontSize = 14,
        }
        self.db = ChatIconsDB
end

function addon:ApplyTempOptions()
        for k,v in pairs(self.tempDB) do
                self.db[k] = v
        end
        self:UpdateTextureLinkFormat()
end

local createCheckButton, checkbutton_PostClick, widget_OnShow, slider_Disable, slider_Enable, widget_SetDependency

function addon:BuildGuiOptions()
        local t = self:CreateFontString(nil,"ARTWORK","GameFontNormalLarge")
        t:SetText("ChatIcons")
        t:SetPoint("TOPLEFT",16,-16)
        self.title = t
        
        t = self:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall")
        t:SetText("Adds icons to your chat frames.")
        t:SetPoint("TOPLEFT",self.title,"BOTTOMLEFT",0,0)
        t:SetPoint("RIGHT",-32,0)
        t:SetHeight(32)
        t:SetJustifyH("LEFT")
        self.subtext = t
        
        self.itemIcons = createCheckButton("Item Icons","items","Item icons are added next to item links in chat.","TOPLEFT",self.subtext,"BOTTOMLEFT",-2,-8)
        self.spellIcons = createCheckButton("Spell Icons","spells","Spell icons are added next to spell links in chat.","TOPLEFT",self.itemIcons,"BOTTOMLEFT",0,-8)
        self.classIcons = createCheckButton("Player Class Icons","class","Class icons are added next to players' names when they speak in party, raid or guild chat.","TOPLEFT",self.spellIcons,"BOTTOMLEFT",0,-8)
        self.achIcons = createCheckButton("Achievement Icons","achievements","Achievement icons are added next to achievement links in chat.","TOPLEFT",self.classIcons,"BOTTOMLEFT",0,-8)
        
        --self.raceIcons = createCheckButton("Player Race Icons","race","Race icons are added next to players' names when they speak in party, raid or guild chat.","TOPLEFT",self.classIcons,"BOTTOMLEFT",0,-8)
        --self.moneyIcons = createCheckButton("Coin Icons","money","","TOPLEFT",self.classIcons,"BOTTOMLEFT",0,-8)
        
        self.autosize = createCheckButton("Use Icon Auto-Sizing","autosize","Icons are sized to be the same height as the surrounding text.","TOPRIGHT",self.subtext,"BOTTOMRIGHT",-110,-8)
        
        local iconSize = createSlider("Icon Size","size",5,30,"Sets the width and height of the icons that appear in chat.","TOPLEFT",self.autosize,"BOTTOMLEFT",3,-20)
        iconSize:SetDependency(self.autosize,true)
        self.iconSize = iconSize
        self.verticalOffset = createSlider("Vertical Offset","offset",-15,15,"Sets the vertical offset of the icon in pixels from the top.","TOPLEFT",self.iconSize,"BOTTOMLEFT",0,-32)
        
        local e = CreateFrame("Frame",nil,self)
        e:SetWidth(357)
        e:SetHeight(100)
        e:SetPoint("BOTTOMLEFT",15,50)
        e:SetBackdrop(GameTooltip:GetBackdrop()) -- lol, cheater
        e:SetBackdropColor(0,0,0,.5)
        e:SetBackdropBorderColor(0.5,0.5,0.5,.5)
        self.exampleBox = e
        
        t = self:CreateFontString(nil,"ARTWORK","GameFontNormal")
        t:SetText("Example Text")
        t:SetPoint("BOTTOMLEFT",e,"TOPLEFT",4,0)
        
        t = e:CreateFontString(nil,"ARTWORK","GameFontHighlight")
        t:SetPoint("TOPLEFT",5,-5)
        t:SetPoint("BOTTOMRIGHT",-10,10)
        t:SetJustifyH("LEFT")
        t:SetJustifyV("TOP")
        self.exampleText = t
        
        self.exampleTextFontSize = createSlider("Example Text Font Size","exampleFontSize",7,25,"Sets the font size used in the example text.","TOPLEFT",t,"BOTTOMLEFT",0,-24)
        
        self.builtGui = true
end

function addon:UpdateExamples()
        if not self.exampleText then return end
        local db = self.tempDB
        local size = db.autosize and 0 or db.size
        local format = TEXTURE_LINK_FORMAT_FORMAT:format(size,size,db.offset)
        self.format = format
        local t = self.exampleText
        local font,size,flags = t:GetFont()
        t:SetFont(font,db.exampleFontSize,flags)
        self.exampleText:SetText(self:ProcessMessage(EXAMPLE_TEXT,format,true))
end

function addon:BuildWidgetMethods()
        checkbutton_PostClick = function(b)
                local value = b:GetChecked() 
                self.tempDB[b.option] = value and true or false -- to force a value into the database when nil is returned
                self:UpdateExamples()
                
                if b.dependentWidgets then
                        for _,widget in pairs(b.dependentWidgets) do
                                widget:OnDependencyValueChanged(value)
                        end
                end
        end
        
        slider_Disable = function(s)
                s:EnableMouse(false)
                local c = GRAY_FONT_COLOR
                s.text:SetTextColor(c.r, c.g, c.b)
                s.valueText:Hide()
                s.lowText:SetTextColor(c.r, c.g, c.b)
                s.highText:SetTextColor(c.r, c.g, c.b)
                s.thumb:Hide()
        end
        
        slider_Enable = function(s)
                local c = HIGHLIGHT_FONT_COLOR
                s.text:SetTextColor(c.r, c.g, c.b)
                s.valueText:Show()
                local c = NORMAL_FONT_COLOR
                s.lowText:SetTextColor(c.r, c.g, c.b)
                s.highText:SetTextColor(c.r, c.g, c.b)
                
                s:EnableMouse(true)
                s.thumb:Show()
        end
        
        slider_OnValueChanged = function(s)
                local value = s:GetValue()
                s.valueText:SetText(value)
                self.tempDB[s.option] = value
                self:UpdateExamples()
        end
        
        widget_OnShow = function(w)
                w:SetValue(self.tempDB[w.option])
        end
        
        widget_SetDependency = function(w,parent,invert)
                if not parent.dependentWidgets then parent.dependentWidgets = {} end
                w.invertDependency = invert
                table.insert(parent.dependentWidgets,w)
                w:OnDependencyValueChanged(parent:GetValue())
        end
        
        widget_OnDependencyValueChanged = function(w,value)
                if w.invertDependency then value = not value end
                if value then w:Enable()
                else w:Disable() end
        end
end

local function setupWidget(widget,name,option,tooltipText,...)
        local text = getglobal(widget:GetName().."Text") -- ew
        text:SetText(name)
        widget.text = text
        widget:SetPoint(...)
        widget.tooltipText = tooltipText
        widget.option = option
        
        widget.SetDependency = widget_SetDependency
        widget.OnDependencyValueChanged = widget_OnDependencyValueChanged
        
        widget:SetScript("OnShow",widget_OnShow)
        widget_OnShow(widget)
end

createCheckButton = function(name,option,tooltipText,...)
        local b = CreateFrame("CheckButton","ChatIcons - "..name,addon,"InterfaceOptionsCheckButtonTemplate")
        b.SetValue = b.SetChecked
        b.GetValue = b.GetChecked
        b:SetScript("PostClick",checkbutton_PostClick)
                
        setupWidget(b,name,option,tooltipText,...)
        b:SetHitRectInsets(0,-b.text:GetWidth(),0,0)
        return b
end

createSlider = function(name,option,min,max,tooltipText,...)
        local s = CreateFrame("Slider","ChatIcons - "..name,addon,"OptionsSliderTemplate")
        local t = s:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall")
        t:SetPoint("TOP",s,"BOTTOM")
        s.valueText = t
        
        t = getglobal(s:GetName() .. "Low") -- ew
        t:SetText(min)
        s.lowText = t
        
        t = getglobal(s:GetName() .. "High") -- ew
        t:SetText(max)
        s.highText = t
        
        s.thumb = getglobal(s:GetName() .. "Thumb") -- ew
        
        s.Enable = slider_Enable
        s.Disable = slider_Disable
        
        s:SetScript("OnValueChanged",slider_OnValueChanged)
        s:SetMinMaxValues(min,max)
        s:SetValueStep(1)
        setupWidget(s,name,option,tooltipText,...)
        return s
end

classIcons = {
        DEATHKNIGHT = "Interface\\Icons\\Spell_Deathknight\\ClassIcon"
        DRUID = "Interface\\Icons\\INV_Misc_MonsterClaw_04",
        WARLOCK = "Interface\\Icons\\Spell_Nature_FaerieFire",
        HUNTER = "Interface\\Icons\\INV_Weapon_Bow_07",
        MAGE = "Interface\\Icons\\INV_Staff_13",
        PRIEST = "Interface\\Icons\\INV_Staff_30",
        WARRIOR = "Interface\\Icons\\INV_Sword_27",
        SHAMAN = "Interface\\Icons\\Spell_Nature_BloodLust",
        PALADIN = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Classes_Paladin",
        ROGUE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Classes_Rogue",
}

--[[raceIcons = {
        HUMAN_MALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Human-Male",
        HUMAN_FEMALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Human-Female",
        GNOME_MALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Gnome-Male",
        GNOME_FEMALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Gnome-Female",
        DWARF_MALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Dwart-Male",
        DWARF_FEMALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Dwarf-Female",
        NIGHTELF_MALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_NightElf-Male",
        NIGHTELF_FEMALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_NightElf-Female",
        DRAENEI_MALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Draenei-Male",
        DRAENEI_FEMALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Draenei-Female",
        UNDEAD_MALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Undaed-Male",
        UNDEAD_FEMALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Undead-Female",
        ORC_MALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Orc-Male",
        ORC_FEMALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Orc-Female",
        TROLL_MALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Troll-Male",
        TROLL_FEMALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Troll-Female",
        TAUREN_MALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Tauren-Male",
        TAUREN_FEMALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_Tauren-Female",
        BLOODELF_MALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_BloodElf-Male",
        BLOODELF_FEMALE = "Interface\\AddOns\\ChatIcons\\images\\UI-CharacterCreate-Races_BloodElf-Female",
}
]]
addon:SetScript("OnShow",addon.OnShow)
addon:SetScript("OnEvent",addon.OnEvent)
addon:RegisterEvent("PLAYER_LOGIN")
addon:ResetOptions()

Go to most recent revision | Compare with Previous | Blame