From 0d6bbd1147651ff80e751b02bf4cab0702282c0e Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Tue, 3 Mar 2026 23:51:52 +0100 Subject: [PATCH] gui2: started working on a SDRAM based GUI implementation. --- avr/modules/lcd2/gui/TODO | 71 +++ avr/modules/lcd2/gui2/base/object.asm | 665 ++++++++++++++++++++++++++ avr/modules/lcd2/gui2/base/widget.asm | 569 ++++++++++++++++++++++ 3 files changed, 1305 insertions(+) create mode 100644 avr/modules/lcd2/gui2/base/object.asm create mode 100644 avr/modules/lcd2/gui2/base/widget.asm diff --git a/avr/modules/lcd2/gui/TODO b/avr/modules/lcd2/gui/TODO index f89cdcf..6ca1031 100644 --- a/avr/modules/lcd2/gui/TODO +++ b/avr/modules/lcd2/gui/TODO @@ -1,4 +1,39 @@ + +object: +- next 2 2 +- parent 2 4 +- child 2 6 +- opts 2 8 +- flags 1 9 +- selector 1 10 +- target 2 12 +- signalMap 2 14 + +widget: +- X 1 15 +- Y 1 16 +- W 1 17 +- H 1 18 +- style 2 (ptr) 20 + - frontCol 2 2 + - backCol 2 4 + - borderCol 2 6 + - borderWidth 1 7 + - font 2 9 + - charWidth 1 10 + - charHeight 1 11 + + + +page: light +- up to 8 light bulbs, each for one device +- lightPage: + - SDRAM: ptr to lightData + - address of target device (1 byte) + - currentMode (1 byte) + - currentColor (4 bytes) + - sensor watch: - SDRAM vars: - change limits @@ -7,6 +42,42 @@ - SENSORWATCH_SD_OFFS_UPPERLIMIT_CRIT_LO - SENSORWATCH_SD_OFFS_LOWERLIMIT_CRIT_LO - add private flags (HAVE_VALUE, USE_UPPERWARNLIMIT, USE_LOWERWARNLIMIT, USE_UPPERCRITLIMIT, USE_LOWERCRITLIMIT) + - widgets: + + Mode: [Auto] [On] [Off] + Color: [Preset1] [Preset2] [Preset3] + Red: [123] + Green: [123] + Blue: [123] + White: [123] + +page: numInput (g_win_numinput) +- SDRAM: + - prevPage + - flags + - minNum + - maxNum + - currPos + - editBuffer[7] +- widgets: + + +textField: +- SDRAM: + - ptrText + - slots: + - setText(newText) + - draw(): draw text and a cursor behind it + + + [123 ] + ------------ + [7] [8] [9] + [4] [5] [6] + [1] [2] [3] + [,] [0] [<] + ------------ + [Okay] [Abort] - new pages: diff --git a/avr/modules/lcd2/gui2/base/object.asm b/avr/modules/lcd2/gui2/base/object.asm new file mode 100644 index 0000000..5def65c --- /dev/null +++ b/avr/modules/lcd2/gui2/base/object.asm @@ -0,0 +1,665 @@ +; *************************************************************************** +; 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_OBJECT_ASM +#define AQH_AVR_GUI2_OBJECT_ASM + + +; *************************************************************************** +; defines + +; Object in flash +.equ OBJECT_OFFS_NEXT_LO = 0 +.equ OBJECT_OFFS_NEXT_HI = 1 +.equ OBJECT_OFFS_PARENT_LO = 2 +.equ OBJECT_OFFS_PARENT_HI = 3 +.equ OBJECT_OFFS_CHILD_LO = 4 +.equ OBJECT_OFFS_CHILD_HI = 5 +.equ OBJECT_OFFS_FLAGS = 6 +.equ OBJECT_OFFS_SELECTOR = 7 +.equ OBJECT_OFFS_TARGET_LO = 8 +.equ OBJECT_OFFS_TARGET_HI = 9 +.equ OBJECT_OFFS_OPTS_LO = 10 +.equ OBJECT_OFFS_OPTS_HI = 11 +.equ OBJECT_OFFS_SIGNALMAP_LO = 12 ; byte address (for LPM!) +.equ OBJECT_OFFS_SIGNALMAP_HI = 13 +.equ OBJECT_SIZE = 14 + +; object opts_lo +.equ OBJECT_OPTSLO_TIMER_BIT = 7 +.equ OBJECT_OPTSLO_MSGRECV_BIT = 6 + +; SignalMap entries +.equ OBJECT_SIGNALMAP_OFFS_SELECTOR = 0 +.equ OBJECT_SIGNALMAP_OFFS_SIGNAL = 1 ; end if 0 +.equ OBJECT_SIGNALMAP_OFFS_HANDLER_LO = 2 +.equ OBJECT_SIGNALMAP_OFFS_HANDLER_HI = 3 + +; signals +.equ OBJECT_SIGNAL_NONE = 0 +.equ OBJECT_SIGNAL_CREATE = 1 +.equ OBJECT_SIGNAL_DESTROY = 2 +.equ OBJECT_SIGNAL_TIMER = 3 +.equ OBJECT_SIGNAL_RECVMSG = 4 ; X=msg +.equ OBJECT_SIGNAL_NEXTFREE = 5 + + + +; *************************************************************************** +; code + +.cseg + + + +; --------------------------------------------------------------------------- +; @routine OBJ_Init @global +; +; @param Y address of object in SDRAM +; @clobbers r16, r17, X + +OBJ_Init: + mov xl, yl + mov xh, yh + clr r16 + ldi r17, OBJECT_SIZE + bigcall Utils_FillSram ; (r17, X) + + ldi r16, LOW(Object_DefaultSignalmap*2) + std Y+OBJECT_OFFS_SIGNALMAP_LO, r16 + ldi r16, HIGH(Object_DefaultSignalmap*2) + std Y+OBJECT_OFFS_SIGNALMAP_HI, r16 + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_Fini @global +; +; @param Y address of object in SDRAM +; @clobbers none + +OBJ_Fini: + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_Free @global +; +; Sends a OBJECT_SIGNAL_DESTROY signal to all children and to the given +; object which frees all objects from the Heap. +; CAVEAT: Y is invalid after return! +; +; @param Y address of object in SDRAM +; @clobbers none + +OBJ_Free: + tst yl + brne OBJ_Free_notNull + tst yh + brne OBJ_Free_notNull + rjmp OBJ_Free_ret + +OBJ_Free_notNull: + ldi r16, OBJECT_SIGNAL_DESTROY + clr r17 + rcall OBJ_TreeHandleSignalChildenFirst ; (any, !R16, !R17, !X, !Y) + +OBJ_Free_ret: + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_OnDestroy @global +; +; Releases given object from heap. +; CAVEAT: Y is invalid after return! +; +; @param Y address of object in SDRAM +; @return CFLAG set if signal handled +; @clobbers r16, r17, r18, r19, r20, r21, r24, r25, X + +OBJ_OnDestroy: + rcall OBJ_Unlink ; (r16, r17, r18, r19, r20, r21, X) + +#ifdef MODULES_HEAP + mov xl, yl + mov xh, yh + bigcall Heap_Free ; (r16, r17, r24, r25, X) +#endif + + sec + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_GetNext @global +; +; @param Y address of object +; @return CFLAG set, if found, cleared otherwise +; @return r19:r18 resulting object +; @clobbers none + +OBJ_GetNext: + tst yl + brne OBJ_GetNext_notNull + tst yh + brne OBJ_GetNext_notNull + rjmp OBJ_GetNext_clcRet +OBJ_GetNext_notNull: + ldd r18, Y+OBJECT_OFFS_NEXT_LO + ldd r19, Y+OBJECT_OFFS_NEXT_HI + tst r18 + brne OBJ_GetNext_secRet + tst r19 + brne OBJ_GetNext_secRet +OBJ_GetNext_clcRet: + clc + rjmp OBJ_GetNext_ret +OBJ_GetNext_secRet: + sec +OBJ_GetNext_ret: + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_GetParent @global +; +; @param Y address of object +; @return CFLAG set, if found, cleared otherwise +; @return r19:r18 resulting object +; @clobbers none + +OBJ_GetParent: + tst yl + brne OBJ_GetParent_notNull + tst yh + brne OBJ_GetParent_notNull + rjmp OBJ_GetParent_clcRet +OBJ_GetParent_notNull: + ldd r18, Y+OBJECT_OFFS_PARENT_LO + ldd r19, Y+OBJECT_OFFS_PARENT_HI + tst r18 + brne OBJ_GetParent_secRet + tst r19 + brne OBJ_GetParent_secRet +OBJ_GetParent_clcRet: + clc + rjmp OBJ_GetParent_ret +OBJ_GetParent_secRet: + sec +OBJ_GetParent_ret: + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_GetFirstChild @global +; +; @param Y address of object +; @return CFLAG set, if found, cleared otherwise +; @return r19:r18 resulting object +; @clobbers none + +OBJ_GetFirstChild: + tst yl + brne OBJ_GetFirstChild_notNull + tst yh + brne OBJ_GetFirstChild_notNull + rjmp OBJ_GetFirstChild_clcRet +OBJ_GetFirstChild_notNull: + ldd r18, Y+OBJECT_OFFS_PARENT_LO + ldd r19, Y+OBJECT_OFFS_PARENT_HI + tst r18 + brne OBJ_GetFirstChild_secRet + tst r19 + brne OBJ_GetFirstChild_secRet +OBJ_GetFirstChild_clcRet: + clc + rjmp OBJ_GetFirstChild_ret +OBJ_GetFirstChild_secRet: + sec +OBJ_GetFirstChild_ret: + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_GetLastChild @global +; +; @param Y address of object +; @return CFLAG set, if found, cleared otherwise +; @return r19:r18 resulting object +; @clobbers none + +OBJ_GetLastChild: + push yl + push yh + rcall OBJ_GetFirstChild ; R19:R18=obj (none) + brcc OBJ_GetLastChild_ret + +OBJ_GetLastChild_loop: + mov yl, r18 + mov yh, r19 + rcall OBJ_GetNext ; R19:R18=obj (none) + brcs OBJ_GetLastChild_loop + mov r18, yl + mov r19, yh + sec +OBJ_GetLastChild_ret: + pop yh + pop yl + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_AddChild @global +; +; @param Y object to add to +; @param X object to add +; @clobbers r18, r19 + +OBJ_AddChild: + rcall OBJ_GetLastChild ; r19:r18=last child (r18, r19) + brcc OBJ_AddChild_setAsFirstChild + ; append to last child + push yl + push yh + mov yl, r18 + mov yh, r19 + std Y+OBJECT_OFFS_NEXT_LO, xl + std Y+OBJECT_OFFS_NEXT_HI, xh + pop yh + pop yl + rjmp OBJ_AddChild_setParent +OBJ_AddChild_setAsFirstChild: + std Y+OBJECT_OFFS_CHILD_LO, xl + std Y+OBJECT_OFFS_CHILD_HI, xh +OBJ_AddChild_setParent: + adiw xh:xl, OBJECT_OFFS_PARENT_LO + st X+, yl + st X, yh + sbiw xh:xl, (OBJECT_OFFS_PARENT_LO+1) + ret +; @end + + + + +; --------------------------------------------------------------------------- +; @routine OBJ_Unlink @global +; +; @param Y object to unlink +; @clobbers r16, r17, r18, r19, r20, r21, X + +OBJ_Unlink: + mov xl, yl + mov xh, yh + adiw xh:xl, OBJECT_OFFS_NEXT_LO ; r21:r20=next + ld r20, X+ + ld r21, X + sbiw xh:xl, (OBJECT_OFFS_NEXT_LO+1) + + push yl + push yh + rcall objGetPredecessor ; Y=predecessor (r16, r17, Y) + brcc OBJ_Unlink_l1 + ; unlink from predecessor + std Y+OBJECT_OFFS_NEXT_LO, r20 ; copy NEXT to predecessor + std Y+OBJECT_OFFS_NEXT_HI, r21 + rjmp OBJ_Unlink_l2 +OBJ_Unlink_l1: ; no predecessor, unlink from parent + pop yh + pop yl + rcall OBJ_GetParent + brcc OBJ_Unlink_clearTreePtrs + push yl + push yh + mov yl, r18 + mov yh, r19 + std Y+OBJECT_OFFS_CHILD_LO, r20 + std Y+OBJECT_OFFS_CHILD_HI, r21 +OBJ_Unlink_l2: + pop yh + pop yl +OBJ_Unlink_clearTreePtrs: + clr r16 + std Y+OBJECT_OFFS_NEXT_LO, r16 + std Y+OBJECT_OFFS_NEXT_HI, r16 + std Y+OBJECT_OFFS_PARENT_LO, r16 + std Y+OBJECT_OFFS_PARENT_HI, r16 +OBJ_Unlink_ret: + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_EmitSignal @global +; +; @param Z byte address of object (for LPM!) +; @param R16 signal number +; @param xl param1 +; @param xh param2 +; @clobbers any, !Y + +OBJ_EmitSignal: + push yl + push yh + ldd r17, Y+OBJECT_OFFS_SELECTOR + ldd r23, Y+OBJECT_OFFS_TARGET_LO + ldd yh, Y+OBJECT_OFFS_TARGET_HI + mov yl, r23 + rcall OBJ_HandleSignal ; (any, !Y) + pop yh + pop yl + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_HandleSignal @global +; +; @param Y byte address of object (for LPM!) +; @param R16 signal number +; @param R17 selector +; @param xl param1 +; @param xh param2 +; @return CFLAG set if handled, cleared otherwise +; @clobbers any, !Y + +OBJ_HandleSignal: + push yl + push yh + rcall objGetHandlerFromSignalMap ; r19:r18=handler (r22, r23, Z) + brcc OBJ_HandleSignal_done + rcall OBJ_HandleSignal_jmpR19R18 +OBJ_HandleSignal_done: + pop yh + pop yl + ret +OBJ_HandleSignal_jmpR19R18: + ; jmp to r19:r18 via stack + push r18 + push r19 + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_TreeHandleSignal @global @recursive +; +; @param Y address of object +; @param R16 signal number +; @param R17 selector +; @param xl param1 +; @param xh param2 +; @return CFLAG set if handled, cleared otherwise +; @clobbers any, !R16, !R17, !X, !Y + +OBJ_TreeHandleSignal: + push yl + push yh + ; call signal handler + push r16 + push r17 + push xl + push xh + rcall OBJ_HandleSignal ; (any, !Y) + pop xh + pop xl + pop r17 + pop r16 + ; handle children + rcall OBJ_GetFirstChild ; r19:r18=object (none) +OBJ_TreeHandleSignal_loop: + brcc OBJ_TreeHandleSignal_done + mov yl, r18 + mov yh, r19 + rcall OBJ_TreeHandleSignal ; recursion! + rcall OBJ_GetNext ; r19:r18=object (none) + rjmp OBJ_TreeHandleSignal_loop +OBJ_TreeHandleSignal_done: + pop yh + pop yl + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_TreeHandleSignalChildenFirst @global @recursive +; +; Sends a given signal to a tree of objects, handling children first. +; After sending a signal to a child object that object is no longer accessed +; from within this routine, so it can be used to send a DESTROY signal which +; frees the object from the memory heap. +; +; @param Y address of object +; @param R16 signal number +; @param R17 selector +; @param xl param1 +; @param xh param2 +; @return CFLAG set if handled, cleared otherwise +; @clobbers any, !R16, !R17, !X, !Y + +OBJ_TreeHandleSignalChildenFirst: + push yl + push yh + ; handle children first + rcall OBJ_GetFirstChild ; r19:r18=object (none) + brcc OBJ_TreeHandleSignalChildenFirst_done +OBJ_TreeHandleSignalChildenFirst_loop: + mov yl, r18 + mov yh, r19 + rcall OBJ_GetNext ; r19:r18=object (none) + ldi r20, 0 + sbci r20, 0 + push r18 + push r19 + push r20 + rcall OBJ_TreeHandleSignalChildenFirst ; recursion! + pop r20 + pop r19 + pop r18 + tst r20 ; result of OBJ_GetNext (0=no next) + brne OBJ_TreeHandleSignalChildenFirst_loop +OBJ_TreeHandleSignalChildenFirst_done: + pop yh + pop yl + ; call signal handler on self + push r16 + push r17 + push xl + push xh + rcall OBJ_HandleSignal ; (any, !Y) + pop xh + pop xl + pop r17 + pop r16 + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_AddFlagsDown @global +; +; @param Y address of object +; @param R16 flags to add +; @clobbers r17, r18, r19 + +OBJ_AddFlagsDown: + push yl + push yh + ldd r17, Y+OBJECT_OFFS_FLAGS + or r17, r16 + std Y+OBJECT_OFFS_FLAGS, r17 + ; handle children + rcall OBJ_GetFirstChild ; r19:r18=object (none) +OBJ_AddFlagsDown_loop: + brcc OBJ_AddFlagsDown_done + mov yl, r18 + mov yh, r19 + rcall OBJ_AddFlagsDown ; recursion! + rcall OBJ_GetNext ; r19:r18=object (none) + rjmp OBJ_AddFlagsDown_loop +OBJ_AddFlagsDown_done: + pop yh + pop yl + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine OBJ_SubFlagsDown @global +; +; @param Y address of object +; @param R16 flags to subtract +; @clobbers r17, r18, r19 + +OBJ_SubFlagsDown: + push yl + push yh + ldd r17, Y+OBJECT_OFFS_FLAGS + com r16 + and r17, r16 + com r16 + std Y+OBJECT_OFFS_FLAGS, r17 + ; handle children + rcall OBJ_GetFirstChild ; r19:r18=object (none) +OBJ_SubFlagsDown_loop: + brcc OBJ_SubFlagsDown_done + mov yl, r18 + mov yh, r19 + rcall OBJ_SubFlagsDown ; recursion! + rcall OBJ_GetNext ; r19:r18=object (none) + rjmp OBJ_SubFlagsDown_loop +OBJ_SubFlagsDown_done: + pop yh + pop yl + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine objGetHandlerFromSignalMap +; +; @param Y address of object +; @param R16 signal number +; @param R17 selector +; @param xl param1 +; @param xh param2 +; @return CFLAG set if found, cleared otherwise +; @return R19:R18 handler found +; @clobbers r22, r23, Z + +objGetHandlerFromSignalMap: + ldd zl, Y+OBJECT_OFFS_SIGNALMAP_LO + ldd zh, Y+OBJECT_OFFS_SIGNALMAP_HI + mov r23, zl + or r23, zh + clc + breq objGetHandlerFromSignalMap_done + ; Z=signal map +objGetHandlerFromSignalMap_loop: + lpm r22, Z+ ; selector + lpm r23, Z+ ; signal (0=end of table) + lpm r18, Z+ ; handler LOW + lpm r19, Z+ ; handler HIGH + tst r23 ; end of table? + clc + breq objGetHandlerFromSignalMap_done ; yes, jmp + cp r16, r23 ; signal match? + brne objGetHandlerFromSignalMap_next ; no, next + tst r22 + breq objGetHandlerFromSignalMap_checkHandler ; accept any selector if it is 0 in table + cp r17, r22 ; selector match? + brne objGetHandlerFromSignalMap_next ; no, next +objGetHandlerFromSignalMap_checkHandler: + mov r23, r18 ; handler==NULL? + or r23, r19 + clc + breq objGetHandlerFromSignalMap_done ; yes, done + sec ; found handler, return in r19:r18 + rjmp objGetHandlerFromSignalMap_done +objGetHandlerFromSignalMap_next: + rjmp objGetHandlerFromSignalMap_loop + +objGetHandlerFromSignalMap_done: + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine objGetPredecessor +; +; @param Y address of object whose predecessor is to be found +; @return CFLAG set if predecessor found, cleared otherwise +; @return Y pointer to predecessor (if CFLAG set) +; @clobbers r16, r17, Y + +objGetPredecessor: + rcall OBJ_GetParent + brcc objGetPredecessor_ret + mov r16, yl + mov r17, yh + rcall OBJ_GetFirstChild ; R19:R18=obj + brcc objGetPredecessor_ret + mov yl, r18 + mov yh, r19 +objGetPredecessor_loop: + rcall OBJ_GetNext + brcc objGetPredecessor_ret + cp r18, r16 + brne objGetPredecessor_next + cp r19, r17 + brne objGetPredecessor_next + sec + rjmp objGetPredecessor_ret +objGetPredecessor_next: + mov yl, r18 + mov yh, r19 + rjmp objGetPredecessor_loop +objGetPredecessor_ret: + ret +; @end + + + + + + + +Object_DefaultSignalmap: + .db 0, OBJECT_SIGNAL_DESTROY, LOW(OBJ_OnDestroy), HIGH(OBJ_OnDestroy) + .db 0, 0, 0, 0 ; end of table + + + +#endif + diff --git a/avr/modules/lcd2/gui2/base/widget.asm b/avr/modules/lcd2/gui2/base/widget.asm new file mode 100644 index 0000000..8eed11d --- /dev/null +++ b/avr/modules/lcd2/gui2/base/widget.asm @@ -0,0 +1,569 @@ +; *************************************************************************** +; 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 + +