; ; drag.s ; ; Support code for dragging operations (MDW) ; ; © 1995-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 GET libs:stream ;----- External dependencies ------------------------------------------------ GET sapphire:akbd GET sapphire:idle GET sapphire:intKeys GET sapphire:sapphire GET sapphire:screen GET sapphire:win ;----- Main code ------------------------------------------------------------ AREA |Sapphire$$Code|,CODE,READONLY ; --- drag_start --- ; ; On entry: R0 == window containing the drag ; R1 == flags word (see flags below) ; R2 == pointer to drag routine ; R3 == magic number to pass in R9 ; R4 == value to pass to routine in R10 ; R5 == value to pass to routine in R12 ; ; On exit: -- ; ; Use: Starts a drag operation. Any outstanding drag operation ; is cancelled on the assumption that someone stole our ; UserDragBox event. EXPORT drag_start drag_start ROUT STMFD R13!,{R0-R7,R12,R14} ;Save some registers WSPACE drag__wSpace ;Find my workspace address ; --- Cancel any current drag operation --- LDR R14,drag__window ;Load current window CMP R14,#0 ;Is there one defined? BLNE drag_cancel ;Yes -- cancel it then ; --- Ensure that this isn't a silly --- ; ; Rather irritatingly, the WIMP's drag-detection is a little ; suspect; it thinks that moving the pointer outside of ; a window while the button is held down is actually a drag. ; We try to hack around this little problem. SWI OS_Mouse ;Read the current mouse pos. CMP R2,#0 ;Are any buttons pressed? LDMEQFD R13!,{R0-R7,R12,PC}^ ;No -- do nothing then ; --- Set up handlers for new drag op --- MOV R0,#0 ;Call me very often please ADR R1,drag__idles ;Point to the handler MOV R2,#0 ;Nothing to pass in R10 MOV R3,R12 ;Pass workspace in R12 BL idle_handler ;Install the handler LDMVSFD R13!,{R0-R7,R12,PC}^ ;If it failed, return now ; --- Set up all the new information --- LDMIA R13,{R0-R3} ;Load information off stack STMIA R12,{R0-R5} ;Save all that lot away MOV R0,#&3F ;Reset the dash pattern STRB R0,drag__dash ;This is the current dash STRB R0,drag__oldDash ;And the previous one BL drag_setDash ;Make it the current pattern SWI OS_ReadMonotonicTime ;Find the current time STR R0,drag__lastTime ;And store that away too ; --- Now read the current position of the drag --- SUB R13,R13,#44 ;Make space for window state LDR R14,drag__window ;Load the window handle STR R14,[R13,#0] ;Save it in the block MOV R1,R13 ;Point to this block SWI Wimp_GetWindowState ;Read the window's position BL drag__find ;Find the current position ADR R14,drag__startPos ;Point to the current posn STMIA R14!,{R4,R5} ;Load the coordinates out STMIA R14!,{R4,R5} ;Store them in start position MOV R0,#drEvent_draw ;Do some drawing please BL drag__draw ;And draw the dash box ADD R13,R13,#44 ;Restore the stack pointer LDMFD R13!,{R0-R7,R12,PC}^ ;Return to caller finally LTORG ; --- drag_scroll --- ; ; On entry: R1 == pointer to window state block ; ; On exit: R2,R3 == new scroll positions to set ; R14 == R1+20 (pointer to scroll offsets) ; ; Use: Works out the scroll positions which should be set to auto- ; scroll the window. The algorithm is simple: the window is ; scrolled so that the point beneath the mouse pointer is ; within the window's visible work area. EXPORT drag_scroll drag_scroll ROUT STMFD R13!,{R0,R1,R4-R7,R14} ;Save some registers ; --- Find the mouse pointer position --- LDMIB R1!,{R4-R7} ;Load the bounding box out LDMIB R1!,{R2,R3} ;And the current scroll pos SUB R13,R13,#20 ;Make a PointerInfo block MOV R1,R13 ;Point at this SWI Wimp_GetPointerInfo ;Read the information LDMIA R13,{R0,R1} ;Load the current position ; --- Now fiddle the scroll positions --- SUBS R14,R0,R4 ;Compare x to left side ADDLT R2,R2,R14 ;If too far left, then scroll SUBS R14,R1,R5 ;Compare y to bottom ADDLT R3,R3,R14 ;If too low, then scroll SUBS R14,R0,R6 ;Compare x to right side ADDGT R2,R2,R14 ;If too far right, scroll SUBS R14,R1,R7 ;Compare y to top ADDGT R3,R3,R14 ;If too high, then scroll ; --- Return everything to caller --- ADD R13,R13,#20 ;Restore the stack pointer LDR R14,[R13,#4] ;Load the pointer out ADD R14,R14,#20 ;Point to scroll offsets LDMFD R13!,{R0,R1,R4-R7,PC}^ ;And return to caller LTORG ; --- drag__dispatch --- ; ; On entry: R0 == event code ; R1-R7 depend on event ; ; On exit: -- ; ; Use: Dispatches a drag event to the current handler. drag__dispatch ROUT STMFD R13!,{R8-R10,R12,R14} ;Save some registers ADR R14,drag__handler ;Point to the handler LDMIA R14,{R8-R10,R12} ;Load the registers out MOV R14,PC ;Set up return address MOV PC,R8 ;Call the routine nicely LDMFD R13!,{R8-R10,R12,PC}^ ;And return to caller LTORG ; --- drag__draw --- ; ; On entry: R0 == event code to pass ; R1 == pointer to window state block (44 bytes required) ; ; On exit: -- ; ; Use: Updates a window using the given event. drag__draw ROUT STMFD R13!,{R0-R9,R14} ;Save some registers MOV R8,R0 ;Look after the event code LDR R9,[R1,#28] ;Load the `behind' pointer ; --- Build the update block --- LDMIB R1,{R2-R5,R7,R14} ;Load the values out of it SUB R6,R2,R7 ;Find the x origin position SUB R4,R4,R2 ;Find the window width MOV R2,R7 ;Get left side of update box ADD R4,R2,R4 ;Get right side of update box SUB R7,R5,R14 ;Find the y origin position SUB R3,R5,R3 ;Find the window height MOV R5,R14 ;Get top of update box SUB R3,R5,R3 ;Get bottom of update box STMIB R1,{R2-R5} ;Save the box back ; --- Set up other registers for the job --- ADR R14,drag__startPos ;Find the start position LDMIA R14,{R2-R5} ;Load the positions out ; --- Finally do the actual update --- SWI Wimp_UpdateWindow ;Start the update job CMP R0,#0 ;Is there anything to do? BEQ %90drag__draw ;No -- then skip ahead 00 MOV R0,R8 ;Get caller's event code BL drag__dispatch ;Call the event handler SWI Wimp_GetRectangle ;Get the next rectangle CMP R0,#0 ;Is there anything left? BNE %b00 ;Yes -- loop back to do it ; --- Tidy up and return to caller --- 90drag__draw STR R9,[R1,#28] ;Store `behind' pointer back LDMFD R13!,{R0-R9,PC}^ ;And return to caller LTORG ; --- drag__find --- ; ; On entry: R1 == pointer to window state block ; ; On exit: R4,R5 == coordinates, suitably transformed ; R6,R7 == window origin coordinates ; CS if mouse button still down, else CC ; ; Use: Locates the mouse pointer within the window. drag__find ROUT STMFD R13!,{R0-R3,R14} ;Save some registers MOV R2,R1 ;Remember initial pointer SUB R13,R13,#20 ;Make space for pointer info MOV R1,R13 ;Point to this block SWI Wimp_GetPointerInfo ;Find the pointer position MOV R1,R2 ;Point to original block ; --- Set up for calling event handler --- LDR R2,[R1,#4] ;Load the left hand side ADD R14,R1,#16 ;Find top and scroll position LDMIA R14,{R5-R7} ;Load them out nicely SUB R6,R2,R6 ;Find the x origin position SUB R7,R5,R7 ;And the y origin position LDMIA R13,{R4,R5} ;Load the coordinates out SUB R4,R4,R6 ;Translate to window coords SUB R5,R5,R7 ;Do that to y coord too MOV R0,#drEvent_trans ;Get handler to translate BL drag__dispatch ;Go and do that then ; --- Tidy up and return --- LDR R14,[R13,#8] ;Load the mouse status CMP R14,#0 ;Are all buttons released? ADD R13,R13,#20 ;Restore the stack block LDMFD R13!,{R0-R3,R14} ;Restore registers ORRNES PC,R14,#C_flag ;If button pressed, return CS BICEQS PC,R14,#C_flag ;Else return CC LTORG ; --- drag__getPosition --- ; ; On entry: R1 == pointer to window state block ; R4,R5 == new position ; R6,R7 == window origin position ; ; On exit: R4,R5 == new position, translated further ; ; Use: Reads the position of the current drag operation. This ; allows the client to do clever things like gridlocking and ; autoscrolling. drag__getPosition ROUT STMFD R13!,{R0,R2,R3,R14} ;Save some registers ADR R14,drag__startPos ;Find the start position LDMIA R14,{R2,R3} ;Load those coordinates out MOV R0,#drEvent_getPos ;Tell client to translate BL drag__dispatch ;Send the event off LDMFD R13!,{R0,R2,R3,PC}^ ;And return to caller LTORG ; --- drag_setDash --- ; ; On entry: R0 == dash pattern byte ; ; On exit: -- ; ; Use: Sets the dash pattern to be the given value. EXPORT drag_setDash drag_setDash ROUT STMFD R13!,{R0-R2,R14} ;Save some registers ; --- Build VDU block --- AND R0,R0,#&FF ;Clear top bits of R0 ORR R1,R0,R0,LSL #8 ;Duplicate the byte ORR R1,R1,R1,LSL #16 ;Fill a word with it MOV R0,#23 ;Get the VDU command code ORR R0,R0,#6<<8 ;OR in the command type ORR R0,R0,R1,LSL #16 ;Put in first two patterns MOV R2,R1,LSR #16 ;Put in last two patterns STMIA R11,{R0-R2} ;Save that on the stack ; --- Set the dash pattern length --- MOV R0,#163 ;Write general graphics info MOV R1,#242 ;Set dash pattern length MOV R2,#8 ;Set the repeat length SWI OS_Byte ;Set the length then ; --- Now set the dash pattern itself --- MOV R0,R11 ;Point to my VDU block MOV R1,#10 ;Size of block in bytes SWI OS_WriteN ;Write that to the VDU things LDMFD R13!,{R0-R2,PC}^ ;And return to caller LTORG ; --- drag__idles --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Handles idle events during a drag operation. drag__idles ROUT STMFD R13!,{R0-R7,R14} ;Save some registers ; --- Check for a cancelled drag --- MOV R0,#intk_Esc ;Get the Escape kep code BL akbd_test ;Test the key BCS %70drag__idles ;Cancelled -- abort it then ; --- Update the dash pattern --- SWI OS_ReadMonotonicTime ;Read the current time LDR R14,drag__lastTime ;Load the old time nicely SUB R0,R0,R14 ;Find the difference MOV R0,R0,LSR #2 ;Divide by 4 ADD R14,R14,R0,LSL #2 ;Add on rounded value STR R14,drag__lastTime ;Save that back LDRB R14,drag__dash ;Load the dash position STRB R14,drag__oldDash ;This is now the old one MOV R0,R0,LSL #1 ;Multiply difference by 2 MOV R0,R14,ROR R0 ;Rotate the dash pattern ORR R0,R0,R0,ROR #24 ;Fake an 8-bit rotate ORR R0,R0,R0,ROR #16 ;Make sure it's done properly STRB R0,drag__dash ;This is the new pattern ; --- Read the new position --- SUB R13,R13,#44 ;Make a window state block LDR R14,drag__window ;Load the window handle out STR R14,[R13,#0] ;Store handle in there MOV R1,R13 ;Point to the block SWI Wimp_GetWindowState ;Read the window information BL drag__find ;Find the new position BL drag__getPosition ;Do any exra processing reqd BCC %50drag__idles ;If done, skip onwards ; --- Work out what needs to be done --- ADR R14,drag__currPos ;Find the current position LDMIA R14,{R2,R3} ;Load that out CMP R2,R4 ;Has the drag box moved? CMPEQ R3,R5 ;Check both coordinates BEQ %30drag__idles ;No -- handle speciallt ; --- Force the update of the drag box --- LDRB R0,drag__oldDash ;Get the old dash pattern BL drag_setDash ;Set this as the pattern MOV R0,#drEvent_undraw ;Tell client to undraw BL drag__draw ;Go and do that then ; --- Now draw the new one --- ADR R14,drag__currPos ;Find the current position STMIA R14,{R4,R5} ;Save new position in there LDRB R0,drag__dash ;Load the new dash pattern BL drag_setDash ;Set this as the pattern MOV R0,#drEvent_draw ;Tell client to draw BL drag__draw ;Go and do that then B %90drag__idles ;Now go and tidy up ; --- Update the drag box in place --- 30drag__idles LDR R14,drag__flags ;Load any interesting flags TST R14,#drFlag_noUpdate ;Do we send update events? BNE %90drag__idles ;No -- then do nothing LDR R0,drag__oldDash ;Load the two dash patterns EOR R0,R0,R0,LSR #8 ;Exclusive OR them together BL drag_setDash ;Set this as the pattern MOV R0,#drEvent_update ;Tell client to update drag BL drag__draw ;Go and do that then B %90drag__idles ;Now go and tidy up ; --- Tidy up at the end of the drag --- 50drag__idles LDRB R0,drag__oldDash ;Get the old dash pattern BL drag_setDash ;Set this as the pattern MOV R0,#drEvent_undraw ;Now remove the drag box BL drag__draw ;Go and do that then ADR R14,drag__startPos ;Point to start position LDMIA R14,{R2-R5} ;Load all that lot MOV R0,#drEvent_done ;Say it's all over BL drag__dispatch ;Send that to the user ; --- Remove this idle handler --- MOV R0,#0 ;We're called very often ADR R1,drag__idles ;Point to the handler MOV R2,#0 ;Passed nothing in R10 MOV R3,R12 ;Passed workspace in R12 BL idle_removeHandler ;Remove the handler MOV R14,#0 ;A convenient zero STR R14,drag__window ;Clear the window handle B %90drag__idles ;Now go and tidy up ; --- Cancel the drag --- 70drag__idles BL drag_cancel ;Cancel the drag B %95drag__idles ;Now go and tidy up ; --- Now tidy up and go home --- 90drag__idles ADD R13,R13,#44 ;Recover any lost stack space 95drag__idles LDMFD R13!,{R0-R7,PC}^ ;And return to caller LTORG ; --- drag_cancel --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Cancels the current drag operation. EXPORT drag_cancel drag_cancel ROUT STMFD R13!,{R0-R3,R12,R14} ;Save some registers WSPACE drag__wSpace ;Find my workspace ; --- Make sure this is worth it --- LDR R14,drag__window ;Load current drag window CMP R14,#0 ;Is it defined? LDMEQFD R13!,{R0-R3,R12,PC}^ ;No -- then do nothing ; --- Undraw the drag box --- SUB R13,R13,#44 ;Drop the stack by a bit LDR R14,drag__window ;Load the window handle out STR R14,[R13,#0] ;Store handle in there MOV R1,R13 ;Point to the block SWI Wimp_GetWindowState ;Read the window information LDR R0,drag__dash ;Load the current dash pos BL drag_setDash ;Set the dash pattern MOV R0,#drEvent_undraw ;Undraw the drag box BL drag__draw ;Go and do that then MOV R0,#drEvent_cancel ;Say the drag was cancelled BL drag__dispatch ;Inform the client of this ; --- Now tidy up and return --- MOV R0,#0 ;We're called very often ADR R1,drag__idles ;Point to the handler MOV R2,#0 ;Passed nothing in R10 MOV R3,R12 ;Passed workspace in R12 BL idle_removeHandler ;Remove the handler MOV R14,#0 ;A convenient zero STR R14,drag__window ;Clear the window handle ADD R13,R13,#44 ;Restore the stack pointer LDMFD R13!,{R0-R3,R12,PC}^ ;And return to caller LTORG ; --- drag_redraw --- ; ; On entry: R1 == pointer to redraw block ; ; On exit: -- ; ; Use: Redraws the drag box, if the redraw takes place in the ; currently dragging window. EXPORT drag_redraw drag_redraw ROUT STMFD R13!,{R0-R7,R12,R14} ;Save some registers WSPACE drag__wSpace ;Find the workspace address ; --- Make sure there's something to do --- LDR R0,[R1,#0] ;Load the window handle LDR R14,drag__window ;Load current drag window CMP R0,R14 ;Do these match up? LDMNEFD R13!,{R0-R7,R12,PC}^ ;No -- do nothing then ; --- Set up registers --- LDR R2,[R1,#4] ;Load left hand side ADD R14,R1,#16 ;Find top and scroll LDMIA R14,{R5-R7} ;Load that lot out SUB R6,R2,R6 ;Find the x origin pos SUB R7,R5,R7 ;And the y origin pos ADR R14,drag__startPos ;Find the start position LDMIA R14,{R2-R5} ;Load position out nicely ; --- Now do the drawing --- LDRB R0,drag__dash ;Load current dash pattern BL drag_setDash ;Set the dash pattern MOV R0,#drEvent_draw ;Now do some drawing BL drag__dispatch ;Send to event handler LDMFD R13!,{R0-R7,R12,PC}^ ;Now return to caller LTORG ; --- drag_eorColour --- ; ; On entry: R0 == colour A ; R1 == colour B ; ; On exit: -- ; ; Use: Sets the foreground colour to be an EOR colour such that ; when painted over Wimp colour A, it appears as Wimp colour B. EXPORT drag_eorColour drag_eorColour ROUT STMFD R13!,{R0-R3,R14} ;Save some registers MOV R2,R0,LSL #2 ;Keep the background colour MOV R3,R1,LSL #2 ;And the foreground colour MOV R1,R11 ;Point to the block SWI Wimp_ReadPalette ;Read the current palette LDR R0,[R11,R2] ;Load the fore palette entry SWI ColourTrans_ReturnColourNumber MOV R2,R0 ;Save the colour number LDR R0,[R11,R3] ;Load the back palette entry SWI ColourTrans_ReturnColourNumber EOR R1,R0,R2 ;Get the EOR colour number MOV R0,#3 ;Set EOR colour please SWI XOS_SetColour ;Set the colour, please BVC %90drag_eorColour ;If it worked, return ; --- We must be running RISC OS 2 --- ; ; This is very tedious -- we have to set the colour by hand. BL screen_getInfo ;Read the screen cache LDR R0,[R0,#screen_bpp] ;Load the current BPP CMP R0,#8 ;Are we in a 256 colour mode? BEQ %50drag_eorColour ;Yes -- handle it specially ; --- Just set the GCOL from R1 --- SWI OS_WriteI+18 ;Set graphics colour SWI OS_WriteI+3 ;Use XOR colour MOV R0,R1 ;Get the colour to set SWI OS_WriteC ;Set the colour B %90drag_eorColour ;Return -- we did it ; --- Set the colour in a 256 colour mode --- 50 MOV R0,R1 ;Get colour in R0 SWI ColourTrans_ColourNumberToGCOL MOV R1,R0 ;Keep the GCOL safe SWI OS_WriteI+18 ;Set graphics colour SWI OS_WriteI+3 ;Use XOR colour MOV R0,R1,LSR #2 ;Get the GCOL part of it SWI OS_WriteC ;Set the colour ; --- Now set the tint --- MOV R0,#23 ;VDU code for tint setting ORR R0,R0,#17<<8 ;Subreason code for tint ORR R0,R0,#2<<16 ;Set the graphics foreground ORR R0,R0,R1,LSL #30 ;Get the tint bits in too MOV R1,#0 ;Other bytes are all 0 MOV R2,#0 ;Two words of them STMIA R11,{R0-R2} ;Save them in scratchpad MOV R0,R11 ;Point at them MOV R1,#10 ;VDU 23 is 10 bytes long SWI OS_WriteN ;Write the whole lot out 90 LDMFD R13!,{R0-R3,PC}^ LTORG drag__wSpace DCD 0 ;----- Flags ---------------------------------------------------------------- drFlag_noUpdate EQU (1<<0) ;Don't generate update events ;----- Drag handler events -------------------------------------------------- ; --- Note --- ; ; The events which request that you draw something are called for each ; rectangle of the draw operation -- i.e. do not call Wimp_GetRectangle ; because this is done for you. ^ 0 drEvent_draw # 1 ;Draw dragged object ;R1 == pointer to redraw blk ;R2,R3 == drag start posn ;R4,R5 == drag current posn ;R6,R7 == window origin ;Dash pattern set up drEvent_undraw # 1 ;Undraw dragged object ;Regs as for drEvent_draw ;Normally use the same code drEvent_update # 1 ;Redraw dragged object in ;place ;Regs as for drEvent_draw ;Dash pattern set up so that ;single plot will rotate box, ;so may share code with ;drEvent_draw drEvent_trans # 1 ;Translate coordinates ;R1 == ptr to window state ;R4,R5 == pointer position ;R6,R7 == window origin ;Translate pointer position ;to internal coordinates if ;this is useful to you. ;Return new coords in R4,R5 drEvent_getPos # 1 ;Read pointer position ;R1 == ptr to window state ;R2,R3 == start position ;R4,R5 == pointer position ;R6,R7 == window origin ;Used to read pointer posn. ;Do any grid snapping here ;and return with R4,R5 as ;coords to use. drEvent_done # 1 ;Drag operation completed ;R1 == ptr to window state ;R2,R3 == drag start posn ;R4,R5 == drag current posn drEvent_cancel # 1 ;Drag operation aborted ;No other registers set up ;----- Workspace ------------------------------------------------------------ ^ 0,R12 drag__wStart # 0 drag__window # 4 ;Window handle of drag drag__flags # 4 ;Various interesting flags drag__handler # 16 ;All the handler information drag__oldDash # 1 ;The old dash pattern drag__dash # 1 ;The current dash pattern # 2 ;Align to word boundary drag__lastTime # 4 ;Last time we changed pattern drag__startPos # 8 ;Find the start position drag__currPos # 8 ;Find the end position drag__wSize EQU {VAR}-drag__wStart AREA |Sapphire$$LibData|,CODE,READONLY DCD drag__wSize DCD drag__wSpace DCD 0 DCD 0 ;----- That's all, folks ---------------------------------------------------- END