Files
aqhomecontrol/avr/modules/lcd2/gui2/base/mlayout.asm
Martin Preuss 1f801c41a1 gui2: started working on matrix layout
this will later become also the base class for new implementations of
HLayout and VLayout to simplify things.
2026-03-18 01:02:11 +01:00

690 lines
19 KiB
NASM

; ***************************************************************************
; 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_MLAYOUT_ASM
#define AQH_AVR_GUI2_MLAYOUT_ASM
; TODO: use this class also for HLayout and VLayout, those are just special
; cases with only one row (HLayout) or column (VLayout)
; ***************************************************************************
; defines
.equ MLAYOUT_OFFS_BEGIN = WIDGET_SIZE
.equ MLAYOUT_OFFS_MODE = MLAYOUT_OFFS_BEGIN+0
.equ MLAYOUT_OFFS_COLSORROWS = MLAYOUT_OFFS_BEGIN+1
.equ MLAYOUT_SIZE = MLAYOUT_OFFS_BEGIN+2
; values for MLAYOUT_OFFS_MODE
.equ HLAYOUT_MODE_COLUMNS = 0
.equ HLAYOUT_MODE_ROWS = 1
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine MLayout_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 (MLAYOUT_MODE_COLUMNS, MLAYOUT_MODE_ROWS)
; @param r21 number of columns or rows (depending on mode in r20)
; @clobbers any
MLayout_new:
push r20
push r21
ldi r24, LOW(;LAYOUT_SIZE)
ldi r25, HIGH(;LAYOUT_SIZE)
bigcall Object_Alloc ; (!r16, !r17, !X)
pop r21
pop r20
brcc MLayout_new_ret
rcall MLayout_Init ; (r16, r17, X)
sec
MLayout_new_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine MLayout_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 (MLAYOUT_MODE_COLUMN, MLAYOUT_MODE_ROW)
; @param r21 number of columns or rows (depending on mode in r20)
; @clobbers r16, r17, X
MLayout_Init:
push r20
push r21
; call base class
bigcall Widget_Init ; (r16, r17, X)
pop r21
pop r20
; set widget-specific data
std Y+MLAYOUT_OFFS_MODE, r20
std Y+MLAYOUT_OFFS_COLSORROWS, r21
; set default signal map
ldi r16, LOW(MLayout_DefaultSignalmap*2)
std Y+OBJECT_OFFS_SIGNALMAP_LO, r16
ldi r16, HIGH(MLayout_DefaultSignalmap*2)
std Y+OBJECT_OFFS_SIGNALMAP_HI, r16
ret
; @end
MLayout_OnLayout:
MLayout_OnGetDefaultWidth:
MLayout_OnGetDefaultHeight:
ret
; ---------------------------------------------------------------------------
; @routine mLayoutColumnsHorizontally
;
; @param Y pointer to widget
mLayoutColumnsHorizontally:
bigcall OBJ_GetFirstChild ; test for children
brcc mLayoutColumnsHorizontally_ret ; none, done here
; preparations
rcall Layout_SetDefaultWidths ; calc default widths of children and store in Y+WIDGET_OFFS_TMP
rcall mLayoutCopyTmpToWidth ; copy to width fields for later
rcall mLayoutGetBorders ; r22=spacing, r23=outer borders
; calc size of each column and store it in the first widget of a column as TMP
rcall mLayoutCalcAndSetSizesSkipped ; (r18-r31, !Y)
; calc total width of first row (which has the maximum sizes of each column)
rcall mLayoutCalcFirstSizesContiguous ; r21:r20 width of first row (r16, r18, r19, r24, r25)
; layout columns of first row
rcall mLayoutColumnsExpandFirstRow ; TODO: only if FILL set in PACK byte!
; copy layout from first row to all other rows
rcall mLayoutCopyTmpFromFirstLine
; finally horizontally position all cells
rcall mLayoutColumnsPositionX
mLayoutColumnsHorizontally_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutColumnsPositionX
;
; @param Y pointer to widget
; @param r22 spacing (between widgets)
; @param r23 outer border size
mLayoutColumnsPositionX:
push yl
push yh
bigcall OBJ_GetFirstChild
brcc mLayoutColumnsPositionX_done
mLayoutColumnsPositionX_loop1:
ldd r24, Y+MLAYOUT_OFFS_COLSORROWS
mov r4, r23 ; X pos (start at left border)
clr r5
mLayoutColumnsPositionX_loop2:
ldd r18, Y+WIDGET_OFFS_TMP_LO ; calculated cell width
ldd r19, Y+WIDGET_OFFS_TMP_HI
ldd r12, Y+WIDGET_OFFS_WIDTH_LO ; default width
ldd r13, Y+WIDGET_OFFS_WIDTH_HI
ldi r17, Y+WIDGET_OFFS_PACK
andi r17, 3 ; WIDGET_PACK_HSELF0_BIT = 0, no shift necessary
rcall mLayoutPackCell ; R21:R20=relative pos (r17, r18, r19)
add r20, r4
adc r21, r5
std Y+WIDGET_OFFS_X_LO, r20 ; set new X
std Y+WIDGET_OFFS_X_HI, r21
std Y+WIDGET_OFFS_WIDTH_LO, r18 ; set new width
std Y+WIDGET_OFFS_WIDTH_HI, r19
add r4, r18 ; advance X
adc r5, r19
bigcall OBJ_GetNext
brcc mLayoutColumnsPositionX_done
mov yl, r18
mov yh, r19
dec r24
brne mLayoutColumnsPositionX_loop2
rjmp mLayoutColumnsPositionX_loop1
mLayoutColumnsPositionX_done:
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutPackCell
;
; @param Y address of widget
; @param r19:r18 size of target widget (i.e. width or height)
; @param r17 pack mode (see @ref WIDGET_PACK_BEGIN)
; @param R13:R12 size of object to pack (i.e. width or height)
; @param r22 spacing (between widgets)
; @return R21:R20 pos
; @clobbers r17, r18, r19
mLayoutPackCell:
; subtract borders
clr r23
sub r18, r22 ; subtract spacing
sbc r19, r23
andi r17, 3 ; only 2 bits pack mode
cpi r17, WIDGET_PACK_END
breq mLayoutPackCell_end
cpi r17, WIDGET_PACK_CENTER
breq mLayoutPackCell_center
rjmp mLayoutPackCell_ret ; begin/filled, align at begin
mLayoutPackCell_end:
sub r18, r12
sbc r19, r13
add r20, r18
adc r21, r19
rjmp mLayoutPackCell_ret
mLayoutPackCell_center:
sub r18, r12
sbc r19, r13
lsr r19
ror r18
add r20, r18
adc r21, r19
rjmp mLayoutPackCell_ret
mLayoutPackCell_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutCopyTmpFromFirstLine
;
; TMP in widgets of first row/column contains the available space per cell.
;
; @param Y pointer to widget
; @clobbers r17, r18, r19, r20, r21, r24
mLayoutCopyTmpFromFirstLine:
push yl
push yh
ldd r24, Y+MLAYOUT_OFFS_COLSORROWS
bigcall OBJ_GetFirstChild
mLayoutCopyTmpFromFirstLine_loop:
push yl
push yh
ldd r20, Y+WIDGET_OFFS_TMP_LO
ldd r21, Y+WIDGET_OFFS_TMP_HI
; goto same cell in next block (e.g. same column in next row)
ldd r17, Y+MLAYOUT_OFFS_COLSORROWS
mLayoutCopyTmpFromFirstLine_loop2:
bigcall OBJ_GetNext
brcc mLayoutCopyTmpFromFirstLine_nextColumn
mov yl, r18
mov yh, r19
dec r17
brne mLayoutCopyTmpFromFirstLine_loop2
std Y+WIDGET_OFFS_TMP_LO, r20
std Y+WIDGET_OFFS_TMP_HI, r21
mLayoutCopyTmpFromFirstLine_nextColumn:
pop yh
pop yl
bigcall OBJ_GetNext
brcc mLayoutCopyTmpFromFirstLine_done
mov yl, r18
mov yh, r19
rjmp mLayoutCopyTmpFromFirstLine_loop
mLayoutCopyTmpFromFirstLine_done:
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutCopyTmpToWidth
;
; @param Y pointer to widget
;
mLayoutCopyTmpToWidth:
push yl
push yh
bigcall OBJ_GetFirstChild
brcc mLayoutCopyTmpToWidth_ret
mLayoutCopyTmpToWidth_loop:
mov yl, r18
mov yh, r19
ldd r18, Y+WIDGET_OFFS_TMP_LO
ldd r19, Y+WIDGET_OFFS_TMP_HI
std Y+WIDGET_OFFS_WIDTH_LO, r18
std Y+WIDGET_OFFS_WIDTH_HI, r19
mLayoutCopyTmpToWidth_next:
rcall OBJ_GetNext
brcs mLayoutCopyTmpToWidth_loop
mLayoutCopyTmpToWidth_ret:
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutCountChildrenWithMatchingPackMode
;
; @param Y pointer to widget
; @param r21:r20 width of first row
mLayoutColumnsExpandFirstRow:
ldd r24, Y+MLAYOUT_OFFS_COLSORROWS
ldi r25, 1
ldi r22, (1<<WIDGET_PACK_HSELF1_BIT) | (1<<WIDGET_PACK_HSELF0_BIT) ; mask
ldi r23, (WIDGET_PACK_FILLED<<WIDGET_PACK_HSELF0_BIT) ; value
rcall mLayoutCountChildrenWithMatchingPackMode ; r16=count (r17, r18, r19, r24)
ldd r18, Y+WIDGET_OFFS_WIDTH_LO
ldd r19, Y+WIDGET_OFFS_WIDTH_HI
sub r18, r20
sbc r19, r21 ; space to distribute among widgets
brcs mLayoutColumnsExpandFirstRow_ret
; divide available space among expandable children
mov r20, r18
mov r21, r19
mov r22, r16
clr r23
bigcall Utils_Divu16_16_16 ; r17:r16=space per expandable widget
mLayoutColumnsExpandFirstRow_setPos:
mov r20, r16
mov r21, r17
ldd r24, Y+MLAYOUT_OFFS_COLSORROWS
ldi r25, 1
ldi r22, (1<<WIDGET_PACK_HSELF1_BIT) | (1<<WIDGET_PACK_HSELF0_BIT) ; mask
ldi r23, (WIDGET_PACK_FILLED<<WIDGET_PACK_HSELF0_BIT) ; value
rcall mLayoutIncTmpOnMatchingPackMode
mLayoutColumnsExpandFirstRow_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutCountChildrenWithMatchingPackMode
;
; @param Y pointer to widget
; @param r22 mask for WIDGET_OFFS_PACK
; @param r23 value for WIDGET_OFFS_PACK
; @param r24 number of widgets to handle per round
; @param r25 number of widgets to skip per round
; @return r16 number of matching children
; @clobbers r17, r18, r19, r24
mLayoutCountChildrenWithMatchingPackMode:
clr r16
push yl
push yh
bigcall OBJ_GetFirstChild
mLayoutCountChildrenWithMatchingPackMode_loop:
brcc mLayoutCountChildrenWithMatchingPackMode_done
mov yl, r18
mov yh, r19
ldd r17, Y+OBJECT_OFFS_FLAGS
sbrs r17, WIDGET_FLAGS_VISIBLE_BIT ; skip invisible widgets
rjmp mLayoutCountChildrenWithMatchingPackMode_advance
ldd r17, Y+WIDGET_OFFS_PACK
eor r17, r23
and r17, r22
brne mLayoutCountChildrenWithMatchingPackMode_next
inc r16
mLayoutCountChildrenWithMatchingPackMode_next:
dec r24
breq mLayoutCountChildrenWithMatchingPackMode_done
mLayoutCountChildrenWithMatchingPackMode_advance:
mov r17, r25
mLayoutCountChildrenWithMatchingPackMode_loop2:
rcall OBJ_GetNext ; (none)
brcc mLayoutCountChildrenWithMatchingPackMode_done
dec r17
brne mLayoutCountChildrenWithMatchingPackMode_loop2
rjmp mLayoutCountChildrenWithMatchingPackMode_loop
mLayoutCountChildrenWithMatchingPackMode_done:
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutIncTmpOnMatchingPackMode
;
; Ignores invisible widgets.
;
; @param Y pointer to widget
; @param R21:R20 value to add to tmp value of expandable widgets
; @param r22 mask for WIDGET_OFFS_PACK
; @param r23 value for WIDGET_OFFS_PACK
; @param r24 number of widgets to handle per round
; @param r25 number of widgets to skip per round
; @clobbers r16, r18, r19, r24
mLayoutIncTmpOnMatchingPackMode:
push yl
push yh
bigcall OBJ_GetFirstChild
brcc mLayoutIncTmpOnMatchingPackMode_done
mLayoutIncTmpOnMatchingPackMode_loop:
mov yl, r18
mov yh, r19
ldd r16, Y+OBJECT_OFFS_FLAGS
sbrs r16, WIDGET_FLAGS_VISIBLE_BIT ; skip invisible widgets
rjmp mLayoutIncTmpOnMatchingPackMode_next
ldd r16, Y+WIDGET_OFFS_PACK
eor r16, r23
and r16, r22
brne mLayoutIncTmpOnMatchingPackMode_advance
ldd r18, Y+WIDGET_OFFS_TMP_LO
ldd r19, Y+WIDGET_OFFS_TMP_HI
add r18, r20
adc r19, r21
std Y+WIDGET_OFFS_TMP_LO, r18
std Y+WIDGET_OFFS_TMP_HI, r19
mLayoutIncTmpOnMatchingPackMode_next:
dec r24
breq mLayoutCountChildrenWithMatchingPackMode_done
mLayoutIncTmpOnMatchingPackMode_advance:
mov r17, r25
mLayoutIncTmpOnMatchingPackMode_loop2:
rcall OBJ_GetNext ; (none)
brcc mLayoutIncTmpOnMatchingPackMode_done
dec r17
brne mLayoutIncTmpOnMatchingPackMode_loop2
rjmp mLayoutIncTmpOnMatchingPackMode_loop
mLayoutIncTmpOnMatchingPackMode_done:
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutGetBorders
;
; @param Y address of widget
; @return r22 spacing
; @return r23 outer borders
mLayoutGetBorders:
ldd zl, Y+WIDGET_OFFS_STYLE_LO
ldd zh, Y+WIDGET_OFFS_STYLE_HI
adiw zh:zl, WIDGET_STYLE_OFFS_SPACING
lpm r22, Z
sbiw zh:zl, WIDGET_STYLE_OFFS_SPACING
adiw zh:zl, WIDGET_STYLE_OFFS_OUTERBORDERSIZE
lpm r23, Z
ret
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutCalcAndSetSizesSkipped
;
; @param Y address of widget
; @param r22 spacing (between widgets)
; @param r23 outer border size
; @clobbers r18-r31, !Y
mLayoutCalcAndSetSizesSkipped:
bigcall OBJ_GetFirstChild
mov r20, Y+MLAYOUT_OFFS_COLSORROWS
push yl
push yh
mLayoutCalcAndSetSizesSkipped_loop:
mov yl, r18
mov yh, r19
push yl
push yh
ldi r24, 1 ; number of widgets to handle per loop
ldd r25, Y+MLAYOUT_OFFS_COLSORROWS ; number of widgets to skip
push r20
rcall mLayoutGetMaxTmpSize ; (r18-r31, !Y)
pop r20
pop yh
pop yl
std Y+WIDGET_OFFS_TMP_LO, r18
std Y+WIDGET_OFFS_TMP_HI, r18
dec r20
breq mLayoutCalcAndSetSizesSkipped_loopEnd
bigcall OBJ_GetNext
brcs mLayoutCalcAndSetSizesSkipped_loop
mLayoutCalcAndSetSizesSkipped_loopEnd:
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutCalcFirstSizesContiguous
;
; @param Y address of widget
; @param r22 spacing (between widgets)
; @param r23 outer border size
; @return r21:r20 total width of contigous first widgets
; @clobbers r16, r18, r19, r24, r25
mLayoutCalcFirstSizesContiguous:
bigcall OBJ_GetFirstChild ; (none)
push yl
push yh
mov yl, r18
mov yh, r19
ldd r24, Y+MLAYOUT_OFFS_COLSORROWS
ldi r25, 1
rcall mLayoutSumNextTmpValues ; r21:r20=total size (r16, r18, r19, r24)
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutSumTmpValues
;
; Ignores invisible widgets. Assumes there ARE children!
;
; @param Y pointer to widget
; @param r22 spacing (between widgets)
; @param r23 outer border size
; @param r24 number of widgets to handle per round
; @param r25 number of widgets to skip per round
; @return r19:r18 total size of all child widgets plus space between and borders
; @clobbers r16, r17, r18, r19, r20, r21, r22, r23, Z
mLayoutSumTmpValues:
clr r20
clr r21
push yl
push yh
bigcall OBJ_GetFirstChild
mov yl, r18
mov yh, r19
rcall mLayoutSumNextTmpValues ; r21:r20=sum
add r20, r23 ; add outer border (begin)
adc r21, r23
sub r21, r23
add r20, r23 ; add outer border (end)
adc r21, r23
sub r21, r23
mov r18, r20
mov r19, r21
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutSumNextTmpValues
;
; Ignores invisible widgets.
;
; @param Y address of widget to start with
; @param r22 spacing (between widgets)
; @param r23 outer border size
; @param r24 number of widgets to handle per round
; @param r25 number of widgets to skip per round
; @return r21:r20 sum of tmp values in widgets
; @return Y address of last widget handled (or last available)
; @clobbers r16, r17, r18, r19, r24
mLayoutSumNextTmpValues:
mLayoutSumNextTmpValues_loop:
ldd r18, Y+OBJECT_OFFS_FLAGS
sbrs r18, WIDGET_FLAGS_VISIBLE_BIT
rjmp mLayoutSumNextTmpValues_advance
ldd r18, Y+WIDGET_OFFS_TMP_LO
ldd r19, Y+WIDGET_OFFS_TMP_HI
add r20, r18 ; add widget size
adc r21, r19
add r20, r22 ; add spacing
adc r21, r22
sub r21, r22
mLayoutSumNextTmpValues_next:
dec r24
breq mLayoutSumNextTmpValues_done
mLayoutSumNextTmpValues_advance:
mov r17, r25
mLayoutSumNextTmpValues_loop2:
rcall OBJ_GetNext ; (none)
brcc mLayoutSumNextTmpValues_done
mov yl, r18
mov yh, r19
dec r17
brne mLayoutSumNextTmpValues_loop2
rjmp mLayoutSumNextTmpValues_loop
mLayoutSumNextTmpValues_loopEnd:
mov r16, r20
or r16, r21
breq mLayoutSumNextTmpValues_done
sub r20, r22 ; sub last spacing
sbc r21, r22
add r21, r22
mLayoutSumNextTmpValues_done:
ret ; r21:r20=sum
; @end
; ---------------------------------------------------------------------------
; @routine mLayoutGetMaxTmpSize
;
; @param Y address of widget
; @param r22 spacing (between widgets)
; @param r23 outer border size
; @param r24 number of widgets to handle per round
; @param r25 number of widgets to skip per round
; @return r19:r18 max size
; @clobbers r18-r31, !Y
mLayoutGetMaxTmpSize:
push yl
push yh
clr xl
clr xh
bigcall OBJ_GetFirstChild
brcc mLayoutGetMaxTmpSize_ret
mLayoutGetMaxRowWidth_loop:
push r24
push r25
rcall Layout_SumNextTmpValues ; r20:r21=sum (r16, r18, r19, r24)
cp xl, r18
cpc xh, r19
brcc mLayoutGetMaxTmpSize_next
mov xl, r18
mov xh, r19
mLayoutGetMaxTmpSize_next:
rcall OBJ_GetNext
brcc mLayoutGetMaxTmpSize_ret
mov yl, r18
mov yh, r19
rjmp mLayoutGetMaxRowWidth_loop
mLayoutGetMaxTmpSize_ret:
mov r18, xl
mov r19, xh
pop yh
pop yl
ret
; @end
; ***************************************************************************
; data in FLASH
MLayout_DefaultSignalmap:
; header
.dw Widget_DefaultSignalmap*2 ; next table to use
; entries
.db 0, WIDGET_SIGNAL_LAYOUT, LOW(MLayout_OnLayout), HIGH(MLayout_OnLayout)
.db WIDGET_VALUE_DEFAULT_WIDTH, WIDGET_SIGNAL_GETVALUE, LOW(MLayout_OnGetDefaultWidth), HIGH(MLayout_OnGetDefaultWidth)
.db WIDGET_VALUE_DEFAULT_HEIGHT, WIDGET_SIGNAL_GETVALUE, LOW(MLayout_OnGetDefaultHeight), HIGH(MLayout_OnGetDefaultHeight)
.db 0, 0, 0, 0 ; end of table
#endif