From 74b4c9351b01381f0dc1d6d4688dcd845fc59720 Mon Sep 17 00:00:00 2001
From: Marc Hohl <marc@hohlart.de>
Date: Sat, 27 Oct 2012 22:22:25 +0200
Subject: [PATCH] Allows optional octavation for clefs

Clef specifications like \clef "G_(8)" or
\clef "bass^[15]" are supported.

A new property clefOctavationStyle (and its cue
clef couterpart cueClefOctavationStyle) is introduced.
When set to 'default, the octavation number is displayed
as before; 'parenthesized calls for parenthesized numbers
and 'bracketed used brackets around the number.

Furthermore, a scheme formatter function is used for
displaying the ocatavation number, so can be customized
more easily.
---
 input/regression/clef-optional-octavation.ly  | 15 +++++
 .../cue-clef-optional-octavation.ly           | 27 ++++++++
 lily/clef-engraver.cc                         | 10 ++-
 lily/cue-clef-engraver.cc                     | 10 ++-
 ly/engraver-init.ly                           |  2 +
 scm/define-context-properties.scm             | 10 +++
 scm/parser-clef.scm                           | 67 +++++++++++++------
 scm/translation-functions.scm                 | 18 +++++
 8 files changed, 132 insertions(+), 27 deletions(-)
 create mode 100644 input/regression/clef-optional-octavation.ly
 create mode 100644 input/regression/cue-clef-optional-octavation.ly

diff --git a/input/regression/clef-optional-octavation.ly b/input/regression/clef-optional-octavation.ly
new file mode 100644
index 0000000000..93d60db8f4
--- /dev/null
+++ b/input/regression/clef-optional-octavation.ly
@@ -0,0 +1,15 @@
+\version "2.17.7"
+
+\header {
+
+  texidoc="Octavate symbols may be parenthesized or bracketed by using
+parentheses or brackets in the command string."
+
+}
+\score {
+  \new Staff {
+    \clef "G^(8)" g''1 |
+    \clef "bass_[15]" c,,1 |
+    \clef "C^(8)" c''1
+  }
+}
diff --git a/input/regression/cue-clef-optional-octavation.ly b/input/regression/cue-clef-optional-octavation.ly
new file mode 100644
index 0000000000..cdc6206d49
--- /dev/null
+++ b/input/regression/cue-clef-optional-octavation.ly
@@ -0,0 +1,27 @@
+\version "2.17.7"
+
+\header {
+  texidoc = "Optional octavation for clefs for cue notes is
+supported by using parentheses or brackets around the octavation number."
+}
+
+vI = \relative c'' { \clef "treble" \repeat unfold 40 g4 }
+\addQuote vIQuote { \vI }
+
+Solo = \relative c' {
+  \clef "treble_8" c1 |
+  \cueDuringWithClef #"vIQuote" #UP #"bass^(15)" { R1 } |
+  c1 | \break
+  c c
+  \clef "bass^8" c1 |
+  \cueDuringWithClef #"vIQuote" #UP #"G_[8]" { R1 R1 } |
+  c
+  \cueDuringWithClef #"vIQuote" #UP #"treble_(8)" { R1 \break R } |
+  c
+}
+
+\score {
+  <<
+    \new Staff \new Voice \Solo
+  >>
+}
diff --git a/lily/clef-engraver.cc b/lily/clef-engraver.cc
index 00c3457717..1471c481b2 100644
--- a/lily/clef-engraver.cc
+++ b/lily/clef-engraver.cc
@@ -119,9 +119,12 @@ Clef_engraver::create_clef ()
           SCM txt = scm_number_to_string (scm_from_int (abs_oct),
                                           scm_from_int (10));
 
-          g->set_property ("text",
-                           scm_list_n (ly_lily_module_constant ("vcenter-markup"),
-                                       txt, SCM_UNDEFINED));
+          SCM style = get_property ("clefOctavationStyle");
+
+          SCM formatter = get_property ("clefOctavationFormatter");
+          if (ly_is_procedure (formatter))
+            g->set_property ("text", scm_call_2 (formatter, txt, style));
+
           Side_position_interface::add_support (g, clef_);
 
           g->set_parent (clef_, Y_AXIS);
@@ -212,6 +215,7 @@ ADD_TRANSLATOR (Clef_engraver,
                 /* read */
                 "clefGlyph "
                 "clefOctavation "
+                "clefOctavationStyle "
                 "clefPosition "
                 "explicitClefVisibility "
                 "forceClef ",
diff --git a/lily/cue-clef-engraver.cc b/lily/cue-clef-engraver.cc
index dad382a27a..1723964266 100644
--- a/lily/cue-clef-engraver.cc
+++ b/lily/cue-clef-engraver.cc
@@ -113,9 +113,12 @@ Cue_clef_engraver::create_octavate_eight (SCM oct)
       SCM txt = scm_number_to_string (scm_from_int (abs_oct),
                                       scm_from_int (10));
 
-      g->set_property ("text",
-                       scm_list_n (ly_lily_module_constant ("vcenter-markup"),
-                                   txt, SCM_UNDEFINED));
+      SCM style = get_property ("cueClefOctavationStyle");
+
+      SCM formatter = get_property ("cueClefOctavationFormatter");
+      if (ly_is_procedure (formatter))
+        g->set_property ("text", scm_call_2 (formatter, txt, style));
+
       Side_position_interface::add_support (g, clef_);
 
       g->set_parent (clef_, Y_AXIS);
@@ -219,6 +222,7 @@ ADD_TRANSLATOR (Cue_clef_engraver,
                 /* read */
                 "cueClefGlyph "
                 "cueClefOctavation "
+                "cueClefOctavationStyle "
                 "cueClefPosition "
                 "explicitCueClefVisibility "
                 "middleCCuePosition "
diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly
index a0b8c838dd..16913705ca 100644
--- a/ly/engraver-init.ly
+++ b/ly/engraver-init.ly
@@ -609,6 +609,8 @@ automatically when an output definition (a @code{\score} or
   endRepeatType = #":|."
   barNumberVisibility = #first-bar-number-invisible-and-no-parenthesized-bar-numbers
   barNumberFormatter = #robust-bar-number-function
+  clefOctavationFormatter = #clef-octavation-markup
+  cueClefOctavationFormatter = #clef-octavation-markup
   automaticBars = ##t
 
   explicitClefVisibility = #all-visible
diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm
index 3e871e72cf..1aaf582cd7 100644
--- a/scm/define-context-properties.scm
+++ b/scm/define-context-properties.scm
@@ -171,6 +171,11 @@ object to a text markup.  Used for chords.")
      (clefGlyph ,string? "Name of the symbol within the music font.")
      (clefOctavation ,integer? "Add this much extra octavation.
 Values of 7 and -7 are common.")
+     (clefOctavationFormatter ,procedure? "A procedure that takes the
+Octavation number as a string and the style as a symbol and returns a markup.")
+     (clefOctavationStyle ,symbol? "Determines the way the octavateEight
+grob is displayed.  Possible values are @samp{default}, @samp{parenthesized}
+and @samp{bracketed}.")
      (clefPosition ,number? "Where should the center of the clef
 symbol go, measured in half staff spaces from the center of the
 staff.")
@@ -192,6 +197,11 @@ crescendo, i.e., @samp{cresc.}.")
      (cueClefGlyph ,string? "Name of the symbol within the music font.")
      (cueClefOctavation ,integer? "Add this much extra octavation.
 Values of 7 and -7 are common.")
+     (cueClefOctavationFormatter ,procedure? "A procedure that takes the
+Octavation number as a string and the style as a symbol and returns a markup.")
+     (cueClefOctavationStyle ,symbol? "Determines the way the octavateEight
+grob is displayed.  Possible values are @samp{default}, @samp{parenthesized}
+and @samp{bracketed}.")
      (cueClefPosition ,number? "Where should the center of the clef
 symbol go, measured in half staff spaces from the center of the
 staff.")
diff --git a/scm/parser-clef.scm b/scm/parser-clef.scm
index f0a79c518f..b2c6dc2084 100644
--- a/scm/parser-clef.scm
+++ b/scm/parser-clef.scm
@@ -124,23 +124,36 @@
   (let ((e '())
 	(c0 0)
 	(oct 0)
-	(match (string-match "^(.*)([_^])([1-9][0-9]*)$" clef-name)))
+	(style 'default)
+	(match (string-match "^(.*)([_^])([^0-9a-zA-Z]*)([1-9][0-9]*)([^0-9a-zA-Z]*)$" clef-name)))
     (if match
 	(begin
 	  (set! clef-name (match:substring match 1))
 	  (set! oct
 		(* (if (equal? (match:substring match 2) "^") -1 1)
-		   (- (string->number (match:substring match 3)) 1)))))
+		   (- (string->number (match:substring match 4)) 1)))
+          (set! style
+                (cond ((equal? (match:substring match 3) "(") 'parenthesized)
+                      ((equal? (match:substring match 3) "[") 'bracketed)
+                      (else style)))))
     (set! e (assoc-get clef-name supported-clefs))
     (if e
-	(let* ((musics (map make-prop-set
-			    `(((symbol . clefGlyph) (value . ,(car e)))
-			      ((symbol . middleCClefPosition)
-			       (value . ,(+ oct
-					    (cadr e)
-					    (assoc-get (car e) c0-pitch-alist))))
-			      ((symbol . clefPosition) (value . ,(cadr e)))
-			      ((symbol . clefOctavation) (value . ,(- oct))))))
+	(let* ((prop-list `(((symbol . clefGlyph) (value . ,(car e)))
+                            ((symbol . middleCClefPosition)
+                             (value . ,(+ oct
+                                          (cadr e)
+                                          (assoc-get (car e) c0-pitch-alist))))
+                            ((symbol . clefPosition) (value . ,(cadr e)))
+                            ((symbol . clefOctavation) (value . ,(- oct)))))
+               ;; the clefOctavationStyle property is set only when
+               ;; not 'default to calm display-lily-tests.scm
+               (prop-list (if (eq? style 'default)
+                              prop-list
+                              (append
+                                prop-list
+                                `(((symbol . clefOctavationStyle)
+                                   (value . ,style))))))
+	       (musics (map make-prop-set prop-list))
 	       (recalc-mid-C (make-music 'ApplyContext))
 	       (seq (make-music 'SequentialMusic
 				'elements (append musics (list recalc-mid-C))))
@@ -164,23 +177,34 @@
   (let ((e '())
 	(c0 0)
 	(oct 0)
-	(match (string-match "^(.*)([_^])([1-9][0-9]*)$" clef-name)))
+	(style 'default)
+	(match (string-match "^(.*)([_^])([^0-9a-zA-Z]*)([1-9][0-9]*)([^0-9a-zA-Z]*)$" clef-name)))
     (if match
 	(begin
 	  (set! clef-name (match:substring match 1))
 	  (set! oct
 		(* (if (equal? (match:substring match 2) "^") -1 1)
-		   (- (string->number (match:substring match 3)) 1)))))
+		   (- (string->number (match:substring match 4)) 1)))
+          (set! style
+                (cond ((equal? (match:substring match 3) "(") 'parenthesized)
+                      ((equal? (match:substring match 3) "[") 'bracketed)
+                      (else style)))))
     (set! e (assoc-get clef-name supported-clefs))
     (if e
-	(let* ((musics (map make-prop-set
-			    `(((symbol . cueClefGlyph) (value . ,(car e)))
-			      ((symbol . middleCCuePosition)
-			       (value . ,(+ oct
-					    (cadr e)
-					    (assoc-get (car e) c0-pitch-alist))))
-			      ((symbol . cueClefPosition) (value . ,(cadr e)))
-			      ((symbol . cueClefOctavation) (value . ,(- oct))))))
+	(let* ((prop-list `(((symbol . cueClefGlyph) (value . ,(car e)))
+                            ((symbol . middleCCuePosition)
+                             (value . ,(+ oct
+                                          (cadr e)
+                                          (assoc-get (car e) c0-pitch-alist))))
+                            ((symbol . cueClefPosition) (value . ,(cadr e)))
+                            ((symbol . cueClefOctavation) (value . ,(- oct)))))
+               (prop-list (if (eq? style 'default)
+                              prop-list
+                              (append
+                                prop-list
+                                `(((symbol . cueClefOctavationStyle)
+                                   (value . ,style))))))
+	       (musics (map make-prop-set prop-list))
 	       (recalc-mid-C (make-music 'ApplyContext))
 	       (seq (make-music 'SequentialMusic
 				'elements (append musics (list recalc-mid-C))))
@@ -205,7 +229,8 @@
 			`((symbol . cueClefGlyph)
 			  (symbol . middleCCuePosition)
 			  (symbol . cueClefPosition)
-			  (symbol . cueClefOctavation))))
+			  (symbol . cueClefOctavation)
+			  (symbol . cueClefOctavationStyle))))
 	 (recalc-mid-C (make-music 'ApplyContext))
 	 (seq (make-music 'SequentialMusic
 			  'elements (append musics (list recalc-mid-C))))
diff --git a/scm/translation-functions.scm b/scm/translation-functions.scm
index 33acfbc7b4..78defd203f 100644
--- a/scm/translation-functions.scm
+++ b/scm/translation-functions.scm
@@ -17,6 +17,24 @@
 ;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
 
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; clefs
+
+(define-public (clef-octavation-markup oct style)
+  "The octavation sign formatting function.  @var{oct} is supposed to be
+a string holding the octavation number, @var{style} determines the
+way the octavation number is displayed."
+  (let* ((delim (if (symbol? style)
+                    (case style
+                      ((parenthesized) (cons "(" ")"))
+                      ((bracketed) (cons "[" "]"))
+                      (else (cons "" "")))
+                    (cons "" "")))
+         (text (string-concatenate (list (car delim) oct (cdr delim)))))
+
+       (make-vcenter-markup text)))
+
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; metronome marks
 
-- 
2.39.5