-- Copyright © 2023 @Groick (Twitch). All rights reserved.
local function L(key, ...) return EasyOptions:Localize(key, ...) end
function EasyOptions:CreateOptionFrameVisible(parent, positionInfo, optionItem)
  optionItem.Text = optionItem.Text or L("Show Frame")
  optionItem.TooltipText = optionItem.TooltipText or L("Indicates whether the frame is visible.")
  local onOptionValueChangedHandlerCustom = optionItem.OnOptionValueChangedHandler
  optionItem.OnOptionValueChangedHandler = function(self)
    local control = self.Control
    local value = self:GetOptionValue()
    EasyOptions:UpdateFrameVisibleState(control.Frame, value)
    if (onOptionValueChangedHandlerCustom ~= nil) then
      onOptionValueChangedHandlerCustom(self)
    end
  end
  --
  local control, controlRegionWidth, controlRegionHeight
  if (optionItem.RadioButtonGroupName ~= nil) then -- Create a RadioButton if the option item has a value for its optionItem.RadioButtonGroupName property, otherwise create a CheckBox.
    control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionRadioButton(parent, positionInfo, optionItem)
  else
    control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionCheckBox(parent, positionInfo, optionItem)
  end
  
  control.Frame = optionItem.Frame
  local frame = optionItem.Frame
  frame.FrameVisibleOptionItem = optionItem
  frame.FrameVisibleControl = control
  
  -- Apply the value(s) of the control(s) to the frame.
  EasyOptions:UpdateFrameVisibleState(control.Frame, control:GetValue())

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionFrameLocked(parent, positionInfo, optionItem)
  optionItem.Text = optionItem.Text or L("Lock Frame")
  optionItem.TooltipText = optionItem.TooltipText or L("Indicates whether the frame is prevented from being moved with the mouse.").."\n\n"..EasyOptions:ConvertTextToColoredText(L("The frame must be visible before it can be moved with the mouse."), EasyOptionsDB["TooltipAlternateTextColor"])
  local onOptionValueChangedHandlerCustom = optionItem.OnOptionValueChangedHandler
  optionItem.OnOptionValueChangedHandler = function(self)
    local control = self.Control
    local value = self:GetOptionValue()
    EasyOptions:UpdateFrameLockedState(control.Frame, value)
    if (onOptionValueChangedHandlerCustom ~= nil) then
      onOptionValueChangedHandlerCustom(self)
    end
  end
  --
  local control, controlRegionWidth, controlRegionHeight
  if (optionItem.RadioButtonGroupName ~= nil) then -- Create a RadioButton if the option item has a value for its optionItem.RadioButtonGroupName property, otherwise create a CheckBox.
    control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionRadioButton(parent, positionInfo, optionItem)
  else
    control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionCheckBox(parent, positionInfo, optionItem)
  end
  
  control.Frame = optionItem.Frame
  local frame = optionItem.Frame
  frame.FrameLockedOptionItem = optionItem
  frame.FrameLockedControl = control
  frame:HookScript("OnEnter", function(self, motion) -- IMPORTANT: We must handle the OnEnter event in order to update the Locked state of the form because the WoW API can re-enable mouse events for a form (i.e., frame:EnableMouse(true)) for an unknown reason. This typically only occurs between the first time that frame:EnableMouse is called and the first time that the form is displayed.
    EasyOptions:UpdateFrameLockedState(self, self.FrameLockedControl:GetValue())
  end)

  -- Apply the value(s) of the control(s) to the frame.
  EasyOptions:UpdateFrameLockedState(control.Frame, control:GetValue())

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionFrameClampedToScreen(parent, positionInfo, optionItem)
  optionItem.Text = optionItem.Text or L("Clamp to Screen")
  optionItem.TooltipText = optionItem.TooltipText or L("Indicates whether the frame is prevented from being moved off-screen.")
  local onOptionValueChangedHandlerCustom = optionItem.OnOptionValueChangedHandler
  optionItem.OnOptionValueChangedHandler = function(self)
    local control = self.Control
    local value = self:GetOptionValue()
    EasyOptions:UpdateFrameClampedToScreenState(control.Frame, value)
    if (onOptionValueChangedHandlerCustom ~= nil) then
      onOptionValueChangedHandlerCustom(self)
    end
  end
  --
  local control, controlRegionWidth, controlRegionHeight
  if (optionItem.RadioButtonGroupName ~= nil) then -- Create a RadioButton if the option item has a value for its optionItem.RadioButtonGroupName property, otherwise create a CheckBox.
    control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionRadioButton(parent, positionInfo, optionItem)
  else
    control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionCheckBox(parent, positionInfo, optionItem)
  end
  
  control.Frame = optionItem.Frame
  local frame = optionItem.Frame
  frame.FrameClampedToScreenOptionItem = optionItem
  frame.FrameClampedToScreenControl = control
  
  -- Apply the value(s) of the control(s) to the frame.
  EasyOptions:UpdateFrameClampedToScreenState(control.Frame, control:GetValue())

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionFrameAnchoredToMouse(parent, positionInfo, optionItem)
  optionItem.Text = optionItem.Text or L("Anchor to Mouse")
  optionItem.TooltipText = optionItem.TooltipText or L("Indicates whether the frame is anchored to the mouse cursor.")
  local onOptionValueChangedHandlerCustom = optionItem.OnOptionValueChangedHandler
  optionItem.OnOptionValueChangedHandler = function(self)
    local control = self.Control
    local value = self:GetOptionValue()
    EasyOptions:UpdateFrameAnchoredToMouseState(control.Frame, value)
    if (onOptionValueChangedHandlerCustom ~= nil) then
      onOptionValueChangedHandlerCustom(self)
    end
  end
  --
  local control, controlRegionWidth, controlRegionHeight
  if (optionItem.RadioButtonGroupName ~= nil) then -- Create a RadioButton if the option item has a value for its optionItem.RadioButtonGroupName property, otherwise create a CheckBox.
    control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionRadioButton(parent, positionInfo, optionItem)
  else
    control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionCheckBox(parent, positionInfo, optionItem)
  end
  
  control.Frame = optionItem.Frame
  local frame = optionItem.Frame
  frame.FrameAnchoredToMouseOptionItem = optionItem
  frame.FrameAnchoredToMouseControl = control
  
  if (frame ~= nil) then
    frame.UpdatePositionIfAnchoredToMouse = function(self)
      if (not frame.IsAnchoredToMouse) then
        return
      end
      local info = frame.ReferenceAnchorPointInfo
      local point, relativeTo, relativePoint, offsetX, offsetY
      if (info ~= nil) then
        point = info.point
        relativeTo = nil -- info.relativeTo -- Always use the default value for this parameter.
        relativePoint = nil -- info.relativePoint -- Always use the default value for this parameter.
        offsetX = info.offsetX
        offsetY = info.offsetY
      end
      point = point or "BOTTOM" -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
      relativeTo = relativeTo or UIParent -- or frame.ParentFrame
      relativePoint = relativePoint or "BOTTOMLEFT" -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
      offsetX = offsetX or 0
      offsetY = offsetY or 0

      local cursorX, cursorY = GetCursorPosition()
      local screenScale = UIParent:GetEffectiveScale()
      offsetX = offsetX + cursorX / screenScale
      offsetY = offsetY + cursorY / screenScale
      offsetX, offsetY = EasyOptions:GetActualFramePositionsFromDisplayedFramePositions(frame, offsetX, offsetY)
      frame:ClearAllPoints()
      frame:SetPoint(point, relativeTo, relativePoint, offsetX, offsetY)
    end
    frame.SetFixedAnchorPointInfos = function(self, fixedAnchorPointInfos)
      local frame = self
      frame.FixedAnchorPointInfos = fixedAnchorPointInfos
      if (EasyOptions:GetLength(frame.FixedAnchorPointInfos) >= 1) then
        frame.ReferenceAnchorPointInfo = frame.FixedAnchorPointInfos[1]
      else
        frame.ReferenceAnchorPointInfo = nil
      end
    end

    frame:HookScript("OnUpdate", function(self)
      local frame = self
      frame:UpdatePositionIfAnchoredToMouse()
    end)
    frame:HookScript("OnShow", function(self)
      local frame = self
      frame:UpdatePositionIfAnchoredToMouse()
    end)
  end
  
  -- Apply the value(s) of the control(s) to the frame.
  EasyOptions:UpdateFrameAnchoredToMouseState(control.Frame, control:GetValue())

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionFramePosition(parent, positionInfo, optionItem)
  local optionName = optionItem.Name
  local value = EasyOptions:GetOptionValueOrDefaultValue(optionName, optionItem.DefaultValue)
  -- local text = EasyOptions:GetControlText(optionItem)
  -- local tooltipTitleText = optionItem.TooltipTitleText or text
  -- local tooltipText = optionItem.TooltipText
  local showParentAnchorPoint = optionItem.ShowParentAnchorPoint or false
  local alignOnSingleRow = optionItem.AlignOnSingleRow or (not showParentAnchorPoint)
  local minOffsetX = optionItem.MinOffsetX or -1000.0
  local maxOffsetX = optionItem.MaxOffsetX or 1000.0
  local minOffsetY = optionItem.MinOffsetY or -1000.0
  local maxOffsetY = optionItem.MaxOffsetY or 1000.0
  local framePositionInfo = EasyOptions:GetFramePositionInfoFromOptionPositionInfo(value)

  local controlTypeName = "FramePositionParent"
  local customControlName = nil
  local controlName = EasyOptions:GetControlName(controlTypeName, customControlName)
  local control = CreateFrame("Frame", controlName, parent) -- Acts as the control that is associated with the OptionItem.
  control.Name = controlName
  control.Type = controlTypeName
  control.BaseType = controlTypeName
  -- EasyOptions:SetTooltip(control, control, tooltipTitleText, tooltipText)
  control:EnableMouse(false)
  
  control.OnEnabledChangedHandler = function(self)
    -- Reserved.
  end
  EasyOptions:AddSupportForEnabledState(control)

  control.Frame = optionItem.Frame
  control.ParentFrame = optionItem.ParentFrame
  local frame = optionItem.Frame
  if (frame ~= nil) then
    frame.FramePositionControl = control
    frame.FramePositionOptionItem = optionItem
    frame.DefaultPositionInfo = optionItem.DefaultValue
    frame.ParentFrame = optionItem.ParentFrame
    frame:HookScript("OnMouseDown", function(self, button)
      if (self:IsMovable()) and (button == "LeftButton") and (not self.IsAnchoredToMouse) and (not self.isMoving) then
        self.isMoving = true
        self:StartMoving() -- Calling frame:StartMoving will cause the WoW API to set frame:IsUserPlaced() to true (see below for where we call self:SetUserPlaced(false) in order to account for this behavior).
        self:SetUserPlaced(false) -- NOTE: We pass false to the SetUserPlaced method in order indicate that the form is not at a custom position which prevents the WoW API (i.e., the WoW client) from using the value that is stored in the WoW layout cache from being applied to the frame when the player logs in.
        -- frame:SetScript("OnUpdate", function(self) -- NOTE: This logic was removed because the WoW client always sets the anchor point of a frame to "TOPLEFT" while the frame is being moved. -- Add a script to update the values of the controls while the user is moving the frame.
        --   local optionItem = frame.FramePositionOptionItem
        --   local control = optionItem.Control
        --   control:UpdateControlsFromFrame(false)
        -- end)
      end
    end)
    frame:HookScript("OnMouseUp", function(self, button)
      if (button == "LeftButton") and (self.isMoving) then
        local optionItem = frame.FramePositionOptionItem
        local control = optionItem.Control
        self:StopMovingOrSizing()
        -- if (frame:HasScript("OnUpdate")) then
        --   frame:SetScript("OnUpdate", nil) -- Remvoe the script.
        -- end
        control:UpdateControlsFromFrame(true)
        self.isMoving = false
      end
    end)
    frame:HookScript("OnHide", function(self)
      if (self.isMoving) then
        local optionItem = frame.FramePositionOptionItem
        local control = optionItem.Control
        self:StopMovingOrSizing()
        -- if (frame:HasScript("OnUpdate")) then
        --   frame:SetScript("OnUpdate", nil) -- Remvoe the script.
        -- end
        control:UpdateControlsFromFrame(true)
        self.isMoving = false
      end
    end)
  end
  
  control:ClearAllPoints()
  control:SetPoint(positionInfo[1], parent, positionInfo[2], positionInfo[3], positionInfo[4])
  
  optionItem.Control = control
  control.OptionItem = optionItem
  if (optionName ~= nil) and (optionName ~= "") then
    EasyOptions.Current.OptionControls[optionName] = control
  end
  
  control.SetFramePosition = function(self, value, updateFramePositionControls, updateFramePositionOptionItem, printCoordinates)
    local frame = self.Frame
    local framePositionInfo = EasyOptions:GetFramePositionInfoFromOptionPositionInfo(value)
    local x, y = EasyOptions:GetActualFramePositionsFromDisplayedFramePositions(frame, framePositionInfo[3], framePositionInfo[4])
    EasyOptions:SetFramePosition(frame, framePositionInfo[1], framePositionInfo[2], x, y, updateFramePositionControls, updateFramePositionOptionItem, printCoordinates)
    -- NOTE: We don't call EasyOptions:SetOptionValueFromControlInfo in this method because we assume that method is called in EasyOptions:UpdateFramePositionOptionItemFromActualPosition.
    -- local allowUpdateControl = false
    -- EasyOptions:SetOptionValueFromControlInfo(self, value, allowUpdateControl)
  end
  control.SetValue = function(self, value)
    self:SetFramePosition(value, true, false, false)
  end
  control.UpdateFramePositionFromOptionValue = function(self)
    local control = self
    local optionItem = control.OptionItem
    local value = EasyOptions:GetOptionValue(optionItem.AddonName, optionItem.Name)
    control:SetFramePosition(value, false, false, false)
  end
  control.EnableUpdateFramePositionFromControls = true
  control.UpdateFramePositionFromControls = function(self, updateFramePositionOptionItem)
    local control = self
    if (not control.EnableUpdateFramePositionFromControls) then
      return
    end
    local frame = control.Frame
    local framePositionInfo = control:GetFramePositionInfoFromControls()
    local updateFramePositionControls = false
    local printCoordinates = false
    EasyOptions:SetFramePosition(frame, framePositionInfo[1], framePositionInfo[2], framePositionInfo[3], framePositionInfo[4], updateFramePositionControls, updateFramePositionOptionItem, printCoordinates)
  end
  control.EnableUpdateControlsFromFrame = true
  control.UpdateControlsFromFrame = function(self, updateFramePositionOptionItem)
    local control = self
    local printCoordinates = false
    if (not control.EnableUpdateControlsFromFrame) then
      return
    end
    if (updateFramePositionOptionItem) then
      EasyOptions:UpdateFramePositionOptionItemFromActualPosition(frame, printCoordinates)
    end
    local frame = control.Frame
    local returnDisplayedFramePositions = true -- Convert from actual offsets to displayed offsets.
    local framePositionInfo = EasyOptions:GetPositionInfoFromFramePoint(frame, returnDisplayedFramePositions, nil) -- EasyOptions:GetFramePositionInfoFromOptionPositionInfo(AddonDB[optionName])
    local previousEnableUpdateFramePositionFromControls = control.EnableUpdateFramePositionFromControls -- Store the value.
    control.EnableUpdateFramePositionFromControls = false -- Disable the value.
    control:SetFramePositionControlsFromFramePositionInfo(framePositionInfo, true)
    control.EnableUpdateFramePositionFromControls = previousEnableUpdateFramePositionFromControls -- Restore the value.
  end
  control.GetFramePositionInfoFromControls = function(self)
    local control = self
    local frame = control.Frame
    local childAnchorPoint = control.FrameAnchorDropDown:GetValue()
    local parentAnchorPoint = childAnchorPoint -- init
    if (control.ParentAnchorDropDown ~= nil) then
      parentAnchorPoint = control.ParentAnchorDropDown:GetValue()
    end
    local x = control.OffsetXSlider:GetValue()
    local y = control.OffsetYSlider:GetValue()
    x, y = EasyOptions:GetActualFramePositionsFromDisplayedFramePositions(frame, x, y) -- Convert from displayed offsets to actual offsets.
    local framePositionInfo = {childAnchorPoint, parentAnchorPoint, x, y}
    return framePositionInfo
  end
  control.SetFramePositionControlsFromFramePositionInfo = function(self, framePositionInfo, updateFramePositionOptionItem)
    local control = self
    local frame = control.Frame
    local previousEnableUpdateFramePositionFromControls = control.EnableUpdateFramePositionFromControls -- Store the value.
    control.EnableUpdateFramePositionFromControls = false -- Disable the value.
    if (control.FrameAnchorDropDown ~= nil) and (control.FrameAnchorDropDown:GetValue() ~= framePositionInfo[1]) then
      control.FrameAnchorDropDown:SetValue(framePositionInfo[1])
    end
    if (control.ParentAnchorDropDown ~= nil) and (control.ParentAnchorDropDown:GetValue() ~= framePositionInfo[2]) then
      control.ParentAnchorDropDown:SetValue(framePositionInfo[2])
    end
    if (control.OffsetXSlider ~= nil) and (control.OffsetXSlider:GetValue() ~= framePositionInfo[3]) then
      control.OffsetXSlider:SetValue(framePositionInfo[3])
    end
    if (control.OffsetYSlider ~= nil) and (control.OffsetYSlider:GetValue() ~= framePositionInfo[4]) then
      control.OffsetYSlider:SetValue(framePositionInfo[4])
    end
    control.EnableUpdateFramePositionFromControls = previousEnableUpdateFramePositionFromControls -- Restore the value.
    control:UpdateFramePositionFromControls(updateFramePositionOptionItem)
  end
  
  -- Create the controls.
  local controlNameCurrent
  local textCurrent
  local tooltipTitleTextCurrent
  local tooltipTextCurrent
  local positionInfoCurrent = {"TOPLEFT", "TOPLEFT", 0, 0} -- init -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  local paddingX = EasyOptions:GetDefaultControlPaddingX()
  local paddingY = EasyOptions:GetDefaultControlPaddingY()
  local customSize_DropDown = EasyOptions:IIF(showParentAnchorPoint and alignOnSingleRow, 110.0, nil)
  local customSize_Slider = EasyOptions:IIF(showParentAnchorPoint and alignOnSingleRow, 150.0, nil)
  local customSize_Button = nil
  local controlCurrent, controlRegionWidthCurrent, controlRegionHeightCurrent
  local controls = {}
  local valueBoxCurrent
  local controlRegionWidth = 0 -- init
  local controlRegionHeight = 0 -- init
  local controlRegionHeight1 = 0 -- init
  -- local sign = EasyOptions:IIF(EasyOptions:IsRightAlignedPositionInfo(positionInfo), -1, 1)
  local dropDownItemInfos_AnchorPositions = {{"LEFT", L("Left")}, {"TOP", L("Top")}, {"RIGHT", L("Right")}, {"BOTTOM", L("Bottom")}, {"TOPLEFT", L("Top Left")}, {"TOPRIGHT", L("Top Right")}, {"BOTTOMLEFT", L("Bottom Left")}, {"BOTTOMRIGHT", L("Bottom Right")}, {"CENTER", L("Center")}}
  --
  -- Frame Anchor
  textCurrent = EasyOptions:IIF(showParentAnchorPoint, L("Frame Anchor"), L("Anchor"))
  tooltipTitleTextCurrent = textCurrent
  tooltipTextCurrent = EasyOptions:IIF(showParentAnchorPoint, L("Specifies the point on the frame that is anchored to the parent's anchor point."), L("Specifies the frame's anchor point."))
  controlNameCurrent = controlName..".FrameAnchor"
  positionInfoCurrent = {positionInfoCurrent[1], positionInfoCurrent[2], 0, 0}
  local onClickHandler_FrameAnchor = function(self, info, arg1, arg2, checked)
    -- local control = info.arg2
    -- control.Parent:UpdateFramePositionFromControls(true)
  end
  local onValueChangedHandler_FrameAnchor = function(self, value)
    local control = self.Owner.Parent -- NOTE: self is the DropDown, self.Owner is the DropDownParent, self.Owner.Parent is the frame that acts as the parent control.
    control:UpdateFramePositionFromControls(true)
  end
  controlCurrent, controlRegionWidthCurrent, controlRegionHeightCurrent = EasyOptions:CreateDropDown(control, controlNameCurrent, framePositionInfo[1], dropDownItemInfos_AnchorPositions, textCurrent, tooltipTitleTextCurrent, tooltipTextCurrent, positionInfoCurrent, customSize_DropDown, nil, nil, onClickHandler_FrameAnchor, onValueChangedHandler_FrameAnchor)
  controlCurrent.OptionItem = optionItem
  controlCurrent.DropDown.OptionItem = optionItem
  controlCurrent.Frame = frame
  controlCurrent.DropDown.Frame = frame
  controlCurrent.AllowSetOptionValue = false -- Only update Options when the value of the parent control changes.
  controlCurrent.DropDown.AllowSetOptionValue = false -- Only update Options when the value of the parent control changes.
  EasyOptions:AddRightButtonDownHandlerForOptionControl(controlCurrent)
  EasyOptions:AddRightButtonDownHandlerForOptionControl(controlCurrent.DropDown)
  control.FrameAnchorDropDown = controlCurrent
  controlRegionWidth = math.max(controlRegionWidthCurrent + positionInfoCurrent[3], controlRegionWidth)
  controlRegionHeight = math.max(controlRegionHeightCurrent - positionInfoCurrent[4], controlRegionHeight)
  controlRegionHeight1 = controlRegionHeight
  table.insert(controls, controlCurrent)
  --
  -- Parent Anchor
  if (showParentAnchorPoint) then
    textCurrent = L("Parent Anchor")
    tooltipTitleTextCurrent = textCurrent
    tooltipTextCurrent = L("Specifies the point on the parent that is anchored to the frame's anchor point.")
    controlNameCurrent = controlName..".ParentAnchor"
    positionInfoCurrent = {positionInfoCurrent[1], positionInfoCurrent[2], positionInfoCurrent[3] + controlRegionWidthCurrent + paddingX, positionInfoCurrent[4]}
    local onClickHandler_ParentAnchor = function(self, info, arg1, arg2, checked)
      -- local control = info.arg2
      -- control.Parent:UpdateFramePositionFromControls(true)
    end
    local onValueChangedHandler_ParentAnchor = function(self, value)
      local control = dropDown.Parent.Parent -- NOTE: dropDown.Parent is the DropDownParent, dropDown.Parent.Parent is the frame that acts as the parent control.
      control:UpdateFramePositionFromControls(true)
    end
    controlCurrent, controlRegionWidthCurrent, controlRegionHeightCurrent = EasyOptions:CreateDropDown(control, controlNameCurrent, framePositionInfo[2], dropDownItemInfos_AnchorPositions, textCurrent, tooltipTitleTextCurrent, tooltipTextCurrent, positionInfoCurrent, customSize_DropDown, nil, nil, onClickHandler_ParentAnchor, onValueChangedHandler_ParentAnchor)
    controlCurrent.OptionItem = optionItem
    controlCurrent.DropDown.OptionItem = optionItem
    controlCurrent.Frame = frame
    controlCurrent.DropDown.Frame = frame
    controlCurrent.AllowSetOptionValue = false -- Only update Options when the value of the parent control changes.
    controlCurrent.DropDown.AllowSetOptionValue = false -- Only update Options when the value of the parent control changes.
    EasyOptions:AddRightButtonDownHandlerForOptionControl(controlCurrent)
    EasyOptions:AddRightButtonDownHandlerForOptionControl(controlCurrent.DropDown)
    control.ParentAnchorDropDown = controlCurrent
    controlRegionWidth = math.max(controlRegionWidthCurrent + positionInfoCurrent[3], controlRegionWidth)
    controlRegionHeight = math.max(controlRegionHeightCurrent - positionInfoCurrent[4], controlRegionHeight)
    table.insert(controls, controlCurrent)
  end
  --
  -- Offset X
  textCurrent = L("Offset X")
  tooltipTitleTextCurrent = textCurrent
  tooltipTextCurrent = L("Specifies the offset of the frame along the x-axis relative to the frame's anchor point.")
  controlNameCurrent = controlName..".OffsetX"
  if (alignOnSingleRow) then
    positionInfoCurrent = {positionInfoCurrent[1], positionInfoCurrent[2], positionInfoCurrent[3] + controlRegionWidthCurrent + paddingX, positionInfoCurrent[4]}
  else
    positionInfoCurrent = {positionInfoCurrent[1], positionInfoCurrent[2], 0, positionInfoCurrent[4] - controlRegionHeight - paddingY}
  end
  local onValueChangedHandler_OffsetX = function(self)
    local control = self.Parent
    control:UpdateFramePositionFromControls(true)
  end
  controlCurrent, valueBoxCurrent, controlRegionWidthCurrent, controlRegionHeightCurrent = EasyOptions:CreateSlider(control, controlNameCurrent, framePositionInfo[3], minOffsetX, maxOffsetX, EasyOptions.Fields.FramePositionValueStep, EasyOptions.Fields.FramePositionRoundFormatString, textCurrent, tooltipTitleTextCurrent, tooltipTextCurrent, positionInfoCurrent, nil, customSize_Slider, nil, nil, nil, nil, onValueChangedHandler_OffsetX)
  controlCurrent.OptionItem = optionItem
  controlCurrent.ValueBox.OptionItem = optionItem
  controlCurrent.Frame = frame
  controlCurrent.ValueBox.Frame = frame
  controlCurrent.AllowSetOptionValue = false -- Only update Options when the value of the parent control changes.
  controlCurrent.ValueBox.AllowSetOptionValue = false -- Only update Options when the value of the parent control changes.
  EasyOptions:AddRightButtonDownHandlerForOptionControl(controlCurrent)
  EasyOptions:AddRightButtonDownHandlerForOptionControl(controlCurrent.ValueBox)
  control.OffsetXSlider = controlCurrent
  controlRegionWidth = math.max(controlRegionWidthCurrent + positionInfoCurrent[3], controlRegionWidth)
  controlRegionHeight = math.max(controlRegionHeightCurrent - positionInfoCurrent[4], controlRegionHeight)
  table.insert(controls, controlCurrent)
  --
  -- Offset Y
  textCurrent = L("Offset Y")
  tooltipTitleTextCurrent = textCurrent
  tooltipTextCurrent = L("Specifies the offset of the frame along the y-axis relative to the frame's anchor point.")
  controlNameCurrent = controlName..".OffsetY"
  positionInfoCurrent = {positionInfoCurrent[1], positionInfoCurrent[2], positionInfoCurrent[3] + controlRegionWidthCurrent + paddingX, positionInfoCurrent[4]}
  local onValueChangedHandler_OffsetY = function(self)
    local control = self.Parent
    control:UpdateFramePositionFromControls(true)
  end
  controlCurrent, valueBoxCurrent, controlRegionWidthCurrent, controlRegionHeightCurrent = EasyOptions:CreateSlider(control, controlNameCurrent, framePositionInfo[4], minOffsetY, maxOffsetY, EasyOptions.Fields.FramePositionValueStep, EasyOptions.Fields.FramePositionRoundFormatString, textCurrent, tooltipTitleTextCurrent, tooltipTextCurrent, positionInfoCurrent, nil, customSize_Slider, nil, nil, nil, nil, onValueChangedHandler_OffsetY)
  controlCurrent.OptionItem = optionItem
  controlCurrent.ValueBox.OptionItem = optionItem
  controlCurrent.Frame = frame
  controlCurrent.ValueBox.Frame = frame
  controlCurrent.AllowSetOptionValue = false -- Only update Options when the value of the parent control changes.
  controlCurrent.ValueBox.AllowSetOptionValue = false -- Only update Options when the value of the parent control changes.
  EasyOptions:AddRightButtonDownHandlerForOptionControl(controlCurrent)
  EasyOptions:AddRightButtonDownHandlerForOptionControl(controlCurrent.ValueBox)
  control.OffsetYSlider = controlCurrent
  controlRegionWidth = math.max(controlRegionWidthCurrent + positionInfoCurrent[3], controlRegionWidth)
  controlRegionHeight = math.max(controlRegionHeightCurrent - positionInfoCurrent[4], controlRegionHeight)
  table.insert(controls, controlCurrent)
  --
  -- Reset Frame Position
  -- textCurrent = L("Reset Frame Position")
  -- tooltipTitleTextCurrent = textCurrent
  -- tooltipTextCurrent = L("Resets the anchor position and the offset of the frame.")
  -- controlNameCurrent = controlName..".ResetFramePosition"
  -- if (alignOnSingleRow) then
  --   positionInfoCurrent = {positionInfoCurrent[1], positionInfoCurrent[2], 0, positionInfoCurrent[4] - controlRegionHeight1 - 0.5 * paddingY}
  -- else
  --   positionInfoCurrent = {positionInfoCurrent[1], positionInfoCurrent[2], 0, positionInfoCurrent[4] - controlRegionHeightCurrent - paddingY}
  -- end
  -- local onClickHandler_ResetFramePosition = function(self)
  --   EasyOptions:ResetFramePosition(self.Frame)
  -- end
  -- controlCurrent, controlRegionWidthCurrent, controlRegionHeightCurrent = EasyOptions:CreateButton(control, controlNameCurrent, textCurrent, tooltipTitleTextCurrent, tooltipTextCurrent, positionInfoCurrent, customSize_Button, onClickHandler_ResetFramePosition)
  -- controlCurrent.OptionItem = optionItem
  -- controlCurrent.Frame = frame
  -- controlCurrent.AllowSetOptionValue = false -- Only update Options when the value of the parent control changes.
  -- control.ResetFramePositionButton = controlCurrent
  -- controlRegionWidth = math.max(controlRegionWidthCurrent + positionInfoCurrent[3], controlRegionWidth)
  -- controlRegionHeight = math.max(controlRegionHeightCurrent - positionInfoCurrent[4], controlRegionHeight)
  -- table.insert(controls, controlCurrent)
  
  EasyOptions:AddControlsToOwner(controls, control)
  EasyOptions:AddControlsToParent(controls, control)
  EasyOptions:SetIsSubOptionItemControl(controls)

  -- Apply the value(s) of the control(s) to the frame.
  control:UpdateFramePositionFromControls(false)

  control:SetSize(controlRegionWidth, controlRegionHeight)
  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionFrameSizeBase(parent, positionInfo, optionItem, setWidth, setHeight)
  if (optionItem.Text == nil) then
    if (setWidth) and (not setHeight) then
      optionItem.Text = L("Width")
    elseif (not setWidth) and (setHeight) then
      optionItem.Text = L("Height")
    else
      optionItem.Text = L("Size")
    end
  end
  if (optionItem.TooltipText == nil) then
    if (setWidth) and (not setHeight) then
      optionItem.TooltipText = L("Specifies the width of the frame.")
    elseif (not setWidth) and (setHeight) then
      optionItem.TooltipText = L("Specifies the height of the frame.")
    else
      optionItem.TooltipText = L("Specifies the size of the frame.")
    end
  end
  optionItem.MinValue = optionItem.MinValue or 1.0
  optionItem.MaxValue = optionItem.MaxValue or 1000.0
  optionItem.ValueStep = optionItem.ValueStep or EasyOptions.Fields.FrameSizeValueStep -- EasyOptions.Fields.FrameSizeRoundIncrement
  optionItem.FormatString = optionItem.FormatString or EasyOptions.Fields.FrameSizeRoundFormatString
  local onOptionValueChangedHandlerCustom = optionItem.OnOptionValueChangedHandler
  optionItem.OnOptionValueChangedHandler = function(self)
    local control = self.Control
    local value = self:GetOptionValue()
    EasyOptions:UpdateFrameSize(control.Frame, value, control.SetFrameWidth, control.SetFrameHeight)
    if (onOptionValueChangedHandlerCustom ~= nil) then
      onOptionValueChangedHandlerCustom(self)
    end
  end
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionSlider(parent, positionInfo, optionItem)
  control.Frame = optionItem.Frame
  control.SetFrameWidth = setWidth
  control.SetFrameHeight = setHeight

  -- Apply the value(s) of the control(s) to the frame.
  EasyOptions:UpdateFrameSize(control.Frame, control:GetValue(), control.SetFrameWidth, control.SetFrameHeight)

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionFrameSize(parent, positionInfo, optionItem)
  local setWidth = true
  local setHeight = true
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionFrameSizeBase(parent, positionInfo, optionItem, setWidth, setHeight)

  local frame = optionItem.Frame
  frame.FrameSizeOptionItem = optionItem
  frame.FrameSizeControl = control

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionFrameWidth(parent, positionInfo, optionItem)
  local setWidth = true
  local setHeight = false
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionFrameSizeBase(parent, positionInfo, optionItem, setWidth, setHeight)

  local frame = optionItem.Frame
  frame.FrameWidthOptionItem = optionItem
  frame.FrameWidthControl = control

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionFrameHeight(parent, positionInfo, optionItem)
  local setWidth = false
  local setHeight = true
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionFrameSizeBase(parent, positionInfo, optionItem, setWidth, setHeight)

  local frame = optionItem.Frame
  frame.FrameHeightOptionItem = optionItem
  frame.FrameHeightControl = control

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionFrameScale(parent, positionInfo, optionItem)
  optionItem.Text = optionItem.Text or L("Scale")
  optionItem.TooltipText = optionItem.TooltipText or L("Specifies the scale of the frame.")
  optionItem.MinValue = math.max(optionItem.MinValue or 0.25, EasyOptions.Fields.FrameScaleRoundIncrement) -- IMPORTANT The value must be > 0.0.
  optionItem.MaxValue = math.max(optionItem.MaxValue or 4.0, EasyOptions.Fields.FrameScaleRoundIncrement) -- IMPORTANT The value must be > 0.0.
  optionItem.ValueStep = optionItem.ValueStep or EasyOptions.Fields.FrameScaleValueStep -- EasyOptions.Fields.FrameScaleRoundIncrement
  optionItem.FormatString = optionItem.FormatString or EasyOptions.Fields.FrameScaleRoundFormatString
  local onOptionValueChangedHandlerCustom = optionItem.OnOptionValueChangedHandler
  optionItem.OnOptionValueChangedHandler = function(self)
    local control = self.Control
    local value = self:GetOptionValue()
    EasyOptions:UpdateFrameScale(control.Frame, value)
    if (onOptionValueChangedHandlerCustom ~= nil) then
      onOptionValueChangedHandlerCustom(self)
    end
  end
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionSlider(parent, positionInfo, optionItem)

  control.Frame = optionItem.Frame
  local frame = optionItem.Frame
  frame.FrameScaleOptionItem = optionItem
  frame.FrameScaleControl = control

  -- Apply the value(s) of the control(s) to the frame.
  EasyOptions:UpdateFrameScale(control.Frame, control:GetValue())

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionFrameStrata(parent, positionInfo, optionItem)
  optionItem.Text = optionItem.Text or L("Strata")
  optionItem.TooltipText = optionItem.TooltipText or L("Specifies the strata of the frame.")
  optionItem.DropDownItemInfos = optionItem.DropDownItemInfos or {{"BACKGROUND", L("Background")}, {"LOW", L("Low")}, {"MEDIUM", L("Medium")}, {"HIGH", L("High")}, {"DIALOG", L("Dialog")}, {"FULLSCREEN", L("Full Screen")}, {"FULLSCREEN_DIALOG", L("Full Screen Dialog")}, {"TOOLTIP", L("Tooltip")}}
  local onOptionValueChangedHandlerCustom = optionItem.OnOptionValueChangedHandler
  optionItem.OnOptionValueChangedHandler = function(self)
    local control = self.Control
    local value = self:GetOptionValue()
    EasyOptions:UpdateFrameStrata(control.Frame, value)
    if (onOptionValueChangedHandlerCustom ~= nil) then
      onOptionValueChangedHandlerCustom(self)
    end
  end
  
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionDropDown(parent, positionInfo, optionItem)
  control.Frame = optionItem.Frame
  control.DropDown.Frame = optionItem.Frame
  
  control.Frame = optionItem.Frame
  local frame = optionItem.Frame
  frame.FrameStrataOptionItem = optionItem
  frame.FrameStrataControl = control
  
  -- Apply the value(s) of the control(s) to the frame.
  EasyOptions:UpdateFrameStrata(control.Frame, control:GetValue())

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionFrameLevel(parent, positionInfo, optionItem)
  optionItem.Text = optionItem.Text or L("Level (Within the Strata)")
  optionItem.TooltipText = optionItem.TooltipText or L("Specifies the level of the frame within its strata.")
  optionItem.MinValue = optionItem.MinValue or 0
  optionItem.MaxValue = optionItem.MaxValue or math.max(9990, optionItem.DefaultValue or 0) -- 10000 -- NOTE: We use 9990 rather than 10000 as the default maximum allowed level because some child frames must have a higher level than their parent frame in order to ensure that the child frame appears on top of the parent frame.
  optionItem.ValueStep = optionItem.ValueStep or EasyOptions.Fields.FrameLevelValueStep -- EasyOptions.Fields.FrameLevelRoundIncrement
  optionItem.FormatString = optionItem.FormatString or EasyOptions.Fields.FrameLevelRoundFormatString
  local onOptionValueChangedHandlerCustom = optionItem.OnOptionValueChangedHandler
  optionItem.OnOptionValueChangedHandler = function(self)
    local control = self.Control
    local value = self:GetOptionValue()
    EasyOptions:UpdateFrameLevel(control.Frame, value)
    if (onOptionValueChangedHandlerCustom ~= nil) then
      onOptionValueChangedHandlerCustom(self)
    end
  end
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionSlider(parent, positionInfo, optionItem)
  
  control.Frame = optionItem.Frame
  local frame = optionItem.Frame
  frame.FrameLevelOptionItem = optionItem
  frame.FrameLevelControl = control
  
  -- Apply the value(s) of the control(s) to the frame.
  EasyOptions:UpdateFrameLevel(control.Frame, control:GetValue())

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionFrameBackgroundColor(parent, positionInfo, optionItem)
  optionItem.Text = optionItem.Text or L("Background Color")
  optionItem.TooltipText = optionItem.TooltipText or L("Specifies the background color of the frame.")
  local onOptionValueChangedHandlerCustom = optionItem.OnOptionValueChangedHandler
  optionItem.OnOptionValueChangedHandler = function(self)
    local control = self.Control
    local value = self:GetOptionValue()
    EasyOptions:UpdateFrameBackgroundColor(control.Frame, value)
    if (onOptionValueChangedHandlerCustom ~= nil) then
      onOptionValueChangedHandlerCustom(self)
    end
  end
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateOptionColorPicker(parent, positionInfo, optionItem)
  
  control.Frame = optionItem.Frame
  local frame = optionItem.Frame
  frame.FrameBackgroundColorOptionItem = optionItem
  frame.FrameBackgroundColorControl = control
  
  -- Apply the value(s) of the control(s) to the frame.
  EasyOptions:UpdateFrameBackgroundColor(control.Frame, control:GetColor())

  return control, controlRegionWidth, controlRegionHeight
end
