;; TODOO ;; sobald funktinalität getestet ;; und abgesegnet -> ;; mach's klein! mach's schnell!... ;;=============================================================================== ;; record input-field: (define-record-type input-field :input-field (really-make-input-field default-text edit-lines window behavior insert-active x-loc y-loc x-dim y-dim x-pos y-pos x-edit-pos y-edit-pos x-offset y-offset x-scroll y-scroll) input-field? (default-text if-default-text) (edit-lines if-edit-lines set-if-edit-lines!) (window if-window set-if-window!) (behavior if-behavior set-if-behavior!) (insert-active if-insert-active set-if-insert-active!) (x-loc if-x-loc set-if-x-loc!) (y-loc if-y-loc set-if-y-loc!) (x-dim if-x-dim set-if-x-dim!) (y-dim if-y-dim set-if-y-dim!) (x-pos if-x-pos set-if-x-pos!) (y-pos if-y-pos set-if-y-pos!) (x-edit-pos if-x-edit-pos set-if-x-edit-pos!) (y-edit-pos if-y-edit-pos set-if-y-edit-pos!) (x-offset if-x-offset set-if-x-offset!) (y-offset if-y-offset set-if-y-offset!) (x-scroll if-x-scroll set-if-x-scroll!) (y-scroll if-y-scroll set-if-y-scroll!)) (define-record-discloser :input-field (lambda (i-f) (list 'input-field (if-default-text i-f)))) ;; record input-field END ;;=============================================================================== ;;=============================================================================== ;; "basics" ; ---------------------------------------------------------------------------- ;; "basics" - make-input-field (define make-input-field (lambda (x-dim y-dim . args) (let* ((args-len (length args)) (default-text (if (> args-len 0) (car args) "")) (behavior (if (> args-len 1) (cadr args) standard-behavior)) (insert-active (if (> args-len 2) (caddr args) #t)) (x-scroll (if (> args-len 3) (cadddr args) #f)) (y-scroll (if (> args-len 4) (caddddr args) #f))) (let ((i-f (really-make-input-field default-text #f #f behavior insert-active #f #f x-dim y-dim 0 0 0 0 0 0 x-scroll y-scroll))) (set-if-edit-lines! i-f (string->if-edit-lines i-f default-text)) i-f)))) ;; "basics" - make-input-field END ;; ---------------------------------------------------------------------------- ;; ---------------------------------------------------------------------------- ;; "basics" - remove / install-input-field & cursor-over-input-field? ;; FIXIT: sollte jemand auf die idee kommen ein input-field in mehrere ;; fenster zu installieren, müsste man hier noch was tun :-( ;; -------------------------------------------- ;; input-field-lookup-list ;; für die zentrale verwaltung der input-fields ;; -------------------------------------------- (define input-fields-lookup-list '()) ;; -------------------------------------------------- ;; install-input-field ordnet einem input-field ein ;; window zu und trägt das input-field in die ;; look-up-liste als weak-pointer ein ;; --------------------------------------------------- (define install-input-field (lambda (i-f window x y) (set-if-window! i-f window) (set-if-y-loc! i-f y) (set-if-x-loc! i-f x) (set! input-fields-lookup-list (cons (make-weak-pointer i-f) (util-filter (lambda (x) x) input-fields-lookup-list))) (refresh-all i-f) (wrefresh window))) (define make&install-input-field (lambda (win x-loc y-loc x-dim y-dim . args) (install-input-field (apply make-input-field x-dim y-dim args) win x-loc y-loc))) (define remove-input-field (lambda (i-f) (set! input-fields-lookup-list (let loop ((input-fields input-fields-lookup-list)) (if (null? input-fields) '() (let ((first (car input-fields))) (if (eq? i-f first) (cdr input-fields) (cons first (loop (cdr input-fields)))))))))) ;; -------------------------------------------------------- ;; cursor-over-input-field? schaut nach, ob ein input-field ;; in das übergebene window eingetragen ist und ob ;; sich der cursor über diesem befindet ;; -------------------------------------------------------- (define cursor-over-input-field? (lambda (window) (let ((x (getx window)) (y (gety window))) (let loop ((i-f-lst input-fields-lookup-list)) (if (null? i-f-lst) #f (let* ((i-f (weak-pointer-ref (car i-f-lst))) (win (if i-f (if-window i-f) #f))) (if (eq? window win) (or (cursor-over-this-input-field? x y i-f) (loop (cdr i-f-lst))) (loop (cdr i-f-lst))))))))) (define cursor-over-this-input-field? (lambda (cursor-x cursor-y i-f) (let* ((upper-left-x (if-x-loc i-f)) (upper-left-y (if-y-loc i-f)) (lower-right-x (- (+ upper-left-x (if-x-dim i-f)) 1)) (lower-right-y (- (+ upper-left-y (if-y-dim i-f)) 1))) (if (and (>= cursor-y upper-left-y) (<= cursor-y lower-right-y) (>= cursor-x upper-left-x) (<= cursor-x lower-right-x)) i-f #f)))) ;; "basics" - remove / install-input-field & cursor-over-input-field END ;; --------------------------------------------------------------------------- ;; --------------------------------------------------------------------------- ;; "basics" - selectors ;; TODOO - vielleicht gibt's sowas wie "export-as" (define input-field-default-text if-default-text) (define input-field-x-location if-x-loc) (define input-field-y-location if-y-loc) (define input-field-x-size if-x-dim) (define input-field-y-size if-y-dim) (define input-field-column if-x-edit-pos) (define input-field-line if-y-edit-pos) (define input-field-x-scroll if-x-scroll) (define input-field-y-scroll if-y-scroll) (define input-field-insert if-insert-active) (define input-field-text (lambda (i-f) (list->string (cat (if-edit-lines i-f))))) ;(define input-field-edit-pos ; (lambda (i-f) ; (values (if-x-edit-pos i-f) ; (if-y-edit-pos i-f)))) ;; "basics" - selectors END ;; --------------------------------------------------------------------------- ;; --------------------------------------------------------------------------- ;; "basics" - clear/reset (define input-field-clear (lambda (i-f) (set-if-x-offset! i-f 0) (set-if-y-offset! i-f 0) (set-if-x-pos! i-f 0) (set-if-y-pos! i-f 0) (set-if-x-edit-pos! i-f 0) (set-if-y-edit-pos! i-f 0) (set-if-edit-lines! i-f '(())) (refresh-all i-f))) (define input-field-reset (lambda (i-f) (set-if-x-offset! i-f 0) (set-if-y-offset! i-f 0) (set-if-x-pos! i-f 0) (set-if-y-pos! i-f 0) (set-if-x-edit-pos! i-f 0) (set-if-y-edit-pos! i-f 0) (set-if-edit-lines! i-f (string->if-edit-lines i-f (if-default-text i-f))) (refresh-all i-f))) ;; "basics" - clear/reset END ;; --------------------------------------------------------------------------- ;; "basics" END ;;=============================================================================== ;;=============================================================================== ;; draw/refresh functions (define paint-black (lambda (i-f) (let ((x-dim (if-x-dim i-f)) (y-dim (if-y-dim i-f)) (x-loc (if-x-loc i-f)) (y-loc (if-y-loc i-f)) (win (if-window i-f))) (let loop ((dy 0) (strings (map list->string (fill-up '() y-dim (fill-up '() x-dim #\space))))) (if (null? strings) #t (begin (mvwaddstr win (+ y-loc dy) x-loc (car strings)) (loop (+ dy 1) (cdr strings)))))))) ;;; TODOOOO (performance): ;;; funktionen geben zurück welcher ;;; refresh notwendig ist z.b.: ;;; 'position ;;; 'current-line ;;; 'from-current-line ... ;;; if-refresh ruft dann das richtige auf (define if-refresh (lambda (i-f msg) (if msg (refresh-all i-f) (values #t #f)))) (define refresh-position (lambda (i-f) (wmove (if-window i-f) (+ (if-y-loc i-f) (if-y-pos i-f)) (+ (if-x-loc i-f) (if-x-pos i-f))) (values #t #t))) (define refresh-from-position (lambda (i-f) #f)) (define refresh-all (lambda (i-f) (let ((x-loc (if-x-loc i-f)) (y-loc (if-y-loc i-f)) (x-dim (if-x-dim i-f)) (y-dim (if-y-dim i-f)) (x-offset (if-x-offset i-f)) (y-offset (if-y-offset i-f)) (win (if-window i-f))) (let* ((if-lines (map (lambda (if-line) (util-filter (lambda (char) (not (char=? char #\newline))) if-line)) (cat (map (lambda (edit-line) (edit-line->if-lines i-f edit-line)) (if-edit-lines i-f))))) (if-lines-cut (take (drop (map (lambda (if-line) (take (drop if-line x-offset) x-dim)) if-lines) y-offset) y-dim)) (if-lines-filled (map (lambda (if-line) (fill-up if-line x-dim #\space)) (fill-up if-lines-cut y-dim '())))) (let loop ((lines if-lines-filled) (y-ofst 0)) (if (null? lines) (refresh-position i-f) (begin (mvwaddstr win (+ y-loc y-ofst) x-loc (list->string (car lines))) (loop (cdr lines) (+ y-ofst 1))))))))) (define refresh-current-line (lambda (i-f) #f)) ;; draw/refresh functions END ;;=============================================================================== ;;=============================================================================== ;; send-input-field (define send-input-field (lambda (i-f msg . args) (if (integer? msg) (cond ((get-behavior i-f msg) => (lambda (method) (apply really-send-input-field i-f method args))) (else (apply really-send-input-field i-f msg args))) (values #f #f)))) (define really-send-input-field (lambda (i-f msg . args) (cond ((and (number? msg) (or (and (> msg 31) (< msg 127)) (= msg 10) (= msg 13))) (if-refresh i-f (insert-char i-f (if (= msg 13) #\newline (ascii->char msg))))) ((eq? msg 'move-prev-line) (if-refresh i-f (move-prev-line i-f))) ((eq? msg 'move-next-line) (if-refresh i-f (move-next-line i-f))) ((eq? msg 'move-left) (if-refresh i-f (move-left i-f))) ((eq? msg 'move-right) (if-refresh i-f (move-right i-f))) ((eq? msg 'delete-right) (if-refresh i-f (delete-right i-f))) ((eq? msg 'move-forward) (if-refresh i-f (move-forward i-f))) ((eq? msg 'move-backward) (if-refresh i-f (move-backward i-f))) ((eq? msg 'delete-left) (if-refresh i-f (delete-left i-f))) ((eq? msg 'delete-all-right) (if-refresh i-f (delete-all-right i-f))) ((eq? msg 'delete-all-left) (if-refresh i-f (delete-all-left i-f))) ((eq? msg 'delete-line) (if-refresh i-f (delete-line i-f))) ((eq? msg 'goto-begin-of-line) (if-refresh i-f (goto-begin-of-line i-f))) ((eq? msg 'goto-end-of-line) (if-refresh i-f (goto-end-of-line i-f))) ((eq? msg 'goto-begin-of-first-line) (if-refresh i-f (goto-begin-of-first-line i-f))) ((eq? msg 'goto-begin-of-last-line) (if-refresh i-f (goto-begin-of-last-line i-f))) ((eq? msg 'goto-begin-of-word-forward) (if-refresh i-f (goto-begin-of-word-forward i-f))) ((eq? msg 'goto-begin-of-word-backward) (if-refresh i-f (goto-begin-of-word-backward i-f))) ((eq? msg 'goto-end-of-word-forward) (if-refresh i-f (goto-begin-of-word-forward i-f))) ((eq? msg 'goto-end-of-word-backward) (if-refresh i-f (goto-begin-of-word-backward i-f))) ; ((eq? msg 'input-field-move-up) ; (if-refresh i-f (input-field-move-up i-f))) ; ((eq? msg 'input-field-move-down) ; (if-refresh i-f (input-field-move-down i-f))) ; ((eq? msg 'input-field-move-left) ; (if-refresh i-f (input-field-move-left i-f))) ; ((eq? msg 'input-field-move-right) ; (if-refresh i-f (input-field-move-right i-f))) ((eq? msg 'refresh-all) (refresh-all i-f)) ((eq? msg 'toggle-insert) (toggle-insert i-f)) ((eq? msg 'restore) (restore-input-field i-f)) ((list? msg) (for-each (lambda (msg-single) (send-input-field i-f msg-single)) msg) (values #t #t)) (else (values #f #f))))) ;; send-input-field END ;;=============================================================================== ;;=============================================================================== ;; behavior lists (define standard-behavior (list (cons key-up 'move-prev-line) (cons key-down 'move-next-line) (cons key-left 'move-left) (cons key-right 'move-right) (cons key-backspace 'delete-left) (cons key-dc 'delete-right) (cons key-home 'goto-begin-of-line) (cons key-end 'goto-end-of-line))) (define standard-behavior-pro (append standard-behavior (list (cons 2 ;; C-b 'move-left) (cons 6 ;; C-f 'move-right) (cons 16 ;; C-p 'move-prev-line) (cons 14 ;; C-n 'move-next-line) (cons 1 ;; C-a 'goto-begin-of-line) (cons 5 ;; C-e 'goto-end-of-line) (cons 4 ;; C-d 'delete-right) (cons 11 ;; C-k 'delete-all-right)))) ;; behavior lists END ;;=============================================================================== ;;=============================================================================== ;; behavior methods (define get-behavior (lambda (i-f msg) (let loop ((behavior (if-behavior i-f))) (if (null? behavior) #f (if (eq? msg (caar behavior)) (cdar behavior) (loop (cdr behavior))))))) ;; ---------------------------------------------------------------------------- ;; move (define move-prev-line (lambda (i-f) (if (first-line? i-f) #f (begin (set-if-y-edit-pos! i-f (- (if-y-edit-pos i-f) 1)) (sync-if-edit-pos i-f))))) (define move-next-line (lambda (i-f) (if (last-line? i-f) #f (begin (set-if-y-edit-pos! i-f (+ (if-y-edit-pos i-f) 1)) (sync-if-edit-pos i-f))))) (define move-left (lambda (i-f) (if (begin-of-line? i-f) #f (begin (set-if-x-edit-pos! i-f (- (if-x-edit-pos i-f) 1)) (sync-if-edit-pos i-f))))) (define move-right (lambda (i-f) (if (or (end-of-line? i-f) (and (right-border? i-f) (lower-border? i-f) (not (if-y-scroll i-f)) (not (if-x-scroll i-f)))) #f (begin (set-if-x-edit-pos! i-f (+ (if-x-edit-pos i-f) 1)) (sync-if-edit-pos i-f))))) (define move-forward (lambda (i-f) (if (move-right i-f) #t (if (move-next-line i-f) (goto-begin-of-line i-f) #f)))) (define move-backward (lambda (i-f) (if (move-left i-f) #t (if (move-prev-line i-f) (goto-end-of-line i-f) #f)))) (define sync-if-edit-pos (lambda (i-f) (call-with-values (lambda () (edit-pos->if-pos i-f (if-x-edit-pos i-f) (if-y-edit-pos i-f))) (lambda (x-pos y-pos) (set-if-x-pos! i-f (- x-pos (if-x-offset i-f))) (set-if-y-pos! i-f (- y-pos (if-y-offset i-f))))) (legalize-position i-f) (if (not (legal-offsets? i-f)) (legalize-offsets i-f) #t))) ;; move END ;; ---------------------------------------------------------------------------- ;; ---------------------------------------------------------------------------- ;; scroll (define scroll-up (lambda (i-f) (set-if-y-offset! i-f (- (if-y-offset i-f) 1)) #t)) (define scroll-down (lambda (i-f) (set-if-y-offset! i-f (+ (if-y-offset i-f) 1)) #t)) (define scroll-left (lambda (i-f) (set-if-x-offset! i-f (- (if-x-offset i-f) 1)) #t)) (define scroll-right (lambda (i-f) (set-if-x-offset! i-f (+ (if-x-offset i-f) 1)) #t)) ;; scroll END ;; ---------------------------------------------------------------------------- ;; ---------------------------------------------------------------------------- ;; insert (define insert-char (lambda (i-f char) (let* ((y-edit-pos (if-y-edit-pos i-f)) (edit-lines (if-edit-lines i-f)) (current-line (list-ref edit-lines y-edit-pos)) (new-lines-tmp (string->edit-lines (list->string ((if (or (char=? char #\newline) (if-insert-active i-f)) insert replace) current-line (if-x-edit-pos i-f) char)))) (new-lines (if (and (= (+ y-edit-pos 1) (length edit-lines)) (end-of-line? i-f) (char=? char #\newline)) (append new-lines-tmp '(())) new-lines-tmp)) (new-edit-lines (append (take edit-lines y-edit-pos) new-lines (drop edit-lines (+ y-edit-pos 1))))) (if (or (if-y-scroll i-f) (= (length (edit-lines->if-lines i-f new-lines)) (length (edit-line->if-lines i-f current-line))) (<= (length (edit-lines->if-lines i-f new-edit-lines)) (if-y-dim i-f))) (begin (set-if-edit-lines! i-f new-edit-lines) (if (char=? char #\newline) (begin (set-if-x-edit-pos! i-f 0) (set-if-y-edit-pos! i-f (+ (if-y-edit-pos i-f) 1)) (sync-if-edit-pos i-f)) (move-right i-f)) #t) #f)))) ;; insert END ;; ---------------------------------------------------------------------------- ;; ---------------------------------------------------------------------------- ;; delete (define delete-right (lambda (i-f) (let* ((x-edit-pos (if-x-edit-pos i-f)) (y-edit-pos (if-y-edit-pos i-f)) (edit-lines (if-edit-lines i-f)) (current-line (list-ref edit-lines y-edit-pos)) (current-line-len (length current-line))) (if (and (< x-edit-pos current-line-len) (not (char=? (list-ref current-line x-edit-pos) #\newline))) (let ((new-line (remove current-line x-edit-pos))) (set-if-edit-lines! i-f (replace edit-lines y-edit-pos new-line)) #t) #f)))) (define delete-left (lambda (i-f) (if (move-left i-f) (delete-right i-f) #f))) (define delete-all-left (lambda (i-f) (let* ((x-edit-pos (if-x-edit-pos i-f)) (y-edit-pos (if-y-edit-pos i-f)) (edit-lines (if-edit-lines i-f)) (current-line (list-ref edit-lines y-edit-pos))) (if (not (zero? x-edit-pos)) (begin (set-if-edit-lines! i-f (replace edit-lines y-edit-pos (drop current-line x-edit-pos))) (set-if-x-edit-pos! i-f 0) (sync-if-edit-pos i-f) #t) #f)))) (define delete-all-right (lambda (i-f) (let* ((x-edit-pos (if-x-edit-pos i-f)) (y-edit-pos (if-y-edit-pos i-f)) (edit-lines (if-edit-lines i-f)) (current-line (list-ref edit-lines y-edit-pos))) (if (and (end-of-line? i-f) (not (last-line? i-f))) (begin (set-if-edit-lines! i-f (append (take edit-lines y-edit-pos) (list (append (reverse (cdr (reverse current-line))) (list-ref edit-lines (+ y-edit-pos 1)))) (drop edit-lines (+ y-edit-pos 2)))) #t) (begin (set-if-edit-lines! i-f (replace edit-lines y-edit-pos (let ((new-line (take current-line x-edit-pos))) (if (char=? (last current-line) #\newline) (append new-line (list #\newline)) new-line)))) #t))))) (define delete-line (lambda (i-f) (let* ((x-edit-pos (if-x-edit-pos i-f)) (y-edit-pos (if-y-edit-pos i-f)) (edit-lines (if-edit-lines i-f)) (edit-lines-len (length edit-lines)) (current-line (list-ref edit-lines y-edit-pos))) (if (= edit-lines-len 1) (begin (set-if-edit-lines! i-f '(())) (set-if-x-edit-pos! i-f 0) (sync-if-edit-pos i-f)) (begin (set-if-edit-lines! i-f (remove edit-lines y-edit-pos)) (set-if-x-edit-pos! i-f 0) (set-if-y-edit-pos! i-f (min y-edit-pos (- edit-lines-len 2))) (sync-if-edit-pos i-f)))))) ;; delete END ;; ---------------------------------------------------------------------------- ;; ---------------------------------------------------------------------------- ;; goto ;; TODOO - fertig machen... (siehe #f) (define goto-begin-of-word-forward (lambda (i-f) (goto-next-forward i-f #\space #\newline) (goto-next-not-forward i-f #\space #\newline) #t)) (define goto-end-of-word-forward (lambda (i-f) #f)) (define goto-begin-of-word-backward (lambda (i-f) (if (and (goto-next-not-backward i-f #\space #\newline) (goto-next-backward i-f #\space #\newline)) (move-forward i-f)) #t)) (define goto-end-of-word-backward (lambda (i-f) #f)) (define goto-begin-of-line (lambda (i-f) (set-if-x-edit-pos! i-f 0) (sync-if-edit-pos i-f))) (define goto-end-of-line (lambda (i-f) (let ((x-edit-pos (if-x-edit-pos i-f)) (y-edit-pos (if-y-edit-pos i-f))) (call-with-values (lambda () (let* ((current-line (list-ref (if-edit-lines i-f) y-edit-pos))) (if (null? current-line) (set-if-x-edit-pos! i-f 0) (let ((len (length current-line)) (end-char (last current-line))) (set-if-x-edit-pos! i-f (if (char=? end-char #\newline) (- len 1) len)))) (edit-pos->if-pos i-f (if-x-edit-pos i-f) y-edit-pos))) (lambda (x-pos y-pos) (set-if-x-pos! i-f (- x-pos (if-x-offset i-f))) (set-if-y-pos! i-f (- y-pos (if-y-offset i-f))) (sync-if-edit-pos i-f)))))) (define goto-begin-of-first-line (lambda (i-f) (set-if-x-edit-pos! i-f 0) (set-if-y-edit-pos! i-f 0) (sync-if-edit-pos i-f))) (define goto-end-of-first-line (lambda (i-f) #f)) (define goto-begin-of-last-line (lambda (i-f) (set-if-x-edit-pos! i-f 0) (set-if-y-edit-pos! i-f (- (length (if-edit-lines i-f)) 1)) (sync-if-edit-pos i-f))) (define goto-end-of-last-line (lambda (i-f) #f)) ;; ------------------------------------------------------------------ ; wozu eigentlich? ;(define goto-end-of-if-line ; (lambda (i-f) ; #f)) ;; ------------------------------------------------------------------ (define goto-next-forward (lambda (i-f . chars) (if (move-forward i-f) (let loop () (let ((sign (sign-under-cursor i-f))) (if (and sign (memq sign chars)) #t (if (move-forward i-f) (loop) #f)))) #f))) (define goto-next-not-forward (lambda (i-f . chars) (if (move-forward i-f) (let loop () (let ((sign (sign-under-cursor i-f))) (if (and sign (not (memq sign chars))) #t (if (move-forward i-f) (loop) #f)))) #f))) (define goto-next-backward (lambda (i-f . chars) (if (move-backward i-f) (let loop () (let ((sign (sign-under-cursor i-f))) (if (and sign (memq sign chars)) #t (if (move-backward i-f) (loop) #f)))) #f))) (define goto-next-not-backward (lambda (i-f . chars) (if (move-backward i-f) (let loop () (let ((sign (sign-under-cursor i-f))) (if (and sign (not (memq sign chars))) #t (if (move-backward i-f) (loop) #f)))) #f))) ;; goto END ;; ---------------------------------------------------------------------------- ;; ---------------------------------------------------------------------------- ;; others (define toggle-insert (lambda (i-f) (set-if-insert-active! i-f (not (if-insert-active i-f))) (values #t #f))) ;; others END ;; ---------------------------------------------------------------------------- ;; behavior methods END ;;=============================================================================== ;;=============================================================================== ;; "mutate" functions and few others (define input-field-refresh (lambda (i-f) (really-send-input-field i-f 'refresh-all))) ;(define input-field-move-up ; (lambda (i-f) ; (let ((y-loc (if-y-loc i-f))) ; (if (> y-loc 1) ; (begin ; (paint-black i-f) ; (set-if-y-loc! i-f (- y-loc ; 1)) ; #t) ; #f)))) ;(define input-field-move-down ; (lambda (i-f) ; (let ((y-loc (if-y-loc i-f))) ; (if (< (+ y-loc (if-y-dim i-f)) ; (- (getmaxy (if-window i-f)) ; 1)) ; (begin ; (paint-black i-f) ; (set-if-y-loc! i-f (+ y-loc ; 1)) ; #t) ; #f)))) ;(define input-field-move-left ; (lambda (i-f) ; (let ((x-loc (if-x-loc i-f))) ; (if (> x-loc 1) ; (begin ; (paint-black i-f) ; (set-if-x-loc! i-f (- x-loc ; 1)) ; #t) ; #f)))) ;(define input-field-move-right ; (lambda (i-f) ; (let ((x-loc (if-x-loc i-f))) ; (if (< (+ x-loc (if-x-dim i-f)) ; (- (getmaxx (if-window i-f)) ; 1)) ; (begin ; (paint-black i-f) ; (set-if-x-loc! i-f (+ x-loc ; 1)) ; #t) ; #f)))) (define input-field-move (lambda (i-f x y) (let ((win (if-window i-f))) (if (and (> x 1) (> y 1) (< (+ x (if-x-dim i-f)) (getmaxx win)) (< (+ y (if-y-dim i-f)) (getmaxy win))) (begin (paint-black i-f) (set-if-x-loc! i-f x) (set-if-y-loc! i-f y) (refresh-all i-f)) #f)))) (define input-field-resize (lambda (i-f x y) (let ((win (if-window i-f))) (if (and (> x 0) (> y 0) (< (+ x (if-x-loc i-f)) (getmaxx win)) (< (+ y (if-y-loc i-f)) (getmaxy win))) (begin (paint-black i-f) (set-if-x-offset! i-f 0) (set-if-y-offset! i-f 0) (set-if-x-pos! i-f 0) (set-if-y-pos! i-f 0) (set-if-x-edit-pos! i-f 0) (set-if-y-edit-pos! i-f 0) (set-if-x-dim! i-f x) (set-if-y-dim! i-f y) (set-if-edit-lines! i-f (string->if-edit-lines i-f (input-field-text i-f))) (refresh-all i-f)) #f)))) (define input-field-toggle-x-scroll (lambda (i-f) (paint-black i-f) (set-if-x-offset! i-f 0) (set-if-y-offset! i-f 0) (set-if-x-pos! i-f 0) (set-if-y-pos! i-f 0) (set-if-x-edit-pos! i-f 0) (set-if-y-edit-pos! i-f 0) (set-if-x-scroll! i-f (not (if-x-scroll i-f))) (set-if-edit-lines! i-f (string->if-edit-lines i-f (input-field-text i-f))) (refresh-all i-f))) (define input-field-toggle-y-scroll (lambda (i-f) (paint-black i-f) (set-if-x-offset! i-f 0) (set-if-y-offset! i-f 0) (set-if-x-pos! i-f 0) (set-if-y-pos! i-f 0) (set-if-x-edit-pos! i-f 0) (set-if-y-edit-pos! i-f 0) (set-if-y-scroll! i-f (not (if-y-scroll i-f))) (set-if-edit-lines! i-f (string->if-edit-lines i-f (input-field-text i-f))) (refresh-all i-f))) (define restore-input-field (lambda (i-f) (set-if-edit-lines! i-f (string->if-edit-lines i-f (input-field-text i-f))) (sync-if-edit-pos i-f) (refresh-all i-f))) ;; mutate-functions END ;;=============================================================================== ;;=============================================================================== ;; helpfunctions (converter, predicates...) (define string->edit-lines (lambda (str) (let loop ((chars (string->list str))) (if (null? chars) '() (call-with-values (lambda () (split-after-first-newline chars)) (lambda (line chars) (cons line (loop chars)))))))) (define string->edit-lines-with-null (lambda (str) (let* ((edit-lines (let loop ((chars (string->list str))) (if (null? chars) '() (call-with-values (lambda () (split-after-first-newline chars)) (lambda (line chars) (cons line (loop chars))))))) (last-line (if (null? edit-lines) #f (last edit-lines)))) (if (and last-line (not (null? last-line)) (char=? (last last-line) #\newline)) (append edit-lines '(())) edit-lines)))) (define split-after-first-newline (lambda (chars) (let loop ((line '()) (chars chars)) (if (null? chars) (values (reverse line) chars) (let ((char (car chars)) (rest (cdr chars))) (if (char=? char #\newline) (values (reverse (cons char line)) rest) (loop (cons char line) rest))))))) (define edit-line->if-lines (lambda (i-f edit-line) (let ((x-dim (if-x-dim i-f)) (x-scroll (if-x-scroll i-f))) (if (or x-scroll (null? edit-line)) (list edit-line) (let loop ((edit-line edit-line)) (if (null? edit-line) '() (call-with-values (lambda () (split-if-line-from-edit-line x-dim edit-line)) (lambda (if-line edit-line) (cons if-line (loop edit-line)))))))))) (define edit-lines->if-lines (lambda (i-f edit-lines) (cat (map (lambda (edit-line) (edit-line->if-lines i-f edit-line)) edit-lines)))) (define split-if-line-from-edit-line (lambda (x-dim edit-line) (let loop ((if-line '()) (rest edit-line) (space-left x-dim)) (if (null? rest) (values (reverse if-line) rest) (let ((char (car rest))) (cond ((char=? char #\newline) (values (reverse (cons char if-line)) (cdr rest))) ((zero? space-left) (values (reverse if-line) rest)) (else (loop (cons char if-line) (cdr rest) (- space-left 1))))))))) (define if-lines->edit-lines (lambda (if-lines) (let loop ((rest if-lines)) (if (null? rest) '() (call-with-values (lambda () (split-edit-line-from-if-lines rest)) (lambda (edit-line rest) (cons edit-line (loop rest)))))))) (define split-edit-line-from-if-lines (lambda (if-lines) (let loop ((edit-line '()) (rest if-lines)) (if (null? rest) (values (reverse edit-line) '()) (let ((rev-line (reverse (car rest)))) (if (null? rev-line) (values '() (cdr rest)) (if (char=? (car rev-line) #\newline) (values (reverse (append rev-line edit-line)) (cdr rest)) (loop (append rev-line edit-line) (cdr rest))))))))) (define string->if-edit-lines (lambda (i-f string) (let* ((edit-lines (string->edit-lines-with-null string)) (if-lines (edit-lines->if-lines i-f edit-lines)) (if-lines-cut (if (if-y-scroll i-f) if-lines (take if-lines (if-y-dim i-f))))) (if-lines->edit-lines if-lines-cut)))) (define if->edit-pos (lambda (i-f) (let ((x-pos (+ (if-x-offset i-f) (if-x-pos i-f))) (y-pos (+ (if-y-offset i-f) (if-y-pos i-f))) (x-scroll (if-x-scroll i-f))) (if x-scroll (values x-pos y-pos) (let loop ((edit-lines (if-edit-lines i-f)) (y-edit-pos 0) (y-pos y-pos)) (if (null? edit-lines) (let ((y-edit-pos (- y-edit-pos 1))) (values (length (list-ref (if-edit-lines i-f) y-edit-pos)) y-edit-pos)) (let* ((edit-line (car edit-lines)) (num-if-lines (length (edit-line->if-lines i-f edit-line)))) (if (< y-pos num-if-lines) (values (+ (* y-pos (if-x-dim i-f)) x-pos) y-edit-pos) (loop (cdr edit-lines) (+ y-edit-pos 1) (- y-pos num-if-lines)))))))))) (define edit-pos->if-pos (lambda (i-f x-edit-pos y-edit-pos) (if (if-x-scroll i-f) (values x-edit-pos y-edit-pos) (let loop ((edit-lines (if-edit-lines i-f)) (y-edit-pos y-edit-pos) (y-pos 0)) (if (null? edit-lines) 'error--edit-pos->if-pos (if (zero? y-edit-pos) (let ((x-dim (if-x-dim i-f))) (values (modulo x-edit-pos x-dim) (+ y-pos (quotient x-edit-pos x-dim)))) (loop (cdr edit-lines) (- y-edit-pos 1) (+ y-pos (length (edit-line->if-lines i-f (car edit-lines))))))))))) ;; ---------------------------------------------------------------------------- ;; legalize-position (define legalize-position (lambda (i-f) (let* ((x-edit-pos (if-x-edit-pos i-f)) (y-edit-pos (if-y-edit-pos i-f)) (current-line (list-ref (if-edit-lines i-f) y-edit-pos)) (current-line-len (length current-line))) (if (or (> x-edit-pos current-line-len) (and (> current-line-len 0) (= x-edit-pos current-line-len) (char=? (last current-line) #\newline))) (goto-end-of-line i-f))) #t)) (define legal-offsets? (lambda (i-f) (let ((x (if-x-pos i-f)) (y (if-y-pos i-f))) (and (>= x 0) (< x (if-x-dim i-f)) (>= y 0) (< y (if-y-dim i-f)))))) (define legalize-offsets (lambda (i-f) (let ((x-pos (if-x-pos i-f)) (x-offset (if-x-offset i-f)) (x-dim (if-x-dim i-f)) (y-pos (if-y-pos i-f)) (y-offset (if-y-offset i-f)) (y-dim (if-y-dim i-f))) (if (< x-pos 0) (begin (set! x-offset (+ x-offset x-pos)) (set! x-pos 0))) (if (> (+ x-pos 1) x-dim) (let ((dx (- (+ x-pos 1) x-dim))) (set! x-offset (+ x-offset dx)) (set! x-pos (- x-pos dx)))) (if (< y-pos 0) (begin (set! y-offset (+ y-offset y-pos)) (set! y-pos 0))) (if (> (+ y-pos 1) y-dim) (let ((dy (- (+ y-pos 1) y-dim))) (set! y-offset (+ y-offset dy)) (set! y-pos (- y-pos dy)))) (set-if-x-pos! i-f x-pos) (set-if-x-offset! i-f x-offset) (set-if-y-pos! i-f y-pos) (set-if-y-offset! i-f y-offset) #t))) ;; legalize-position END ;; ---------------------------------------------------------------------------- ;; ---------------------------------------------------------------------------- ;; predicates (define first-line? (lambda (i-f) (zero? (if-y-edit-pos i-f)))) (define last-line? (lambda (i-f) (= (+ (if-y-edit-pos i-f) 1) (length (if-edit-lines i-f))))) (define begin-of-line? (lambda (i-f) (zero? (if-x-edit-pos i-f)))) (define end-of-line? (lambda (i-f) (let* ((x-edit-pos (if-x-edit-pos i-f)) (y-edit-pos (if-y-edit-pos i-f)) (edit-line (list-ref (if-edit-lines i-f) y-edit-pos))) (or (= x-edit-pos (length edit-line)) (char=? (list-ref edit-line x-edit-pos) #\newline))))) (define left-border? (lambda (i-f) (= (if-x-pos i-f) 0))) (define right-border? (lambda (i-f) (= (if-x-pos i-f) (- (if-x-dim i-f) 1)))) (define lower-border? (lambda (i-f) (= (if-y-pos i-f) (- (if-y-dim i-f) 1)))) (define upper-border? (lambda (i-f) (= (if-y-pos i-f) 0))) ;; predicates END ;; ---------------------------------------------------------------------------- ;; ---------------------------------------------------------------------------- ;; selectors (define sign-at-xy (lambda (i-f x y) #f)) (define sign-under-cursor (lambda (i-f) (let* ((x-edit-pos (if-x-edit-pos i-f)) (y-edit-pos (if-y-edit-pos i-f)) (current-line (list-ref (if-edit-lines i-f) y-edit-pos)) (current-line-len (length current-line))) (if (< x-edit-pos current-line-len) (list-ref current-line x-edit-pos) #f)))) (define sign-before-cursor (lambda (i-f) #f)) (define sign-behind-cursor (lambda (i-f) #f)) ;; selectors END ;; ---------------------------------------------------------------------------- ;; helpfunctions END ;;=============================================================================== ;;=============================================================================== ;; "primitives" (define caddddr (lambda (x) (car (cddddr x)))) (define last (lambda (lst) (if (null? lst) 'error--last (car (reverse lst))))) (define fill-up (lambda (lst len elem) (append lst (let loop ((n (- len (length lst)))) (if (< n 0) 'error--fill-up (if (zero? n) '() (cons elem (loop (- n 1))))))))) (define cat (lambda (lst-lst) (if (null? lst-lst) '() (append (car lst-lst) (cat (cdr lst-lst)))))) (define split (lambda (lst n) (let loop ((fst '()) (scnd lst) (n n)) (if (or (null? scnd) (zero? n)) (values (reverse fst) scnd) (loop (cons (car scnd) fst) (cdr scnd) (- n 1)))))) (define remove (lambda (lst pos) (append (take lst pos) (drop lst (+ pos 1))))) (define insert (lambda (lst n elem) (if (zero? n) (cons elem lst) (cons (car lst) (insert (cdr lst) (- n 1) elem))))) (define replace (lambda (lst n elem) (if (zero? n) (cons elem (if (null? lst) lst (cdr lst))) (cons (car lst) (replace (cdr lst) (- n 1) elem))))) (define take (lambda (lst n) (if (or (null? lst) (zero? n)) '() (cons (car lst) (take (cdr lst) (- n 1)))))) (define drop (lambda (lst n) (if (or (null? lst) (zero? n)) lst (drop (cdr lst) (- n 1))))) ;; "primitives" END ;;===============================================================================