components_ui_progress_ProgressPill.bs

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

' Same padding, icon slot and action-safe edge as Toast, so the two read as one family.
const PILL_PADDING = 30
const PILL_SPINNER_SIZE = 32
const PILL_SPINNER_GAP = 12
' 1080 - the 5% action-safe margin (96px)
const PILL_BOTTOM_EDGE = 984

sub init()
  m.container = m.top.findNode("pillContainer")
  m.background = m.top.findNode("pillBackground")
  m.spinner = m.top.findNode("pillSpinner")
  m.label = m.top.findNode("pillText")
  m.fadeIn = m.top.findNode("fadeIn")

  m.background.blendColor = m.global.constants.colorBackgroundSecondary
  m.spinner.poster.width = PILL_SPINNER_SIZE
  m.spinner.poster.height = PILL_SPINNER_SIZE

  m.isSized = false
  m.container.opacity = 0
  m.top.visible = false

  ' The label can only be measured once it has rendered (same approach as Toast).
  m.top.enableRenderTracking = true
  m.top.observeField("renderTracking", "onRenderTracking")
  m.top.observeField("text", "onTextChanged")
  m.top.observeField("isShown", "onIsShownChanged")
end sub

sub onTextChanged()
  m.label.text = m.top.text
  m.isSized = false
end sub

sub onIsShownChanged()
  if not m.top.isShown
    m.fadeIn.control = "stop"
    m.container.opacity = 0
    m.top.visible = false
    return
  end if
  m.top.visible = true
  if m.isSized then reveal()
end sub

sub onRenderTracking()
  if m.top.renderTracking <> "full" or m.isSized then return
  sizeAndPosition()
  if m.isSized and m.top.isShown then reveal()
end sub

sub reveal()
  m.container.opacity = 0
  m.fadeIn.control = "start"
end sub

sub sizeAndPosition()
  if m.label.text.Len() = 0 then return
  m.label.width = 0
  m.label.height = 0
  textWidth = m.label.localBoundingRect().width
  if textWidth = 0 then return

  height = m.label.font.size * 0.7 + PILL_PADDING * 2
  if height < PILL_SPINNER_SIZE + PILL_PADDING * 2 then height = PILL_SPINNER_SIZE + PILL_PADDING * 2
  width = PILL_PADDING + PILL_SPINNER_SIZE + PILL_SPINNER_GAP + textWidth + PILL_PADDING

  m.background.width = width
  m.background.height = height
  m.spinner.translation = [PILL_PADDING, (height - PILL_SPINNER_SIZE) / 2]
  labelX = PILL_PADDING + PILL_SPINNER_SIZE + PILL_SPINNER_GAP
  m.label.width = textWidth
  m.label.height = height
  m.label.translation = [labelX, 0]

  ' Centered, on the 720p output grid (every 3 px of 1080p); see dialogLayout.bs.
  x = int((1920 - width) / 2)
  y = int(PILL_BOTTOM_EDGE - height)
  m.top.translation = [x - (x mod 3), y - (y mod 3)]
  m.isSized = true
end sub