Files
aqhomecontrol/avr/modules/lcd2/gui2/base/guiapp.asm
2026-03-09 02:08:33 +01:00

612 lines
14 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_GUIAPP_ASM
#define AQH_AVR_GUI2_GUIAPP_ASM
; ***************************************************************************
; defines
; Widget in flash
.equ GUIAPP_OFFS_BEGIN = OBJECT_SIZE
.equ GUIAPP_OFFS_ROOTWINDOW_LO = GUIAPP_OFFS_BEGIN+0
.equ GUIAPP_OFFS_ROOTWINDOW_HI = GUIAPP_OFFS_BEGIN+1
.equ GUIAPP_OFFS_SCREENSAVER_LO = GUIAPP_OFFS_BEGIN+2
.equ GUIAPP_OFFS_SCREENSAVER_HI = GUIAPP_OFFS_BEGIN+3
.equ GUIAPP_OFFS_CURRENTWINDOW_LO = GUIAPP_OFFS_BEGIN+4
.equ GUIAPP_OFFS_CURRENTWINDOW_HI = GUIAPP_OFFS_BEGIN+5
.equ GUIAPP_OFFS_TOUCHWIDGET_LO = GUIAPP_OFFS_BEGIN+6
.equ GUIAPP_OFFS_TOUCHWIDGET_HI = GUIAPP_OFFS_BEGIN+7
.equ GUIAPP_OFFS_GUITIMER = GUIAPP_OFFS_BEGIN+8
.equ GUIAPP_SIZE = WIDGET_OFFS_BEGIN+9
.equ GUIAPP_GUITIMER = 2
; ***************************************************************************
; data
.dseg
guiapp_touch_event:
.byte WIDGET_TOUCH_SIZE
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine GuiApp_new @global
;
; @return CFLAG set of okay, cleared otherwise
; @return Y address of newly created object
; @param r16 value for OBJECT_OFFS_OPTS
; @clobbers any
GuiApp_new:
ldi r24, LOW(GUIAPP_SIZE)
ldi r25, HIGH(GUIAPP_SIZE)
bigcall Object_Alloc ; (!r16, !r17)
brcc GuiApp_new_ret
rcall GuiApp_Init ; (r16, r17, X)
sec
GuiApp_new_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_Init @global
;
; @param Y address of object in SDRAM
; @param r16 value for OBJECT_OFFS_OPTS
; @clobbers r16, r17, X
GuiApp_Init:
; call base class
bigcall OBJ_Init ; (r16, r17, X)
; set default signal map
ldi r16, LOW(GuiApp_DefaultSignalmap*2)
std Y+OBJECT_OFFS_SIGNALMAP_LO, r16
ldi r16, HIGH(GuiApp_DefaultSignalmap*2)
std Y+OBJECT_OFFS_SIGNALMAP_HI, r16
; create root window
push yl
push yh
mov xl, yl
mov xh, yh
ldi r16, 0 ; opts
ldi r17, 0 ; pack
bigcall RootWindow_new
; always visible
ldd r16, Y+OBJECT_OFFS_FLAGS
sbr r16, (1<<WIDGET_FLAGS_VISIBLE_BIT) | (1<<WIDGET_FLAGS_LAYOUT_BIT) | (1<<WIDGET_FLAGS_DIRTY_BIT)
std Y+OBJECT_OFFS_FLAGS, r16
mov xl, yl
mov xh, yh
pop yh
pop yl
brcc GuiApp_Init_ret
std Y+GUIAPP_OFFS_ROOTWINDOW_LO, xl
std Y+GUIAPP_OFFS_ROOTWINDOW_HI, xh
; debug
std Y+GUIAPP_OFFS_CURRENTWINDOW_LO, xl
std Y+GUIAPP_OFFS_CURRENTWINDOW_HI, xh
ldi r16, GUIAPP_GUITIMER
std Y+GUIAPP_OFFS_GUITIMER, r16
GuiApp_Init_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_Every100ms @global
;
; @param Y address of object in SDRAM
GuiApp_Every100ms:
ldi r16, OBJECT_SIGNAL_TIMER
clr r17
bigcall OBJ_HandleSignal
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_MsgReceived @global
;
; @param Y address of object in SDRAM
GuiApp_MsgReceived:
ldi r16, OBJECT_SIGNAL_RECVMSG
clr r17
bigcall OBJ_HandleSignal
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_PreventScreenSaver @global
;
; @param Y address of object in SDRAM
; @clobbers any, !Y
GuiApp_PreventScreenSaver:
rcall GuiApp_GetScreenSaver
brcc GuiApp_PreventScreenSaver_ret
push yl
push yh
mov yl, r18
mov yh, r19
ldi r16, WIDGET_SIGNAL_KEEPALIVE
clr r17
bigcall OBJ_HandleSignal
pop yh
pop yl
GuiApp_PreventScreenSaver_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_GrabTouchEvents
;
; @param Y address of object in SDRAM
; @param X byte address of widget grabbing touch events
; @return CFLAG set if grabbed, cleared otherwise
; @clobbers R16, R17, Y
GuiApp_GrabTouchEvents:
ldd r16, Y+GUIAPP_OFFS_TOUCHWIDGET_LO
ldd r17, Y+GUIAPP_OFFS_TOUCHWIDGET_HI
or r16, r17
clc
brne GuiApp_GrabTouchEvents_ret ; only grab if not already grabbed!
std Y+GUIAPP_OFFS_TOUCHWIDGET_LO, xl
std Y+GUIAPP_OFFS_TOUCHWIDGET_HI, xh
sec
GuiApp_GrabTouchEvents_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_UngrabTouchEvents
;
; @param Y address of object in SDRAM
; @param X byte address of widget ungrabbing touch events
; @return CFLAG set if ungrabbed, cleared otherwise
; @clobbers R16, R17
GuiApp_UngrabTouchEvents:
ldd r16, Y+GUIAPP_OFFS_TOUCHWIDGET_LO
ldd r17, Y+GUIAPP_OFFS_TOUCHWIDGET_HI
eor r16, xl
eor r17, xh
or r16, r17
clc
brne GuiApp_UngrabTouchEvents_ret ; only ungrab same widget!
clr r16
std Y+GUIAPP_OFFS_TOUCHWIDGET_LO, r16
std Y+GUIAPP_OFFS_TOUCHWIDGET_HI, r16
sec
GuiApp_UngrabTouchEvents_ret:
ret
; @end
; ***************************************************************************
; getters and setters
; ---------------------------------------------------------------------------
; @routine GuiApp_GetRootWindow @global
;
; @param Y address of object in SDRAM
; @param CFLAG set if response is not a NULL pointer
; @return r19:r18 root window
; @clobbers none
GuiApp_GetRootWindow:
ldd r18, Y+GUIAPP_OFFS_ROOTWINDOW_LO
ldd r19, Y+GUIAPP_OFFS_ROOTWINDOW_HI
sec
tst r18
brne GuiApp_GetRootWindow_ret
tst r19
brne GuiApp_GetRootWindow_ret
clc
GuiApp_GetRootWindow_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_SetRootWindow @global
;
; @param Y address of object in SDRAM
; @param X address of new window
GuiApp_SetRootWindow:
std Y+GUIAPP_OFFS_ROOTWINDOW_LO, xl
std Y+GUIAPP_OFFS_ROOTWINDOW_HI, xh
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_GetCurrentWindow @global
;
; @param Y address of object in SDRAM
; @param CFLAG set if response is not a NULL pointer
GuiApp_GetCurrentWindow:
ldd r18, Y+GUIAPP_OFFS_CURRENTWINDOW_LO
ldd r19, Y+GUIAPP_OFFS_CURRENTWINDOW_HI
sec
tst r18
brne GuiApp_GetCurrentWindow_ret
tst r19
brne GuiApp_GetCurrentWindow_ret
clc
GuiApp_GetCurrentWindow_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_SetCurrentWindow @global
;
; @param Y address of object in SDRAM
; @param X address of new window
GuiApp_SetCurrentWindow:
std Y+GUIAPP_OFFS_CURRENTWINDOW_LO, xl
std Y+GUIAPP_OFFS_CURRENTWINDOW_HI, xh
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_GetScreenSaver @global
;
; @param Y address of object in SDRAM
; @param CFLAG set if response is not a NULL pointer
GuiApp_GetScreenSaver:
ldd r18, Y+GUIAPP_OFFS_SCREENSAVER_LO
ldd r19, Y+GUIAPP_OFFS_SCREENSAVER_HI
sec
tst r18
brne GuiApp_GetScreenSaver_ret
tst r19
brne GuiApp_GetScreenSaver_ret
clc
GuiApp_GetScreenSaver_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_SetScreenSaver @global
;
; @param Y address of object in SDRAM
; @param X address of new window
GuiApp_SetScreenSaver:
std Y+GUIAPP_OFFS_SCREENSAVER_LO, xl
std Y+GUIAPP_OFFS_SCREENSAVER_HI, xh
ret
; @end
; ***************************************************************************
; signal handlers
; ---------------------------------------------------------------------------
; @routine GuiApp_OnDestroy @global
;
; @param Y address of object in SDRAM
; @return CFLAG set if signal handled
; @clobbers any, !Y
GuiApp_OnDestroy:
; TODO (destroy rootWindow)
; Clear CFLAG so that destroy handlers of base classes are called
; after this routine returns. This way the last routine called will be
; OBJ_OnDestroy which then frees the whole SDRAM object on heap.
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_OnTimer
;
; @param Y address of object in SDRAM
; @clobbers any, !Y
GuiApp_OnTimer:
; rcall guiAppCheckTouch ; (any, !Y)
; rcall guiAppSendTimerEvents ; (any, !Y)
rcall guiAppCheckSendGuiEvents ; (any, !Y)
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_OnMsgReceived @global
;
; @param Y address of object in SDRAM
; @param X pointer to message received in SDRAM
GuiApp_OnMsgReceived:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_OnTouch
;
; @param Y address of object in SDRAM
; @clobbers any, !Y
GuiApp_OnTouch:
rcall guiAppSendTouchEvents
ret
; @end
; ---------------------------------------------------------------------------
; @routine guiAppSendTimerEvents
;
; @param Y ptr to GUIAPP
; @clobbers any, !Y
guiAppSendTimerEvents:
ldi r16, OBJECT_SIGNAL_TIMER
clr r17
ldi r20, (1<<OBJECT_OPTS_TIMER_BIT)
ldi r21, (1<<OBJECT_OPTS_TIMER_BIT)
rcall guiAppSendRootEventsIfOpts
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine guiAppCheckSendGuiEvents
;
; Send GUI events to current window if timer elapsed.
;
; @param Y ptr to GUIAPP
; @clobbers any, !Y
guiAppCheckSendGuiEvents:
push yl
push yh
rcall GuiApp_GetCurrentWindow
brcc guiAppCheckSendGuiEvents_done
ldd r16, Y+GUIAPP_OFFS_GUITIMER
tst r16
breq guiAppCheckSendGuiEvents_done
dec r16
std Y+GUIAPP_OFFS_GUITIMER, r16
brne guiAppCheckSendGuiEvents_done
; timer elapsed, send layout events, draw events
push yl
push yh
mov yl, r18
mov yh, r19
ldi r16, WIDGET_SIGNAL_LAYOUT
clr r17
ldi r20, (1<<WIDGET_FLAGS_VISIBLE_BIT) | (1<<WIDGET_FLAGS_LAYOUT_BIT)
bigcall OBJ_TreeHandleSignalIfFlagsSet ; (any, !Y)
ldi r16, WIDGET_SIGNAL_DRAW
clr r17
ldi r20, (1<<WIDGET_FLAGS_VISIBLE_BIT) | (1<<WIDGET_FLAGS_DIRTY_BIT)
bigcall OBJ_TreeHandleSignalIfFlagsSet ; (any, !Y)
pop yh
pop yl
ldi r16, GUIAPP_GUITIMER
std Y+GUIAPP_OFFS_GUITIMER, r16
guiAppCheckSendGuiEvents_done:
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine guiAppSendTouchEvents
;
; Send touch events to current window or grabbing widget.
;
; @param Y ptr to GUIAPP
; @clobbers any, !Y
guiAppSendTouchEvents:
push yl
push yh
ldd r18, Y+GUIAPP_OFFS_TOUCHWIDGET_LO
ldd r19, Y+GUIAPP_OFFS_TOUCHWIDGET_HI
mov r16, r18
or r16, r19
breq guiAppSendTouchEvents_sendToAll
mov yl, r18
mov yh, r19
ldi r16, WIDGET_SIGNAL_TOUCH
clr r17
bigcall OBJ_HandleSignal
rjmp guiAppSendTouchEvents_done
guiAppSendTouchEvents_sendToAll:
rcall GuiApp_GetCurrentWindow ; r19:r18=current window (none)
brcc guiAppSendTouchEvents_done
; send touch signal
mov yl, r18
mov yh, r19
ldi r16, WIDGET_SIGNAL_TOUCH
clr r17
ldi r20, (1<<WIDGET_OPTS_INPUT_BIT)
ldi r21, (1<<WIDGET_OPTS_INPUT_BIT)
bigcall OBJ_TreeHandleSignalIfMatchingOpts
guiAppSendTouchEvents_done:
pop yh
pop yl
; send keepAlive to screensaver
rcall GuiApp_PreventScreenSaver
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine guiAppSendRootMsgEvents
;
; Send touch events to root window.
;
; @param Y ptr to GUIAPP
; @param X pointer to message received in SDRAM
; @clobbers any, !Y
guiAppSendRootMsgEvents:
ldi r16, WIDGET_SIGNAL_TOUCH
clr r17
ldi r20, (1<<OBJECT_OPTS_MSGRECV_BIT)
ldi r21, (1<<OBJECT_OPTS_MSGRECV_BIT)
rcall guiAppSendRootEventsIfOpts
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine guiAppSendRootEventsIfOpts
;
; Send events to all widgets with matching OPTS_LO.
;
; @param Y ptr to GUIAPP
; @param R16 signal number
; @param R17 selector
; @param xl param1
; @param xh param2
; @param r20 mask for OBJECT_OFFS_OPTS
; @param r21 value for OBJECT_OFFS_OPTS to match
; @clobbers any, !Y
guiAppSendRootEventsIfOpts:
push yl
push yh
rcall GuiApp_GetRootWindow ; r19:r18=root window (none)
brcc guiAppSendRootEventsIfOpts_done
; send signal to root window and all below
mov yl, r18
mov yh, r19
bigcall OBJ_TreeHandleSignalIfMatchingOpts
guiAppSendRootEventsIfOpts_done:
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine guiAppCheckTouch
;
; @param Y ptr to GUIAPP
; @clobbers any, !Y
guiAppCheckTouch:
bigcall Display_InputGetState ; r16=flags, r5:r4=x, r7:r6=y
mov r17, r16
andi r17, (1<<DISPLAY_IFLAGS_CHGCOORD_BIT) | (1<<DISPLAY_IFLAGS_CHGPRESS_BIT)
breq guiAppCheckTouch_ret
ldi xl, LOW(guiapp_touch_event)
ldi xh, HIGH(guiapp_touch_event)
st X+, r4 ; X
st X+, r5
st X+, r6 ; Y
st X+, r7
st X, r16 ; flags
sbiw xh:xl, 4 ; (4 times incremented)
; send touch signal
ldi r16, WIDGET_SIGNAL_TOUCH
clr r17
bigcall OBJ_HandleSignal
guiAppCheckTouch_ret:
ret
; @end
; ***************************************************************************
; data in FLASH
GuiApp_DefaultSignalmap:
; header
.dw Object_DefaultSignalmap*2 ; next table to use
; entries
.db 0, OBJECT_SIGNAL_TIMER, LOW(GuiApp_OnTimer), HIGH(GuiApp_OnTimer)
.db 0, OBJECT_SIGNAL_DESTROY, LOW(GuiApp_OnDestroy), HIGH(GuiApp_OnDestroy)
.db 0, 0, 0, 0 ; end of table
#endif