% Feta (not the Font-En-Tja) music font --  ancient custodes
% This file is part of LilyPond, the GNU music typesetter.
%
% Copyright (C) 2000--2023 Juergen Reuter <reuter@ipd.uka.de>
%
% The LilyPond font is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version, or under the SIL Open Font License.
%
% LilyPond is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.

save black_notehead_width;
numeric black_notehead_width;

fet_begingroup ("custodes");

%
% character aligment:
%
%   The custos is assumed to be vertically centered around (0, 0).
%   The left-most edge of the custos should touch the vertical line
%   that goes though the point (0, 0).
%
% set_char_box() conventions:
%
% * breapth: Ignored (as far as I know).  Should be set to 0.
%
% * width: Should cover the horizontal range of the custos that is to
%   be printed in the staff.  If the custos has an appendage that is
%   supposed to reach beyond the right end of the staff, the width
%   should be set such that the appendage is outside of the char box.
%
% * depth: Should match the bottom edge of the custos.  Affects
%   vertical collision handling.
%
% * height: Should match the top edge of the custos.  Affects vertical
%   collision handling.
%

save between_staff_lines, on_staff_line, anywhere;

between_staff_lines := 0;
on_staff_line := 1;
anywhere := 2;

save dir_up, dir_down;

dir_up := 1;
dir_down := -1;


%%%%%%%%
%
%
% Hufnagel style
%
%

% parameterized hufnagel custos
def custos_hufnagel (expr verbose_name, internal_name,
                          direction, staffline_adjustment) =

  fet_beginchar (verbose_name, internal_name);
    save alpha, dalpha, ht, wd, stem_ht, pen_size;

    ht# = noteheight#;
    wd# / ht# = 0.6;
    alpha = 35;
    dalpha = direction * alpha;

    if staffline_adjustment = between_staff_lines:
      stem_ht# = 1.00 staff_space#;
    elseif staffline_adjustment = on_staff_line:
      stem_ht# = 1.50 staff_space#;
    else: % staffline_adjustment = anywhere
      stem_ht# = 1.25 staff_space#;
    fi;

    pen_size# = 0.5 (wd# ++ ht#);

    define_pixels (ht, wd, pen_size, stem_ht);

    save ellipse, pat, T;
    path ellipse, pat;
    transform T;

    T := identity xscaled linethickness
                  yscaled pen_size
                  rotated -dalpha;
    pickup pencircle transformed T;
    ellipse := fullcircle transformed T;

    if direction = dir_up:
      top y1 = ht / 2;
      bot y2 = -ht / 2;
    else:
      bot y1 = -ht / 2;
      top y2 = ht / 2;
    fi;

    lft x1 = 0;
    rt  x2 = wd;
    y3 - y2 = direction * stem_ht;
    (y3 - y2) = (x3 - x2) * tand (90 - dalpha);

    fill get_subpath (ellipse, z1 - z2, z2 - z1, z1)
         if direction > 0:
           -- get_subpath (ellipse, z2 - z1, z3 - z2, z2)
         else:
           -- get_subpoint (ellipse, z2 - z1, z2)
           -- get_subpoint (ellipse, z3 - z2, z2)
         fi
         -- get_subpath (ellipse, z3 - z2, z2 - z3, z3)
         if direction > 0:
           -- get_subpoint (ellipse, z2 - z3, z2)
           -- get_subpoint (ellipse, z1 - z2, z2)
         else:
           -- get_subpath (ellipse, z2 - z3, z1 - z2, z2)
         fi
         -- cycle;

    % The stem is intentionally outside of the char box.
    if direction > 0:
      set_char_box (0, wd#, ht# / 2, stem_ht#);
    else:
      set_char_box (0, wd#, stem_ht#, ht# / 2);
    fi;

    labels (1, 2, 3);
  fet_endchar;
enddef;


% custos hufnagel, stem up, between staff lines
custos_hufnagel ("custos Hufnagel (up, between lines)", "hufnagel.u0",
                 dir_up, between_staff_lines);


% custos hufnagel, stem up, on staff line
custos_hufnagel ("custos Hufnagel (up, on line)", "hufnagel.u1",
                 dir_up, on_staff_line);


% custos hufnagel, stem up, anywhere
custos_hufnagel ("custos Hufnagel (up)", "hufnagel.u2",
                 dir_up, anywhere);


% custos hufnagel, stem down, between staff lines
custos_hufnagel ("reverse custos Hufnagel (down, between lines)", "hufnagel.d0",
                 dir_down, between_staff_lines);


% custos hufnagel, stem down, on staff line
custos_hufnagel ("reverse custos Hufnagel (down, on line)", "hufnagel.d1",
                 dir_down, on_staff_line);


% custos hufnagel, stem down, anywhere
custos_hufnagel ("reverse custos Hufnagel (down)", "hufnagel.d2",
                 dir_down, anywhere);


%%%%%%%%
%
%
% Medicaea style
%
%

def custos_medicaea (expr verbose_name, internal_name,
                          direction, staffline_adjustment) =
  fet_beginchar (verbose_name, internal_name);
    save ht, wd, stem_ht;

    ht# = noteheight#;
    wd# / ht# = 0.25;

    if staffline_adjustment = between_staff_lines:
      stem_ht# = 1.00 staff_space#;
    elseif staffline_adjustment = on_staff_line:
      stem_ht# = 1.50 staff_space#;
    else: % staffline_adjustment = anywhere
      stem_ht# = 1.25 staff_space#;
    fi;

    define_pixels (ht, wd, stem_ht);

    save ellipse, T;
    path ellipse;
    transform T;

    T := identity xscaled 0.6 linethickness
                  yscaled ht;
    pickup pencircle transformed T;
    ellipse := fullcircle transformed T;

    lft x1 = 0;
    y1 = 0;
    rt x2 = wd;
    y2 = y1;

    fill get_subpath (ellipse, left, right, z1)
         -- get_subpath (ellipse, right, left, z2)
         -- cycle;

    pickup pencircle scaled 0.6 linethickness;

    rt x3 = wd;
    y3 = 0;
    x4 = x3;
    if direction > 0:
      top y4 = stem_ht;
      draw_rounded_block (bot lft z3, top rt z4,
                          0.6 linethickness);
    else:
      bot y4 = -stem_ht;
      draw_rounded_block (bot lft z4, top rt z3,
                          0.6 linethickness);
    fi;


    if direction > 0:
      set_char_box (0, wd#, ht# / 2, stem_ht#);
    else:
      set_char_box (0, wd#, stem_ht#, ht# / 2);
    fi;

    labels (1, 2, 3, 4);
  fet_endchar;
enddef;


% custos medicaea, stem up, between staff lines
custos_medicaea ("custos Med. (up, between lines)", "medicaea.u0",
                 dir_up, between_staff_lines);


% custos medicaea, stem up, on staff line
custos_medicaea ("custos Med. (up, on line)", "medicaea.u1",
                 dir_up, on_staff_line);


% custos medicaea, stem up, anywhere
custos_medicaea ("custos Med. (up)", "medicaea.u2",
                 dir_up, anywhere);


% custos medicaea, stem down, between staff lines
custos_medicaea ("reverse custos Med. (down, between lines)", "medicaea.d0",
                 dir_down, between_staff_lines);


% custos medicaea, stem down, on staff line
custos_medicaea ("reverse custos Med. (down, on line)", "medicaea.d1",
                 dir_down, on_staff_line);


% custos medicaea, stem down, anywhere
custos_medicaea ("reverse custos Med. (down)", "medicaea.d2",
                 dir_down, anywhere);


%%%%%%%%
%
%
% Editio Vaticana style
%
%

def custos_vaticana (expr verbose_name, internal_name,
                          direction, staffline_adjustment) =
  fet_beginchar (verbose_name, internal_name);
    save ht, wd, u_offs, l_offs, stem_size, stem_end;
    save pen_ht, l_shift, curve_ht, bend_ht;

    ht# = noteheight#;
    wd# = 0.24 ht#;

    if staffline_adjustment = between_staff_lines:
      stem_size# = 1.00;
    elseif staffline_adjustment = on_staff_line:
      stem_size# = 1.50;
    else: % staffline_adjustment = anywhere
      stem_size# = 1.25;
    fi;

    curve_ht# = 0.6 ht#;
    bend_ht# = 0.10 ht#;
    l_shift# = 0.04 ht#;
    u_offs# = +direction * 0.5 * (bend_ht# + l_shift#);
    l_offs# = -direction * 0.5 * (bend_ht# - l_shift#);
    stem_end# = direction * stem_size# * staff_space#;
    pen_ht# = curve_ht# - l_shift#;

    define_pixels (u_offs, l_offs, stem_end, ht, wd, pen_ht);

    pickup pencircle scaled 0.6 linethickness;

    z1 = (0, u_offs);
    z2 = (0.7 wd, l_offs);
    z3 = (wd, l_offs);

    penpos1 (pen_ht, 90);
    penpos2 (pen_ht, 90);
    penpos3 (pen_ht, 90);

    penstroke z1e{z2 - z1}
              .. {right}z2e
              .. z3e;

    rt x4 = wd;
    x5 = x4;

    if direction > 0:
      y4 = y3r;
      top y5 = stem_end;
      draw_rounded_block (bot lft z4, top rt z5, 0.6 linethickness);
    else:
      y4 = y3l;
      bot y5 = stem_end;
      draw_rounded_block (bot lft z5, top rt z4, 0.6 linethickness);
    fi;

    if direction > 0:
      set_char_box (0, wd#, -l_offs# + 0.5 pen_ht#, stem_end#);
    else:
      set_char_box (0, wd#, -stem_end#, +l_offs# + 0.5 pen_ht#);
    fi;

    penlabels (1, 2, 3);
    labels (4, 5);
  fet_endchar;
enddef;


% custos vaticana, stem up, between staff lines
custos_vaticana ("custos Ed. Vat. (up, between lines)", "vaticana.u0",
                 dir_up, between_staff_lines);


% custos vaticana, stem up, on staff line
custos_vaticana ("custos Ed. Vat. (up, on line)", "vaticana.u1",
                 dir_up, on_staff_line);


% custos vaticana, stem up, anywhere
custos_vaticana ("custos Ed. Vat. (up)", "vaticana.u2",
                 dir_up, anywhere);


% custos vaticana, stem down, between staff lines
custos_vaticana ("reverse custos Ed. Vat. (down, between lines)", "vaticana.d0",
                 dir_down, between_staff_lines);


% custos vaticana, stem down, on_staff_line
custos_vaticana ("reverse custos Ed. Vat. (down, on line)", "vaticana.d1",
                 dir_down, on_staff_line);


% custos vaticana, stem down, anywhere
custos_vaticana ("reverse custos Ed. Vat. (down)", "vaticana.d2",
                 dir_down, anywhere);


%%%%%%%%
%
%
% Mensural style
%
%

def custos_mensural (expr verbose_name, internal_name,
                          direction, staffline_adjustment) =
  fet_beginchar (verbose_name, internal_name);
    save alpha, dalpha, ht, wd, stem_ht;

    ht# = noteheight#;
    wd# / ht# = 1.2;
    alpha = 35;
    dalpha = direction * alpha;

    if staffline_adjustment = between_staff_lines:
      stem_ht# = 2.00 staff_space#;
    elseif staffline_adjustment = on_staff_line:
      stem_ht# = 2.50 staff_space#;
    else: % staffline_adjustment = anywhere
      stem_ht# = 2.25 staff_space#;
    fi;

    define_pixels (ht, wd, stem_ht);

    save ellipse, T;
    path ellipse;
    transform T;

    T := identity xscaled linethickness
                  yscaled 0.4 ht
                  rotated -dalpha;
    pickup pencircle transformed T;
    ellipse := fullcircle transformed T;

    if direction > 0:
      bot y1 = bot y3 = bot y5 = -direction * 0.33 ht;
      top y2 = top y4 = +direction * 0.33 ht;
    else:
      top y1 = top y3 = top y5 = -direction * 0.33 ht;
      bot y2 = bot y4 = +direction * 0.33 ht;
    fi;

    lft x1 = 0.0 wd;
    lft x2 = 0.2 wd;
    lft x3 = 0.4 wd;
    lft x4 = 0.6 wd;
    lft x5 = 0.8 wd;

    y6 - y5 = direction * stem_ht;
    y6 - y5 = (x6 - x5) * tand (90 - dalpha);

    if direction > 0:
      fill get_subpath (ellipse, z1 - z2, z2 - z1, z1)
           -- get_subpoint (ellipse, z2 - z1, z2)
           -- get_subpoint (ellipse, z3 - z2, z2)
           -- get_subpath (ellipse, z3 - z2, z4 - z3, z3)
           -- get_subpoint (ellipse, z4 - z3, z4)
           -- get_subpoint (ellipse, z5 - z4, z4)
           -- get_subpath (ellipse, z5 - z4, z6 - z5, z5)
           -- get_subpath (ellipse, z6 - z5, z5 - z6, z6)
           -- get_subpoint (ellipse, z5 - z6, z5)
           -- get_subpoint (ellipse, z4 - z5, z5)
           -- get_subpath (ellipse, z4 - z5, z3 - z4, z4)
           -- get_subpoint (ellipse, z3 - z4, z3)
           -- get_subpoint (ellipse, z2 - z3, z3)
           -- get_subpath (ellipse, z2 - z3, z1 - z2, z2)
           -- cycle;
    else:
      fill get_subpath (ellipse, z1 - z2, z2 - z1, z1)
           -- get_subpath (ellipse, z2 -z1, z3 - z2, z2)
           -- get_subpoint (ellipse, z3 - z2, z3)
           -- get_subpoint (ellipse, z4 - z3, z3)
           -- get_subpath (ellipse, z4 -z3, z5 - z4, z4)
           -- get_subpoint (ellipse, z5 - z4, z5)
           -- get_subpoint (ellipse, z6 - z5, z5)
           -- get_subpath (ellipse, z6 - z5, z5 - z6, z6)
           -- get_subpath (ellipse, z5 - z6, z4 - z5, z5)
           -- get_subpoint (ellipse, z4 - z5, z4)
           -- get_subpoint (ellipse, z3 - z4, z4)
           -- get_subpath (ellipse, z3 - z4, z2 - z3, z3)
           -- get_subpoint (ellipse, z2 - z3, z2)
           -- get_subpoint (ellipse, z1 - z2, z2)
           -- cycle;
    fi;

    % The stem is intentionally outside of the char box.
    if direction > 0:
      set_char_box (0, wd#, +direction * 0.33 ht#, stem_ht#);
    else:
      set_char_box (0, wd#, stem_ht#, -direction * 0.33 ht#);
    fi;

    labels (1, 2, 3, 4, 5, 6);
  fet_endchar;
enddef;


% custos mensural, stem up, between staff lines
custos_mensural ("custos mensural (up, between lines)", "mensural.u0",
                 dir_up, between_staff_lines);


% custos mensural, stem up, on staff line
custos_mensural ("custos mensural (up, on line)", "mensural.u1",
                 dir_up, on_staff_line);


% custos mensural, stem up, anywhere
custos_mensural ("custos mensural (up)", "mensural.u2",
                 dir_up, anywhere);


% custos mensural, stem down, between staff lines
custos_mensural ("reverse custos mensural (down, between lines)", "mensural.d0",
                 dir_down, between_staff_lines);


% custos mensural, stem down, on staff line
custos_mensural ("reverse custos mensural (down, on line)", "mensural.d1",
                 dir_down, on_staff_line);


% custos mensural, stem down, anywhere
custos_mensural ("reverse custos mensural (down)", "mensural.d2",
                 dir_down, anywhere);

fet_endgroup ("custodes");
