; *************************************************************************** ; 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_WIDGET = OBJECT_SIZE .equ WIDGET_OFFS_X_LO = WIDGET_OFFS_WIDGET+0 .equ WIDGET_OFFS_X_HI = WIDGET_OFFS_WIDGET+1 .equ WIDGET_OFFS_Y_LO = WIDGET_OFFS_WIDGET+2 .equ WIDGET_OFFS_Y_HI = WIDGET_OFFS_WIDGET+3 .equ WIDGET_OFFS_WIDTH_LO = WIDGET_OFFS_WIDGET+4 .equ WIDGET_OFFS_WIDTH_HI = WIDGET_OFFS_WIDGET+5 .equ WIDGET_OFFS_HEIGHT_LO = WIDGET_OFFS_WIDGET+6 .equ WIDGET_OFFS_HEIGHT_HI = WIDGET_OFFS_WIDGET+7 .equ WIDGET_OFFS_STYLE_LO = WIDGET_OFFS_WIDGET+8 ; byte address (for LPM!) .equ WIDGET_OFFS_STYLE_HI = WIDGET_OFFS_WIDGET+9 .equ WIDGET_SIZE = WIDGET_OFFS_WIDGET+10 ; widget style object .equ WIDGET_STYLE_OFFS_FRONTCOL_NORM = 0 .equ WIDGET_STYLE_OFFS_BACKCOL_NORM = 1 .equ WIDGET_STYLE_OFFS_BORDERCOL_NORM = 2 .equ WIDGET_STYLE_OFFS_SHADOWCOL_NORM = 3 .equ WIDGET_STYLE_OFFS_FRONTCOL_ACTIVATED = 4 .equ WIDGET_STYLE_OFFS_BACKCOL_ACTIVATED = 5 .equ WIDGET_STYLE_OFFS_BORDERCOL_ACTIVATED = 6 .equ WIDGET_STYLE_OFFS_SHADOWCOL_ACTIVATED = 7 .equ WIDGET_STYLE_OFFS_OUTERBORDERSIZE = 8 .equ WIDGET_STYLE_OFFS_INNERBORDERSIZE = 9 .equ WIDGET_STYLE_OFFS_FONT_LO = 10 .equ WIDGET_STYLE_OFFS_FONT_HI = 11 .equ WIDGET_STYLE_OFFS_CHARWIDTH = 12 .equ WIDGET_STYLE_OFFS_CHARHEIGHT = 13 .equ WIDGET_STYLE_SIZE = 14 ; widget opts_lo (bits 7 and 6 used by OBJECT_OPTSLO) .equ WIDGET_OPTSLO_INPUT_BIT = 5 ; TOUCH, KEY .equ WIDGET_OPTSLO_BORDER_BIT = 4 .equ WIDGET_OPTSLO_XALIGN1_BIT = 3 ; (2 bit: left, right, center, filled) .equ WIDGET_OPTSLO_XALIGN0_BIT = 2 .equ WIDGET_OPTSLO_YALIGN1_BIT = 1 ; (2 bit: top, bottom, center, filled) .equ WIDGET_OPTSLO_YALIGN0_BIT = 0 ; values for WIDGET_OPTSLO_XALIGN (2 bits) .equ WIDGET_OPTSLO_XALIGN_LEFT = 0 .equ WIDGET_OPTSLO_XALIGN_RIGHT = 1 .equ WIDGET_OPTSLO_XALIGN_CENTER = 2 .equ WIDGET_OPTSLO_XALIGN_FILLED = 3 ; values for WIDGET_OPTSLO_YALIGN (2 bits) .equ WIDGET_OPTSLO_YALIGN_TOP = 0 .equ WIDGET_OPTSLO_YALIGN_BOTTOM = 1 .equ WIDGET_OPTSLO_YALIGN_CENTER = 2 .equ WIDGET_OPTSLO_YALIGN_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_CLICKED = OBJECT_SIGNAL_NEXTFREE+5 .equ WIDGET_SIGNAL_NEXTFREE = OBJECT_SIGNAL_NEXTFREE+6 ; *************************************************************************** ; code .cseg ; --------------------------------------------------------------------------- ; @routine Widget_Init @global ; ; @param Y address of object in SDRAM ; @clobbers r16, r17, X Widget_Init: ; call base class bigcall OBJ_Init ; (r16, r17, X) ; clear widget-specific data mov xl, yl mov xh, yh adiw xh:xl, WIDGET_OFFS_WIDGET clr r16 ldi r17, (WIDGET_SIZE-WIDGET_OFFS_WIDGET) bigcall Utils_FillSram ; (r17, X) ; 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 default style 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 ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_Fini @global ; ; @param Y address of object in SDRAM ; @clobbers none Widget_Fini: ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_Clear @global ; ; @param Y address of widget Widget_Clear: rcall widgetLoadDimsForFullWidget ; (none) rcall Widget_MakeAbsPos ; (r16, r17, r18, r19) rcall Widget_SelectColors ; (R16) mov r2, r0 ; use background mov r3, r1 bigcall Display_FillRect ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_DrawBorder @global ; ; @param Y address of widget ; @param r3:r2 color ; @clobbers any, !Z Widget_DrawBorder: rcall widgetLoadDimsForFullWidget ; (none) rcall Widget_MakeAbsPos ; (R16, R17) rcall Widget_SelectBorderColors ; (R16) bigcall Display_DrawRect Widget_DrawBorder_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_FillRect @global ; ; @param Y address of widget ; @param r3:r2 color ; @param r5:r4 X0 ; @param r7:r6 Y0 ; @param r9:r8 X1/W ; @param r11:r10 Y1/H ; @clobbers any, !Z Widget_FillRect: rcall Widget_MakeAbsPos ; (r16, r17, r18, r19) mov r2, r0 ; use background mov r3, r1 bigcall Display_FillRect ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_DrawImage @global ; ; @param Y address of widget ; @param R1:R0 background color ; @param R5:R4 X relative to widget ; @param R7:R6 Y relative to widget ; @param Z byte address pointer to image in FLASH (for LPM!) ; @clobbers all, !Y Widget_DrawImage: push yl push yh rcall widgetCalcAbsPosAndBorders ; (R16, R17) bigcall ili9341ImageDraw pop yh pop yl ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_DrawTextFlash @global ; ; @param Y address of widget ; @param R5:R4 X relative to widget ; @param R7:R6 Y relative to widget ; @return Z pointer to next char to write if CFLAG clear ; @clobbers any, !Y Widget_DrawTextFlash: rcall Widget_SelectColors ; (R16) rjmp Widget_DrawColoredTextFlash ; @end ; --------------------------------------------------------------------------- ; @routine Widget_DrawTextRam @global ; ; @param Y address of widget ; @param R5:R4 X relative to widget ; @param R7:R6 Y relative to widget ; @param X pointer to text in SDRAM ; @return CFLAG set if completely written ; @return X pointer to next char to write if CFLAG clear ; @clobbers any, !Y Widget_DrawTextRam: rcall Widget_SelectColors ; (R16) rjmp Widget_DrawColoredTextRam ; @end ; --------------------------------------------------------------------------- ; @routine Widget_DrawColoredTextFlash @global ; ; @param Y address of widget ; @param R1:R0 background color ; @param R3:R2 foreground color ; @param R5:R4 X relative to widget ; @param R7:R6 Y relative to widget ; @param Z byte address pointer to text in flash (for LPM!) ; @return CFLAG set if completely written ; @return Z pointer to next char to write if CFLAG clear ; @clobbers any, !Y Widget_DrawColoredTextFlash: rcall widgetCalcAbsPosAndBorders ; (R16, R17) Widget_DrawColoredTextFlash_loop: lpm r16, Z tst r16 sec breq Widget_DrawColoredTextFlash_loopEnd push zl push zh rcall widgetDrawChar ; (any, !Y, !R6, !R7, !R8, !R9, !R10, !R11) pop zh pop zl brcc Widget_DrawColoredTextFlash_loopEnd adiw zh:zl, 1 rjmp Widget_DrawColoredTextFlash_loop Widget_DrawColoredTextFlash_loopEnd: ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_DrawColoredTextRam @global ; ; @param Y address of widget ; @param R1:R0 background color ; @param R3:R2 foreground color ; @param R5:R4 X relative to widget ; @param R7:R6 Y relative to widget ; @param X pointer to text in SDRAM ; @return CFLAG set if completely written ; @clobbers any, !Y Widget_DrawColoredTextRam: rcall widgetCalcAbsPosAndBorders ; (R16, R17) Widget_DrawColoredTextRam_loop: ld r16, X tst r16 sec breq Widget_DrawColoredTextRam_loopEnd push xl push xh rcall widgetDrawChar ; (any, !Y, !R6, !R7, !R8, !R9, !R10, !R11) pop xh pop xl brcc Widget_DrawColoredTextRam_loopEnd adiw xh:xl, 1 rjmp Widget_DrawColoredTextRam_loop Widget_DrawColoredTextRam_loopEnd: ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_MakeAbsPos @global ; ; @param Y address of widget ; @param r5:r4 X ; @param r7:r6 Y ; @clobbers r16, r17, r18, r19 Widget_MakeAbsPos: push yl push yh Widget_MakeAbsPos_loop: ; adjust X ldd r16, Y+WIDGET_OFFS_X_LO ldd r17, Y+WIDGET_OFFS_X_HI add r4, r16 adc r5, r17 ; adjust Y ldd r16, Y+WIDGET_OFFS_Y_LO ldd r17, Y+WIDGET_OFFS_Y_HI add r6, r16 adc r7, r17 ; continue with parent rcall OBJ_GetParent ; r19:r18=parent widget (none) brcc Widget_MakeAbsPos_loopEnd mov yl, r18 mov yh, r19 rjmp Widget_MakeAbsPos_loop Widget_MakeAbsPos_loopEnd: pop yh pop yl ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_SelectColors @global ; ; @param Y address of widget ; @return r1:r0 background color ; @return r3:r2 foreground color ; @clobbers R16 Widget_SelectColors: push zl push zh ldd zl, Y+WIDGET_OFFS_STYLE_LO ldd zh, Y+WIDGET_OFFS_STYLE_HI ldd r16, Y+OBJECT_OFFS_FLAGS sbrc r16, WIDGET_FLAGS_ACTIVATED_BIT rjmp Widget_SelectColors_activated adiw zh:zl, WIDGET_STYLE_OFFS_FRONTCOL_NORM rjmp Widget_SelectColors_readColors Widget_SelectColors_activated: adiw zh:zl, WIDGET_STYLE_OFFS_FRONTCOL_ACTIVATED Widget_SelectColors_readColors: lpm r2, Z+ ; read foreground color lpm r3, Z+ lpm r0, Z+ ; read background color lpm r1, Z pop zh pop zl ret ; @end ; --------------------------------------------------------------------------- ; @routine Widget_SelectBorderColors @global ; ; @param Y address of widget ; @return r1:r0 border color ; @return r3:r2 shadow color ; @clobbers R16 Widget_SelectBorderColors: push zl push zh ldd zl, Y+WIDGET_OFFS_STYLE_LO ldd zh, Y+WIDGET_OFFS_STYLE_HI ldd r16, Y+OBJECT_OFFS_FLAGS sbrc r16, WIDGET_FLAGS_ACTIVATED_BIT rjmp Widget_SelectBorderColors_activated adiw zh:zl, WIDGET_STYLE_OFFS_BORDERCOL_NORM rjmp Widget_SelectBorderColors_readColors Widget_SelectBorderColors_activated: adiw zh:zl, WIDGET_STYLE_OFFS_BORDERCOL_ACTIVATED Widget_SelectBorderColors_readColors: lpm r2, Z+ ; read border color lpm r3, Z+ lpm r0, Z+ ; read shadow color lpm r1, 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 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 clr r17 add r16, r4 ; char width+X adc r17, r5 sub r16, r8 ; check against window width sbc r17, r9 pop r16 brcc 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 widgetLoadDimsForFullWidget ; ; @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 widgetLoadDimsForFullWidget: 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 Widget_DefaultSignalmap: .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