racket/collects/drscheme/private/first-line-text.ss
Robby Findler 8c9e4bcfe0 some white-on-black fixes
svn: r11447
2008-08-27 04:42:45 +00:00

229 lines
9.2 KiB
Scheme
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#lang scheme/base
(require scheme/gui/base
scheme/class
framework)
(provide first-line-text-mixin
first-line-text-mixin<%>)
(define first-line-text-mixin<%>
(interface ()
highlight-first-line))
(define dark-color (make-object color% 50 0 50))
(define dark-wob-color (make-object color% 220 150 220))
(define first-line-text-mixin
(mixin ((class->interface text%)) (first-line-text-mixin<%>)
(inherit get-text paragraph-end-position get-admin invalidate-bitmap-cache position-location
scroll-to local-to-global get-dc)
(define bx (box 0))
(define by (box 0))
(define bw (box 0))
(define fancy-first-line? #f)
(define first-line "")
(define end-of-first-line 0)
(define first-line-is-lang? #f)
(define/private (show-first-line?)
(and fancy-first-line? first-line-is-lang?))
(define/private (update-first-line)
(set! end-of-first-line (paragraph-end-position 0))
(set! first-line (get-text 0 end-of-first-line))
(set! first-line-is-lang? (is-lang-line? first-line)))
(define/augment (after-insert start len)
(when (<= start end-of-first-line)
(update-first-line))
(inner (void) after-insert start len))
(define/augment (after-delete start len)
(when (<= start end-of-first-line)
(update-first-line))
(inner (void) after-delete start len))
(define/private (fetch-first-line-height)
(let-values ([(_1 h _2 _3) (send (get-dc) get-text-extent first-line (get-font))])
h))
(define/override (scroll-editor-to localx localy width height refresh? bias)
(let ([admin (get-admin)])
(cond
[(not admin)
#f]
[(show-first-line?)
(let ([h (fetch-first-line-height)])
(set-box! by localy)
(local-to-global #f by)
(cond
[(<= (unbox by) h)
;; the max is relevant when we're already scrolled to the top.
(send admin scroll-to localx (max 0 (- localy h)) width height refresh? bias)]
[else
(send admin scroll-to localx localy width height refresh? bias)]))]
[else
(send admin scroll-to localx localy width height refresh? bias)])))
(define/public (highlight-first-line on?)
(unless (equal? fancy-first-line? on?)
(set! fancy-first-line? on?)
(invalidate-bitmap-cache)
(let ([canvas (send this get-canvas)])
(when canvas
(send canvas refresh)))))
(define/override (on-event event)
(cond
[(or (send event moving?)
(send event leaving?)
(send event entering?))
(super on-event event)]
[else
(let ([y (send event get-y)]
[h (fetch-first-line-height)]
[admin (get-admin)])
(unless admin (send admin get-view #f by #f #f #f))
(cond
[(and admin
(< y h)
(not (= (unbox by) 0)))
(send admin scroll-to (send event get-x) 0 0 0 #t)
(super on-event event)]
[else
(super on-event event)]))]))
(define/override (on-paint before? dc left top right bottom dx dy draw-caret)
(unless before?
(when (show-first-line?)
(let ([admin (get-admin)])
(when admin
(send admin get-view bx by bw #f #f)
(unless (= (unbox by) 0)
(let ([first-line (get-text 0 (paragraph-end-position 0))]
[old-pen (send dc get-pen)]
[old-brush (send dc get-brush)]
[old-smoothing (send dc get-smoothing)]
[old-α (send dc get-alpha)]
[old-font (send dc get-font)]
[old-text-foreground (send dc get-text-foreground)])
(send dc set-font (get-font))
(send dc set-smoothing 'aligned)
(let-values ([(tw th _1 _2) (send dc get-text-extent first-line)])
(let ([line-height (+ (unbox by) dy th 1)]
[line-left (+ (unbox bx) dx)]
[line-right (+ (unbox bx) dx (unbox bw))])
(if (preferences:get 'framework:white-on-black?)
(send dc set-pen "white" 1 'solid)
(send dc set-pen "black" 1 'solid))
(send dc draw-line line-left line-height line-right line-height)
(when (eq? (send dc get-smoothing) 'aligned)
(let ([start 3/10]
[end 0]
[steps 10])
(send dc set-pen
(if (preferences:get 'framework:white-on-black?)
dark-wob-color
dark-color)
1
'solid)
(let loop ([i steps])
(unless (zero? i)
(let ([alpha-value (+ start (* (- end start) (/ i steps)))])
(send dc set-alpha alpha-value)
(send dc draw-line
line-left
(+ line-height i)
line-right
(+ line-height i))
(loop (- i 1))))))))
(send dc set-alpha 1)
(send dc set-pen "gray" 1 'transparent)
(if (preferences:get 'framework:white-on-black?)
(send dc set-brush "black" 'solid)
(send dc set-brush "white" 'solid))
(send dc draw-rectangle
(+ (unbox bx) dx)
(+ (unbox by) dy)
(unbox bw)
th)
(send dc set-text-foreground
(if (preferences:get 'framework:white-on-black?)
(send the-color-database find-color "white")
(send the-color-database find-color "black")))
(send dc draw-text first-line (+ (unbox bx) dx) (+ (unbox by) dy)))
(send dc set-text-foreground old-text-foreground)
(send dc set-font old-font)
(send dc set-pen old-pen)
(send dc set-brush old-brush)
(send dc set-alpha old-α)
(send dc set-smoothing old-smoothing)))))))
(super on-paint before? dc left top right bottom dx dy draw-caret))
(inherit get-style-list)
(define/private (get-font)
(let* ([style-list (get-style-list)]
[std (or (send style-list find-named-style "Standard")
(send style-list find-named-style "Basic"))])
(send std get-font)))
(super-new)))
;; is-lang-line? : string -> boolean
;; given the first line in the editor, this returns #t if it is a #lang line.
(define (is-lang-line? l)
(let ([m (regexp-match #rx"^#(!|(lang ))([-+_/a-zA-Z0-9]+)(.|$)" l)])
(and m
(let ([lang-name (list-ref m 3)]
[last-char (list-ref m 4)])
(and (not (char=? #\/ (string-ref lang-name 0)))
(not (char=? #\/ (string-ref lang-name (- (string-length lang-name) 1))))
(or (string=? "" last-char)
(char-whitespace? (string-ref last-char 0))))))))
;; test cases for is-lang-line?
#;
(list (is-lang-line? "#lang x")
(is-lang-line? "#lang scheme")
(is-lang-line? "#lang scheme ")
(not (is-lang-line? "#lang schemeα"))
(not (is-lang-line? "#lang scheme/ "))
(not (is-lang-line? "#lang /scheme "))
(is-lang-line? "#lang sch/eme ")
(is-lang-line? "#lang r6rs")
(is-lang-line? "#!r6rs")
(is-lang-line? "#!r6rs ")
(not (is-lang-line? "#!/bin/sh")))
#;
(begin
(define f (new frame% [label ""] [width 200] [height 200]))
;(define t (new (editor:standard-style-list-mixin (first-line-text-mixin text%))))
(define t
(new
(scheme:text-mixin
(text:autocomplete-mixin
(color:text-mixin
(mode:host-text-mixin
(values ; text:delegate-mixin
(text:foreground-color-mixin
(first-line-text-mixin
text:info%)))))))))
(require scheme/runtime-path)
(define-runtime-path here ".")
(send t load-file (build-path (build-path here 'up 'up "framework" "private" "text.ss")))
#;
(send t insert (apply string-append (map (λ (x) (build-string 100 (λ (i) (if (= i 99) #\newline x))))
(string->list "abcdefghijklnopqrstuvwxyz"))))
(define c (new editor-canvas% [parent f] [editor t]))
(define b (new button% [callback (λ (c dc) (send t highlight-first-line #t))] [label "on"] [parent f]))
(define b2 (new button% [callback (λ (c dc) (send t highlight-first-line #f))] [label "off"] [parent f]))
(send c focus)
(send f show #t))