; ; ptr.s ; ; Pointer changing and caret blinking (TMA) ; ; © 1994-1998 Straylight ; ;----- Licensing note ------------------------------------------------------- ; ; This file is part of Straylight's Sapphire library. ; ; Sapphire is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2, or (at your option) ; any later version. ; ; Sapphire is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with Sapphire. If not, write to the Free Software Foundation, ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ;----- Standard header ------------------------------------------------------ GET libs:header GET libs:swis ;----- External dependencies ------------------------------------------------ GET sapphire:event GET sapphire:except GET sapphire:idle GET sapphire:resspr GET sapphire:sapphire GET sapphire:screen GET sapphire:sprite GET sapphire:string GET sapphire:wimp ;----- Main code ------------------------------------------------------------ AREA |Sapphire$$Code|,CODE,READONLY ;----- Pointer shape changing ----------------------------------------------- ; --- ptr_setShape --- ; ; On entry: R0 == sprite name ; R1 == x offset of hot spot ; R2 == y offset of hot spot ; ; On exit: -- ; ; Use: Set the pointer sprite to the given name. The sprite area ; used is that returned from resspre_area. EXPORT ptr_setShape ptr_setShape ROUT STMFD R13!,{R0-R7,R12,R14} ;Stack some registers WSPACE ptr__wSpace ;Get my workspace ; --- Try to find a good match for the mode --- MOV R1,R0 ;Get name in R1 BL screen_getInfo ;Get mode information block MOV R7,R0 ;Remember its position MOV R0,R11 ;Put my buffer in R0 BL str_cpy ;Copy the string across MOV R4,#'0' ;For ASCII conversion LDR R1,[R7,#screen_dx] ;Get x pixel size ADD R1,R4,R1 ;Convert to ASCII pix size STRB R1,[R0],#1 ;Store it in the buffer LDR R1,[R7,#screen_dy] ;Get y pixel size ADD R1,R4,R1 ;Convert to ASCII pix size STRB R1,[R0],#1 ;Store it in the buffer MOV R1,#0 STRB R1,[R0] ;Stick a NULL on the end ; --- Does sprite exist (sprite call corrupts R0-R6) --- MOV R0,#40 ;Read sprite information MOV R2,R11 ;Pointer to sprite name BL sprite_op ;Does the sprite exist LDMIA R13,{R2,R4,R5} ;Get users name, x and y BVS %10ptr_setShape ;If sprite didn't exist... ; --- Now use the new sprite --- MOV R2,R11 ;Use this sprite name ; --- Alter the x and y offsets for new resolution --- LDR R0,[R7,#screen_xEig] ;Get the screen xEig MOV R4,R4,LSL #1 ;Multiply by 2 MOV R4,R4,LSR R0 ;And shift down by xEig LDR R0,[R7,#screen_yEig] ;Get the screen yEig MOV R5,R5,LSL #2 ;Multiply by 4 MOV R5,R5,LSR R0 ;And shift down by yEig 10ptr_setShape MOV R0,#36 ;Set pointer shape MOV R3,#2 ;Pointer shape number MOV R6,#0 ;Scale factors MOV R7,#0 ;Pixel translation BL sprite_op ;Do the correct SpriteOp ; --- Alter my flags --- LDR R0,ptr__flags ;Get my flags ORR R0,R0,#ptr__USERSET+ptr__NOTDEFAULT STR R0,ptr__flags ;Store the flags back ; --- Return to caller --- LDMFD R13!,{R0-R7,R12,PC}^ ;Return to user LTORG ; --- ptr_resetShape --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Resets the pointer shape to the default. EXPORT ptr_resetShape ptr_resetShape ROUT STMFD R13!,{R0,R12,R14} ;Save some registers WSPACE ptr__wSpace ;Get my workspace ; --- Is the default pointer already on? --- LDR R0,ptr__flags ;Get my flags TST R0,#ptr__NOTDEFAULT ;Are we using default LDMEQFD R13!,{R0,R12,PC}^ ;Yes, return ; --- Alter the flags --- BIC R0,R0,#ptr__NOTDEFAULT+ptr__USERSET STR R0,ptr__flags ;Store the flags ; --- Now reset the shape using *pointer (Yuck) --- ADR R0,ptr__pointer ;Point to command SWI OS_CLI ;Execute it LDMFD R13!,{R0,R12,PC}^ ;Return to user LTORG ptr__pointer DCB "Pointer",0 ;*Pointer command string ;----- Automatic pointer changing ------------------------------------------- ; --- ptr__idles --- ; ; On entry: R12 == pointer to my workspace ; ; On exit: -- ; ; Use: Called on idle events to try to change the pointer ; shape if it needs to. ptr__idles ROUT STMFD R13!,{R0-R7,R14} ;Stack some registers LDR R0,ptr__flags ;Get my flags TST R0,#ptr__USERSET ;Are we using user ptr? LDMNEFD R13!,{R0-R7,PC}^ ;Yes, return ; --- Is the pointer over an icon? --- MOV R1,R11 ;Use the scratch pad SWI Wimp_GetPointerInfo ;Get pointer info LDR R0,[R1,#16] ;Get icon under pointer LDR R2,ptr__oldIcon ;What were we over before? STR R0,ptr__oldIcon ;This is now previous icon CMP R2,R0 ;Are they the same LDMEQFD R13!,{R0-R7,PC}^ ;Yes -- return CMP R0,#-1 ;Is it the window background? BEQ %90ptr__idles ;Yes -- skip to the end ; --- Is this icon interesting? --- STR R0,[R1,#4] ;Store the icon number LDR R2,[R1,#12] ;Get the returned window hnd STR R2,[R1,#0] ;Store it at beginning SWI Wimp_GetIconState ;Get the state of the icon LDR R2,[R1,#24] ;Get the icon flags MOV R7,R2,LSR#12 ;Get the button type AND R7,R7,#15 ;...only TST R2,#&100 ;Is it indirected? TSTNE R2,#&01 ;Is it a text icon? BEQ %90ptr__idles ;Not both -- return AND R2,R2,#&1f0000 ;Get the ESG number CMP R2,#&1f0000 ;Is it 31? BEQ %90ptr__idles ;Yes -- it's shaded LDR R2,[R1,#32] ;Get the validation string CMP R2,#-1 ;Does it exist? BEQ %90ptr__idles ;No -- return ; --- Now parse validation string for xp,, --- ; ; This is based on a state drive parser with the following ; defined states: ; ; 0 == not in anything useful ; 1 == looking for xp ; 2 == reading sprite name ; 3 == reading x value ; 4 == reading y value ; 5 == finished MOV R0,#1 ;Set the current state to 1 ADD R3,R11,#20 ;Use this buffer MOV R5,#0 ;Current x value MOV R6,#0 ;Current y value ; --- All cases return to here --- 00ptr__idles CMP R0,#5 ;Are we in state 5? BEQ %70ptr__idles ;Yes -- we're finished LDRB R1,[R2],#1 ;Get a character CMP R1,#31 ;Is it a terminator BLE %70ptr__idles ;Yes -- we're finished ; --- case '\' --- CMP R1,#'\' ;Is it the escape character? BNE %10ptr__idles ;No -- try next case LDRB R4,[R2] ;Get the next byte CMP R4,#31 ;Is it a terminator MOVGT R1,R4 ;No -- use this ADDGT R2,R2,#1 ;...and increment pointer CMP R0,#1 ;Are we in state 1? MOVEQ R0,#0 ;Yes -- go into state 0 CMP R0,#2 ;Are we in state 2 STREQB R1,[R3],#1 ;Yes -- store the character B %00ptr__idles ;break ; --- case ';' --- 10ptr__idles CMP R1,#';' ;Is it a new command? BNE %20ptr__idles ;No -- try next case CMP R0,#1 ;Is the state greater than 1? MOVGT R0,#5 ;Yes -- state = 5 MOVLE R0,#1 ;No -- state = 1 B %00ptr__idles ;break ; --- case 'X' / 'x' --- 20ptr__idles CMP R1,#'X' ;Is is an 'X'? CMPNE R1,#'x' ;Or an 'x'? BNE %30ptr__idles ;No -- try next case CMP R0,#1 ;Are we in state 1? BNE %21ptr__idles ;No -- go ahead a bit LDRB R4,[R2] ;Get next character CMP R4,#'P' ;Is it a 'P'? CMPNE R4,#'p' ;Or a 'p'? ADDEQ R2,R2,#1 ;Yes -- increment pointer MOVEQ R0,#2 ;...and set state to 2 B %00ptr__idles ;break 21ptr__idles CMP R0,#2 ;Are we in state 2? STREQB R1,[R3],#1 ;Yes -- store the character B %00ptr__idles ;break ; --- case ',' --- 30ptr__idles CMP R1,#',' ;Is it a ,? BNE %40ptr__idles ;No -- try next case CMP R0,#2 ;Are we in state 2? MOVEQ R4,#0 ;Yes -- get the NULL byte STREQB R4,[R3],#1 ;... store it at end of name CMPNE R0,#3 ;Or state 3? CMPNE R0,#4 ;Or state 4? ADDEQ R0,R0,#1 ;If any, increment the state B %00ptr__idles ;break ; --- default --- 40ptr__idles CMP R0,#1 ;Are we in state 1? MOVEQ R0,#0 ;Yes -- put it in state 0 BEQ %00ptr__idles ;break CMP R0,#2 ;State 2? STREQB R1,[R3],#1 ;Yes -- store the character BEQ %00ptr__idles ;break CMP R0,#3 ;Are we in state 3? CMPNE R0,#4 ;Or 4? BNE %00ptr__idles ;No -- break CMP R1,#'0' ;Is it less than '0' BLT %00ptr__idles ;Yes -- break CMP R1,#'9' ;Is it greater than '9' BGT %00ptr__idles ;Yes -- break SUB R1,R1,#'0' ;Turn it into a number MOV R4,#10 ;A useful number CMP R0,#3 ;Are we reading x? MLAEQ R5,R4,R5,R1 ;Yes -- calculate new x MLANE R6,R4,R6,R1 ;No -- calculate new y B %00ptr__idles ;break ; --- We have finished parsing the string --- 70ptr__idles CMP R0,#1 ;Is the state > 1? BLE %80ptr__idles ;No -- try default case ADD R0,R11,#20 ;Point to sprite name MOV R1,R5 ;The x value MOV R2,R6 ;The y value BL ptr_setShape ;Set the pointer shape LDR R14,ptr__flags ;Get the new flags BIC R14,R14,#ptr__USERSET ;The user didn't set it STR R14,ptr__flags ;Store them again LDMFD R13!,{R0-R7,PC}^ ;Return ; --- If the button type was writable, use caret_ptr --- 80ptr__idles CMP R7,#14 ;Writable? CMPNE R7,#15 BNE %90ptr__idles ;Return ADR R0,ptr__caretPtr ;The sprite name MOV R1,#4 ;X offset MOV R2,#5 ;Y Offset BL ptr_setShape ;Set the pointer shape LDR R14,ptr__flags ;Get the new flags BIC R14,R14,#ptr__USERSET ;The user didn't set it STR R14,ptr__flags ;Store them again LDMFD R13!,{R0-R7,PC}^ ;Return ; --- Return to the user --- 90ptr__idles BL ptr_resetShape ;Reset the pointer LDMFD R13!,{R0-R7,PC}^ ;...and return LTORG ; --- ptr__postFilter --- ; ; On entry: R0 == event code returned ; R1 == pointer to block returned ; R12 == pointer to my workspace ; ; On exit: -- ; ; Use: Called as a post-filter to trap pointer entering/leaving ; events, so that idles may be added for pointer ; changing. ptr__postFilter ROUT ; --- Ensure that we want this event --- CMP R0,#4 ;Pointer leaving? BEQ %50ptr__postFilter ;Yes -- handle that CMPNE R0,#5 ;Or entering? MOVNES PC,R14 ;Neither, return now ; --- Pointer is entering one of tasks windows --- STMFD R13!,{R0-R3,R14} ;Stack some registers MOV R0,#2 ;Call it this frequently ADR R1,ptr__idles ;Call this on idle events MOV R2,#0 ;Our user handle MOV R3,R12 ;Put our workspace in R12 BL idle_handler ;Add the idle handler MOV R0,#-1 ;Set up previous icon number STR R0,ptr__oldIcon ;...to a non positive value LDMFD R13!,{R0-R3,PC}^ ;Return to caller ; --- Pointer is leaving a window --- 50 STMFD R13!,{R0-R3,R14} ;Stack some registers MOV R0,#2 ;Call it this frequently ADR R1,ptr__idles ;Call this on idle events MOV R2,#0 ;Our user handle MOV R3,R12 ;Put our workspace in R12 BL idle_removeHandler ;Remove the handler routine LDR R14,ptr__flags ;Load my flags word TST R14,#ptr__USERSET ;Is it the user's pointer? BLEQ ptr_resetShape ;No -- clear pointer shape LDMFD R13!,{R0-R3,PC}^ ;And return to caller LTORG ptr__caretPtr DCB "ptr_caret",0 ;----- Caret blinking ------------------------------------------------------- ; --- ptr__doCaret --- ; ; On entry: R0 == flags word ; R1 == pointer to block to use ; ; On exit: -- ; ; Use: Turn the caret on or off, according to the relevent bit ; in the flags word. ptr__doCaret ROUT MOV R5,R0 ;Remember flags word SWI Wimp_GetCaretPosition ;Get the caret position LDR R0,[R1,#0] ;Window handle LDR R2,[R1,#8] ;X offset LDR R3,[R1,#12] ;Y offset LDR R4,[R1,#16] ;Caret height and flags ; --- Set or clear the 'invisible' bit --- TST R5,#ptr__ON ;Turn the caret on? ORREQ R4,R4,#1<<25 ;No, set the 'invisible' bit BICNE R4,R4,#1<<25 ;No, clear 'invisible' bit ; --- Set the caret position --- LDR R5,[R1,#20] ;Index into string LDR R1,[R1,#4] ;Icon handle SWI Wimp_SetCaretPosition ;Put back invisible caret MOVS PC,R14 ;Return to caller LTORG ; --- ptr__blinkCaret --- ; ; On entry: R12 == workspace pointer ; ; On exit: -- ; ; Use: Called by an alarm to flash the caret. ptr__blinkCaret ROUT STMFD R13!,{R0-R5,R14} ;Stack some registers ; --- Do I own the task the carets in? --- MOV R1,R11 ;Point to scratchpad SWI Wimp_GetCaretPosition ;Get the caret position LDR R2,[R1,#0] ;Get window handle CMP R2,#-1 ;Is it in a window? BEQ %00 ;No -- set up alarm, return ; --- Send a acknowledgement message around --- MOV R0,#20 ;Message size STR R0,[R1,#0] ;Store in message block MOV R0,#0 ;Your ref STR R0,[R1,#0] ;Store in message block MOV R0,#19 ;Send message_acknowlegde SWI Wimp_SendMessage ;Send the message ; --- My task handle is now in R2 --- BL wimp_taskHandle ;Get the actual task handle CMP R0,R2 ;Do we own caret? BNE %00 ;No -- set up alarm, return ; --- Mess about withe my flags, and blink caret --- LDR R0,ptr__flags ;Get my flags word TST R0,#ptr__ON ;Is the caret on? BICNE R0,R0,#ptr__ON ;The caret is now off ORREQ R0,R0,#ptr__ON ;The caret is now on STR R0,ptr__flags ;Store flags back BL ptr__doCaret ;Blink the caret ; --- Prepare another alarm --- 00 BL ptr__setUpAlarm ;Prepare to flash again ; --- And return to caller --- LDMFD R13!,{R0-R5,PC}^ ;Stack some registers LTORG ; --- ptr__setUpAlarm --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Sets up an alarm to blink the caret ptr__setUpAlarm ROUT STMFD R13!,{R14} ;Stack return address SWI OS_ReadMonotonicTime ;Get the current time ADD R0,R0,#25 ;Add 1/25 of a second ADR R1,ptr__blinkCaret ;Call this routine ADR R2,ptr__setUpAlarm ;My private handle MOV R3,R12 ;Pass this for R12 BL idle_setAlarm ;Set up the alarm LDMFD R13!,{PC} ;Return to caller LTORG ; --- ptr_blinkOn --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Makes the caret blink while it is in a window owned by your ; application. EXPORT ptr_blinkOn ptr_blinkOn ROUT STMFD R13!,{R0-R3,R12,R14} ;Stack some registers WSPACE ptr__wSpace ;Point to my workspace ; --- Turn on caret blinking --- LDR R14,ptr__flags ;Get my flags TST R14,#ptr__BLINKING ;Is blinking on? LDMNEFD R13!,{R0-R3,R12,PC}^ ;Yes -- return ORR R14,R14,#ptr__BLINKING ;Set the 'is blinking' bit STR R14,ptr__flags ;Store the flags word BL ptr__setUpAlarm ;Set up the blinking alarm ; --- Return to client --- LDMFD R13!,{R0-R3,R12,PC}^ ;And return LTORG ; --- ptr_blinkOff --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Turns the caret blinking off. EXPORT ptr_blinkOff ptr_blinkOff ROUT STMFD R13!,{R0-R5,R12,R14} ;Stack some registers WSPACE ptr__wSpace ;Point to my workspace ; --- Is blinking already off? --- LDR R14,ptr__flags ;Get my flags TST R14,#ptr__BLINKING ;Is blinking on? LDMEQFD R13!,{R0-R5,R12,PC}^ ;Yes -- return BIC R14,R14,#ptr__BLINKING ;Clear the 'is blinking' bit STR R14,ptr__flags ;Store the flags word ; --- Remove any blink alarms already set up --- ADR R0,ptr__setUpAlarm ;My private handle BL idle_removeAllAlarms ;Remove all alarms I own ; --- Update my flags appropriately --- LDR R0,ptr__flags ;Get my flags word ORR R0,R0,#ptr__ON ;Caret is on STR R0,ptr__flags ;Store the flags back MOV R1,R11 ;Point to scratchpad BL ptr__doCaret ;Turn the caret off ; --- Return to client --- LDMFD R13!,{R0-R5,R12,PC}^ ;And return LTORG ;----- Initialisation ------------------------------------------------------- ; --- ptr_init --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Initialises the ptr system. EXPORT ptr_init ptr_init ROUT STMFD R13!,{R0,R1,R12,R14} ;Stack some registers WSPACE ptr__wSpace ;Get my workspace ; --- Are we already initialised? --- LDR R0,ptr__flags ;Get my flags TST R0,#ptr__INITED ;Are we initialised? LDMNEFD R13!,{R0,R9,PC}^ ;Yes -- return ORR R0,R0,#ptr__INITED+ptr__ON ;Set flags STR R0,ptr__flags ;And store them back ; --- Ensure that the event system is initialised --- BL event_init ; --- And set up a post-filter for pointer changing --- ADR R0,ptr__postFilter ;Address of routine to call MOV R1,R12 ;Call with my workspace BL event_postFilter ;And add to the post filters ; --- Set up exit handler --- BL except_init ;Make sure except is awake ADR R0,ptr_resetShape ;Make pointer normal on exit MOV R1,R12 ;Pass workspace in R12 BL except_atExit ;Register the routine ; --- That's it now --- LDMFD R13!,{R0,R1,R12,PC}^ ;Return LTORG ptr__wSpace DCD 0 ;My workspace pointer ;----- Workspace ------------------------------------------------------------ ^ 0,R12 ptr__wStart # 0 ptr__flags # 4 ;Flags ptr__INITED EQU (1<<0) ;I've been initialised ptr__BLINKING EQU (1<<1) ;Caret blinking is on ptr__ON EQU (1<<2) ;Caret is on ptr__NOTDEFAULT EQU (1<<3) ;We're not using default ptr ptr__USERSET EQU (1<<4) ;The user set the pointer ptr__oldIcon # 4 ;Icon we were previously over ptr__wSize EQU {VAR}-ptr__wStart AREA |Sapphire$$LibData|,CODE,READONLY DCD ptr__wSize ;Workspace size DCD ptr__wSpace ;Workspace pointer DCD 40 ;Scratchpad size DCD ptr_init ;Initialisation code ;----- That's all, folks ---------------------------------------------------- END