components_ui_button_TextButton.bs

import "pkg:/source/utils/misc.bs"

sub init()
  m.buttonFocusBorder = m.top.findNode("buttonFocusBorder")
  m.buttonBackground = m.top.findNode("buttonBackground")
  m.buttonText = m.top.findNode("buttonText")

  m.top.observeField("background", "onBackgroundChanged")
  m.top.observeField("textColor", "onTextColorChanged")
  m.top.observeField("text", "onTextChanged")
  m.top.observeField("padding", "onPaddingChanged")
  m.top.observeField("focusedChild", "onFocusChanged")
  m.top.observeField("minWidth", "onSizeChanged")
  m.top.observeField("minHeight", "onSizeChanged")

  applyTheme()
end sub

sub applyTheme()
  colorConstants = m.global.constants.colors

  ' Set default colors
  m.top.background = colorConstants.background_secondary
  m.top.textColor = colorConstants.text_primary
  m.top.focusBackground = colorConstants.background_primary
  m.top.textFocusColor = colorConstants.text_primary
end sub

sub onFocusChanged()
  colorConstants = m.global.constants.colors

  if m.top.hasFocus()
    ' Button background
    if isValid(m.top.focusBackground)
      m.buttonBackground.blendColor = m.top.focusBackground
    end if
    ' Button text
    if isValid(m.top.textFocusColor)
      m.buttonText.color = m.top.textFocusColor
    end if
    ' Focus border
    if m.top.enableBorder
      m.buttonFocusBorder.blendColor = colorConstants.primary
      m.buttonFocusBorder.visible = true
    end if
  else
    ' Button background
    if isValid(m.top.background)
      m.buttonBackground.blendColor = m.top.background
    end if
    ' Button text
    if isValid(m.top.textColor)
      m.buttonText.color = m.top.textColor
    end if
    ' Focus border
    m.buttonFocusBorder.visible = false
  end if
end sub

sub onBackgroundChanged()
  m.buttonBackground.blendColor = m.top.background
end sub

sub onTextColorChanged()
  m.buttonText.color = m.top.textColor
end sub

sub onTextChanged()
  m.buttonText.text = m.top.text
  setSizeAndCenterText()
end sub

sub setSizeAndCenterText()
  if not isValid(m.buttonText) then return
  if m.buttonText.text.Len() = 0 then return

  ' Store the current text to detect if we've already sized for this text
  if not isValid(m.lastSizedText) then m.lastSizedText = ""
  if m.lastSizedText = m.buttonText.text and isValid(m.top.width) and m.top.width > 0
    ' We've already sized this text, just update the focus border and return
    setFocusBorderSize()
    return
  end if
  m.lastSizedText = m.buttonText.text

  ' Always use font-based calculation to avoid stale localBoundingRect() issues
  textLength = m.buttonText.text.Len()
  fontSize = m.buttonText.font.size
  charWidth = fontSize * 0.64
  textWidth = textLength * charWidth

  ' Use font size for height to avoid stale localBoundingRect() issues
  textHeight = fontSize

  ' print "[TextButton] text='"; m.buttonText.text; "', length="; textLength; ", charWidth="; charWidth; ", textWidth="; textWidth; ", textHeight="; textHeight

  ' Calculate button dimensions with padding
  buttonWidth = textWidth + (m.top.padding * 2)
  buttonHeight = textHeight + (m.top.padding * 2)

  ' print "[TextButton] size with padding: width=", buttonWidth, ", height=", buttonHeight

  ' Ensure minimum dimensions (this is the ONLY place minWidth should be enforced)
  if buttonWidth < m.top.minWidth
    buttonWidth = m.top.minWidth
  end if
  if buttonHeight < m.top.minHeight
    buttonHeight = m.top.minHeight
  end if

  ' print "[TextButton] ACTUAL size (using minWidth): width=", buttonWidth, ", height=", buttonHeight

  ' Set background size
  m.buttonBackground.width = buttonWidth
  m.buttonBackground.height = buttonHeight

  ' Center the text in the button
  m.buttonText.width = buttonWidth
  m.buttonText.height = buttonHeight
  m.buttonText.translation = [0, 0]

  setFocusBorderSize()
end sub

sub onPaddingChanged()
  setSizeAndCenterText()
end sub

sub onSizeChanged()
  setSizeAndCenterText()
end sub

sub onHeightChanged()
  setSizeAndCenterText()
end sub

sub onWidthChanged()
  setSizeAndCenterText()
end sub

sub onEnabledChanged()
  colorConstants = m.global.constants.colors

  if m.top.enabled
    m.top.background = colorConstants.background_secondary
    m.top.textColor = colorConstants.text_primary
  else
    m.top.background = colorConstants.background_primary
    m.top.textColor = colorConstants.text_disabled
  end if
end sub

sub setFocusBorderSize()
  if not m.top.enableBorder then return
  if m.buttonBackground.width < 1 then return

  m.buttonFocusBorder.width = m.buttonBackground.width + (m.top.borderSize * 2)
  m.buttonFocusBorder.height = m.buttonBackground.height + (m.top.borderSize * 2)

  ' translate the button so the focus border is visible
  m.buttonBackground.translation = [m.top.borderSize, m.top.borderSize]
  m.buttonText.translation = [m.top.borderSize, m.top.borderSize]
end sub