; ***************************************************************************
; copyright   : (C) 2025 by Martin Preuss
; email       : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome".                              *
; * Please see toplevel file COPYING of that project for license details.   *
; ***************************************************************************


; ***************************************************************************
; defs

.equ WID_WIDGET_INTER_BORDER = 2



; ***************************************************************************
; code

.cseg



; ---------------------------------------------------------------------------
; @routine WID_Widget_new @global
;
; @param Y pointer to window SRAM
; @param X pointer to parent
; @param r18 WID_OFFS_OPTIONS1
; @param r19 WID_OFFS_OPTIONS2

WID_Widget_Init:
  push r18
    push r19
      push xl
        push xh
          ldi zl, LOW(WID_Widget_Handler)
          ldi zh, HIGH(WID_Widget_Handler)
          clr r17
          rcall OBJ_Init
        pop xh
      pop xl
    pop r19
  pop r18
  std Y+WID_OFFS_OPTIONS1, r18
  std Y+WID_OFFS_OPTIONS2, r19
  mov r16, xl
  or r16, xh
  breq WID_Widget_noParent
  ; copy defaults from parent
  adiw xh:xl, WID_OFFS_BG_COL_LO
  ld r16, X+                       ; WID_OFFS_BG_COL_LO
  std Y+WID_OFFS_BG_COL_LO, r16
  ld r16, X+                       ; WID_OFFS_BG_COL_HI
  std Y+WID_OFFS_BG_COL_HI, r16
  ld r16, X+                       ; WID_OFFS_FG_COL_LO
  std Y+WID_OFFS_FG_COL_LO, r16
  ld r16, X+                       ; WID_OFFS_FG_COL_HI
  std Y+WID_OFFS_FG_COL_HI, r16
  ld r16, X+                       ; WID_OFFS_FONT_LO
  std Y+WID_OFFS_FONT_LO, r16
  ld r16, X+                       ; WID_OFFS_FONT_HI
  std Y+WID_OFFS_FONT_HI, r16
  rjmp WID_Widget_end
WID_Widget_noParent:               ; preset without parent
  clr r16
  std Y+WID_OFFS_FONT_LO, r16
  std Y+WID_OFFS_FONT_HI, r16
  
  std Y+WID_OFFS_FG_COL_LO, r16    ; foreground black
  std Y+WID_OFFS_FG_COL_HI, r16
  dec r16
  std Y+WID_OFFS_BG_COL_LO, r16    ; background white
  std Y+WID_OFFS_BG_COL_HI, r16
  
  ldi r16, 2                       ; default borders
  std Y+WID_OFFS_BORDER_TOP, r16
  std Y+WID_OFFS_BORDER_BOT, r16
  std Y+WID_OFFS_BORDER_LEFT, r16
  std Y+WID_OFFS_BORDER_RIGHT, r16
WID_Widget_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine WID_Widget_Handler
;
; Signal handler for an object. A signal can have up to 3 parameters
; conveyed in registers R18, R19 and X.
;
; @param Y pointer to object SRAM
; @param r16 signal
; @param R18 1st param
; @param R19 2nd param
; @param X   3rd param
; @clobbers any, !Y

WID_Widget_Handler:
  cpi r16, WID_SIGNAL_GETMINWIDTH
  breq WID_Widget_Handler_getMinWidth
  cpi r16, WID_SIGNAL_GETMINHEIGHT
  breq WID_Widget_Handler_getMinHeight
  cpi r16, WID_SIGNAL_LAYOUT
  breq WID_Widget_Handler_layout
  cpi r16, WID_SIGNAL_DRAW
  breq WID_Widget_Handler_draw
  ; for now just forward signal to all children
WID_Widget_Handler_forward:
  rcall OBJ_ForwardSignalToChildren
  ret
WID_Widget_Handler_getMinWidth:
  rjmp widgetGetMinWidth
WID_Widget_Handler_getMinHeight:
  rjmp widgetGetMinHeight
WID_Widget_Handler_layout:
  rjmp widgetLayout
WID_Widget_Handler_draw:
  rjmp wDraw
; @end




wDraw:
  ldd r16, Y+OBJ_OFFS_OPTIONS
  sbrs r16,  WID_OPTIONS0_BIT_VISIBLE    ; only draw visible widgets
    rjmp wDraw_ret
  cbr r16, (1<<WID_OPTIONS0_BIT_DIRTY)
  std Y+OBJ_OFFS_OPTIONS, r16
  
  ; fill window background
  ldd r2,  Y+WID_OFFS_BG_COL_LO
  ldd r3,  Y+WID_OFFS_BG_COL_HI
  ldd r4,  Y+WID_OFFS_ABS_X_LO
  ldd r5,  Y+WID_OFFS_ABS_X_HI
  ldd r6,  Y+WID_OFFS_ABS_Y_LO
  ldd r7,  Y+WID_OFFS_ABS_Y_HI
  ldd r8,  Y+WID_OFFS_WIDTH_LO
  ldd r9,  Y+WID_OFFS_WIDTH_HI
  ldd r10, Y+WID_OFFS_HEIGHT_LO
  ldd r11, Y+WID_OFFS_HEIGHT_HI
  bigcall ILI9341_FillRect
wDraw_ret:
  ret
; @end




widgetLayout:
  rjmp wVLayout



wVLayout:
  rcall wSetChildrenWidthsFromMinWidths
  rcall wSetChildrenHeightsFromMinHeights

  ; count number of expandable children
  ldi r16, (1<<WID_OPTIONS1_BIT_STRETCH_Y)        ; value
  ldi r17, (1<<WID_OPTIONS1_BIT_STRETCH_Y)        ; mask
  rcall widgetCountVisibleChildrenWithOptions1    ; r18=number of matching visible children (r24, r25, X)
  tst r18
  breq wVLayout_Ydone                             ; no expandable children, nothing to distribute
  ; determine full height needed by all children
  push r18                                        ; number of visible expandable child widgets
    clr r17                                       ; mask=0 -> count all visible children
    rcall wGetSumOfMatchingVisibleChildrenHeights ; r19:r18=sum of all children heights
  pop r22
  clr r23                                         ; r23:r22=number of visible expandable children
  ; calculate number of bytes to add to each expandable child widget
  ldd r20, Y+WID_OFFS_HEIGHT_LO                   ; total height
  ldd r21, Y+WID_OFFS_HEIGHT_HI
  clr r16
  ldd r17, Y+WID_OFFS_BORDER_TOP                  ; subtract top border
  sub r20, r17
  sbc r21, r16
  brcs wVLayout_heightTooSmall                    ; jmp if too small
  ldd r17, Y+WID_OFFS_BORDER_BOT                  ; subtract bottom border
  sub r20, r17
  sbc r21, r16
  brcs wVLayout_heightTooSmall                    ; jmp if too small
  
  sub r20, r18                                    ; r21:r20 = HEIGHT-SUM_OF_VIS_CHILDREN_HEIGHTS
  sbc r21, r19
  brcc wVLayout_heightTooSmall
  breq wVLayout_yDone                             ; nothing to distribute
  bigcall Utils_Divu16_16_16                      ; r17:r16 = r21:r20 / r23:r22
  ; add additional pixel to heights of expandable child widgets
  rcall wAddToHeightsOfExpandableVisibleChildren

wVLayout_yDone:
  rcall wSetRelYFromHeightInVisibleChildren
  rcall wAlignChildrenHorizontally
;  rcall wSetAbsoluteCoords call in GUI loop after calling layout on all widgets
wVLayout_heightTooSmall:
  ; TODO: how to handle this case?
  ret
; @end



wSetAbsoluteCoords:
  push yl
    push yh
wSetAbsoluteCoords_loop:
      ldd r18, Y+OBJ_OFFS_OPTIONS
      andi r18, WID_OPTIONS0_BIT_VISIBLE
      breq wSetAbsoluteCoords_nextSibling
      push yl
        push yh
          bigcall Tree_GetParentObject
          clr r18
          clr r19
          clr r20
          clr r21
          mov r17, xl
          or r17, xh
          breq wSetAbsoluteCoords_r1820set
          mov yl, xl
          mov yh, xh
          ldd r18, Y+WID_OFFS_ABS_X_LO
          ldd r19, Y+WID_OFFS_ABS_X_HI
          ldd r20, Y+WID_OFFS_ABS_Y_LO
          ldd r21, Y+WID_OFFS_ABS_Y_HI
wSetAbsoluteCoords_r1820set:
        pop yh
      pop yl
      ; handle X
      ldd r16, Y+WID_OFFS_REL_X_LO
      ldd r17, Y+WID_OFFS_REL_X_HI
      add r16, r18
      adc r17, r19
      std Y+WID_OFFS_ABS_X_LO, r16
      std Y+WID_OFFS_ABS_X_HI, r17
      ; handle Y
      ldd r16, Y+WID_OFFS_REL_Y_LO
      ldd r17, Y+WID_OFFS_REL_Y_HI
      add r16, r20
      adc r17, r21
      std Y+WID_OFFS_ABS_Y_LO, r16
      std Y+WID_OFFS_ABS_Y_HI, r17
      bigcall Tree_GetObjectBelow
      rjmp wSetAbsoluteCoords_loopEnd
wSetAbsoluteCoords_nextSibling:
      bigcall Tree_GetNextSibling
wSetAbsoluteCoords_loopEnd:
      mov r17, xl
      or r17, xh
      breq wSetAbsoluteCoords_end
      mov yl, xl
      mov yh, xh
    rjmp wSetAbsoluteCoords_loop
wSetAbsoluteCoords_end:
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine wAlignChildrenHorizontally
;
; Horizontally align children within the width of the parent widget.
; Only changes Y+WID_OFFS_REL_X_LO/HI.
;
; @param Y pointer to object SRAM
; @clobbers r16, r17, r18, r19, r24, r25

wAlignChildrenHorizontally:
  push yl
    push yh
      ldd r24, Y+WID_OFFS_WIDTH_LO           ; parent width
      ldd r25, Y+WID_OFFS_WIDTH_HI
      ldd r19, Y+WID_OFFS_BORDER_LEFT        ; subtract left border
      mov r16, r19
      clr r17
      sub r24, r16
      sbc r25, r17
      ldd r16, Y+WID_OFFS_BORDER_RIGHT       ; subtract right border
      sub r24, r16
      sbc r25, r17                           ; r25:r24=parent width minus lateral borders, r19=left border
      rcall Tree_GetFirstChildObject         ; (none)
wAlignChildrenHorizontally_loop:
        mov r17, xl
        or r17, xh
        breq wAlignChildrenHorizontally_loopEnd
        mov yl, xl
        mov yh, yl
        ldd r18, Y+OBJ_OFFS_OPTIONS
        andi r18, WID_OPTIONS0_BIT_VISIBLE
        breq wAlignChildrenHorizontally_loopNext
        push r24
          push r25
            push r19
              rcall wAlignHorizontally
            pop r19
            add r24, r19
            adc r25, r19
            sub r25, r19
            std Y+WID_OFFS_REL_X_LO, r24
            std Y+WID_OFFS_REL_X_HI, r25
          pop r25
        pop r24
wAlignChildrenHorizontally_loopNext:
        rcall Tree_GetNextSibling            ; (none)
      rjmp wAlignChildrenHorizontally_loop
wAlignChildrenHorizontally_loopEnd:
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine wAlignHorizontally
;
; @param  r25:r24 parent width minus lateral borders
; @return r25:r24 proposed X position relative to parent
; @clobbers r16, r17

wAlignHorizontally:
  ldd r16, Y+WID_OFFS_OPTIONS1
  sbrc r16, WID_OPTIONS1_BIT_STRETCH_X
    rjmp wAlignHorizontally_stretch
  andi r16, (WID_OPTIONS1_BIT_HALIGN0 | WID_OPTIONS1_BIT_HALIGN1)
  cpi r16, (0<<WID_OPTIONS1_BIT_HALIGN1) | (0<<WID_OPTIONS1_BIT_HALIGN0)
  breq wAlignHorizontally_left
  cpi r16, (0<<WID_OPTIONS1_BIT_HALIGN1) | (1<<WID_OPTIONS1_BIT_HALIGN0)
  breq wAlignHorizontally_right
wAlignHorizontally_center:
  ldd r16, Y+WID_OFFS_WIDTH_LO
  ldd r17, Y+WID_OFFS_WIDTH_HI
  sub r24, r16
  sbc r25, r17
  lsr r25
  ror r24
  ret
wAlignHorizontally_left:
  clr r24
  clr r25
  ret
wAlignHorizontally_right:
  ldd r16, Y+WID_OFFS_WIDTH_LO
  ldd r17, Y+WID_OFFS_WIDTH_HI
  sub r24, r16
  sbc r25, r17
wAlignHorizontally_stretch:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine wSetRelYFromHeightInVisibleChildren
;
; @param Y pointer to object SRAM
; @clobbers r17, r18, r19, r24, r25, X

wSetRelYFromHeightInVisibleChildren:
  push yl
    push yh
      ldd r24, Y+WID_OFFS_BORDER_TOP
      clr r25
      rcall Tree_GetFirstChildObject         ; (none)
wSetRelYFromHeightInVisibleChildren_loop:
        mov r17, xl
        or r17, xh
        breq wSetRelYFromHeightInVisibleChildren_loopEnd
        mov yl, xl
        mov yh, yl
        ldd r18, Y+OBJ_OFFS_OPTIONS
        andi r18, WID_OPTIONS0_BIT_VISIBLE
        breq wSetRelYFromHeightInVisibleChildren_loopNext
        std Y+WID_OFFS_REL_Y_LO, r24
        std Y+WID_OFFS_REL_Y_HI, r25
        ldd r18, Y+WID_OFFS_WIDTH_LO
        ldd r19, Y+WID_OFFS_WIDTH_HI
        add r24, r18                         ; TODO: handle carry later
        adc r25, r19
        adiw r25:r24, WID_WIDGET_INTER_BORDER
wSetRelYFromHeightInVisibleChildren_loopNext:
        rcall Tree_GetNextSibling            ; (none)
      rjmp wSetRelYFromHeightInVisibleChildren_loop
wSetRelYFromHeightInVisibleChildren_loopEnd:
      mov r18, r24
      mov r19, r25
    pop yh
  pop yl
  ret
; @end







; ---------------------------------------------------------------------------
; @routine widgetGetMinWidth
;
; @return r19:r18 minimum width of widget
; @clobbers any, !Y

widgetGetMinWidth:
  ldi r16, WID_SIGNAL_GETMINWIDTH
  rjmp widgetGetLargestChildMinSize
; @end



; ---------------------------------------------------------------------------
; @routine widgetGetMinHeight
;
; @return r19:r18 minimum height of widget
; @clobbers any, !Y

widgetGetMinHeight:
  ldi r16, WID_SIGNAL_GETMINHEIGHT
  rjmp widgetSumOfChildrenMinSize
; @end



; ---------------------------------------------------------------------------
; @routine widgetSumOfChildrenMinSize
;
; @param r16 signal to send (WID_SIGNAL_GETMINWIDTH, WID_SIGNAL_GETMINHEIGHT)
; @return r19:r18 minimum width or height of widget
; @clobbers any, !Y

widgetSumOfChildrenMinSize:
  push yl
    push yh
      rcall Tree_GetFirstChildObject         ; (none)
      clr r24
      clr r25
widgetSumOfChildrenMinSize_loop:
        mov r17, xl
        or r17, xh
        breq widgetSumOfChildrenMinSize_loopEnd
        mov yl, xl
        mov yh, yl
        ldd r18, Y+OBJ_OFFS_OPTIONS
        andi r18, WID_OPTIONS0_BIT_VISIBLE
        breq widgetSumOfChildrenMinSize_loopNext
        push r16
          push r24
            push r25
              ldi r18, 1                     ; default value for when the signal is not handled
              ldi r19, 0                     ; default value for when the signal is not handled
              rcall OBJ_Handler              ; ask child for its minimum size
            pop r25
          pop r24
        pop r16
        add r24, r18                         ; TODO: handle carry later
        adc r25, r19
        adiw r25:r24, WID_WIDGET_INTER_BORDER
widgetSumOfChildrenMinSize_loopNext:
        rcall Tree_GetNextSibling            ; (none)
      rjmp widgetSumOfChildrenMinSize_loop
widgetSumOfChildrenMinSize_loopEnd:
      mov r18, r24
      mov r19, r25
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine widgetGetLargestChildMinSize
;
; @param r16 signal to send (WID_SIGNAL_GETMINWIDTH, WID_SIGNAL_GETMINHEIGHT)
; @return r19:r18 minimum width or height of widget
; @clobbers any, !Y

widgetGetLargestChildMinSize:
  push yl
    push yh
      rcall Tree_GetFirstChildObject         ; (none)
      clr r24
      clr r25
widgetGetLargestChildMinSize_loop:
        mov r17, xl
        or r17, xh
        breq widgetGetLargestChildMinSize_loopEnd
        mov yl, xl
        mov yh, yl
        ldd r18, Y+OBJ_OFFS_OPTIONS
        andi r18, WID_OPTIONS0_BIT_VISIBLE
        breq widgetGetLargestChildMinSize_loopNext
        push r16
          push r24
            push r25
              ldi r18, 1                     ; default value for when the signal is not handled
              ldi r19, 0                     ; default value for when the signal is not handled
              rcall OBJ_Handler              ; ask child for its minimum size
            pop r25
          pop r24
        pop r16
        sub r24, r18
        sbc r25, r19
        add r24, r18
        adc r25, r19
        brcc widgetGetLargestChildMinSize_loopNext
        mov r24, r18
        mov r25, r19
widgetGetLargestChildMinSize_loopNext:
        rcall Tree_GetNextSibling            ; (none)
      rjmp widgetGetLargestChildMinSize_loop
widgetGetLargestChildMinSize_loopEnd:
      mov r18, r24
      mov r19, r25
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine widgetCountVisibleChildrenWithOptions1
;
; Count visible direct children with a matching WID_OFFS_OPTIONS1 field.
;
; @param r16  option1 value combination wanted
; @param r17  option1 mask of bits to match
; @return r18 number of matching direct children
; @clobbers r18, r24, r25, X

widgetCountVisibleChildrenWithOptions1:
  push yl
    push yh
      rcall Tree_GetFirstChildObject         ; (none)
      clr r24
widgetCountVisibleChildrenWithOptions1_loop:
        mov r25, xl
        or r25, xh
        breq widgetCountVisibleChildrenWithOptions1_loopEnd
        mov yl, xl
        mov yh, yl
        ldd r18, Y+OBJ_OFFS_OPTIONS
        andi r18, WID_OPTIONS0_BIT_VISIBLE
        breq widgetCountVisibleChildrenWithOptions1_next
        ldd r18, Y+WID_OFFS_OPTIONS1
        eor r18, r17
        and r18, r16
        brne widgetCountVisibleChildrenWithOptions1_next
        inc r24
widgetCountVisibleChildrenWithOptions1_next:
        rcall Tree_GetNextSibling            ; (none)
      rjmp widgetSumOfChildrenMinSize_loop
widgetCountVisibleChildrenWithOptions1_loopEnd:
      mov r18, r24
    pop yh
  pop yl
  ret
; @end




; ---------------------------------------------------------------------------
; @routine wGetSumOfMatchingVisibleChildrenHeights
;
; Add heights of all matching visible children.
;
; @param r16  option1 value combination wanted
; @param r17  option1 mask of bits to match
; @return r19:r18 sum of widths of all visible direct children
; @clobbers r24, r25, X

wGetSumOfMatchingVisibleChildrenHeights:
  push yl
    push yh
      rcall Tree_GetFirstChildObject         ; (none)
      clr r24
      clr r25
wGetSumOfMatchingVisibleChildrenHeights_loop:
        mov r18, xl
        or r18, xh
        breq wGetSumOfMatchingVisibleChildrenHeights_loopEnd
        mov yl, xl
        mov yh, yl
        ldd r18, Y+OBJ_OFFS_OPTIONS
        andi r18, WID_OPTIONS0_BIT_VISIBLE
        breq wGetSumOfMatchingVisibleChildrenHeights_next
        ldd r18, Y+WID_OFFS_OPTIONS1
        eor r18, r17
        and r18, r16
        brne wGetSumOfMatchingVisibleChildrenHeights_next
        ldd r18, Y+WID_OFFS_HEIGHT_LO
        ldd r19, Y+WID_OFFS_HEIGHT_HI
        add r24, r18
        adc r25, r19
wGetSumOfMatchingVisibleChildrenHeights_next:
        rcall Tree_GetNextSibling            ; (none)
      rjmp wGetSumOfMatchingVisibleChildrenHeights_loop
wGetSumOfMatchingVisibleChildrenHeights_loopEnd:
      mov r18, r24
      mov r19, r25
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine wAddToWidthsOfExpandableVisibleChildren
;
; @param Y = pointer to widget data in SRAM
; @param r17:r16 number to add to the widths of all visible X-expandable children
; @clobbers r18, r19, X

wAddToWidthsOfExpandableVisibleChildren:
  push yl
    push yh
      rcall Tree_GetFirstChildObject         ; (none)
wAddToWidthsOfExpandableVisibleChildren_loop:
        mov r18, xl
        or r18, xh
        breq wAddToWidthsOfExpandableVisibleChildren_loopEnd
        mov yl, xl
        mov yh, yl
        ldd r18, Y+OBJ_OFFS_OPTIONS
        andi r18, WID_OPTIONS0_BIT_VISIBLE
        breq wAddToWidthsOfExpandableVisibleChildren_next
        ldd r18, Y+WID_OFFS_OPTIONS1
        andi r18, WID_OPTIONS1_BIT_STRETCH_X
        breq wAddToWidthsOfExpandableVisibleChildren_next
        ldd r18, Y+WID_OFFS_WIDTH_LO
        ldd r19, Y+WID_OFFS_WIDTH_HI
        add r18, r16
        adc r19, r17
        std Y+WID_OFFS_WIDTH_LO, r18
        std Y+WID_OFFS_WIDTH_HI, r19
wAddToWidthsOfExpandableVisibleChildren_next:
        rcall Tree_GetNextSibling            ; (none)
      rjmp wAddToWidthsOfExpandableVisibleChildren_loop
wAddToWidthsOfExpandableVisibleChildren_loopEnd:
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine wAddToHeightsOfExpandableVisibleChildren
;
; @param Y = pointer to widget data in SRAM
; @param r17:r16 number to add to the heights of all visible Y-expandable children
; @clobbers r18, r19, X

wAddToHeightsOfExpandableVisibleChildren:
  push yl
    push yh
      rcall Tree_GetFirstChildObject         ; (none)
wAddToHeightsOfExpandableVisibleChildren_loop:
        mov r18, xl
        or r18, xh
        breq wAddToHeightsOfExpandableVisibleChildren_loopEnd
        mov yl, xl
        mov yh, yl
        ldd r18, Y+OBJ_OFFS_OPTIONS
        andi r18, WID_OPTIONS0_BIT_VISIBLE
        breq wAddToHeightsOfExpandableVisibleChildren_next
        ldd r18, Y+WID_OFFS_OPTIONS1
        andi r18, WID_OPTIONS1_BIT_STRETCH_Y
        breq wAddToHeightsOfExpandableVisibleChildren_next
        ldd r18, Y+WID_OFFS_HEIGHT_LO
        ldd r19, Y+WID_OFFS_HEIGHT_HI
        add r18, r16
        adc r19, r17
        std Y+WID_OFFS_HEIGHT_LO, r18
        std Y+WID_OFFS_HEIGHT_HI, r19
wAddToHeightsOfExpandableVisibleChildren_next:
        rcall Tree_GetNextSibling            ; (none)
      rjmp wAddToHeightsOfExpandableVisibleChildren_loop
wAddToHeightsOfExpandableVisibleChildren_loopEnd:
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine wSetChildrenWidthsFromMinWidths
;
; @clobbers any, !Y

wSetChildrenWidthsFromMinWidths:
  push yl
    push yh
      rcall Tree_GetFirstChildObject         ; (none)
wSetChildrenWidthsFromMinWidths_loop:
        mov r17, xl
        or r17, xh
        breq wSetChildrenWidthsFromMinWidths_loopEnd
        mov yl, xl
        mov yh, yl
        ldd r18, Y+OBJ_OFFS_OPTIONS
        sbrs r18, WID_OPTIONS0_BIT_VISIBLE
          rjmp wSetChildrenWidthsFromMinWidths_loopNext  ; jump if not visible
        sbrc r18, WID_OPTIONS1_BIT_FIXED_WIDTH
          rjmp  wSetChildrenWidthsFromMinWidths_loopNext ; jump if fixed width
        ldi r16, WID_SIGNAL_GETMINWIDTH
        ldi r18, 1                           ; default value for when the signal is not handled
        ldi r19, 0                           ; default value for when the signal is not handled
        rcall OBJ_Handler                    ; ask child for its minimum size
        std Y+WID_OFFS_WIDTH_LO, r18
        std Y+WID_OFFS_WIDTH_HI, r19
wSetChildrenWidthsFromMinWidths_loopNext:
        rcall Tree_GetNextSibling            ; (none)
      rjmp wSetChildrenWidthsFromMinWidths_loop
wSetChildrenWidthsFromMinWidths_loopEnd:
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine wSetChildrenHeightsFromMinHeights
;
; @clobbers any, !Y

wSetChildrenHeightsFromMinHeights:
  push yl
    push yh
      rcall Tree_GetFirstChildObject         ; (none)
wSetChildrenHeightsFromMinHeights_loop:
        mov r17, xl
        or r17, xh
        breq wSetChildrenHeightsFromMinHeights_loopEnd
        mov yl, xl
        mov yh, yl
        ldd r18, Y+OBJ_OFFS_OPTIONS
        sbrs r18, WID_OPTIONS0_BIT_VISIBLE
          rjmp wSetChildrenHeightsFromMinHeights_loopNext ; jump if not visible
        sbrc r18, WID_OPTIONS1_BIT_FIXED_HEIGHT
          rjmp wSetChildrenHeightsFromMinHeights_loopNext ; jump if fixed height
        ldi r16, WID_SIGNAL_GETMINHEIGHT
        ldi r18, 1                                        ; default value for when the signal is not handled
        ldi r19, 0                                        ; default value for when the signal is not handled
        rcall OBJ_Handler                                 ; ask child for its minimum size
        std Y+WID_OFFS_HEIGHT_LO, r18
        std Y+WID_OFFS_HEIGHT_HI, r19
wSetChildrenHeightsFromMinHeights_loopNext:
        rcall Tree_GetNextSibling            ; (none)
      rjmp wSetChildrenHeightsFromMinHeights_loop
wSetChildrenHeightsFromMinHeights_loopEnd:
    pop yh
  pop yl
  ret
; @end




