-------------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Options Detached Frames
-- Author: Mik
-------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------
-- Private constants.
-------------------------------------------------------------------------------------

local OPTIONS_FRAME_NAME = "MSBTFrameOptions";
local DETACHED_INPUT_FRAME_NAME = "MSBTDetachedInputFrame";
local ACKNOWLEDGE_FRAME_NAME = "MSBTAcknowledgeFrame";
local FONT_CONFIG_FRAME_NAME = "MSBTFontConfigFrame";
local PARTIAL_EFFECTS_CONFIG_FRAME_NAME = "MSBTPartialEffectsConfigFrame";
local DAMAGE_COLORS_CONFIG_FRAME_NAME = "MSBTDamageColorsConfigFrame";
local SCROLL_AREAS_CONFIG_FRAME_NAME = "MSBTScrollAreasConfigFrame";
local SCROLL_AREA_SELECTION_FRAME_NAME = "MSBTScrollAreaSelectionFrame";
local TRIGGER_CONFIG_FRAME_NAME = "MSBTTriggerConfigFrame";
local TRIGGER_CONFIG_CLASSES_FRAME_NAME = "MSBTTriggerConfigClassesFrame";
local TRIGGER_CONFIG_CONDITION_FRAME_NAME = "MSBTTriggerConfigConditionFrame";
local TRIGGER_CONFIG_EVENT_TYPES_FRAME_NAME = "MSBTTriggerConfigEventTypesFrame";

-- None, Thin, Thick
local OUTLINE_MAP = {"", "OUTLINE", "THICKOUTLINE"};


-------------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------------

-- Tables to hold the various dropdown options.
local fontDropdownOptions = {};
local fontDropdownInheritOptions = {};
local outlineDropdownOptions = {};
local outlineDropdownInheritOptions = {};
local scrollAreaDropdownOptions = {};
local animationStyleDropdownOptions = {};
local stickyAnimStyleDropdownOptions = {};
local triggerMainConditionDropdownOptions = {};
local triggerSecondaryConditionDropdownOptions = {};


-- Holds the supported trigger events.
local supportedTriggerEvents = {};

-- Holds a map of what controls to show for trigger condition types.
local conditionControlMap = {};

-- Tables to hold temp settings.
local fontSettingsTable = {};
local originalScrollAreaSettings = {};
local tempScrollAreaSettings;
local tempTriggerClasses = {};
local tempMainConditions = {};
local tempMainConditionParams = {};
local tempSecondaryConditions = {};
local tempSecondaryConditionParams = {};
local tempTriggerEvents = {};

-- Scroll area mover frames.
local scrollAreaMoverFrames = {};


-------------------------------------------------------------------------------------
-- Detached input frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the detached input frame.
-- **********************************************************************************
function MikSBTOpt.InitDetachedInputFrame()
 -- Setup the okay and cancel buttons for the detached input frame.
 local key = "InputOkayButton";	MikSBTOpt.SetupButton(DETACHED_INPUT_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.DetachedInputFrameButtonOnClick);
 key = "InputCancelButton";		MikSBTOpt.SetupButton(DETACHED_INPUT_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.DetachedInputFrameButtonOnClick);
end

-- **********************************************************************************
-- Shows the detached input frame using the data supplied in the passed config table.
-- **********************************************************************************
function MikSBTOpt.ShowDetachedInputFrame(configTable)
 -- Don't do anything if the passed config table is invalid.
 if (not configTable) then return; end

 -- Hide all of the detached frames.
 MikSBTOpt.HideDetachedFrames()

 local detachedInputFrame = getglobal(DETACHED_INPUT_FRAME_NAME);
 detachedInputFrame.validateFunc = configTable.ValidateFunc;
 detachedInputFrame.saveFunc = configTable.SaveFunc;
 detachedInputFrame.customArg1 = configTable.CustomArg1;

 MikSBTOpt.SetupEditbox(DETACHED_INPUT_FRAME_NAME .. "InputEditbox", configTable.EditboxLabel, configTable.EditboxTooltip, MikSBTOpt.DetachedInputFrameOnTextChanged);
 MikSBTOpt.PopulateEditbox(DETACHED_INPUT_FRAME_NAME .. "InputEditbox", configTable.DefaultText);
 this = getglobal(DETACHED_INPUT_FRAME_NAME .. "InputEditbox");
 MikSBTOpt.DetachedInputFrameOnTextChanged();

 detachedInputFrame:ClearAllPoints();
 detachedInputFrame:SetPoint(configTable.AnchorPoint or "TOPLEFT", configTable.AnchorFrame, configTable.RelativePoint or "BOTTOMLEFT");
 detachedInputFrame:Show();
 detachedInputFrame:Raise();
end


-- **********************************************************************************
-- Called when the text in the input editbox changes.
-- **********************************************************************************
function MikSBTOpt.DetachedInputFrameOnTextChanged()
 local okayButton = getglobal(DETACHED_INPUT_FRAME_NAME .. "InputOkayButton");
 local validationText = getglobal(DETACHED_INPUT_FRAME_NAME .. "ValidationText");

 -- Clear validation message and enable the save button.
 validationText:SetText("");
 okayButton:Enable();

 -- Check if there is a validation function.
 if (getglobal(DETACHED_INPUT_FRAME_NAME).validateFunc) then
  -- Call the validation function with the new text in the editbox.
  local message = getglobal(DETACHED_INPUT_FRAME_NAME).validateFunc(this:GetText());

  -- Disable the save button and display the validation message if validation failed.
  if (message) then
   validationText:SetText(message);
   okayButton:Disable();
  end
 end
end


-- **********************************************************************************
-- Called when a button on the detached input frame is pressed.
-- **********************************************************************************
function MikSBTOpt.DetachedInputFrameOnEnterPressed()
 local okayButton = getglobal(DETACHED_INPUT_FRAME_NAME .. "InputOkayButton"); 
 if (okayButton:IsEnabled() ~= 0) then
  this = okayButton;
  MikSBTOpt.DetachedInputFrameButtonOnClick();
 end
end


-- **********************************************************************************
-- Called when a button on the detached input frame is pressed.
-- **********************************************************************************
function MikSBTOpt.DetachedInputFrameButtonOnClick()
 -- Okay button.
 if (string.find(this:GetName(), "InputOkayButton")) then
  -- Call the passed save function with the entered text, if there is one.
  if (getglobal(DETACHED_INPUT_FRAME_NAME).saveFunc) then
   getglobal(DETACHED_INPUT_FRAME_NAME).saveFunc(getglobal(DETACHED_INPUT_FRAME_NAME .. "InputEditbox"):GetText(), getglobal(DETACHED_INPUT_FRAME_NAME).customArg1);
  end
  getglobal(DETACHED_INPUT_FRAME_NAME):Hide();

 -- Cancel button.
 elseif (string.find(this:GetName(), "InputCancelButton")) then
  getglobal(DETACHED_INPUT_FRAME_NAME):Hide();
 end
end


-------------------------------------------------------------------------------------
-- Acknowledge frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the acknowledge frame.
-- **********************************************************************************
function MikSBTOpt.InitAcknowledgeFrame()
 -- Set the acknowledge text.
 getglobal(ACKNOWLEDGE_FRAME_NAME .. "Text"):SetText(MSBTLocale.MSG_ACKNOWLEDGE_TEXT);

 -- Setup the yes and no buttons for the acknowledge frame.
 MikSBTOpt.SetupButton(ACKNOWLEDGE_FRAME_NAME .. "AcknowledgeYesButton", YES, nil, MikSBTOpt.AcknowledgeFrameButtonOnClick);
 MikSBTOpt.SetupButton(ACKNOWLEDGE_FRAME_NAME .. "AcknowledgeNoButton", NO, nil, MikSBTOpt.AcknowledgeFrameButtonOnClick);
end

-- **********************************************************************************
-- Shows the acknowledge frame using the data supplied in the passed config table.
-- **********************************************************************************
function MikSBTOpt.ShowAcknowledgeFrame(configTable)
 -- Don't do anything if the passed config table is invalid.
 if (not configTable) then return; end

 -- Hide all of the detached frames.
 MikSBTOpt.HideDetachedFrames()

 local acknowledgeFrame = getglobal(ACKNOWLEDGE_FRAME_NAME);
 acknowledgeFrame.acknowledgeFunc = configTable.AcknowledgeFunc;
 acknowledgeFrame.customArg1 = configTable.CustomArg1;

 acknowledgeFrame:ClearAllPoints();
 local found, _, lineNumber = string.find(configTable.AnchorFrame:GetName(), "ScrollLine(%d+)");
 if (found and tonumber(lineNumber) <= 5) then
  acknowledgeFrame:SetPoint("TOPRIGHT", configTable.AnchorFrame, "BOTTOMRIGHT");
 elseif (found) then
  acknowledgeFrame:SetPoint("BOTTOMRIGHT", configTable.AnchorFrame, "TOPRIGHT");
 else
  acknowledgeFrame:SetPoint("TOPLEFT", configTable.AnchorFrame, "BOTTOMLEFT");
 end

 acknowledgeFrame:Show();
 acknowledgeFrame:Raise();
end


-- **********************************************************************************
-- Called when a button on the acknowledge frame is pressed.
-- **********************************************************************************
function MikSBTOpt.AcknowledgeFrameButtonOnClick()
 local acknowledgeFrame = getglobal(ACKNOWLEDGE_FRAME_NAME);

 -- Yes button.
 if (string.find(this:GetName(), "YesButton")) then
  -- Call the acknowledge function if there is one.
  if (acknowledgeFrame.acknowledgeFunc) then
   acknowledgeFrame.acknowledgeFunc(acknowledgeFrame.customArg1);
  end
  acknowledgeFrame:Hide();

 -- No button.
 elseif (string.find(this:GetName(), "NoButton")) then
  acknowledgeFrame:Hide();
 end
end


-------------------------------------------------------------------------------------
-- Font config frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the font configuration frame.
-- **********************************************************************************
function MikSBTOpt.InitFontConfigFrame()
 -- Populate the list of available outlines.
 for outlineIndex, outlineName in ipairs(MSBTLocale.OUTLINES) do
  table.insert(outlineDropdownOptions, {Name = outlineName, Value = outlineIndex});
 end

 -- Populate the list of available outlines including the inherit option.
 table.insert(outlineDropdownInheritOptions, {Name = MSBTLocale.MSG_INHERIT_TEXT, Value = 0});
 for outlineIndex, outlineName in ipairs(MSBTLocale.OUTLINES) do
  table.insert(outlineDropdownInheritOptions, {Name = outlineName, Value = outlineIndex});
 end

 -- Setup the inherit normal and crit font size checkboxes.
 local key = "InheritNormalFontSizeCheckbox";	MikSBTOpt.SetupCheckbox(FONT_CONFIG_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.FontConfigFrameCheckboxOnClick);
 key = "InheritCritFontSizeCheckbox";		MikSBTOpt.SetupCheckbox(FONT_CONFIG_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.FontConfigFrameCheckboxOnClick);

 -- Setup the normal and crit font size sliders
 key = "NormalFontSizeSlider";	MikSBTOpt.SetupSlider(FONT_CONFIG_FRAME_NAME .. key, MSBTLocale.SLIDERS[key].Label, MSBTLocale.SLIDERS[key].Tooltip, 12, 32, 2, MikSBTOpt.UpdateFontPreviews);
 key = "CritFontSizeSlider";		MikSBTOpt.SetupSlider(FONT_CONFIG_FRAME_NAME .. key, MSBTLocale.SLIDERS[key].Label, MSBTLocale.SLIDERS[key].Tooltip, 12, 32, 2, MikSBTOpt.UpdateFontPreviews);

 -- Set the normal and crit size font preview text.
 getglobal(FONT_CONFIG_FRAME_NAME .. "NormalPreviewText"):SetText(MSBTLocale.MSG_NORMAL_PREVIEW_TEXT);
 getglobal(FONT_CONFIG_FRAME_NAME .. "CritPreviewText"):SetText(MSBTLocale.MSG_CRIT);

 -- Setup the save and cancel buttons for the font config frame.
 key = "FontSaveButton";	MikSBTOpt.SetupButton(FONT_CONFIG_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.FontConfigFrameButtonOnClick);
 key = "FontCancelButton";	MikSBTOpt.SetupButton(FONT_CONFIG_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.FontConfigFrameButtonOnClick);

end


-- **********************************************************************************
-- Shows the font config frame using the data supplied in the passed config table.
-- **********************************************************************************
function MikSBTOpt.ShowFontConfigFrame(configTable)
 -- Don't do anything if the passed config table is invalid.
 if (not configTable) then return; end

 -- Hide all of the detached frames.
 MikSBTOpt.HideDetachedFrames()


 -- Get the font config frame.
 local fontConfigFrame = getglobal(FONT_CONFIG_FRAME_NAME);

 -- Set the title to the value in the passed config table.
 getglobal(FONT_CONFIG_FRAME_NAME .. "Title"):SetText(configTable.Title);

 -- Refresh the list of options for the font and outline dropdowns.
 MikSBTOpt.RefreshFontOptions();


 -- Get the correct fonts and outlines depending on if they can inherit or not.
 local dropdownOpts = fontDropdownOptions;
 local outlineOpts = outlineDropdownOptions;
 if (configTable.CanInherit) then
  dropdownOpts = fontDropdownInheritOptions;
  outlineOpts = outlineDropdownInheritOptions;
 end

 -- Setup and populate the normal font dropdown.
 local key = "NormalFontDropdown";	MikSBTOpt.SetupDropdown(FONT_CONFIG_FRAME_NAME .. key, MSBTLocale.DROPDOWNS[key].Label, MSBTLocale.DROPDOWNS[key].Tooltip, MikSBTOpt.UpdateFontPreviews, dropdownOpts);
 MikSBTOpt.PopulateDropdown(FONT_CONFIG_FRAME_NAME .. key, configTable.DefaultNormalFontName);

 -- Setup and populate the normal outline dropdown.
 key = "NormalOutlineDropdown";	MikSBTOpt.SetupDropdown(FONT_CONFIG_FRAME_NAME .. key, MSBTLocale.DROPDOWNS[key].Label, MSBTLocale.DROPDOWNS[key].Tooltip, MikSBTOpt.UpdateFontPreviews, outlineOpts);
 MikSBTOpt.PopulateDropdown(FONT_CONFIG_FRAME_NAME .. key, configTable.DefaultNormalOutlineIndex);


 -- Show the inherit normal font size checkbox and normal font size slider.
 getglobal(FONT_CONFIG_FRAME_NAME .. "InheritNormalFontSizeCheckbox"):Show();
 getglobal(FONT_CONFIG_FRAME_NAME .. "NormalFontSizeSlider"):Show();

 -- Populate the normal font size.
 MikSBTOpt.PopulateSlider(FONT_CONFIG_FRAME_NAME .. "NormalFontSizeSlider", configTable.DefaultNormalFontSize);

 -- Check if the normal font size is inherited.
 if (configTable.DefaultNormalFontSize == 0) then
  -- Check the inherit normal font size checkbox and hide the normal font size sider.
  MikSBTOpt.PopulateCheckbox(FONT_CONFIG_FRAME_NAME .. "InheritNormalFontSizeCheckbox", true);
  getglobal(FONT_CONFIG_FRAME_NAME .. "NormalFontSizeSlider"):Hide();
 else
  -- Uncheck the inherit normal font size checkbox.
  MikSBTOpt.PopulateCheckbox(FONT_CONFIG_FRAME_NAME .. "InheritNormalFontSizeCheckbox", false);
 end

 -- Hide the inherit normal font size checkbox if inheritance is disabled.
 if (not configTable.CanInherit) then
  getglobal(FONT_CONFIG_FRAME_NAME .. "InheritNormalFontSizeCheckbox"):Hide();
 -- Inheritance is enabled, so copy the inherited values.
 else
  fontConfigFrame.InheritedNormalFontName = configTable.InheritedNormalFontName;
  fontConfigFrame.InheritedNormalOutlineIndex = configTable.InheritedNormalOutlineIndex;
  fontConfigFrame.InheritedNormalFontSize = configTable.InheritedNormalFontSize;
 end


 -- Check if the crit settings should be setup and shown.
 if (configTable.CanCrit) then
  -- Setup and show the crit font dropdown.
  key = "CritFontDropdown";	MikSBTOpt.SetupDropdown(FONT_CONFIG_FRAME_NAME .. key, MSBTLocale.DROPDOWNS[key].Label, MSBTLocale.DROPDOWNS[key].Tooltip, MikSBTOpt.UpdateFontPreviews, dropdownOpts);
  MikSBTOpt.PopulateDropdown(FONT_CONFIG_FRAME_NAME .. key, configTable.DefaultCritFontName);
  getglobal(FONT_CONFIG_FRAME_NAME .. key):Show();

  -- Setup and show the crit outline dropdown.
  key = "CritOutlineDropdown";	MikSBTOpt.SetupDropdown(FONT_CONFIG_FRAME_NAME .. key, MSBTLocale.DROPDOWNS[key].Label, MSBTLocale.DROPDOWNS[key].Tooltip, MikSBTOpt.UpdateFontPreviews, outlineOpts);
  MikSBTOpt.PopulateDropdown(FONT_CONFIG_FRAME_NAME .. key, configTable.DefaultCritOutlineIndex);
  getglobal(FONT_CONFIG_FRAME_NAME .. key):Show();


  -- Show the inherit crit font size checkbox and crit font size slider.
  getglobal(FONT_CONFIG_FRAME_NAME .. "InheritCritFontSizeCheckbox"):Show();
  getglobal(FONT_CONFIG_FRAME_NAME .. "CritFontSizeSlider"):Show();

  -- Populate the crit font size.
  MikSBTOpt.PopulateSlider(FONT_CONFIG_FRAME_NAME .. "CritFontSizeSlider", configTable.DefaultCritFontSize);

  -- Check if the crit font size is inherited.
  if (configTable.DefaultCritFontSize == 0) then
   -- Check the inherit crit font size checkbox and hide the crit font size sider.
   MikSBTOpt.PopulateCheckbox(FONT_CONFIG_FRAME_NAME .. "InheritCritFontSizeCheckbox", true);
   getglobal(FONT_CONFIG_FRAME_NAME .. "CritFontSizeSlider"):Hide();
  else
   -- Uncheck the inherit crit font size checkbox.
   MikSBTOpt.PopulateCheckbox(FONT_CONFIG_FRAME_NAME .. "InheritCritFontSizeCheckbox", false);
  end

  -- Hide the inherit crit font size checkbox if inheritance is disabled.
  if (not configTable.CanInherit) then
   getglobal(FONT_CONFIG_FRAME_NAME .. "InheritCritFontSizeCheckbox"):Hide();
 -- Inheritance is enabled, so copy the inherited values.
 else
  fontConfigFrame.InheritedCritFontName = configTable.InheritedCritFontName;
  fontConfigFrame.InheritedCritOutlineIndex = configTable.InheritedCritOutlineIndex;
  fontConfigFrame.InheritedCritFontSize = configTable.InheritedCritFontSize;
  end


  -- Show the crit preview text.
  getglobal(FONT_CONFIG_FRAME_NAME .. "CritPreview"):Show();

 -- Don't setup and show crit controls.
 else
  -- Hide the crit controls.
  getglobal(FONT_CONFIG_FRAME_NAME .. "CritFontDropdown"):Hide();
  getglobal(FONT_CONFIG_FRAME_NAME .. "CritOutlineDropdown"):Hide();
  getglobal(FONT_CONFIG_FRAME_NAME .. "InheritCritFontSizeCheckbox"):Hide();
  getglobal(FONT_CONFIG_FRAME_NAME .. "CritFontSizeSlider"):Hide();
  getglobal(FONT_CONFIG_FRAME_NAME .. "CritPreview"):Hide();
 end


 fontConfigFrame.saveFunc = configTable.SaveFunc;
 fontConfigFrame.customArg1 = configTable.CustomArg1;

 fontConfigFrame:ClearAllPoints();
 local found, _, lineNumber = string.find(configTable.AnchorFrame:GetName(), "ScrollLine(%d+)");
 if (found and tonumber(lineNumber) <= 2) then
  fontConfigFrame:SetPoint("TOPRIGHT", configTable.AnchorFrame, "BOTTOMRIGHT");
 elseif (found) then
  fontConfigFrame:SetPoint("BOTTOMRIGHT", configTable.AnchorFrame, "TOPRIGHT");
 else
  fontConfigFrame:SetPoint("BOTTOMLEFT", configTable.AnchorFrame, "TOPLEFT");
 end
 fontConfigFrame:Show();
 fontConfigFrame:Raise();

 -- Update the font previews.
 MikSBTOpt.UpdateFontPreviews();
end


-- **********************************************************************************
-- Called when a button on the font config frame is pressed.
-- **********************************************************************************
function MikSBTOpt.FontConfigFrameButtonOnClick()
 local fontConfigFrame = getglobal(FONT_CONFIG_FRAME_NAME);

 -- Save button.
 if (string.find(this:GetName(), "SaveButton")) then
  -- Call the save function if there is one.
  if (fontConfigFrame.saveFunc) then
   fontConfigFrame.saveFunc(fontSettingsTable, fontConfigFrame.customArg1);
  end
  fontConfigFrame:Hide();

 -- Cancel button.
 elseif (string.find(this:GetName(), "CancelButton")) then
  fontConfigFrame:Hide();
 end
end


-- **********************************************************************************
-- Called when a checkbox on the font config frame is clicked.
-- **********************************************************************************
function MikSBTOpt.FontConfigFrameCheckboxOnClick()
 -- Inherit Normal Font Size.
 if (string.find(this:GetName(), "InheritNormalFontSizeCheckbox")) then
  local slider = getglobal(FONT_CONFIG_FRAME_NAME .. "NormalFontSizeSlider");
  if (this:GetChecked()) then
   slider:Hide();
  else
   slider:Show();
   MikSBTOpt.PopulateSlider(slider:GetName(), getglobal(FONT_CONFIG_FRAME_NAME).InheritedNormalFontSize);
  end
  MikSBTOpt.UpdateFontPreviews();

 -- Inherit Crit Font Size.
 elseif (string.find(this:GetName(), "InheritCritFontSizeCheckbox")) then
  local slider = getglobal(FONT_CONFIG_FRAME_NAME .. "CritFontSizeSlider");
  if (this:GetChecked()) then
   slider:Hide();
  else
   slider:Show();
   MikSBTOpt.PopulateSlider(slider:GetName(), getglobal(FONT_CONFIG_FRAME_NAME).InheritedCritFontSize);
  end
  MikSBTOpt.UpdateFontPreviews();

 end
end


-- **********************************************************************************
-- This function refreshes the list of fonts to show in the font config frame
-- dropdowns.
-- **********************************************************************************
function MikSBTOpt.RefreshFontOptions()
 -- Clear the font dropdown options table.
 local numFonts = #fontDropdownOptions;
 for x = numFonts, 1, -1 do
  table.remove(fontDropdownOptions);
 end

 -- Populate the list of available fonts.
 local registeredFonts = MikSBT.GetRegisteredFonts();
 for fontName, fontData in pairs(registeredFonts) do
  table.insert(fontDropdownOptions, fontName);
 end

 -- Sort the table.
 table.sort(fontDropdownOptions);


 -- Clear the font dropdown options table with the inherit option.
 local numFonts = #fontDropdownInheritOptions;
 for x = numFonts, 1, -1 do
  table.remove(fontDropdownInheritOptions);
 end

 -- Populate the list of available fonts including the inherit option.
 for fontName in pairs(registeredFonts) do
  table.insert(fontDropdownInheritOptions, fontName);
 end

 -- Sort the table.
 table.sort(fontDropdownInheritOptions);

 -- Add the inherit option.
 table.insert(fontDropdownInheritOptions, 1, {Name = MSBTLocale.MSG_INHERIT_TEXT, Value = 0});
end


-- **********************************************************************************
-- Updates the font settings table with values selected.
-- **********************************************************************************
function MikSBTOpt.RefreshSelectedFontSettings()
 -- Get the font configuration frame.
 local fontConfigFrame = getglobal(FONT_CONFIG_FRAME_NAME);

 -- Get the selected normal font name.
 fontSettingsTable.NormalFontName = UIDropDownMenu_GetSelectedValue(getglobal(FONT_CONFIG_FRAME_NAME .. "NormalFontDropdown"));

 -- Get the selected normal outline index.
 fontSettingsTable.NormalOutlineIndex = UIDropDownMenu_GetSelectedValue(getglobal(FONT_CONFIG_FRAME_NAME .. "NormalOutlineDropdown"));

 -- Get the selected normal font size.
 local slider = getglobal(FONT_CONFIG_FRAME_NAME .. "NormalFontSizeSlider");
 if (slider:IsShown()) then
  fontSettingsTable.NormalFontSize = slider:GetValue();
 else
  fontSettingsTable.NormalFontSize = 0;
 end


 -- Check if the crit settings are shown.
 if (getglobal(FONT_CONFIG_FRAME_NAME .. "CritFontDropdown"):IsShown()) then
  -- Get the selected crit font name.
  fontSettingsTable.CritFontName = UIDropDownMenu_GetSelectedValue(getglobal(FONT_CONFIG_FRAME_NAME .. "CritFontDropdown"));

  -- Get the selected crit outline index.
  fontSettingsTable.CritOutlineIndex = UIDropDownMenu_GetSelectedValue(getglobal(FONT_CONFIG_FRAME_NAME .. "CritOutlineDropdown"));

  -- Get the selected crit font size.
  local slider = getglobal(FONT_CONFIG_FRAME_NAME .. "CritFontSizeSlider");
  if (slider:IsShown()) then
   fontSettingsTable.CritFontSize = slider:GetValue();
  else
   fontSettingsTable.CritFontSize = 0;
  end

 -- Crit controls hidden.
 else
  -- Clear the crit font settings.
  fontSettingsTable.CritFontName = nil;
  fontSettingsTable.CritOutlineIndex = nil;
  fontSettingsTable.CritFontSize = nil;
 end
end


-- **********************************************************************************
-- Updates the font previews with values selected.
-- **********************************************************************************
function MikSBTOpt.UpdateFontPreviews()
 -- Refresh the selected font settings.
 MikSBTOpt.RefreshSelectedFontSettings();

 -- Get the font configuration frame.
 local fontConfigFrame = getglobal(FONT_CONFIG_FRAME_NAME);

 -- Get the selected normal font name.
 local normalFontName = fontSettingsTable.NormalFontName;
 if (normalFontName == 0) then
  normalFontName = fontConfigFrame.InheritedNormalFontName;
 end

 -- Get the selected normal outline index.
 local normalOutlineIndex = fontSettingsTable.NormalOutlineIndex;
 if (normalOutlineIndex == 0) then
  normalOutlineIndex = fontConfigFrame.InheritedNormalOutlineIndex;
 end

 -- Get the selected normal font size.
 local normalFontSize = fontSettingsTable.NormalFontSize;
 if (normalFontSize == 0) then
  normalFontSize = fontConfigFrame.InheritedNormalFontSize;
 end

 -- Make sure the normal font name is valid.
 if (normalFontName ~= nil) then
  local previewText = getglobal(FONT_CONFIG_FRAME_NAME .. "NormalPreviewText");
  previewText:SetFont(MikSBT.GetRegisteredFonts()[normalFontName], normalFontSize, OUTLINE_MAP[normalOutlineIndex]);
 end

 -- Check if the crit controls are shown.
 if (getglobal(FONT_CONFIG_FRAME_NAME .. "CritFontDropdown"):IsShown()) then
  -- Get the selected crit font name.
  local critFontName = fontSettingsTable.CritFontName;
  if (critFontName == 0) then
   critFontName = fontConfigFrame.InheritedCritFontName;
  end

  -- Get the selected crit outline index.
  local critOutlineIndex = fontSettingsTable.CritOutlineIndex;
  if (critOutlineIndex == 0) then
   critOutlineIndex = fontConfigFrame.InheritedCritOutlineIndex;
  end

  -- Get the selected crit font size.
  local critFontSize = fontSettingsTable.CritFontSize;
  if (critFontSize == 0) then
   critFontSize = fontConfigFrame.InheritedCritFontSize;
  end

  -- Make sure the crit font name is valid.
  if (critFontName ~= nil) then
   local previewText = getglobal(FONT_CONFIG_FRAME_NAME .. "CritPreviewText");
   previewText:SetFont(MikSBT.GetRegisteredFonts()[critFontName], critFontSize, OUTLINE_MAP[critOutlineIndex]);
  end
 end
end


-------------------------------------------------------------------------------------
-- Partial effects config frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the partial effects configuration frame.
-- **********************************************************************************
function MikSBTOpt.InitPartialEffectsConfigFrame()
 -- Setup the partial effect color swatches.
 MikSBTOpt.SetupColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "CrushingBlowsSwatch", nil, MikSBTOpt.PartialEffectsConfigFrameColorSwatchOnChange);
 MikSBTOpt.SetupColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "GlancingHitsSwatch", nil, MikSBTOpt.PartialEffectsConfigFrameColorSwatchOnChange);
 MikSBTOpt.SetupColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "AbsorbsSwatch", nil, MikSBTOpt.PartialEffectsConfigFrameColorSwatchOnChange);
 MikSBTOpt.SetupColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "BlocksSwatch", nil, MikSBTOpt.PartialEffectsConfigFrameColorSwatchOnChange);
 MikSBTOpt.SetupColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "ResistsSwatch", nil, MikSBTOpt.PartialEffectsConfigFrameColorSwatchOnChange);
 MikSBTOpt.SetupColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "VulnerabilitiesSwatch", nil, MikSBTOpt.PartialEffectsConfigFrameColorSwatchOnChange);
 MikSBTOpt.SetupColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "OverhealsSwatch", nil, MikSBTOpt.PartialEffectsConfigFrameColorSwatchOnChange);

 -- Setup the partial effect checkboxes.
 local key = "ColorPartialEffectsCheckbox";	MikSBTOpt.SetupCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.PartialEffectsConfigFrameCheckboxOnClick);
 key = "CrushingBlowsCheckbox";	MikSBTOpt.SetupCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.PartialEffectsConfigFrameCheckboxOnClick);
 key = "GlancingHitsCheckbox";	MikSBTOpt.SetupCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.PartialEffectsConfigFrameCheckboxOnClick);
 key = "AbsorbsCheckbox";		MikSBTOpt.SetupCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.PartialEffectsConfigFrameCheckboxOnClick);
 key = "BlocksCheckbox";		MikSBTOpt.SetupCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.PartialEffectsConfigFrameCheckboxOnClick);
 key = "ResistsCheckbox";		MikSBTOpt.SetupCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.PartialEffectsConfigFrameCheckboxOnClick);
 key = "VulnerabilitiesCheckbox";	MikSBTOpt.SetupCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.PartialEffectsConfigFrameCheckboxOnClick);
 key = "OverhealsCheckbox";		MikSBTOpt.SetupCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.PartialEffectsConfigFrameCheckboxOnClick);
end


-- **********************************************************************************
-- Shows the partial effects configuration frame.
-- **********************************************************************************
function MikSBTOpt.ShowPartialEffectsConfigFrame(anchorFrame)
 -- Hide all of the detached frames.
 MikSBTOpt.HideDetachedFrames()

 -- Populate the partial effect color swatches.
 local color = MSBTProfiles.CurrentProfile.PartialEffectSettings.Crushing.Color;	MikSBTOpt.PopulateColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "CrushingBlowsSwatch", color.r, color.g, color.b);
 color = MSBTProfiles.CurrentProfile.PartialEffectSettings.Glancing.Color;		MikSBTOpt.PopulateColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "GlancingHitsSwatch", color.r, color.g, color.b);
 color = MSBTProfiles.CurrentProfile.PartialEffectSettings.Absorb.Color;		MikSBTOpt.PopulateColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "AbsorbsSwatch", color.r, color.g, color.b);
 color = MSBTProfiles.CurrentProfile.PartialEffectSettings.Block.Color;			MikSBTOpt.PopulateColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "BlocksSwatch", color.r, color.g, color.b);
 color = MSBTProfiles.CurrentProfile.PartialEffectSettings.Resist.Color;		MikSBTOpt.PopulateColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "ResistsSwatch", color.r, color.g, color.b);
 color = MSBTProfiles.CurrentProfile.PartialEffectSettings.Vulnerability.Color;	MikSBTOpt.PopulateColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "VulnerabilitiesSwatch", color.r, color.g, color.b);
 color = MSBTProfiles.CurrentProfile.PartialEffectSettings.Overheal.Color;		MikSBTOpt.PopulateColorSwatch(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "OverhealsSwatch", color.r, color.g, color.b);

 -- Populate the partial effect checkboxes.
 MikSBTOpt.PopulateCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "ColorPartialEffectsCheckbox", not MSBTProfiles.CurrentProfile.PartialEffectSettings.ColoringDisabled);
 MikSBTOpt.PopulateCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "CrushingBlowsCheckbox", not MSBTProfiles.CurrentProfile.PartialEffectSettings.Crushing.Disabled);
 MikSBTOpt.PopulateCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "GlancingHitsCheckbox", not MSBTProfiles.CurrentProfile.PartialEffectSettings.Glancing.Disabled);
 MikSBTOpt.PopulateCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "AbsorbsCheckbox", not MSBTProfiles.CurrentProfile.PartialEffectSettings.Absorb.Disabled);
 MikSBTOpt.PopulateCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "BlocksCheckbox", not MSBTProfiles.CurrentProfile.PartialEffectSettings.Block.Disabled);
 MikSBTOpt.PopulateCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "ResistsCheckbox", not MSBTProfiles.CurrentProfile.PartialEffectSettings.Resist.Disabled);
 MikSBTOpt.PopulateCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "VulnerabilitiesCheckbox", not MSBTProfiles.CurrentProfile.PartialEffectSettings.Vulnerability.Disabled);
 MikSBTOpt.PopulateCheckbox(PARTIAL_EFFECTS_CONFIG_FRAME_NAME .. "OverhealsCheckbox", not MSBTProfiles.CurrentProfile.PartialEffectSettings.Overheal.Disabled);


 -- Get the partial effect config frame.
 local partialEffectsConfigFrame = getglobal(PARTIAL_EFFECTS_CONFIG_FRAME_NAME);

 -- Anchor the frame and show it above the others.
 partialEffectsConfigFrame:ClearAllPoints();
 partialEffectsConfigFrame:SetPoint("BOTTOMLEFT", anchorFrame, "TOPLEFT");
 partialEffectsConfigFrame:Show();
 partialEffectsConfigFrame:Raise();
end


-- **********************************************************************************
-- Called when a color swatch on the partial effects config frame changes.
-- **********************************************************************************
function MikSBTOpt.PartialEffectsConfigFrameColorSwatchOnChange(colorSwatch)
 -- Crushing blows.
 if (string.find(colorSwatch:GetName(), "CrushingBlowsSwatch")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Crushing.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Crushing.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Crushing.Color.b = colorSwatch.b;

 -- Glancing hits.
 elseif (string.find(colorSwatch:GetName(), "GlancingHitsSwatch")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Glancing.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Glancing.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Glancing.Color.b = colorSwatch.b;

 -- Absorbs.
 elseif (string.find(colorSwatch:GetName(), "AbsorbsSwatch")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Absorb.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Absorb.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Absorb.Color.b = colorSwatch.b;

 -- Blocks.
 elseif (string.find(colorSwatch:GetName(), "BlocksSwatch")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Block.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Block.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Block.Color.b = colorSwatch.b;

 -- Resists.
 elseif (string.find(colorSwatch:GetName(), "ResistsSwatch")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Resist.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Resist.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Resist.Color.b = colorSwatch.b;

 -- Vulnerabilities.
 elseif (string.find(colorSwatch:GetName(), "VulnerabilitiesSwatch")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Vulnerability.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Vulnerability.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Vulnerability.Color.b = colorSwatch.b;

 -- Overheals.
 elseif (string.find(colorSwatch:GetName(), "OverhealsSwatch")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Overheal.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Overheal.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Overheal.Color.b = colorSwatch.b;

 end
end


-- **********************************************************************************
-- Called when a button on the parital effects configuration frame is pressed.
-- **********************************************************************************
function MikSBTOpt.PartialEffectsConfigFrameCheckboxOnClick()
 -- Color partial effects.
 if (string.find(this:GetName(), "ColorPartialEffectsCheckbox")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.ColoringDisabled = not this:GetChecked() and true or nil;

 -- Crushing blows.
 elseif (string.find(this:GetName(), "CrushingBlowsCheckbox")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Crushing.Disabled = not this:GetChecked() and true or nil;

 -- Glancing hits.
 elseif (string.find(this:GetName(), "GlancingHitsCheckbox")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Glancing.Disabled  = not this:GetChecked() and true or nil;

 -- Partial absorbs.
 elseif (string.find(this:GetName(), "AbsorbsCheckbox")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Absorb.Disabled = not this:GetChecked() and true or nil;

 -- Partial blocks.
 elseif (string.find(this:GetName(), "BlocksCheckbox")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Block.Disabled = not this:GetChecked() and true or nil;

 -- Partial resists.
 elseif (string.find(this:GetName(), "ResistsCheckbox")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Resist.Disabled = not this:GetChecked() and true or nil;

 -- Vulnerabilities.
 elseif (string.find(this:GetName(), "VulnerabilitiesCheckbox")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Vulnerability.Disabled = not this:GetChecked() and true or nil;

 -- Overheals.
 elseif (string.find(this:GetName(), "OverhealsCheckbox")) then
  MSBTProfiles.CurrentProfile.PartialEffectSettings.Overheal.Disabled = not this:GetChecked() and true or nil;

 end
end


-------------------------------------------------------------------------------------
-- Damage colors config frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the damage colors configuration frame.
-- **********************************************************************************
function MikSBTOpt.InitDamageColorsConfigFrame()
 -- Setup the damage color labels.
 getglobal(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "PhysicalDamageLabel"):SetText(SPELL_SCHOOL0_CAP);
 getglobal(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "HolyDamageLabel"):SetText(SPELL_SCHOOL1_CAP);
 getglobal(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "FireDamageLabel"):SetText(SPELL_SCHOOL2_CAP);
 getglobal(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "NatureDamageLabel"):SetText(SPELL_SCHOOL3_CAP);
 getglobal(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "FrostDamageLabel"):SetText(SPELL_SCHOOL4_CAP);
 getglobal(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "ShadowDamageLabel"):SetText(SPELL_SCHOOL5_CAP);
 getglobal(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "ArcaneDamageLabel"):SetText(SPELL_SCHOOL6_CAP);
 
 -- Setup the damage color swatches.
 MikSBTOpt.SetupColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "PhysicalDamageSwatch", nil, MikSBTOpt.DamageColorsConfigFrameColorSwatchOnChange);
 MikSBTOpt.SetupColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "HolyDamageSwatch", nil, MikSBTOpt.DamageColorsConfigFrameColorSwatchOnChange);
 MikSBTOpt.SetupColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "FireDamageSwatch", nil, MikSBTOpt.DamageColorsConfigFrameColorSwatchOnChange);
 MikSBTOpt.SetupColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "NatureDamageSwatch", nil, MikSBTOpt.DamageColorsConfigFrameColorSwatchOnChange);
 MikSBTOpt.SetupColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "FrostDamageSwatch", nil, MikSBTOpt.DamageColorsConfigFrameColorSwatchOnChange);
 MikSBTOpt.SetupColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "ShadowDamageSwatch", nil, MikSBTOpt.DamageColorsConfigFrameColorSwatchOnChange);
 MikSBTOpt.SetupColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "ArcaneDamageSwatch", nil, MikSBTOpt.DamageColorsConfigFrameColorSwatchOnChange);

 -- Setup the color damage amounts checkbox.
 local key = "ColorDamageAmountsCheckbox";	MikSBTOpt.SetupCheckbox(DAMAGE_COLORS_CONFIG_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.DamageColorsConfigFrameCheckboxOnClick);
end


-- **********************************************************************************
-- Shows the damage colors configuration frame.
-- **********************************************************************************
function MikSBTOpt.ShowDamageColorsConfigFrame(anchorFrame)
 -- Hide all of the detached frames.
 MikSBTOpt.HideDetachedFrames()

 -- Populate the damage color swatches.
 local color = MSBTProfiles.CurrentProfile.DamageColorSettings.Physical.Color;	MikSBTOpt.PopulateColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "PhysicalDamageSwatch", color.r, color.g, color.b);
 color = MSBTProfiles.CurrentProfile.DamageColorSettings.Holy.Color;			MikSBTOpt.PopulateColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "HolyDamageSwatch", color.r, color.g, color.b);
 color = MSBTProfiles.CurrentProfile.DamageColorSettings.Fire.Color;			MikSBTOpt.PopulateColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "FireDamageSwatch", color.r, color.g, color.b);
 color = MSBTProfiles.CurrentProfile.DamageColorSettings.Nature.Color;			MikSBTOpt.PopulateColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "NatureDamageSwatch", color.r, color.g, color.b);
 color = MSBTProfiles.CurrentProfile.DamageColorSettings.Frost.Color;			MikSBTOpt.PopulateColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "FrostDamageSwatch", color.r, color.g, color.b);
 color = MSBTProfiles.CurrentProfile.DamageColorSettings.Shadow.Color;			MikSBTOpt.PopulateColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "ShadowDamageSwatch", color.r, color.g, color.b);
 color = MSBTProfiles.CurrentProfile.DamageColorSettings.Arcane.Color;			MikSBTOpt.PopulateColorSwatch(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "ArcaneDamageSwatch", color.r, color.g, color.b);

 -- Populate the color damage amounts checkbox.
 MikSBTOpt.PopulateCheckbox(DAMAGE_COLORS_CONFIG_FRAME_NAME .. "ColorDamageAmountsCheckbox", not MSBTProfiles.CurrentProfile.DamageColorSettings.ColoringDisabled);


 -- Get the damage color config frame.
 local damageColorsConfigFrame = getglobal(DAMAGE_COLORS_CONFIG_FRAME_NAME);

 -- Anchor the frame and show it above the others.
 damageColorsConfigFrame:ClearAllPoints();
 damageColorsConfigFrame:SetPoint("BOTTOMLEFT", anchorFrame, "TOPLEFT");
 damageColorsConfigFrame:Show();
 damageColorsConfigFrame:Raise();
end


-- **********************************************************************************
-- Called when a color swatch on the damage colors config frame changes.
-- **********************************************************************************
function MikSBTOpt.DamageColorsConfigFrameColorSwatchOnChange(colorSwatch)
 -- Physical damage.
 if (string.find(colorSwatch:GetName(), "PhysicalDamageSwatch")) then
  MSBTProfiles.CurrentProfile.DamageColorSettings.Physical.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Physical.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Physical.Color.b = colorSwatch.b;

 -- Holy damage.
 elseif (string.find(colorSwatch:GetName(), "HolyDamageSwatch")) then
  MSBTProfiles.CurrentProfile.DamageColorSettings.Holy.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Holy.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Holy.Color.b = colorSwatch.b;

 -- Fire damage.
 elseif (string.find(colorSwatch:GetName(), "FireDamageSwatch")) then
  MSBTProfiles.CurrentProfile.DamageColorSettings.Fire.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Fire.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Fire.Color.b = colorSwatch.b;

 -- Nature damage.
 elseif (string.find(colorSwatch:GetName(), "NatureDamageSwatch")) then
  MSBTProfiles.CurrentProfile.DamageColorSettings.Nature.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Nature.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Nature.Color.b = colorSwatch.b;

 -- Frost damage.
 elseif (string.find(colorSwatch:GetName(), "FrostDamageSwatch")) then
  MSBTProfiles.CurrentProfile.DamageColorSettings.Frost.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Frost.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Frost.Color.b = colorSwatch.b;

 -- Shadow damage.
 elseif (string.find(colorSwatch:GetName(), "ShadowDamageSwatch")) then
  MSBTProfiles.CurrentProfile.DamageColorSettings.Shadow.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Shadow.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Shadow.Color.b = colorSwatch.b;

 -- Arcane damage.
 elseif (string.find(colorSwatch:GetName(), "ArcaneDamageSwatch")) then
  MSBTProfiles.CurrentProfile.DamageColorSettings.Arcane.Color.r = colorSwatch.r;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Arcane.Color.g = colorSwatch.g;
  MSBTProfiles.CurrentProfile.DamageColorSettings.Arcane.Color.b = colorSwatch.b;

 end
end


-- **********************************************************************************
-- Called when a button on the damage colors configuration frame is pressed.
-- **********************************************************************************
function MikSBTOpt.DamageColorsConfigFrameCheckboxOnClick()
 -- Color damage amounts.
 if (string.find(this:GetName(), "ColorDamageAmountsCheckbox")) then
  MSBTProfiles.CurrentProfile.DamageColorSettings.ColoringDisabled = not this:GetChecked() and true or nil;
 end
end


-------------------------------------------------------------------------------------
-- Scroll areas config frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the scroll areas configuration frame.
-- **********************************************************************************
function MikSBTOpt.InitScrollAreasConfigFrame()
 -- Populate the list of available text aligns.
 local textAlignDropdownOptions = {};
 for textAlignIndex, textAlignName in ipairs(MSBTLocale.TEXT_ALIGNS) do
  table.insert(textAlignDropdownOptions, {Name = textAlignName, Value = textAlignIndex});
 end

 -- Sort the table.
 table.sort(textAlignDropdownOptions, MikSBTOpt.DropdownOptionsNameCompareFunc);

 -- Setup the text aligns dropdown.
 local key = "TextAlignDropdown";	MikSBTOpt.SetupDropdown(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, MSBTLocale.DROPDOWNS[key].Label, MSBTLocale.DROPDOWNS[key].Tooltip, MikSBTOpt.ScrollAreasConfigFrameDropdownOnClick, textAlignDropdownOptions);

 -- Setup the reverse direction checkbox.
 key = "ReverseDirectionCheckbox";	MikSBTOpt.SetupCheckbox(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.ScrollAreasConfigFrameCheckboxOnClick);

 -- Setup the scroll height slider.
 key = "ScrollHeightSlider";		MikSBTOpt.SetupSlider(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, MSBTLocale.SLIDERS[key].Label, MSBTLocale.SLIDERS[key].Tooltip, 100, 500, 2, MikSBTOpt.ScrollAreasConfigFrameSliderOnValueChanged);

 -- Setup the x and y offset editboxes.
 key = "XOffsetEditbox";		MikSBTOpt.SetupEditbox(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, MSBTLocale.EDITBOXES[key].Label, MSBTLocale.EDITBOXES[key].Tooltip, MikSBTOpt.ScrollAreasConfigFrameEditboxOnTextChanged);
 key = "YOffsetEditbox";		MikSBTOpt.SetupEditbox(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, MSBTLocale.EDITBOXES[key].Label, MSBTLocale.EDITBOXES[key].Tooltip, MikSBTOpt.ScrollAreasConfigFrameEditboxOnTextChanged);

 -- Setup the preview, save, and cancel buttons.
 key = "ScrollAreasPreviewButton";	MikSBTOpt.SetupButton(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.ScrollAreasConfigFrameButtonOnClick);
 key = "ScrollAreasSaveButton";	MikSBTOpt.SetupButton(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.ScrollAreasConfigFrameButtonOnClick);
 key = "ScrollAreasCancelButton";	MikSBTOpt.SetupButton(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.ScrollAreasConfigFrameButtonOnClick);
end


-- **********************************************************************************
-- Shows the scroll areas configuration frame.
-- **********************************************************************************
function MikSBTOpt.ShowScrollAreasConfigFrame()
 -- Get the scroll areas config and option frames.
 local optionsFrame = getglobal(OPTIONS_FRAME_NAME);
 local scrollAreasConfigFrame = getglobal(SCROLL_AREAS_CONFIG_FRAME_NAME);

 -- Load up the temp and original scroll area settings tables.
 MikSBTOpt.RefreshScrollAreasConfigTempSettings()

 -- Create scroll area mover frames.
 MikSBTOpt.CreateScrollAreaMoverFrames();

 -- Refresh the scroll areas and normal/sticky animation styles dropdown options
 MikSBTOpt.RefreshScrollAreasConfigDropdownOptions();

 -- Setup and populate the scroll area dropdown.
 local key = "ScrollAreaDropdown";		MikSBTOpt.SetupDropdown(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, MSBTLocale.DROPDOWNS[key].Label, MSBTLocale.DROPDOWNS[key].Tooltip, MikSBTOpt.ScrollAreaDropdownOnClick, scrollAreaDropdownOptions);
 MikSBTOpt.PopulateDropdown(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, 1);
 MikSBTOpt.ScrollAreaDropdownOnClick();

 -- Show the scroll areas config frame.
 scrollAreasConfigFrame:Show();

 -- Hide the options frame.
 optionsFrame:Hide();
end


-- **********************************************************************************
-- Called when the scroll area dropdown is clicked.
-- **********************************************************************************
function MikSBTOpt.ScrollAreaDropdownOnClick()
 local scrollAreaIndex = UIDropDownMenu_GetSelectedValue(getglobal(SCROLL_AREAS_CONFIG_FRAME_NAME .. "ScrollAreaDropdown"));

 -- Reset the backdrop color of all the scroll area mover frames to grey.
 for _, frame in ipairs(scrollAreaMoverFrames) do
  frame:SetBackdropColor(0.8, 0.8, 0.8, 1.0);
 end

 -- Set the backdrop color for the selected scroll area mover frame to red and raise the frame.
 scrollAreaMoverFrames[scrollAreaIndex]:SetBackdropColor(0.5, 0.05, 0.05, 1.0);
 scrollAreaMoverFrames[scrollAreaIndex]:Raise();
 
 -- Populate the animation style.
 key = "AnimationStyleDropdown";		MikSBTOpt.SetupDropdown(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, MSBTLocale.DROPDOWNS[key].Label, MSBTLocale.DROPDOWNS[key].Tooltip, MikSBTOpt.ScrollAreasConfigFrameDropdownOnClick, animationStyleDropdownOptions);
 MikSBTOpt.PopulateDropdown(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, tempScrollAreaSettings[scrollAreaIndex].AnimationStyle);

 -- Populate the sticky animation style.
 key = "StickyAnimationStyleDropdown";	MikSBTOpt.SetupDropdown(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, MSBTLocale.DROPDOWNS[key].Label, MSBTLocale.DROPDOWNS[key].Tooltip, MikSBTOpt.ScrollAreasConfigFrameDropdownOnClick, stickyAnimStyleDropdownOptions);
 MikSBTOpt.PopulateDropdown(SCROLL_AREAS_CONFIG_FRAME_NAME .. key, tempScrollAreaSettings[scrollAreaIndex].StickyAnimationStyle);

 -- Populate the text alignment.
 MikSBTOpt.PopulateDropdown(SCROLL_AREAS_CONFIG_FRAME_NAME .. "TextAlignDropdown", tempScrollAreaSettings[scrollAreaIndex].TextAlignIndex);

 -- Populate the reverse direction checkbox.
 MikSBTOpt.PopulateCheckbox(SCROLL_AREAS_CONFIG_FRAME_NAME .. "ReverseDirectionCheckbox", tempScrollAreaSettings[scrollAreaIndex].Reversed);

 -- Populate the scroll height slider.
 MikSBTOpt.PopulateSlider(SCROLL_AREAS_CONFIG_FRAME_NAME .. "ScrollHeightSlider", tempScrollAreaSettings[scrollAreaIndex].ScrollHeight);

 -- Populate the x and y offset editboxes
 MikSBTOpt.PopulateEditbox(SCROLL_AREAS_CONFIG_FRAME_NAME .. "XOffsetEditbox", tempScrollAreaSettings[scrollAreaIndex].OffsetX);
 MikSBTOpt.PopulateEditbox(SCROLL_AREAS_CONFIG_FRAME_NAME .. "YOffsetEditbox", tempScrollAreaSettings[scrollAreaIndex].OffsetY);
end


-- **********************************************************************************
-- Called when a dropdown on the scroll areas config frame is pressed.
-- **********************************************************************************
function MikSBTOpt.ScrollAreasConfigFrameDropdownOnClick(frameName)
 local scrollAreaIndex = UIDropDownMenu_GetSelectedValue(getglobal(SCROLL_AREAS_CONFIG_FRAME_NAME .. "ScrollAreaDropdown"));

 -- Animation style.
 if (string.find(frameName, "AnimationStyleDropdown")) then
  tempScrollAreaSettings[scrollAreaIndex].AnimationStyle = UIDropDownMenu_GetSelectedValue(getglobal(frameName));

 -- Sticky animation style.
 elseif (string.find(frameName, "StickyAnimationStyleDropdown")) then
  tempScrollAreaSettings[scrollAreaIndex].StickyAnimationStyle = UIDropDownMenu_GetSelectedValue(getglobal(frameName));

 -- Text align.
 elseif (string.find(frameName, "TextAlignDropdown")) then
  tempScrollAreaSettings[scrollAreaIndex].TextAlignIndex  = UIDropDownMenu_GetSelectedValue(getglobal(frameName));

 end
end


-- **********************************************************************************
-- Called when a button on the scroll areas config frame is pressed.
-- **********************************************************************************
function MikSBTOpt.ScrollAreasConfigFrameButtonOnClick()
 local optionsFrame = getglobal(OPTIONS_FRAME_NAME);
 local scrollAreasConfigFrame = getglobal(SCROLL_AREAS_CONFIG_FRAME_NAME);

 -- Preview button.
 if (string.find(this:GetName(), "PreviewButton")) then
  MikSBTOpt.SaveScrollAreaSettings(tempScrollAreaSettings);

  -- Display preview message in all the scroll areas.
  for scrollAreaIndex in ipairs(tempScrollAreaSettings) do
   MikSBT.DisplayMessage(MSBTLocale.MSG_SCROLL_AREA_PREVIEW_TEXT, scrollAreaIndex);
  end

 -- Save button.
 elseif (string.find(this:GetName(), "SaveButton")) then
  MikSBTOpt.SaveScrollAreaSettings(tempScrollAreaSettings);

  -- Hide the scroll area mover frames.
  for _, moverFrame in ipairs(scrollAreaMoverFrames) do
   moverFrame:Hide();
  end

  scrollAreasConfigFrame:Hide();
  optionsFrame:Show();

 -- Cancel button.
 elseif (string.find(this:GetName(), "CancelButton")) then
  MikSBTOpt.SaveScrollAreaSettings(originalScrollAreaSettings);

  -- Hide the scroll area mover frames.
  for _, moverFrame in ipairs(scrollAreaMoverFrames) do
   moverFrame:Hide();
  end

  scrollAreasConfigFrame:Hide();
  optionsFrame:Show();
 end
end


-- **********************************************************************************
-- Called when a checkbox on the scroll areas config frame is clicked.
-- **********************************************************************************
function MikSBTOpt.ScrollAreasConfigFrameCheckboxOnClick()
 -- Reverse Direction
 if (string.find(this:GetName(), "ReverseDirectionCheckbox")) then
  local scrollAreaIndex = UIDropDownMenu_GetSelectedValue(getglobal(SCROLL_AREAS_CONFIG_FRAME_NAME .. "ScrollAreaDropdown"));
  tempScrollAreaSettings[scrollAreaIndex].Reversed = this:GetChecked() and true or nil;
 end
end


-- **********************************************************************************
-- Called when a slider on the scroll areas config frame is clicked.
-- **********************************************************************************
function MikSBTOpt.ScrollAreasConfigFrameSliderOnValueChanged()
 local scrollAreaIndex = UIDropDownMenu_GetSelectedValue(getglobal(SCROLL_AREAS_CONFIG_FRAME_NAME .. "ScrollAreaDropdown"));

 -- Scroll height.
 if (string.find(this:GetName(), "ScrollHeightSlider")) then
  tempScrollAreaSettings[scrollAreaIndex].ScrollHeight = this:GetValue();
  MikSBTOpt.RepositionScrollAreaMoverFrames();
 end
end


-- **********************************************************************************
-- Called when the text changes in one of the editboxes on the scroll areas 
-- config frame.
-- **********************************************************************************
function MikSBTOpt.ScrollAreasConfigFrameEditboxOnTextChanged()
 local scrollAreaIndex = UIDropDownMenu_GetSelectedValue(getglobal(SCROLL_AREAS_CONFIG_FRAME_NAME .. "ScrollAreaDropdown"));

 -- X offset.
 if (string.find(this:GetName(), "XOffsetEditbox")) then
  local newOffset = tonumber(this:GetText());
  if (newOffset) then
   tempScrollAreaSettings[scrollAreaIndex].OffsetX = newOffset;
   MikSBTOpt.RepositionScrollAreaMoverFrames();
  end

 -- Y offset.
 elseif (string.find(this:GetName(), "YOffsetEditbox")) then
  local newOffset = tonumber(this:GetText());
  if (newOffset) then
   tempScrollAreaSettings[scrollAreaIndex].OffsetY = newOffset;
   MikSBTOpt.RepositionScrollAreaMoverFrames();
  end

 end
end


-- **********************************************************************************
-- This function refreshes the temp scroll area settings table and the original
-- settings.
-- **********************************************************************************
function MikSBTOpt.RefreshScrollAreasConfigTempSettings()
 -- Delete the old original scroll area settings.
 local numOriginalScrollAreas = #originalScrollAreaSettings;
 for x = numOriginalScrollAreas, 1, -1 do
  table.remove(originalScrollAreaSettings);
 end

 -- Loop through all of the scroll areas and copy the appropriate settings for each one.
 for _, scrollAreaSettings in ipairs(MSBTProfiles.CurrentProfile.ScrollAreaSettings) do
  local copiedSettings = {};
  copiedSettings.AnimationStyle = scrollAreaSettings.AnimationStyle or MSBTDefaults.ScrollAreaSettings.AnimationStyle;
  copiedSettings.StickyAnimationStyle = scrollAreaSettings.StickyAnimationStyle or MSBTDefaults.ScrollAreaSettings.StickyAnimationStyle;
  copiedSettings.TextAlignIndex = scrollAreaSettings.TextAlignIndex or MSBTDefaults.ScrollAreaSettings.TextAlignIndex;
  copiedSettings.Reversed = scrollAreaSettings.Reversed or nil;
  copiedSettings.ScrollHeight = scrollAreaSettings.ScrollHeight or MSBTDefaults.ScrollAreaSettings.ScrollHeight;
  copiedSettings.OffsetX = scrollAreaSettings.OffsetX or MSBTDefaults.ScrollAreaSettings.OffsetX;
  copiedSettings.OffsetY = scrollAreaSettings.OffsetY or MSBTDefaults.ScrollAreaSettings.OffsetY;

  table.insert(originalScrollAreaSettings, copiedSettings);
 end
 
 -- Copy the settings as the original.
 tempScrollAreaSettings = MSBTTableRecycler.CopyTable(originalScrollAreaSettings);
end


-- **********************************************************************************
-- This function refreshes the list of fonts to show in the font config frame
-- dropdowns.
-- **********************************************************************************
function MikSBTOpt.RefreshScrollAreasConfigDropdownOptions()
 -- Clear the scroll areas options table.
 local numScrollAreas = #scrollAreaDropdownOptions;
 for x = numScrollAreas, 1, -1 do
  table.remove(scrollAreaDropdownOptions);
 end

 -- Populate the list of available scroll areas.
 for scrollAreaIndex, scrollAreaSettings in ipairs(MSBTProfiles.CurrentProfile.ScrollAreaSettings) do
  table.insert(scrollAreaDropdownOptions, {Name = scrollAreaSettings.Name, Value = scrollAreaIndex});
 end


 -- Clear the animation styles options table.
 local numAnimStyles = #animationStyleDropdownOptions;
 for x = numAnimStyles, 1, -1 do
  table.remove(animationStyleDropdownOptions);
 end
 
 local localizedName;
 local registeredAnimStyles = MikSBT.GetRegisteredAnimationStyles();
 for animationStyle, animStyleSettings in pairs(registeredAnimStyles) do
  localizedName = MSBTLocale.ANIMATION_STYLES[animationStyle] or animStyleSettings.Name or animationStyle;
  table.insert(animationStyleDropdownOptions, {Name = localizedName, Value = animationStyle});
 end

 -- Sort the table.
 table.sort(animationStyleDropdownOptions, MikSBTOpt.DropdownOptionsNameCompareFunc);


 -- Clear the sticky animation styles options table.
 local numStickyAnimStyles = #stickyAnimStyleDropdownOptions;
 for x = numStickyAnimStyles, 1, -1 do
  table.remove(stickyAnimStyleDropdownOptions);
 end
 
 local registeredStickyAnimStyles = MikSBT.GetRegisteredStickyAnimationStyles();
 for stickyAnimStyle, animStyleSettings in pairs(registeredStickyAnimStyles) do
  localizedName = MSBTLocale.STICKY_ANIMATION_STYLES[stickyAnimStyle] or animStyleSettings.Name or stickyAnimStyle;
  table.insert(stickyAnimStyleDropdownOptions, {Name = localizedName, Value = stickyAnimStyle});
 end

 -- Sort the table.
 table.sort(stickyAnimStyleDropdownOptions, MikSBTOpt.DropdownOptionsNameCompareFunc);
end


-- **********************************************************************************
-- This function creates scroll area mover frames for all of the scroll areas.
-- **********************************************************************************
function MikSBTOpt.CreateScrollAreaMoverFrames()
 -- Make sure a scroll area mover frame exists for each scroll area.
 for scrollAreaIndex in ipairs(tempScrollAreaSettings) do
  if (not scrollAreaMoverFrames[scrollAreaIndex]) then
   local frame = CreateFrame("FRAME", nil, UIParent, "MSBTScrollAreaMoverFrameTemplate");
   frame.Title = frame:CreateFontString(nil, "OVERLAY");
   frame.Title:SetFont("Fonts\\ARIALN.TTF", 12);
   frame.Title:SetPoint("CENTER", frame);
   frame.ScrollAreaIndex = scrollAreaIndex;
   scrollAreaMoverFrames[scrollAreaIndex] = frame;
  end
 end

 -- Reposition the scroll area mover frames.
 MikSBTOpt.RepositionScrollAreaMoverFrames();
end


-- **********************************************************************************
-- This function creates scroll area mover frames for all of the scroll areas.
-- **********************************************************************************
function MikSBTOpt.RepositionScrollAreaMoverFrames()
 for scrollAreaIndex, scrollAreaSettings in ipairs(tempScrollAreaSettings) do
  local frame = scrollAreaMoverFrames[scrollAreaIndex];

  frame:ClearAllPoints();
  frame:SetPoint("BOTTOM", UIParent, "CENTER", tempScrollAreaSettings[scrollAreaIndex].OffsetX, tempScrollAreaSettings[scrollAreaIndex].OffsetY);
  frame:SetHeight(tempScrollAreaSettings[scrollAreaIndex].ScrollHeight);
  frame.Title:SetText(MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex].Name .. " (" .. scrollAreaSettings.OffsetX .. ", " .. scrollAreaSettings.OffsetY .. ")");
  frame:Show();
 end
end


-- **********************************************************************************
-- Save the coordinates of the scroll area mover.
-- **********************************************************************************
function MikSBTOpt.SaveScrollAreaMoverCoordinates()
 -- Get the UIParent center x and y coords.
 local uiParentX, uiParentY = UIParent:GetCenter();
 local xOffset = math.floor(this:GetCenter() - uiParentX);
 local yOffset = math.ceil(this:GetBottom() - uiParentY);
 
 -- Save the x and y offsets.
 tempScrollAreaSettings[this.ScrollAreaIndex].OffsetX = xOffset;
 tempScrollAreaSettings[this.ScrollAreaIndex].OffsetY = yOffset;

 -- Populate the x and y offset editboxes if the moved frame is the selected one.
 if (this.ScrollAreaIndex == UIDropDownMenu_GetSelectedValue(getglobal(SCROLL_AREAS_CONFIG_FRAME_NAME .. "ScrollAreaDropdown"))) then
  MikSBTOpt.PopulateEditbox(SCROLL_AREAS_CONFIG_FRAME_NAME .. "XOffsetEditbox", xOffset);
  MikSBTOpt.PopulateEditbox(SCROLL_AREAS_CONFIG_FRAME_NAME .. "YOffsetEditbox", yOffset); 
 end

 -- Reposition the scroll area mover frames to update the coordinates.
 MikSBTOpt.RepositionScrollAreaMoverFrames();
end


-- **********************************************************************************
-- Save the passed table to the scroll area settings.
-- **********************************************************************************
function MikSBTOpt.SaveScrollAreaSettings(settingsTable)
 -- Copy the settings in the passed scroll area settings table to the current profile.
 for scrollAreaIndex, scrollAreaSettings in ipairs(settingsTable) do
  local profileSASettings = MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex];

  profileSASettings.AnimationStyle = MikSBTOpt.GetPrunedValue(scrollAreaSettings.AnimationStyle, MSBTDefaults.ScrollAreaSettings.AnimationStyle);
  profileSASettings.StickyAnimationStyle = MikSBTOpt.GetPrunedValue(scrollAreaSettings.StickyAnimationStyle, MSBTDefaults.ScrollAreaSettings.StickyAnimationStyle);
  profileSASettings.TextAlignIndex = MikSBTOpt.GetPrunedValue(scrollAreaSettings.TextAlignIndex, MSBTDefaults.ScrollAreaSettings.TextAlignIndex);
  profileSASettings.Reversed = scrollAreaSettings.Reversed;
  profileSASettings.ScrollHeight = MikSBTOpt.GetPrunedValue(scrollAreaSettings.ScrollHeight, MSBTDefaults.ScrollAreaSettings.ScrollHeight);
  profileSASettings.OffsetX = MikSBTOpt.GetPrunedValue(scrollAreaSettings.OffsetX, MSBTDefaults.ScrollAreaSettings.OffsetX);
  profileSASettings.OffsetY = MikSBTOpt.GetPrunedValue(scrollAreaSettings.OffsetY, MSBTDefaults.ScrollAreaSettings.OffsetY);
 end
end


-------------------------------------------------------------------------------------
-- Scroll areas selection frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Shows the scroll area selection frame using the passed settings.
-- **********************************************************************************
function MikSBTOpt.ShowScrollAreaSelectionFrame(configTable)
 -- Don't do anything if the passed config table is invalid.
 if (not configTable) then return; end

 -- Hide all of the detached frames.
 MikSBTOpt.HideDetachedFrames()

 -- Clear the scroll areas options table.
 local numScrollAreas = #scrollAreaDropdownOptions;
 for x = numScrollAreas, 1, -1 do
  table.remove(scrollAreaDropdownOptions);
 end

 -- Populate the list of available scroll areas.
 for scrollAreaIndex, scrollAreaSettings in ipairs(MSBTProfiles.CurrentProfile.ScrollAreaSettings) do
  table.insert(scrollAreaDropdownOptions, {Name = scrollAreaSettings.Name, Value = scrollAreaIndex});
 end

 -- Set the title.
 getglobal(SCROLL_AREA_SELECTION_FRAME_NAME .. "Title"):SetText(configTable.Title);

 -- Setup and populate the select scroll area dropdown.
 local key = "SelectScrollAreaDropdown";
 MikSBTOpt.SetupDropdown(SCROLL_AREA_SELECTION_FRAME_NAME .. key, MSBTLocale.DROPDOWNS[key].Label, MSBTLocale.DROPDOWNS[key].Tooltip, MikSBTOpt.ScrollAreaSelectionFrameDropdownOnClick, scrollAreaDropdownOptions);
 MikSBTOpt.PopulateDropdown(SCROLL_AREA_SELECTION_FRAME_NAME .. key, configTable.SelectedValue);


 -- Get the scroll area selection frame.
 local scrollAreaSelectionFrame = getglobal(SCROLL_AREA_SELECTION_FRAME_NAME);

 scrollAreaSelectionFrame.saveFunc = configTable.SaveFunc;
 scrollAreaSelectionFrame.customArg1 = configTable.CustomArg1;



 -- Anchor the frame and show it above the others.
 scrollAreaSelectionFrame:ClearAllPoints();
 local found, _, lineNumber = string.find(configTable.AnchorFrame:GetName(), "ScrollLine(%d+)");
 if (found and tonumber(lineNumber) <= 5) then
  scrollAreaSelectionFrame:SetPoint("TOPRIGHT", configTable.AnchorFrame, "BOTTOMRIGHT");
 elseif (found) then
  scrollAreaSelectionFrame:SetPoint("BOTTOMRIGHT", configTable.AnchorFrame, "TOPRIGHT");
 end
 scrollAreaSelectionFrame:Show();
 scrollAreaSelectionFrame:Raise();
end


-- **********************************************************************************
-- Called when the dropdown on the scroll area selection frame is clicked.
-- **********************************************************************************
function MikSBTOpt.ScrollAreaSelectionFrameDropdownOnClick(frameName)
 local scrollAreaIndex = UIDropDownMenu_GetSelectedValue(getglobal(frameName));
 local scrollAreaSelectionFrame = getglobal(SCROLL_AREA_SELECTION_FRAME_NAME);

 -- Call the passed save function with the selected scroll area index, if there is one.
 if (scrollAreaSelectionFrame.saveFunc) then
 scrollAreaSelectionFrame.saveFunc(scrollAreaIndex, scrollAreaSelectionFrame.customArg1);
 end
end


-------------------------------------------------------------------------------------
-- Trigger config frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the trigger configuration frame.
-- **********************************************************************************
function MikSBTOpt.InitTriggerConfigFrame()
 -- Setup the labels.
 getglobal(TRIGGER_CONFIG_FRAME_NAME .. "TriggerClassesLabel"):SetText(MSBTLocale.MSG_TRIGGER_CLASSES .. ":");
 getglobal(TRIGGER_CONFIG_FRAME_NAME .. "MainConditionsLabel"):SetText(MSBTLocale.MSG_MAIN_CONDITIONS .. ":");
 getglobal(TRIGGER_CONFIG_FRAME_NAME .. "SecondaryConditionsLabel"):SetText(MSBTLocale.MSG_SECONDARY_CONDITIONS .. ":");

 -- Setup the buttons.
 local key = "EditTriggerClassesButton";	MikSBTOpt.SetupButton(TRIGGER_CONFIG_FRAME_NAME .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggerConfigFrameButtonOnClick);
 key = "AddMainConditionButton";		MikSBTOpt.SetupButton(TRIGGER_CONFIG_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggerConfigFrameButtonOnClick);
 key = "AddSecondaryConditionButton";	MikSBTOpt.SetupButton(TRIGGER_CONFIG_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggerConfigFrameButtonOnClick);
 key = "TriggerEventTypesButton";		MikSBTOpt.SetupButton(TRIGGER_CONFIG_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggerConfigFrameButtonOnClick);
 key = "TriggerSaveButton";			MikSBTOpt.SetupButton(TRIGGER_CONFIG_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggerConfigFrameButtonOnClick);
 key = "TriggerCancelButton";			MikSBTOpt.SetupButton(TRIGGER_CONFIG_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggerConfigFrameButtonOnClick);

 -- Populate and sort the list of available trigger main conditions.
 for conditionType, conditionName in pairs(MSBTLocale.TRIGGER_MAIN_CONDITIONS) do
  table.insert(triggerMainConditionDropdownOptions, {Name = conditionName, Value = conditionType});
 end
 table.sort(triggerMainConditionDropdownOptions, MikSBTOpt.DropdownOptionsNameCompareFunc);

 -- Populate and sort the list of available trigger secondary conditions.
 for conditionType, conditionName in pairs(MSBTLocale.TRIGGER_SECONDARY_CONDITIONS) do
  table.insert(triggerSecondaryConditionDropdownOptions, {Name = conditionName, Value = conditionType});
 end
 table.sort(triggerSecondaryConditionDropdownOptions, MikSBTOpt.DropdownOptionsNameCompareFunc);
end


-- **********************************************************************************
-- Shows the trigger configuration frame.
-- **********************************************************************************
function MikSBTOpt.ShowTriggerConfigFrame(triggerKey)
 -- Hide all of the detached frames.
 MikSBTOpt.HideDetachedFrames()

 local triggerConfigFrame = getglobal(TRIGGER_CONFIG_FRAME_NAME);
 triggerConfigFrame.TriggerKey = triggerKey;

 local triggerData = MSBTProfiles.CurrentProfile.Triggers[triggerKey];
 getglobal(TRIGGER_CONFIG_FRAME_NAME .. "Title"):SetText(triggerData.EventSettings.Message);

 -- Populate the temp trigger classes table and the controls in the trigger config classes sub frame.
 if (triggerData.TriggerSettings.Classes) then
  MikSBTOpt.PopulateCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "AllClassesCheckbox", false);
  MikSBTOpt.TriggerConfigClassesFrameDisableClassCheckboxes(false)
  
  MikSBTOpt.PopulateCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "DruidCheckbox", triggerData.TriggerSettings.Classes["DRUID"]);
  MikSBTOpt.PopulateCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "HunterCheckbox", triggerData.TriggerSettings.Classes["HUNTER"]);
  MikSBTOpt.PopulateCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "MageCheckbox", triggerData.TriggerSettings.Classes["MAGE"]);
  MikSBTOpt.PopulateCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "PaladinCheckbox", triggerData.TriggerSettings.Classes["PALADIN"]);
  MikSBTOpt.PopulateCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "PriestCheckbox", triggerData.TriggerSettings.Classes["PRIEST"]);
  MikSBTOpt.PopulateCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "RogueCheckbox", triggerData.TriggerSettings.Classes["ROGUE"]);
  MikSBTOpt.PopulateCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "ShamanCheckbox", triggerData.TriggerSettings.Classes["SHAMAN"]);
  MikSBTOpt.PopulateCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "WarlockCheckbox", triggerData.TriggerSettings.Classes["WARLOCK"]);
  MikSBTOpt.PopulateCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "WarriorCheckbox", triggerData.TriggerSettings.Classes["WARRIOR"]);
 else
  MikSBTOpt.PopulateCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "AllClassesCheckbox", true);
  MikSBTOpt.TriggerConfigClassesFrameDisableClassCheckboxes(true)
 end

 -- Updates the temp trigger classes table with the initial trigger settings.
 MikSBTOpt.UpdateTriggerClasses();

 -- Clear the temp main conditions and params tables and populate them with the data for the trigger.
 MSBTTableRecycler.EraseTable(tempMainConditions);
 MSBTTableRecycler.EraseTable(tempMainConditionParams);
 for conditionNum, conditionType in pairs(triggerData.TriggerSettings.MainConditions) do
  tempMainConditions[conditionNum] = conditionType;
  tempMainConditionParams[conditionNum] = triggerData.TriggerSettings.MainConditionParams and triggerData.TriggerSettings.MainConditionParams[conditionNum] or nil;
 end

 -- Clear the temp secondary conditions and params tables and populate them with the data for the trigger.
 MSBTTableRecycler.EraseTable(tempSecondaryConditions);
 MSBTTableRecycler.EraseTable(tempSecondaryConditionParams);
 if (triggerData.TriggerSettings.SecondaryConditions) then
  for conditionNum, conditionType in pairs(triggerData.TriggerSettings.SecondaryConditions) do
   tempSecondaryConditions[conditionNum] = conditionType;
   tempSecondaryConditionParams[conditionNum] = triggerData.TriggerSettings.SecondaryConditionParams and triggerData.TriggerSettings.SecondaryConditionParams[conditionNum] or nil;
  end
 end

 -- Clear the temp trigger events table and populate it with the correct ones.
 MSBTTableRecycler.EraseTable(tempTriggerEvents);
 if (triggerData.TriggerSettings.TriggerEvents) then
  for _, event in ipairs(triggerData.TriggerSettings.TriggerEvents) do
   tempTriggerEvents[event] = true;
  end
 end

 -- Enable/disable the trigger event types button based on if any of the main
 -- conditions are search patterns.
 MikSBTOpt.TriggerConfigFrameUpdateEventTypesButton();

 triggerConfigFrame:ClearAllPoints();
 triggerConfigFrame:SetPoint("RIGHT", getglobal(OPTIONS_FRAME_NAME), "RIGHT", -35, 0);
 triggerConfigFrame:Show();
 triggerConfigFrame:Raise();
end


-- **********************************************************************************
-- Updates the scroll frame for the main conditions list.
-- **********************************************************************************
function MikSBTOpt.TriggerMainConditionsListUpdate()
 local totalItems = #tempMainConditions;

 local scrollFrame = getglobal(TRIGGER_CONFIG_FRAME_NAME .. "MainConditionsScrollFrame");
 FauxScrollFrame_Update(scrollFrame, totalItems, 4, 25);
 local skipCount = FauxScrollFrame_GetOffset(scrollFrame);

 -- Loop through all of the scroll lines.
 local objScrollLine, conditionType, conditionText, key;
 for i = 1, 4 do
  -- Get the scroll line object.
  objScrollLine = getglobal(TRIGGER_CONFIG_FRAME_NAME .. "MainConditionScrollLine" .. i);

  -- Check if there is no data for the scroll line.
  if (i > totalItems) then
   objScrollLine:Hide();
  else
   objScrollLine:Show();

   -- Get the condition number and type.
   objScrollLine.ConditionNum = i + skipCount;
   conditionType = tempMainConditions[objScrollLine.ConditionNum];

   -- Create the output condition text based on the settings.
   conditionText = MSBTLocale.TRIGGER_MAIN_CONDITIONS[conditionType] or UNKNOWN;
   if (tempMainConditionParams[objScrollLine.ConditionNum]) then
    conditionText = conditionText .. " - " .. tempMainConditionParams[objScrollLine.ConditionNum];
   end

   key = "EditConditionButton";		MikSBTOpt.SetupButton(objScrollLine:GetName() .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggerConfigFrameButtonOnClick);

   getglobal(objScrollLine:GetName() .. "ConditionText"):SetText(conditionText);

   key = "DeleteConditionButton";		MikSBTOpt.SetupButton(objScrollLine:GetName() .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggerConfigFrameButtonOnClick);
  end
 end
end


-- **********************************************************************************
-- Updates the scroll frame for the secondary conditions list.
-- **********************************************************************************
function MikSBTOpt.TriggerSecondaryConditionsListUpdate()
 local totalItems = #tempSecondaryConditions;

 local scrollFrame = getglobal(TRIGGER_CONFIG_FRAME_NAME .. "SecondaryConditionsScrollFrame");
 FauxScrollFrame_Update(scrollFrame, totalItems, 3, 25);
 local skipCount = FauxScrollFrame_GetOffset(scrollFrame);


 -- Loop through all of the scroll lines.
 local objScrollLine, conditionType, conditionText, key;
 for i = 1, 3 do
  -- Get the scroll line object.
  objScrollLine = getglobal(TRIGGER_CONFIG_FRAME_NAME .. "SecondaryConditionScrollLine" .. i);

  -- Check if there is no data for the scroll line.
  if (i > totalItems) then
   objScrollLine:Hide();
  else
   objScrollLine:Show();

   -- Get the condition number and type.
   objScrollLine.ConditionNum = i + skipCount;
   conditionType = tempSecondaryConditions[objScrollLine.ConditionNum];

   -- Create the output condition text based on the settings.
   conditionText = MSBTLocale.TRIGGER_SECONDARY_CONDITIONS[conditionType] or UNKNOWN;
   if (tempSecondaryConditionParams[objScrollLine.ConditionNum]) then
    conditionText = conditionText .. " - " .. tempSecondaryConditionParams[objScrollLine.ConditionNum];
   end

   key = "EditConditionButton";		MikSBTOpt.SetupButton(objScrollLine:GetName() .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggerConfigFrameButtonOnClick);

   getglobal(objScrollLine:GetName() .. "ConditionText"):SetText(conditionText);

   key = "DeleteConditionButton";		MikSBTOpt.SetupButton(objScrollLine:GetName() .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggerConfigFrameButtonOnClick);
  end
 end
end


-- **********************************************************************************
-- Called when a button on the trigger config frame is pressed.
-- **********************************************************************************
function MikSBTOpt.TriggerConfigFrameButtonOnClick()
 -- Trigger classes button.
 if (string.find(this:GetName(), "EditTriggerClassesButton")) then
  MikSBTOpt.ShowTriggerConfigClassesFrame();


 -- Add Main conditions button.
 elseif (string.find(this:GetName(), "AddMainConditionButton")) then
  local configTable = {};
  configTable.MenuOptions = triggerMainConditionDropdownOptions;
  configTable.ConditionNum = #tempMainConditions + 1;
  configTable.ConditionType = MSBTTriggers.MAINCONDITIONTYPE_SELF_HEALTH;
  configTable.ConditionParam = 1;
  configTable.SaveFunc = MikSBTOpt.EditTriggerMainCondition;
  MikSBTOpt.ShowTriggerConfigConditionFrame(configTable);

  
 -- Main condition edit button.
 elseif (string.find(this:GetName(), "MainConditionScrollLine%dEditConditionButton")) then
  local configTable = {};
  configTable.MenuOptions = triggerMainConditionDropdownOptions;
  configTable.ConditionNum = this:GetParent().ConditionNum;
  configTable.ConditionType = tempMainConditions[configTable.ConditionNum];
  configTable.ConditionParam = tempMainConditionParams[configTable.ConditionNum];
  configTable.SaveFunc = MikSBTOpt.EditTriggerMainCondition;
  MikSBTOpt.ShowTriggerConfigConditionFrame(configTable);


 -- Main condition delete button.
 elseif (string.find(this:GetName(), "MainConditionScrollLine%dDeleteConditionButton")) then
  -- Hide all of the trigger config sub frames.
  MikSBTOpt.HideTriggerConfigSubFrames();

  local numConditions = #tempMainConditions;
  local conditionNum = this:GetParent().ConditionNum;
 
  -- If the condition being delete is not the last one.
  if (conditionNum < numConditions) then
   for x = conditionNum, numConditions - 1 do
    tempMainConditions[x] = tempMainConditions[x + 1];
    tempMainConditionParams[x] = tempMainConditionParams[x + 1];
   end
  end

  tempMainConditions[numConditions] = nil;
  tempMainConditionParams[numConditions] = nil;

  -- Refresh the main conditions list and update the event types button enable/disable state.
  MikSBTOpt.TriggerMainConditionsListUpdate();
  MikSBTOpt.TriggerConfigFrameUpdateEventTypesButton();
  

 -- Add Secondary conditions button.
 elseif (string.find(this:GetName(), "AddSecondaryConditionButton")) then
  local configTable = {};
  configTable.MenuOptions = triggerSecondaryConditionDropdownOptions;
  configTable.ConditionNum = #tempSecondaryConditions + 1;
  configTable.ConditionType = MSBTTriggers.SECONDARYCONDITIONTYPE_SPELL_READY;
  configTable.ConditionParam = nil;
  configTable.SaveFunc = MikSBTOpt.EditTriggerSecondaryCondition;
  MikSBTOpt.ShowTriggerConfigConditionFrame(configTable);


 -- Secondary condition edit button.
 elseif (string.find(this:GetName(), "SecondaryConditionScrollLine%dEditConditionButton")) then
  local configTable = {};
  configTable.MenuOptions = triggerSecondaryConditionDropdownOptions;
  configTable.ConditionNum = this:GetParent().ConditionNum;
  configTable.ConditionType = tempSecondaryConditions[configTable.ConditionNum];
  configTable.ConditionParam = tempSecondaryConditionParams[configTable.ConditionNum];
  configTable.SaveFunc = MikSBTOpt.EditTriggerSecondaryCondition;
  MikSBTOpt.ShowTriggerConfigConditionFrame(configTable);


 -- Secondary condition delete button.
 elseif (string.find(this:GetName(), "SecondaryConditionScrollLine%dDeleteConditionButton")) then
  -- Hide all of the trigger config sub frames.
  MikSBTOpt.HideTriggerConfigSubFrames();

  local numConditions = #tempSecondaryConditions;
  local conditionNum = this:GetParent().ConditionNum;
 
  -- If the condition being delete is not the last one.
  if (conditionNum < numConditions) then
   for x = conditionNum, numConditions - 1 do
    tempSecondaryConditions[x] = tempSecondaryConditions[x + 1];
    tempSecondaryConditionParams[x] = tempSecondaryConditionParams[x + 1];
   end
  end

  tempSecondaryConditions[numConditions] = nil;
  tempSecondaryConditionParams[numConditions] = nil;

  -- Refresh the secondary conditions list.
  MikSBTOpt.TriggerSecondaryConditionsListUpdate();


 -- Trigger event types button.
 elseif (string.find(this:GetName(), "TriggerEventTypesButton")) then
  MikSBTOpt.ShowTriggerConfigEventTypesFrame();


 -- Save button.
 elseif (string.find(this:GetName(), "SaveButton")) then
  local triggerSettings = MSBTProfiles.CurrentProfile.Triggers[this:GetParent().TriggerKey].TriggerSettings;

  -- Save the classes.
  if (not tempTriggerClasses["ALL"]) then
   triggerSettings.Classes = MSBTTableRecycler.CopyTable(tempTriggerClasses);
  else
   triggerSettings.Classes = nil;
  end

  -- Check if there are any main conditions and save them.
  if (next(tempMainConditions)) then
   triggerSettings.MainConditions = MSBTTableRecycler.CopyTable(tempMainConditions);

   if (next(tempMainConditionParams)) then
    triggerSettings.MainConditionParams = MSBTTableRecycler.CopyTable(tempMainConditionParams);
   else
    triggerSettings.MainConditionParams = nil;
   end
  else
   triggerSettings.MainConditions = {};
   triggerSettings.MainConditionParams = nil;
  end

  -- Check if there are any secondary conditions and save them.
  if (next(tempSecondaryConditions)) then
   triggerSettings.SecondaryConditions = MSBTTableRecycler.CopyTable(tempSecondaryConditions);

   if (next(tempSecondaryConditionParams)) then
    triggerSettings.SecondaryConditionParams = MSBTTableRecycler.CopyTable(tempSecondaryConditionParams);
   else
    triggerSettings.SecondaryConditionParams = nil;
   end
  else
   triggerSettings.SecondaryConditions = nil;
   triggerSettings.SecondaryConditionParams = nil;
  end

  -- Check if there are any trigger events selected and save them.
  if (next(tempTriggerEvents) and getglobal(TRIGGER_CONFIG_FRAME_NAME .. "TriggerEventTypesButton"):IsEnabled()) then
   triggerSettings.TriggerEvents = {};
   for event in pairs(tempTriggerEvents) do
    table.insert(triggerSettings.TriggerEvents, event);
   end
  else
   triggerSettings.TriggerEvents = nil;
  end

  -- Reregister the triggers to update the changes.
  MSBTTriggers.RegisterAllTriggers();

  MikSBTOpt.HideTriggerConfigSubFrames();
  getglobal(TRIGGER_CONFIG_FRAME_NAME):Hide();


 -- Cancel button.
 elseif (string.find(this:GetName(), "CancelButton")) then
  MikSBTOpt.HideTriggerConfigSubFrames();
  getglobal(TRIGGER_CONFIG_FRAME_NAME):Hide();

 end
end


-- **********************************************************************************
-- Enables or disables the trigger event types button depending on whether or not
-- there are any search pattern main conditions.
-- **********************************************************************************
function MikSBTOpt.TriggerConfigFrameUpdateEventTypesButton()
 local enableButton;

 -- Loop through all of the main conditions looking for a search pattern type.
 for conditionNum, conditionType in ipairs(tempMainConditions) do
  if (conditionType == MSBTTriggers.MAINCONDITIONTYPE_SEARCH_PATTERN) then
   enableButton = true;
  end 
 end

 -- Enable or disable the trigger event types button accordingly.
 if (enableButton) then
  getglobal(TRIGGER_CONFIG_FRAME_NAME .. "TriggerEventTypesButton"):Enable();
 else
  getglobal(TRIGGER_CONFIG_FRAME_NAME .. "TriggerEventTypesButton"):Disable();
 end
end


-- **********************************************************************************
-- Called by the trigger conditions frame with the condition type and parameter to
-- update the main condition num to.
-- **********************************************************************************
function MikSBTOpt.EditTriggerMainCondition(conditionNum, conditionType, conditionParam)
 tempMainConditions[conditionNum] = conditionType;
 tempMainConditionParams[conditionNum] = conditionParam;

 -- Refresh the main conditions list and update the event types button enable/disable state.
 MikSBTOpt.TriggerMainConditionsListUpdate();
 MikSBTOpt.TriggerConfigFrameUpdateEventTypesButton(); 
end


-- **********************************************************************************
-- Called by the trigger conditions frame with the condition type and parameter to
-- update the secondary condition num to.
-- **********************************************************************************
function MikSBTOpt.EditTriggerSecondaryCondition(conditionNum, conditionType, conditionParam)
 tempSecondaryConditions[conditionNum] = conditionType;
 tempSecondaryConditionParams[conditionNum] = conditionParam;

 -- Refresh the secondary conditions list.
 MikSBTOpt.TriggerSecondaryConditionsListUpdate();
end


-------------------------------------------------------------------------------------
-- Trigger config condition frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the trigger condition frame.
-- **********************************************************************************
function MikSBTOpt.InitTriggerConfigConditionFrame()
 -- Setup the save and cancel buttons for the trigger config condition frame.
 local key = "ConditionSaveButton";	MikSBTOpt.SetupButton(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggerConfigConditionFrameButtonOnClick);
 key = "ConditionCancelButton";	MikSBTOpt.SetupButton(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggerConfigConditionFrameButtonOnClick);

 -- Set the width of the condition type dropdown.
 UIDropDownMenu_SetWidth(190, getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. "ConditionTypeDropdown"));

 conditionControlMap[MSBTTriggers.MAINCONDITIONTYPE_SELF_HEALTH] = {Type="Slider", MinValue=1, MaxValue=100, StepAmount=1};
 conditionControlMap[MSBTTriggers.MAINCONDITIONTYPE_SELF_MANA] = {Type="Slider", MinValue=1, MaxValue=100, StepAmount=1};
 conditionControlMap[MSBTTriggers.MAINCONDITIONTYPE_PET_HEALTH] = {Type="Slider", MinValue=1, MaxValue=100, StepAmount=1};
 conditionControlMap[MSBTTriggers.MAINCONDITIONTYPE_ENEMY_HEALTH] = {Type="Slider", MinValue=1, MaxValue=100, StepAmount=1};
 conditionControlMap[MSBTTriggers.MAINCONDITIONTYPE_FRIENDLY_HEALTH] = {Type="Slider", MinValue=1, MaxValue=100, StepAmount=1};
 conditionControlMap[MSBTTriggers.MAINCONDITIONTYPE_SELF_BUFF_GAIN] = {Type="Editbox"};
 conditionControlMap[MSBTTriggers.MAINCONDITIONTYPE_SELF_DEBUFF_GAIN] = {Type="Editbox"};
 conditionControlMap[MSBTTriggers.MAINCONDITIONTYPE_TARGET_BUFF_GAIN] = {Type="Editbox"};
 conditionControlMap[MSBTTriggers.MAINCONDITIONTYPE_TARGET_DEBUFF_GAIN] = {Type="Editbox"};
 conditionControlMap[MSBTTriggers.MAINCONDITIONTYPE_TARGET_DEBUFF_APP] = {Type="Editbox"};
 conditionControlMap[MSBTTriggers.MAINCONDITIONTYPE_SEARCH_PATTERN] = {Type="Editbox"};

 conditionControlMap[MSBTTriggers.SECONDARYCONDITIONTYPE_SPELL_READY] = {Type="Editbox"};
 conditionControlMap[MSBTTriggers.SECONDARYCONDITIONTYPE_BUFF_INACTIVE] = {Type="Editbox"};
 conditionControlMap[MSBTTriggers.SECONDARYCONDITIONTYPE_MINIMUM_POWER] = {Type="Editbox"};
 conditionControlMap[MSBTTriggers.SECONDARYCONDITIONTYPE_WARRIOR_STANCE] = {Type="Slider", MinValue=1, MaxValue=3, StepAmount=1};
 conditionControlMap[MSBTTriggers.SECONDARYCONDITIONTYPE_TRIGGER_COOLDOWN] = {Type="Slider", MinValue=1, MaxValue=30, StepAmount=1};
end


-- **********************************************************************************
-- Shows the trigger config condition frame using the data supplied in the passed
-- config table.
-- **********************************************************************************
function MikSBTOpt.ShowTriggerConfigConditionFrame(configTable)
 -- Don't do anything if the passed config table is invalid.
 if (not configTable) then return; end

 -- Hide all of the trigger config sub frames.
 MikSBTOpt.HideTriggerConfigSubFrames()

 local conditionFrame = getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME);
 conditionFrame.saveFunc = configTable.SaveFunc;
 conditionFrame.ConditionNum = configTable.ConditionNum;

 local key = "ConditionTypeDropdown";
 MikSBTOpt.SetupDropdown(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. key, MSBTLocale.DROPDOWNS[key].Label, MSBTLocale.DROPDOWNS[key].Tooltip, MikSBTOpt.TriggerConditionTypeDropdownOnClick, configTable.MenuOptions);
 MikSBTOpt.PopulateDropdown(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. key, configTable.ConditionType);
 MikSBTOpt.TriggerConditionTypeDropdownOnClick(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. key);

 -- Populate the condition's parameter if there is one.
 if (configTable.ConditionParam) then
  if (getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. "ParameterSlider"):IsShown()) then
   MikSBTOpt.PopulateSlider(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. "ParameterSlider", configTable.ConditionParam);
  elseif (getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. "ParameterEditbox"):IsShown()) then
   MikSBTOpt.PopulateEditbox(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. "ParameterEditbox", configTable.ConditionParam);
  end
 end

 conditionFrame:ClearAllPoints();
 conditionFrame:SetPoint("TOPRIGHT", getglobal(TRIGGER_CONFIG_FRAME_NAME), "TOPLEFT", 5, 0);
 conditionFrame:Show();
 conditionFrame:Raise();
end


-- **********************************************************************************
-- Called when a button on the trigger config condition frame is pressed.
-- **********************************************************************************
function MikSBTOpt.TriggerConfigConditionFrameButtonOnClick()
 -- Save button.
 if (string.find(this:GetName(), "ConditionSaveButton")) then
  local conditionNum = getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME).ConditionNum;
  local conditionType = UIDropDownMenu_GetSelectedValue(getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. "ConditionTypeDropdown"));
  local conditionParam;

  if (getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. "ParameterSlider"):IsShown()) then
   conditionParam = getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. "ParameterSlider"):GetValue();
  elseif (getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. "ParameterEditbox"):IsShown()) then
   conditionParam = getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. "ParameterEditbox"):GetText();
  end

  if (conditionType == MSBTTriggers.SECONDARYCONDITIONTYPE_MINIMUM_POWER) then
   conditionParam = tonumber(conditionParam) or 0;
  end

  -- Call the passed save function with the entered text, if there is one.
  if (getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME).saveFunc) then
   getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME).saveFunc(conditionNum, conditionType, conditionParam);
  end
  getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME):Hide();

 -- Cancel button.
 elseif (string.find(this:GetName(), "ConditionCancelButton")) then
  getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME):Hide();
 end
end


-- **********************************************************************************
-- Called when the trigger condition type dropdown is clicked.
-- **********************************************************************************
function MikSBTOpt.TriggerConditionTypeDropdownOnClick(frameName)
 local conditionType = UIDropDownMenu_GetSelectedValue(getglobal(frameName));
 local objParameterEditbox = getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. "ParameterEditbox");
 local objParameterSlider = getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME .. "ParameterSlider");
 local mapInfo = conditionControlMap[conditionType];

 objParameterEditbox:Hide();
 objParameterSlider:Hide();

 if (mapInfo) then
  -- Show the correct parameter control type for condition.
  if (mapInfo.Type == "Slider") then
   objParameterSlider:Show();
   MikSBTOpt.SetupSlider(objParameterSlider:GetName(), MSBTLocale.MSG_PARAMETER, nil, mapInfo.MinValue, mapInfo.MaxValue, mapInfo.StepAmount, nil);
   MikSBTOpt.PopulateSlider(objParameterSlider:GetName(), mapInfo.MinValue);
   getglobal(objParameterSlider:GetName() .. "Text"):SetText(MSBTLocale.MSG_PARAMETER .. ": " .. objParameterSlider:GetValue());
  elseif (conditionControlMap[conditionType].Type == "Editbox") then
   objParameterEditbox:Show();
   MikSBTOpt.SetupEditbox(objParameterEditbox:GetName(), MSBTLocale.MSG_PARAMETER, nil, nil);
   objParameterEditbox:SetText("");
  end 
 end
end


-------------------------------------------------------------------------------------
-- Trigger config classes frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the trigger classes frame.
-- **********************************************************************************
function MikSBTOpt.InitTriggerConfigClassesFrame()
 -- Setup the title.
 getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "Title"):SetText(MSBTLocale.MSG_TRIGGER_CLASSES);

 -- Setup the all classes checkbox.
 local key = "AllClassesCheckbox";	MikSBTOpt.SetupCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, nil, MikSBTOpt.TriggerConfigClassesFrameCheckboxOnClick);

 -- Setup the individual class checkboxes.
 MikSBTOpt.SetupCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "DruidCheckbox", MSBTLocale.CLASS_NAMES["DRUID"], nil, MikSBTOpt.TriggerConfigClassesFrameCheckboxOnClick);
 MikSBTOpt.SetupCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "HunterCheckbox", MSBTLocale.CLASS_NAMES["HUNTER"], nil, MikSBTOpt.TriggerConfigClassesFrameCheckboxOnClick);
 MikSBTOpt.SetupCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "MageCheckbox", MSBTLocale.CLASS_NAMES["MAGE"], nil, MikSBTOpt.TriggerConfigClassesFrameCheckboxOnClick);
 MikSBTOpt.SetupCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "PaladinCheckbox", MSBTLocale.CLASS_NAMES["PALADIN"], nil, MikSBTOpt.TriggerConfigClassesFrameCheckboxOnClick);
 MikSBTOpt.SetupCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "PriestCheckbox", MSBTLocale.CLASS_NAMES["PRIEST"], nil, MikSBTOpt.TriggerConfigClassesFrameCheckboxOnClick);
 MikSBTOpt.SetupCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "RogueCheckbox", MSBTLocale.CLASS_NAMES["ROGUE"], nil, MikSBTOpt.TriggerConfigClassesFrameCheckboxOnClick);
 MikSBTOpt.SetupCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "ShamanCheckbox", MSBTLocale.CLASS_NAMES["SHAMAN"], nil, MikSBTOpt.TriggerConfigClassesFrameCheckboxOnClick);
 MikSBTOpt.SetupCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "WarlockCheckbox", MSBTLocale.CLASS_NAMES["WARLOCK"], nil, MikSBTOpt.TriggerConfigClassesFrameCheckboxOnClick);
 MikSBTOpt.SetupCheckbox(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "WarriorCheckbox", MSBTLocale.CLASS_NAMES["WARRIOR"], nil, MikSBTOpt.TriggerConfigClassesFrameCheckboxOnClick);
end


-- **********************************************************************************
-- Show the trigger config classes frame.
-- **********************************************************************************
function MikSBTOpt.ShowTriggerConfigClassesFrame()
 -- Hide all of the trigger config sub frames.
 MikSBTOpt.HideTriggerConfigSubFrames();

 local triggerConfigClassesFrame = getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME);

 triggerConfigClassesFrame:ClearAllPoints();
 triggerConfigClassesFrame:SetPoint("TOPRIGHT", getglobal(TRIGGER_CONFIG_FRAME_NAME), "TOPLEFT", 5, 0);
 triggerConfigClassesFrame:Show();
 triggerConfigClassesFrame:Raise();
end


-- **********************************************************************************
-- Called when the all classes checkbox is clicked on the trigger config classes 
-- frame.
-- **********************************************************************************
function MikSBTOpt.TriggerConfigClassesFrameCheckboxOnClick()
 -- All classes.
 if (string.find(this:GetName(), "AllClassesCheckbox")) then
  MikSBTOpt.TriggerConfigClassesFrameDisableClassCheckboxes(this:GetChecked());
 end

 -- Update the temp trigger classes table and text label.
 MikSBTOpt.UpdateTriggerClasses();
end


-- **********************************************************************************
-- Disables or enables the individual class checkboxes according to the passed
-- value.
-- **********************************************************************************
function MikSBTOpt.TriggerConfigClassesFrameDisableClassCheckboxes(disable)
  -- Check/uncheck and disable/enable the individual class checkboxes.
 if (disable) then
   local key = "DruidCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(true);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Disable();

   key = "HunterCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(true);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Disable();

   key = "MageCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(true);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Disable();

   key = "PaladinCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(true);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Disable();

   key = "PriestCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(true);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Disable();

   key = "RogueCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(true);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Disable();

   key = "ShamanCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(true);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Disable();

   key = "WarlockCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(true);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Disable();

   key = "WarriorCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(true);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Disable();
 else
   local key = "DruidCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(false);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Enable();

   key = "HunterCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(false);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Enable();

   key = "MageCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(false);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Enable();

   key = "PaladinCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(false);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Enable();

   key = "PriestCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(false);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Enable();

   key = "RogueCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(false);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Enable();

   key = "ShamanCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(false);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Enable();

   key = "WarlockCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(false);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Enable();

   key = "WarriorCheckbox";
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):SetChecked(false);
   getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. key):Enable();
 end
end


-- **********************************************************************************
-- Updates the temp trigger classes table and text label according to what's checked
-- in the trigger classes config frame.
-- **********************************************************************************
function MikSBTOpt.UpdateTriggerClasses()
 -- Set the selected classes to true and nil the others.
 tempTriggerClasses["ALL"] = getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "AllClassesCheckbox"):GetChecked() and true or nil;
 tempTriggerClasses["DRUID"] = getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "DruidCheckbox"):GetChecked() and true or nil;
 tempTriggerClasses["HUNTER"] = getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "HunterCheckbox"):GetChecked() and true or nil;
 tempTriggerClasses["MAGE"] = getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "MageCheckbox"):GetChecked() and true or nil;
 tempTriggerClasses["PALADIN"] = getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "PaladinCheckbox"):GetChecked() and true or nil;
 tempTriggerClasses["PRIEST"] = getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "PriestCheckbox"):GetChecked() and true or nil;
 tempTriggerClasses["ROGUE"] = getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "RogueCheckbox"):GetChecked() and true or nil;
 tempTriggerClasses["SHAMAN"] = getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "ShamanCheckbox"):GetChecked() and true or nil;
 tempTriggerClasses["WARLOCK"] = getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "WarlockCheckbox"):GetChecked() and true or nil;
 tempTriggerClasses["WARRIOR"] = getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME .. "WarriorCheckbox"):GetChecked() and true or nil;

 -- Check if all classes is selected.
 if (tempTriggerClasses["ALL"]) then
  getglobal(TRIGGER_CONFIG_FRAME_NAME .. "TriggerClassesText"):SetText(MSBTLocale.CHECKBOXES["AllClassesCheckbox"].Label);
 else
  -- Loop through the selected trigger classes and create a string.
  local selectedClasses = "";
  for triggerClass in pairs(tempTriggerClasses) do
   selectedClasses = selectedClasses .. MSBTLocale.CLASS_NAMES[triggerClass] .. ", ";
  end

  -- Strip off the extra comma and space and set the text.
  selectedClasses = string.sub(selectedClasses, 1, string.len(selectedClasses) - 2);
  getglobal(TRIGGER_CONFIG_FRAME_NAME .. "TriggerClassesText"):SetText(selectedClasses);
 end
end


-------------------------------------------------------------------------------------
-- Trigger config event types frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the trigger config event types frame.
-- **********************************************************************************
function MikSBTOpt.InitTriggerConfigEventTypesFrame()
 -- Setup the title.
 getglobal(TRIGGER_CONFIG_EVENT_TYPES_FRAME_NAME .. "Title"):SetText(MSBTLocale.BUTTONS["TriggerEventTypesButton"].Label);


 local searchPatternEvents = MSBTTriggers.GetSupportedSearchPatternEvents();

 for _, event in ipairs(searchPatternEvents) do
  table.insert(supportedTriggerEvents, event);
 end

 -- Sort the supported trigger events.
 table.sort(supportedTriggerEvents);
end


-- **********************************************************************************
-- Shows the trigger config event types frame.
-- **********************************************************************************
function MikSBTOpt.ShowTriggerConfigEventTypesFrame()
 -- Hide all of the trigger config sub frames.
 MikSBTOpt.HideTriggerConfigSubFrames();

 local triggerConfigEventTypesFrame = getglobal(TRIGGER_CONFIG_EVENT_TYPES_FRAME_NAME);

 triggerConfigEventTypesFrame:ClearAllPoints();
 triggerConfigEventTypesFrame:SetPoint("TOPRIGHT", getglobal(TRIGGER_CONFIG_FRAME_NAME), "TOPLEFT", 5, 0);
 triggerConfigEventTypesFrame:Show();
 triggerConfigEventTypesFrame:Raise();
end


-- **********************************************************************************
-- Updates the scroll frame for the trigger events list.
-- **********************************************************************************
function MikSBTOpt.TriggerEventsListUpdate()
 local totalItems = #supportedTriggerEvents;

 local scrollFrame = getglobal(TRIGGER_CONFIG_EVENT_TYPES_FRAME_NAME .. "ScrollFrame");
 FauxScrollFrame_Update(scrollFrame, totalItems, 8, 25);
 local skipCount = FauxScrollFrame_GetOffset(scrollFrame);

  -- Loop through all of the scroll lines.
 local objScrollLine;
 for i = 1, 8 do
  -- Get the scroll line object.
  objScrollLine = getglobal(TRIGGER_CONFIG_EVENT_TYPES_FRAME_NAME .. "ScrollLine" .. i);

  -- Check if there is no data for the scroll line.
  if (i > totalItems) then
   objScrollLine:Hide();
  else
   objScrollLine:Show();

   objScrollLine.TriggerEvent = supportedTriggerEvents[i+skipCount];

   -- Setup and populate the trigger event checkbox
   MikSBTOpt.SetupCheckbox(objScrollLine:GetName() .. "TriggerEventCheckbox", supportedTriggerEvents[i+skipCount], nil, MikSBTOpt.TriggerConfigEventTypesFrameCheckboxOnClick);
   MikSBTOpt.PopulateCheckbox(objScrollLine:GetName() .. "TriggerEventCheckbox", tempTriggerEvents[objScrollLine.TriggerEvent]);
  end
 end
end


-- **********************************************************************************
-- Called when a checkbox on the trigger config event types frame is clicked.
-- **********************************************************************************
function MikSBTOpt.TriggerConfigEventTypesFrameCheckboxOnClick()
 -- Trigger event checkbox.
 if (string.find(this:GetName(), "TriggerEventCheckbox")) then
  tempTriggerEvents[this:GetParent().TriggerEvent] = this:GetChecked() and true or nil;
 end
end


-------------------------------------------------------------------------------------
-- General utility functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the detached frames.
-- **********************************************************************************
function MikSBTOpt.InitDetachedFrames()
 MikSBTOpt.InitDetachedInputFrame();
 MikSBTOpt.InitAcknowledgeFrame();
 MikSBTOpt.InitFontConfigFrame();
 MikSBTOpt.InitPartialEffectsConfigFrame();
 MikSBTOpt.InitDamageColorsConfigFrame();
 MikSBTOpt.InitScrollAreasConfigFrame();
 MikSBTOpt.InitTriggerConfigFrame();
 MikSBTOpt.InitTriggerConfigClassesFrame();
 MikSBTOpt.InitTriggerConfigConditionFrame();
 MikSBTOpt.InitTriggerConfigEventTypesFrame()
end


-- **********************************************************************************
-- Hides all detached frames.
-- **********************************************************************************
function MikSBTOpt.HideDetachedFrames()
 -- Hide detached frames.
 getglobal(DETACHED_INPUT_FRAME_NAME):Hide();
 getglobal(ACKNOWLEDGE_FRAME_NAME):Hide();
 getglobal(FONT_CONFIG_FRAME_NAME):Hide();
 getglobal(PARTIAL_EFFECTS_CONFIG_FRAME_NAME):Hide();
 getglobal(DAMAGE_COLORS_CONFIG_FRAME_NAME):Hide();
 getglobal(SCROLL_AREA_SELECTION_FRAME_NAME):Hide();
 getglobal(TRIGGER_CONFIG_FRAME_NAME):Hide();
 MikSBTOpt.HideTriggerConfigSubFrames();
end

-- **********************************************************************************
-- Hides the trigger config detached frame's sub frames.
-- **********************************************************************************
function MikSBTOpt.HideTriggerConfigSubFrames()
 getglobal(TRIGGER_CONFIG_CLASSES_FRAME_NAME):Hide();
 getglobal(TRIGGER_CONFIG_CONDITION_FRAME_NAME):Hide();
 getglobal(TRIGGER_CONFIG_EVENT_TYPES_FRAME_NAME):Hide();
end