original commit: f4aadc8a0507be7e00334a1a939cb4441974b734
This commit is contained in:
Robby Findler 1998-08-31 21:36:26 +00:00
parent 8418866da8
commit 74e787e9ab
9 changed files with 181 additions and 1709 deletions

View File

@ -0,0 +1,53 @@
(unit/sig framework:path-utils^
(import)
(define generate-autosave-name
(lambda (name)
(let-values ([(base name dir?)
(if (null? name)
(values (current-directory) "mredauto" #f)
(split-path name))])
(let* ([base (if (string? base)
base
(current-directory))]
[path (if (relative-path? base)
(build-path (current-directory) base)
base)]
[without-ext
(if (eq? (system-type) 'windows)
(list->string
(let loop ([list (string->list name)])
(if (or (null? list)
(char=? (car list) #\.))
()
(cons (car list)
(loop (cdr list))))))
name)])
(let loop ([n 1])
(let ([new-name
(build-path path
(if (eq? (system-type) 'windows)
(string-append without-ext
"."
(number->string n))
(string-append "#"
name
"#"
(number->string n)
"#")))])
(if (file-exists? new-name)
(loop (add1 n))
new-name)))))))
(define generate-backup-name
(lambda (name)
(if (eq? (system-type) 'windows)
(list->string
(let loop ([list (string->list name)])
(if (or (null? list)
(char=? (car list) #\.))
'(#\. #\b #\a #\k)
(cons (car list)
(loop (cdr list))))))
(string-append name "~")))))

View File

@ -0,0 +1,95 @@
(unit/sig framework:icon^
(import)
(define icon-path
(with-handlers ([void (lambda (x) (collection-path "system"))])
(collection-path "icons")))
(define (load-icon % name type)
(let ([p (build-path icon-path name)]
[bitmap #f])
(unless (file-exists? p)
(fprintf (current-error-port) "WARNING: couldn't find ~a~n" p))
(lambda ()
(if bitmap
bitmap
(begin (set! bitmap (make-object % p type))
bitmap)))))
(define (load-bitmap/mdc % name type)
(let* ([p (build-path icon-path name)]
[bitmap #f]
[memory-dc #f]
[force
(lambda ()
(set! bitmap (make-object % p type))
(set! memory-dc (make-object memory-dc%))
(when (send bitmap ok?)
(send memory-dc select-object bitmap)))])
(unless (file-exists? p)
(fprintf (current-error-port) "WARNING: couldn't find ~a~n" p))
(values
(lambda ()
(or bitmap
(begin (force)
bitmap)))
(lambda ()
(or memory-dc
(begin (force)
memory-dc))))))
(define-values (get-anchor-bitmap get-anchor-mdc)
(load-bitmap/mdc bitmap% "anchor.gif" 'gif))
(define-values (get-lock-bitmap get-lock-mdc)
(load-bitmap/mdc bitmap% "lock.gif" 'gif))
(define-values (get-unlock-bitmap get-unlock-mdc)
(load-bitmap/mdc bitmap% "unlock.gif" 'gif))
(define get-autowrap-bitmap (load-icon bitmap% "return.xbm" 'xbm))
(define get-paren-highlight-bitmap (load-icon bitmap% "paren.xbm" 'xbm))
(define get-reset-console-bitmap (load-icon bitmap% "reset.xbm" 'xbm))
(define get
(let ([icon #f]
[p (build-path icon-path "mred.xbm")])
(unless (file-exists? p)
(fprintf (current-error-port) "WARNING: couldn't find ~a~n" p))
(lambda ()
(or icon
(begin
(set! icon (make-object icon% p 'xbm))
icon)))))
(define-values (get-gc-on-dc get-gc-width get-gc-height)
(let* ([get-bitmap (load-icon bitmap%
"recycle.gif"
'gif)]
[bitmap #f]
[mdc #f]
[fetch
(lambda ()
(unless mdc
(set! mdc (make-object memory-dc%))
(set! bitmap (get-bitmap))
(send mdc select-object bitmap)))])
(values (lambda () (fetch) mdc)
(lambda () (fetch) (if (send bitmap ok?)
(send bitmap get-width)
10))
(lambda () (fetch) (if (send bitmap ok?)
(send bitmap get-height)
10)))))
(define get-gc-off-dc
(let ([mdc #f])
(lambda ()
(if mdc
mdc
(begin
(set! mdc (make-object memory-dc%))
(send mdc select-object
(make-object bitmap%
(get-gc-width)
(get-gc-height)))
(send mdc clear)
mdc))))))

View File

@ -4,7 +4,6 @@
[handler : framework:handler^]
[scheme-paren : framework:scheme-paren^])
; This is a list of keys that are typed with the SHIFT key, but
; are not normally thought of as shifted. It will have to be
; changed for different keyboards.
@ -43,11 +42,18 @@
(lambda (method)
(lambda (edit event)
(let ([frame
(let loop ([p (send event wx:get-event-object)]) ;;???
(if (is-a? p frame%)
p
(loop (send p get-parent))))])
((ivar/proc frame method))
(let ([frame
(cond
[(is-a? obj editor<%>)
(let ([canvas (send obj get-active-canvas)])
(and canvas
(send canvas get-top-level-window)))]
[(is-a? obj area<%>)
(send obj get-top-level-window)]
[else #f])]))])
(if frame
((ivar/proc frame method))
(bell))
#t)))])
(lambda (kmap)
(let* ([map (lambda (key func)

View File

@ -413,11 +413,15 @@
button% horiz
(lambda (button evt)
(let ([new-value
(get-font-from-user
(format "Please choose a new ~a font" name)
fonts)])
(mred:gui-utils:get-single-choice
(format "Please choose a new ~a font"
name)
"Fonts"
fonts
null -1 -1 #t 300 400)])
(when new-value
(set-preference pref-sym (or (send new-value get-face) "<UNKNOWN>"))
(set-preference pref-sym
new-value)
(set-edit-font (get-preference font-size-pref-sym)))))
"Change")]
;; WARNING!!! CHECK INIT ARGS wx:

View File

@ -271,8 +271,8 @@
open-url
open-file))
(define-signature mred:icon^
(get-icon
(define-signature framework:icon^
(get
get-paren-highlight-bitmap
get-autowrap-bitmap
@ -306,8 +306,8 @@
global-search-keymap
global-file-keymap))
(define-signature mred:match-cache^
(match-cache%))
(define-signature framework:match-cache^
(%))
(define-signature mred:menu^
(max-manual-menu-id
@ -322,14 +322,14 @@
make-project-frame%
project-frame%))
(define-signature mred:scheme-paren^
(scheme-paren-pairs
scheme-quote-pairs
scheme-comments
scheme-forward-match
scheme-backward-match
scheme-balanced?
scheme-backward-containing-sexp))
(define-signature framework:scheme-paren^
(paren-pairs
quote-pairs
comments
forward-match
backward-match
balanced?
backward-containing-sexp))
(define-signature mred:scheme-mode^
(scheme-mode-allow-console-eval
@ -347,7 +347,7 @@
scheme-interaction-mode%
scheme-mode-style-list))
(define-signature mred:paren^
(define-signature framework:paren^
(balanced?
forward-match
backward-match

View File

@ -1,10 +0,0 @@
(unit/sig mred:application^
(import)
(define current-app-name (make-parameter
"MrEd"
(lambda (x)
(unless (string? x)
(error 'current-app-name
"the app name must be a string"))
x))))

View File

@ -1,59 +0,0 @@
(unit/sig mred:exit^
(import [wx : wx^]
[mred:constants : mred:constants^]
[mred:preferences : mred:preferences^]
[mred:gui-utils : mred:gui-utils^])
(rename (-exit exit))
(mred:debug:printf 'invoke "mred:exit@")
(define exit-callbacks '())
(define insert-exit-callback
(lambda (f)
(set! exit-callbacks (cons f exit-callbacks))
f))
(define remove-exit-callback
(lambda (cb)
(set! exit-callbacks
(let loop ([cb-list exit-callbacks])
(cond
[(null? cb-list) ()]
[(eq? cb (car cb-list)) (cdr cb-list)]
[else (cons (car cb-list) (loop (cdr cb-list)))])))))
(define exiting? #f)
(define run-exit-callbacks
(lambda ()
(let loop ([cb-list exit-callbacks])
(cond
[(null? cb-list) #t]
[(not ((car cb-list))) #f]
[else (loop (cdr cb-list))]))))
(define -exit
(opt-lambda ([just-ran-callbacks? #f])
(unless exiting?
(dynamic-wind
(lambda () (set! exiting? #t))
(lambda ()
(if (and (let*-values ([(w capW)
(if (eq? wx:platform 'windows)
(values "exit" "Exit")
(values "quit" "Quit"))]
[(message)
(string-append "Are you sure you want to "
w
"?")])
(if (mred:preferences:get-preference 'mred:verify-exit)
(if (mred:gui-utils:get-choice message capW "Cancel")
#t
#f)
#t))
(or just-ran-callbacks?
(run-exit-callbacks)))
(exit)
#f))
(lambda () (set! exiting? #f)))))))

View File

@ -1,957 +0,0 @@
(unit/sig mred:keymap^
(import [wx : wx^]
[mred:constants : mred:constants^]
[mred:preferences : mred:preferences^]
[mred:exit : mred:exit^]
[mred:finder : mred:finder^]
[mred:handler : mred:handler^]
[mred:find-string : mred:find-string^]
[mred:scheme-paren : mred:scheme-paren^]
[mred:gui-utils : mred:gui-utils^]
[mred:test : mred:testable-window^])
(mred:debug:printf 'invoke "mred:keymap@")
; This is a list of keys that are typed with the SHIFT key, but
; are not normally thought of as shifted. It will have to be
; changed for different keyboards.
(define shifted-key-list
'("?" ":" "~" "\""
"<" ">" "{" "}" "[" "]" "(" ")"
"!" "@" "#" "$" "%" "^" "&" "*" "_" "+"
"|"))
(define keyerr
(lambda (str)
(display str (current-error-port))
(newline (current-error-port))))
(define (set-keymap-error-handler keymap)
(send keymap set-error-callback keyerr))
(define (set-keymap-implied-shifts keymap)
(map (lambda (k) (send keymap implies-shift k))
shifted-key-list))
(define (make-meta-prefix-list key)
(list (string-append "m:" key)
(string-append "c:[;" key)
(string-append "ESC;" key)))
(define send-map-function-meta
(lambda (keymap key func)
(for-each (lambda (key)
;(printf "mapping ~a to ~a~n" key func)
(send keymap map-function key func))
(make-meta-prefix-list key))))
(mred:preferences:set-preference-default 'mred:delete-forward?
(not (eq? wx:platform 'unix))
(lambda (x)
(or (not x)
(eq? x #t))))
(define setup-global-search-keymap
(let* ([send-frame
(lambda (method)
(lambda (edit event)
(let ([frame
(let loop ([p (send event get-event-object)])
(if (is-a? p wx:frame%)
p
(loop (send p get-parent))))])
((ivar/proc frame method))
#t)))])
(lambda (kmap)
(let* ([map (lambda (key func)
(send kmap map-function key func))]
[map-meta (lambda (key func)
(send-map-function-meta kmap key func))]
[add (lambda (name func)
(send kmap add-key-function name func))]
[add-m (lambda (name func)
(send kmap add-mouse-function name func))])
(add "move-to-search-or-search" (send-frame 'move-to-search-or-search)) ;; key 1
(add "move-to-search-or-reverse-search" (send-frame 'move-to-search-or-reverse-search)) ;; key 1b, backwards
(add "find-string" (send-frame 'search)) ;; key 2
(add "toggle-search-focus" (send-frame 'toggle-search-focus)) ;; key 3
(add "hide-search" (send-frame 'hide-search)) ;; key 4
(case wx:platform
[(unix)
(map "c:s" "move-to-search-or-search")
(map-meta "%" "move-to-search-or-search")
(map "c:r" "move-to-search-or-reverse-search")
(map "f3" "find-string")
(map "c:i" "toggle-search-focus")
(map "c:g" "hide-search")]
[(windows)
(map "c:f" "move-to-search-or-search")
(map "c:r" "move-to-search-or-reverse-search")
(map "f3" "find-string")
(map "c:g" "find-string")
(map "c:i" "toggle-search-focus")]
[(macintosh)
(map "c:s" "move-to-search-or-search")
(map "c:g" "hide-search")
(map "d:f" "move-to-search-or-search")
(map "d:r" "move-to-search-or-reverse-search")
(map "d:g" "find-string")
(map "d:o" "toggle-search-focus")])))))
(define setup-global-file-keymap
(let* ([rcs
(let ([last-checkin-string ""])
(mred:preferences:set-preference-default
'rcs-pathname (list "/usr/local/RCS/" "/usr/bin/" "/usr/local/bin/")
(lambda (x)
(and (list? x)
(andmap string? x))))
(lambda (edit event)
(let/ec k
(let* ([rcs-binaries (list "ci" "co" "rlog")]
[rcs-pathname (let loop ([paths (mred:preferences:get-preference 'rcs-pathname)])
(cond
[(null? paths) (k (wx:message-box "could not find RCS binaries."))]
[else (if (andmap (lambda (b)
(file-exists? (build-path (car paths) b)))
rcs-binaries)
(car paths)
(loop (cdr paths)))]))]
[filename (send edit get-filename)]
[username (wx:get-user-id)])
(when (null? filename)
(k (wx:message-box "no file associated with this edit")))
(let-values ([(my-out my-in my-pid my-err)
(apply values (process* (build-path rcs-pathname "rlog")
"-L" "-R" (string-append "-l" username) filename))])
(let-values ([(their-out their-in their-pid their-err)
(apply values (process* (build-path rcs-pathname "rlog")
"-L" "-R" "-l" filename))])
(let ([my-lock? (not (eof-object? (read my-out)))]
[locked? (not (eof-object? (read their-out)))])
(for-each close-input-port (list my-out my-err their-out their-err))
(for-each close-output-port (list my-in their-in))
(cond
[(not (system* (build-path rcs-pathname "rlog") "-h" "-q" filename))
(system* (build-path rcs-pathname "ci") "-t-" filename)
(wx:message-box "Initial Checkin Completed")]
[my-lock?
(when (send edit modified?)
(case (mred:gui-utils:unsaved-warning (send edit get-filename) "Checkin" #t)
[(save) (send edit save-file (send edit get-filename)
(send edit get-file-format))]
[(cancel) (k (void))]
[else (void)]))
(let* ([msg (mred:gui-utils:get-text-from-user
"Please Enter Log Message"
"Check In"
last-checkin-string)]
[result (system* (build-path rcs-pathname "ci")
"-u" (string-append "-m" msg) filename)])
(set! last-checkin-string (or msg ""))
(if result
(send edit load-file
(send edit get-filename)
(send edit get-file-format))
(mred:gui-utils:message-box "Checkin Unsucessful")))]
[locked? (mred:gui-utils:message-box "Someone else has the lock")]
[else
(let ([current-dir (current-directory)])
(let-values ([(base name _) (split-path filename)])
(unless (eq? 'relative base)
(current-directory base))
(let ([res (system* (build-path rcs-pathname "co")
"-q" "-l" name)])
(current-directory current-dir)
(if res
(send edit load-file
(send edit get-filename)
(send edit get-file-format))
(wx:message-box "Checkout Failed")))))]))))))))]
[save-file-as
(lambda (edit event)
(let ([file (mred:finder:put-file)])
(if file
(send edit save-file file)))
#t)]
[save-file
(lambda (edit event)
(if (null? (send edit get-filename))
(save-file-as edit event)
(send edit save-file))
#t)]
[load-file
(lambda (edit event)
(mred:handler:open-file)
#t)])
(lambda (kmap)
(map (lambda (k) (send kmap implies-shift k)) shifted-key-list)
(let* ([map (lambda (key func)
(send kmap map-function key func))]
[map-meta (lambda (key func)
(send-map-function-meta kmap key func))]
[add (lambda (name func)
(send kmap add-key-function name func))]
[add-m (lambda (name func)
(send kmap add-mouse-function name func))])
(add "rcs" rcs)
(add "save-file" save-file)
(add "save-file-as" save-file-as)
(add "load-file" load-file)
(when (eq? wx:platform 'unix)
'(map "c:x;c:q" "rcs"))
(map "c:x;c:s" "save-file")
(map "d:s" "save-file")
(map "c:x;c:w" "save-file-as")
(map "c:x;c:f" "load-file")))))
; This installs the standard keyboard mapping
(define setup-global-keymap
; Define some useful keyboard functions
(let* ([ring-bell
(lambda (edit event)
(wx:bell))]
[toggle-anchor
(lambda (edit event)
(send edit set-anchor
(not (send edit get-anchor))))]
[center-view-on-line
(lambda (edit event)
(let ([new-mid-line (send edit position-line
(send edit get-start-position))]
[bt (box 0)]
[bb (box 0)])
(send edit get-visible-line-range bt bb)
(let* ([half (sub1 (quotient (- (unbox bb) (unbox bt)) 2))]
[top-pos (send edit line-start-position
(max (- new-mid-line half) 0))]
[bottom-pos (send edit line-start-position
(min (+ new-mid-line half)
(send edit position-line
(send edit last-position))))])
(send edit scroll-to-position
top-pos
#f
bottom-pos)))
#t)]
[flash-paren-match
(lambda (edit event)
(send edit on-default-char event)
(let ([pos (mred:scheme-paren:scheme-backward-match
edit
(send edit get-start-position)
0)])
(when pos
(send edit flash-on pos (+ 1 pos))))
#t)]
[collapse-variable-space
(lambda (leave-one? edit event)
(letrec ([end-pos (send edit last-position)]
[find-nonwhite
(lambda (pos d)
(let ([c (send edit get-character pos)])
(cond
[(char=? #\newline c) pos]
[(or (and (< pos 0) (= d -1))
(and (> pos end-pos) (= d 1)))
(if (= d -1)
-1
end-pos)]
[(char-whitespace? c)
(find-nonwhite (+ pos d) d)]
[else pos])))])
(let ([sel-start (send edit get-start-position)]
[sel-end (send edit get-end-position)])
(when (= sel-start sel-end)
(let ([start (+ (find-nonwhite (- sel-start 1) -1)
(if leave-one? 2 1))]
[end (find-nonwhite sel-start 1)])
(if (< start end)
(begin
(send edit begin-edit-sequence)
(send edit delete start end)
(if (and leave-one?
(not (char=? #\space
(send edit get-character
(sub1 start)))))
(send edit insert " " (sub1 start) start))
(send edit set-position start)
(send edit end-edit-sequence))
(when leave-one?
(let ([at-start
(send edit get-character sel-start)]
[after-start
(send edit get-character
(sub1 sel-start))])
(cond
[(char-whitespace? at-start)
(if (not (char=? at-start #\space))
(send edit insert " " sel-start
(add1 sel-start)))
(send edit set-position (add1 sel-start))]
[(char-whitespace? after-start)
(if (not (char=? after-start #\space))
(send edit insert " " (sub1 sel-start)
sel-start))]
[else
(send edit insert " ")])))))))))]
[collapse-space
(lambda (edit event)
(collapse-variable-space #t edit event))]
[remove-space
(lambda (edit event)
(collapse-variable-space #f edit event))]
[collapse-newline
(lambda (edit event)
(letrec ([find-nonwhite
(lambda (pos d offset)
(call/ec
(lambda (escape)
(let ([max (if (> offset 0)
(send edit last-position)
-1)])
(let loop ([pos pos])
(if (= pos max)
(escape pos)
(let ([c (send edit get-character
(+ pos offset))])
(cond
[(char=? #\newline c)
(loop (+ pos d))
(escape pos)]
[(char-whitespace? c)
(loop (+ pos d))]
[else pos]))))))))])
(let ([sel-start (send edit get-start-position)]
[sel-end (send edit get-end-position)])
(if (= sel-start sel-end)
(let* ([pos-line
(send edit position-line sel-start #f)]
[pos-line-start
(send edit line-start-position pos-line)]
[pos-line-end
(send edit line-end-position pos-line)]
[whiteline?
(let loop ([pos pos-line-start])
(if (>= pos pos-line-end)
#t
(and (char-whitespace?
(send edit get-character pos))
(loop (add1 pos)))))]
[start (find-nonwhite pos-line-start -1 -1)]
[end (find-nonwhite pos-line-end 1 0)]
[start-line
(send edit position-line start #f)]
[start-line-start
(send edit line-start-position start-line)]
[end-line
(send edit position-line end #f)]
[end-line-start
(send edit line-start-position (add1 end-line))])
(cond
[(and whiteline?
(= start-line pos-line)
(= end-line pos-line))
; Special case: just delete this line
(send edit delete pos-line-start (add1 pos-line-end))]
[(and whiteline? (< start-line pos-line))
; Can delete before & after
(send* edit
(begin-edit-sequence)
(delete (add1 pos-line-end) end-line-start)
(delete start-line-start pos-line-start)
(end-edit-sequence))]
[else
; Only delete after
(send edit delete (add1 pos-line-end)
end-line-start)]))))))]
[open-line
(lambda (edit event)
(let ([sel-start (send edit get-start-position)]
[sel-end (send edit get-end-position)])
(if (= sel-start sel-end)
(send* edit
(insert #\newline)
(set-position sel-start)))))]
[transpose-chars
(lambda (edit event)
(let ([sel-start (send edit get-start-position)]
[sel-end (send edit get-end-position)])
(when (= sel-start sel-end)
(let ([sel-start
(if (= sel-start
(send edit line-end-position
(send edit position-line sel-start)))
(sub1 sel-start)
sel-start)])
(let ([s (send edit get-text
sel-start (add1 sel-start))])
(send* edit
(begin-edit-sequence)
(delete sel-start (add1 sel-start))
(insert s (- sel-start 1))
(set-position (add1 sel-start))
(end-edit-sequence)))))))]
[transpose-words
(lambda (edit event)
(let ([sel-start (send edit get-start-position)]
[sel-end (send edit get-end-position)])
(when (= sel-start sel-end)
(let ([word-1-start (box sel-start)])
(send edit find-wordbreak word-1-start ()
wx:const-break-for-caret)
(let ([word-1-end (box (unbox word-1-start))])
(send edit find-wordbreak () word-1-end
wx:const-break-for-caret)
(let ([word-2-end (box (unbox word-1-end))])
(send edit find-wordbreak () word-2-end
wx:const-break-for-caret)
(let ([word-2-start (box (unbox word-2-end))])
(send edit find-wordbreak word-2-start ()
wx:const-break-for-caret)
(let ([text-1 (send edit get-text
(unbox word-1-start)
(unbox word-1-end))]
[text-2 (send edit get-text
(unbox word-2-start)
(unbox word-2-end))])
(send* edit
(begin-edit-sequence)
(insert text-1
(unbox word-2-start)
(unbox word-2-end))
(insert text-2
(unbox word-1-start)
(unbox word-1-end))
(set-position (unbox word-2-end))
(end-edit-sequence))))))))))]
[capitalize-it
(lambda (edit char-case1 char-case2)
(let ([sel-start (send edit get-start-position)]
[sel-end (send edit get-end-position)]
[real-end (send edit last-position)])
(when (= sel-start sel-end)
(let ([word-end (let ([b (box sel-start)])
(send edit find-wordbreak () b
wx:const-break-for-caret)
(min real-end (unbox b)))])
(send edit begin-edit-sequence)
(let loop ([pos sel-start]
[char-case char-case1])
(when (< pos word-end)
(let ([c (send edit get-character pos)])
(cond
[(char-alphabetic? c)
(send edit insert
(list->string
(list (char-case c)))
pos (add1 pos))
(loop (add1 pos) char-case2)]
[else
(loop (add1 pos) char-case)]))))
(send* edit
(end-edit-sequence)
(set-position word-end))))))]
[capitalize-word
(lambda (edit event)
(capitalize-it edit char-upcase char-downcase))]
[upcase-word
(lambda (edit event)
(capitalize-it edit char-upcase char-upcase))]
[downcase-word
(lambda (edit event)
(capitalize-it edit char-downcase char-downcase))]
[kill-word
(lambda (edit event)
(let ([sel-start (send edit get-start-position)]
[sel-end (send edit get-end-position)])
(let ([end-box (box sel-end)])
(send edit find-wordbreak () end-box
wx:const-break-for-caret)
(send edit kill 0 sel-start (unbox end-box)))))]
[backward-kill-word
(lambda (edit event)
(let ([sel-start (send edit get-start-position)]
[sel-end (send edit get-end-position)])
(let ([start-box (box sel-start)])
(send edit find-wordbreak start-box ()
wx:const-break-for-caret)
(send edit kill 0 (unbox start-box) sel-end))))]
[region-click
(lambda (edit event f)
(when (send event button-down?)
(let ([x-box (box (send event get-x))]
[y-box (box (send event get-y))]
[eol-box (box #f)])
(send edit global-to-local x-box y-box)
(let ([click-pos (send edit find-position
(unbox x-box)
(unbox y-box)
eol-box)]
[start-pos (send edit get-start-position)]
[end-pos (send edit get-end-position)])
(let ([eol (unbox eol-box)])
(if (< start-pos click-pos)
(f click-pos eol start-pos click-pos)
(f click-pos eol click-pos end-pos)))))))]
[copy-click-region
(lambda (edit event)
(region-click edit event
(lambda (click eol start end)
(send edit flash-on start end)
(send edit copy #f 0 start end))))]
[cut-click-region
(lambda (edit event)
(region-click edit event
(lambda (click eol start end)
(send edit cut #f 0 start end))))]
[paste-click-region
(lambda (edit event)
(region-click edit event
(lambda (click eol start end)
(send edit set-position click)
(send edit paste 0 click))))]
[mouse-copy-clipboard
(lambda (edit event)
(send edit copy #f (send event get-time-stamp)))]
[mouse-paste-clipboard
(lambda (edit event)
(send edit paste (send event get-time-stamp)))]
[mouse-cut-clipboard
(lambda (edit event)
(send edit cut #f (send event get-time-stamp)))]
[select-click-word
(lambda (edit event)
(region-click edit event
(lambda (click eol start end)
(let ([start-box (box click)]
[end-box (box click)])
(send edit find-wordbreak
start-box
end-box
wx:const-break-for-selection)
(send edit set-position
(unbox start-box)
(unbox end-box))))))]
[select-click-line
(lambda (edit event)
(region-click edit event
(lambda (click eol start end)
(let* ([line (send edit position-line
click eol)]
[start (send edit line-start-position
line #f)]
[end (send edit line-end-position
line #f)])
(send edit set-position start end)))))]
[goto-line
(lambda (edit event)
(let ([num-str (mred:gui-utils:get-text-from-user
"Goto Line:"
"Goto Line")])
(if (string? num-str)
(let ([line-num (string->number num-str)])
(if line-num
(let ([pos (send edit line-start-position
(sub1 line-num))])
(send edit set-position pos))))))
#t)]
[goto-position
(lambda (edit event)
(let ([num-str (mred:gui-utils:get-text-from-user
"Goto Position:"
"Goto Position")])
(if (string? num-str)
(let ([pos (string->number num-str)])
(if pos
(send edit set-position (sub1 pos))))))
#t)]
[repeater
(lambda (n edit)
(let* ([km (send edit get-keymap)]
[done
(lambda ()
(send km set-break-sequence-callback void)
(send km remove-grab-key-function))])
(send km set-grab-key-function
(lambda (name local-km edit event)
(if (null? name)
(let ([k (send event get-key-code)])
(if (<= (char->integer #\0) k (char->integer #\9))
(set! n (+ (* n 10) (- k (char->integer #\0))))
(begin
(done)
(dynamic-wind
(lambda ()
(send edit begin-edit-sequence))
(lambda ()
(let loop ([n n])
(unless (zero? n)
(send edit on-char event)
(loop (sub1 n)))))
(lambda ()
(send edit end-edit-sequence))))))
(begin
(done)
(dynamic-wind
(lambda ()
(send edit begin-edit-sequence))
(lambda ()
(let loop ([n n])
(unless (zero? n)
(send local-km call-function name edit event)
(loop (sub1 n)))))
(lambda ()
(send edit end-edit-sequence)))))
#t))
(send km set-break-sequence-callback done)
#t))]
[make-make-repeater
(lambda (n)
(lambda (edit event)
(repeater n edit)))]
[current-macro '()]
[building-macro #f] [build-macro-km #f] [build-protect? #f]
[do-macro
(lambda (edit event)
; If c:x;e during record, copy the old macro
(when building-macro
(set! building-macro (append (reverse current-macro)
(cdr building-macro))))
(let ([bm building-macro]
[km (send edit get-keymap)])
(dynamic-wind
(lambda ()
(set! building-macro #f)
(send edit begin-edit-sequence))
(lambda ()
(let/ec escape
(for-each
(lambda (f)
(let ([name (car f)]
[event (cdr f)])
(if (null? name)
(send edit on-char event)
(if (not (send km call-function
name edit event #t))
(escape #t)))))
current-macro)))
(lambda ()
(send edit end-edit-sequence)
(set! building-macro bm))))
#t)]
[start-macro
(lambda (edit event)
(if building-macro
(send build-macro-km break-sequence)
(letrec* ([km (send edit get-keymap)]
[done
(lambda ()
(if build-protect?
(send km set-break-sequence-callback done)
(begin
(set! building-macro #f)
(send km set-break-sequence-callback void)
(send km remove-grab-key-function))))])
(set! building-macro '())
(set! build-macro-km km)
(send km set-grab-key-function
(lambda (name local-km edit event)
(dynamic-wind
(lambda ()
(set! build-protect? #t))
(lambda ()
(if (null? name)
(send edit on-default-char event)
(send local-km call-function name edit event)))
(lambda ()
(set! build-protect? #f)))
(when building-macro
(set! building-macro
(cons (cons name event)
building-macro)))
#t))
(send km set-break-sequence-callback done)))
#t)]
[end-macro
(lambda (edit event)
(when building-macro
(set! current-macro (reverse building-macro))
(set! build-protect? #f)
(send build-macro-km break-sequence))
#t)]
[delete-key
(lambda (edit event)
(let ([kmap (send edit get-keymap)])
(send kmap call-function
(if (mred:preferences:get-preference 'mred:delete-forward?)
"delete-next-character"
"delete-previous-character")
edit event #t)))]
[toggle-overwrite
(lambda (edit event)
(send edit set-overwrite-mode
(not (send edit get-overwrite-mode))))])
(lambda (kmap)
; Redirect keymapping error messages to stderr
(send kmap set-error-callback keyerr)
; Set the implied shifting map
(map (lambda (k) (send kmap implies-shift k)) shifted-key-list)
(let* ([map (lambda (key func)
(send kmap map-function key func))]
[map-meta (lambda (key func)
(send-map-function-meta kmap key func))]
[add (lambda (name func)
(send kmap add-key-function name func))]
[add-m (lambda (name func)
(send kmap add-mouse-function name func))])
; Standards
(wx:add-media-buffer-functions kmap)
(wx:add-media-editor-functions kmap)
(wx:add-media-pasteboard-functions kmap)
; Map names to keyboard functions
(add "toggle-overwrite" toggle-overwrite)
(add "exit" (lambda (edit event)
(let ([frame (send edit get-frame)])
(if frame
((ivar frame file-menu:quit))
(wx:bell)))))
(add "ring-bell" ring-bell)
(add "flash-paren-match" flash-paren-match)
(add "toggle-anchor" toggle-anchor)
(add "center-view-on-line" center-view-on-line)
(add "collapse-space" collapse-space)
(add "remove-space" remove-space)
(add "collapse-newline" collapse-newline)
(add "open-line" open-line)
(add "transpose-chars" transpose-chars)
(add "transpose-words" transpose-words)
(add "capitalize-word" capitalize-word)
(add "upcase-word" upcase-word)
(add "downcase-word" downcase-word)
(add "kill-word" kill-word)
(add "backward-kill-word" backward-kill-word)
(let loop ([n 9])
(unless (negative? n)
(let ([s (number->string n)])
(add (string-append "command-repeat-" s)
(make-make-repeater n))
(loop (sub1 n)))))
(add "do-saved-macro" do-macro)
(add "start-macro-record" start-macro)
(add "end-macro-record" end-macro)
(add-m "copy-clipboard" mouse-copy-clipboard)
(add-m "cut-clipboard" mouse-cut-clipboard)
(add-m "paste-clipboard" mouse-paste-clipboard)
(add-m "copy-click-region" copy-click-region)
(add-m "cut-click-region" cut-click-region)
(add-m "paste-click-region" paste-click-region)
(add-m "select-click-word" select-click-word)
(add-m "select-click-line" select-click-line)
(add "goto-line" goto-line)
(add "goto-position" goto-position)
(add "delete-key" delete-key)
; Map keys to functions
(map "c:g" "ring-bell")
(map-meta "c:g" "ring-bell")
(map "c:x;c:g" "ring-bell")
(map "c:c;c:g" "ring-bell")
(map ")" "flash-paren-match")
(map "]" "flash-paren-match")
(map "}" "flash-paren-match")
(map "\"" "flash-paren-match")
(map "c:p" "previous-line")
(map "up" "previous-line")
(map "s:c:p" "select-up")
(map "s:up" "select-up")
(map "c:n" "next-line")
(map "down" "next-line")
(map "s:c:n" "select-down")
(map "s:down" "select-down")
(map "c:e" "end-of-line")
(map "d:RIGHT" "end-of-line")
(map "m:RIGHT" "end-of-line")
(map "END" "end-of-line")
(map "d:s:RIGHT" "select-to-end-of-line")
(map "m:s:RIGHT" "select-to-end-of-line")
(map "s:END" "select-to-end-of-line")
(map "s:c:e" "select-to-end-of-line")
(map "c:a" "beginning-of-line")
(map "d:LEFT" "beginning-of-line")
(map "m:LEFT" "beginning-of-line")
(map "HOME" "beginning-of-line")
(map "d:s:LEFT" "select-to-beginning-of-line")
(map "m:s:LEFT" "select-to-beginning-of-line")
(map "s:HOME" "select-to-beginning-of-line")
(map "s:c:a" "select-to-beginning-of-line")
(map "c:f" "forward-character")
(map "right" "forward-character")
(map "s:c:f" "forward-select")
(map "s:right" "forward-select")
(map "c:b" "backward-character")
(map "left" "backward-character")
(map "s:c:b" "backward-select")
(map "s:left" "backward-select")
(map-meta "f" "forward-word")
(map "a:RIGHT" "forward-word")
(map "c:RIGHT" "forward-word")
(map-meta "s:f" "forward-select-word")
(map "a:s:RIGHT" "forward-select-word")
(map "c:s:RIGHT" "forward-select-word")
(map-meta "b" "backward-word")
(map "a:LEFT" "backward-word")
(map "c:left" "backward-word")
(map-meta "s:b" "backward-select-word")
(map "a:s:LEFT" "backward-select-word")
(map "c:s:left" "backward-select-word")
(map-meta "<" "beginning-of-file")
(map "d:UP" "beginning-of-file")
(map "c:HOME" "beginning-of-file")
(map "s:c:home" "select-to-beginning-of-file")
(map "s:d:up" "select-to-beginning-of-file")
(map-meta ">" "end-of-file")
(map "d:DOWN" "end-of-file")
(map "c:end" "end-of-file")
(map "s:c:end" "select-to-end-of-file")
(map "s:d:down" "select-to-end-of-file")
(map "c:v" "next-page")
(map "a:DOWN" "next-page")
(map "pagedown" "next-page")
(map "c:DOWN" "next-page")
(map "s:c:v" "select-page-down")
(map "a:s:DOWN" "select-page-down")
(map "s:pagedown" "select-page-down")
(map "s:c:DOWN" "select-page-down")
(map-meta "v" "previous-page")
(map "a:up" "previous-page")
(map "pageup" "previous-page")
(map "c:up" "previous-page")
(map-meta "s:v" "select-page-up")
(map "s:a:up" "select-page-up")
(map "s:pageup" "select-page-up")
(map "s:c:up" "select-page-up")
(map "c:h" "delete-previous-character")
(map "c:d" "delete-next-character")
(map "del" "delete-key")
(map-meta "d" "kill-word")
(map-meta "del" "backward-kill-word")
(map-meta "c" "capitalize-word")
(map-meta "u" "upcase-word")
(map-meta "l" "downcase-word")
(map "c:l" "center-view-on-line")
(map "c:k" "delete-to-end-of-line")
(map "c:y" "paste-clipboard")
(map-meta "y" "paste-next")
(map "a:v" "paste-clipboard")
(map "d:v" "paste-clipboard")
(map "c:_" "undo")
(map "c:+" "redo")
(map "a:z" "undo")
(map "d:z" "undo")
(map "c:x;u" "undo")
(map "c:w" "cut-clipboard")
(map "a:x" "cut-clipboard")
(map "d:x" "cut-clipboard")
(map-meta "w" "copy-clipboard")
(map "a:c" "copy-clipboard")
(map "d:c" "copy-clipboard")
(map-meta "space" "collapse-space")
(map-meta "\\" "remove-space")
(map "c:x;c:o" "collapse-newline")
(map "c:o" "open-line")
(map "c:t" "transpose-chars")
(map-meta "t" "transpose-words")
(map "c:space" "toggle-anchor")
(map "insert" "toggle-overwrite")
(map-meta "o" "toggle-overwrite")
(map-meta "g" "goto-line")
(map-meta "p" "goto-position")
(map "c:u" "command-repeat-0")
(let loop ([n 9])
(unless (negative? n)
(let ([s (number->string n)])
(map-meta s (string-append "command-repeat-" s))
(loop (sub1 n)))))
(map "c:x;e" "do-saved-macro")
(map "c:x;(" "start-macro-record")
(map "c:x;)" "end-macro-record")
(map "leftbuttontriple" "select-click-line")
(map "leftbuttondouble" "select-click-word")
(map "c:x;c:c" "exit")
(map "rightbutton" "copy-click-region")
(map "rightbuttondouble" "cut-click-region")
(map "middlebutton" "paste-click-region")
(map "c:rightbutton" "copy-clipboard")))))
(define global-keymap (make-object wx:keymap%))
(setup-global-keymap global-keymap)
(define global-file-keymap (make-object wx:keymap%))
(setup-global-file-keymap global-file-keymap)
(define global-search-keymap (make-object wx:keymap%))
(setup-global-search-keymap global-search-keymap))

View File

@ -1,660 +0,0 @@
(unit/sig mred:preferences^
(import [wx : wx^]
[mred:constants : mred:constants^]
[mred:exn : mred:exn^]
[mred : mred:container^]
[mred:exit : mred:exit^]
[mred:gui-utils : mred:gui-utils^]
[mred:canvas : mred:canvas^]
[mred:edit : mred:edit^]
[mzlib:pretty-print : mzlib:pretty-print^]
[mzlib:function : mzlib:function^])
(mred:debug:printf 'invoke "mred:preferences@")
(define preferences-filename (wx:find-path 'pref-file))
(define preferences (make-hash-table))
(define marshall-unmarshall (make-hash-table))
(define callbacks (make-hash-table))
(define defaults (make-hash-table))
(define-struct un/marshall (marshall unmarshall))
(define-struct marshalled (data))
(define-struct pref (value))
(define-struct default (value checker))
(define guard
(lambda (when p value thunk failure)
(let ([h
(lambda (x)
(let ([msg
(format "exception raised ~a for ~a with ~a: ~a~n"
when p value
(exn-message x))])
(failure x)))])
(with-handlers ([(lambda (x) #t) h])
(thunk)))))
(define unmarshall
(lambda (p marshalled)
(let/ec k
(let* ([data (marshalled-data marshalled)]
[unmarshall-fn (un/marshall-unmarshall (hash-table-get marshall-unmarshall
p
(lambda () (k data))))])
(guard "unmarshalling" p marshalled
(lambda () (unmarshall-fn data))
(lambda (exn)
(hash-table-get
defaults
p
(lambda ()
(wx:message-box
(format
"no default for ~a"
p))
(raise (mred:exn:make-exn:during-preferences
(if (exn? exn)
(exn-message exn)
(format "~s" exn))
((debug-info-handler))))))))))))
(define get-callbacks
(lambda (p)
(hash-table-get callbacks
p
(lambda () null))))
(define add-preference-callback
(lambda (p callback)
(hash-table-put! callbacks p (append (get-callbacks p) (list callback)))
(lambda ()
(hash-table-put!
callbacks p
(mzlib:function:remove callback
(get-callbacks p)
eq?)))))
(define check-callbacks
(lambda (p value)
(andmap (lambda (x)
(guard "calling callback" p value
(lambda () (x p value))
(lambda (exn)
(raise (mred:exn:make-exn:during-preferences
(if (exn? exn)
(exn-message exn)
(format "~s" exn))
((debug-info-handler)))))))
(get-callbacks p))))
(define get-preference
(lambda (p)
(let ([ans (hash-table-get preferences p
(lambda ()
(raise (mred:exn:make-exn:unknown-preference
(format "attempted to get unknown preference: ~a" p)
((debug-info-handler))))))])
(cond
[(marshalled? ans)
(let* ([default-s
(hash-table-get
defaults p
(lambda ()
(error 'get-preference
"no default pref for: ~a~n"
p)))]
[default (default-value default-s)]
[checker (default-checker default-s)]
[unmarshalled (let ([unmarsh (unmarshall p ans)])
(if (checker unmarsh)
unmarsh
(begin
(printf "WARNING: ~s rejecting invalid pref ~s in favor of ~s (pred: ~s)~n"
p unmarsh default checker)
default)))]
[_ (mred:debug:printf 'prefs "get-preference checking callbacks: ~a to ~a"
p unmarshalled)]
[pref (if (check-callbacks p unmarshalled)
unmarshalled
default)])
(hash-table-put! preferences p (make-pref pref))
(mred:debug:printf 'prefs "get-preference.1 returning ~a as ~a"
p pref)
pref)]
[(pref? ans)
(let ([ans (pref-value ans)])
(mred:debug:printf 'prefs "get-preference.2 returning ~a as ~a"
p ans)
ans)]
[else (error 'prefs.ss "robby error.1: ~a" ans)]))))
(define set-preference
(lambda (p value)
(let* ([pref (hash-table-get preferences p (lambda () #f))])
(cond
[(pref? pref)
(mred:debug:printf 'prefs "set-preference.1 checking callbacks: ~a to ~a" p value)
(when (check-callbacks p value)
(mred:debug:printf 'prefs "set-preference.1 setting ~a to ~a"
p value)
(set-pref-value! pref value))]
[(or (marshalled? pref)
(not pref))
(mred:debug:printf 'prefs "set-preference.2 checking callbacks: ~a to ~a" p value)
(when (check-callbacks p value)
(mred:debug:printf 'prefs "set-preference.2 setting ~a to ~a"
p value)
(hash-table-put! preferences p (make-pref value)))]
[else
(error 'prefs.ss "robby error.0: ~a" pref)]))))
(define set-preference-un/marshall
(lambda (p marshall unmarshall)
(hash-table-put! marshall-unmarshall p (make-un/marshall marshall unmarshall))))
(define restore-defaults
(lambda ()
(mred:debug:printf 'prefs "setting prefs to default values")
(hash-table-for-each
defaults
(lambda (p v) (set-preference p v)))
(mred:debug:printf 'prefs "finished setting prefs to default values")))
(define set-preference-default
(lambda (p value checker)
(let ([t (checker value)])
(unless t
(error 'set-preference-default "~s: checker (~s) returns ~s for ~s, expected #t~n" p checker t value)))
(mred:debug:printf 'prefs "setting default value for ~a to ~a" p value)
(hash-table-get preferences p
(lambda ()
(hash-table-put! preferences p (make-pref value))))
(hash-table-put! defaults p (make-default value checker))))
;; this is here becuase exit has to come before
;; prefs.ss in the loading order.
(set-preference-default 'mred:verify-exit #t
(lambda (x)
(or (not x)
(eq? x #t))))
(define save-user-preferences
(let ([marshall-pref
(lambda (p ht-value)
(cond
[(marshalled? ht-value) (list p (marshalled-data ht-value))]
[(pref? ht-value)
(let* ([value (pref-value ht-value)]
[marshalled
(let/ec k
(guard "marshalling" p value
(lambda ()
((un/marshall-marshall
(hash-table-get marshall-unmarshall p
(lambda ()
(k value))))
value))
(lambda (exn)
(raise (mred:exn:make-exn:during-preferences
(if (exn? exn)
(exn-message exn)
(format "~s" exn))
((debug-info-handler)))))))])
(list p marshalled))]
[else (error 'prefs.ss "robby error.2: ~a" ht-value)]))])
(lambda ()
(mred:debug:printf 'prefs "saving user preferences")
(with-handlers ([(lambda (x) #t)
(lambda (exn)
(mred:gui-utils:message-box
(format "Error saving preferences~n~a"
(exn-message exn))
"Error saving preferences"))])
(call-with-output-file preferences-filename
(lambda (p)
(mzlib:pretty-print:pretty-print
(hash-table-map preferences marshall-pref) p))
'truncate 'text))
(mred:debug:printf 'prefs "saved user preferences"))))
(mred:exit:insert-exit-callback
(lambda ()
(with-handlers ([(lambda (x) #t)
(lambda (exn)
(mred:gui-utils:message-box
(format "Error saving preferences: ~a"
(exn-message exn))
"Saving Prefs"))])
(save-user-preferences))))
(define read-user-preferences
(let ([parse-pref
(lambda (p marshalled)
(let/ec k
(let* ([ht-pref (hash-table-get preferences p (lambda () #f))]
[unmarshall-struct (hash-table-get marshall-unmarshall p (lambda () #f))])
(mred:debug:printf 'prefs "read-user-preferences; p: ~a ht-pref: ~a; marshalled: ~a"
p ht-pref marshalled)
(cond
[(and (pref? ht-pref) unmarshall-struct)
(set-preference p ((un/marshall-unmarshall unmarshall-struct) marshalled))]
;; in this case, assume that no marshalling/unmarshalling
;; is going to take place with the pref, since an unmarshalled
;; pref was already there.
[(pref? ht-pref)
(set-preference p marshalled)]
[(marshalled? ht-pref) (set-marshalled-data! ht-pref marshalled)]
[(and (not ht-pref) unmarshall-struct)
(set-preference p ((un/marshall-unmarshall unmarshall-struct) marshalled))]
[(not ht-pref)
(hash-table-put! preferences p (make-marshalled marshalled))]
[else (error 'prefs.ss "robby error.3: ~a" ht-pref)]))))])
(lambda ()
(mred:debug:printf 'prefs "reading user preferences")
(let/ec k
(when (file-exists? preferences-filename)
(let ([err
(lambda (input msg)
(wx:message-box (let* ([max-len 150]
[s1 (format "~s" input)]
[ell "..."]
[s2 (if (<= (string-length s1) max-len)
s1
(string-append (substring s1 0 (- max-len
(string-length ell)))
ell))])
(format "found bad pref: ~a~n~a" msg s2))
"Preferences"))])
(let loop ([input (with-handlers
([(lambda (exn) #t)
(lambda (exn)
(wx:message-box
(format "Error reading preferences~n~a"
(exn-message exn))
"Error reading preferences")
(k #f))])
(call-with-input-file preferences-filename
read
'text))])
(cond
[(pair? input)
(let ([err-msg
(let/ec k
(let ([first (car input)])
(unless (pair? first)
(k "expected pair of pair"))
(let ([arg1 (car first)]
[t1 (cdr first)])
(unless (pair? t1)
(k "expected pair of two pairs"))
(let ([arg2 (car t1)]
[t2 (cdr t1)])
(unless (null? t2)
(k "expected null after two pairs"))
(parse-pref arg1 arg2)
(k #f)))))])
(when err-msg
(err input err-msg)))
(loop (cdr input))]
[(null? input) (void)]
[else (err input "expected a pair")])))))
(mred:debug:printf 'prefs "read user preferences"))))
(define-struct ppanel (title container panel))
(define font-families-name/const
(list (list "Default" wx:const-default)
(list "Decorative" wx:const-decorative)
(list "Roman" wx:const-roman)
(list "Decorative" wx:const-script)
(list "Swiss" wx:const-swiss)
(list "Modern" wx:const-modern)))
(define font-families (map car font-families-name/const))
(define font-size-entry "defaultFontSize")
(define font-default-string "Default Value")
(define font-default-size 12)
(define font-section "mred")
(define build-font-entry (lambda (x) (string-append "Screen" x "__")))
(define font-file (wx:find-path 'setup-file))
(define (build-font-preference-symbol family)
(string->symbol (string-append "mred:" family)))
(let ([set-default
(lambda (build-font-entry default pred)
(lambda (family)
(let ([name (build-font-preference-symbol family)]
[font-entry (build-font-entry family)])
(set-preference-default name
default
(cond
[(string? default) string?]
[(number? default) number?]
[else (error 'internal-error.set-default "unrecognized default: ~a~n" default)]))
(add-preference-callback
name
(lambda (p new-value)
(wx:write-resource
font-section
font-entry
(if (and (string? new-value)
(string=? font-default-string new-value))
""
new-value)
font-file))))))])
(for-each (set-default build-font-entry font-default-string
string?)
font-families)
((set-default (lambda (x) x)
font-default-size
number?)
font-size-entry))
(define (later-on)
(local [(define sema (make-semaphore 1))
(define running #f)
(define (start-one thunk)
(local [(define (do-one)
(thunk)
(semaphore-wait sema)
(set! running #f)
(semaphore-post sema))]
(semaphore-wait sema)
(when running
(kill-thread running))
(set! running (thread do-one))
(semaphore-post sema)))]
start-one))
(define ppanels
(list
(make-ppanel
"General"
(lambda (parent)
(let* ([main (make-object mred:vertical-panel% parent)]
[make-check
(lambda (pref title bool->pref pref->bool)
(let* ([callback
(lambda (_ command)
(set-preference pref (bool->pref (send command checked?))))]
[pref-value (get-preference pref)]
[initial-value (pref->bool pref-value)]
[c (make-object mred:check-box% main callback title)])
(send c set-value initial-value)
(add-preference-callback pref
(lambda (p v)
(send c set-value (pref->bool v))))))]
[id (lambda (x) x)])
(send main minor-align-left)
(make-check 'mred:highlight-parens "Highlight between matching parens" id id)
(make-check 'mred:fixup-parens "Correct parens" id id)
(make-check 'mred:paren-match "Flash paren match" id id)
(make-check 'mred:autosaving-on? "Auto-save files" id id)
(make-check 'mred:delete-forward? "Map delete to backspace" not not)
(make-check 'mred:file-dialogs "Use platform-specific file dialogs"
(lambda (x) (if x 'std 'common))
(lambda (x) (eq? x 'std)))
(make-check 'mred:verify-exit "Verify exit" id id)
(make-check 'mred:verify-change-format "Ask before changing save format" id id)
(make-check 'mred:auto-set-wrap? "Wordwrap editor buffers" id id)
(make-check 'mred:show-status-line "Show status-line" id id)
(make-check 'mred:line-offsets "Count line and column numbers from one" id id)
(make-check 'mred:menu-bindings "Enable keybindings in menus" id id)
(unless (eq? wx:platform 'unix)
(make-check 'mred:print-output-mode "Automatically print to postscript file"
(lambda (b) (if b 1 0))
(lambda (n) (= n 1))))
(make-check 'mred:display-line-numbers "Display line numbers in buffer; not character offsets" id id)
main))
#f)
(make-ppanel
"Default Fonts"
(lambda (parent)
(letrec* ([font-size-pref-sym (build-font-preference-symbol font-size-entry)]
[ex-string "The quick brown fox jumped over the lazy dogs."]
[main (make-object mred:vertical-panel% parent)]
[fonts (cons font-default-string (wx:get-font-list))]
[make-family-panel
(lambda (name)
(let* ([pref-sym (build-font-preference-symbol name)]
[family-const-pair (assoc name font-families-name/const)]
[edit (make-object mred:edit:media-edit%)]
[_ (send edit insert ex-string)]
[set-edit-font
(lambda (size)
(let ([delta (make-object wx:style-delta% wx:const-change-size size)]
[face (get-preference pref-sym)])
(if (and (string=? face font-default-string)
family-const-pair)
(send delta set-family (cadr family-const-pair))
(send delta set-delta-face (get-preference pref-sym)))
(send edit change-style delta 0 (send edit last-position))))]
[horiz (make-object mred:horizontal-panel% main -1 -1 -1 -1 wx:const-border)]
[label (make-object mred:message% horiz name)]
[message (make-object mred:message% horiz
(let ([b (box "")])
(if (and (wx:get-resource
font-section
(build-font-entry name)
b)
(not (string=? (unbox b)
"")))
(unbox b)
font-default-string)))]
[button
(make-object
mred:button% horiz
(lambda (button evt)
(let ([new-value
(mred:gui-utils:get-single-choice
(format "Please choose a new ~a font"
name)
"Fonts"
fonts
null -1 -1 #t 300 400)])
(unless (null? new-value)
(set-preference pref-sym
new-value)
(set-edit-font (get-preference font-size-pref-sym)))))
"Change")]
[canvas (make-object mred:media-canvas% horiz -1 -1 -1 -1 ""
(bitwise-ior wx:const-mcanvas-hide-h-scroll
wx:const-mcanvas-hide-v-scroll))])
(set-edit-font (get-preference font-size-pref-sym))
(send canvas set-media edit)
(add-preference-callback
pref-sym
(lambda (p new-value)
(send horiz change-children
(lambda (l)
(let ([new-message (make-object
mred:message%
horiz
new-value)])
(set! message new-message)
(update-message-sizes font-message-get-widths
font-message-user-min-sizes)
(list label
new-message
button
canvas))))))
(vector set-edit-font
(lambda () (send message get-width))
(lambda (width) (send message user-min-width width))
(lambda () (send label get-width))
(lambda (width) (send label user-min-width width)))))]
[set-edit-fonts/messages (map make-family-panel font-families)]
[collect (lambda (n) (map (lambda (x) (vector-ref x n)) set-edit-fonts/messages))]
[set-edit-fonts (collect 0)]
[font-message-get-widths (collect 1)]
[font-message-user-min-sizes (collect 2)]
[category-message-get-widths (collect 3)]
[category-message-user-min-sizes (collect 4)]
[update-message-sizes
(lambda (gets sets)
(let ([width (mzlib:function:foldl (lambda (x l) (max l (x))) 0 gets)])
(for-each (lambda (set) (set width)) sets)))]
[size-panel (make-object mred:horizontal-panel% main -1 -1 -1 -1 wx:const-border)]
[size-slider
(make-object mred:slider% size-panel
(lambda (slider evt)
(set-preference font-size-pref-sym
(send slider get-value)))
"Size"
(let ([b (box 0)])
(if (wx:get-resource font-section
font-size-entry
b)
(unbox b)
font-default-size))
1 127 50)]
[guard-change-font (later-on)])
(update-message-sizes font-message-get-widths font-message-user-min-sizes)
(update-message-sizes category-message-get-widths category-message-user-min-sizes)
(add-preference-callback
font-size-pref-sym
(lambda (p value)
(guard-change-font
(lambda ()
(map (lambda (f) (f value)) set-edit-fonts)))
(unless (= value (send size-slider get-value))
(send size-slider set-value value))
#t))
(make-object mred:message% main
"Restart to see font changes")
main))
#f)))
(define make-run-once
(lambda ()
(let ([semaphore (make-semaphore 1)])
(lambda (t)
(dynamic-wind (lambda () (semaphore-wait semaphore))
t
(lambda () (semaphore-post semaphore)))))))
(define run-once (make-run-once))
(define preferences-dialog #f)
(define add-preference-panel
(lambda (title container)
(run-once
(lambda ()
(let ([new-ppanel (make-ppanel title container #f)])
(set! ppanels
(let loop ([ppanels ppanels])
(cond
[(null? ppanels) (list new-ppanel)]
[(string=? (ppanel-title (car ppanels))
title)
(loop (cdr ppanels))]
[else (cons (car ppanels)
(loop (cdr ppanels)))])))
(when preferences-dialog
(send preferences-dialog added-pane)))))))
(define hide-preferences-dialog
(lambda ()
(run-once
(lambda ()
(when preferences-dialog
(send preferences-dialog show #f))))))
(define show-preferences-dialog
(lambda ()
(mred:gui-utils:show-busy-cursor
(lambda ()
(run-once
(lambda ()
(save-user-preferences)
(if preferences-dialog
(send preferences-dialog show #t)
(set! preferences-dialog
(let ([cursor-off (mred:gui-utils:delay-action
2 wx:begin-busy-cursor
wx:end-busy-cursor)])
(begin0 (make-preferences-dialog)
(cursor-off)))))))))))
(define make-preferences-dialog
(lambda ()
(letrec* ([frame
(make-object (class-asi mred:frame%
(public [added-pane (lambda ()
(ensure-constructed)
(refresh-menu)
(send popup-menu set-selection (sub1 (length ppanels)))
(send single-panel active-child
(ppanel-panel (car (list-tail ppanels (sub1 (length ppanels)))))))]))
'() "Preferences")]
[panel (make-object mred:vertical-panel% frame)]
[popup-callback
(lambda (choice command-event)
(send single-panel active-child
(ppanel-panel (list-ref ppanels (send command-event get-command-int)))))]
[make-popup-menu
(lambda ()
(let ([menu (make-object mred:choice% panel popup-callback
"Category" -1 -1 -1 -1
(map ppanel-title ppanels))])
(send menu stretchable-in-x #f)
menu))]
[popup-menu (make-popup-menu)]
[single-panel (make-object mred:single-panel% panel -1 -1 -1 -1 wx:const-border)]
[bottom-panel (make-object mred:horizontal-panel% panel)]
[ensure-constructed
(lambda ()
(for-each (lambda (ppanel)
(unless (ppanel-panel ppanel)
(let ([panel ((ppanel-container ppanel) single-panel)])
(unless (is-a? panel mred:panel%)
(error 'preferences-dialog
"expected the preference panel to be a mred:panel%. Got ~a instead~n"
panel))
(set-ppanel-panel! ppanel panel))))
ppanels)
(send single-panel change-children (lambda (l) (map ppanel-panel ppanels)))
(send single-panel active-child (ppanel-panel (car ppanels))))]
[refresh-menu
(lambda ()
(let ([new-popup (make-popup-menu)])
(send new-popup set-selection (send popup-menu get-selection))
(set! popup-menu new-popup)
(send panel change-children
(lambda (l) (list new-popup
single-panel
bottom-panel)))))]
[ok-callback (lambda args
(save-user-preferences)
(hide-preferences-dialog))]
[ok-button (make-object mred:button% bottom-panel ok-callback "OK")]
[cancel-callback (lambda args
(hide-preferences-dialog)
(read-user-preferences))]
[cancel-button (make-object mred:button% bottom-panel cancel-callback "Cancel")])
(send ok-button user-min-width (send cancel-button get-width))
(send* bottom-panel
(stretchable-in-y #f)
(major-align-right))
(ensure-constructed)
(send popup-menu set-selection 0)
(send frame show #t)
frame)))
(read-user-preferences))