; Copyright 1998 Acorn Computers Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; ; > Wimp.s.AutoScroll ;;----------------------------------------------------------------------------- ;; Automatic window scrolling ;;----------------------------------------------------------------------------- [ Autoscr ; Flags layout af_enable * 2_00000000000000000000000000000011 af_horizontal * 2_00000000000000000000000000000001 af_vertical * 2_00000000000000000000000000000010 af_scrollrq * 2_00000000000000000000000000000100 af_read * 2_00000000000000000000000010000000 af_scrolling * 2_00000000000000000000000100000000 af_ptrout * 2_00000000000000000000001000000000 af_ptrpause * 2_00000000000000000000010000000000 af_ptrin * 2_00000000000000000000100000000000 af_ptrleft * 2_00000000000000000001000000000000 af_ptrdown * 2_00000000000000000010000000000000 af_ptrright * 2_00000000000000000100000000000000 af_ptrup * 2_00000000000000001000000000000000 af_canleft * 2_00000000000000010000000000000000 af_candown * 2_00000000000000100000000000000000 af_canright * 2_00000000000001000000000000000000 af_canup * 2_00000000000010000000000000000000 af_status_bits * 2_00000000000011111111111100000000 af_status_can * 2_00000000000011110000000000000000 af_status_horiz * 2_00000000000001010000000000000000 af_status_vert * 2_00000000000010100000000000000000 ; Block definition ^ 0 a_handle # 4 a_pausex0 # 4 a_pausey0 # 4 a_pausex1 # 4 a_pausey1 # 4 a_pauselen # 4 a_rout # 4 a_wsptr # 4 ;;----------------------------------------------------------------------------- ;; SWI Wimp_AutoScroll ;; ;; in R0 = autoscroll state flags ;; bit 0 set => enable horizontal scrolling ;; bit 1 set => enable vertical scrolling ;; bit 2 set => send Scroll_Request instead of Open_Window_Request ;; bit 7 set => just read current states of flags/block ;; R1 -> block ;; +0 window handle to scroll (must be owned by task) ;; +4 left pause zone size ;; +8 bottom pause zone size ;; +12 right pause zone size ;; +16 top pause zone size ;; +20 pause duration (0 = pause not required, -1 = default length) ;; +24 pointer-changing routine (0 for none, 1 for default) ;; +28 workspace pointer for routine (if [R1,#24] >= &8000) ;; out R0 = new autoscroll state flags ;; bits 0-2 preserved, or (if bit 7 set on entry) read ;; bit 7 clear ;; bit 8 set => pause complete ;; bit 9 set => pointer not over visible area rectangles ;; bit 10 set => pointer over pause zone(s) rectangles ;; bit 11 set => pointer over centre zone rectangles ;; bit 12 set => pointer left of centre zone ;; bit 13 set => pointer below centre zone ;; bit 14 set => pointer right of centre zone ;; bit 15 set => pointer above centre zone ;; bit 16 set => there is work area left of the visible area ;; bit 17 set => there is work area below the visible area ;; bit 18 set => there is work area right of the visible area ;; bit 19 set => there is work area above the visible area ;;----------------------------------------------------------------------------- SWIWimp_AutoScroll MyEntry "AutoScroll" TST R0, #af_read BNE return_autoscroll_state ; Wimp_Init not necessary to read state LDR R14, taskhandle LDR R14, [wsptr, R14] TST R14, #task_unused MyXError WimpBadOp, NE, L BVS ExitWimp ; check alive TST R0, #af_enable BEQ %FT01 ; don't bother validating if disabling CMP userblk, #ApplicationStart MyXError WimpBadPtrInR1, LO, L BVS ExitWimp ; then check pointer LDR handle, [userblk, #a_handle] BL checkhandle_owner BVS ExitWimp ; then check it's one of our windows ASSERT a_handle = 0 LDMIA userblk, {R1, cx0, cy0, cx1, cy1, x0, y0, x1} 01 BL int_autoscroll LDRVC R0, autoscr_state B ExitWimp return_autoscroll_state CMP userblk, #ApplicationStart MyXError WimpBadPtrInR1, LO, L BVS ExitWimp ; just check pointer ADRL R14, autoscr_state LDMIA R14, {R0, R1, cx0, cy0, cx1, cy1, x0, y0, x1} TST R0, #af_enable ASSERT a_handle = 0 STMNEIA userblk, {R1, cx0, cy0, cx1, cy1, x0, y0, x1} B ExitWimp ;;----------------------------------------------------------------------------- ;; int_autoscroll ;; ;; in R0 = autoscroll state flags (see above) ;; R1 = (external) window handle to scroll ;; cx0 = left pause zone size ;; cy0 = bottom pause zone size ;; cx1 = right pause zone size ;; cy1 = top pause zone size ;; x0 = pause duration (0 = pause not required, -1 = default length) ;; y0 = pointer routine (or 0 or 1) ;; x1 = pointer routine workspace (if y0 >= &8000) ;;----------------------------------------------------------------------------- int_autoscroll Entry "R0-x1" MOV R0, #0 BL update_autoscroll_state ; deactivate any existing autoscroll ; (does nothing if already off) LDR R0, [sp] ADRL R14, autoscr_handle STMIA R14, {R1, cx0, cy0, cx1, cy1, x0, y0, x1} CMP x0, #-1 ; default pause time requested? LDREQB x0, autoscr_default_pause MOVEQ x0, x0, LSL #1 ADDEQ x0, x0, x0, LSL #2 ; load default time *10 (ds -> cs) CMP y0, #ApplicationStart BHS %FT01 ; if a user routine, leave alone TST y0, #1 ; NB if you add further types, keeping MOVEQ y0, #0 ; bit 0 set will guarantee that some ADRNE y0, autoscroll_pointer_routine_1 ; sort of pointer is displayed MOV x1, wsptr ; even when running on this old Wimp 01 ADRL R14, autoscr_pause STMIA R14, {x0, y0, x1} BL update_autoscroll_state CLRV TST R0, #af_enable EXIT NE MOV R0, #SpriteReason_SetPointerShape ADRL R14, special_pointer ; if turned off, get pointer to sprite LDR R14, [R14] ; name to return shape number 1 to TEQ R14, #0 ADREQL R2, ptr_default2 ADRNEL R2, pointer_sprite MOV R3, #&61 ; just reprogram the shape MOV R4, #0 ; assume origin at top-left MOV R5, #0 MOV R6, #0 MOV R7, #0 SWI XWimp_SpriteOp CLRV EXIT update_autoscroll_state ; In: R0 = new autoscroll state, in bits 0-4 ; Sends a message to the autoscroll owner if the state (of any bit) has changed Entry "R0-R2" LDR R1, autoscr_state STR R0, autoscr_state BL update_autoscroll_flags LDR R0, autoscr_state CLRV TEQ R0, R1 EXIT EQ ; no change LDR R14, autoscr_rout TEQ R14, #0 EXIT EQ ; no pointer update routine CLRV ; make sure clean on entry Push "wsptr" LDR R14, autoscr_rout Push "R14" ; store new PC LDR R14, autoscr_wsptr Push "R14" ; store new wsptr MOV R14, PC ; gets PC+8 Pull "wsptr, PC" ; BL [autoscr_rout] Pull "wsptr" ; retrieve Wimp wsptr EXIT update_autoscroll_flags ; Updates status flag bits to reflect current state Entry "R0-y1,handle,userblk" ADRL R14, autoscr_state LDMIA R14, {R0, R1, cx0, cy0, cx1, cy1} TST R0, #af_enable MOVEQ R0, #0 ; if turned off, zero all bits and exit STREQ R0, autoscr_state STREQB R0, autoscr_scrolling STREQB R0, autoscr_pausing EXIT EQ LDR R14, =af_status_bits ; all bits default to 0 BIC userblk, R0, R14 ; keep in userblk until end of routine Abs handle, R1 LDR R0, mousexpos LDR R1, mouseypos ADD R14, handle, #w_wax0 LDMIA R14, {cx0, cy0, cx1, cy1} ; cx0-cy1 = visible area SUB cx1, cx1, #1 ; make inclusive SUB cy1, cy1, #1 BL get_centre_zone ; x0-y1 = centre zone SUB x1, x1, #1 ; make inclusive SUB y1, y1, #1 CMP cx0, R0 ; is pointer outside visible area? CMPLE R0, cx1 CMPLE cy0, R1 CMPLE R1, cy1 ORRGT userblk, userblk, #af_ptrout BGT %FT01 CMP x0, R0 ; is it in the centre, or a pause zone? CMPLE R0, x1 CMPLE y0, R1 CMPLE R1, y1 ORRGT userblk, userblk, #af_ptrpause ORRLE userblk, userblk, #af_ptrin MOVLE R14, #0 STRLEB R14, autoscr_scrolling ; deactivate scrolling if in centre STRLEB R14, autoscr_pausing 01 LDRB R14, autoscr_scrolling ; read separate flag for this TEQ R14, #0 ORRNE userblk, userblk, #af_scrolling CMP R0, x0 ; is it in the left pause zone? ORRLT userblk, userblk, #af_ptrleft CMP R1, y0 ; is it in the down pause zone? ORRLT userblk, userblk, #af_ptrdown CMP R0, x1 ; is it in the right pause zone? ORRGT userblk, userblk, #af_ptrright CMP R1, y1 ; is it in the up pause zone? ORRGT userblk, userblk, #af_ptrup ADD R14, handle, #w_wax0 ; get visible area and scroll offsets LDMIA R14, {cx0, cy0, cx1, cy1, x0, y1} SUB cx1, cx1, cx0 ; convert to work area coordinates SUB cy0, cy0, cy1 MOV cx0, x0 MOV cy1, y1 ADD cx1, cx1, cx0 ADD cy0, cy0, cy1 ADD R14, handle, #w_wex0 ; get work area extent LDMIA R14, {x0, y0, x1, y1} CMP cx0, x0 ; is there space to move left? ORRGT userblk, userblk, #af_canleft CMP cy0, y0 ; is there space to move down? ORRGT userblk, userblk, #af_candown CMP cx1, x1 ; is there space to move right? ORRLT userblk, userblk, #af_canright CMP cy1, y1 ; is there space to move up? ORRLT userblk, userblk, #af_canup AND R0, userblk, #af_enable TEQ R0, #af_vertical ; do we clear the horizontal bits? BICEQ userblk, userblk, #af_status_horiz TEQ R0, #af_horizontal ; do we clear the vertical bits? BICEQ userblk, userblk, #af_status_vert STR userblk, autoscr_state EXIT get_centre_zone ; In: handle = autoscroll window handle ; Out: x0-y0 = centre zone (may be zero width or height) Entry "cx0-cy1" ADRL R14, autoscr_pz_x0 ; load zone sizes LDMIA R14, {cx0, cy0, cx1, cy1} CMP cx0, #0 ; can't be negative MOVLT cx0, #0 CMP cy0, #0 MOVLT cy0, #0 CMP cx1, #0 MOVLT cx1, #0 CMP cy1, #0 MOVLT cy1, #0 LDR R14, autoscr_state AND R14, R14, #af_enable TEQ R14, #af_vertical ; if just vertical scrolling, MOVEQ cx0, #0 ; don't supply horizontal pause zones MOVEQ cx1, #0 TEQ R14, #af_horizontal ; if just horizontal scrolling, MOVEQ cy0, #0 ; don't supply vertical pause zones MOVEQ cy1, #0 ADD R14, handle, #w_wax0 ; load visible area LDMIA R14, {x0, y0, x1, y1} ADD x0, x0, cx0 ; add on the specified borders SUB x1, x1, cx1 ADD y0, y0, cy0 SUB y1, y1, cy1 CMP x1, x0 ; if x pause zone won't fit ADDLT x1, x1, x0 MOVLT x0, x1, LSR#1 ; find the middle of the overlap MOVLT x1, x0 CMP y1, y0 ; if y pause zone won't fit ADDLT y1, y1, y0 MOVLT y0, y1, LSR#1 ; find the middle of the overlap MOVLT y1, y0 EXIT autoscroll_pointer_routine_1 ; handles pointer changes according to the default rules ; In: R0 = new autoscroll state ; R1 = old autoscroll state Entry "R0-R7" TST R0, #af_scrolling ; don't show pointer if not scrolling MOVEQ R0, #0 TST R1, #af_scrolling MOVEQ R1, #0 AND R0, R0, R0, LSL #4 ; only consider directions in which we AND R0, R0, #af_status_can ; can scroll *and* where the pointer is AND R1, R1, R1, LSL #4 ; suitably positioned AND R1, R1, #af_status_can TEQ R0, #0 ; reduce to on/off status MOVNE R0, #1 TEQ R1, #0 MOVNE R1, #1 TEQ R0, R1 ; don't do anything if status constant EXIT EQ TEQ R0, #0 ; is it being turned on or off? BEQ %FT10 ; turn *on* autoscroll pointer ADRL R4, autoscr_old_ptr_colours MOV R0, #1 ; remember old colour 1 MOV R1, #&19 SWI XOS_ReadPalette BIC R2, R2, #&FF STR R2, [R4], #4 MOV R0, #2 ; remember old colour 2 MOV R1, #&19 SWI XOS_ReadPalette BIC R2, R2, #&FF STR R2, [R4], #4 MOV R0, #3 ; remember old colour 3 MOV R1, #&19 SWI XOS_ReadPalette BIC R2, R2, #&FF STR R2, [R4], #4 ASSERT autoscr_old_ptr_number - autoscr_old_ptr_colours = 3*4 MOV R0,#&6A ; set/read pointer shape no MOV R1,#127 ; this is invalid, so won't be set SWI XOS_Byte ; R1 := actual shape number AND R1, R1, #&F ; forget linkage flag STRB R1, [R4] ; remember old pointer number ADR R0, autoscroll_pointers LDR R2, [sp] ; get R0 from stack AND R2, R2, #af_enable ; get allowed directions SUB R2, R2, #1 ADD R2, R0, R2, LSL#4 ; point at the details for relevant ptr MOV R0, #SpriteReason_ReadSpriteSize SWI XWimp_SpriteOp MOV R5, R4, LSR#1 ; active point y-offset MOV R4, R3, LSR#1 ; active point x-offset TEQ R1, #1 ; does pointer number need changing? MOVEQ R3, #&61 ; just change shape MOVNE R3, #&21 ; change number and shape ; bit 5 clear => uses Wimp palette MOV R6, #0 ; scale for mode MOV R7, #0 ; no translation table MOV R0, #SpriteReason_SetPointerShape SWI XWimp_SpriteOp CLRV EXIT 10 ; turn *off* autoscroll pointer LDRB R3, autoscr_old_ptr_number TEQ R3, #1 MOVNE R0, #SpriteReason_SetPointerShape MOVNE R2, #0 ORRNE R3, R3, #&30 ; just change number MOVNE R4, #0 MOVNE R5, #0 MOVNE R6, #0 MOVNE R7, #0 SWINE XWimp_SpriteOp MOV R0, #SpriteReason_SetPointerShape ADRL R2, ptr_default2 MOV R3, #&61 ; just change shape 1 to ptr_default MOV R4, #0 MOV R5, #0 MOV R6, #0 MOV R7, #0 SWI XWimp_SpriteOp ADRL R2, autoscr_old_ptr_colours LDR R0, [R2], #4 ; R0 = &BBGGRR00 MOV R1, R0, LSR#24 ; R1 = &BB MOV R0, R0, LSL#8 ; R0 = &GGRR0000 LDR R3, =&1901 ORR R0, R0, R3 Push "R0, R1" MOV R0, #OsWord_WritePalette MOV R1, sp SWI XOS_Word ; restore original pointer colour 1 ADD sp, sp, #8 LDR R0, [R2], #4 ; R0 = &BBGGRR00 MOV R1, R0, LSR#24 ; R1 = &BB MOV R0, R0, LSL#8 ; R0 = &GGRR0000 LDR R3, =&1902 ORR R0, R0, R3 Push "R0, R1" MOV R0, #OsWord_WritePalette MOV R1, sp SWI XOS_Word ; restore original pointer colour 2 ADD sp, sp, #8 LDR R0, [R2], #4 ; R0 = &BBGGRR00 MOV R1, R0, LSR#24 ; R1 = &BB MOV R0, R0, LSL#8 ; R0 = &GGRR0000 LDR R3, =&1903 ORR R0, R0, R3 Push "R0, R1" MOV R0, #OsWord_WritePalette MOV R1, sp SWI XOS_Word ; restore original pointer colour 3 ADD sp, sp, #8 CLRV EXIT autoscroll_pointers DCB "ptr_autoscrh", 0, 0, 0, 0 DCB "ptr_autoscrv", 0, 0, 0, 0 DCB "ptr_autoscr", 0, 0, 0, 0, 0 poll_autoscroll ; Called during poll - update scroll flags, issue open/scroll rqs if necessary EntryS "R0-cy1" LDR R0, autoscr_state BL update_autoscroll_state LDRB R0, autoscr_scrolling ; what we do depends upon current state TEQ R0, #0 BNE continueautoscroll LDRB R0, autoscr_pausing TEQ R0, #0 BNE %FT10 ; Neither pausing nor scrolling LDR R0, autoscr_state TST R0, #af_ptrin EXITS NE ; nothing to do in centre LDR R1, autoscr_pause TEQ R1, #0 ; if no pause, start scrolling BEQ startautoscroll ; as soon as we leave the centre TST R0, #af_ptrout EXITS NE ; can't do anything if outside SWI XOS_ReadMonotonicTime ; R0 = current time ADD R0, R0, R1 ; R0 = time when pause ends STR R0, autoscr_next_t LDR R0, mousexpos ; recalculate pause end time STR R0, autoscr_last_x ; if these change subsequently LDR R0, mouseypos ; STR R0, autoscr_last_y ; MOV R0, #-1 STRB R0, autoscr_pausing ; mark pausing EXITS 10 ; Pausing LDR R0, autoscr_state TST R0, #af_ptrpause MOVEQ R0, #0 ; abandon the pause if no longer in STREQB R0, autoscr_pausing ; the pause zone(s) EXITS EQ SWI XOS_ReadMonotonicTime ; R0 = current time LDR cx0, mousexpos LDR cx1, autoscr_last_x TEQ cx0, cx1 LDREQ cy0, mouseypos LDREQ cy1, autoscr_last_y TEQEQ cy0, cy1 LDRNE R1, autoscr_pause ; if the pointer's moved, update the ADDNE R0, R0, R1 ; pointer position and pause end time STRNE R0, autoscr_next_t STRNE cx0, autoscr_last_x STRNE cy0, autoscr_last_y EXITS NE LDR R1, autoscr_next_t ; exit if pause hasn't finished CMP R0, R1 EXITS LO ; else drop through to startautoscroll startautoscroll MOV R0, #-1 ; set flags as necessary STRB R0, autoscr_scrolling MOV R0, #0 STRB R0, autoscr_pausing LDR R0, autoscr_state BL update_autoscroll_state SWI XOS_ReadMonotonicTime ; R0 = current time STR R0, autoscr_last_t ADD R0, R0, #autoscr_update_delay STR R0, autoscr_next_t LDR R0, autoscr_state TST R0, #af_scrollrq ; if issuing Open_Window_Requests, EXITS EQ ; don't do anything else at this time LDR handle, autoscr_handle Abs handle, handle LDR R0, [handle, #w_taskhandle] Task "R0",, "Autoscroll start" ADD sp, sp, #Proc_RegOffset+7*4 ; skip stuff pushed to stack MOV R1, #0 ; x scroll "direction" MOV R2, #0 ; y scroll "direction" B userscroll ; return Scroll_Request event continueautoscroll LDRB R0, autoscr_pausing ; check flag - ensure control passes TEQ R0, #0 ; further down the Wimp_Poll action MOVNE R0, #0 ; list at least once per window update STRB R0, autoscr_pausing EXITS NE SWI XOS_ReadMonotonicTime ; R0 = current time LDR R1, autoscr_next_t CMP R1, R0 EXITS HI ; give other events a chance MOV R1, #-1 STRB R1, autoscr_pausing ; give other events a chance next time LDR R1, autoscr_last_t SUB R1, R0, R1 ; time since last update STR R1, tempworkspace ; keep in case we need it later STR R0, autoscr_last_t ADD R0, R0, #autoscr_update_delay STR R0, autoscr_next_t LDR handle, autoscr_handle Abs handle, handle LDR R0, [handle, #w_taskhandle] Task "R0",, "Autoscroll continue" LDR R0, autoscr_state TST R0, #af_scrollrq AND R0, R0, R0, LSL#4 ; clear "can" bits where pointer isn't BEQ continueautoscroll_open ADD sp, sp, #Proc_RegOffset+7*4 ; skip stuff pushed to stack MOV R1, #0 ; determine scroll "directions" MOV R2, #0 TST R0, #af_canleft MOVNE R1, #-3 TST R0, #af_candown MOVNE R2, #-3 TST R0, #af_canright MOVNE R1, #+3 TST R0, #af_canup MOVNE R2, #+3 B userscroll ; return Scroll_Request event continueautoscroll_open TST R0, #af_status_can EXITS EQ ; don't do anything if we can't scroll ADD sp, sp, #Proc_RegOffset+7*4 ; skip stuff pushed to stack ADD R14, handle, #w_wax0 LDMIA R14, {cx0, cy0, cx1, cy1, x0, y0} STMIA userblk, {R0, cx0, cy0, cx1, cy1} MOV cx0, x0 ; old scroll offsets MOV cy0, y0 BL get_centre_zone ; overwrites x0-y1 LDR R14, dx SUB x1, x1, R14 ; make inclusive LDR R14, dy SUB y1, y1, R14 LDR R14, tempworkspace ; retrieve time since last update LDR R1, mousexpos ; find pointer x offset from window TST R0, #af_canleft SUBNE R1, R1, x0 SUBEQ R1, R1, x1 TST R0, #af_status_horiz MULNE R1, R14, R1 ; multiply by time, and scale down MOVNE R1, R1, ASR#autoscr_speed_factor TEQ R1, #0 LDRPL R14, dx ; compensate for the asymmetric effect ADDPL R1, R1, R14 ; of the rounding-down in OpenWindow TST R0, #af_status_horiz ADDNE cx0, cx0, R1 ; add to old scroll offset LDR R14, tempworkspace ; retrieve time since last update LDR R1, mouseypos ; find pointer y offset from window TST R0, #af_candown SUBNE R1, R1, y0 SUBEQ R1, R1, y1 TST R0, #af_status_vert MULNE R1, R14, R1 ; multiply by time, and scale down MOVNE R1, R1, ASR#autoscr_speed_factor TEQ R1, #0 LDRPL R14, dy ; compensate for the asymmetric effect ADDPL R1, R1, R14 ; of the rounding-down in OpenWindow TST R0, #af_status_vert ADDNE cy0, cy0, R1 ; add to old scroll offset Rel cx1, handle ; finish writing to [userblk] STR cx1, [userblk, #u_handle] ADD R14, userblk, #u_scx STMIA R14, {cx0, cy0, cx1} ; store scx, scy, bhandle B Exit_OpenWindow ; finally, get the window re-opened! ] LTORG DCD 12648430 ; amuse the hackers... ;-) END