gui: added configuration-based dialog

creates a dialog with widgets from a configuration stored as sequence of
bytes in flash.
This commit is contained in:
Martin Preuss
2026-05-06 23:43:15 +02:00
parent 5483df48cd
commit ce1fd901e7

View File

@@ -0,0 +1,403 @@
; ***************************************************************************
; 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_GUI_BASE_CDIALOG_ASM
#define AQH_AVR_GUI_BASE_CDIALOG_ASM
; ***************************************************************************
; defines
; CDIALOG data
.equ CDIALOG_OFFS_BEGIN = MAINWINDOW_SIZE
.equ CDIALOG_OFFS_CONFIG_LO = CDIALOG_OFFS_BEGIN+0
.equ CDIALOG_OFFS_CONFIG_HI = CDIALOG_OFFS_BEGIN+1
.equ CDIALOG_SIZE = CDIALOG_OFFS_BEGIN+2
; CDIALOG dialog configuration
.equ CDIALOGCFG_MAINWIDGET_TYPE_HLAYOUT = 1
.equ CDIALOGCFG_MAINWIDGET_TYPE_VLAYOUT = 2
.equ CDIALOGCFG_MAINWIDGET_TYPE_MLAYOUT = 3
.equ CDIALOGCFG_MAINWIDGET_TYPE_NEXT = 4
.equ CDIALOGCFG_WIDGET_TYPE_LABEL = 1
.equ CDIALOGCFG_WIDGET_TYPE_VALUELABEL = 2
.equ CDIALOGCFG_WIDGET_TYPE_IMAGEVIEW = 3
.equ CDIALOGCFG_WIDGET_TYPE_HSPINNER = 4
.equ CDIALOGCFG_WIDGET_TYPE_TEXTBUTTON = 5
.equ CDIALOGCFG_WIDGET_TYPE_IMAGEBUTTON = 6
.equ CDIALOGCFG_WIDGET_TYPE_NEXT = 7
.equ CDIALOGCFG_WIDGET_FLAGS_MINMAXVALUES_BIT = 0
.equ CDIALOGCFG_OFFS_HEADER_TYPE = 0 ; HLAYOUT, VLAYOUT, MLAYOUT
.equ CDIALOGCFG_OFFS_HEADER_FLAGS = 1
.equ CDIALOGCFG_OFFS_HEADER_PARAM1 = 2 ; R20
.equ CDIALOGCFG_OFFS_HEADER_PARAM2 = 3 ; R21
.equ CDIALOGCFG_HEADER_SIZE = 4
.equ CDIALOGCFG_OFFS_WIDGET_TYPE = 0 ; 0=end
.equ CDIALOGCFG_OFFS_WIDGET_FLAGS = 1
.equ CDIALOGCFG_OFFS_WIDGET_SELECTOR = 2
.equ CDIALOGCFG_OFFS_WIDGET_RESERVED = 3
.equ CDIALOGCFG_OFFS_WIDGET_OPTS = 4
.equ CDIALOGCFG_OFFS_WIDGET_PACK = 5
.equ CDIALOGCFG_OFFS_WIDGET_STYLE_LO = 6
.equ CDIALOGCFG_OFFS_WIDGET_STYLE_HI = 7
.equ CDIALOGCFG_OFFS_WIDGET_PARAM1 = 8 ; R20
.equ CDIALOGCFG_OFFS_WIDGET_PARAM2 = 9 ; R21
.equ CDIALOGCFG_OFFS_WIDGET_PARAM3 = 10 ; R22
.equ CDIALOGCFG_OFFS_WIDGET_PARAM4 = 11 ; R23
.equ CDIALOGCFG_OFFS_WIDGET_MINVALUE_LO = 12
.equ CDIALOGCFG_OFFS_WIDGET_MINVALUE_HI = 13
.equ CDIALOGCFG_OFFS_WIDGET_MAXVALUE_LO = 14
.equ CDIALOGCFG_OFFS_WIDGET_MAXVALUE_HI = 15
.equ CDIALOGCFG_WIDGET_SIZE = 16
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine CDialog__Init @global
;
; @param Y pointer to MainWindow
; @param X pointer to root window
; @param R21:R20 title ressource
; @param r23:r22 pointer to settings (byte addr for LPM!)
; @return CFLAG set of okay, cleared otherwise
; @clobbers any, !Y
CDialog_Init:
push r22
push r23
ldi r16, 0 ; OPTS
ldi r17, (WIDGET_PACK_FILLED<<WIDGET_PACK_HSELF0_BIT) | (WIDGET_PACK_FILLED<<WIDGET_PACK_VSELF0_BIT) ; PACK
bigcall MainWindow_Init
pop r23
pop r22
brcc CDialog_Init_ret
; store config
std Y+CDIALOG_OFFS_CONFIG_LO, r22
std Y+CDIALOG_OFFS_CONFIG_HI, r23
; create content
bigcall MainWindow_GetContentWidget ; r19:r18=content window
brcc CDialog_Init_ret
mov xl, r18 ; use content window as parent
mov xh, r19
push zl
push zh
push xl ; content window
push xh
ldd zl, Y+CDIALOG_OFFS_CONFIG_LO
ldd zh, Y+CDIALOG_OFFS_CONFIG_HI
push yl ; main window
push yh
rcall cDialogCreateContent
pop yh
pop yl
pop xh
pop xl
pop zh
pop zl
brcc CDialog_Init_ret
push yl
push yh
bigcall C03App_CreateBackButton
pop yh
pop yl
CDialog_Init_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine CDialog_GetChildBySelector
;
; @param Y pointer to MainWindow
; @param Z pointer to dialog configuration
; @param r16 selector to search for
; @return CFLAG set if widget found, cleared otherwise
; @return r19:r18 resulting widget
; @clobbers R16, R17, R18, R19
CDialog_GetChildBySelector:
push zl
push zh
adiw zh:zl, CDIALOGCFG_HEADER_SIZE
; determine child index
clr r18
CDialog_GetChildBySelector_loop:
lpm r17, Z ; CDIALOGCFG_OFFS_WIDGET_TYPE
tst r17
breq CDialog_GetChildBySelector_popRet
adiw zh:zl, CDIALOGCFG_OFFS_WIDGET_SELECTOR
lpm r17, Z
sbiw zh:zl, CDIALOGCFG_OFFS_WIDGET_SELECTOR
cp r17, r16
breq CDialog_GetChildBySelector_found
inc r18
adiw zh:zl, CDIALOGCFG_WIDGET_SIZE
rjmp CDialog_GetChildBySelector_loop
CDialog_GetChildBySelector_found:
bigcall MainWindow_GetFirstChildOfContentWidget
brcc CDialog_GetChildBySelector_popRet
push yl
push yh
mov yl, r18
mov yh, r19
mov r16, r18
bigcall OBJ_GetChildAt ; (r16)
pop yh
pop yl
CDialog_GetChildBySelector_popRet:
pop zh
pop zl
ret
; @end
; ---------------------------------------------------------------------------
; @routine cDialogCreateContent
;
; @param Y pointer to main window
; @param X pointer to content window of MainWindow (is a VLayout, becomes parent)
; @param Z pointer to dialog configuration
; @return CFLAG set of okay, cleared otherwise
; @return Y pointer to created content widget
cDialogCreateContent:
push yl ; MainWindow
push yh
rcall cDialogMkMainWidget
mov xl, yl ; layout widget
mov xh, yh
pop yh ; MainWindow
pop yl
brcc cDialogCreateContent_ret
adiw zh:zl, CDIALOGCFG_HEADER_SIZE ; go to first child widget
cDialogCreateContent_loop:
lpm r16, Z
tst r16
breq cDialogCreateContent_done
push yl
push yh
push xl
push xh
rcall cDialogMkChildWidget
pop xh
pop xl
pop yh
pop yl
brcc cDialogCreateContent_ret
adiw zh:zl, CDIALOGCFG_WIDGET_SIZE
rjmp cDialogCreateContent_loop
cDialogCreateContent_done:
sec
cDialogCreateContent_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine cDialogMkMainWidget
;
; @param Y pointer to main window
; @param X pointer to content window of MainWindow (is a VLayout, becomes parent)
; @param Z pointer to dialog configuration
; @return CFLAG set of okay, cleared otherwise
; @return Y pointer to created content widget
; @clobbers any, !Z
cDialogMkMainWidget:
lpm r16, Z
cpi r16, CDIALOGCFG_MAINWIDGET_TYPE_NEXT
brcc cDialogMkMainWidget_ret
dec r16
clr r17
ldi r18, LOW(cDialogMkMainWidget_table)
ldi r19, HIGH(cDialogMkMainWidget_table)
add r18, r16
adc r19, r17
; prepare params, opts and pack
adiw zh:zl, CDIALOGCFG_OFFS_HEADER_PARAM1
lpm r20, Z+
lpm r21, Z
sbiw zh:zl, (CDIALOGCFG_OFFS_HEADER_PARAM1+1)
ldi r16, 0 ; OPTS
ldi r17, (WIDGET_PACK_FILLED<<WIDGET_PACK_HSELF0_BIT) | (WIDGET_PACK_FILLED<<WIDGET_PACK_VSELF0_BIT) ; PACK
push zl
push zh
rcall cDialogMkMainWidget_callTable
pop zh
pop zl
cDialogMkMainWidget_ret:
ret
cDialogMkMainWidget_callTable:
push r18 ; indirect jump
push r19
ret
cDialogMkMainWidget_table:
rjmp cDialogMkMainWidget_hlayout
rjmp cDialogMkMainWidget_vlayout
rjmp cDialogMkMainWidget_mlayout
cDialogMkMainWidget_hlayout:
bigjmp HLayout_new
cDialogMkMainWidget_vlayout:
bigjmp VLayout_new
cDialogMkMainWidget_mlayout:
bigjmp MCLayout_new
; @end
; ---------------------------------------------------------------------------
; @routine cDialogMkChildWidget
; @param Y pointer to main window
; @param X pointer to parent window
; @param Z pointer to current widget configuration
; @return CFLAG set of okay, cleared otherwise
; @return Y pointer to created widget
; @clobbers any, !Z
cDialogMkChildWidget:
lpm r16, Z
cpi r16, CDIALOGCFG_WIDGET_TYPE_NEXT
brcs cDialogMkChildWidget_typeOk
rjmp cDialogMkChildWidget_ret
cDialogMkChildWidget_typeOk:
dec r16
; prepare params
adiw zh:zl, CDIALOGCFG_OFFS_WIDGET_PARAM1
lpm r20, Z+
lpm r21, Z+
lpm r22, Z+
lpm r23, Z
sbiw zh:zl, (CDIALOGCFG_OFFS_WIDGET_PARAM1+3)
; determine position within jumptable
clr r17
ldi r18, LOW(cDialogMkChildWidget_table)
ldi r19, HIGH(cDialogMkChildWidget_table)
add r18, r16
adc r19, r17
; prepare opts and pack mode
adiw zh:zl, CDIALOGCFG_OFFS_WIDGET_OPTS
lpm r16, Z+
lpm r17, Z
sbiw zh:zl, (CDIALOGCFG_OFFS_WIDGET_OPTS+1)
; call table routine
push zl
push zh
push yl
push yh
rcall cDialogMkChildWidget_callTable
pop r21 ; pop Y into r21:r20
pop r20
pop zh
pop zl
brcc cDialogMkChildWidget_ret
; set target and selector
adiw zh:zl, CDIALOGCFG_OFFS_WIDGET_SELECTOR
lpm r16, Z
sbiw zh:zl, CDIALOGCFG_OFFS_WIDGET_SELECTOR
std Y+OBJECT_OFFS_SELECTOR, r16
std Y+OBJECT_OFFS_TARGET_LO, r20
std Y+OBJECT_OFFS_TARGET_HI, r21
; set style (if any)
adiw zh:zl, CDIALOGCFG_OFFS_WIDGET_STYLE_LO
lpm r16, Z+
lpm r17, Z
sbiw zh:zl, (CDIALOGCFG_OFFS_WIDGET_STYLE_LO+1)
mov r18, r16
or r18, r17
breq cDialogMkChildWidget_setminmax
std Y+WIDGET_OFFS_STYLE_LO, r16
std Y+WIDGET_OFFS_STYLE_HI, r17
cDialogMkChildWidget_setminmax:
adiw zh:zl, CDIALOGCFG_OFFS_WIDGET_FLAGS
lpm r16, Z
sbiw zh:zl, CDIALOGCFG_OFFS_WIDGET_FLAGS
sbrs r16, CDIALOGCFG_WIDGET_FLAGS_MINMAXVALUES_BIT ; only set min/max if flag set
rjmp cDialogMkChildWidget_done
adiw zh:zl, CDIALOGCFG_OFFS_WIDGET_MINVALUE_LO
lpm xl, Z+
lpm xh, Z
sbiw zh:zl, (CDIALOGCFG_OFFS_WIDGET_MINVALUE_LO+1)
push zl
push zh
bigcall Widget_SetMinValue
pop zh
pop zl
adiw zh:zl, CDIALOGCFG_OFFS_WIDGET_MAXVALUE_LO
lpm xl, Z+
lpm xh, Z
sbiw zh:zl, (CDIALOGCFG_OFFS_WIDGET_MAXVALUE_LO+1)
push zl
push zh
bigcall Widget_SetMaxValue
pop zh
pop zl
cDialogMkChildWidget_done:
sec
cDialogMkChildWidget_ret:
ret
cDialogMkChildWidget_callTable:
push r18 ; indirect jump
push r19
ret
cDialogMkChildWidget_table:
rjmp cDialogMkChildWidget_label
rjmp cDialogMkChildWidget_vlabel
rjmp cDialogMkChildWidget_imageview
rjmp cDialogMkChildWidget_hspinner
rjmp cDialogMkChildWidget_textbutton
rjmp cDialogMkChildWidget_imagebutton
cDialogMkChildWidget_label:
bigjmp Label_new
cDialogMkChildWidget_vlabel:
bigjmp ValueLabel_new
cDialogMkChildWidget_imageview:
bigjmp ImageView_new
cDialogMkChildWidget_hspinner:
bigjmp HSpinner_new
cDialogMkChildWidget_textbutton:
bigjmp TextButton_new
cDialogMkChildWidget_imagebutton:
bigjmp ImageButton_new
; @end
#endif