CnPCaret 35.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
; Copyright 2019 RISC OS Open 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.CnPCaret

 [ CnP
; In: R0 = window handle
;     R1 = icon handle
;     R2 = X offset relative to window origin
;     R3 = Y offset relative to window origin
;     R4 = caret height/flags
;     R5 = string index
; [+  R6 = maximum selection index]
;We are given x,y coords relative to window work area origin

; remove existing caret or selection or whatever first, depending on how we're called

int_set_caret_position ROUT
        Push    "R0-R6,R11,R14"

ROOL's avatar
ROOL committed
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
        ; if we're called with R5=-1 then R4,R5 are calculated from R0-R3
        ; however, R4 is undefined on entry so could be anything.
        ; Internally we'd like to be able to use the call to put a ghost caret
        ; to a mouse click...
        ; we're doing the call by a SWI now, so need a way to get ghost caret calculations
        ; add R5=-2 for this purpose - calculate ghost caret details from x/y coords
        ; R4 *must* now be a valid flag set
        CMP     R5,#-1
        BNE     %FT00
        CMP     R1,#-1
        MOVNE   R4,#-1                 ; R4 now is -1 (ie no flags)
00
        CMP     R5,#-2
        MOVEQ   R5,#-1

        ; validate existing caret blocks
        LDR     handle,caretdata
        CMP     handle,#nullptr
        BLNE    checkhandle
        MOVVS   handle,#nullptr
        STRVS   handle,caretdata

        LDR     handle,ghostcaretdata
        CMP     handle,#nullptr
        BLNE    checkhandle
        MOVVS   handle,#nullptr
        STRVS   handle,ghostcaretdata

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
        LDR     R14,taskhandle          ; calling task
        Push    "R14"                   ; preserve for later

        CMP     R4,#-2
        MOVEQ   R4,#-1                  ; workaround bug in Filer 1.96-2.45 which calls with R4=-2 instead of -1

        LDR     R14,dragtype            ; is there currently an icon selection drag?
        TEQ     R14,#drag_icon_selection
        BNE     %FT00

        ; are we moving the main caret?  If not, doesn't matter
        CMP     R4,#-1                  ; R4=-1 implies main caret
        TSTNE   R4,#crf_ghostcaret :OR: crf_selection
        BNE     %FT00

        ; if so, then we need to see if we're relocating outside the icon
        ; if we are, then the drag should be cancelled

        LDR     R14,caretdata+caretwindow
        TEQ     R0,R14
        LDREQ   R14,caretdata+careticon
        TEQEQ   R1,R14
        BEQ     %FT00                   ; same window/icon so continue unchanged

        ; we need to stop the drag before proceeding
        Push    "R0,x0,y0,x1,y1"

        LDR     R0,caretdata+caretwindow
        Abs     handle,R0
        MOV     R14,#0
        STR     R14,dragtype
        MOV     R14,#bignum
        STR     R14,[handle,#w_seldata+wselxoverride]

        BL      clearpointerwindow      ; corrupts x0,y0,x1,y1

        BL      iconautoscroll_stop
        Pull    "R0,x0,y0,x1,y1"
00
99 100
        AcceptLoosePointer_NegOrZero R0,nullptr
        CMP     R0,R0,ASR #31
101 102 103 104
        BEQ     %FT07                   ; we know this one's not valid
        MOV     handle,R0
        BL      checkhandle             ; valid window handle?
        BVC     %FT01
ROOL's avatar
ROOL committed
105
        BVS     %FT08                   ; destination isn't valid, so just remove the caret
106 107 108 109 110
07
        ; if we've been called with r0=-1 then we may need to add some flags...
        LDR     R14,taskidentifier1     ; 'TASK'
        CMP     R2,R14                  ; is R2 'TASK'
        MOVNE   R4,#0                   ; if we're called with TASK then R4 has correct flags.  If not, we need
111
                                        ; to make sure we have some valid flags
112
        MOVEQ   R2,#0                   ; if we were called with R2='TASK' then
ROOL's avatar
ROOL committed
113 114 115 116 117 118
        STREQ   R2,[sp,#(2+1+8)*4]      ; ensure R2=0 on return - taskhandle stacked below r2
08
        SavePSR R6                      ; keep V flag for exiting later
        Push    "R6"
        STR     R0,[sp,#8]              ; preserve error message
        MOV     R0,#-1                  ; carry on as an invalid window handle
119 120 121 122 123

        BL      wscp_remove_current_caret ; remove the caret, queue redraw as necessary

        ; need to clear the appropriate data blocks
        MOV     R14,#nullptr
ROOL's avatar
ROOL committed
124 125
        CMP     R4,#-1
        TSTNE   R4,#crf_ghostcaret :OR: crf_selection   ; normal caret?
126
        STREQ   R14,caretdata
ROOL's avatar
ROOL committed
127
        BEQ     exitsetcaret_abort
128 129 130

        TST     R4,#crf_ghostcaret                      ; ghost caret?
        STRNE   R14,ghostcaretdata
ROOL's avatar
ROOL committed
131
        BNE     exitsetcaret_abort
132 133

        TST     R4,#crf_selection                       ; unshaded selection?
ROOL's avatar
ROOL committed
134
        BEQ     exitsetcaret_abort
135 136 137

        LDR     R11,selectionwindow
        CMP     R11,#nullptr
ROOL's avatar
ROOL committed
138
        BEQ     exitsetcaret_abort
139 140 141 142 143 144

        BL      clipboard_check_current_drag_op ; stop drag op if selection has been terminated

        Abs     R11,R11
        STR     R14,[R11,#w_seldata]                    ; update if handle is valid
        STR     R14,selectionwindow                     ; current selection window is now invalid too
ROOL's avatar
ROOL committed
145
        B       exitsetcaret_abort
146 147 148
01
        ; continues - r0 is a confirmed valid window handle

ROOL's avatar
ROOL committed
149 150 151 152 153 154 155
        ; is the window currently open and able to receive a focus?
        Push    "R1,R10"
        MOV     R1,#-1
        BL      setfocus
        Pull    "R1,R10"
        BVS     %BT08                                   ; no - abort and clear caret
02
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
        ; set up the hascaret etc. blocks for the current state of the icon before gaining caret
        LDR     R14,caretdata
        EORS    R14,R14,R0
        LDREQ   R14,caretdata+careticon
        EOREQ   R14,R14,R1
        STR     R14,hascaret

        LDR     R14,ghostcaretdata
        EORS    R14,R14,R0
        LDREQ   R14,ghostcaretdata+ghostcareticon
        EOREQ   R14,R14,R1
        STR     R14,hasghostcaret

        LDR     R14,[handle,#w_seldata]
        EOR     R14,R14,R1
        STR     R14,hasselection

        ; work out which block we're playing with - main or ghost caret
        CMP     R4,#-1
        TSTNE   R4,#crf_selection           ; are we doing a selection caret?  Different data blocks if we are.
        BNE     %FT40

        CMP     R4,#-1                      ; which caret block do we need?
        TSTNE   R4,#crf_ghostcaret
        ADREQL  R11,caretdata
        ADRNEL  R11,ghostcaretdata
        LDR     R14,[R11]
        STR     R14,oldcaretwindow

        BL      wscp_remove_current_caret
        ; was it OK?
        MOVVS   R14,#nullptr
        STRVS   R13,[R11]
        STRVS   R0,[sp,#4]                  ; taskhandle stacked first
        BVS     exitsetcaret                ; mark this caret as invalid and exit

        ; are we setting caret to an icon or just the work area?
        CMP     R1,#0
        BLT     wscp_workarea

        ; we're placing in an icon
        ; we either use string offset or the coords supplied

        ; is the icon handle valid?
        LDR     R14,[handle,#w_nicons]
        CMP     R1,R14                      ; icon handle out of range?
        BGT     exitsetcaret                ; abort if so

        LDR     R14,[handle,#w_taskhandle]
        Task    R14,,"SetCaret"             ; page in window owner task
        ; check string offsets to ensure valid (ie within string itself)
        CMP     R5,#0
        BLPL    wscp_make_offsets_valid

        ; sort checksum for the string if need to
        CMP     R4,#0
        ADRMIL  R14,caretx                  ; no flags in this situation, assume normal caret
        STRMI   R14,caretx_dest
        BMI     %FT18
        TST     R4,#crf_ghostcaret
        ADREQL  R14,caretx
        ADRNEL  R14,ghostcaretx
        STR     R14,caretx_dest             ; determine whose caretx gets set
        BEQ     %FT17

        Push    "R0,R11"
        LDR     R11,[handle,#w_icons]
        ADD     R11,R11,R1,LSL #i_shift     ; get icon address
        BL      writable_calc_checksum
        STR     R0,ghostcaretchecksum
        Pull    "R0,R11"
17
;        CMP     R4,#0
;        BMI     %FT18
        CMP     R5,#0
        BMI     %FT18

        Push    "R4"
        BL      setcaretcoords          ; recompute.  We may want to keep the height after
        BIC     R14,R4,#&ff000000
        BIC     R14,R14,#&ff0000
        Pull    "R4"
        BIC     R4,R4,#&ff
        BIC     R4,R4,#&ff00
        ORR     R4,R4,R14               ; merge height and flags
18
        CMP     R5,#0                   ; if R5<0 then R4,R5 <-- R0,R1,R2,R3
        BGE     %FT99

        Push    "R0,R1,R4"
        CMP     R2,#&10000
        MOVGT   R2,#&10000
        CMP     R3,#&10000
        MOVGT   R3,#&10000
        BL      findcaret               ; get R4,R5. We'll add the flags back in now.
        BIC     R14,R4,#&ff000000
        BIC     R14,R14,#&ff0000        ; remove flags (if any)
        Pull    "R0,R1,R4"
        CMP     R4,#-1
        MOVEQ   R4,R14
        BICNE   R4,R4,#&ff
        BICNE   R4,R4,#&ff00            ; remove old caret height
        ORRNE   R4,R4,R14               ; merge in new caret height, keeping flags
99
        CMP     R4,#-1                  ; if R4<0 then R2,R3,R4 <-- R0,R1,R5
        MOVEQ   R4,#0                   ; fix up flags for the call
        BLEQ    setcaretcoords

        TST     R4,#crf_ghostcaret
        ADREQL  R11,caretdata
        BEQ     %FT98

        ; override scrollx position?
        TST     R4,#crf_nocentre
        MOVEQ   R6,#bignum
        BEQ     %FT96

        ; if we were called with R5=-2, then new scrollx is in original R3, else it is in R2
        LDR     R6,[sp,#5*4]            ; get R5 from stack
        CMP     R6,#-2
        LDREQ   R6,[sp,#3*4]            ; get R3 from stack if R5 was -2
        LDRNE   R6,[sp,#2*4]            ; get R2 from stack otherwise
96
        ; if ghost caret is on top of a selection, hide the ghost caret
        LDR     R14,[handle,#w_seldata+wselicon]
        CMP     R14,#nullptr
        BEQ     %FT97                   ; no selection
        CMP     R14,R1
        BNE     %FT97                   ; different icon, so no need to check
        LDR     R14,[handle,#w_seldata+wsellowindex] ; low bound of selection
        CMP     R14,R5
        BGT     %FT97                   ; we're left of low bound
        LDR     R14,[handle,#w_seldata+wselhighindex] ; high bound
        CMP     R14,R5
        ORRGE   R4,R4,#crf_invisible    ; we're in selection zone, so hide caret
97
        ADRL    R11,ghostcaretdata
        STMIA   R11,{R0-R5}
        ; we've set/adjusted a ghost caret.
        ; was there a main caret in the same icon?
        ; if so, we'll need to recalculate its position
        BL      refreshcaret_ghost_main
        B       %FT20
98
        STMIA   R11,{R0-R5}             ; processed values
        ; ** no r6 for scrollx now

;        BL      check_shaded_selection_window

        ; focus on?
        LDR     R14,oldcaretwindow

        CMP     R0,R14
        BEQ     %FT20                   ; same window, no repeat messages
        BL      check_shaded_selection_window
        BL      send_gaincaret
        BL      focuson
ROOL's avatar
ROOL committed
313 314 315
        MOVVS   R14,#nullptr
        STRVS   R14,[R11]
        BVS     exitsetcaret
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
20
        ; redraw the target icon
        Push    "R0-R2"
        LDR     handle,[R11,#0]
        Abs     handle,handle           ; window handle of current caret
        LDR     R0,[R11,#4]             ; icon handle of current caret
        MOV     R1,#0
        MOV     R2,#0

        BL      int_set_icon_state
        Pull    "R0-R2"
        B       exitsetcaret

wscp_workarea
        ; setting a caret (ghost or main) to the window work area
        ; no need to calculate string offsets etc
        ; just place the caret and leave
        BL      upcaret
ROOL's avatar
ROOL committed
334
        BVS     %FT22
335 336

        ; upcaret corrupts R11
ROOL's avatar
ROOL committed
337 338
        CMP     R4,#-1
        TSTNE   R4,#crf_ghostcaret
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
        ADREQL  R11,caretdata
        ADRNEL  R11,ghostcaretdata

        ; update stored data block
        STMIA   R11,{R0-R5}
        TST     R4,#crf_ghostcaret      ; if we're a ghost caret we don't do messages
        BNE     %FT21

        LDR     R14,oldcaretwindow
        CMP     R0,R14
        BEQ     %FT21                   ; same window, no repeat messages
        BL      send_gaincaret
        BL      check_shaded_selection_window
        BL      focuson
21
        MOVVS   R14,#nullptr            ; if not successful, clear the caret block
        STRVS   R14,[R11,#0]
        B       exitsetcaret
ROOL's avatar
ROOL committed
357 358 359 360 361 362 363 364
22
        MOV     R14,#nullptr
        CMP     R4,#-1
        TSTNE   R4,#crf_ghostcaret
        ADREQL  R11,caretdata           ; upcaret may corrupt R11
        ADRNEL  R11,ghostcaretdata
        STR     R14,[R11,#0]
        B       exitsetcaret
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
40
        ; we are updating a selection caret
        BL      wscp_remove_current_caret
        BVS     %FT49

        ; need to sort out the positions of the start and end indices
        CMP     R5,R6
        BGT     exitsetcaret            ; invalid range, so abort
41
        ; is the icon handle valid?
        LDR     R14,[handle,#w_nicons]
        CMP     R1,R14                  ; icon handle out of range?
        Pull    "R0-R6,R11,R14",HS      ; abort if so
        BHS     exitsetcaret

        LDR     R14,[handle,#w_taskhandle]
        Task    R14,,"SetCaret"         ; page in window owner task

        BL      wscp_make_offsets_valid ; ensure R5,R6 within string bounds

        Rel     R11,handle
        BL      clipboard_check_current_drag_op ; if we're messing with a drag selection, abort the drag

        CMP     R5,R6                   ; if we're the same, we need to remove the selection
        BNE     %FT41

        ; r5=r6, so remove the selection for now
        LDR     R11,[handle,#w_seldata+wselicon] ; keep icon handle for later...
        MOV     R14,#nullptr
        STR     R14,[handle,#w_seldata+wselicon]
        ; was the selection the selection window?  If so, remove that
        LDR     R0,selectionwindow
        Abs     R0,R0
        TEQ     R0,handle
        STREQ   R14,selectionwindow

        ; do we need to recalculate the normal caret?
        LDR     R1,caretdata
        Abs     R1,R1
        EOR     R1,R1,handle
        LDR     R2,caretdata+careticon
        EOR     R1,R1,R2
        EORS    R1,R1,R11
        BLEQ    refreshcaret_main       ; it's the same icon

        MOV     R0,R11
        MOV     R1,#0
        MOV     R2,#0
        BL      int_set_icon_state
        B       exitsetcaret
41
        Push    "R0,R11"
        LDR     R11,[handle,#w_icons]
        ADD     R11,R11,R1,LSL #i_shift   ; icon address
        BL      writable_calc_checksum
        STR     R0,[handle,#w_seldata+wselchecksum]    ; store checksum
        Pull    "R0,R11"

        STR     R1,[handle,#w_seldata+wselicon] ; store icon handle
        STR     R5,[handle,#w_seldata+wsellowindex] ; store start offset
        STR     R6,[handle,#w_seldata+wselhighindex] ; store end offset

        Push    "R2"                    ; we may need this later...

        ; start index
        ; convert to X coord and also obtain height
        ; we lose flags from R4... preserve these

        MOV     R11,R4
        ADD     R14,handle,#w_seldata+wselxoff
        STR     R14,caretx_dest
        BL      setcaretcoords
        ; sets r2,r3
        ; keep r2,r3
        ;str r2,[handle,#w_seldata+wselxoff]
        STR     R3,[handle,#w_seldata+wselyoff]
        ; keep flags but add in the caret height part
        BIC     R11,R11,#&ff00
        BIC     R11,R11,#&00ff
        ORR     R4,R11,R4
        STR     R4,[handle,#w_seldata+wselflags] ; store flags in w_seldata

        ; do the end index
        LDR     R5,[handle,#w_seldata+wselhighindex]  ; get end index as R6 has been corrupted
        ADD     R14,handle,#w_seldata+wselwidth
        STR     R14,caretx_dest
        BL      setcaretcoords

        LDR     R14,[handle,#w_seldata+wselwidth]
        LDR     R2,[handle,#w_seldata+wselxoff]
        SUB     R14,R14,R2
        STR     R14,[handle,#w_seldata+wselwidth] ; make a width

        ; do we want to override the scrollx with a user value?
        Pull    "R2"
        LDR     R4,[sp,#(4+1)*4]        ; get original R4 from entry to see if we have crf_nocentre

        TST     R4,#crf_nocentre
        MOVEQ   R2,#bignum

        STR     R2,[handle,#w_seldata+wselxoverride] ; store scrollx directly
        ; does this window also have the current input focus?
        ; if not, then we need to transfer that too
        LDR     R14,caretdata
        Abs     R14,R14
        TEQ     handle,R14

        MOVNE   R14,#2
        STRNE   R14,refreshmaincaret           ; refresh main caret by moving it to selection spot

        ; redraw the icon to reflect changes
        Rel     R14,handle
        STR     R14,selectionwindow
        LDR     R0,[handle,#w_seldata+wselicon]
        MOV     R1,#0
        MOV     R2,#0
        BL      int_set_icon_state
        B       exitsetcaret
49
        ; failed to set caret
        ; clean selection block and exit
        MOV     R14,#nullptr
        STR     R14,selectionwindow
        STR     R14,[handle,#w_seldata+wselicon]
        ; fall through...

exitsetcaret
ROOL's avatar
ROOL committed
492 493 494
        SavePSR R6
        Push    "R6"
exitsetcaret_abort
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
        CheckAllWindows "int_set_caret_position (after)"

        ; do we need to recalculate the main caret?
        LDR     R14,refreshmaincaret
        TEQ     R14,#1
        BLEQ    refreshcaret_main
00
        ; redraw anything queued
        LDR     R10,redrawcaretwindow
        CMP     R10,#nullptr
        LDRNE   R0,redrawcareticon
        CMPNE   R0,#nullptr
        Abs     R10,R10,NE
        MOVNE   R1,#0
        MOVNE   R2,#0
        BLNE    int_set_icon_state

        ; and return
ROOL's avatar
ROOL committed
513
        Pull    "R6"                    ; get saved PSR
514 515 516 517 518 519
        Pull    "R14"                   ; taskhandle is remembered
        Task    R14,,"Restoring after SetCaret"

        ; did we need to move input focus to match the selection?
        LDR     R14,refreshmaincaret
        TEQ     R14,#2
ROOL's avatar
ROOL committed
520 521 522 523
        BEQ     %FT01
        RestPSR R6
        Pull    "R0-R6,R11,PC"          ; no, continue as normal by exiting
01
524 525 526 527 528 529 530 531 532 533 534
        ; yes.  We've finished our things, so we can re-call set_caret_position to set the input focus.
        ; that way losefocus/gainfocus messages etc will be sent properly and so on

        ; input focus goes to end point of selection, so
        LDMFD   R13,{R0-R6,R11}

        MOV     R5,R6                   ; index into string is now the end point
        BIC     R4,R4,#crf_selection :OR: crf_nocentre ; was selection, but make it the main caret
        ; everything else can stay the same
        BL      int_set_caret_position  ; back round again for another go

ROOL's avatar
ROOL committed
535
        RestPSR R6
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
        Pull    "R0-R6,R11,PC"          ; finally quit

wscp_remove_current_caret ROUT
; on entry, r0=window handle or -1
;           r1=icon handle if r0!=-1
;           r4=flags

        Push    "R0-R5,R10,R11,R14"

        ; clear redraw block
        MOV     R14,#nullptr
        STR     R14,redrawcaretwindow
        STR     R14,redrawcareticon

        MOV     R14,#0
        STR     R14,refreshmaincaret

        ; have we changed to a different window for the main caret?
        CMP     R4,#-1                  ; invalid flags? assume main caret
        BEQ     %FT00

        TST     R4,#crf_selection :OR: crf_ghostcaret
        BNE     %FT01

00      ; we are dealing with the main caret, so do the check
        LDR     R14,caretdata
        CMP     R0,R14
        BEQ     %FT01
        Push    "R0"
        MOV     R0,R14
        BL      focusoff                ; preserves flags
        BL      send_losecaret
        BL      check_unshaded_selection_window
        Pull    "R0"
01
        ; continue.
        ; need to pull a caret or a selection...
        CMP     R4,#-1                  ; invalid flags
        BEQ     %FT02
        TST     R4,#crf_selection
        BNE     wscp_rcc_selection_redraw
02
        ; we are removing one of the carets
        ; is it an icon?  If so, then the caret will be obliterated and redrawn in the new writeable icon redraw code
        ; so we can just request a redraw of the initial icon if it's different at this point

        ; work out which block we're playing with - main or ghost caret
        CMP     R4,#-1
        TSTNE   R4,#crf_ghostcaret
        ADREQL  R11,caretdata
        BEQ     %FT03

        ; ghost caret is on the move
        ADRL    R11,ghostcaretdata
        ; if current ghost caret is same as current main caret, we'll need to refresh the main caret
        LDR     R0,caretdata
        LDR     R1,caretdata+careticon
        LDR     R2,ghostcaretdata
        LDR     R3,ghostcaretdata+ghostcareticon
        EOR     R14,R0,R1
        EOR     R14,R14,R2
        EORS    R14,R14,R3
        MOVEQ   R14,#1
        MOVNE   R14,#0
        STR     R14,refreshmaincaret    ; set up redraw on exit...
03
        ; is there a previous window in use?
        ; if not, we can bail out
        LDR     R0,[R11,#0]             ; get window handle for current caret
        CMP     R0,#nullptr
        Pull    "R0-R5,R10,R11,PC",EQ

        ; is there a previous icon?
        LDR     R14,[R11,#4]            ; get icon handle for current caret
        CMP     R14,#0
        BGE     wscp_rcc_queue_redraw
        ; request screen redraw for that area - this will remove the old caret by EOR
        LDMIA   R11,{R0-R4}             ; get previous caret state
        BL      upcaret

        Pull    "R0-R5,R10,R11,PC"

wscp_rcc_selection_redraw
        ; if main caret present, it will need refreshing...
        LDR     R5,caretdata
        LDR     R14,selectionwindow
        TEQ     R14,R5
        BNE     %FT60

        LDR     R5,caretdata+careticon
        LDR     R14,[handle,#w_seldata+wselicon]
        TEQ     R5,R14
        MOVEQ   R14,#1
        STREQ   R14,refreshmaincaret    ; main caret will be in the selection
60
        LDR     R10,selectionwindow
        CMP     R10,#nullptr
        BEQ     %FT91                   ; no unshaded selection window, so skip next bit

        CMP     R10,R0
        BEQ     %FT91                   ; moving within the same window

        Abs     R10,R10
        LDR     R14,[handle,#w_seldata+wselicon]  ; icon handle for redraw - current selection

        MOV     R5,#nullptr
        STR     R5,selectionwindow      ; clear current unshaded selection window
        MOV     R0,R14
        MOV     R1,#0
        MOV     R2,#0
        BL      int_set_icon_state      ; redraw that icon to make it shaded

        Pull    "R0-R5,R10,R11,PC"
91
        ; new window becomes the unshaded selection as it will also gain the input focus
        ; we may have things to do to any other selection in the new window
        ; retrieve window handle for the destination
        Pull    "R0"
        Abs     R10,R0
        LDR     R14,[handle,#w_seldata]
        CMP     R14,R1                  ; moving to a new icon?
        Pull    "R1-R5,R10,R11,PC",EQ   ; no, same as before.  So no need to redraw (we'll get redrawn later)
        STR     R0,redrawcaretwindow    ; queue window/icon for redraw
        STR     R14,redrawcareticon
        Pull    "R1-R5,R10,R11,PC"

wscp_rcc_queue_redraw
        ; r11=pointer to window handle (ie caret data block or similar)
        ; r14=icon handle from the current caret state
        LDR     R11,[R11]               ; get the window handle itself
        CMP     R10,R11                 ; new window is the same as old?
        BNE     %FT02                   ; redraw regardless

        CMP     R14,R1                  ; different icon?
        ; if the same, then we rely on the icon redraw to follow when we set the updated caret position...
        Pull    "R0-R5,R10,R11,PC",EQ
02
        ; it's a different icon, so we redraw the one we're leaving
        STR     R11,redrawcaretwindow
        STR     R14,redrawcareticon
        Pull    "R0-R5,R10,R11,PC"

wscp_make_offsets_valid
        Push    "R7,R14"

        ; if R5<=0, then don't need to alter this one
        CMP     R5,#0
        BLE     %FT03

        ; clamp R5 to string length
        MOV     R7,R5
        BL      wscp_clamp_length
        MOV     R5,R7
03
        ; do we need to adjust R6 too?
        TST     R4,#crf_selection
        Pull    "R7,PC",EQ              ; no, exit

        CMP     R5,#0
        MOVLT   R5,#0                   ; r5<0 is not valid for selections

        CMP     R6,#0
        Pull    "R7,PC",EQ              ; no need to clamp
        MOV     R7,R6
        BL      wscp_clamp_length
        MOV     R6,R7
        Pull    "R7,PC"

wscp_clamp_length
        ; clamp offset to string length
        ; On entry, r7=current offset
        ;            r0=window handle
        ;            r1=icon handle
        ; On exit, r7=clamped offset
        Push    "R8-R10,R14"

        LDR     R14,[handle,#w_nicons]
        CMP     R1,R14
        LDR     R10,[handle,#w_icons]
        ADD     R10,R10,R1,LSL #i_shift ; R10 now points to icon data block
        LDR     R9,[R10,#i_flags]
        TST     R9,#if_indirected
        MOVEQ   R9,#12
        ADDEQ   R8,R10,#i_data
        LDRNE   R9,[R10,#i_data+8]      ; max length
        LDRNE   R8,[R10,#i_data]
        ; r9=maximum string length
        ; r8=pointer to string data

        MOV     R14,#0                  ; current string length
79
        LDRB    R10,[R8,R14]
        CMP     R10,#32
        BLT     %FT80                   ; we have hit the end of the string

        SUBS    R9,R9,#1                ; any more allowed?
        BEQ     %FT80                   ; end of string

        ADD     R14,R14,#1              ; next byte

        CMP     R7,R14                  ; have we matched the caret offset yet?
        BNE     %BT79                   ; no - try again

        Pull    "R8-R10,PC"             ; yes - offset is within string
80
        ; end of string
        ; R7 can't be any greater than this
        MOV     R7,R14
        Pull    "R8-R10,PC"

check_unshaded_selection_window
        ; if the window losing the input focus has a selection, redraw it to ensure it becomes unshaded
        CMP     R0,#nullptr
        MOVEQ   PC,R14
        Push    "R0-R2,R10,R14"
        Abs     R10,R0
        LDR     R14,[handle,#w_seldata+wselicon]
        CMP     R14,#nullptr
        Pull    "R0-R2,R10,PC",EQ       ; nothing to do here

        MOV     R2,#0
        MOV     R1,#0
        MOV     R0,R14
        MOV     R14,#nullptr
        STR     R14,selectionwindow     ; no active selection right now...
        BL      int_set_icon_state

        Pull    "R0-R2,R10,PC"

check_shaded_selection_window
        ; if the window gaining the input focus has a selection, we need to make sure it is redrawn as active
        Push    "R0-R2,R11,R14"

        LDR     R14,[handle,#w_seldata+wselicon] ; selection icon
        CMP     R14,#nullptr
        Pull    "R0-R2,R11,PC",EQ       ; nothing here

        ; we have a selection
        ; update the selectionwindow
        Rel     R11,handle
        STR     R11,selectionwindow

        ; redraw the icon with the selection
        MOV     R2,#0
        MOV     R1,#0
        MOV     R0,R14
        BL      int_set_icon_state

        Pull    "R0-R2,R11,PC"

writable_calc_checksum
        ; calculate checksum on text from an icon
        ; In: r11 is pointer to icon block
        ; Out: r0 is checksum
        Push    "R1-R4,R14"
        ; get max string length
        LDR     R14,[R11,#i_flags]
        TST     R14,#if_indirected
        MOVEQ   R4,#12
        ADDEQ   R1,R11,#i_data
        LDRNE   R4,[R11,#i_data+8]
        LDRNE   R1,[R11,#i_data]

        ; r1 has string pointer
        ; r4 has max length in bytes

        ; get text string length
        MOV     R2,R1
70
        LDRB    R0,[R2],#1
        CMP     R0,#32
        BLT     %FT71

        SUBS    R4,R4,#1
        BNE     %BT70
71
        ; R1 points to start of block
        ; R2 now points to byte after end of block
        ; block potentially includes terminator, but not a problem
        MOV     R0,#0
        MOV     R3,#1
        SWI     XOS_CRC

        Pull    "R1-R4,PC"

; refresh caret states - recalculation of positions and redraw if there are changes
; needed as moving one caret may induce movement of another one.

refreshcaret_main
        Push    "R0-R5,R10,R11,R14"
        ADRL    R11,caretdata
        LDMIA   R11,{R0-R5}
        Abs     handle,R0

        ; make sure the task is paged in for checking
        LDR     R14,[handle,#w_taskhandle]
        Task    R14,,"Refreshcaret_main"

        ADRL    R14,caretx
        STR     R14,caretx_dest
        BL      setcaretcoords

        STR     R2,caretdata+caretxoff          ; update store
        STR     R3,caretdata+caretyoff
        Pull    "R0-R5,R10,R11,PC"

refreshcaret_ghost_main
        ; ghost caret has been updated
        ; if the main caret is in the same icon, it may have moved on screen (though string index unchanged)
        ; on entry, r0-r5 are the caret block as updated (ghost caret data)
        Push    "R14"
        LDR     R14,caretdata
        TEQ     R14,R0
        Pull    "PC",NE

        LDR     R14,caretdata+careticon
        TEQ     R14,R1
        Pull    "PC",NE

        ; same icon.  Do the recalculation.
        ADRL    R11,caretdata
        LDMIA   R11,{R0-R5}

        ADRL    R14,caretx
        STR     R14,caretx_dest
        BL      setcaretcoords

        STR     R2,caretdata+caretxoff          ; update store
        STR     R3,caretdata+caretyoff
        ; no need to redraw as we're redrawing due to ghost caret change already
        MOV     R14,#0
        STR     R14,refreshmaincaret    ; don't need to refresh again if we were planning to

        ; restore settings.
        ADRL    R11,ghostcaretdata
        LDMIA   R11,{R0-R5}
        Pull    "PC"

ghostcaret_checksum_fail
; the checksum failed, so we need to
; * remove ghost caret
; * remove selection if affected too
; * adjust screen coords of main caret if relevant
; Entry: r0=checksum
;        r10=window handle
;        Task already paged in
; Exit: all preserved
        Push    "R0-R1,R14"
        ; if selection is in same icon, it may also be affected
        LDR     R14,ghostcaretdata+ghostcareticon
        LDR     R1,[handle,#w_seldata+wselicon]
        TEQ     R1,R14
        MOV     R14,#nullptr
        BNE     %FT01                   ; not the same icon

        LDR     R1,[handle,#w_seldata+wselchecksum]
        TEQ     R0,R1
        BEQ     %FT01                   ; the checksum is actually valid for the selection, so leave it alone

        STR     R14,[handle,#w_seldata+wselicon] ; clear selection state
        STR     R14,selectioniconaddr

        ; current selection window as well?
        LDR     R0,selectionwindow
        Abs     R0,R0
        TEQ     R0,handle
        STREQ   R14,selectionwindow     ; if so, clear it
01
        ; check against the main caret
        LDR     R0,caretdata
        LDR     R1,ghostcaretdata
        STR     R14,ghostcaretdata      ; we can now reset this bit
        STR     R14,ghostcareticonaddr
        TEQ     R0,R1
        Pull    "R0-R1,PC",NE           ; differs
        LDR     R0,caretdata+careticon
        LDR     R1,ghostcaretdata+ghostcareticon
        TEQ     R0,R1
        Pull    "R0-R1,PC",NE

        ; recalc main caret
        Push    "R2-R11"
        ADRL    R14,caretdata
        LDMIA   R14,{R0-R5}             ; get current caret state
        ADRL    R14,caretx
        STR     R14,caretx_dest
        STR     R14,hasghostcaret       ; not any more

        ; do we still have the selection?
        LDR     R14,[handle,#w_seldata+wselicon]
        TEQ     R14,R1
        MOV     R14,#0
        STREQ   R14,hasselection        ; we have it
        STRNE   handle,hasselection     ; not us
        STR     R14,hascaret            ; still have this one

        BL      setcaretcoords          ; do the recalculation
        STR     R2,caretdata+caretxoff
        STR     R3,caretdata+caretyoff
        Pull    "R2-R11"
        Pull    "R0-R1,PC"

selectioncaret_checksum_fail
; the checksum failed so we need to
; * remove selection box
; * remove ghost caret if in same icon and its checksum is invalid
; * adjust screen coords of main caret if relevant
; Entry: r0=checksum
;        r10=window handle
;        Task already paged in
; Exit: all preserved
        Push    "R0-R1,R14"
        ; ghost caret in same icon?
        LDR     R14,ghostcaretdata
        Abs     R14,R14
        TEQ     R14,R10
        BNE     %FT01                   ; not same window
        LDR     R14,ghostcaretdata+ghostcareticon
        LDR     R1,[handle,#w_seldata]
        TEQ     R1,R14
        BNE     %FT01                   ; not same icon

        ; checksum
        LDR     R1,ghostcaretchecksum
        TEQ     R0,R1
        BEQ     %FT02                   ; checksum is actually valid so we leave the ghost caret alone
        ; note that ghost caret overrides main caret, so we don't recalculate main caret coords

        ; remove ghost caret
        MOV     R14,#nullptr
        STR     R14,ghostcaretdata
        STR     R14,ghostcareticonaddr
01
        LDR     R1,[handle,#w_seldata+wselicon] ; icon
        ; remove selection caret
        MOV     R14,#nullptr
        STR     R14,[handle,#w_seldata+wselicon]
        STR     R14,selectioniconaddr
        LDR     R0,selectionwindow
        Abs     R0,R0
        TEQ     R0,handle
        STREQ   R14,selectionwindow     ; no active selection if it was us

        LDR     R0,caretdata+careticon
        TEQ     R0,R1
        Pull    "R0-R1,PC",NE           ; not same icon

        LDR     R0,caretdata
        Abs     R0,R0
        TEQ     R0,handle
        Pull    "R0-R1,PC",NE           ; not same window

        ; recalc main caret
        Push    "R2-R11"
        ADRL    R14,caretdata
        LDMIA   R14,{R0-R5}             ; get current caret state
        ADRL    R14,caretx
        STR     R14,caretx_dest
        STR     R14,hasghostcaret       ; not any more as we're doing a main caret
        STR     R14,hasselection        ; definitely not

        MOV     R14,#0
        STR     R14,hascaret            ; still have this one

        BL      setcaretcoords          ; do the recalculation
        STR     R2,caretdata+caretxoff
        STR     R3,caretdata+caretyoff
        Pull    "R2-R11"
        Pull    "R0-R1,PC"
02
        MOV     R14,#nullptr
        STR     R14,[handle,#w_seldata+wselicon] ; clear selection
        STR     R14,selectioniconaddr
        LDR     R0,selectionwindow
        Abs     R0,R0
        TEQ     R0,handle
        STREQ   R14,selectionwindow     ; no active selection if it was us
        Pull    "R0-R1,PC"              ; return.  No update of main caret as the ghost caret overrides it anyway

clipboard_check_current_drag_op
        Push    "R10,R14"

        ; Entry: R11=window handle
        LDR     R10,clipboard_spritearea_addr
        TEQ     R10,#0
        Pull    "R10,PC",EQ             ; no drag system available
        ; check to see if we are currently dragging from this window
        ; if dragging==TRUE and drag_finished==FALSE (as drag_aborted==TRUE means drag_finished==TRUE too)
        LDRB    R14,[R10,#cbtask_var_dragging]
        TEQ     R14,#CNPTRUE
        LDREQB  R14,[R10,#cbtask_var_drag_finished]
        TEQEQ   R14,#CNPFALSE
        LDREQ   R14,[R10,#cbtask_var_source_window]
        TEQEQ   R14,R11
        ; if R11==dragging source
        ; abort the drag as the selection is being messed with
        MOVEQ   R14,#clipboard_pw_dragabort
        ADREQL  R10,clipboard_pollword
        STREQ   R14,[R10]

        Pull    "R10,PC"
 ]

        END