Quantcast

Renamed RPChatBubbles to Speaker Bee. Added Sound Effects. Switched to Dragonflight Settings. Added font size setting. Added shadow load setting. Bumped version to 10.0.0

Christopher Tse [11-03-22 - 10:43]
Renamed RPChatBubbles to Speaker Bee. Added Sound Effects. Switched to Dragonflight Settings. Added font size setting. Added shadow load setting. Bumped version to 10.0.0
Filename
BlizzChatIntegration.lua
ChatBubblePool.lua
MainFrame.lua
MainFrame.xml
README.md
RoleplayChatBubbles.toc
Settings.lua
Settings.xml
SpeakerBee.toc
diff --git a/BlizzChatIntegration.lua b/BlizzChatIntegration.lua
index c57dbb0..0258015 100644
--- a/BlizzChatIntegration.lua
+++ b/BlizzChatIntegration.lua
@@ -46,14 +46,14 @@ local function printTable(t, depth)
 	end
 end

-local function getChatBubbleText(chatBubble)
+local function getChatBubbleFontString(chatBubble)
 	--9.0.1 put frame data into a child of the bubble. I think this is a part of the backdrop api change. But anyway,
 	--we're just going to assume that the frame data is the first element of the chat bubble table.
 	chatBubbleFrame = select(1,chatBubble:GetChildren());
 	for i = 1, chatBubbleFrame:GetNumRegions() do
 		local region = select(i, chatBubbleFrame:GetRegions())
 		if region:GetObjectType() == "FontString" then
-			return region:GetText()
+			return region
 		end
 	end
 end
@@ -69,12 +69,17 @@ local function getNamedPoint(chatBubble,pointName)
 end

 local function skinBubble(chatBubble)
-	local message = getChatBubbleText(chatBubble);
+	local fontString = getChatBubbleFontString(chatBubble);
+	local message = fontString:GetText()
 	local name = messageToSender[message]
+	local fontSize = settings.get("FONT_SIZE");
 	if (name == nil) then
 		name = "";
 	end

+	local fontPath, _, fontFlags = fontString:GetFont();
+	fontString:SetFont(fontPath, fontSize, fontFlags);
+
 	local NameText = CreateFrame("EditBox","BlizzBoxNameText",chatBubble);
 	NameText:SetFrameStrata("MEDIUM"); --This is the default but better to be explicit
 	--NameText:SetMultiLine(true);
@@ -158,8 +163,9 @@ local function checkBubbles(chatBubbles)
 			if not chatBubble.rpSkinned then
 				skinBubble(chatBubble)
 			else
-				local message = getChatBubbleText(chatBubble)
-				local sender = messageToSender[message]
+				local fontString = getChatBubbleFontString(chatBubble);
+				local message = fontString:GetText();
+				local sender = messageToSender[message];
 				if sender == nil then
 					sender = "";
 				end
@@ -175,16 +181,16 @@ Timer:SetScript("OnUpdate", function(self, elapsed)
 	if self.elapsed > 0.01 then
 		self:Stop();
 		--This returns all chat bubbles created through default Blizz's UI. Custom chat bubbles aren't seen here
-		chatBubbles = C_ChatBubbles:GetAllChatBubbles()
-		checkBubbles(chatBubbles)
+		local chatBubbles = C_ChatBubbles:GetAllChatBubbles();
+		checkBubbles(chatBubbles);
 	end
 end)

 local function onChatMessage(_, event, message, sender, ...)
 	local name = GetColoredName(event, message, sender, ...);
-	messageInBubble = message:gsub("|c%w%w%w%w%w%w%w%w(.*)|r","%1"); --Replace colours
+	local messageInBubble = message:gsub("|c%w%w%w%w%w%w%w%w(.*)|r","%1"); --Replace colours
 	messageInBubble = messageInBubble:gsub("|H.*|h%[(.*)%]|h", "%1") --Replace hyperlinks
-	messageInBubble, count = messageInBubble:gsub("{rt[1-8]}","|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_%1:0|t"); --Replace raid icons
+	messageInBubble = messageInBubble:gsub("{rt[1-8]}","|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_%1:0|t"); --Replace raid icons
 	messageToSender[messageInBubble] = name;
 	--At the time of the chat event, the chat bubble hasn't been created yet. So we'll wait 0.01 seconds before looking for chat bubbles to skin.
 	Timer:Start();
diff --git a/ChatBubblePool.lua b/ChatBubblePool.lua
index 0879af3..a682a12 100644
--- a/ChatBubblePool.lua
+++ b/ChatBubblePool.lua
@@ -3,11 +3,16 @@

 local ADDON_NAME, Import = ...;

+local settings;
 local pool = {}

 Import.ChatBubblePool = {};
 local ChatBubblePool = Import.ChatBubblePool

+local function OnStart(self)
+	settings = Import.settings;
+end
+
 local function setChatBubbleWidth(chatBubbleBg, parent, width)
 	chatBubbleBg:SetPoint("TOPLEFT",parent,"TOP",-width/2,16);
 	chatBubbleBg:SetPoint("BOTTOMLEFT",parent,"BOTTOM",-width/2,-16);
@@ -66,6 +71,7 @@ local function closeBubble(chatBubble)
 	chatBubble:Hide();
 	chatBubble:SetMessage("");
 	chatBubble:SetName("");
+	PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON);

 	chatBubble.nameBox:SetAlpha(0.01)
 	chatBubble:ClearAllPoints();
@@ -239,16 +245,7 @@ local function clearFocusAndSelection(editBox)
 	editBox:HighlightText(0,0);
 end

-function ChatBubblePool.getChatBubble()
-	for index, chatBubble in ipairs(pool) do
-		if chatBubble.isAvailable then
-			chatBubble:Show()
-			chatBubble.isAvailable = false;
-			return chatBubble
-		end
-	end
-
-	-- If we got here, there isn't any available chat bubble so create a new one
+local function createChatBubble(fontSize)
 	local frameName = "RPChatBubble" .. #pool

 	local newChatBubble = CreateFrame("Frame",frameName,nil)
@@ -268,13 +265,16 @@ function ChatBubblePool.getChatBubble()

 	local editBox = CreateFrame("EditBox",frameName.."-EditBox",newChatBubble);
 	editBox:SetPoint("TOPLEFT",newChatBubble);
-	editBox:SetPoint("TOPRIGHT",newChatBubble);
+	editBox:SetPoint("TOPRIGHT",newChatBubble);
 	editBox:SetMultiLine(true);
 	editBox:SetAutoFocus(false);
 	editBox:SetFontObject("ChatBubbleFont");
 	editBox:SetJustifyH("CENTER");
 	editBox:SetScript("OnEnterPressed", function(self) if IsShiftKeyDown() then self:Insert("\n") else self:ClearFocus() end end);
 	editBox:SetScript("OnEscapePressed",clearFocusAndSelection);
+
+	local fontPath, _, fontFlags = editBox:GetFont();
+	editBox:SetFont(fontPath, fontSize, fontFlags);
 	--Apparently, the below code stops the user from being able to change the cursor location
 	--editBox:EnableMouse(true)
 	--editBox:SetScript("OnMouseDown", function(self) newChatBubble:StartMoving() end )
@@ -303,7 +303,8 @@ function ChatBubblePool.getChatBubble()
 	--We use an invisible FontString to measure the length of the text inside the edit box.
 	editBox.stringMeasure = editBox:CreateFontString(nil,"OVERLAY","ChatBubbleFont");
 	editBox.stringMeasure:SetAlpha(0);
-	editBox:SetScript("OnTextChanged", function(self)
+	editBox.stringMeasure:SetFont(fontPath, fontSize, fontFlags);
+	editBox:SetScript("OnTextChanged", function(self)
 	    editBox.stringMeasure:SetText(self:GetText());
 		adjustChatBubbleWidth(newChatBubble);
 		checkTailBounds(newChatBubble);
@@ -311,8 +312,7 @@ function ChatBubblePool.getChatBubble()

 	--This is a hack that centers the newChatBubble using the center of the editbox
 	newChatBubble.center = { x=chatBubbleBackground:GetWidth()/2, y=chatBubbleBackground:GetHeight()/2 };
-	newChatBubble:SetPoint("TOP",WorldFrame,"CENTER",0,newChatBubble.center.y);
-
+	newChatBubble:SetPoint("TOP", WorldFrame, "CENTER", 0, newChatBubble.center.y);

 	local closeButton = CreateFrame("Button",frameName.."-CloseButton",chatBubbleBackground,"UIPanelCloseButton")
 	closeButton:SetFrameLevel("21");
@@ -368,7 +368,7 @@ function ChatBubblePool.getChatBubble()
 		adjustNameBoxWidth(newChatBubble)
 		adjustChatBubbleWidth(newChatBubble)
 	end);
-
+
 	local midTex = nameBoxBackground:CreateTexture("nameBoxBackgroundTex-middle","BACKGROUND");
 	midTex:SetTexture("Interface/CHATFRAME/ChatFrameTab-BGMid.blp");
 	midTex:SetPoint("TOPLEFT",16,0);
@@ -381,7 +381,7 @@ function ChatBubblePool.getChatBubble()
 	rightTex:SetTexture("Interface/CHATFRAME/ChatFrameTab-BGRight.blp");
 	rightTex:SetPoint("TOPLEFT",midTex,"TOPRIGHT");
 	rightTex:SetPoint("BOTTOMLEFT",midTex,"BOTTOMRIGHT");
-
+
 	local nameBoxColorPicker = CreateFrame("Button",frameName.."-ColorPickerButton",newChatBubble);
 	nameBoxColorPicker:SetSize(16,16);
 	nameBoxColorPicker:SetFrameLevel("25") -- Needs to be higher than the EditBox to override it
@@ -412,7 +412,7 @@ function ChatBubblePool.getChatBubble()
 	tail.minY = 8;
 	tail:SetPoint("TOPLEFT",chatBubbleBackground,"BOTTOMLEFT",tail.minX,tail.bottomOffset)
 	tail.side = "BOTTOM";
-	tail.Reset = function(self)
+	tail.Reset = function(self)
 		self.tex:SetRotation(0);
 		self:ClearAllPoints();
 		self:SetPoint("TOPLEFT",chatBubbleBackground,"BOTTOMLEFT",tail.minX,tail.bottomOffset);
@@ -429,13 +429,13 @@ function ChatBubblePool.getChatBubble()

 	--Functions for outside use
 	newChatBubble.GetName = nameBox.GetText;
-	newChatBubble.SetName = function(self,name)
-		if (name == nil) then name = ""; end;
-		nameBox:SetText(name);
+	newChatBubble.SetName = function(self,name)
+		if (name == nil) then name = ""; end;
+		nameBox:SetText(name);
 		if (name ~= "" ) then
-			nameBox:SetAlpha(1)
+			nameBox:SetAlpha(1)
 		else
-			nameBox:SetAlpha(0);
+			nameBox:SetAlpha(0);
 		end;
 	end;
 	newChatBubble.GetMessage = editBox.GetText;
@@ -444,6 +444,10 @@ function ChatBubblePool.getChatBubble()
 	newChatBubble.SetNameColor = function(self,r,g,b) nameBox:SetTextColor(r,g,b); nameBox.colorPickerTex:SetColorTexture(r,g,b) end;
 	newChatBubble.GetTextColor = function(self) return editBox:GetTextColor() end;
 	newChatBubble.SetTextColor = function(self,r,g,b) editBox:SetTextColor(r,g,b) end;
+	newChatBubble.SetFontSize = function(self,fontSize)
+		editBox:SetFont(fontPath, fontSize, fontFlags);
+		editBox.stringMeasure:SetFont(fontPath, fontSize, fontFlags);
+	end

 	local origR,origG,origB = nameBox:GetTextColor();
 	newChatBubble.ResetNameColor = function(self) self:SetNameColor(origR,origG,origB); end;
@@ -451,6 +455,20 @@ function ChatBubblePool.getChatBubble()
 	return newChatBubble
 end

+function ChatBubblePool.getChatBubble()
+	for index, chatBubble in ipairs(pool) do
+		if chatBubble.isAvailable then
+			chatBubble:Show();
+			chatBubble.isAvailable = false;
+			chatBubble:SetFontSize(settings.get("FONT_SIZE"));
+			return chatBubble
+		end
+	end
+
+	-- If we got here, there isn't any available chat bubble so create a new one
+	return createChatBubble(settings.get("FONT_SIZE"));
+end
+
 local function doEvent(self, event, ...)
 	if event == "PLAY_MOVIE" then
 		closeBubbles()
@@ -465,4 +483,6 @@ local frame = CreateFrame("FRAME","ChatBubbleEventHandler");
 frame:RegisterEvent("PLAY_MOVIE");
 frame:RegisterEvent("CINEMATIC_START");
 frame:RegisterEvent("CINEMATIC_STOP");
-frame:SetScript("OnEvent",doEvent);
\ No newline at end of file
+frame:SetScript("OnEvent",doEvent);
+
+Import.ChatBubblePool.OnStart = OnStart;
\ No newline at end of file
diff --git a/MainFrame.lua b/MainFrame.lua
index 3aff316..040e419 100644
--- a/MainFrame.lua
+++ b/MainFrame.lua
@@ -17,16 +17,17 @@ function RPChatBubbles_OnLoad(self, event,...)
     self:RegisterEvent("ADDON_LOADED");
 	self:RegisterEvent("MODIFIER_STATE_CHANGED");
 	self:RegisterEvent("PLAYER_TARGET_CHANGED");
-	self:SetBackdrop(BACKDROP_DIALOG_32_32)
-	self:OnBackdropLoaded()
+	self:SetBackdrop(BACKDROP_DIALOG_32_32);
+	self:OnBackdropLoaded();
 end

 function RPChatBubbles_OnEvent(self, event, ...)
-     if event == "ADDON_LOADED" and ... == ADDON_NAME then
+	if event == "ADDON_LOADED" and ... == ADDON_NAME then
 		Import:initSettings();
 		settings = Import.settings;
 		sharedFunctions = Import.SharedFunctions;
 		initMainFrame(self);
+		ChatBubblePool:OnStart();
 		for moduleName, moduleStructure in pairs(Import.modules) do
 			moduleStructure:OnStart();
 		end
@@ -39,11 +40,11 @@ function RPChatBubbles_OnEvent(self, event, ...)
 end

 function RPChatBubbles_createChatBubble()
+	PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON);
 	local bubble = ChatBubblePool.getChatBubble();
 	local textColor = settings.get("SELECTED_COLOR_RGB");
 	local selectedColor = settings.get("SELECTED_COLOR");
 	local GetUnitNameAndColor = Import.SharedFunctions.GetUnitNameAndColor;
-

 	local unitID = nil;

@@ -58,7 +59,7 @@ function RPChatBubbles_createChatBubble()
 	--If we are trying to populate the name field using shift or control, then enter this block.
 	--The method used will depend on whether TotalRP3 is installed or not
 	if unitID then
-		name, color = GetUnitNameAndColor(unitID);
+		local name, color = GetUnitNameAndColor(unitID);
 		if name then
 			bubble:SetName(name);
 			-- The Color will only be populated if TotalRP3 is enabled.
@@ -66,7 +67,7 @@ function RPChatBubbles_createChatBubble()
 			if color then
 				bubble:SetNameColor(color:GetRGB());
 			end
-		else
+		else
 			bubble:SetName("");
 		end
 	end
@@ -78,6 +79,7 @@ function RPChatBubbles_toggleVisibility()
 	else
 		settings.set("IS_FRAME_VISIBLE", true);
 	end
+	PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON);
 	SetVisibility(MainFrame, settings.get("IS_FRAME_VISIBLE"));
 end

@@ -99,7 +101,7 @@ function initMainFrame(self)
 	self:SetScript("OnDragStop", function(self)
 		self:StopMovingOrSizing();
 	end);
-	SetVisibility(self, settings.get("IS_FRAME_VISIBLE"));
+	SetVisibility(self, settings.get("IS_FRAME_VISIBLE"), true);
 end

 function handleKeyPress()
@@ -217,7 +219,7 @@ function cancelCustomColor()
 	settings.set("SELECTED_COLOR_RGB", previousColor);
 end

-function SetVisibility(self, visible)
+function SetVisibility(self, visible, init)
 	if visible then
 		self:SetAlpha(1.0);
 		removeVisibilityScripts(MainFrame);
@@ -225,15 +227,16 @@ function SetVisibility(self, visible)
 		removeVisibilityScripts(SettingsButton);
 		removeVisibilityScripts(HideButton);
 		removeVisibilityScripts(ColorDropdownButton);
-		HideButtonTexture:SetTexture("Interface/Addons/RoleplayChatBubbles/button/UI-hideButton");
+		HideButtonTexture:SetTexture("Interface/Addons/RoleplayChatBubbles/button/UI-showButton");
 	else
-		self:SetAlpha(0.5);
+		local showShadow = (not init) or settings.get("SHADOW_LOAD");
+		self:SetAlpha(showShadow and 0.5 or 0);
 		addVisibilityScripts(MainFrame);
 		addVisibilityScripts(CreateButton);
 		addVisibilityScripts(SettingsButton);
 		addVisibilityScripts(HideButton);
 		addVisibilityScripts(ColorDropdownButton);
-		HideButtonTexture:SetTexture("Interface/Addons/RoleplayChatBubbles/button/UI-showButton");
+		HideButtonTexture:SetTexture("Interface/Addons/RoleplayChatBubbles/button/UI-hideButton");
 	end
 end

diff --git a/MainFrame.xml b/MainFrame.xml
index c1f00b9..0e7bfcc 100644
--- a/MainFrame.xml
+++ b/MainFrame.xml
@@ -7,20 +7,9 @@
 		<Anchors>
 			<Anchor point="CENTER" x="-7" y="29" />
 		</Anchors>
-		<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
-			<BackgroundInsets>
-				<AbsInset left="11" right="12" top="12" bottom="11" />
-			</BackgroundInsets>
-			<TileSize>
-				<AbsValue val="32" />
-			</TileSize>
-			<EdgeSize>
-				<AbsValue val="32" />
-			</EdgeSize>
-		</Backdrop>
 		<Layers>
 			<Layer level="OVERLAY">
-				<FontString inherits="GameFontNormal" text="RP Chat Bubbles">
+				<FontString inherits="GameFontNormal" text="Speaker Bee">
 					<Size x="103" y="20" />
 					<Anchors>
 						<Anchor point="TOPLEFT" x="25" y="-14" />
@@ -35,7 +24,7 @@
 					<Anchor point="TOPLEFT" x="15" y="-35" />
 				</Anchors>
 				<Frames>
-					<Frame text="" name="ColorDropdownButton" inherits="UIDropDownMenuTemplate">
+					<Frame name="ColorDropdownButton" inherits="UIDropDownMenuTemplate">
 						<Size x="20" y="23" />
 						<Anchors>
 							<Anchor point="TOPLEFT" relativeTo="CreateButton" relativePoint="TOPRIGHT" x="-16" y="0" />
diff --git a/README.md b/README.md
index 11bc5a0..28eee4a 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-# RP Chat Bubbles
+# Speaker Bee

 ## About
 This is an immersion related addon for World of Warcraft that allows you to create customizable click-and-draggable chat bubbles. Useful for screenshots. Also adds the name of the person speaking to the chat bubbles.

 ## Installation
-You can install this addon through CurseForge's app. However, if you wish to download this manually, you can simply download this repository and put the RPChatBubbles folder into the addons folder of your WoW Installation, which is should be under \_retail\_/Interface/Addons
+You can install this addon through CurseForge's app. However, if you wish to download this manually, you can simply download this repository and put the SpeakerBee folder into the addons folder of your WoW Installation, which is should be under \_retail\_/Interface/Addons
diff --git a/RoleplayChatBubbles.toc b/RoleplayChatBubbles.toc
deleted file mode 100644
index 3fe54e1..0000000
--- a/RoleplayChatBubbles.toc
+++ /dev/null
@@ -1,10 +0,0 @@
-## Title: RoleplayChatBubbles
-## Version: 1.0
-## Author: Christopher Tse
-## Interface: 90207
-## OptionalDeps: totalRP3
-## SavedVariablesPerCharacter: settings
-
-Settings.xml
-ChatBubblePool.lua
-MainFrame.xml
diff --git a/Settings.lua b/Settings.lua
index a13bd75..a069216 100644
--- a/Settings.lua
+++ b/Settings.lua
@@ -8,15 +8,22 @@ defaultValue = {
 	DRESS_BLIZZ_BUBBLE = true,
 	SMART_COLORING = true,
 	CREATE_BUTTON_EXTRA_TEXT = true,
+	SHADOW_LOAD = true,

 	SELECTED_COLOR_RGB = { r = 1.0, g = 1.0, b = 1.0 },
 	SELECTED_COLOR = "Say",
 	CUSTOM_COLOR = { r = 1.0, g = 1.0, b = 1.0 },

 	GENERATE_TOTAL_RP3_BUBBLES = true,
-	GENERATE_TOTAL_RP3_BUBBLES_FOR_OTHER_PLAYERS = true
+	GENERATE_TOTAL_RP3_BUBBLES_FOR_OTHER_PLAYERS = true,
+
+	FONT_SIZE = 14
 }

+local temporaryValue = {}
+
+CategoryId = -1;
+
 function initSettings()
 	if settings == nil then
 		settings = {}
@@ -31,74 +38,189 @@ function initSettings()
 		settings[key] = value;
 	end
 	Import.settings = settings;
+	ConstructSettingsUI();
+	hooksecurefunc(SettingsPanel, "FinalizeCommit", CommitChanges);
 end

-function ConfigureFrameOnRuntime(self, event, ...)
-	--Check if TRP3 is installed and turn off the TRP3 options if it's not there.
-	if TRP3_API == nil then
-		totalRP3Header:SetFontObject("GameFontDisableLarge");
-		totalRP3GenerateOptionLabel:SetFontObject("GameFontDisable");
-		totalRP3GenerateOtherPlayerLabel:SetFontObject("GameFontDisable");
-		totalRP3GenerateCheck:Disable();
-		totalRP3GenerateOtherCheck:Disable();
-		NotInstalledLabel:Show();
+
+
+function CommitChanges()
+	local restartRequired = (temporaryValue.FONT_SIZE ~= nil and settings.FONT_SIZE ~= temporaryValue.FONT_SIZE) or
+	           (temporaryValue.DRESS_BLIZZ_BUBBLE ~= nil and settings.DRESS_BLIZZ_BUBBLE ~= temporaryValue.DRESS_BLIZZ_BUBBLE);
+
+
+	for key, value in pairs(temporaryValue) do
+		settings[key] = value;
 	end
-	self:RegisterForDrag("LeftButton");
-	self:SetScript("OnDragStart",self.StartMoving);
-	self:SetScript("OnDragStop",self.StopMovingOrSizing);
-	self:SetBackdrop(BACKDROP_DIALOG_32_32)
-	self:OnBackdropLoaded()
+
+	if (restartRequired) then
+		ReloadUI()
+	end
+	temporaryValue = {}
 end

-function ShowSettingsPanel()
-	if not SettingsPanel:IsVisible() then
-		SettingsPanel:Show()
-
-		DressBlizzBubbleCheck:SetChecked(settings.get("DRESS_BLIZZ_BUBBLE"));
-		ExtraTextCheck:SetChecked(settings.get("CREATE_BUTTON_EXTRA_TEXT"));
-		SmartColoringCheck:SetChecked(settings.get("SMART_COLORING"));
-		totalRP3GenerateCheck:SetChecked(settings.get("GENERATE_TOTAL_RP3_BUBBLES"));
-		totalRP3GenerateOtherCheck:SetChecked(settings.get("GENERATE_TOTAL_RP3_BUBBLES_FOR_OTHER_PLAYERS"));
-
-		TotalRP3_onStart();
-	else
-		CancelSettings();
+function ConstructSettingsUI()
+	local category, layout = Settings.RegisterVerticalLayoutCategory("Speaker Bee");
+
+	-- layout:AddInitializer(CreateSettingsListSectionHeaderInitializer("General"));
+	AddGeneralHeader(layout);
+	RegisterFontSize(category);
+	RegisterDressBlizzBubble(category);
+	RegisterCreateButtonExtraText(category);
+	RegisterSmartNameColours(category);
+	RegisterShadowLoad(category);
+
+	RegisterTotalRP3Settings(layout, category);
+
+	Settings.RegisterAddOnCategory(category)
+
+	CategoryId = category:GetID();
+end
+
+function AddGeneralHeader(layout)
+	local name = "TotalRP3";
+	local data = {name = name};
+	local topInitializer = Settings.CreateElementInitializer("SpeakerBeeGeneralHeader", data);
+	topInitializer = layout:AddInitializer(topInitializer);
+end
+
+function RegisterFontSize(category)
+	local variable = "FONT_SIZE";
+	local name = "Font Size";
+	local tooltip = "Controls the font size of all chat bubbles.";
+	local defaultValue = settings.get("FONT_SIZE");
+	local minValue = 8;
+	local maxValue = 128;
+	local step = 2;
+
+	local setting = Settings.RegisterAddOnSetting(category, name, variable, type(defaultValue), defaultValue);
+	setting:SetCommitFlags(Settings.CommitFlag.Apply);
+
+	local callback = function(o, s, value)
+		temporaryValue.FONT_SIZE = value;
+		ToggleRestartRequired();
 	end
+	Settings.SetOnValueChangedCallback(variable, callback);
+	local options = Settings.CreateSliderOptions(minValue, maxValue, step);
+
+	options:SetLabelFormatter(MinimalSliderWithSteppersMixin.Label.Right);
+	Settings.CreateSlider(category, setting, options, tooltip)
 end

-function ToggleReloadWarning(self, event, ...)
-	--This function detects if the user has changed the Dress Blizz Bubble setting, which will show a reload required message on changed.
-	if settings.DRESS_BLIZZ_BUBBLE ~= DressBlizzBubbleCheck:GetChecked() then
-		if not UIReloadWarningLabel:IsVisible() then
-			UIReloadWarningLabel:Show();
-			SettingsPanel:SetSize(SettingsPanel:GetWidth(),SettingsPanel:GetHeight()+UIReloadWarningLabel:GetHeight()+5);
-		end
-	else
-		if UIReloadWarningLabel:IsVisible() then
-			UIReloadWarningLabel:Hide();
-			SettingsPanel:SetSize(SettingsPanel:GetWidth(),SettingsPanel:GetHeight()-UIReloadWarningLabel:GetHeight()-5);
-		end
+function RegisterDressBlizzBubble(category)
+	local variable = "DRESS_BLIZZ_BUBBLE"
+    local name = "Dress Chat Bubbles"
+    local tooltip = "If checked, this puts the speaking character's name on regular chat bubbles"
+    local defaultValue = settings.get("DRESS_BLIZZ_BUBBLE");
+
+	local callback = function(o, s, value)
+		temporaryValue.DRESS_BLIZZ_BUBBLE = value;
+		ToggleRestartRequired();
 	end
+
+	local setting = Settings.RegisterAddOnSetting(category, name, variable, type(defaultValue), defaultValue);
+	setting:SetCommitFlags(Settings.CommitFlag.Apply);
+	Settings.SetOnValueChangedCallback(variable, callback);
+    Settings.CreateCheckBox(category, setting, tooltip);
 end

-function SaveSettings(self, event, ...)
-	local reloadRequired = settings.DRESS_BLIZZ_BUBBLE ~= DressBlizzBubbleCheck:GetChecked()
-
-	settings.DRESS_BLIZZ_BUBBLE = DressBlizzBubbleCheck:GetChecked();
-	settings.GENERATE_TOTAL_RP3_BUBBLES = totalRP3GenerateCheck:GetChecked();
-	settings.GENERATE_TOTAL_RP3_BUBBLES_FOR_OTHER_PLAYERS = totalRP3GenerateOtherCheck:GetChecked();
-	settings.SMART_COLORING = SmartColoringCheck:GetChecked();
-	settings.CREATE_BUTTON_EXTRA_TEXT = ExtraTextCheck:GetChecked();
-
-	SettingsPanel:Hide();
-	if reloadRequired then
-		ReloadUI()
+
+function RegisterCreateButtonExtraText(category)
+	local variable = "CREATE_BUTTON_EXTRA_TEXT"
+    local name = "Dynamic Create Button"
+    local tooltip = "If checked, the create button text will change to include (target) or (self) when shift or ctrl is held"
+    local defaultValue = settings.get("CREATE_BUTTON_EXTRA_TEXT")
+
+	local setting = Settings.RegisterAddOnSetting(category, name, variable, type(defaultValue), defaultValue);
+	Settings.SetOnValueChangedCallback(variable, function(o, s, value) temporaryValue.CREATE_BUTTON_EXTRA_TEXT = value; end);
+    Settings.CreateCheckBox(category, setting, tooltip);
+end
+
+function RegisterSmartNameColours(category)
+	local variable = "SMART_COLORING"
+    local name = "Smart Name Colouring"
+    local tooltip = "If checked, the colour of the name on custom chat bubbles will automatically select npc or player colours when shift or ctrl is held"
+    local defaultValue = settings.get("SMART_COLORING")
+
+	local setting = Settings.RegisterAddOnSetting(category, name, variable, type(defaultValue), defaultValue);
+	Settings.SetOnValueChangedCallback(variable, function(o, s, value) temporaryValue.SMART_COLORING = value; end);
+    Settings.CreateCheckBox(category, setting, tooltip);
+end
+
+function RegisterShadowLoad(category)
+	local variable = "SHADOW_LOAD"
+	local name = "Load Shadow Frame"
+	local tooltip = "If checked and the addon frame is hidden, the frame will show up as a shadow when the game loads until you mouse over it."
+	local defaultValue = settings.get("SHADOW_LOAD");
+
+	local setting = Settings.RegisterAddOnSetting(category, name, variable, type(defaultValue), defaultValue);
+	Settings.SetOnValueChangedCallback(variable, function(o, s, value) temporaryValue.SHADOW_LOAD = value; end);
+    Settings.CreateCheckBox(category, setting, tooltip);
+end
+function RegisterTotalRP3Settings(layout, category)
+    local totalRP3Installed = TRP3_API ~= nil;
+
+	local function isModifiable()
+		return totalRP3Installed;
 	end
+
+	AddTotalRP3Header(layout, totalRP3Installed)
+	RegisterGenerateTotalRP3BubbleSetting(category, layout, isModifiable);
+end
+
+function AddTotalRP3Header(layout, totalRP3Installed)
+	local headerTemplate = totalRP3Installed and "SettingsListSectionHeaderTemplate" or "TotalRP3SectionHeaderDisabled";
+	local name = "TotalRP3";
+	local data = {name = name};
+	layout:AddInitializer(Settings.CreateElementInitializer(headerTemplate, data));
 end

-function CancelSettings()
-	SettingsPanel:Hide();
+
+function RegisterGenerateTotalRP3BubbleSetting(category, layout, isModifiable)
+	local variable = "GENERATE_TOTAL_RP3_BUBBLES"
+    local name = "Enable NPC Speech Bubbles"
+    local tooltip = "If checked, a chat bubble is created whenever you use the NPC speech feature of TotalRP3"
+    local defaultValue = settings.get("GENERATE_TOTAL_RP3_BUBBLES");
+
+	local setting = Settings.RegisterAddOnSetting(category, name, variable, type(defaultValue), defaultValue);
+	Settings.SetOnValueChangedCallback(variable, function(o, s, value) temporaryValue.GENERATE_TOTAL_RP3_BUBBLES = value; end);
+    local initializer = Settings.CreateCheckBox(category, setting, tooltip);
+	initializer:AddModifyPredicate(isModifiable);
+
+	RegisterGenerateTotalRP3BubbleForOthersSetting(category, initializer, isModifiable);
+end
+
+function RegisterGenerateTotalRP3BubbleSettingForSelf(category, parent, isModifiable)
+
+end
+
+function RegisterGenerateTotalRP3BubbleForOthersSetting(category, parent, isModifiable)
+	local variable = "GENERATE_TOTAL_RP3_BUBBLES_FOR_OTHER_PLAYERS"
+    local name = "From other players"
+    local tooltip = "If checked, a chat bubble is created whenever you use the NPC speech feature of TotalRP3"
+    local defaultValue = settings.get("GENERATE_TOTAL_RP3_BUBBLES_FOR_OTHER_PLAYERS");
+
+	local setting = Settings.RegisterAddOnSetting(category, name, variable, type(defaultValue), defaultValue);
+	Settings.SetOnValueChangedCallback(variable, function(o, s, value) temporaryValue.GENERATE_TOTAL_RP3_BUBBLES_FOR_OTHER_PLAYERS = value; end);
+    local initializer = Settings.CreateCheckBox(category, setting, tooltip);
+	initializer:SetParentInitializer(parent, isModifiable);
+end
+
+function ToggleRestartRequired()
+	if ((temporaryValue.FONT_SIZE ~= nil and temporaryValue.FONT_SIZE ~= settings.FONT_SIZE) or
+        (temporaryValue.DRESS_BLIZZ_BUBBLE ~= nil and temporaryValue.DRESS_BLIZZ_BUBBLE ~= settings.DRESS_BLIZZ_BUBBLE)) then
+		    SpeakerBeeRestartRequired:Show();
+		else
+			SpeakerBeeRestartRequired:Hide();
+	end
+end
+
+
+
+function ShowSettingsPanel()
+	PlaySound(SOUNDKIT.IG_MAINMENU_OPEN);
+	SettingsPanel:OpenToCategory(CategoryId);
 end

 Import.initSettings = initSettings;
-Import.ShowSettingsPanel = ShowSettingsPanel
\ No newline at end of file
+Import.ShowSettingsPanel = ShowSettingsPanel;
\ No newline at end of file
diff --git a/Settings.xml b/Settings.xml
index 95eec72..21277f3 100644
--- a/Settings.xml
+++ b/Settings.xml
@@ -1,146 +1,65 @@
 <Ui xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.blizzard.com/wow/ui/">
 	<Script file="Settings.lua" />
-	<Frame name="SettingsPanel" hidden="true" parent="UIParent" toplevel="true" movable="true" enableMouse="true" inherits="BackdropTemplate">
-		<Size>
-			<AbsDimension x="546" y="270" />
-		</Size>
-		<Anchors>
-			<Anchor point="CENTER" x="22" y="-24" />
-		</Anchors>
-		<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
-			<BackgroundInsets>
-				<AbsInset left="11" right="12" top="12" bottom="11" />
-			</BackgroundInsets>
-			<TileSize>
-				<AbsValue val="32" />
-			</TileSize>
-			<EdgeSize>
-				<AbsValue val="32" />
-			</EdgeSize>
-		</Backdrop>
+
+	<Frame name="SpeakerBeeGeneralHeader" virtual="true">
+		<Size y="45"/>
 		<Layers>
 			<Layer level="OVERLAY">
-				<FontString name="Header" inherits="GameFontNormalHuge" text="Settings" justifyH="LEFT">
-					<Size x="80" y="20" />
-					<Anchors>
-						<Anchor point="TOPLEFT" x="17" y="-18" />
-					</Anchors>
-				</FontString>
-				<FontString name="GeneralHeader" inherits="GameFontNormalLargeLeft" text="General">
-					<Size x="80" y="20" />
-					<Anchors>
-						<Anchor point="TOPLEFT" x="25" y="-45" />
-					</Anchors>
-				</FontString>
-				<FontString name="DressBlizzBubbleLabel" inherits="GameFontHighlightLeft" text="Put name on regular chat bubbles?">
-					<Size x="419" y="20" />
-					<Anchors>
-						<Anchor point="TOPLEFT" x="25" y="-72" />
-					</Anchors>
-				</FontString>
-				<FontString name="totalRP3Header" inherits="GameFontNormalLarge" text="TotalRP3" justifyH="LEFT">
-					<Size x="80" y="20" />
-					<Anchors>
-						<Anchor point="TOPLEFT" x="25" y="-145" />
-					</Anchors>
-				</FontString>
-				<FontString name="totalRP3GenerateOptionLabel" inherits="GameFontHighlight" text="Generate chat bubbles for NPC Speeches?" justifyH="LEFT">
-					<Size x="419" y="20" />
-					<Anchors>
-						<Anchor point="TOPLEFT" x="25" y="-172" />
-					</Anchors>
-				</FontString>
-				<FontString name="totalRP3GenerateOtherPlayerLabel" inherits="GameFontHighlight" text="Generate chat bubbles for NPC Speeches by other players?" justifyH="LEFT">
-					<Size x="436" y="20" />
+				<FontString name="SpeakerBeeGeneralText" inherits="GameFontHighlightLarge" text="General" justifyH="LEFT">
 					<Anchors>
-						<Anchor point="TOPLEFT" x="25" y="-194" />
+						<Anchor point="TOPLEFT" x="7" y="-16"/>
 					</Anchors>
 				</FontString>
-				<FontString name="NotInstalledLabel" inherits="GameFontRed" hidden="true" text="(Not Installed)" justifyH="LEFT">
-					<Size x="100" y="20" />
+				<FontString name="SpeakerBeeRestartRequired" inherits="GameFontRed" text="UI Reload Required" justifyH="LEFT" hidden="true">
 					<Anchors>
-						<Anchor point="TOPLEFT" relativeTo="totalRP3Header" relativePoint="TOPRIGHT" x="5" y="0" />
+						<Anchor point="BOTTOMLEFT" relativePoint="BOTTOMRIGHT" relativeTo="SpeakerBeeGeneralText" x="8"></Anchor>
 					</Anchors>
-					<Color r="0.784" g="0.102" b="0.102" />
 				</FontString>
-				<FontString name="UIReloadWarningLabel" inherits="GameFontRed" hidden="true" text="UI Reload Required." justifyH="LEFT">
-					<Size x="299" y="20" />
+			</Layer>
+		</Layers>
+	</Frame>
+
+	<Frame name="SpeakerBeeTRP3GenerateSubheader" mixin="SettingsListElementMixin" virtual="true">
+		<Size x="280" y="26"/>
+		<Layers>
+			<Layer level="OVERLAY">
+				<FontString parentKey="Text" inherits="GameFontNormal" justifyH="LEFT" wordwrap="false"/>
+			</Layer>
+		</Layers>
+		<Scripts>
+			<OnLoad method="OnLoad"/>
+		</Scripts>
+	</Frame>
+
+	<Frame name="TotalRP3SectionHeader" mixin="SettingsListSectionHeaderMixin" virtual="true">
+		<Size y="45"/>
+		<Layers>
+			<Layer level="OVERLAY">
+				<FontString parentKey="Title" inherits="GameFontHighlightLarge" justifyH="LEFT" justifyV="TOP">
 					<Anchors>
-						<Anchor point="TOPLEFT" x="25" y="-224" />
+						<Anchor point="TOPLEFT" x="7" y="-16"/>
 					</Anchors>
 				</FontString>
-				<FontString name="ExtraTextLabel" inherits="GameFontHighlightLeft" text="Update &quot;Create&quot; button text when holding ctrl/shift">
-					<Size x="462" y="20" />
+			</Layer>
+		</Layers>
+	</Frame>
+
+	<Frame name="TotalRP3SectionHeaderDisabled" mixin="SettingsListSectionHeaderMixin" virtual="true">
+		<Size y="45"/>
+		<Layers>
+			<Layer level="OVERLAY">
+				<FontString name="totalRP3Header2" parentKey="Title" inherits="GameFontDisableLarge" text="TotalRP3" justifyH="LEFT">
 					<Anchors>
-						<Anchor point="TOPLEFT" x="25" y="-94" />
+						<Anchor point="TOPLEFT" x="7" y="-16"/>
 					</Anchors>
 				</FontString>
-				<FontString name="SmartColoringLabel" inherits="GameFontHighlightLeft" text="Auto switch between player/npc colours when creating for target/self">
-					<Size x="462" y="20" />
+				<FontString name="NotInstalledLabel" inherits="GameFontRed" text="(Not Installed)" justifyH="LEFT">
 					<Anchors>
-						<Anchor point="TOPLEFT" x="25" y="-118" />
+						<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="totalRP3Header2" x="5" y="0" />
 					</Anchors>
 				</FontString>
 			</Layer>
 		</Layers>
-		<Frames>
-			<CheckButton name="totalRP3GenerateCheck" inherits="UICheckButtonTemplate" text="CheckButton1">
-				<Anchors>
-					<Anchor point="TOPLEFT" x="493" y="-164" />
-				</Anchors>
-			</CheckButton>
-			<CheckButton name="totalRP3GenerateOtherCheck" inherits="UICheckButtonTemplate" text="CheckButton2">
-				<Anchors>
-					<Anchor point="TOPLEFT" x="493" y="-188" />
-				</Anchors>
-			</CheckButton>
-			<Button name="OkayButton" inherits="UIPanelButtonTemplate" text="Okay">
-				<Size x="253" y="23" />
-				<Anchors>
-					<Anchor point="BOTTOMLEFT" x="17" y="21" />
-				</Anchors>
-				<Scripts>
-					<OnClick function="SaveSettings">
-
-					</OnClick>
-				</Scripts>
-			</Button>
-			<Button name="CancelButton" inherits="UIPanelButtonTemplate" text="Cancel">
-				<Size x="247" y="23" />
-				<Anchors>
-					<Anchor point="BOTTOMLEFT" x="276" y="21" />
-				</Anchors>
-				<Scripts>
-					<OnClick function="CancelSettings">
-
-					</OnClick>
-				</Scripts>
-			</Button>
-			<CheckButton name="SmartColoringCheck" inherits="UICheckButtonTemplate" text="CheckButton1">
-				<Anchors>
-					<Anchor point="TOPLEFT" x="493" y="-113" />
-				</Anchors>
-			</CheckButton>
-			<CheckButton name="DressBlizzBubbleCheck" inherits="UICheckButtonTemplate" text="CheckButton1">
-				<Anchors>
-					<Anchor point="TOPLEFT" x="493" y="-65" />
-				</Anchors>
-				<Scripts>
-					<OnClick function="ToggleReloadWarning">
-
-					</OnClick>
-				</Scripts>
-			</CheckButton>
-			<CheckButton name="ExtraTextCheck" inherits="UICheckButtonTemplate" text="CheckButton1">
-				<Anchors>
-					<Anchor point="TOPLEFT" x="493" y="-89" />
-				</Anchors>
-			</CheckButton>
-		</Frames>
-		<Scripts>
-			<OnLoad function="ConfigureFrameOnRuntime">
-
-			</OnLoad>
-		</Scripts>
 	</Frame>
+
 </Ui>
\ No newline at end of file
diff --git a/SpeakerBee.toc b/SpeakerBee.toc
new file mode 100644
index 0000000..0b83ec5
--- /dev/null
+++ b/SpeakerBee.toc
@@ -0,0 +1,10 @@
+## Title: Speaker Bee
+## Version: 1.0
+## Author: Christopher Tse
+## Interface: 100000
+## OptionalDeps: totalRP3
+## SavedVariablesPerCharacter: settings
+
+Settings.xml
+ChatBubblePool.lua
+MainFrame.xml