scsh-ncurses/scheme/input-fields.scm

1462 lines
36 KiB
Scheme
Raw Normal View History

;; 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
;;===============================================================================