Quantcast

* Finished Buff Window configuration

James Whitehead II [12-22-06 - 05:58]
* Finished Buff Window configuration
* Added buff colors swatch
* Created Single/Double columns
Filename
PerfectRaid.lua
PerfectRaid.toc
PerfectRaidOptions.lua
diff --git a/PerfectRaid.lua b/PerfectRaid.lua
index 28d6a2f..3281401 100644
--- a/PerfectRaid.lua
+++ b/PerfectRaid.lua
@@ -18,7 +18,7 @@

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHsqsANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
@@ -42,6 +42,12 @@ function PerfectRaid:Initialize()
 		profile = {
 			headers = {},
 			buffs = {},
+			positions = {},
+			simple = {
+				voffset = 15,
+				titles = true,
+			},
+			mode = "double",
 		},
 	}

@@ -67,7 +73,101 @@ function PerfectRaid:Enable()
 	self:RegisterEvent("UNIT_MAXFOCUS", "UNIT_MAXMANA")
 	self:RegisterEvent("UNIT_AURA")

-	self:CreateRaidHeaders()
+	local mode = self.db.profile.mode
+	if mode == "singleclass" then
+		self:CreateSingleColumn()
+	elseif mode == "singlegroup" then
+		self:CreateSingleColumn("group")
+	elseif mode == "double" then
+		self:CreateDoubleColumn()
+	elseif mode == "advanced" then
+		self:CreateRaidHeaders()
+	end
+end
+
+function PerfectRaid:CreateSingleColumn(sort)
+	self.column = self.column or {}
+	local column = self.column
+
+	local classes = {"Warrior","Priest","Druid","Shaman","Paladin","Rogue","Mage","Warlock","Hunter"}
+	local voffset = self.db.profile.simple.voffset * -1
+	local titles = self.db.profile.simple.titles
+
+	if sort == "group" then
+		classes = {"Group 1","Group 2","Group 3","Group 4","Group 5","Group 6","Group 7","Group8"}
+	end
+
+	for i=1,#classes do
+		local filter
+		if sort == "group" then
+			filter = string.sub(classes[i], -1, -1)
+		else
+			filter = string.upper(classes[i])
+		end
+		local title = titles and classes[i] or nil
+
+		if not column[i] then
+			column[i] = self:CreateRaidFrame("PRColumn"..i, title, filter, nil, column[1])
+			column[i]:Show()
+		else
+			self:ChangeRaidFrame("PRColumn"..i, title, filter, nil, column[1])
+			column[i]:Show()
+			column[i]:ClearAllPoints()
+		end
+	end
+
+	self:RestorePosition("PRColumn1")
+
+	for i=2,#classes do
+		self.column[i].locked = true
+		self.column[i]:SetPoint("TOP", self.column[i-1], "BOTTOM", 0, voffset)
+	end
+
+	if GetNumRaidMembers() <= 0 then
+		for i,frame in ipairs(column) do
+			frame:Hide()
+		end
+	end
+end
+
+function PerfectRaid:CreateDoubleColumn()
+	self.column = self.column or {}
+	local column = self.column
+
+	local voffset = self.db.profile.simple.voffset * -1
+	local titles = self.db.profile.simple.titles
+	local classes = {"Group 1","Group 2","Group 3","Group 4","Group 5","Group 6","Group 7","Group8"}
+
+	for i=1,#classes do
+		local filter = string.sub(classes[i], -1, -1)
+		local title = titles and classes[i] or nil
+
+		if not column[i] then
+			column[i] = self:CreateRaidFrame("PRColumn"..i, title, filter, nil, column[1])
+			column[i]:Show()
+		else
+			self:ChangeRaidFrame("PRColumn"..i, title, filter, nil, column[1])
+			column[i]:Show()
+			column[i]:ClearAllPoints()
+		end
+	end
+
+	self:RestorePosition("PRColumn1")
+
+	for i=2,4 do
+		column[i].locked = true
+		column[i]:SetPoint("TOP", column[i-1], "BOTTOM", 0, voffset)
+	end
+	column[5]:SetPoint("TOPLEFT", column[1], "TOPRIGHT", 50, 0)
+	for i=6,8 do
+		column[i].locked = true
+		column[i]:SetPoint("TOP", column[i-1], "BOTTOM", 0, voffset)
+	end
+	if GetNumRaidMembers() <= 0 then
+		for i,frame in ipairs(column) do
+			frame:Hide()
+		end
+	end
 end

 function PerfectRaid:CreateRaidHeaders()
@@ -103,14 +203,23 @@ function PerfectRaid:SavePosition(name)

     x,y = x*s,y*s

-	local opt = self.db.profile.headers[tonumber(string.sub(name, -1, -1))]
+	local opt = self.db.profile.positions[name]
+	if not opt then
+		self.db.profile.positions[name] = {}
+		opt = self.db.profile.positions[name]
+	end
     opt.PosX = x
     opt.PosY = y
 end

 function PerfectRaid:RestorePosition(name)
 	local f = getglobal(name)
-	local opt = self.db.profile.headers[tonumber(string.sub(name, -1, -1))]
+	local opt = self.db.profile.positions[name]
+	if not opt then
+		self.db.profile.positions[name] = {}
+		opt = self.db.profile.positions[name]
+	end
+
 	local x = opt.PosX
 	local y = opt.PosY

@@ -128,30 +237,35 @@ function PerfectRaid:RestorePosition(name)
 	f:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
 end

-function PerfectRaid:ChangeRaidFrame(name, title, filter, strict)
+function PerfectRaid:ChangeRaidFrame(name, title, filter, strict, dragparent)
 	local frame = getglobal(name)
 	frame.title:SetText(title or "")
 	frame:SetAttribute("groupFilter", filter)
 	frame:SetAttribute("strictFiltering", strict)
+	frame:SetAttribute("dragparent", dragparent or frame)
 	frame:Hide()
 	frame:Show()
 end

 local function OnDragStart(frame)
-	local parent = frame:GetParent()
-	parent:StartMoving()
+	local parent = frame:GetAttribute("dragparent")
+	if not parent.locked then
+		parent:StartMoving()
+		PerfectRaid.moving = parent
+	end
 end

 local function OnDragStop(frame)
-	local parent = frame:GetParent()
+	local parent = frame:GetAttribute("dragparent")
 	parent:StopMovingOrSizing()
 	PerfectRaid:SavePosition(parent:GetName())
+	PerfectRaid.moving = nil
 end

-function PerfectRaid:CreateRaidFrame(name, title, filter, strict)
+function PerfectRaid:CreateRaidFrame(name, title, filter, strict, dragparent)
 	local frame = CreateFrame("Frame", name, UIParent, "SecureRaidGroupHeaderTemplate")
 	frame.title = frame:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
-	frame.title:SetPoint("BOTTOM", frame, "TOP", 0, 5)
+	frame.title:SetPoint("BOTTOM", frame, "TOP", 0, 3)
 	frame.title:SetText(title or "")
 	frame:SetAttribute("point", "TOP")
 	frame:SetAttribute("groupFilter", filter)
@@ -160,6 +274,7 @@ function PerfectRaid:CreateRaidFrame(name, title, filter, strict)
 	frame:SetAttribute("yOffset", -2)
 	frame:SetAttribute("sortMethod", "NAME")
 	frame:SetAttribute("strictFiltering", strict)
+	frame:SetAttribute("dragparent", dragparent or frame)
 	frame.initialConfigFunction = PerfectRaid.ConfigureButton
 	frame:SetMovable(true)
 	frame:SetClampedToScreen(true)
@@ -201,9 +316,13 @@ function PerfectRaid:UNIT_HEALTH(event, unit)
 	if not frames[unit] then return end
 	local health = UnitHealth(unit)
 	local max = UnitHealthMax(unit)
+	-- Hack to fix api issue
+	if max < health then max = health end
 	local deficit = max - health
 	local perc = UnitHealthMax(unit) / health
 	local class = select(2, UnitClass(unit))
+	local perc = (health/max) or 0
+
 	if deficit > 999 then
 		deficit = string.format("%.1fk", deficit / 1000)
 	elseif deficit == 0 then
@@ -235,7 +354,8 @@ function PerfectRaid:UNIT_HEALTH(event, unit)
 		if unavail[unit] then
 			for frame in pairs(frames[unit]) do
 				local color = frame.classcolor
-				frame.healthbar:SetStatusBarColor(color.r, color.g, color.b)
+--				frame.healthbar:SetStatusBarColor(color.r, color.g, color.b)
+				frame.healthbar:SetStatusBarColor(utils.GetHPSeverity(perc))
 				frame.healthbar:SetMinMaxValues(0, UnitHealthMax(unit))
 				frame.healthbar:SetValue(UnitHealth(unit))
 				frame:SetBackdropBorderColor(color.r, color.g, color.b)
@@ -254,6 +374,7 @@ function PerfectRaid:UNIT_HEALTH(event, unit)
 			if not range then frame:SetAlpha(0.3) else frame:SetAlpha(1.0) end
 			local class = select(2, UnitClass(unit))
 			frame.healthbar:SetValue(health)
+			frame.healthbar:SetStatusBarColor(utils.GetHPSeverity(perc))
 			frame.status:SetText(deficit)
 		end
 	end
@@ -318,6 +439,7 @@ local function OnShow(frame)

 	self:UNIT_HEALTH(nil, unit)
 	self:UNIT_MANA(nil, unit)
+	self:UNIT_AURA(nil, unit)
 end

 local function OnHide(frame)
@@ -336,7 +458,7 @@ local function OnAttributeChanged(frame, name, value)
 end

 function PerfectRaid.ConfigureButton(button)
-	button:SetWidth(90)
+	button:SetWidth(160)
 	button:SetHeight(14)
 --	button:SetBackdrop(GameTooltip:GetBackdrop())
 	button:SetBackdropColor(0.3, 0.3, 0.3)
@@ -344,9 +466,12 @@ function PerfectRaid.ConfigureButton(button)

 	ClickCastFrames[button] = true
 	button:SetAttribute("*type1", "target")
-
+
+	local parent = button:GetParent()
+	button:SetAttribute("dragparent", parent:GetAttribute("dragparent"))
+
 	local bar = CreateFrame("StatusBar", nil, button)
-	bar:SetPoint("TOPLEFT", 0, 0)
+	bar:SetPoint("TOPLEFT", 70, 0)
 	bar:SetPoint("BOTTOMRIGHT", 0, 0)
 	bar:SetStatusBarTexture("Interface\\AddOns\\PerfectRaid\\images\\smooth")
 	button.healthbar = bar
@@ -361,6 +486,8 @@ function PerfectRaid.ConfigureButton(button)

 	local font = button.healthbar:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
 	font:SetPoint("RIGHT", button.healthbar, "LEFT", -2, 0)
+	font:SetPoint("LEFT", button, "LEFT", 0, 0)
+	font:SetJustifyH("RIGHT")
 	button.name = font

 	local font = button.healthbar:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
@@ -383,10 +510,10 @@ end
 function PerfectRaid:RAID_ROSTER_UPDATE()
 	if GetNumRaidMembers() > 0 then
 		--PRaidPartyHeader:Hide()
-		for k,v in pairs(self.headers) do
-			v:StopMovingOrSizing()
-			v:Show()
+		if self.moving then
+			self.moving:StopMovingOrSizing()
 		end
+		self:ShowHideTitles()
 	else
 		if PRaidPartyHeader then
 			PRaidPartyHeader:Show()
@@ -396,17 +523,69 @@ function PerfectRaid:RAID_ROSTER_UPDATE()
 				tbl[k] = nil
 			end
 		end
-
-		for k,v in pairs(self.headers) do
-			v:Hide()
+		if self.headers then
+			for k,v in pairs(self.headers) do
+				v.title:Hide()
+			end
+		end
+		if self.column then
+			for k,v in pairs(self.column) do
+				v.title:Hide()
+			end
 		end
 	end
 end

+function PerfectRaid:ShowHideTitles()
+	if self.column then
+		for i,frame in pairs(self.column) do
+			local active
+			for i=1,frame:GetNumChildren() do
+				local button = frame:GetAttribute("Child"..i)
+				if button:IsShown() then
+					active = true
+				end
+			end
+			if not active then
+				frame.title:Hide()
+			else
+				frame.title:Show()
+			end
+		end
+	end
+
+	if self.headers then
+		for i,frame in pairs(self.column) do
+			local active
+			for i=1,frame:GetNumChildren() do
+				local button = frame:GetAttribute("Child"..i)
+				if button:IsShown() then
+					active = true
+				end
+			end
+			if not active then
+				frame.title:Hide()
+			else
+				frame.title:Show()
+			end
+		end
+	end
+end
+
+local class = select(2, UnitClass("player"))
+local spells = {
+	DRUID = "Healing Touch",
+	SHAMAN = "Healing Wave",
+	PRIEST = "Lesser Heal",
+	PALADIN = "Holy Light",
+}
+
+local rangespell = spells[class]
+
 local elapsed = 0
 function PerfectRaid.OnUpdate(frame, arg1)
 	for unit,tbl in pairs(frames) do
-		local range = IsSpellInRange("Healing Touch", unit) == 1
+		local range = IsSpellInRange(rangespell, unit) == 1
 		local alpha = range and 1.0 or 0.3
 		for frame in pairs(tbl) do
 			frame:SetAlpha(alpha)
@@ -419,7 +598,7 @@ local frame = CreateFrame("Frame", "PRUpdateFrame")
 frame:SetScript("OnUpdate", PerfectRaid.OnUpdate)

 local buffcache = {}
-
+local work = {}
 function PerfectRaid:UNIT_AURA(event, unit)
 	if not frames[unit] then return end
 	for k,v in pairs(buffcache) do buffcache[k] = nil end
@@ -434,7 +613,37 @@ function PerfectRaid:UNIT_AURA(event, unit)
 		local name,rank,texture,count = UnitDebuff(unit, i)
 		if not name then break end
 		buffcache[name] = (buffcache[name] or 0) + 1
-	end
+	end
+
+	for k,v in pairs(work) do work[k] = nil end
+
+	local buffs = self.db.profile.buffs
+	for i,entry in ipairs(buffs) do
+		local checkcond = false
+		if entry.missing then
+			if not buffcache[entry.buffname] and not buffcache[entry.groupbuff or "nil"] then
+				checkcond = true
+			end
+		else
+			if buffcache[entry.buffname] or buffcache[entry.groupbuff or "nil"] then
+				checkcond = true
+			end
+		end
+
+		local conds = self.conditions
+		if checkcond then
+			for i,name in pairs(entry.cond) do
+				if conds[name] and conds[name](unit) then
+					table.insert(work, entry.colortext)
+				end
+			end
+		end
+	end
+
+	local status = strjoin(" ", unpack(work))
+	for frame in pairs(frames[unit]) do
+		frame.aura:SetText(status)
+	end
 end

 --seterrorhandler(function(msg) PerfectRaid:Print(msg .. debugstack()) end)
diff --git a/PerfectRaid.toc b/PerfectRaid.toc
index 619f186..1ba7880 100644
--- a/PerfectRaid.toc
+++ b/PerfectRaid.toc
@@ -6,6 +6,7 @@
 ## OptionalDeps: Dongle

 Dongle.lua
+DongleUtils.lua
 PerfectRaid.xml
 PerfectRaid.lua
 PerfectRaidOptions.lua
diff --git a/PerfectRaidOptions.lua b/PerfectRaidOptions.lua
index 01a4a69..07a3587 100644
--- a/PerfectRaidOptions.lua
+++ b/PerfectRaidOptions.lua
@@ -29,6 +29,8 @@
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------]]

+local utils = DongleStub("DongleUtils")
+
 function PerfectRaid:SkinFrame(frame)
 	local topleft = frame:CreateTexture()
 	topleft:SetHeight(32) topleft:SetWidth(32)
@@ -427,7 +429,7 @@ function PerfectRaid:CreateOptions()
 	button4:SetPoint("CENTER", frame, "BOTTOM", 40, 25)

 	button3:SetScript("OnClick", function()
-		local edit = scrollframe.editSave
+		local edit = self.editSave
 		local entry = edit or {}
 		entry.name = edit1:GetText()
 		if entry.name == "" then entry.name = "Unnamed" end
@@ -457,38 +459,80 @@ function PerfectRaid:CreateOptions()
 			boxes[i]:SetChecked(nil)
 		end
 		edit1:SetText("")
-		scrollframe.editSave = nil
+		self.editSave = nil
 		frame:Hide()
 	end)

 	button2:SetScript("OnClick", function()
+		local list,frame,checklist
+
+		if self.editMode == "Frames" then
+			list = self.db.profile.headers
+			frame = PREditRaid
+			checklist = "filters"
+		elseif self.editMode == "Buffs" then
+			list = self.db.profile.buffs
+			frame = PREditBuff
+			checklist = "cond"
+		end
+
 		local idx = selected.idx
 		local offset = FauxScrollFrame_GetOffset(scrollframe)
-		local entry = self.db.profile.headers[offset + idx]
-		scrollframe.editSave = entry
+		local entry = list[offset + idx]
+		self.editSave = entry

-		for i=1,#boxes do
-			edit1:SetText(entry.name)
-			local box = boxes[i]
-			for k,v in pairs(entry.filters) do
+		boxes = frame.boxes
+
+		for i,box in ipairs(boxes) do
+			for k,v in pairs(entry[checklist]) do
 				if box.value == v then
 					box:SetChecked()
 				end
 			end
 		end
+
+		if self.editMode == "Frames" then
+			edit1:SetText(entry.name)
+		elseif self.editMode == "Buffs" then
+			PREditBuffName:SetText(entry.buffname or "")
+			PREditGroupName:SetText(entry.groupbuff or "")
+			PREditDispText:SetText(entry.disptext or "")
+			PRIconButton.icon:SetTexture(entry.texture)
+			PRBuffCheckMissing:SetChecked(entry.missing)
+			PRBuffCheckDisabled:SetChecked(entry.disabled)
+			PRColorSelect.normalTexture:SetVertexColor(unpack(entry.color))
+		end
+
 		frame:Show()
 	end)

 	button5:SetScript("OnClick", function()
+		local list
+
+		if self.editMode == "Frames" then
+			list = self.db.profile.headers
+		elseif self.editMode == "Buffs" then
+			list = self.db.profile.buffs
+		end
+
 		local idx = selected.idx
 		local offset = FauxScrollFrame_GetOffset(scrollframe)

-		local header = self.headers[offset + idx]
-		table.remove(self.db.profile.headers, offset + idx)
-		header:Hide()
-		header:SetAttribute("groupFilter", nil)
-		header:SetAttribute("nameList", nil)
-		self:CreateRaidHeaders()
+		local entry = list[offset + idx]
+		table.remove(list, offset + idx)
+
+		if self.editMode == "Frames" then
+			local header = self.headers[offset + idx]
+			header:Hide()
+			header:SetAttribute("groupFilter", nil)
+			header:SetAttribute("nameList", nil)
+			self:CreateRaidHeaders()
+		elseif self.editMode == "Buffs" then
+			for unit in pairs(self.frames) do
+				self:UNIT_AURA(nil, unit)
+			end
+		end
+
 		selected = nil
 		scrollframe.update()
 	end)
@@ -512,7 +556,7 @@ end
 function PerfectRaid:CreateBuffEditWindow()
 	local frame = CreateFrame("Frame", "PREditBuff")
 	frame:SetFrameStrata("HIGH")
-	frame:SetHeight(400)
+	frame:SetHeight(415)
 	frame:SetWidth(350)
 	frame:SetPoint("CENTER", 75, -25)
 	self:SkinFrame(frame)
@@ -576,21 +620,111 @@ function PerfectRaid:CreateBuffEditWindow()
     iconbutton:SetScript("OnLeave", function() GameTooltip:Hide() end)
 	iconbutton:SetScript("OnClick", function() PRIconSelectFrame:Show() end)

-	buffname:SetScript("OnTabPressed", function() groupbuff:SetFocus() end)
-	groupbuff:SetScript("OnTabPressed", function() disptext:SetFocus() end)
-	disptext:SetScript("OnTabPressed", function() buffname:SetFocus() end)
+	buffname:SetScript("OnTabPressed", function()
+		if IsShiftKeyDown() then disptext:SetFocus() else groupbuff:SetFocus() end
+	end)
+	groupbuff:SetScript("OnTabPressed", function()
+		if IsShiftKeyDown() then buffname:SetFocus() else disptext:SetFocus() end
+	end)
+	disptext:SetScript("OnTabPressed", function()
+		if IsShiftKeyDown() then groupbuff:SetFocus() else buffname:SetFocus() end
+	end)

 	frame:SetScript("OnShow", function() buffname:SetFocus() end)

-	function makecheck(text, value)
-		local box = CreateFrame("CheckButton", "Buff"..text, frame, "UICheckButtonTemplate")
+	-- Color Swatch
+	local function colorSwatchCancel()
+		local self = ColorPickerFrame.object;
+		local r, g, b = self.r, self.g, self.b;
+		self.normalTexture:SetVertexColor(r, g, b);
+	end
+
+	local function colorSwatchColor()
+		local self = ColorPickerFrame.object;
+		local r, g, b = ColorPickerFrame:GetColorRGB();
+		self.normalTexture:SetVertexColor(r, g, b);
+		self.color[1] = r
+		self.color[2] = g
+		self.color[3] = b
+	end
+
+	local function colorSwatchOpacity()
+		local self = ColorPickerFrame.object;
+		local a = OpacitySliderFrame:GetValue();
+	end
+
+	local function colorSwatchShow(self)
+		local r, g, b, a;
+		self.color = self.color or {1,1,1}
+
+		local color = self.color;
+		if ( color ) then
+			r, g, b, a = unpack(color);
+		end
+
+		self.r, self.g, self.b = r, g, b
+		self.opacityFunc = colorSwatchOpacity;
+		self.swatchFunc = colorSwatchColor;
+		self.cancelFunc = colorSwatchCancel;
+
+		ColorPickerFrame.object = self;
+		UIDropDownMenuButton_OpenColorPicker(self);
+		ColorPickerFrame:SetFrameStrata("TOOLTIP");
+		ColorPickerFrame:Raise();
+	end
+
+	local function colorSwatchOnClick(self)
+		CloseMenus();
+		colorSwatchShow(self);
+	end
+
+	local function colorSwatchOnEnter(self)
+		self.bg:SetVertexColor(1, 0.82, 0);
+	end
+
+	local function colorSwatchOnLeave(self)
+		self.bg:SetVertexColor(1, 1, 1);
+	end
+
+	local swatch = CreateFrame("Button", "PRColorSelect", frame);
+	swatch:SetHeight(20) swatch:SetWidth(20)
+	swatch:SetPoint("LEFT", disptext, "RIGHT", 5, 0)
+	local bg = swatch:CreateTexture(nil, "BACKGROUND");
+	local normalTexture = swatch:CreateTexture(nil, "ARTWORK");
+
+	normalTexture:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch");
+	normalTexture:SetAllPoints(swatch);
+	swatch:SetNormalTexture(normalTexture);
+	bg:SetTexture(1, 1, 1);
+	bg:SetPoint("TOPLEFT", swatch, 1, -1);
+	bg:SetPoint("BOTTOMRIGHT", swatch, 0, 1);
+
+	self.color = {1,1,1,1}
+	if ( self.color ) then
+		normalTexture:SetVertexColor(unpack(self.color))
+	end
+
+	swatch.bg, swatch.normalTexture = bg, normalTexture;
+	swatch.object, swatch.hasAlpha = self, 1
+
+	swatch:SetScript("OnLeave", colorSwatchOnLeave);
+	swatch:SetScript("OnEnter", colorSwatchOnEnter);
+	swatch:SetScript("OnClick", colorSwatchOnClick);
+
+	function makecheck(text, func, name)
+		name = name or text
+		local box = CreateFrame("CheckButton", "PRBuffCheck"..name, frame, "UICheckButtonTemplate")
 		box.text = getglobal(box:GetName().."Text")
 		box.text:SetText(text)
+		box.value = text
+		box.func = func
 		return box
 	end

 	-- Create buff condition checkboxes.
 	local boxes = {}
+	frame.boxes = boxes
+
 	boxes[1] = makecheck("Warrior", self.conditions.Warrior)
 	boxes[1]:SetPoint("TOPLEFT", iconbutton, "BOTTOMLEFT", -85, -5)
 	boxes[2] = makecheck("Rogue", self.conditions.Rogue)
@@ -619,9 +753,12 @@ function PerfectRaid:CreateBuffEditWindow()
 	boxes[12] = makecheck("Range", self.conditions.Range)
 	boxes[12]:SetPoint("LEFT", boxes[11], "RIGHT", 80, 0)

-	local missing = makecheck("Only display if the given buff is missing")
+	local missing = makecheck("Only display if the given buff is missing", nil, "Missing")
 	missing:SetPoint("TOPLEFT", boxes[10], "BOTTOMLEFT", 0, -5)

+	local disabled = makecheck("Disable", nil, "Disabled")
+	disabled:SetPoint("TOPLEFT", missing, "BOTTOMLEFT", 0, -5)
+
 	local saveicon = CreateFrame("Button", "PRButtonBuffSave", frame)
 	self:SkinButton(saveicon)
 	saveicon.text:SetText("Save")
@@ -759,12 +896,33 @@ function PerfectRaid:CreateBuffEditWindow()

 	PRButtonBuffSave:SetScript("OnClick", function()
 		local list = self.db.profile.buffs
-		local entry = {}
+		local entry = self.editSave or {}

 		entry.name = buffname:GetText()
 		entry.desc = disptext:GetText() or iconbutton.icon:GetTexture()
-		table.insert(list, entry)
+		entry.cond = {}
+		for i,box in ipairs(boxes) do
+			if box:GetChecked() then
+				table.insert(entry.cond, box.value)
+			end
+		end
+		entry.buffname = buffname:GetText()
+		entry.groupbuff = groupbuff:GetText()
+		entry.disptext = disptext:GetText()
+		entry.texture = iconbutton.icon:GetTexture()
+		entry.missing = missing:GetChecked()
+		entry.disabled = disabled:GetChecked()
+		entry.color = swatch.color
+		entry.colortext = string.format("|cFF%s%s|r", utils.RGBToHex(unpack(entry.color)), entry.disptext)
+
+		if not self.editSave then
+			table.insert(list, entry)
+		end
 		PRButtonBuffCancel:Click()
+		PRScrollFrame.update()
+		for unit in pairs(self.frames) do
+			self:UNIT_AURA("UNIT_AURA", unit)
+		end
 	end)

 	PRButtonBuffCancel:SetScript("OnClick", function()
@@ -775,6 +933,7 @@ function PerfectRaid:CreateBuffEditWindow()
 			groupbuff:SetText("")
 			disptext:SetText("")
 			iconbutton.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
+			swatch.normalTexture:SetVertexColor(1,1,1)
 		end
 		missing:SetChecked(false)
 	end)