;;;;
;;;; e d i t o r . s t k		-- A small editor to create enhanced
;;;;					   text (used for Help page construction)
;;;;
;;;; Copyright © 1993-1999 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
;;;; 
;;;; Permission to use, copy, modify, distribute,and license this
;;;; software and its documentation for any purpose is hereby granted,
;;;; provided that existing copyright notices are retained in all
;;;; copies and that this notice is included verbatim in any
;;;; distributions.  No written agreement, license, or royalty fee is
;;;; required for any of the authorized uses.
;;;; This software is provided ``AS IS'' without express or implied
;;;; warranty.
;;;;
;;;; This software is a derivative work of other copyrighted softwares; the
;;;; copyright notices of these softwares are placed in the file COPYRIGHTS
;;;;
;;;;           Author: Erick Gallesio [eg@kaolin.unice.fr]
;;;;    Creation date:  6-Dec-1993 17:25
;;;; Last file update:  3-Sep-1999 19:50 (eg)

(select-module Tk)
(provide "editor")

;;;;
;;;; Font definition
;;;;

(define stk:STF-signature "STF-0.1")

(define stk:normal-font "*-Courier-Medium-R-Normal-*-120-*")

(define stk:all-fonts `(
   (normal		,stk:normal-font)
   (fixed		"fixed")
   (big			"-*-times-*-r-*-*-*-240-*-*-*-*-*-*")
   (roman-12		"-*-times-*-r-*-*-*-120-*-*-*-*-*-*")
   (roman-14		"-*-times-*-r-*-*-*-140-*-*-*-*-*-*")
   (roman-16		"-*-times-*-r-*-*-*-160-*-*-*-*-*-*")
   (roman-18		"-*-times-*-r-*-*-*-180-*-*-*-*-*-*")
   (italic-12		"-*-times-*-i-*-*-*-120-*-*-*-*-*-*")
   (italic-14		"-*-times-*-i-*-*-*-140-*-*-*-*-*-*")
   (italic-16		"-*-times-*-i-*-*-*-160-*-*-*-*-*-*")
   (italic-18		"-*-times-*-i-*-*-*-180-*-*-*-*-*-*")
   (bold-12		"-*-helvetica-bold-r-*-*-*-120-*-*-*-*-*-*")
   (bold-14		"-*-helvetica-bold-r-*-*-*-140-*-*-*-*-*-*")
   (bold-16		"-*-helvetica-bold-r-*-*-*-160-*-*-*-*-*-*")
   (bold-18		"-*-helvetica-bold-r-*-*-*-180-*-*-*-*-*-*")
   (bold-italic-12	"-*-helvetica-bold-o-*-*-*-120-*-*-*-*-*-*")
   (bold-italic-14	"-*-helvetica-bold-o-*-*-*-140-*-*-*-*-*-*")
   (bold-italic-16	"-*-helvetica-bold-o-*-*-*-160-*-*-*-*-*-*")
   (bold-italic-18	"-*-helvetica-bold-o-*-*-*-180-*-*-*-*-*-*")
   (tty-12		"-adobe-courier-medium-*-*-*-*-120-*-*-*-*-*-*")
   (tty-14		"-adobe-courier-medium-*-*-*-*-140-*-*-*-*-*-*")
   (tty-16		"-adobe-courier-medium-*-*-*-*-160-*-*-*-*-*-*")
   (tty-18		"-adobe-courier-medium-*-*-*-*-180-*-*-*-*-*-*")))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; Fonts utilities
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (stk:unset-tags editor-window start end)
  (for-each (lambda (tag) 
	      (editor-window 'tag 'remove (car tag) start end))
	    stk:all-fonts))
  
(define (stk:set-font editor-window font start end)
  ;; Be sure this tag exists
  (editor-window 'tag 'conf font :font (cadr (assoc font stk:all-fonts)))
  ;; Delete all the tags associated to this range
  (stk:unset-tags editor-window start end)
  ;; Set a new tag for this character range
  (editor-window 'tag 'add font start end))

(define (stk:set-underline editor-window start end)
  (editor-window 'tag 'conf 'underline :underline #t)
  (editor-window 'tag 'add 'underline start end))

(define (stk:fontify-selection editor-window font)
  (catch
     (stk:set-font editor-window 
		   font 
		   (editor-window 'index 'sel.first)
		   (editor-window 'index 'sel.last))))

(define (stk:underline-selection editor-window value)
  (catch
     (let ((start (editor-window 'index 'sel.first))
	   (end   (editor-window 'index 'sel.last)))
       ;; Remove all underlining information in this area
       (editor-window 'tag 'remove 'underline start end)
       ;; Set underline if value is #t
       (when value (stk:set-underline editor-window start end)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; Scheme Text Format (STF) management
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (stk:get-STF editor-window)
  (list stk:STF-signature
	(editor-window 'get "1.0" 'end)
	(let ((l '()))
	  (for-each (lambda (t)
		      (let ((tags (editor-window 'tag 'range (car t))))
			(unless (null? tags)
			   (set! l (cons (list (car t) tags) l)))))
		    (cons `(underline #f) stk:all-fonts))
	  l)))

(define (stk:set-STF editor-window STF)
  (let ((text (cadr STF)) (fmts (caddr STF)))
    ;; First insert new text
    (editor-window 'delete "1.0" 'end)
    (editor-window 'insert "1.0" text)
    (editor-window 'mark 'set 'insert "1.0")
    ;; And now enhence it
    (for-each (lambda (t) 
		(do ((l (cadr t) (cddr l)))
		    ((null? l))
		  (if (eqv? (car t) 'underline)
		      (stk:set-underline editor-window (car l) (cadr l))
		      (stk:set-font editor-window (car t) (car l) (cadr l)))))
	      fmts))
  (update))
  
(define (stk:write-file editor-window file)
  (with-output-to-file file 
    (lambda ()
      (format #t ";;;; ~S\n" stk:STF-signature)
      (format #t "~S\n" (stk:get-STF editor-window)))))


(define (stk:write-file-ascii editor-window file)
  (with-output-to-file file 
    (lambda ()
      (format #t "~A" (editor-window 'get "1.0" 'end)))))

(define (stk:read-file editor-window file)
  (with-input-from-file file
      (lambda ()
	(let ((first-line (read-line)))
	  (if (string=? first-line (format #f ";;;; ~S" stk:STF-signature))
	      ;; File is a STF file
	      (stk:set-STF editor-window (read))
	      ;; File must be read as a "normal" file
	      (begin
		(editor-window 'delete "1.0" 'end)
		(do ((l first-line (read-line)))
		    ((eof-object? l))
		  (editor-window 'insert 'end l)
		  (editor-window 'insert 'end "\n"))
		(editor-window 'mark 'set 'insert "1.0")))))))

(define (stk:get-filename toplevel) ; return the content of the file name  entry
  (let ((entry (string->widget (& toplevel ".bt.e"))))
    (entry 'get)))

(define (stk:set-filename toplevel filename)
  (let ((entry (string->widget (& toplevel ".bt.e"))))
    (entry 'delete 0 'end)
    (entry 'insert 0 filename)))
	

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; Interface
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (stk:make-editor name  . exit_code)
  (let* ((top 	     (toplevel name))
	 (menu-bar   (frame     (& name ".mb") :bd 2 :relief "groove"))
	 (bottom     (frame     (& name ".bt")))
	 (text-area  (frame     (& name ".ta")))
	 (exit_code  (if (null? exit_code) `(destroy ,top) (car exit_code)))
	 (the-editor ()))

    ;;
    ;; Window manager management
    ;; 
    (wm 'maxsize name 1000 800)
    (wm 'protocol name "WM_DELETE_WINDOW" exit_code)
	
    ;;
    ;; Text area frame
    ;;
    (pack [scrollbar (& text-area ".sc") :orient "vert" 
		     			 :bd 2
					 :relief "groove"
		     			 :command (format #f "~A 'yview" 
							  (& text-area ".ed"))]
	  :side "left" :fill "y")
    (pack [text (& text-area ".ed") :padx 4 
				    :pady 4
				    :bd 2
				    :wrap "word"
				    :relief "groove"
				    :yscroll (format #f "~A 'set"
						     (& text-area ".sc"))]
	  :side "right" :expand #t :fill "both")

    (set! the-editor (string->widget (& text-area ".ed")))

    ;;
    ;; Menu Creation
    ;;

    (let* ((File (menubutton (& menu-bar ".file") 
			     :text "File"
			     :padx 10
			     :menu (& menu-bar ".file.m")))
	   (m	 (eval (menu (& menu-bar ".file.m")))))

      (m 'add 'command 
	      :label "  Read  "    
	      :command `(stk:read-file ,the-editor (stk:get-filename ,top)))
      (m 'add 'command 
	      :label "  Save  "
	      :command `(stk:write-file ,the-editor (stk:get-filename ,top)))
      (m 'add 'command 
	      :label "  Save Ascii  "
	      :command `(stk:write-file-ascii ,the-editor (stk:get-filename ,top)))
      (m 'add 'separator)
      (m 'add 'command :label "  Quit  " :command exit_code)
      
      (pack File :side "left"))

    (let* ((Font (menubutton (& menu-bar ".font")		       
			     :text "Font" 
			     :padx 10
			     :menu (& menu-bar ".font.m")))
	    (m    (eval (menu (& menu-bar ".font.m")))))

      (for-each (lambda(font)
		  (m 'add 'command 
		     	  :label    (car font)
			  :font     (cadr font)
			  :command `(stk:fontify-selection ,the-editor
							   ',(car font))))
		stk:all-fonts)
      (m 'add 'separator)
      (m 'add 'command
	      :label "Underline"    
	      :command `(stk:underline-selection ,the-editor #t))
      (m 'add 'command 
	      :label "No underline"
	      :command `(stk:underline-selection ,the-editor #f))

      (pack Font :side "left"))

    ;;
    ;; Bottom frame
    ;;
    (pack [label (& bottom ".l") :text "File name" :padx 10] :side "left")
    (pack [entry (& bottom ".e") :relief "ridge"] :side "left" :expand #t :fill "x")

    ;;
    ;; Pack everybody
    ;;
    (pack menu-bar  :fill "x")
    (pack text-area :expand #t :fill "both")
    (pack bottom    :fill "x" :ipady 4 :ipadx 10)))


;; A simple editor accessible from prompt
(define (ed . file)
  (require "editor")
  (let ((editor-name (gensym ".editor")))
    (stk:make-editor editor-name)
    (unless (null? file)
       (stk:read-file (string->widget (& editor-name ".ta.ed")) (car file))
       (stk:set-filename editor-name (car file)))))