; ***************************************************************************
; copyright   : (C) 2026 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.   *
; ***************************************************************************

#ifndef AQH_AVR_GUI2_HLAYOUT_ASM
#define AQH_AVR_GUI2_HLAYOUT_ASM


; ***************************************************************************
; defines

.equ HLAYOUT_OFFS_BEGIN    =  WIDGET_SIZE
.equ HLAYOUT_OFFS_MODE     =  HLAYOUT_OFFS_BEGIN+0
.equ HLAYOUT_SIZE          =  HLAYOUT_OFFS_BEGIN+1


; values for HLAYOUT_OFFS_MODE
.equ HLAYOUT_MODE_EXPAND   = 0
.equ HLAYOUT_MODE_SPREAD   = 1





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

.cseg



; ---------------------------------------------------------------------------
; @routine HLayout_new @global
;
; @return CFLAG set of okay, cleared otherwise
; @return Y address of newly created object
; @param X parent widget
; @param r16 value for OBJECT_OFFS_OPTS
; @param r17 value for WIDGET_OFFS_PACK
; @param r20 layout mode (HLAYOUT_MODE_EXPAND, HLAYOUT_MODE_SPREAD)
; @clobbers any

HLayout_new:
  push r20
    ldi r24, LOW(HLAYOUT_SIZE)
    ldi r25, HIGH(HLAYOUT_SIZE)
    bigcall Object_Alloc         ; (!r16, !r17, !X)
  pop r20
  brcc HLayout_new_ret
  rcall HLayout_Init               ; (r16, r17, X)
  sec
HLayout_new_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine HLayout_Init @global
;
; @param Y address of widget
; @param X parent widget (if any)
; @param r16 value for OBJECT_OFFS_OPTS
; @param r17 value for WIDGET_OFFS_PACK
; @param r20 layout mode (HLAYOUT_MODE_EXPAND, HLAYOUT_MODE_SPREAD)
; @clobbers r16, r17, X

HLayout_Init:
  push r20
    ; call base class
    bigcall Widget_Init             ; (r16, r17, X)
  pop r20
  brcc HLayout_Init_ret
  
  ; set widget-specific data
  std Y+HLAYOUT_OFFS_MODE, r20

  ; set default signal map
  ldi r16, LOW(HLayout_DefaultSignalmap*2)
  std Y+OBJECT_OFFS_SIGNALMAP_LO, r16
  ldi r16, HIGH(HLayout_DefaultSignalmap*2)
  std Y+OBJECT_OFFS_SIGNALMAP_HI, r16

HLayout_Init_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine HLayout_OnLayout
;
; @param Y pointer to widget
; @clobbers any, !Y

HLayout_OnLayout:
  ; create and preset context
  rcall LayoutCtx_CreateContextFor1D    ; X=ctx, r16=num of children
  brcc HLayout_OnLayout_ret
  ; do layout
  mov r25, r16
  rcall hLayoutHorizontally
  rcall hLayoutVertically
  ; release layout context
  bigcall LayoutCtx_free
  ; force re-drawing of this widget, clear layout bit
  ldd r16, Y+OBJECT_OFFS_FLAGS
  sbr r16, (1<<WIDGET_FLAGS_DIRTY_BIT)
  cbr r16, (1<<WIDGET_FLAGS_LAYOUT_BIT)
  std Y+OBJECT_OFFS_FLAGS, r16
HLayout_OnLayout_ret:
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine HLayout_OnGetDefaultHeight
;
; @param Y pointer to widget
; @return r19:r18 value
; @clobbers any, !Y

HLayout_OnGetDefaultHeight:
  rcall Layout_SetDefaultHeights
  rcall Layout_GetMaxTmp
  bigcall Widget_AddOuterStyleBorders   ; (r20, r21)
  sec
  ret

; @end



; ---------------------------------------------------------------------------
; @routine HLayout_OnGetDefaultWidth
;
; @param Y pointer to widget
; @return r19:r18 value
; @clobbers any, !Y

HLayout_OnGetDefaultWidth:
  rcall Layout_SetDefaultWidths
  rcall Layout_SumTmpValues     ; r19:r18=default width
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine hLayoutVertically
;
; @param Y pointer to widget
; @param X layout context
; @param r25 number of children
; @clobbers any, !X, !Y

hLayoutVertically:
  rcall hLayoutPrepareVertical           ; (any, !R25, !X, !Y)
  rcall hLayoutReadLayoutWriteVertical   ; (r16-r24)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine hLayoutPrepareVertical
;
; @param Y pointer to widget
; @param X layout context
; @param r25 number of children
; @clobbers any, !R25, !X, !Y,

hLayoutPrepareVertical:
  push xl
    push xh
      push yl
        push yh
          push r25
            rcall Layout_SetDefaultHeights
          pop r25
        pop yh
      pop yl
    pop xh
  pop xl

  ldd r20, Y+WIDGET_OFFS_HEIGHT_LO
  ldd r21, Y+WIDGET_OFFS_HEIGHT_HI
  adiw xh:xl, LAYOUT_CTX_OFFS_TOTALSIZE_LO
  st X+, r20
  st X, r21
  sbiw xh:xl, (LAYOUT_CTX_OFFS_TOTALSIZE_LO+1)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine hLayoutReadLayoutWriteVertical
;
; @param Y pointer to widget
; @param X layout context
; @param r25 number of children
; @clobbers r16-r24

hLayoutReadLayoutWriteVertical:
  ; read positions and flags into new layout context
  bigcall LayoutCtx_ReadYDimsContiguous   ; (R16, r18, r19, Z)

  ; layout
  adiw xh:xl, LAYOUT_CTX_OFFS_BORDERS
  ld r18, X
  clr r19
  sbiw xh:xl, LAYOUT_CTX_OFFS_BORDERS
  bigcall LayoutCtx_SetFixedPos           ; (r24)
  mov r22, r18                            ; save border
  
  bigcall LayoutCtx_GetMaxSize            ; r19:r18=max default size (r18, r19, r20, r21, r24)
  ldd r16, Y+WIDGET_OFFS_PACK
  andi r16, (1<<WIDGET_PACK_VSELF1_BIT) | (1<<WIDGET_PACK_VSELF0_BIT)
  cpi r16, (WIDGET_PACK_FILLED<<WIDGET_PACK_VSELF0_BIT)
  brne vLayoutReadLayoutWriteVertical_setSize
  ; use full possible width
  adiw xh:xl, LAYOUT_CTX_OFFS_TOTALSIZE_LO
  ld r18, X+
  ld r19, X
  sbiw xh:xl, (LAYOUT_CTX_OFFS_TOTALSIZE_LO+1)
  clr r23
  lsl r22
  rol r23
  sub r18, r22
  sbc r19, r23
vLayoutReadLayoutWriteVertical_setSize:
  bigcall LayoutCtx_SetFixedSize          ; (r24)

  ; pack
  bigcall LayoutCtx_PackYContiguous       ; (R16, r18, r19, Z)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine hLayoutHorizontally
;
; @param Y pointer to widget
; @param X layout context
; @param r25 number of children
; @clobbers any, !Y

hLayoutHorizontally:
  rcall hLayoutPrepareHorizontal         ; (any, !R25, !X, !Y)
  rcall hLayoutReadLayoutWriteHorizontal ; (r16-r24)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine hLayoutPrepareHorizontal
;
; @param Y pointer to widget
; @param X layout context
; @param r25 number of children
; @clobbers any, !R25, !X, !Y,

hLayoutPrepareHorizontal:
  push xl
    push xh
      push yl
        push yh
          push r25
            rcall Layout_SetDefaultWidths  ; (any, !Y)
          pop r25
        pop yh
      pop yl
    pop xh
  pop xl

  ; setup layout context for horizontal operations
  ldd r20, Y+WIDGET_OFFS_WIDTH_LO
  ldd r21, Y+WIDGET_OFFS_WIDTH_HI
  adiw xh:xl, LAYOUT_CTX_OFFS_TOTALSIZE_LO
  st X+, r20
  st X, r21
  sbiw xh:xl, (LAYOUT_CTX_OFFS_TOTALSIZE_LO+1)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine hLayoutReadLayoutWriteHorizontal
;
; @param Y pointer to widget
; @param X layout context
; @param r25 number of children
; @clobbers r16-r24

hLayoutReadLayoutWriteHorizontal:
  ; read X positions and flags into new layout context
  bigcall LayoutCtx_ReadXDimsContiguous            ; (R16, r18, r19, Z)

  ; layout
  push r25
    ldd r24, Y+HLAYOUT_OFFS_MODE
    cpi r24, HLAYOUT_MODE_SPREAD
    breq hLayoutReadLayoutWriteHorizontal_spread
    bigcall LayoutCtx_LayoutExpand                 ; (r16-r25)
    rjmp hLayoutReadLayoutWriteHorizontal_pack
hLayoutReadLayoutWriteHorizontal_spread:
    bigcall LayoutCtx_LayoutSpread                 ; (r16-r25)
hLayoutReadLayoutWriteHorizontal_pack:
  pop r25

  ; pack
  push r25
    bigcall LayoutCtx_PackXContiguous              ; (r16-r21, r24, r25)
  pop r25
  
  ; write back dims
;  bigcall LayoutCtx_WriteXDimsContiguous           ; (r16, r18, r19, r24)
  ret
; @end








; ***************************************************************************
; data in FLASH

HLayout_DefaultSignalmap:
  ; header
  .dw Widget_DefaultSignalmap*2  ; next table to use
  ; entries
  .db 0,                           WIDGET_SIGNAL_LAYOUT,   LOW(HLayout_OnLayout),           HIGH(HLayout_OnLayout)
  .db WIDGET_VALUE_DEFAULT_WIDTH,  WIDGET_SIGNAL_GETVALUE, LOW(HLayout_OnGetDefaultWidth),  HIGH(HLayout_OnGetDefaultWidth)
  .db WIDGET_VALUE_DEFAULT_HEIGHT, WIDGET_SIGNAL_GETVALUE, LOW(HLayout_OnGetDefaultHeight), HIGH(HLayout_OnGetDefaultHeight)

  .db 0, 0, 0, 0  ; end of table



#endif

