components_ui_button_TextButton.bs
import "pkg:/source/utils/misc.bs"
sub init()
m.buttonBackground = m.top.findNode("buttonBackground")
m.buttonBorder = m.top.findNode("buttonBorder")
m.buttonText = m.top.findNode("buttonText")
m.top.observeField("enabled", "onEnabledChanged")
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")
' Enable render tracking on parent to know when component has rendered
m.top.enableRenderTracking = true
m.top.observeField("renderTracking", "onRenderComplete")
applyTheme()
end sub
sub applyTheme()
constants = m.global.constants
' Set default colors
m.top.background = constants.colorBackgroundSecondary
m.top.textColor = constants.colorTextPrimary
m.top.focusBorder = constants.colorPrimary
m.top.focusBackground = constants.colorBackgroundSecondary
m.top.textFocusColor = constants.colorTextPrimary
end sub
sub onFocusChanged()
if m.top.hasFocus()
' Button border - change to focus color
if m.top.enableBorder
m.buttonBorder.blendColor = m.top.focusBorder
else
' Border disabled - ensure it stays invisible
m.buttonBorder.blendColor = m.top.background
end if
' Button background
m.buttonBackground.blendColor = m.top.focusBackground
' Button text
m.buttonText.color = m.top.textFocusColor
else
' Button border - match background color
m.buttonBorder.blendColor = m.top.background
' Button background
m.buttonBackground.blendColor = m.top.background
' Button text
m.buttonText.color = m.top.textColor
end if
end sub
sub onBackgroundChanged()
m.buttonBackground.blendColor = m.top.background
' Border matches background when not focused OR when borders are disabled
if not m.top.hasFocus() or not m.top.enableBorder
m.buttonBorder.blendColor = m.top.background
end if
end sub
sub onTextColorChanged()
m.buttonText.color = m.top.textColor
end sub
sub onTextChanged()
m.buttonText.text = m.top.text
' If already rendered, resize immediately. Otherwise wait for onRenderComplete
if m.top.renderTracking = "full"
setSizeAndCenterText()
end if
end sub
' Called when the component has rendered and we can measure the label accurately
sub onRenderComplete()
if m.top.renderTracking <> "full" then return
setSizeAndCenterText()
end sub
sub setSizeAndCenterText()
if not isValid(m.buttonText) then return
if m.buttonText.text.Len() = 0 then return
' Reset label size to allow accurate measurement of text content
m.buttonText.width = 0
m.buttonText.height = 0
' Get accurate text dimensions from rendered label
boundingRect = m.buttonText.localBoundingRect()
textWidth = boundingRect.width
' If not rendered yet, wait for onRenderComplete
if textWidth = 0 then return
' Calculate visible text height for equal padding
' localBoundingRect height includes line spacing, adjust to match horizontal padding
fontSize = m.buttonText.font.size
visibleTextHeight = fontSize * 0.7
' Calculate button dimensions with padding
buttonWidth = textWidth + (m.top.padding * 2)
buttonHeight = visibleTextHeight + (m.top.padding * 2)
' 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
' 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()
' Show the button now that it's properly sized
m.buttonBackground.visible = true
m.buttonBorder.visible = true
m.buttonText.visible = true
' Signal that the button is ready (sized and visible)
m.top.ready = true
end sub
sub onPaddingChanged()
setSizeAndCenterText()
end sub
sub onSizeChanged()
setSizeAndCenterText()
end sub
sub onHeightChanged()
setSizeAndCenterText()
end sub
sub onWidthChanged()
setSizeAndCenterText()
end sub
sub onEnabledChanged()
constants = m.global.constants
if m.top.enabled
m.top.background = constants.colorBackgroundSecondary
m.top.textColor = constants.colorTextPrimary
else
m.top.background = constants.colorBackgroundPrimary
m.top.textColor = constants.colorTextDisabled
end if
end sub
sub setFocusBorderSize()
if m.buttonBackground.width < 1 then return
' Border poster must be same size as background
m.buttonBorder.width = m.buttonBackground.width
m.buttonBorder.height = m.buttonBackground.height
end sub