]> git.donarmstrong.com Git - lilypond.git/blobdiff - scm/new-markup.scm
remove tail, filter-list, filter-out-list,
[lilypond.git] / scm / new-markup.scm
index 5c86dd4ca30c9aedaee20eb6063f79b0e78eb5b6..f04cf768d8e3b980ee2089bf75e1b7d922e248ff 100644 (file)
@@ -45,24 +45,21 @@ for the reader.
 
 " ; " 
 
-;; debugging.
-
-(define (mydisplay x) (display x) (newline) x)
-
 (define-public (simple-markup grob props . rest)
   (Text_item::text_to_molecule grob props (car rest))
   )
 
+
 (define-public (stack-molecule-line space molecules)
   (if (pair? molecules)
       (if (pair? (cdr molecules))
          (let* (
                 (tail (stack-molecule-line  space (cdr molecules)))
                 (head (car molecules))
-                (xoff (+ space (cdr (ly:get-molecule-extent head X))))
+                (xoff (+ space (cdr (ly:molecule-get-extent head X))))
                 )
            
-           (ly:add-molecule
+           (ly:molecule-add
             head
             (ly:molecule-translate-axis tail xoff X))
          )
@@ -78,11 +75,11 @@ for the reader.
 
 (define (combine-molecule-list lst)
   (if (null? (cdr lst)) (car lst)
-      (ly:add-molecule (car lst) (combine-molecule-list (cdr lst)))
+      (ly:molecule-add (car lst) (combine-molecule-list (cdr lst)))
       ))
 
 (define-public (combine-markup grob props . rest)
-  (ly:add-molecule
+  (ly:molecule-add
    (interpret-markup grob props (car rest))
    (interpret-markup grob props (cadr rest))))
   
@@ -104,6 +101,14 @@ for the reader.
     ))
 
 
+(define-public (finger-markup grob props . rest)
+  (interpret-markup grob
+                   (cons (list '(font-relative-size . -3)
+                               '(font-family . number))
+                               props)
+                   (car rest)))
+
+
 (define-public fontsize-markup (set-property-markup 'font-relative-size))
 (define-public magnify-markup (set-property-markup 'font-magnification))
 
@@ -111,6 +116,8 @@ for the reader.
   (font-markup 'font-series 'bold))
 (define-public number-markup
   (font-markup 'font-family 'number))
+(define-public roman-markup
+  (font-markup 'font-family 'roman))
 
 
 (define-public huge-markup
@@ -136,12 +143,37 @@ for the reader.
    (map (lambda (x) (interpret-markup grob props x)) (car rest)))
   )
 
+(define-public (dir-column-markup grob props . rest)
+  "Make a column of args, going up or down, depending on DIRECTION."
+  (let*
+      (
+       (dir (cdr (chain-assoc 'direction props)))
+       )
+    (stack-lines
+     (if (number? dir) dir -1)
+     0.0 (cdr (chain-assoc 'baseline-skip props))
+     (map (lambda (x) (interpret-markup grob props x)) (car rest)))
+    ))
+
+(define-public (center-markup grob props . rest)
+  (let*
+    (
+     (mols (map (lambda (x) (interpret-markup grob props x)) (car rest)))
+     (cmols (map (lambda (x) (ly:molecule-align-to! x X CENTER)) mols))
+     )
+    
+    (stack-lines
+     -1 0.0 (cdr (chain-assoc 'baseline-skip props))
+     mols)
+    ))
+
 (define-public (musicglyph-markup grob props . rest)
   (ly:find-glyph-by-name
    (ly:get-font grob (cons '((font-family . music)) props))
    (car rest))
   )
 
+
 (define-public (lookup-markup grob props . rest)
   "Lookup a glyph by name."
   (ly:find-glyph-by-name
@@ -163,7 +195,85 @@ for the reader.
                              (car rest) Y)
   )
 
-(define-public (normal-size-superscript-markup grob props . rest)
+
+(define-public (note-markup grob props . rest)
+  "Syntax: \\note #LOG #DOTS #DIR. "
+  (let*
+      (
+       (log (car rest))
+       (dot-count (cadr rest))
+       (dir (caddr rest))
+       (font (ly:get-font grob (cons '((font-family .  music)) props)))
+       (stemlen (max 3 (- log 1)))
+       (headgl
+       (ly:find-glyph-by-name font (string-append "noteheads-" (number->string (min log 2)))))
+
+       (stemth 0.13)
+       (stemy (* dir stemlen))
+       (attachx (if (> dir 0) (- (cdr (ly:molecule-get-extent headgl X)) stemth)
+                   0))
+       (attachy (* dir 0.28))
+       (stemgl (if (> log 0)
+                  (ly:round-filled-box (cons
+                                    (cons attachx (+ attachx  stemth))
+                                    (cons (min stemy attachy)
+                                          (max stemy attachy)))
+                                   (/ stemth 3)
+                                   ) #f))
+       (dot (ly:find-glyph-by-name font "dots-dot"))
+       (dotwid  (interval-length (ly:molecule-get-extent dot X)))
+       (dots (if (> dot-count 0)
+                (reduce-no-unit        ; TODO: use reduce.
+                 (lambda (x y)
+                   (ly:molecule-add x y))
+                 (map (lambda (x)
+                        (ly:molecule-translate-axis
+                         dot  (* (+ 1 (* 2 x)) dotwid) X) )
+                      (iota dot-count 1)))
+                #f
+                ))
+       
+       (flaggl (if (> log 2)
+                  (ly:molecule-translate
+                   (ly:find-glyph-by-name
+                    font
+                    (string-append "flags-"
+                                   (if (> dir 0) "u" "d")
+                                   (number->string log)
+                                   ))
+                   (cons (+ attachx (/ stemth 2)) stemy))
+
+                   #f)))
+    
+    (if flaggl
+       (set! stemgl (ly:molecule-add flaggl stemgl)))
+
+    (if (ly:molecule? stemgl)
+       (set! stemgl (ly:molecule-add stemgl headgl))
+        (set! stemgl headgl)
+       )
+    
+    (if (ly:molecule? dots)
+       (set! stemgl
+             (ly:molecule-add
+              (ly:molecule-translate-axis
+               dots
+               (+
+                (if (and (> dir 0) (> log 2))
+                    (* 1.5 dotwid) 0)
+                ;; huh ? why not necessary?
+               ;(cdr (ly:molecule-get-extent headgl X))
+                     dotwid
+                )
+               X)
+              stemgl 
+              )
+             ))
+
+    stemgl
+    ))
+
+(define-public (normal-size-super-markup grob props . rest)
   (ly:molecule-translate-axis (interpret-markup
                               grob
                               props (car rest))
@@ -197,6 +307,35 @@ for the reader.
                              Y)
   )
 
+(define-public (normal-size-sub-markup grob props . rest)
+  (ly:molecule-translate-axis (interpret-markup
+                              grob
+                              props (car rest))
+                             (* -0.5 (cdr (chain-assoc 'baseline-skip props)))
+                             Y)
+  )
+
+(define-public (hbracket-markup grob props . rest)
+  (let*
+      (
+       (th 0.1) ;; todo: take from GROB.
+       (m (interpret-markup grob props (car rest)))
+       )
+
+    (bracketify-molecule m X th (* 2.5 th) th)  
+))
+
+(define-public (bracket-markup grob props . rest)
+  (let*
+      (
+       (th 0.1) ;; todo: take from GROB.
+       (m (interpret-markup grob props (car rest)))
+       )
+
+    (bracketify-molecule m Y th (* 2.5 th) th)  
+))
+
+
 ;; todo: fix negative space
 (define (hspace-markup grob props . rest)
   "Syntax: \\hspace NUMBER."
@@ -224,11 +363,10 @@ for the reader.
        (fs (cdr (chain-assoc 'font-relative-size props)))
        (entry (cons 'font-relative-size (- fs 1)))
        )
-  (interpret-markup
-   grob (cons (list entry) props)
-   (car rest))
-
-  ))
+    (interpret-markup
+     grob (cons (list entry) props)
+     (car rest))
+    ))
 
 (define-public (bigger-markup  grob props . rest)
   "Syntax: \\bigger MARKUP"
@@ -283,30 +421,45 @@ for the reader.
   )
   (and (list? arg) (markup-list-inner? arg)))
 
-
 (define (markup-argument-list? signature arguments)
+  "Typecheck argument list."
   (if (and (pair? signature) (pair? arguments))
       (and ((car signature) (car arguments))
           (markup-argument-list? (cdr signature) (cdr arguments)))
       (and (null? signature) (null? arguments)))
   )
 
+
+(define (markup-argument-list-error signature arguments number)
+  "return (ARG-NR TYPE-EXPECTED ARG-FOUND) if an error is detected, or
+#f is no error found.
+"
+  (if (and (pair? signature) (pair? arguments))
+      (if (not ((car signature) (car arguments)))
+         (list number (type-name (car signature)) (car arguments))
+         (markup-argument-list-error (cdr signature) (cdr arguments) (+ 1 number)))
+      #f
+  ))
+
 ;;
 ;; full recursive typecheck.
 ;;
 (define (markup-typecheck? arg)
-  (and (pair? arg)
+  (or (string? arg)
+      (and (pair? arg)
        (markup-function? (car arg))
        (markup-argument-list?
        (object-property (car arg) 'markup-signature)
        (cdr arg))
   ))
+)
 
 ;; 
 ;; typecheck, and throw an error when something amiss.
 ;; 
 (define (markup-thrower-typecheck arg)
   (cond
+   ((string? arg) #t)
    ((not (pair? arg))
     (throw 'markup-format "Not a pair" arg)
     )
@@ -321,9 +474,13 @@ for the reader.
    #t
   )
 
+;;
+;; good enough if you only  use make-XXX-markup functions.
+;; 
 (define (cheap-markup? x)
-  (and (pair? x)
-       (markup-function? (car x)))
+  (or (string? x)
+      (and (pair? x)
+          (markup-function? (car x))))
 )
 
 ;;
@@ -331,8 +488,7 @@ for the reader.
 ;; 
 (define markup?  cheap-markup?)
 
-
-(define markup-function-list
+(define markup-functions-and-signatures
   (list
 
    ;; abs size
@@ -350,20 +506,28 @@ for the reader.
 
    ;; 
    (cons sub-markup (list markup?))
-   (cons super-markup (list markup?))
+   (cons normal-size-sub-markup (list markup?))
    
+   (cons super-markup (list markup?))
+   (cons normal-size-super-markup (list markup?))
+
+   (cons finger-markup (list markup?))
    (cons bold-markup (list markup?))
    (cons italic-markup (list markup?))
-   
+   (cons roman-markup (list markup?))
    (cons number-markup (list markup?))
+   (cons hbracket-markup  (list markup?))
+   (cons bracket-markup  (list markup?))
+   (cons note-markup (list integer? integer? ly:dir?))
    
    (cons column-markup (list markup-list?))
+   (cons dir-column-markup (list markup-list?))
+   (cons center-markup (list markup-list?))
    (cons line-markup  (list markup-list?))
 
    (cons combine-markup (list markup? markup?))
    (cons simple-markup (list string?))
    (cons musicglyph-markup (list scheme?))
-   
    (cons translate-markup (list number-pair? markup?))
    (cons override-markup (list pair? markup?))
    (cons char-markup (list integer?))
@@ -384,7 +548,9 @@ for the reader.
        (set-object-property! (car x) 'markup-signature (cdr x))
        (set-object-property! (car x) 'markup-keyword (markup-signature-to-keyword (cdr x)))
        )
-     markup-function-list)
+     markup-functions-and-signatures)
+
+(define-public markup-function-list (map car markup-functions-and-signatures))
 
 
 ;; construct a
@@ -395,6 +561,8 @@ for the reader.
 ;; Invalid argument 4 : expecting a BLADIBLA, found: (list-ref 4 args)
 ;;
 ;; right now, you get the entire argument list.
+
+
 (define (make-markup-maker  entry)
   (let*
        ((foo-markup (car entry))
@@ -404,15 +572,75 @@ for the reader.
         )
       
       `(define (,(string->symbol make-name) . args)
-        (if (markup-argument-list? ,signature args)
+        (let*
+            (
+             (arglen (length  args))
+             (siglen (length ,signature))
+             (error-msg
+              (if (and (> 0 siglen) (> 0 arglen))
+                  (markup-argument-list-error ,signature args 1)))
+             
+             )
+        
+        (if (or (not (= arglen siglen)) (< siglen 0) (< 0 arglen))
+            (scm-error 'markup-format ,make-name "Expect ~A arguments for ~A. Found ~A: ~S"
+                       (list (length ,signature)
+                             ,make-name
+                             (length args)
+                             args) #f))
+        (if error-msg
+            (scm-error 'markup-format ,make-name "Invalid argument in position ~A\n Expect: ~A\nFound: ~S." error-msg #f)
+            
             (cons ,foo-markup args)
-            (scm-error 'markup-format ,make-name "Invalid argument list: ~A." (list args) #f)
             )))
     )
+)
 
 
+
+(define (make-markup markup-function make-name signature args)
+  
+  " Construct a markup object from MARKUP-FUNCTION and ARGS. Typecheck
+against SIGNATURE, reporting MAKE-NAME as the user-invoked function.
+"
+
+  (let*
+      (
+       (arglen (length args))
+       (siglen (length signature))
+       (error-msg
+       (if (and (> siglen 0) (> arglen 0))
+           (markup-argument-list-error signature args 1)))
+       )
+
+
+    (if (or (not (= arglen siglen)) (< siglen 0) (< arglen 0))
+       (scm-error 'markup-format make-name "Expect ~A arguments for ~A. Found ~A: ~S"
+                  (list siglen
+                        make-name
+                        arglen
+                        args) #f))
+
+    (if error-msg
+       (scm-error 'markup-format make-name "Invalid argument in position ~A\nExpect: ~A\nFound: ~S." error-msg #f)
+       
+       (cons markup-function  args)
+       )))
+
+(define (make-markup-maker entry)
+  (let* (
+        (name (symbol->string (procedure-name (car entry))))
+        (make-name  (string-append "make-" name))
+        (signature (object-property (car entry) 'markup-signature))
+        )
+  
+    `(define-public (,(string->symbol make-name) . args)
+       (make-markup ,(car entry) ,make-name ,(cons 'list signature)  args)
+       ))
+  )
+
 (eval
- (cons 'begin (map make-markup-maker markup-function-list))
+ (cons 'begin (map make-markup-maker markup-functions-and-signatures))
  markup-module
  )
 
@@ -429,36 +657,67 @@ for the reader.
 
 
 (define-public (brew-new-markup-molecule grob)
-  (interpret-markup grob
-                   (Font_interface::get_property_alist_chain grob)
-                   (ly:get-grob-property grob 'text)
-                   )
-  )
+  (let*
+      ((t (ly:get-grob-property grob 'text))
+       (chain (Font_interface::get_property_alist_chain grob)))
+    (if (markup? t)
+       (interpret-markup grob  chain t)
+       (Text_item::text_to_molecule grob t chain)
+       )))
 
-(define-public empty-markup `(,simple-markup ""))
+(define-public empty-markup (make-simple-markup ""))
 
 (define (interpret-markup  grob props markup)
-  (let*
-      (
-       (func (car markup))
-       (args (cdr markup))
-       )
-    
-    (apply func (cons grob (cons props args)) )
-    ))
+  (if (string? markup)
+      (simple-markup grob props markup)
+      (let*
+         (
+          (func (car markup))
+          (args (cdr markup))
+          )
+       
+       (apply func (cons grob (cons props args)) )
+       )))
+
+
+;;;;;;;;;;;;;;;;
+;; utility
+
+(define (markup-join markups sep)
+  "Return line-markup of MARKUPS, joining them with markup SEP"
+  (if (pair? markups)
+      (make-line-markup (list-insert-separator markups sep))
+      empty-markup))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+(if #f
+   (define (typecheck-with-error x)
+     (catch
+      'markup-format
+      (lambda () (markup? x))
+      (lambda (key message arg)
+       (display "\nERROR: markup format error: \n")
+       (display message)
+       (newline)
+       (write arg (current-output-port))
+       )
+      )))
+
 ;; test make-foo-markup functions
 (if #f
-(begin
-  (make-line-markup (make-simple-markup "FOO")
-                   (make-simple-markup "foo")
-                   )
+    (begin
+      (newline)
+      (newline)
+      (display (make-line-markup (list (make-simple-markup "FOO"))))
+      
+      (make-line-markup (make-simple-markup "FOO"))
+      (make-line-markup (make-simple-markup "FOO") (make-simple-markup "foo"))
+      (make-raise-markup "foo" (make-simple-markup "foo"))
+      )
+    )
 
-  (make-teeny-markup (make-simple-markup 1)))
-)
 
 ;;
 ;; test typecheckers. Not wholly useful, because errors are detected
@@ -470,17 +729,7 @@ for the reader.
    ;; To get error messages, see above to install the alternate
    ;; typecheck routine for markup?.
    
-   (define (typecheck-with-error x)
-     (catch
-      'markup-format
-      (lambda () (markup? x))
-      (lambda (key message arg)
-       (display "\nERROR: markup format error: \n")
-       (display message)
-       (newline)
-       (write arg (current-output-port))
-       )
-      ))
+
 
    (display (typecheck-with-error `(,simple-markup "foobar")))
    (display (typecheck-with-error `(,simple-markup "foobar")))