% --------------------------------------------------------------------------
% the LEADSHEETS package
% 
%   typesetting leadsheets and songbooks
%
% --------------------------------------------------------------------------
% Clemens Niederberger
% E-Mail: contact@mychemistry.eu
% --------------------------------------------------------------------------
% Copyright 2014-2017 Clemens Niederberger
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% of this license or (at your option) any later version.
% The latest version of this license is in
%   http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Clemens Niederberger.
% --------------------------------------------------------------------------
\LeadsheetsExplLibrary{chords}{2016/07/02 printing chords}

\msg_new:nnn {leadsheets} {no-chords}
  { No~ more~ chords~ left~ for~ verse~ type~ `#1'~ \msg_line_context: }

\leadsheets_load_library:n {chordnames}

\bool_new:N \l__leadsheets_output_notation_german_bool
\bool_new:N \l__leadsheets_input_notation_german_bool
  
\tl_new:N    \l__leadsheets_current_chord_tl
\tl_new:N    \l__leadsheets_chord_stack_alignment_tl
\tl_set:Nn   \l__leadsheets_chord_stack_alignment_tl {c}

\bool_new:N  \l__leadsheets_smash_chords_bool
\bool_new:N  \g__leadsheets_smash_next_chord_bool
\bool_new:N  \l__leadsheets_chord_gobble_after_bool
\bool_new:N  \l__leadsheets_record_chords_bool
\bool_new:N  \l__leadsheets_chord_print_bool
\bool_set_true:N \l__leadsheets_chord_print_bool

\prop_new:N  \g__leadsheets_chords_sequences_prop

\seq_new:N   \g__leadsheets_chords_sequences_seq

\dim_new:N   \l__leadsheets_empty_chord_dim
\dim_set:Nn  \l__leadsheets_empty_chord_dim {1em}

\cs_new:Npn \leadsheets_chord_print:n #1 {#1}
\cs_generate_variant:Nn \leadsheets_chord_print:n {V}

\cs_new_protected:Npn \leadsheets_set_chord:nnn #1#2#3
  {
    \bool_if:NTF #1
      { \bool_set_true:N \l__leadsheets_chord_gobble_after_bool }
      { \bool_set_false:N \l__leadsheets_chord_gobble_after_bool }
    \bool_if:NT #2
      { \bool_set_true:N \g__leadsheets_smash_next_chord_bool }
    \__leadsheets_set_chord:nwn {#3}
  }

\cs_new_protected:Npn \__leadsheets_set_chord:nwn #1#2~#3
  {
    \leadsheets_place_above:Vnn
      \l__leadsheets_chord_stack_alignment_tl
      {#1}
      {
        \tl_if_blank:nTF {#2}
          {\skip_horizontal:N \l__leadsheets_empty_chord_dim}
          {#2}
      }
    \tl_if_blank:nF {#3}
      { \bool_if:NF \l__leadsheets_chord_gobble_after_bool {\c_space_tl} }
    #3
  }

\cs_new_protected:Npn \leadsheets_chord:nnn #1#2#3
  {
    \leadsheets_if_record_chords:T
      { \seq_gput_right:Nn \g__leadsheets_chords_sequences_seq { {#3} } }
    \leadsheets_set_chord:nnn
      {#1}
      {#2}
      { \leadsheets_chord_write:n {#3} }
  }

\group_begin:

\cs_new_protected:Npn \leadsheets_chord_write:n
  {
    \group_begin:
      \char_set_catcode_other:N \#
      \char_set_catcode_active:N \^
      \__leadsheets_chord_write:n
  }

% for convenient input of sharps:
\char_set_catcode_other:N \#
% because ^ is active in the song environment:
\char_set_catcode_active:N \^
% # is other so we need another parameter character:
\char_set_catcode_parameter:N \?

\cs_new_protected:Npn \__leadsheets_chord_write:n ?1
  {
    \tl_set:Nn \l__leadsheets_current_chord_tl {?1}
    % => convert to English input
    \bool_if:NTF \l__leadsheets_input_notation_german_bool
      {
        \tl_replace_all:Nnn \l__leadsheets_current_chord_tl {B} {Bb}
        \tl_replace_all:Nnn \l__leadsheets_current_chord_tl {H} {B}
      }
      { \tl_replace_all:Nnn \l__leadsheets_current_chord_tl {H} {B} }
    \leadsheets_if_library:nT {songs}
      {
        \bool_if:nT
          {
            \leadsheets_if_property_p:Vn \l_leadsheets_current_song_id_tl {key}
            &&
            ( \l__leadsheets_transpose_bool || \l__leadsheets_transpose_capo_bool )
          }
          {
            \leadsheets_transpose:xVN
              { \leadsheets_get_property:Vn \l_leadsheets_current_song_id_tl {key} }
              \l__leadsheets_transpose_steps_int
              \l__leadsheets_current_chord_tl
          }
        \bool_if:nTF
          {
            ! \leadsheets_if_property_p:Vn \l_leadsheets_current_song_id_tl {key}
            &&
            ( \l__leadsheets_transpose_bool || \l__leadsheets_transpose_capo_bool )
          }
          {
            \msg_warning:nnV {leadsheets}
              {transpose-key}
              \l_leadsheets_current_song_id_tl
          }
      }
    % => convert to specified output
    \bool_if:NT \l__leadsheets_output_notation_german_bool
      {
        \tl_replace_all:Nnn \l__leadsheets_current_chord_tl {Bb}  {@@@}
        \tl_replace_all:Nnn \l__leadsheets_current_chord_tl {B}   {H}
        \tl_replace_all:Nnn \l__leadsheets_current_chord_tl {@@@} {B}
        \tl_replace_all:Nnn \l__leadsheets_current_chord_tl {B#}  {H}
      }
    % => this is \chordname initially:
    \leadsheets_chord_print:V \l__leadsheets_current_chord_tl
    \group_end:
  }
\group_end:

\cs_generate_variant:Nn \leadsheets_chord_write:n { V }

\cs_new_protected:Npn \leadsheets_place_above:nnn #1#2#3
  {
    \bool_if:NTF \l__leadsheets_chord_print_bool
      {
        \group_begin:
          \leadsheets_if_library:nT {songs}
            { \leadsheets_ignore_lines: }
          \bool_if:NT \g__leadsheets_smash_next_chord_bool
            {
              \bool_set_true:N \l__leadsheets_smash_chords_bool
              \bool_gset_false:N \g__leadsheets_smash_next_chord_bool
            }
          \linespread{1} \selectfont
          \begin{tabular} [b] {@{}#1@{}}
            \bool_if:NTF \l__leadsheets_smash_chords_bool
              {\makebox[0pt][c]{#2}}
              {#2} \\
            #3
          \end{tabular}
        \group_end:
      }
      {#3}
  }
\cs_generate_variant:Nn \leadsheets_place_above:nnn { V }

\keys_define:nn {leadsheets}
  {
    smash-chords     .bool_set:N = \l__leadsheets_smash_chords_bool ,
    smash-next-chord .bool_set:N = \g__leadsheets_smash_next_chord_bool ,
    empty-chord-dim  .dim_set:N  = \l__leadsheets_empty_chord_dim ,
    remember-chords  .bool_set:N = \l__leadsheets_record_chords_bool ,
    align-chords     .tl_set:N   = \l__leadsheets_chord_stack_alignment_tl ,
    chord-cs         .code:n     =
      \cs_set_protected:Npn \leadsheets_chord_print:n {#1} ,
    chord-cs         .initial:n  = \chordname ,
    print-chords     .bool_set:N = \l__leadsheets_chord_print_bool ,
    chords/output-notation .choice: ,
    chords/output-notation/german  .code:n =
      \bool_set_true:N \l__leadsheets_output_notation_german_bool ,
    chords/output-notation/english .code:n =
      \bool_set_false:N \l__leadsheets_output_notation_german_bool ,
    chords/input-notation .choice: ,
    chords/input-notation/german   .code:n =
      \bool_set_true:N \l__leadsheets_input_notation_german_bool ,
    chords/input-notation/english  .code:n =
      \bool_set_false:N \l__leadsheets_input_notation_german_bool
  }

\NewDocumentCommand \chord {st-} { \leadsheets_chord:nnn {#1} {#2} }

\NewDocumentCommand \writechord {} { \leadsheets_chord_write:n }

% --------------------------------------------------------------------------
% record changes for a verse and automatically print them in the next:
\prg_new_conditional:Npnn \leadsheets_if_record_chords: {T,F,TF}
  {
    \bool_if:nTF
      {
        \l__leadsheets_record_chords_bool &&
        ! \prop_if_in_p:NV
            \g__leadsheets_chords_sequences_prop
            \l_leadsheets_verse_type_tl &&
        !\l__leadsheets_measuring_bool
      }
      { \prg_return_true: }
      { \prg_return_false: }
  }

\prg_new_conditional:Npnn \leadsheets_if_recall_chords: {T,F,TF}
  {
    \bool_if:nTF
      {
        \l__leadsheets_record_chords_bool &&
        \prop_if_in_p:NV
          \g__leadsheets_chords_sequences_prop
          \l_leadsheets_verse_type_tl
        &&
        !\l__leadsheets_measuring_bool
      }
      { \prg_return_true: }
      { \prg_return_false: }
  }

\cs_new_protected:Npn \leadsheets_recall_chord:nn #1#2
  {
    \seq_pop_left:NNF \g__leadsheets_chords_sequences_seq
      \l__leadsheets_tmpa_tl
      { \msg_error:nnV {leadsheets} {no-chords} \l_leadsheets_verse_type_tl }
    \leadsheets_set_chord:nnn
      {#1}
      {#2}
      { \leadsheets_chord_write:V \l__leadsheets_tmpa_tl }
  }

\NewDocumentCommand \recallchord {st-}
  { \leadsheets_recall_chord:nn {#1} {#2} }

\NewDocumentCommand \getorprintchord {}
  {
    \leadsheets_if_recall_chords:TF
      { \recallchord }
      { \chord }
  }
  
\endinput

HISTORY:

2014/08/10 - first version
2015/07/02 - input/output notation is done here now instead of in the
             `chordnames' library so transposing works with either input
             correctly
           - options `input-notation' and `output-notation' now directly
             belong to the `chords' library.
           - this is now a user library
2016/07/02 - \getorprintchord
