; *************************************************************************** ; 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_WIDGET_ASM #define AQH_AVR_GUI2_WIDGET_ASM ; *************************************************************************** ; defines ; Widget in flash .equ WIDGET_OFFS_BEGIN = OBJECT_SIZE .equ WIDGET_OFFS_X_LO = WIDGET_OFFS_BEGIN+0 .equ WIDGET_OFFS_X_HI = WIDGET_OFFS_BEGIN+1 .equ WIDGET_OFFS_Y_LO = WIDGET_OFFS_BEGIN+2 .equ WIDGET_OFFS_Y_HI = WIDGET_OFFS_BEGIN+3 .equ WIDGET_OFFS_WIDTH_LO = WIDGET_OFFS_BEGIN+4 .equ WIDGET_OFFS_WIDTH_HI = WIDGET_OFFS_BEGIN+5 .equ WIDGET_OFFS_HEIGHT_LO = WIDGET_OFFS_BEGIN+6 .equ WIDGET_OFFS_HEIGHT_HI = WIDGET_OFFS_BEGIN+7 .equ WIDGET_OFFS_STYLE_LO = WIDGET_OFFS_BEGIN+8 ; byte address (for LPM!) .equ WIDGET_OFFS_STYLE_HI = WIDGET_OFFS_BEGIN+9 .equ WIDGET_OFFS_PACK = WIDGET_OFFS_BEGIN+10 .equ WIDGET_OFFS_TMP_LO = WIDGET_OFFS_BEGIN+11 .equ WIDGET_OFFS_TMP_HI = WIDGET_OFFS_BEGIN+12 .equ WIDGET_SIZE = WIDGET_OFFS_BEGIN+13 ; widget style object .equ WIDGET_STYLE_OFFS_FRONTCOL_NORM = 0 .equ WIDGET_STYLE_OFFS_BACKCOL_NORM = 2 .equ WIDGET_STYLE_OFFS_BORDERCOL_NORM = 4 .equ WIDGET_STYLE_OFFS_SHADOWCOL_NORM = 6 .equ WIDGET_STYLE_OFFS_FRONTCOL_ACTIVATED = 8 .equ WIDGET_STYLE_OFFS_BACKCOL_ACTIVATED = 10 .equ WIDGET_STYLE_OFFS_BORDERCOL_ACTIVATED = 12 .equ WIDGET_STYLE_OFFS_SHADOWCOL_ACTIVATED = 14 .equ WIDGET_STYLE_OFFS_OUTERBORDERSIZE = 16 .equ WIDGET_STYLE_OFFS_SPACING = 17 .equ WIDGET_STYLE_OFFS_FONT_LO = 18 .equ WIDGET_STYLE_OFFS_FONT_HI = 19 .equ WIDGET_STYLE_OFFS_CHARWIDTH = 20 .equ WIDGET_STYLE_OFFS_CHARHEIGHT = 21 .equ WIDGET_STYLE_SIZE = 22 ; widget opts_lo (bits 7 and 6 used by OBJECT_OPTS) .equ WIDGET_OPTS_INPUT_BIT = 5 ; TOUCH, KEY .equ WIDGET_OPTS_BORDER_BIT = 4 ; widget WIDGET_OFFS_PACK .equ WIDGET_PACK_HSELF0_BIT = 0 .equ WIDGET_PACK_HSELF1_BIT = 1 .equ WIDGET_PACK_VSELF0_BIT = 2 .equ WIDGET_PACK_VSELF1_BIT = 3 .equ WIDGET_PACK_HCONTENT0_BIT = 4 .equ WIDGET_PACK_HCONTENT1_BIT = 5 .equ WIDGET_PACK_VCONTENT0_BIT = 6 .equ WIDGET_PACK_VCONTENT1_BIT = 7 ; values for WIDGET_OFFS_PACK (2 bits) .equ WIDGET_PACK_BEGIN = 0 .equ WIDGET_PACK_END = 1 .equ WIDGET_PACK_CENTER = 2 .equ WIDGET_PACK_FILLED = 3 ; widget flags .equ WIDGET_FLAGS_VISIBLE_BIT = 7 .equ WIDGET_FLAGS_TOUCH_BIT = 6 .equ WIDGET_FLAGS_DIRTY_BIT = 5 .equ WIDGET_FLAGS_LAYOUT_BIT = 4 .equ WIDGET_FLAGS_ACTIVATED_BIT = 3 .equ WIDGET_FLAGS_SELECTED_BIT = 2 ; SDRAM data for signal WIDGET_SIGNAL_TOUCH .equ WIDGET_TOUCH_OFFS_X_LO = 0 .equ WIDGET_TOUCH_OFFS_X_HI = 1 .equ WIDGET_TOUCH_OFFS_Y_LO = 2 .equ WIDGET_TOUCH_OFFS_Y_HI = 3 .equ WIDGET_TOUCH_OFFS_STATE = 4 .equ WIDGET_TOUCH_SIZE = 5 ; signals .equ WIDGET_SIGNAL_SHOW = OBJECT_SIGNAL_NEXTFREE+0 .equ WIDGET_SIGNAL_HIDE = OBJECT_SIGNAL_NEXTFREE+1 .equ WIDGET_SIGNAL_LAYOUT = OBJECT_SIGNAL_NEXTFREE+2 .equ WIDGET_SIGNAL_DRAW = OBJECT_SIGNAL_NEXTFREE+3 .equ WIDGET_SIGNAL_TOUCH = OBJECT_SIGNAL_NEXTFREE+4 .equ WIDGET_SIGNAL_COMMAND = OBJECT_SIGNAL_NEXTFREE+5 .equ WIDGET_SIGNAL_CHANGE = OBJECT_SIGNAL_NEXTFREE+6 .equ WIDGET_SIGNAL_SETVALUE = OBJECT_SIGNAL_NEXTFREE+7 .equ WIDGET_SIGNAL_GETVALUE = OBJECT_SIGNAL_NEXTFREE+8 .equ WIDGET_SIGNAL_KEEPALIVE = OBJECT_SIGNAL_NEXTFREE+9 .equ WIDGET_SIGNAL_TOUCH_BEGIN = OBJECT_SIGNAL_NEXTFREE+10 .equ WIDGET_SIGNAL_TOUCH_MOVE = OBJECT_SIGNAL_NEXTFREE+11 .equ WIDGET_SIGNAL_TOUCH_END = OBJECT_SIGNAL_NEXTFREE+12 .equ WIDGET_SIGNAL_NEXTFREE = OBJECT_SIGNAL_NEXTFREE+13 ; values for signals WIDGET_SIGNAL_SETVALUE and WIDGET_SIGNAL_GETVALUE .equ WIDGET_VALUE_DEFAULT_WIDTH = 1 .equ WIDGET_VALUE_DEFAULT_HEIGHT = 2 .equ WIDGET_VALUE_NEXTFREE = 3 ; *************************************************************************** ; code .cseg ; --------------------------------------------------------------------------- ; @routine Widget_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 ; @clobbers any Widget_new: ldi r24, LOW(WIDGET_SIZE) ldi r25, HIGH(WIDGET_SIZE) bigcall Object_Alloc ; (!r16, !r17, !X) brcc Widget_new_ret rcall Widget_Init ; (r16, r17, X) sec Widget_new_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_Init @global ; ; @param Y address of object in SDRAM ; @param r16 value for OBJECT_OFFS_OPTS ; @param r17 value for WIDGET_OFFS_PACK ; @param X parent widget (if any) ; @clobbers r16, r17, X Widget_Init: push xl push xh push r17 ; call base class bigcall OBJ_Init ; (r16, r17, X) pop r17 pop xh pop xl std Y+WIDGET_OFFS_PACK, r17 ; set default signal map ldi r16, LOW(Widget_DefaultSignalmap*2) std Y+OBJECT_OFFS_SIGNALMAP_LO, r16 ldi r16, HIGH(Widget_DefaultSignalmap*2) std Y+OBJECT_OFFS_SIGNALMAP_HI, r16 ; set style mov r16, xl or r16, xh breq Widget_Init_setDefaultStyle ; use style from parent adiw xh:xl, WIDGET_OFFS_STYLE_LO ld r16, X+ std Y+WIDGET_OFFS_STYLE_LO, r16 ld r16, X std Y+WIDGET_OFFS_STYLE_HI, r16 sbiw xh:xl, (WIDGET_OFFS_STYLE_LO+1) rjmp Widget_Init_setDefaultSize Widget_Init_setDefaultStyle: ldi r16, LOW(Widget_DefaultStyle*2) std Y+WIDGET_OFFS_STYLE_LO, r16 ldi r16, HIGH(Widget_DefaultStyle*2) std Y+WIDGET_OFFS_STYLE_HI, r16 Widget_Init_setDefaultSize: ; initial size: 1x1 px ldi r16, 1 clr r17 std Y+WIDGET_OFFS_WIDTH_LO, r16 std Y+WIDGET_OFFS_WIDTH_HI, r17 std Y+WIDGET_OFFS_HEIGHT_LO, r16 std Y+WIDGET_OFFS_HEIGHT_HI, r17 ; add to parent (if any) mov r16, xl or r16, xh breq Widget_Init_ret bigcall OBJ_AddChild ; (r18, r19) ; parent needs to layout with the new child adiw xh:xl, OBJECT_OFFS_FLAGS ld r16, X sbr r16, (1< shift 2 times right lsr r17 andi r17, 3 rcall widgetPack ; r21:r20=new pos (r17, r18, r19) mov r6, r20 mov r7, r21 ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_PackContentX @global ; ; Calc pos according to WIDGET_PACK_HCONTENT in WIDGET_OFFS_PACK. ; ; @param Y address of widget ; @param R13:R12 width of object to align ; @return R5:R4 X ; @clobbers r17, r18, r19, r20, r21 Widget_PackContentX: ldd r18, Y+WIDGET_OFFS_WIDTH_LO ldd r19, Y+WIDGET_OFFS_WIDTH_HI ldd r17, Y+WIDGET_OFFS_PACK swap r17 ; WIDGET_PACK_HCONTENT0_BIT = 4 -> shift 4 times right andi r17, 3 rcall widgetPack ; r21:r20=new pos (r17, r18, r19) mov r4, r20 mov r5, r21 ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_PackContentY @global ; ; Calc pos according to WIDGET_PACK_VCONTENT in WIDGET_OFFS_PACK. ; ; @param Y address of widget ; @param R13:R12 height of object to align ; @return R7:R6 Y ; @clobbers r17, r18, r19, r20, r21 Widget_PackContentY: ldd r18, Y+WIDGET_OFFS_HEIGHT_LO ldd r19, Y+WIDGET_OFFS_HEIGHT_HI ldd r17, Y+WIDGET_OFFS_PACK swap r17 ; WIDGET_PACK_VCONTENT0_BIT = 6 -> shift 6 times right lsr r17 lsr r17 andi r17, 3 rcall widgetPack ; r21:r20=new pos (r17, r18, r19) mov r6, r20 mov r7, r21 ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_GetCharWidth @global ; ; @param Y address of widget ; @return R16 character width with current font (in pixels) ; @clobbers none Widget_GetCharWidth: push zl push zh ldd zl, Y+WIDGET_OFFS_STYLE_LO ldd zh, Y+WIDGET_OFFS_STYLE_HI adiw zh:zl, WIDGET_STYLE_OFFS_CHARWIDTH lpm r16, Z pop zh pop zl ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_GetCharHeight @global ; ; @param Y address of widget ; @return R16 character height with current font (in pixels) ; @clobbers none Widget_GetCharHeight: push zl push zh ldd zl, Y+WIDGET_OFFS_STYLE_LO ldd zh, Y+WIDGET_OFFS_STYLE_HI adiw zh:zl, WIDGET_STYLE_OFFS_CHARHEIGHT lpm r16, Z pop zh pop zl ret ; @end ; --------------------------------------------------------------------------- ; @routine widgetDrawChar ; ; @param Y address of widget ; @param R16 char to write ; @param R5:R4 absolute X on screen (in display coords) ; @param R7:R6 absolute Y on screen (in display coords) ; @param R9:R8 first X pos right of windows (in display coords) ; @return CFLAG set if char printed, cleared otherwise ; @return R5:R4 X pos behind char ; @clobbers any, !Y, !R6, !R7, !R8, !R9, !R10, !R11 widgetDrawChar: push yl push yh push r16 ; get font and charWidth ldd zl, Y+WIDGET_OFFS_STYLE_LO ldd zh, Y+WIDGET_OFFS_STYLE_HI adiw zh:zl, WIDGET_STYLE_OFFS_CHARWIDTH lpm r18, Z ; char width sbiw zh:zl, WIDGET_STYLE_OFFS_CHARWIDTH adiw zh:zl, WIDGET_STYLE_OFFS_FONT_LO lpm r19, Z+ lpm zh, Z mov zl, r19 ; check whether char fits into widget mov r16, r18 clr r17 add r16, r4 ; char width+X adc r17, r5 cp r8, r16 ; check against window width cpc r9, r17 ; sub r16, r8 ; check against window width ; sbc r17, r9 pop r16 brcs widgetDrawChar_done ; not fit, jmp ; draw char push r8 push r9 push r10 push r11 push r18 ; save char width bigcall Display_DrawChar pop r18 pop r11 pop r10 pop r9 pop r8 ; increment X clr r16 add r4, r18 adc r5, r16 sec widgetDrawChar_done: pop yh pop yl ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_LoadDimsForFullWidget ; ; @param Y address of widget ; @return r5:r4 X (0) ; @return r7:r6 Y (0) ; @return r9:r8 widget width ; @return r11:R10 widget height ; @clobbers none Widget_LoadDimsForFullWidget: clr r4 clr r5 clr r6 clr r7 ldd r8, Y+WIDGET_OFFS_WIDTH_LO ldd r9, Y+WIDGET_OFFS_WIDTH_HI ldd r10, Y+WIDGET_OFFS_HEIGHT_LO ldd r11, Y+WIDGET_OFFS_HEIGHT_HI ret ; @end ; --------------------------------------------------------------------------- ; @routine widgetCalcAbsPosAndBorders ; ; @param Y address of widget ; @param R5:R4 X relative to widget ; @param R7:R6 Y relative to widget ; @return R9:R8 first X pos right of widget ; @return R5:R4 X relative to screen ; @return R7:R6 Y relative to screen ; @return R9:R8 first X pos right of widget (abs) ; @return R11:R10 first Y pos below widget (abs) ; @clobbers r16, r17 widgetCalcAbsPosAndBorders: rcall Widget_MakeAbsPos ; (R16, R17) ldd r8, Y+WIDGET_OFFS_WIDTH_LO ldd r9, Y+WIDGET_OFFS_WIDTH_HI add r8, r4 ; convert width to first pos right of widget adc r9, r5 ldd r10, Y+WIDGET_OFFS_HEIGHT_LO ldd r11, Y+WIDGET_OFFS_HEIGHT_HI add r10, r6 adc r11, r7 ; convert height to first pos below widget ret ; @end ; --------------------------------------------------------------------------- ; @routine widgetPack ; ; @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) ; @return R21:R20 pos ; @clobbers r17, r18, r19 widgetPack: ; subtract borders push zl push zh ldd zl, Y+WIDGET_OFFS_STYLE_LO ldd zh, Y+WIDGET_OFFS_STYLE_HI adiw zh:zl, WIDGET_STYLE_OFFS_OUTERBORDERSIZE lpm r20, Z pop zh pop zl clr r21 sub r18, r20 ; subtract border at begin sbc r19, r21 sub r18, r20 ; subtract border at end sbc r19, r21 ; r19:r18=host size - (border*2) andi r17, 3 ; only 2 bits pack mode cpi r17, WIDGET_PACK_END breq widgetPack_end cpi r17, WIDGET_PACK_CENTER breq widgetPack_center rjmp widgetPack_ret ; begin/filled, align at begin widgetPack_end: sub r18, r12 sbc r19, r13 add r20, r18 adc r21, r19 rjmp widgetPack_ret widgetPack_center: sub r18, r12 sbc r19, r13 lsr r19 ror r18 add r20, r18 adc r21, r19 rjmp widgetPack_ret widgetPack_ret: ret ; @end ; *************************************************************************** ; data in FLASH Widget_DefaultSignalmap: ; header .dw Object_DefaultSignalmap*2 ; next table to use ; entries .db 0, WIDGET_SIGNAL_DRAW, LOW(Widget_OnDraw), HIGH(Widget_OnDraw) .db 0, WIDGET_SIGNAL_LAYOUT, LOW(Widget_OnLayout), HIGH(Widget_OnLayout) .db 0, WIDGET_SIGNAL_GETVALUE, LOW(Widget_OnGetValue), HIGH(Widget_OnGetValue) ; handle any value here .db 0, WIDGET_SIGNAL_SHOW, LOW(Widget_OnShow), HIGH(Widget_OnShow) .db 0, WIDGET_SIGNAL_HIDE, LOW(Widget_OnHide), HIGH(Widget_OnHide) .db 0, 0, 0, 0 ; end of table Widget_DefaultStyle: .dw DISPLAY_COLOR_BLACK ; frontCol_norm .dw DISPLAY_COLOR_LIGHTGREY ; backCol_norm .dw DISPLAY_COLOR_BLACK ; borderCol_norm .dw DISPLAY_COLOR_WHITE ; shadowCol_norm .dw DISPLAY_COLOR_WHITE ; frontCol_activated .dw DISPLAY_COLOR_NAVY ; backCol_activated .dw DISPLAY_COLOR_BLACK ; borderCol_activated .dw DISPLAY_COLOR_WHITE ; shadowCol_activated .db 0, 1 ; outerBorderSize, innerBorderSize .dw ili9341Font12x16_1*2 ; font .db 12, 16 ; charWidth, charHeight #endif