1#lang racket/base 2(provide text-inline-overview@) 3 4(require racket/unit 5 mred/mred-sig 6 racket/class 7 "../preferences.rkt" 8 "text-sig.rkt" 9 "sig.rkt" 10 (prefix-in unsafe: (only-in racket/draw/private/bitmap make-bitmap))) 11 12(define-local-member-name 13 get-primary-bmp 14 get-secondary-bmp 15 maybe-queue-do-a-little-work? 16 do-a-little-work 17 do-all-of-the-work 18 up-to-date? 19 get-invalid-start 20 get-invalid-end) 21 22(define maximum-bitmap-width 200) 23 24(define-unit text-inline-overview@ 25 (import mred^ 26 [prefix color-prefs: framework:color-prefs^]) 27 (export text-inline-overview^) 28 29 (define transparent-color (make-object color% 255 255 255 0)) 30 (define extra-blue-parts-margin 10) 31 (define arrow-cursor (make-object cursor% 'arrow)) 32 33 (define inline-overview<%> (interface ((class->interface text%)) 34 get-inline-overview-enabled? 35 set-inline-overview-enabled? 36 is-inline-overview-work-pending? 37 )) 38 (define inline-overview-mixin 39 (mixin ((class->interface text%)) (inline-overview<%>) 40 (define is-do-a-little-work-enqueued? #f) 41 (define invalid-start #f) 42 (define invalid-end #f) 43 (define primary-bmp #f) 44 (define secondary-bmp #f) 45 (define bmp-width 0) 46 (define enabled? #f) 47 ;; known-blank : nat 48 ;; the lines after and including known-blank are known to be blank in the bitmap 49 (define known-blank +inf.0) 50 51 (define/public (is-inline-overview-work-pending?) is-do-a-little-work-enqueued?) 52 53 (define/public (get-inline-overview-enabled?) enabled?) 54 (define/public (set-inline-overview-enabled? _e?) 55 (define e? (and _e? #t)) 56 (unless (equal? e? enabled?) 57 (set! enabled? e?) 58 (cond 59 [enabled? 60 (reset-entire-overview)] 61 [else 62 (invalidate-entire-overview-region #f) 63 (set! bmp-width 0) 64 (set! scratch-string #f) 65 (set! primary-bmp #f) 66 (set! secondary-bmp #f) 67 (set! known-blank +inf.0)]))) 68 69 (define/private (reset-entire-overview) 70 (define h (last-paragraph)) 71 (update-bmp-width 0 h) 72 (define to-create-h (+ h 20)) 73 (unless (and primary-bmp 74 (= (send primary-bmp get-width) bmp-width) 75 (= (send primary-bmp get-height) to-create-h)) 76 (set! primary-bmp (unsafe:make-bitmap bmp-width to-create-h)) 77 (set! secondary-bmp (unsafe:make-bitmap bmp-width to-create-h)) 78 (set! known-blank 0)) 79 (union-invalid 0 h) 80 (maybe-queue-do-a-little-work?)) 81 82 (define/public (get-primary-bmp) primary-bmp) 83 (define/public (get-secondary-bmp) secondary-bmp) 84 85 (super-new) 86 87 (define loading-file? #f) 88 (define/augment (on-load-file filename format) 89 (set! loading-file? #t) 90 (inner (void) on-load-file filename format)) 91 (define/augment (after-load-file success?) 92 (inner (void) after-load-file success?) 93 (set! loading-file? #f) 94 (reset-entire-overview)) 95 96 (define/augment (after-insert start len) 97 (inner (void) after-insert start len) 98 (when (and enabled? (not loading-file?)) 99 (set! width-could-have-changed-since-last-do-a-little-work? #t) 100 (define ps (position-paragraph start)) 101 (define pe (position-paragraph (+ start len))) 102 (cond 103 [(= ps pe) 104 ;; edit is just on a single line, 105 ;; so we mark that line as invalid 106 (union-invalid ps pe)] 107 [else 108 ;; the insertion spans multiple lines, so we 109 ;; copy the known good stuff to the secondary 110 ;; bitmap and swap the bitmaps and just give 111 ;; up on tracking which parts are blank 112 (set! known-blank +inf.0) 113 (define current-h (send primary-bmp get-height)) 114 (define w (send primary-bmp get-width)) 115 (define h 116 (cond 117 [(>= (last-paragraph) current-h) 118 (if (< (* 2 current-h) (last-paragraph)) 119 (+ 20 (last-paragraph)) 120 (* 2 current-h))] 121 [else current-h])) 122 (define make-new-bitmaps? (not (= current-h h))) 123 (define bmp-to-draw-into 124 (if make-new-bitmaps? 125 (unsafe:make-bitmap bmp-width h) 126 secondary-bmp)) 127 (define bdc (new bitmap-dc% [bitmap bmp-to-draw-into])) 128 (unless make-new-bitmaps? (send bdc erase)) 129 (send bdc draw-bitmap-section primary-bmp 0 0 0 0 w ps) 130 (send bdc draw-bitmap-section primary-bmp 0 pe 0 ps w (- current-h ps)) 131 (when make-new-bitmaps? 132 (set! secondary-bmp bmp-to-draw-into) 133 (set! primary-bmp (unsafe:make-bitmap bmp-width h)) 134 (set! known-blank 0)) 135 (swap-bitmaps) 136 (union-invalid ps pe)]) 137 (maybe-queue-do-a-little-work?))) 138 139 (define/augment (on-delete start len) 140 (inner (void) on-delete start len) 141 (when (and enabled? (not loading-file?)) 142 (set! width-could-have-changed-since-last-do-a-little-work? #t) 143 (define ps (position-paragraph start)) 144 (define pe (position-paragraph (+ start len))) 145 (cond 146 [(= ps pe) 147 (union-invalid ps ps)] 148 [else 149 (set! known-blank +inf.0) 150 (define h (send secondary-bmp get-height)) 151 (define w (send secondary-bmp get-width)) 152 (define invalid-region-size (- (+ (last-paragraph) 1) pe)) 153 154 (define bdc (new bitmap-dc% [bitmap secondary-bmp])) 155 (send bdc erase) 156 157 ; copy stuff before start of invalid region to other bitmap 158 (send bdc draw-bitmap-section primary-bmp 0 0 0 0 w ps) 159 160 ; copy stuff after end of invalid region to other bitmap 161 (send bdc draw-bitmap-section primary-bmp 162 0 ps 163 0 pe 164 w invalid-region-size) 165 (send bdc set-pen "black" 1 'transparent) 166 (send bdc set-brush transparent-color 'solid) 167 (send bdc draw-rectangle 168 0 169 (- (last-paragraph) 1) 170 w 171 (- h ps (- invalid-region-size pe))) 172 173 (swap-bitmaps) 174 175 (union-invalid ps ps)]) 176 (maybe-queue-do-a-little-work?))) 177 178 (define/augment (after-change-style start len) 179 (inner (void) after-change-style start len) 180 (when enabled? 181 (define ps (position-paragraph start)) 182 (define pe (position-paragraph (+ start len))) 183 (union-invalid ps pe) 184 (maybe-queue-do-a-little-work?))) 185 186 (define last-time-on-paint-called #f) 187 (define/override (on-paint before? dc left top right bottom dx dy draw-caret) 188 (super on-paint before? dc left top right bottom dx dy draw-caret) 189 (when (and enabled? before? (get-admin)) 190 (define-values (view-height 191 bitmap-first-visible-paragraph 192 top-paragraph 193 bot-paragraph 194 bitmap-x-coordinate 195 bitmap-y-coordinate) 196 (get-bitmap-placement-info)) 197 198 (when (or (<= left bitmap-x-coordinate right) 199 (<= left (+ bitmap-x-coordinate bmp-width) right)) 200 (define visible-height (- bot-paragraph top-paragraph)) 201 (define old-pen (send dc get-pen)) 202 (define old-brush (send dc get-brush)) 203 (send dc set-pen "black" 1 'transparent) 204 (send dc set-brush 205 (color-prefs:lookup-in-color-scheme 'framework:program-contour-current-location-bar) 206 'solid) 207 (send dc draw-rectangle 208 (- (+ dx bitmap-x-coordinate) extra-blue-parts-margin) 209 (+ dy 210 bitmap-y-coordinate 211 (- top-paragraph bitmap-first-visible-paragraph)) 212 (+ extra-blue-parts-margin (send primary-bmp get-width)) 213 visible-height) 214 (send dc draw-bitmap-section primary-bmp 215 (+ dx bitmap-x-coordinate) 216 (+ dy bitmap-y-coordinate) 217 0 bitmap-first-visible-paragraph 218 (send primary-bmp get-width) view-height) 219 220 (send dc set-brush old-brush) 221 (send dc set-pen old-pen)))) 222 223 (define/override (after-scroll-to) 224 (when enabled? 225 ;; we a scroll happens, we need to redraw 226 ;; the the entire overview region, as scrolling 227 ;; invalidates only the newly exposed region 228 (invalidate-entire-overview-region #f))) 229 230 (define/private (invalidate-entire-overview-region just-union?) 231 (define-values (view-height 232 bitmap-first-visible-paragraph 233 top-paragraph 234 bot-paragraph 235 bitmap-x-coordinate 236 bitmap-y-coordinate) 237 (get-bitmap-placement-info)) 238 (define x (- bitmap-x-coordinate extra-blue-parts-margin)) 239 (define w (+ bmp-width extra-blue-parts-margin)) 240 (cond 241 [just-union? 242 (union-region-to-invalidate x 243 bitmap-y-coordinate 244 w 245 view-height)] 246 [else 247 (invalidate-bitmap-cache x 248 bitmap-y-coordinate 249 w 250 view-height)])) 251 252 ;; pre: admin is not #f 253 (define/private (get-bitmap-placement-info) 254 ;; bitmap-first-visible-paragraph is which paragraph of the first 255 ;; line of the bitmap that should be visible at the top of the screen. 256 ;; top-paragraph is the paragraph of the main body of text that's 257 ;; at the top of the window 258 (define-values (x y view-width view-height) (get-view-info)) 259 (define view-right (+ x view-width)) 260 261 ;; in editor coordinates, the location where the upper-left part of the 262 ;; drawn part of the bitmap goes (the drawing uses draw-bitmap-section 263 ;; so this won't be where the upper-left corner of the 264 ;; content of the bitmap goes) 265 (define bitmap-x-coordinate (- view-right (send primary-bmp get-width))) 266 (define bitmap-y-coordinate y) 267 268 (define top-paragraph (xy-to-paragraph x y)) 269 (define bot-paragraph (xy-to-paragraph x (+ y view-height))) 270 (define bitmap-first-visible-paragraph 271 (get-bitmap-first-visible-paragraph view-height top-paragraph)) 272 (values view-height 273 bitmap-first-visible-paragraph 274 top-paragraph 275 bot-paragraph 276 bitmap-x-coordinate 277 bitmap-y-coordinate)) 278 279 ;; pre: admin is not #f 280 (define/private (get-view-info) 281 (define xb (box 0)) 282 (define yb (box 0)) 283 (define wb (box 0)) 284 (define hb (box 0)) 285 (define admin (get-admin)) 286 (send admin get-view xb yb wb hb) 287 (values (unbox xb) (unbox yb) (unbox wb) (unbox hb))) 288 289 (define/private (get-bitmap-first-visible-paragraph view-height top-paragraph) 290 (cond 291 [(<= (last-paragraph) view-height) 0] 292 ;top 293 [(> (- (ceiling (/ view-height 2)) top-paragraph) 0) 0] 294 [(< (- (last-paragraph) top-paragraph) (ceiling (/ view-height 2))) 295 (- (last-paragraph) view-height)] 296 ; subtract half the size of the editor from where we want to 297 ; draw the blue box to find the start of the bitmap 298 [else 299 (- top-paragraph (/ view-height 2))])) 300 301 (define/override (on-default-event event) 302 (cond 303 [(and enabled? (get-admin)) 304 (cond 305 [(send event button-up? 'left) 306 (define-values (mx my) (dc-location-to-editor-location 307 (send event get-x) 308 (send event get-y))) 309 (define-values (view-height 310 bitmap-first-visible-paragraph 311 top-paragraph 312 bot-paragraph 313 bitmap-x-coordinate 314 bitmap-y-coordinate) 315 (get-bitmap-placement-info)) 316 (cond 317 [(mouse-event-in-range? event mx my 318 bitmap-x-coordinate bitmap-y-coordinate 319 bot-paragraph bitmap-first-visible-paragraph) 320 (define p (+ (paragraph-start-position 321 (inexact->exact 322 (ceiling (+ (- my bitmap-y-coordinate) 323 bitmap-first-visible-paragraph)))) 324 (inexact->exact 325 (ceiling 326 (- mx bitmap-x-coordinate))))) 327 (define by (box 0)) 328 (position-location p #f by) 329 (begin-edit-sequence) 330 (set-position p p) 331 (scroll-editor-to 0 (- (unbox by) (/ view-height 2)) 332 0 view-height 333 #t 'none) 334 (end-edit-sequence)] 335 [else (super on-default-event event)])] 336 [else (super on-default-event event)])] 337 [else (super on-default-event event)])) 338 339 (define/override (adjust-cursor event) 340 (cond 341 [(and enabled? (get-admin)) 342 (define-values (mx my) (dc-location-to-editor-location 343 (send event get-x) 344 (send event get-y))) 345 (define-values (view-height 346 bitmap-first-visible-paragraph 347 top-paragraph 348 bot-paragraph 349 bitmap-x-coordinate 350 bitmap-y-coordinate) 351 (get-bitmap-placement-info)) 352 (cond 353 [(mouse-event-in-range? event mx my 354 bitmap-x-coordinate bitmap-y-coordinate 355 bot-paragraph bitmap-first-visible-paragraph) 356 arrow-cursor] 357 [else (super adjust-cursor event)])] 358 [else (super adjust-cursor event)])) 359 360 (define/private (mouse-event-in-range? event mx my 361 bitmap-x-coordinate bitmap-y-coordinate 362 bot-paragraph bitmap-first-visible-paragraph) 363 (and (<= (- bitmap-x-coordinate extra-blue-parts-margin) 364 mx 365 (+ bitmap-x-coordinate (send primary-bmp get-width))) 366 (<= bitmap-y-coordinate 367 my 368 (+ bitmap-y-coordinate 369 (- (last-paragraph) bitmap-first-visible-paragraph))))) 370 371 372 (inherit invalidate-bitmap-cache 373 split-snip get-snip-position 374 paragraph-start-position 375 dc-location-to-editor-location 376 paragraph-end-position 377 position-paragraph 378 position-location 379 last-paragraph 380 get-character 381 insert 382 delete 383 get-text 384 find-snip 385 get-canvas 386 get-admin 387 find-position 388 set-position 389 scroll-editor-to 390 begin-edit-sequence 391 end-edit-sequence) 392 393 (define/private (xy-to-paragraph x y) 394 (position-paragraph (find-position x y))) 395 396 (define/private (swap-bitmaps) 397 (define temp primary-bmp) 398 (set! primary-bmp secondary-bmp) 399 (set! secondary-bmp temp)) 400 401 (define/private (update-invalid-start nstart) 402 (set! invalid-start nstart)) 403 404 (define/private (union-invalid start end) 405 (set! invalid-start 406 (if invalid-start 407 (min start invalid-start) 408 start)) 409 (set! invalid-end 410 (if invalid-end 411 (max end invalid-end) 412 end))) 413 (define/private (clear-invalid) 414 (set! invalid-start #f) 415 (set! invalid-end #f)) 416 417 (define/private (update-bmp-width ps pe) 418 ;; initialize this to `1` so that we always have a non-empty bitmap 419 (define text-width 1) 420 (for ([i (in-range ps (+ 1 pe))]) 421 (define w (- (paragraph-end-position i) (paragraph-start-position i))) 422 (set! text-width (max text-width w))) 423 (when (> text-width bmp-width) 424 (set! bmp-width (min maximum-bitmap-width (+ 20 text-width)))) 425 (when (or (not scratch-string) 426 (< (string-length scratch-string) bmp-width)) 427 (set! scratch-string (make-string bmp-width)))) 428 429 (define/public (maybe-queue-do-a-little-work?) 430 (let loop () 431 (cond 432 [(or (up-to-date?) is-do-a-little-work-enqueued?) 433 (void)] 434 [else 435 (set! is-do-a-little-work-enqueued? #t) 436 (queue-callback 437 (λ () 438 (set! is-do-a-little-work-enqueued? #f) 439 (when enabled? 440 (do-a-little-work) 441 (loop))) 442 #f)]))) 443 444 (define/public (do-all-of-the-work) 445 (let loop () 446 (unless (up-to-date?) 447 (do-a-little-work) 448 (loop)))) 449 (define width-could-have-changed-since-last-do-a-little-work? #f) 450 (define/public (do-a-little-work) 451 (cond 452 [(up-to-date?) 453 (void)] 454 [(or invalid-start invalid-end) 455 (define start-time (current-inexact-milliseconds)) 456 (define bmp-width-changed? 457 (cond 458 [width-could-have-changed-since-last-do-a-little-work? 459 (set! width-could-have-changed-since-last-do-a-little-work? #f) 460 (define previous-bmp-width bmp-width) 461 (update-bmp-width invalid-start invalid-end) 462 (not (= previous-bmp-width bmp-width))] 463 [else #f])) 464 (when bmp-width-changed? 465 (define new-primary-bmp (unsafe:make-bitmap bmp-width (send primary-bmp get-height))) 466 (define new-secondary-bmp (unsafe:make-bitmap bmp-width (send primary-bmp get-height))) 467 (define bdc (new bitmap-dc% [bitmap primary-bmp])) 468 (send bdc set-bitmap new-primary-bmp) 469 (send bdc erase) 470 (send bdc draw-bitmap primary-bmp 0 0) 471 (set! primary-bmp new-primary-bmp) 472 (set! secondary-bmp new-secondary-bmp) 473 (set! known-blank 0)) 474 (define start-of-updated-lines invalid-start) 475 (define end-of-updated-lines 476 (let loop ([line-line-last-snip #f] 477 [y invalid-start]) 478 (define relevant-portion-known-blank? (>= y known-blank)) 479 (cond 480 [(= y invalid-end) 481 (update-one-line y line-line-last-snip relevant-portion-known-blank?) 482 (clear-invalid) 483 y] 484 [else 485 (define this-line-last-snip 486 (update-one-line y line-line-last-snip relevant-portion-known-blank?)) 487 (cond 488 [(< (+ start-time 10) (current-inexact-milliseconds)) 489 (update-invalid-start (+ 1 y)) 490 y] 491 [else 492 (loop this-line-last-snip 493 (+ y 1))])]))) 494 (set! known-blank (if invalid-start 495 (max known-blank invalid-start) 496 +inf.0)) 497 (when (get-admin) 498 (define-values (view-height 499 bitmap-first-visible-paragraph 500 top-paragraph 501 bot-paragraph 502 bitmap-x-coordinate 503 bitmap-y-coordinate) 504 (get-bitmap-placement-info)) 505 (cond 506 [bmp-width-changed? 507 (invalidate-entire-overview-region #t)] 508 [else 509 (union-region-to-invalidate 510 (- bitmap-x-coordinate extra-blue-parts-margin) 511 (+ (- bitmap-y-coordinate 512 bitmap-first-visible-paragraph) 513 start-of-updated-lines) 514 (+ bmp-width extra-blue-parts-margin) 515 (+ (- end-of-updated-lines start-of-updated-lines) 1))]))] 516 [else ;; region-to-invalidate must be #t here 517 (invalidate-region-to-invalidate)])) 518 519 ;; (or/c #f (vector l t r b <time-first-invalid-region-was-known>)) 520 (define region-to-invalidate #f) 521 (define/private (union-region-to-invalidate l t w h) 522 (define r (+ l w)) 523 (define b (+ t h)) 524 (cond 525 [region-to-invalidate 526 (set! region-to-invalidate 527 (vector (min l (vector-ref region-to-invalidate 0)) 528 (min t (vector-ref region-to-invalidate 1)) 529 (max r (vector-ref region-to-invalidate 2)) 530 (max b (vector-ref region-to-invalidate 3)) 531 (vector-ref region-to-invalidate 4)))] 532 [else 533 (set! region-to-invalidate (vector l t r b (current-inexact-milliseconds)))]) 534 535 (cond 536 [(< (+ (vector-ref region-to-invalidate 4) 1000.) (current-inexact-milliseconds)) 537 ;; when we have had an invalid region for a while, then 538 ;; just go ahead an invalidate it so the user sees some progress 539 (invalidate-region-to-invalidate)] 540 [else 541 ;; when we have an invalid region that starts in the viewing 542 ;; region but continues on beyond the viewing region, then 543 ;; we draw it right now (even if we are not finished computing 544 ;; the entire overview) 545 ;; the thought is that the user might not be scrolling, and 546 ;; so this region is the one that they're going to be 547 ;; looking at, so lets draw it right away instead of making 548 ;; them wait until we've figured out the overview for the 549 ;; entire file (which might be big) 550 (define-values (x y view-width view-height) (get-view-info)) 551 (define view-b (+ y view-height)) 552 (define top-inside? (<= y (vector-ref region-to-invalidate 1) view-b)) 553 (define bottom-inside? (<= y (vector-ref region-to-invalidate 3) view-b)) 554 (when (and top-inside? (not bottom-inside?)) 555 (invalidate-region-to-invalidate))])) 556 557 ;; pre: region-to-invalidate =/= #f 558 (define/private (invalidate-region-to-invalidate) 559 (invalidate-bitmap-cache (vector-ref region-to-invalidate 0) 560 (vector-ref region-to-invalidate 1) 561 (- (vector-ref region-to-invalidate 2) 562 (vector-ref region-to-invalidate 0)) 563 (- (vector-ref region-to-invalidate 3) 564 (vector-ref region-to-invalidate 1))) 565 (set! region-to-invalidate #f)) 566 567 (define scratch-string #f) 568 ;; update-one-line : nat bitmap-dc% (or/c #f snip%) nat -> (or/c #f snip%) 569 ;; it returns the last snip on the line (if it has one to return) 570 ;; and that value is passed back into the function so it can shortcircuit 571 ;; the call to `find-snip` 572 (define/private (update-one-line y last-lines-last-snip relevant-portion-known-blank?) 573 (define para-start (paragraph-start-position y)) 574 (define this-lines-first-snip 575 (if last-lines-last-snip 576 (send-generic last-lines-last-snip snip-next) 577 (find-snip para-start 'after-or-none))) 578 (let loop ([snip this-lines-first-snip] 579 [x 0]) 580 (cond 581 [snip 582 ;; we didn't run past the end of the buffer 583 ;; iterate over the current snip's content 584 ;; filling in this line of the bitmap 585 (define count (send-generic snip snip-get-count)) 586 (send-generic snip snip-get-text! scratch-string 0 (min maximum-bitmap-width count) 0) 587 (cond 588 [(and (= 1 count) 589 (eq? #\newline (string-ref scratch-string 0))) 590 (copy-single-line-bytes-out y x) 591 (unless relevant-portion-known-blank? 592 (erase-rest-of-line primary-bmp bmp-width x y)) 593 snip] 594 [(< x maximum-bitmap-width) 595 (setup-color (send (send-generic snip snip-get-style) get-foreground)) 596 (for ([ch (in-string scratch-string)] 597 [i (in-range x (min maximum-bitmap-width (+ count x)))]) 598 (cond 599 [(char-whitespace? ch) 600 (set-transparent-pixel i)] 601 [else 602 (set-colored-pixel i)])) 603 (loop (send-generic snip snip-next) 604 (+ x count))] 605 [else 606 (copy-single-line-bytes-out y x) 607 #f])] 608 [else 609 (copy-single-line-bytes-out y x) 610 (unless relevant-portion-known-blank? 611 (erase-rest-of-line primary-bmp bmp-width x y)) 612 #f]))) 613 614 (define single-line-bytes (make-bytes (* maximum-bitmap-width 4))) 615 (define (copy-single-line-bytes-out y _w) 616 (define w (min maximum-bitmap-width _w)) 617 (send-generic primary-bmp bitmap-set-argb-pixels 0 y w 1 single-line-bytes)) 618 619 (define color-bytes (bytes 0 0 0 0)) 620 (define/private (setup-color c) 621 (define α (send-generic c color-alpha)) 622 (cond 623 [(= α 1.0) 624 (bytes-set! color-bytes 0 255)] 625 [else 626 (bytes-set! color-bytes 0 (inexact->exact (round (* α 255))))]) 627 (bytes-set! color-bytes 1 (send-generic c color-red)) 628 (bytes-set! color-bytes 2 (send-generic c color-green)) 629 (bytes-set! color-bytes 3 (send-generic c color-blue))) 630 (define/private (set-colored-pixel x) 631 (bytes-copy! single-line-bytes (* x 4) color-bytes)) 632 (define/private (set-transparent-pixel x) 633 (bytes-copy! single-line-bytes (* x 4) transparent-bytes 0 4)) 634 635 (define/public (up-to-date?) 636 (and (not invalid-start) 637 (not invalid-end) 638 (not region-to-invalidate))) 639 (define/public (get-invalid-start) 640 invalid-start) 641 (define/public (get-invalid-end) 642 invalid-end))) 643 644 (define snip-get-style (generic snip% get-style)) 645 (define snip-get-count (generic snip% get-count)) 646 (define snip-get-text! (generic snip% get-text!)) 647 (define snip-next (generic snip% next)) 648 (define bitmap-set-argb-pixels (generic bitmap% set-argb-pixels)) 649 (define color-red (generic color% red)) 650 (define color-green (generic color% green)) 651 (define color-blue (generic color% blue)) 652 (define color-alpha (generic color% alpha))) 653 654;; this is a cheat, as we get bitmap% both from 655;; the unit import and from the a direct require 656;; of racket/gui/base, meaning that we're not really 657;; parameterized over mred^ 658(require (only-in racket/gui/base bitmap%)) 659 660;; provided for the test suite 661(provide set-transparent-pixels 662 erase-rest-of-line 663 transparent-bytes-count 664 maximum-bitmap-width 665 do-all-of-the-work 666 get-primary-bmp) 667 668(define bitmap-set-argb-pixels (generic bitmap% set-argb-pixels)) 669(define transparent-bytes 670 (bytes 0 255 255 255 0 255 255 255 671 0 255 255 255 0 255 255 255 672 0 255 255 255 0 255 255 255 673 0 255 255 255 0 255 255 255)) 674(define transparent-bytes-count (/ (bytes-length transparent-bytes) 4)) 675(define (set-transparent-pixels bmp x y n) 676 (send-generic bmp bitmap-set-argb-pixels x y n 1 transparent-bytes)) 677 678(define (erase-rest-of-line bmp w x y) 679 (cond 680 [(>= x w) (void)] 681 [else 682 (for ([x (in-range x (- w transparent-bytes-count) transparent-bytes-count)]) 683 (set-transparent-pixels bmp x y transparent-bytes-count)) 684 (define leftover (modulo (- w x) transparent-bytes-count)) 685 (cond 686 [(= 0 leftover) 687 (set-transparent-pixels bmp 688 (- w transparent-bytes-count) 689 y 690 transparent-bytes-count)] 691 [else 692 (set-transparent-pixels bmp (- w leftover) y leftover)])])) 693