4 ; Pointer changing and caret blinking (TMA)
6 ; © 1994-1998 Straylight
9 ;----- Licensing note -------------------------------------------------------
11 ; This file is part of Straylight's Sapphire library.
13 ; Sapphire is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
18 ; Sapphire is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ; GNU General Public License for more details.
23 ; You should have received a copy of the GNU General Public License
24 ; along with Sapphire. If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 ;----- Standard header ------------------------------------------------------
32 ;----- External dependencies ------------------------------------------------
44 ;----- Main code ------------------------------------------------------------
46 AREA |Sapphire$$Code|,CODE,READONLY
48 ;----- Pointer shape changing -----------------------------------------------
50 ; --- ptr_setShape ---
52 ; On entry: R0 == sprite name
53 ; R1 == x offset of hot spot
54 ; R2 == y offset of hot spot
58 ; Use: Set the pointer sprite to the given name. The sprite area
59 ; used is that returned from resspre_area.
64 STMFD R13!,{R0-R7,R12,R14} ;Stack some registers
65 WSPACE ptr__wSpace ;Get my workspace
67 ; --- Try to find a good match for the mode ---
69 MOV R1,R0 ;Get name in R1
70 BL screen_getInfo ;Get mode information block
71 MOV R7,R0 ;Remember its position
72 MOV R0,R11 ;Put my buffer in R0
73 BL str_cpy ;Copy the string across
75 MOV R4,#'0' ;For ASCII conversion
76 LDR R1,[R7,#screen_dx] ;Get x pixel size
77 ADD R1,R4,R1 ;Convert to ASCII pix size
78 STRB R1,[R0],#1 ;Store it in the buffer
79 LDR R1,[R7,#screen_dy] ;Get y pixel size
80 ADD R1,R4,R1 ;Convert to ASCII pix size
81 STRB R1,[R0],#1 ;Store it in the buffer
83 STRB R1,[R0] ;Stick a NULL on the end
85 ; --- Does sprite exist (sprite call corrupts R0-R6) ---
87 MOV R0,#40 ;Read sprite information
88 MOV R2,R11 ;Pointer to sprite name
89 BL sprite_op ;Does the sprite exist
91 LDMIA R13,{R2,R4,R5} ;Get users name, x and y
92 BVS %10ptr_setShape ;If sprite didn't exist...
94 ; --- Now use the new sprite ---
96 MOV R2,R11 ;Use this sprite name
98 ; --- Alter the x and y offsets for new resolution ---
100 LDR R0,[R7,#screen_xEig] ;Get the screen xEig
101 MOV R4,R4,LSL #1 ;Multiply by 2
102 MOV R4,R4,LSR R0 ;And shift down by xEig
103 LDR R0,[R7,#screen_yEig] ;Get the screen yEig
104 MOV R5,R5,LSL #2 ;Multiply by 4
105 MOV R5,R5,LSR R0 ;And shift down by yEig
107 10ptr_setShape MOV R0,#36 ;Set pointer shape
108 MOV R3,#2 ;Pointer shape number
109 MOV R6,#0 ;Scale factors
110 MOV R7,#0 ;Pixel translation
112 BL sprite_op ;Do the correct SpriteOp
114 ; --- Alter my flags ---
116 LDR R0,ptr__flags ;Get my flags
117 ORR R0,R0,#ptr__USERSET+ptr__NOTDEFAULT
118 STR R0,ptr__flags ;Store the flags back
120 ; --- Return to caller ---
122 LDMFD R13!,{R0-R7,R12,PC}^ ;Return to user
126 ; --- ptr_resetShape ---
132 ; Use: Resets the pointer shape to the default.
134 EXPORT ptr_resetShape
137 STMFD R13!,{R0,R12,R14} ;Save some registers
138 WSPACE ptr__wSpace ;Get my workspace
140 ; --- Is the default pointer already on? ---
142 LDR R0,ptr__flags ;Get my flags
143 TST R0,#ptr__NOTDEFAULT ;Are we using default
144 LDMEQFD R13!,{R0,R12,PC}^ ;Yes, return
146 ; --- Alter the flags ---
148 BIC R0,R0,#ptr__NOTDEFAULT+ptr__USERSET
149 STR R0,ptr__flags ;Store the flags
151 ; --- Now reset the shape using *pointer (Yuck) ---
153 ADR R0,ptr__pointer ;Point to command
154 SWI OS_CLI ;Execute it
156 LDMFD R13!,{R0,R12,PC}^ ;Return to user
160 ptr__pointer DCB "Pointer",0 ;*Pointer command string
162 ;----- Automatic pointer changing -------------------------------------------
166 ; On entry: R12 == pointer to my workspace
170 ; Use: Called on idle events to try to change the pointer
171 ; shape if it needs to.
175 STMFD R13!,{R0-R7,R14} ;Stack some registers
177 LDR R0,ptr__flags ;Get my flags
178 TST R0,#ptr__USERSET ;Are we using user ptr?
179 LDMNEFD R13!,{R0-R7,PC}^ ;Yes, return
181 ; --- Is the pointer over an icon? ---
183 MOV R1,R11 ;Use the scratch pad
184 SWI Wimp_GetPointerInfo ;Get pointer info
185 LDR R0,[R1,#16] ;Get icon under pointer
186 LDR R2,ptr__oldIcon ;What were we over before?
187 STR R0,ptr__oldIcon ;This is now previous icon
188 CMP R2,R0 ;Are they the same
189 LDMEQFD R13!,{R0-R7,PC}^ ;Yes -- return
190 CMP R0,#-1 ;Is it the window background?
191 BEQ %90ptr__idles ;Yes -- skip to the end
193 ; --- Is this icon interesting? ---
195 STR R0,[R1,#4] ;Store the icon number
196 LDR R2,[R1,#12] ;Get the returned window hnd
197 STR R2,[R1,#0] ;Store it at beginning
198 SWI Wimp_GetIconState ;Get the state of the icon
199 LDR R2,[R1,#24] ;Get the icon flags
201 MOV R7,R2,LSR#12 ;Get the button type
202 AND R7,R7,#15 ;...only
204 TST R2,#&100 ;Is it indirected?
205 TSTNE R2,#&01 ;Is it a text icon?
206 BEQ %90ptr__idles ;Not both -- return
207 AND R2,R2,#&1f0000 ;Get the ESG number
208 CMP R2,#&1f0000 ;Is it 31?
209 BEQ %90ptr__idles ;Yes -- it's shaded
211 LDR R2,[R1,#32] ;Get the validation string
212 CMP R2,#-1 ;Does it exist?
213 BEQ %90ptr__idles ;No -- return
215 ; --- Now parse validation string for xp<name>,<x>,<y> ---
217 ; This is based on a state drive parser with the following
220 ; 0 == not in anything useful
221 ; 1 == looking for xp
222 ; 2 == reading sprite name
223 ; 3 == reading x value
224 ; 4 == reading y value
227 MOV R0,#1 ;Set the current state to 1
228 ADD R3,R11,#20 ;Use this buffer
229 MOV R5,#0 ;Current x value
230 MOV R6,#0 ;Current y value
232 ; --- All cases return to here ---
234 00ptr__idles CMP R0,#5 ;Are we in state 5?
235 BEQ %70ptr__idles ;Yes -- we're finished
236 LDRB R1,[R2],#1 ;Get a character
237 CMP R1,#31 ;Is it a terminator
238 BLE %70ptr__idles ;Yes -- we're finished
242 CMP R1,#'\' ;Is it the escape character?
243 BNE %10ptr__idles ;No -- try next case
244 LDRB R4,[R2] ;Get the next byte
245 CMP R4,#31 ;Is it a terminator
246 MOVGT R1,R4 ;No -- use this
247 ADDGT R2,R2,#1 ;...and increment pointer
248 CMP R0,#1 ;Are we in state 1?
249 MOVEQ R0,#0 ;Yes -- go into state 0
250 CMP R0,#2 ;Are we in state 2
251 STREQB R1,[R3],#1 ;Yes -- store the character
252 B %00ptr__idles ;break
256 10ptr__idles CMP R1,#';' ;Is it a new command?
257 BNE %20ptr__idles ;No -- try next case
258 CMP R0,#1 ;Is the state greater than 1?
259 MOVGT R0,#5 ;Yes -- state = 5
260 MOVLE R0,#1 ;No -- state = 1
261 B %00ptr__idles ;break
263 ; --- case 'X' / 'x' ---
265 20ptr__idles CMP R1,#'X' ;Is is an 'X'?
266 CMPNE R1,#'x' ;Or an 'x'?
267 BNE %30ptr__idles ;No -- try next case
268 CMP R0,#1 ;Are we in state 1?
269 BNE %21ptr__idles ;No -- go ahead a bit
270 LDRB R4,[R2] ;Get next character
271 CMP R4,#'P' ;Is it a 'P'?
272 CMPNE R4,#'p' ;Or a 'p'?
273 ADDEQ R2,R2,#1 ;Yes -- increment pointer
274 MOVEQ R0,#2 ;...and set state to 2
275 B %00ptr__idles ;break
277 21ptr__idles CMP R0,#2 ;Are we in state 2?
278 STREQB R1,[R3],#1 ;Yes -- store the character
279 B %00ptr__idles ;break
283 30ptr__idles CMP R1,#',' ;Is it a ,?
284 BNE %40ptr__idles ;No -- try next case
285 CMP R0,#2 ;Are we in state 2?
286 MOVEQ R4,#0 ;Yes -- get the NULL byte
287 STREQB R4,[R3],#1 ;... store it at end of name
288 CMPNE R0,#3 ;Or state 3?
289 CMPNE R0,#4 ;Or state 4?
290 ADDEQ R0,R0,#1 ;If any, increment the state
291 B %00ptr__idles ;break
295 40ptr__idles CMP R0,#1 ;Are we in state 1?
296 MOVEQ R0,#0 ;Yes -- put it in state 0
297 BEQ %00ptr__idles ;break
299 STREQB R1,[R3],#1 ;Yes -- store the character
300 BEQ %00ptr__idles ;break
301 CMP R0,#3 ;Are we in state 3?
303 BNE %00ptr__idles ;No -- break
304 CMP R1,#'0' ;Is it less than '0'
305 BLT %00ptr__idles ;Yes -- break
306 CMP R1,#'9' ;Is it greater than '9'
307 BGT %00ptr__idles ;Yes -- break
308 SUB R1,R1,#'0' ;Turn it into a number
309 MOV R4,#10 ;A useful number
310 CMP R0,#3 ;Are we reading x?
311 MLAEQ R5,R4,R5,R1 ;Yes -- calculate new x
312 MLANE R6,R4,R6,R1 ;No -- calculate new y
313 B %00ptr__idles ;break
315 ; --- We have finished parsing the string ---
317 70ptr__idles CMP R0,#1 ;Is the state > 1?
318 BLE %80ptr__idles ;No -- try default case
319 ADD R0,R11,#20 ;Point to sprite name
320 MOV R1,R5 ;The x value
321 MOV R2,R6 ;The y value
322 BL ptr_setShape ;Set the pointer shape
323 LDR R14,ptr__flags ;Get the new flags
324 BIC R14,R14,#ptr__USERSET ;The user didn't set it
325 STR R14,ptr__flags ;Store them again
326 LDMFD R13!,{R0-R7,PC}^ ;Return
328 ; --- If the button type was writable, use caret_ptr ---
330 80ptr__idles CMP R7,#14 ;Writable?
332 BNE %90ptr__idles ;Return
333 ADR R0,ptr__caretPtr ;The sprite name
336 BL ptr_setShape ;Set the pointer shape
337 LDR R14,ptr__flags ;Get the new flags
338 BIC R14,R14,#ptr__USERSET ;The user didn't set it
339 STR R14,ptr__flags ;Store them again
340 LDMFD R13!,{R0-R7,PC}^ ;Return
342 ; --- Return to the user ---
344 90ptr__idles BL ptr_resetShape ;Reset the pointer
345 LDMFD R13!,{R0-R7,PC}^ ;...and return
349 ; --- ptr__postFilter ---
351 ; On entry: R0 == event code returned
352 ; R1 == pointer to block returned
353 ; R12 == pointer to my workspace
357 ; Use: Called as a post-filter to trap pointer entering/leaving
358 ; events, so that idles may be added for pointer
363 ; --- Ensure that we want this event ---
365 CMP R0,#4 ;Pointer leaving?
366 BEQ %50ptr__postFilter ;Yes -- handle that
367 CMPNE R0,#5 ;Or entering?
368 MOVNES PC,R14 ;Neither, return now
370 ; --- Pointer is entering one of tasks windows ---
372 STMFD R13!,{R0-R3,R14} ;Stack some registers
373 MOV R0,#2 ;Call it this frequently
374 ADR R1,ptr__idles ;Call this on idle events
375 MOV R2,#0 ;Our user handle
376 MOV R3,R12 ;Put our workspace in R12
377 BL idle_handler ;Add the idle handler
378 MOV R0,#-1 ;Set up previous icon number
379 STR R0,ptr__oldIcon ;...to a non positive value
380 LDMFD R13!,{R0-R3,PC}^ ;Return to caller
382 ; --- Pointer is leaving a window ---
384 50 STMFD R13!,{R0-R3,R14} ;Stack some registers
385 MOV R0,#2 ;Call it this frequently
386 ADR R1,ptr__idles ;Call this on idle events
387 MOV R2,#0 ;Our user handle
388 MOV R3,R12 ;Put our workspace in R12
389 BL idle_removeHandler ;Remove the handler routine
390 LDR R14,ptr__flags ;Load my flags word
391 TST R14,#ptr__USERSET ;Is it the user's pointer?
392 BLEQ ptr_resetShape ;No -- clear pointer shape
393 LDMFD R13!,{R0-R3,PC}^ ;And return to caller
397 ptr__caretPtr DCB "ptr_caret",0
399 ;----- Caret blinking -------------------------------------------------------
401 ; --- ptr__doCaret ---
403 ; On entry: R0 == flags word
404 ; R1 == pointer to block to use
408 ; Use: Turn the caret on or off, according to the relevent bit
413 MOV R5,R0 ;Remember flags word
414 SWI Wimp_GetCaretPosition ;Get the caret position
415 LDR R0,[R1,#0] ;Window handle
416 LDR R2,[R1,#8] ;X offset
417 LDR R3,[R1,#12] ;Y offset
418 LDR R4,[R1,#16] ;Caret height and flags
420 ; --- Set or clear the 'invisible' bit ---
422 TST R5,#ptr__ON ;Turn the caret on?
423 ORREQ R4,R4,#1<<25 ;No, set the 'invisible' bit
424 BICNE R4,R4,#1<<25 ;No, clear 'invisible' bit
426 ; --- Set the caret position ---
428 LDR R5,[R1,#20] ;Index into string
429 LDR R1,[R1,#4] ;Icon handle
431 SWI Wimp_SetCaretPosition ;Put back invisible caret
433 MOVS PC,R14 ;Return to caller
437 ; --- ptr__blinkCaret ---
439 ; On entry: R12 == workspace pointer
443 ; Use: Called by an alarm to flash the caret.
447 STMFD R13!,{R0-R5,R14} ;Stack some registers
449 ; --- Do I own the task the carets in? ---
451 MOV R1,R11 ;Point to scratchpad
452 SWI Wimp_GetCaretPosition ;Get the caret position
453 LDR R2,[R1,#0] ;Get window handle
454 CMP R2,#-1 ;Is it in a window?
455 BEQ %00 ;No -- set up alarm, return
457 ; --- Send a acknowledgement message around ---
459 MOV R0,#20 ;Message size
460 STR R0,[R1,#0] ;Store in message block
462 STR R0,[R1,#0] ;Store in message block
463 MOV R0,#19 ;Send message_acknowlegde
464 SWI Wimp_SendMessage ;Send the message
466 ; --- My task handle is now in R2 ---
468 BL wimp_taskHandle ;Get the actual task handle
469 CMP R0,R2 ;Do we own caret?
470 BNE %00 ;No -- set up alarm, return
472 ; --- Mess about withe my flags, and blink caret ---
474 LDR R0,ptr__flags ;Get my flags word
475 TST R0,#ptr__ON ;Is the caret on?
476 BICNE R0,R0,#ptr__ON ;The caret is now off
477 ORREQ R0,R0,#ptr__ON ;The caret is now on
478 STR R0,ptr__flags ;Store flags back
480 BL ptr__doCaret ;Blink the caret
482 ; --- Prepare another alarm ---
484 00 BL ptr__setUpAlarm ;Prepare to flash again
486 ; --- And return to caller ---
488 LDMFD R13!,{R0-R5,PC}^ ;Stack some registers
492 ; --- ptr__setUpAlarm ---
498 ; Use: Sets up an alarm to blink the caret
502 STMFD R13!,{R14} ;Stack return address
503 SWI OS_ReadMonotonicTime ;Get the current time
504 ADD R0,R0,#25 ;Add 1/25 of a second
505 ADR R1,ptr__blinkCaret ;Call this routine
506 ADR R2,ptr__setUpAlarm ;My private handle
507 MOV R3,R12 ;Pass this for R12
508 BL idle_setAlarm ;Set up the alarm
509 LDMFD R13!,{PC} ;Return to caller
513 ; --- ptr_blinkOn ---
519 ; Use: Makes the caret blink while it is in a window owned by your
525 STMFD R13!,{R0-R3,R12,R14} ;Stack some registers
526 WSPACE ptr__wSpace ;Point to my workspace
528 ; --- Turn on caret blinking ---
530 LDR R14,ptr__flags ;Get my flags
531 TST R14,#ptr__BLINKING ;Is blinking on?
532 LDMNEFD R13!,{R0-R3,R12,PC}^ ;Yes -- return
534 ORR R14,R14,#ptr__BLINKING ;Set the 'is blinking' bit
535 STR R14,ptr__flags ;Store the flags word
537 BL ptr__setUpAlarm ;Set up the blinking alarm
539 ; --- Return to client ---
541 LDMFD R13!,{R0-R3,R12,PC}^ ;And return
545 ; --- ptr_blinkOff ---
551 ; Use: Turns the caret blinking off.
556 STMFD R13!,{R0-R5,R12,R14} ;Stack some registers
557 WSPACE ptr__wSpace ;Point to my workspace
559 ; --- Is blinking already off? ---
561 LDR R14,ptr__flags ;Get my flags
562 TST R14,#ptr__BLINKING ;Is blinking on?
563 LDMEQFD R13!,{R0-R5,R12,PC}^ ;Yes -- return
565 BIC R14,R14,#ptr__BLINKING ;Clear the 'is blinking' bit
566 STR R14,ptr__flags ;Store the flags word
568 ; --- Remove any blink alarms already set up ---
570 ADR R0,ptr__setUpAlarm ;My private handle
571 BL idle_removeAllAlarms ;Remove all alarms I own
573 ; --- Update my flags appropriately ---
575 LDR R0,ptr__flags ;Get my flags word
576 ORR R0,R0,#ptr__ON ;Caret is on
577 STR R0,ptr__flags ;Store the flags back
578 MOV R1,R11 ;Point to scratchpad
579 BL ptr__doCaret ;Turn the caret off
581 ; --- Return to client ---
583 LDMFD R13!,{R0-R5,R12,PC}^ ;And return
587 ;----- Initialisation -------------------------------------------------------
595 ; Use: Initialises the ptr system.
600 STMFD R13!,{R0,R1,R12,R14} ;Stack some registers
601 WSPACE ptr__wSpace ;Get my workspace
603 ; --- Are we already initialised? ---
605 LDR R0,ptr__flags ;Get my flags
606 TST R0,#ptr__INITED ;Are we initialised?
607 LDMNEFD R13!,{R0,R9,PC}^ ;Yes -- return
609 ORR R0,R0,#ptr__INITED+ptr__ON ;Set flags
610 STR R0,ptr__flags ;And store them back
612 ; --- Ensure that the event system is initialised ---
616 ; --- And set up a post-filter for pointer changing ---
618 ADR R0,ptr__postFilter ;Address of routine to call
619 MOV R1,R12 ;Call with my workspace
620 BL event_postFilter ;And add to the post filters
622 ; --- Set up exit handler ---
624 BL except_init ;Make sure except is awake
625 ADR R0,ptr_resetShape ;Make pointer normal on exit
626 MOV R1,R12 ;Pass workspace in R12
627 BL except_atExit ;Register the routine
629 ; --- That's it now ---
631 LDMFD R13!,{R0,R1,R12,PC}^ ;Return
635 ptr__wSpace DCD 0 ;My workspace pointer
637 ;----- Workspace ------------------------------------------------------------
642 ptr__flags # 4 ;Flags
644 ptr__INITED EQU (1<<0) ;I've been initialised
645 ptr__BLINKING EQU (1<<1) ;Caret blinking is on
646 ptr__ON EQU (1<<2) ;Caret is on
647 ptr__NOTDEFAULT EQU (1<<3) ;We're not using default ptr
648 ptr__USERSET EQU (1<<4) ;The user set the pointer
650 ptr__oldIcon # 4 ;Icon we were previously over
652 ptr__wSize EQU {VAR}-ptr__wStart
654 AREA |Sapphire$$LibData|,CODE,READONLY
656 DCD ptr__wSize ;Workspace size
657 DCD ptr__wSpace ;Workspace pointer
658 DCD 40 ;Scratchpad size
659 DCD ptr_init ;Initialisation code
661 ;----- That's all, folks ----------------------------------------------------