-- Copyright © 2023 @Groick (Twitch). All rights reserved.
local function L(key, ...) return EasyOptions:Localize(key, ...) end
function EasyOptions:CreateListView(parent, customControlName, text, tooltipTitleText, tooltipText, listViewItemsText, positionInfo, customListViewPanelWidth, customSize, allowFillWidthByDefault, fontObjectName, customFontInfo, customTextColor)
  local typeName = "ListView"
  local baseTypeName = "ListView"
  local defaultSize = EasyOptions:GetDefaultListViewSize()
  local showBackgroundAndBorder = true
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateGroupBoxBase(typeName, baseTypeName, parent, customControlName, text, tooltipTitleText, tooltipText, positionInfo, customSize, defaultSize, showBackgroundAndBorder, allowFillWidthByDefault, fontObjectName, customFontInfo, customTextColor)

  control.GetValue = function(self)
    return self:GetListViewItemIDOfSelectedListViewItem()
  end
  control.SetValue = function(self, value)
    self:SelectListViewItem(value)
  end
  control.GetNumberOfListViewItems = function(self)
    return EasyOptions:GetLength(self.ListViewItems)
  end
  control.GetListViewItem = function(self, listViewItemID)
    local control = self
    if (control.ListViewItems == nil) or (listViewItemID == nil) then
      return nil
    end
    return control.ListViewItems[listViewItemID]
  end
  control.GetFirstListViewItem = function(self)
    local control = self
    local length = control:GetNumberOfListViewItems()
    if (length == 0) then
      return nil
    end
    return control.ListViewItems[1]
  end
  control.GetLastListViewItem = function(self)
    local control = self
    local length = control:GetNumberOfListViewItems()
    if (length == 0) then
      return nil
    end
    return control.ListViewItems[length]
  end
  control.GetNextAvailableListViewItemID = function(self)
    local control = self
    return control:GetNumberOfListViewItems() + 1
  end
  control.HasSelectedListViewItem = function(self)
    local control = self
    return (control.SelectedListViewItem ~= nil)
  end
  control.IsValidListViewItemID = function(self, listViewItemID)
    if (listViewItemID == nil) then
      return false
    end
    return (listViewItemID >= 1) and (listViewItemID <= control:GetNumberOfListViewItems())
  end
  control.GetListViewItemIDOfSelectedListViewItem = function(self)
    return EasyOptions:GetListViewValue(self)
  end
  control.SelectListViewItem = function(self, listViewItemID)
    EasyOptions:SetListViewValue(self, listViewItemID)
  end
  
  local hasWidth, hasHeight, shouldFillWidth = EasyOptions:GetSizeInfoFromCustomSize(customSize)
  
  control.ListViewItems = {}
  control.ListViewItemFrames = {}
  control.AllowResizeHeightToFitListViewItems = (not hasHeight)
  control.AllowResizeListViewPanelWidthToFitListViewItems = (customListViewPanelWidth == nil)
  control.ListViewItemsRegionWidth = 0
  control.ListViewItemsRegionHeight = 0

  local listViewPanel = EasyOptions:CreateListViewPanel(control, customListViewPanelWidth)

  local listViewItemID
  local listViewItemText
  local listViewItemTooltipTitleText
  local listViewItemTooltipText
  local listViewItemOnClickHandler
  local control_ListViewItem, controlRegionWidth_ListViewItem, controlRegionHeight_ListViewItem
  local length = EasyOptions:GetLength(listViewItemsText)
  for i = 1, length do
    listViewItemID = control:GetNextAvailableListViewItemID()
    listViewItemText = listViewItemsText[i]
    listViewItemTooltipTitleText = nil
    listViewItemTooltipText = nil
    listViewItemOnClickHandler = nil
    control_ListViewItem, controlRegionWidth_ListViewItem, controlRegionHeight_ListViewItem = EasyOptions:CreateListViewItem(control, listViewItemID, listViewItemText, listViewItemTooltipTitleText, listViewItemTooltipText, listViewItemOnClickHandler)
  end
  -- control.ControlRegionWidth = control.ControlRegionWidth + 0
  -- control.ControlRegionHeight = control.ControlRegionHeight + 0
  EasyOptions:UpdateListViewAfterAddListViewItems(control)
  controlRegionWidth = control.ControlRegionWidth -- This parameter must be updated after EasyOptions:UpdateListViewAfterAddListViewItems is called.
  controlRegionHeight = control.ControlRegionHeight -- This parameter must be updated after EasyOptions:UpdateListViewAfterAddListViewItems is called.

  -- Override the OnEnabledChangedHandler method.
  local onEnabledChangedHandlerBase = control.OnEnabledChangedHandler
  control.OnEnabledChangedHandler = function(self)
    local control = self
    -- Reserved.
    if (onEnabledChangedHandlerBase ~= nil) then
      onEnabledChangedHandlerBase(self)
    end
  end
  -- EasyOptions:AddSupportForEnabledState(control) -- We do not call this method here because we assume that this method is called in the method that creates this control.
  
  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateListViewPanel(listView, customListViewPanelWidth)
  -- Description: Creates and returns the frame that contains the ListViewItems.
  local controlName = EasyOptions:GetChildControlName(listView, ".ListViewPanel")
  local showBackground = false
  local showBorder = true
  local width = customListViewPanelWidth or EasyOptions:GetDefaultListViewPanelWidth(0, 0)
  local height = 1
  local positionScrollFrameInsideBorderFrame = true
  local customScrollFramePadding = {0, 0, 0, 0} -- {topLeftPaddingX, topLeftPaddingY, bottomRightPaddingX, bottomRightPaddingY}
  local onScrollHandler = function(scrollFrame, offset, isHorizontalScroll)
    local control = scrollFrame.Control
    control:SetControlPointToFillBorderFrameWidth() -- IMPORTANT: This is required because scrolling a control seems to clear the control's anchor points.
  end
  local control, borderFrame, scrollFrame = EasyOptions:CreateControlContainedInScrollFrame("Frame", listView, controlName, showBackground, showBorder, width, height, positionScrollFrameInsideBorderFrame, customScrollFramePadding, onScrollHandler)
  control.Name = controlName
  control.Type = "ListViewPanel"
  control.BaseType = "ListViewPanel"
  control:EnableMouse(false)

  control.ListView = listView
  listView.ListViewPanel = control
  listView.ListViewPanelBorderFrame = borderFrame
  listView.ListViewPanelScrollFrame = scrollFrame
  
  control.SetControlPointToFillBorderFrameWidth = function(self)
    local control = self
    local scrollFrame = control.ScrollFrame
    local offsetX = -scrollFrame.ScrollBarRegionWidth
    control:SetPoint("RIGHT", control.BorderFrame, "RIGHT", offsetX, 0) -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  end 
  control:SetSize(1, 1)
  -- control:SetSize(width, height)
  control:SetControlPointToFillBorderFrameWidth()
  
  borderFrame:ClearAllPoints()
  borderFrame:SetPoint("TOPLEFT", listView, "TOPLEFT", 0, 0) -- "LEFT", "TOP", "RIGHT", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  borderFrame:SetPoint("BOTTOM", listView, "BOTTOM", 0, 0) -- "LEFT", "TOP", "RIGHT", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  
  -- control:SetScript("OnClick", onClickHandler)
  control.OnEnabledChangedHandler = function(self)
    -- Reserved.
  end
  EasyOptions:AddSupportForEnabledState(control)
  
  EasyOptions:AddControlToOwner(control, listView)
  EasyOptions:AddControlToParent(control, listView)

  local controlRegionWidth = width -- listView.ControlRegionWidth
  local controlRegionHeight = height -- listView.ControlRegionHeight
  control.ControlRegionWidth = controlRegionWidth
  control.ControlRegionHeight = controlRegionHeight
  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateListViewItem(listView, listViewItemID, text, tooltipTitleText, tooltipText, onClickHandler)
  local customControlName
  local controlTypeName = "ListViewItem"
  if (listView == nil) or (listView.Name == nil) or (listViewItemID == nil) then
    customControlName = nil
  else
    customControlName = listView.Name.."."..controlTypeName..tostring(listViewItemID)
  end
  local controlName = EasyOptions:GetControlName(controlTypeName, customControlName)
  
  local parent = listView.ListViewPanel
  local labelAnchorControl = listView.ListViewPanel
  local customControlName = controlName
  local fontObjectName = EasyOptions.Fields.DefaultLabelFontObjectName
  local positionInfo_Initial = {"TOPLEFT", "TOPLEFT", 0, 0} -- The ListViewItem will be moved later in this method (see below).
  local customSize = nil
  local wordWrap = false -- Do not allow ListViewItem text to wrap.
  local customFontInfo = nil
  local customTextColor = nil
  local includeUnderline = false
  local customUnderlineWidth = nil
  local frameTemplate = nil
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateLabel(parent, labelAnchorControl, controlTypeName, customControlName, text, tooltipTitleText, tooltipText, fontObjectName, positionInfo_Initial, customSize, wordWrap, customFontInfo, customTextColor, includeUnderline, customUnderlineWidth, frameTemplate)
  control.BaseType = controlTypeName

  control.Select = function(self)
    local control = self
    if (control.ListView == nil) then
      return
    end
    control.ListView:SelectListViewItem(control.ListViewItemID)
  end
  
  local listViewItemFrame = EasyOptions:CreateListViewItemFrame(listView, listViewItemID)
  
  control.ListView = listView
  control.ListViewItemID = listViewItemID
  control.ListViewItemFrame = listViewItemFrame
  control.IsSelected = false
  control.IsHighlighted = false
  listViewItemFrame.ListViewItem = control
  
  local heightPadding = 2 -- This was implemented as a way to create a small gap between the visible appearance of the ListViewItem and the bottom of the ListViewPanel when the scroll bar is scrolled to the bottom of its range.
  local highlightTextureDeltaHeight = 4 -- Indicates how much the highlight texture is above and below the label's text.
  local offsetX = EasyOptions:GetLabelOffsetX()
  local offsetY = 0 -- -highlightTextureDeltaHeight -- EasyOptions:GetLabelOffsetY() - 3
  local indentX = 8
  --
  control:SetHeight(control:GetHeight() + 2 * highlightTextureDeltaHeight + heightPadding)
  --
  control.Label:ClearAllPoints()
  control.Label:SetPoint("TOPLEFT", control, "TOPLEFT", offsetX + indentX, offsetY + EasyOptions:GetLabelOffsetY() - 1)
  control.Label:SetPoint("RIGHT", control, "RIGHT", 0, 0)
  --
  local highlightTexture = control:CreateTexture(controlName..".Highlight", "ARTWORK")
  highlightTexture:SetTexture(EasyOptions:GetTextureInfo("ListViewItemBackgroundHighlightFilePath"))
  highlightTexture:SetPoint("TOPLEFT", control, "TOPLEFT", offsetX, offsetY)
  highlightTexture:SetPoint("BOTTOMRIGHT", control, "BOTTOMRIGHT", 0, offsetY + heightPadding) -- NOTE: This will cause the highlightTexture to appear to extend beyond the label, but that is desirable so ellipsis will be contained within the highlightTexture if they are shown by a label due to the label's width being too small to fit its text.
  control.HighlightTexture = highlightTexture
  controlRegionHeight = controlRegionHeight + 2 * highlightTextureDeltaHeight
  control:SetHitRectInsets(0, 0, 0, heightPadding) -- Left, Right, Top, Bottom. Negative values increase the size of the hit box and positive values decrease the size of the hit box.
  
  local marginX = EasyOptions:GetDefaultListViewItemMarginX()
  local marginY = EasyOptions:GetDefaultListViewItemMarginY()
  local paddingY = EasyOptions:GetDefaultListViewItemPaddingY()
  local offsetX_Initial = marginX
  local offsetY_Initial = marginY - 4
  local offsetX_Adjacent = 0
  local offsetY_Adjacent = paddingY - heightPadding
  local listViewItemPrevious = listView:GetLastListViewItem()
  local positionReferenceControl
  local positionInfo
  if (listViewItemPrevious == nil) then
    positionReferenceControl = parent
    positionInfo = {"TOPLEFT", "TOPLEFT", offsetX_Initial, -offsetY_Initial} -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  else
    positionReferenceControl = listViewItemPrevious
    positionInfo = {"TOPLEFT", "BOTTOMLEFT", offsetX_Adjacent, -offsetY_Adjacent} -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  end
  control:ClearAllPoints()
  control:SetPoint(positionInfo[1], positionReferenceControl, positionInfo[2], positionInfo[3], positionInfo[4])
  control:SetPoint("RIGHT", parent, "RIGHT", -marginX, 0)
  
  EasyOptions:UpdateListViewItemAppearance(control)

  control:HookScript("OnEnter", function(self)
    local control = self
    control.IsHighlighted = true
    EasyOptions:UpdateListViewItemAppearance(control)
  end)
  control:HookScript("OnLeave", function(self)
    local control = self
    control.IsHighlighted = false
    EasyOptions:UpdateListViewItemAppearance(control)
  end)
  local onClickHandlerCustom = onClickHandler
  control:HookScript("OnMouseDown", function(self, button)
    local control = self
    if (control.ListView ~= nil) and (button == "LeftButton") then
      control.ListView.MouseDownListViewItem = control
    end
    if (onClickHandlerCustom ~= nil) then
      onClickHandlerCustom(self, button)
    end
  end)
  control:HookScript("OnMouseUp", function(self, button)
    local control = self
    if (not control.IsSelected) and (control.IsHighlighted) and (control.ListView ~= nil) and (control.ListView.MouseDownListViewItem == control) and (button == "LeftButton") then
      control.ListView:SelectListViewItem(control.ListViewItemID)
    end
  end)
  -- control:SetScript("OnClick", onClickHandler)
  
  table.insert(listView.ListViewItems, control)
  table.insert(listView.ListViewItemFrames, listViewItemFrame)
  EasyOptions:AddControlToOwner(control, listView)
  EasyOptions:AddControlToParent(control, parent)
  EasyOptions:AddControlToOwner(listViewItemFrame, listView)
  EasyOptions:AddControlToParent(listViewItemFrame, listView)
  
  -- Override the OnEnabledChangedHandler method.
  local onEnabledChangedHandlerBase = control.OnEnabledChangedHandler
  control.OnEnabledChangedHandler = function(self)
    local control = self
    if (not control:IsEnabled()) then
      control.IsHighlighted = false
    end
    EasyOptions:UpdateListViewItemAppearance(control)
    if (onEnabledChangedHandlerBase ~= nil) then
      onEnabledChangedHandlerBase(self)
    end
  end
  -- EasyOptions:AddSupportForEnabledState(control) -- We do not call this method here because we assume that this method is called in the method that creates this control.
  
  control.ControlRegionWidth = controlRegionWidth
  control.ControlRegionHeight = controlRegionHeight
  listView.ListViewItemsRegionWidth = math.max(controlRegionWidth, listView.ListViewItemsRegionWidth)
  listView.ListViewItemsRegionHeight = listView.ListViewItemsRegionHeight + controlRegionHeight + EasyOptions:IIF(listViewItemPrevious ~= nil, paddingY, 0)
  EasyOptions:UpdateListViewAfterAddListViewItems(listView) -- IMPORTANT: This must be called after listView.ListViewItemsRegionWidth and listView.ListViewItemsRegionHeight are set.

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateListViewItemFrame(listView, listViewItemID)
  local controlName = EasyOptions:GetChildControlName(listView, ".ListViewItemFrame"..tostring(listViewItemID))
  local control = EasyOptions:CreateContainerFrame(controlName, listView, false, false, true)
  control.Name = controlName
  control.Type = "ListViewItemFrame"
  control.BaseType = "ListViewItemFrame"
  control:EnableMouse(false)
  
  control.ListViewItemID = listViewItemID
  
  local width = 1
  local height = 1
  control:SetSize(width, height)

  control:ClearAllPoints()
  control:SetPoint("TOPLEFT", listView.ListViewPanelBorderFrame, "TOPRIGHT", -4, 0) -- "LEFT", "TOP", "RIGHT", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  control:SetPoint("BOTTOMRIGHT", listView, "BOTTOMRIGHT", 0, 0) -- "LEFT", "TOP", "RIGHT", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  control:Hide()
  
  -- control:SetScript("OnClick", onClickHandler)
  control.OnEnabledChangedHandler = function(self)
    -- Reserved.
  end
  EasyOptions:AddSupportForEnabledState(control)
  
  local controlRegionWidth = width -- listView.ControlRegionWidth
  local controlRegionHeight = height -- listView.ControlRegionHeight
  control.ControlRegionWidth = controlRegionWidth
  control.ControlRegionHeight = controlRegionHeight
  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionListView(parent, positionInfo, optionItem)
  local optionName = optionItem.Name
  local text = EasyOptions:GetControlText(optionItem)
  local tooltipTitleText = optionItem.TooltipTitleText or text
  local tooltipText = optionItem.TooltipText
  local listViewItemsText = nil
  local customListViewPanelWidth = optionItem.ListViewPanelWidth
  local customSize = optionItem.Size
  local allowFillWidthByDefault = (optionItem.AutoFitWidth == false)
  local fontObjectName = nil
  local customFontInfo = optionItem.FontInfo
  local customTextColor = optionItem.TextColor
  --
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateListView(parent, nil, text, tooltipTitleText, tooltipText, listViewItemsText, positionInfo, customListViewPanelWidth, customSize, allowFillWidthByDefault, fontObjectName, customFontInfo, customTextColor)
  -- EasyOptions:AddRightButtonDownHandlerForOptionControl(control)
  --
  optionItem.Control = control
  control.OptionItem = optionItem
  if (optionName ~= nil) and (optionName ~= "") then
    EasyOptions.Current.OptionControls[optionName] = control
  end
  
  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionListViewItem(parent, positionInfo, optionItem)
  local optionName = optionItem.Name
  local text = EasyOptions:GetControlText(optionItem)
  local tooltipTitleText = optionItem.TooltipTitleText or text
  local tooltipText = optionItem.TooltipText
  local customSize = optionItem.Width
  local onClickHandler = optionItem.OnClickHandler
  
  local listView
  local listViewItemID
  if (parent == nil) or (parent.BaseType ~= "ListView") then
    listView = nil
    listViewItemID = 1
  else
    listView = parent
    listViewItemID = listView:GetNextAvailableListViewItemID()
  end

  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateListViewItem(listView, listViewItemID, text, tooltipTitleText, tooltipText, onClickHandler)
  -- EasyOptions:AddRightButtonDownHandlerForOptionControl(control)
  
  optionItem.Control = control
  control.OptionItem = optionItem
  control.ListViewItemFrame.OptionItem = optionItem
  if (optionName ~= nil) and (optionName ~= "") then
    EasyOptions.Current.OptionControls[optionName] = control
  end
  
  return control.ListViewItemFrame, controlRegionWidth, controlRegionHeight -- IMPORTANT: We must return control.ListViewItemFrame rather than control so controls of child OptionItems will be added to control.ListViewItemFrame.
end
function EasyOptions:UpdateListViewAfterAddListViewItems(control)
  -- Initialize properties.
  control.ListViewItemsRegionWidthPrevious = control.ListViewItemsRegionWidthPrevious or 0
  control.ListViewItemsRegionHeightPrevious = control.ListViewItemsRegionHeightPrevious or 0
  
  -- Update properties.
  -- control.ControlRegionWidth = control.ControlRegionWidth + (control.ListViewItemsRegionWidth - control.ListViewItemsRegionWidthPrevious)
  control.ControlRegionHeight = math.max(control.ControlRegionHeight, control.ListViewItemsRegionHeight)
  
  -- Resize the ListView to fit its ListViewItems (if required).
  local marginY = EasyOptions:GetDefaultListViewItemMarginY()
  local controlHeightMinRequiredForListViewItems = control.ListViewItemsRegionHeight + 2 * marginY
  local controlHeightMinDesired = math.min(controlHeightMinRequiredForListViewItems, EasyOptions:GetOptionPanelSizeExcludingMargins()[2])
  --
  -- Auto set the height (if required).
  --  IMPORTANT: We must set the height before we update the visible state of the scroll bar (or set the width of the ListViewPanel).
  if (control.AllowResizeHeightToFitListViewItems) and (control:GetHeight() < controlHeightMinDesired) then
    local controlHeightPrevious = control:GetHeight()
    control:SetHeight(controlHeightMinDesired)
    control.ControlRegionHeight = control.ControlRegionHeight + (control:GetHeight() - controlHeightPrevious)
  end
  --
  -- Update the visible state of the scroll bar.
  local requiresVerticalScrollBar = (control:GetHeight() + 1.0) < controlHeightMinRequiredForListViewItems -- NOTE: We add padding to the actual height to account for potential rounding errors and to avoid showing the scroll bars if the actual control height is very close to the desired control height.
  control.ListViewPanelScrollFrame:SetVerticalScrollBarVisibleState(requiresVerticalScrollBar)
  -- control.ListViewPanelScrollFrame:AutoSetVerticalScrollBarVisibleState() -- NOTE: We cannot use control.ListViewPanelScrollFrame:AutoSetVerticalScrollBarVisibleState() because that method does not seem to work until the control is shown.
  --
  -- Auto set the width of the ListViewPanel.
  --  IMPORTANT: This must be done after we update the visible state of the scroll bar.
  local listViewPanelWidthMinDesired = EasyOptions:GetDefaultListViewPanelWidth(control.ListViewItemsRegionWidth, control.ListViewPanelScrollFrame.ScrollBarRegionWidth)
  if (control.AllowResizeListViewPanelWidthToFitListViewItems) and (control.ListViewPanelBorderFrame:GetWidth() < listViewPanelWidthMinDesired) then
    control.ListViewPanelBorderFrame:SetWidth(listViewPanelWidthMinDesired)
    if (control:GetWidth() < control.ListViewPanelBorderFrame:GetWidth()) then
      control:SetWidth(control.ListViewPanelBorderFrame:GetWidth()) -- Resize the ListView to be wide enough to fit its ListViewPanel.
    end
  end
  --
  control.ListViewPanel:SetControlPointToFillBorderFrameWidth()

  -- Update the state of the ListViewItems.
  local listViewItemIDOfSelectedListViewItem = control:GetListViewItemIDOfSelectedListViewItem() or 1 -- init
  local optionItem = control.OptionItem
  if (optionItem ~= nil) then
    if (EasyOptionsDB["EnableStickyListViewItems"]) then
      -- Restore the previously selected item from options.
      local optionName = optionItem.Name
      local value = EasyOptions:GetOptionValueOrDefaultValue(optionName, nil) -- IMPORTANT: We don't pass optionItem.DefaultValue because we want to use a value that is stored in options, but not the default value for the option item.
      if (control:IsValidListViewItemID(value)) then
        listViewItemIDOfSelectedListViewItem = value
      end
    else
      -- -- Set the option value to the initially selected item.
      -- local allowUpdateControl = false
      -- EasyOptions:SetOptionValueFromControlInfo(control, listViewItemIDOfSelectedListViewItem, allowUpdateControl)
    end
  end
  control:SelectListViewItem(listViewItemIDOfSelectedListViewItem) -- IMPORTANT: We must call control:SelectListViewItem after a new item is added to the ListView in order to update the graphics of the ListViewItem that was added, even if the newly added ListViewItem should not be selected.
  
  -- Update properties.
  control.ListViewItemsRegionWidthPrevious = control.ListViewItemsRegionWidth
  control.ListViewItemsRegionHeightPrevious = control.ListViewItemsRegionHeight
end
function EasyOptions:UpdateListViewItemAppearance(control)
  if (control == nil) then
    return
  end

  -- Text
  if (control:IsEnabled()) then -- Only modify the text color if the control is enabled.
    local textColor = EasyOptions:IIF(control.IsSelected, {1.0, 1.0, 1.0}, EasyOptionsDB["ControlHighlightColor"]) -- The text color of the standard WoW ListViewItem is white when it is selected and the highlight color (a.k.a., title color) when it is not selected.
    control.Label:SetTextColor(textColor[1], textColor[2], textColor[3], 1.0)
    EasyOptions:SetDefaultTextColor(control.Label, true) -- Update the control's default text color.
  end

  -- HighlightTexture
  local highlightTextureVisible = control.IsSelected or control.IsHighlighted
  local highlightTextureColor = EasyOptions:IIF(control.IsSelected and control:IsEnabled(), EasyOptionsDB["ControlHighlightColor"], {0.5, 0.5, 0.5})
  control.HighlightTexture:SetVertexColor(highlightTextureColor[1], highlightTextureColor[2], highlightTextureColor[3], 1.0)
  EasyOptions:SetVisibleState(control.HighlightTexture, highlightTextureVisible)
end
function EasyOptions:SelectListViewItem(listView, listViewItemID)
  if (listView:GetNumberOfListViewItems() == 0) then
    return
  end

  -- Update control properties.
  local length = listView:GetNumberOfListViewItems()
  local listViewItem
  local listViewItemFrame
  listView.SelectedListViewItem = nil -- init
  for i = 1, length do
    listViewItem = listView.ListViewItems[i]
    listViewItemFrame = listViewItem.ListViewItemFrame
    -- Set listViewItem.IsSelected.
    listViewItem.IsSelected = (listViewItem.ListViewItemID == listViewItemID)
    if (listViewItem.IsSelected) then
      listView.SelectedListViewItem = listViewItem
    end
    -- Update the ListViewItem's appearance.
    EasyOptions:UpdateListViewItemAppearance(listViewItem)
    -- Update the visible state of the ListViewItem's ListViewItemFrame.
    if (listViewItemFrame ~= nil) then
      EasyOptions:SetVisibleState(listViewItemFrame, listViewItem.IsSelected)
    end
  end
end
function EasyOptions:GetListViewValue(control)
  if (control.SelectedListViewItem == nil) then
    return nil
  else
    return control.SelectedListViewItem.ListViewItemID
  end
end
function EasyOptions:SetListViewValue(control, listViewItemID)
  -- Update the control.
  EasyOptions:SelectListViewItem(control, listViewItemID)

  -- Update Options (if required).
  if (not EasyOptions.Current.IsBuildingOptionFrame) then
    local allowUpdateControl = false
    EasyOptions:SetOptionValueFromControlInfo(control, listViewItemID, allowUpdateControl)
  end
end
function EasyOptions:GetDefaultListViewSize()
  local referenceSize = EasyOptions:GetDefaultGroupBoxSize()
  local width = referenceSize[1]
  local height = 16 + 2 * EasyOptions:GetDefaultListViewItemMarginY() -- This value is arbitrary, but it should be a small value because the ListView's ListViewPanel height is only allowed to increase from its current value when fitting the height of its ListViewItems.
  return {width, height}
end
function EasyOptions:GetDefaultListViewPanelWidth(listViewItemWidthMax, scrollBarRegionWidth)
  local result = listViewItemWidthMax + EasyOptions:GetDefaultListViewPanelWidthMinRequired(scrollBarRegionWidth)
  result = EasyOptions:LimitValue(result, EasyOptions:GetDefaultListViewPanelWidthMin(scrollBarRegionWidth), EasyOptions:GetDefaultListViewPanelWidthMax(), true)
  return result
end
function EasyOptions:GetDefaultListViewPanelWidthMin(scrollBarRegionWidth)
  return 32 + EasyOptions:GetDefaultListViewPanelWidthMinRequired(scrollBarRegionWidth)
end
function EasyOptions:GetDefaultListViewPanelWidthMax()
  return EasyOptions:GetWidthForNumberOfColumns(1) -- + EasyOptions:GetDefaultListViewPanelWidthMinRequired(scrollBarRegionWidth)
end
function EasyOptions:GetDefaultListViewPanelWidthMinRequired(scrollBarRegionWidth)
  return EasyOptions.Fields.DefaultScrollBarRegionWidth + 2 * EasyOptions:GetDefaultListViewItemMarginX() + scrollBarRegionWidth
end
function EasyOptions:GetDefaultListViewItemMarginX()
  -- Description: Specifies the default distance from the left edge of a ListViewPanel to the left edge of the ListViewItems.
  return EasyOptions:GetDefaultControlMarginX()
end
function EasyOptions:GetDefaultListViewItemMarginY()
  -- Description: Specifies the default distance from the top edge of a ListViewPanel to the top edge of the first ListViewItem.
  return EasyOptions:GetDefaultControlMarginY()
end
function EasyOptions:GetDefaultListViewItemPaddingY()
  -- Description: Specifies the default distance between ListViewItems.
  return math.min(1, EasyOptions:GetDefaultControlPaddingY())
end
