% Feta (not the Font-En-Tja) music font -- draw accordion symbols
% This file is part of LilyPond, the GNU music typesetter.
%
% Copyright (C) 1998--2023 Han-Wen Nienhuys <hanwen@xs4all.nl>
%
% 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 you can redistribute it 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/>.

fet_begingroup ("accordion");

%
% These dimensions are the same for all register symbols.
% The different symbols should calculate their other dimensions from them.
%

accreg_dot_size# := .5 staff_space#;
accreg_linethickness# := 1.3 stafflinethickness#;
accreg_lh# := 1.0 staff_space#;

define_pixels (accreg_dot_size, accreg_linethickness, accreg_lh);


fet_beginchar ("accordion register discant", "discant")
  save r, pat, lh, lt;
  path pat;

  r# = 3/2 accreg_lh#;
  define_pixels (r);

  set_char_box (r# + accreg_linethickness# / 2,
                r# + accreg_linethickness# / 2,
                0.7 accreg_linethickness# / 2,
                2 r# + 0.7 accreg_linethickness# / 2);

  lh = vround (2/3 r);
  lt = vround (0.7 accreg_linethickness);
  d := vround (0.7 accreg_linethickness / 2);
  h := 3 lh + lt - d;
  b := w := (3 lh + hround accreg_linethickness) / 2;

  penpos1 (hround accreg_linethickness, 0);
  penpos2 (lt, 90);
  penpos3 (hround accreg_linethickness, 180);
  penpos4 (lt, 270);

  z1r = (w, 0.5 [-d, h]);
  z2r = (0, h);
  z3r = (-b, 0.5 [-d, h]);
  z4r = (0, -d);

  penlabels (1, 2, 3, 4);

  % mf doesn't handle pixel dropouts in outline objects, so we use
  % `draw' if not called by mpost
  if known miterlimit:
    fill z1r
         .. z2r
         .. z3r
         .. z4r
         .. cycle;
    unfill z1l
           .. z2l
           .. z3l
           .. z4l
           .. cycle;
  else:
    pickup pencircle xscaled accreg_linethickness yscaled lt;
    draw z1
         .. z2
         .. z3
         .. z4
         .. cycle;
  fi;

  pat := z4{right}
         .. z1{up}
         .. {left}z2;

  pickup penrazor scaled lt rotated 90;

  top z5 = pat intersectionpoint ((0, lh + lt - d) -- (w, lh + lt - d));
  z6 = z5 xscaled -1;
  bot z7 = pat intersectionpoint ((0, 2 lh - d) -- (w, 2 lh - d));
  z8 = z7 xscaled -1;

  labels (5, 6, 7, 8);

  draw z5
       -- z6;
  draw z7
       -- z8;
fet_endchar;


fet_beginchar ("accordion register dot", "dot")
  set_char_box (accreg_dot_size# / 2, accreg_dot_size# / 2,
                accreg_dot_size# / 2, accreg_dot_size# / 2);

  pickup pencircle scaled accreg_dot_size;

  rt x0 = hround (accreg_dot_size / 2);
  top y0 = vround (accreg_dot_size / 2);

  drawdot z0;
fet_endchar;


fet_beginchar ("accordion register freebass", "freebass")
  save r, lh, lt;

  r# = accreg_lh#;
  define_pixels (r);

  set_char_box (r# + accreg_linethickness# / 2,
                r# + accreg_linethickness# / 2,
                0.7 accreg_linethickness# / 2,
                2 r# + 0.7 accreg_linethickness# / 2);

  lh = vround r;
  lt = vround (0.7 accreg_linethickness);
  d := vround (0.7 accreg_linethickness / 2);
  h := 2 lh + lt - d;
  b := w := (2 lh + hround accreg_linethickness) / 2;

  penpos1 (hround accreg_linethickness, 0);
  penpos2 (lt, 90);
  penpos3 (accreg_linethickness, 180);
  penpos4 (lt, 270);

  z1r = (w, 0.5 [-d, h]);
  z2r = (0, h);
  z3r = (-b, 0.5 [-d, h]);
  z4r = (0, -d);

  penlabels (1, 2, 3, 4);

  % mf doesn't handle pixel dropouts in outline objects, so we use
  % `draw' if not called by mpost
  if known miterlimit:
    fill z1r
         .. z2r
         .. z3r
         .. z4r
         .. cycle;
    unfill z1l
           .. z2l
           .. z3l
           .. z4l
           .. cycle;
  else:
    pickup pencircle xscaled accreg_linethickness yscaled lt;
    draw z1
         .. z2
         .. z3
         .. z4
         .. cycle;
  fi;

  pickup penrazor scaled lt rotated 90;

  draw z1
       -- z3;
fet_endchar;


fet_beginchar ("accordion register stdbass", "stdbass")
  save r, p, lh, lt;
  path pat;

  r# = 2 accreg_lh#;
  define_pixels (r);

  set_char_box (r# + accreg_linethickness# / 2,
                r# + accreg_linethickness# / 2,
                0.7 accreg_linethickness# / 2,
                2 r# + 0.7 accreg_linethickness# / 2);

  lh = vround (1/2 r);
  lt = vround (0.7 accreg_linethickness);
  d := vround (0.7 accreg_linethickness / 2);
  h := 4 lh + lt - d;
  b := w := (4 lh + hround accreg_linethickness) / 2;

  penpos1 (hround accreg_linethickness, 0);
  penpos2 (lt, 90);
  penpos3 (hround accreg_linethickness, 180);
  penpos4 (lt, 270);

  z1r = (w, 0.5 [-d, h]);
  z2r = (0, h);
  z3r = (-b, 0.5 [-d, h]);
  z4r = (0, -d);

  penlabels (1, 2, 3, 4);

  % mf doesn't handle pixel dropouts in outline objects, so we use
  % `draw' if not called by mpost
  if known miterlimit:
    fill z1r
         .. z2r
         .. z3r
         .. z4r
         .. cycle;
    unfill z1l
           .. z2l
           .. z3l
           .. z4l
           .. cycle;
  else:
    pickup pencircle xscaled accreg_linethickness yscaled lt;
    draw z1
         .. z2
         .. z3
         .. z4
         .. cycle;
  fi;

  pat := z4{right}
         .. z1{up}
         .. {left}z2;

  pickup penrazor scaled lt rotated 90;

  top z5 = pat intersectionpoint ((0, lh + lt - d) -- (w, lh + lt - d));
  z6 = z5 xscaled -1;
  bot z7 = pat intersectionpoint ((0, 3 lh - d) -- (w, 3 lh - d));
  z8 = z7 xscaled -1;

  labels (5, 6, 7, 8);

  draw z1
       -- z3;
  draw z5
       -- z6;
  draw z7
       -- z8;
fet_endchar;


fet_beginchar ("accordion register bayanbass", "bayanbass")
  save lh, lt;

  lh = vround accreg_lh;
  lt = vround accreg_linethickness;

  set_char_box (accreg_lh# + accreg_linethickness# / 2,
                accreg_lh# + accreg_linethickness# / 2,
                accreg_linethickness# / 2,
                3 accreg_lh# + accreg_linethickness# / 2);

  d := vround (accreg_linethickness# / 2);
  h := 3 lh + lt - d;

  draw_rounded_block ((-w, -d), (-w + lt, h), lt);
  draw_rounded_block ((w - lt, -d), (w, h), lt);

  pickup penrazor scaled lt rotated 90;

  bot z1 = (-w + lt / 2, -d);
  bot z2 = (-w + lt / 2, lh - d);
  bot z3 = (-w + lt / 2, 2 lh - d);
  bot z4 = (-w + lt / 2, 3 lh - d);

  bot z5 = (w - lt / 2, -d);
  bot z6 = (w - lt / 2, lh - d);
  bot z7 = (w - lt / 2, 2 lh - d);
  bot z8 = (w - lt / 2, 3 lh - d);

  labels (range 1 thru 8);

  draw z1
       -- z5;
  draw z2
       -- z6;
  draw z3
       -- z7;
  draw z4
       -- z8;
fet_endchar;


def def_B (expr w, h) =
  pickup pencircle scaled 0.15 linethickness;

  penpos10 (thin, -90);
  penpos11 (thin, -90);
  penpos12 (thick, 0);
  penpos13 (thin, 90);
  penpos14 (thin, 90);

  penpos15 (thick, 180);
  penpos16 (thin, -90);
  penpos17 (thin, -90);
  penpos18 (thick, 0);
  penpos19 (thick, 0);

  z10 = (0, 0);
  z11 = (cOne * w, 0);
  z12 = (w, .5 mb * h);
  z13 = (cTwo * w, mb * h);
  z14 = (2 thick, mb * h);
  z15 = (.94 w, h - .5 mt * h);
  z16 = z13 + (0, mt * h);
  z17 = (0, h);
  z18 = (1.5 thick, 0);
  z19 = (1.5 thick, h);
enddef;


def def_S (expr w, h) =
  pickup pencircle scaled 0.03 linethickness;

  penpos1 (thin, 180);
  penpos2 (thin, -90);
  penpos3 (thick, 0);
  penpos4 (.5 thick, 90);
  penpos5 (thick, 0);
  penpos6 (thin, -90);
  penpos7 (thin, 180);
  penpos8 (thin, 180);
  penpos9 (thin, 0);

  z1 = (0, hs);
  z2 = (w / 2, 0);
  z3 = (w - .5 thick, .5 mb * h);
  z4 = (w / 2, mb * h);
  z5 = (.5 thick, h - .5 mt * h);
  z6 = (w / 2, h);
  z7 = (w, h - hs);
  z8 = (0, y2r);
  z9 = (w, y6l);

  path bue, bueoverst;

  bue := z2{left}
         .. z1{up};

  t := xpart (bue intersectiontimes (z8l -- z7l));

  bueoverst := z6{right}
               .. z7{down};
enddef;


def def_some_vars =
  save hs, mb, mt, thin, thick, height, width, cOne, cTwo;
  save bx, hx;

  width = .8 (4 staff_space);
  height = 2.4 staff_space;
  % URG.  smaller sizes should be wider and fatter
  % thin = 0.05 staff_space;
  % thick = 0.2 staff_space;

  4 hx + bx = 1.15;
  10 hx + bx = 1;
  fatten := designsize * hx + bx * 1.2;
  thick := 0.2 staff_space * fatten;

  % urg: mustn't ever go thinner than blot!
  thin# := blot_diameter#;
  define_pixels (thin);

  hs = 0.4 staff_space;
  mb = .53;
  mt = .47;
  cOne = 0.65;
  cTwo = 0.60;
enddef;


fet_beginchar ("accordion oldEE", "oldEE")
  save r, pp, ir, lh, lt, stroke_width;

  r# = staff_space#;
  define_pixels (r);

  lr = .4 staff_space - linethickness;
  ir = .6 staff_space;
  stroke_width = .05 staff_space + .5 linethickness;

  set_char_box (r# + accreg_linethickness# / 2,
                r# + accreg_linethickness# / 2,
                0, 2 r# + 0.7 accreg_linethickness#);

  z1 = (0, 0);
  z2 = (0, ir);
  z3 = (0, -ir);

  penpos1 (blot_diameter, 0);
  penpos2 (stroke_width + blot_diameter, 0);
  penpos3 (stroke_width + blot_diameter, 0);

  pickup pencircle scaled (lr + blot_diameter);

  for pp := 0 step 45 until 135:
    drawdot z2 rotated pp;
    drawdot z3 rotated pp;

    penstroke (z2e
               -- z1e
               -- z3e) rotated pp;
  endfor;

  pickup pencircle scaled lr;

  drawdot (0, 0);

  currentpicture := currentpicture shifted (0, h / 2);

  lh = vround (2 r);
  lt = vround (0.7 accreg_linethickness);

  h := lh + lt;
  b := w := (lh + hround accreg_linethickness) / 2;

  penpos10 (hround accreg_linethickness, 0);
  penpos11 (lt, 90);
  penpos12 (hround accreg_linethickness, 180);
  penpos13 (lt, 270);

  z10r = (w, h / 2);
  z11r = (0, h);
  z12r = (-b, h / 2);
  z13r = (0, 0);

  % penlabels (1, 2, 10, 11, 12, 13);

  % mf doesn't handle pixel dropouts in outline objects, so we use
  % `draw' if not called by mpost
  if known miterlimit:
    fill z10r
         .. z11r
         .. z12r
         .. z13r
         .. cycle;
    unfill z10l
           .. z11l
           .. z12l
           .. z13l
           .. cycle;
  else:
    pickup pencircle xscaled accreg_linethickness yscaled lt;
    draw z10
         .. z11
         .. z12
         .. z13
         .. cycle;
  fi;
fet_endchar;


fet_beginchar ("accordion push", "push");
  save width, height;

  height# := 2.0 staff_space# + 3.0 stafflinethickness#;
  width# := 0.4 height#;

  define_pixels (height, width);

  save linewidth;

  linewidth# := stafflinethickness# + .05 staff_space#;
  define_whole_blacker_pixels (linewidth);

  set_char_box (width#, 0,
                0, height#);

  pickup pencircle scaled linewidth;

  lft x1 = -width;
  top y1 = height;

  rt x2 = 0;
  y2 = 0.5 * (y1 + y3);

  x3 = x1;
  bot y3 = 0;

  save nw_offset, ne_offset;
  pair nw_offset, ne_offset;
  save sw_offset, se_offset, line_radius;
  pair sw_offset, se_offset;

  line_radius := linewidth / 2;
  nw_offset := line_radius * unitvector (z1 - z2);
  ne_offset := nw_offset rotated -90;
  sw_offset := line_radius * unitvector (z3 - z2);
  se_offset := sw_offset rotated 90;

  z4 = ((z1 - ne_offset)
        -- (z2 - ne_offset))
       intersectionpoint
       ((z2 - se_offset)
        -- (z3 - se_offset));

  labels (1, 2, 3, 4);

  fill z1 + ne_offset
       -- z2 + ne_offset
       .. rt z2 {down}
       .. z2 + se_offset
       -- z3 + se_offset
       .. z3 + sw_offset {- se_offset}
       .. z3 - se_offset
       -- z4
       -- z1 - ne_offset
       .. z1 + nw_offset {ne_offset}
       .. cycle;
fet_endchar;


fet_beginchar ("accordion pull", "pull");
  save width, height;

  height# := 2.0 staff_space# + 3.0 stafflinethickness#;
  width# := 0.4 height#;

  define_pixels (height, width);

  save linewidth;

  linewidth# := stafflinethickness# + .05 staff_space#;
  define_whole_blacker_pixels (linewidth);

  set_char_box (width# - linewidth#, linewidth#,
                0, height#);

  pickup pencircle scaled linewidth;

  save penradius;
  penradius := linewidth / 2;

  rt x1 = linewidth;
  bot y1 = 0;

  x2 = x1;
  top y2 = height;

  lft x3 = -width + linewidth;
  y3 = y2;

  x4 = x3;
  y4 = y2 - linewidth;

  x5 = x1;
  y5 = y4;

  labels (1, 2, 3, 4);

  fill z1 + penradius * right {up}
       -- z2 + penradius * right {up}
       .. z2 + penradius * up {left}
       -- z3 + penradius * up {left}
       .. z3 + penradius * left {down}
       -- z4 + penradius * left {down}
       .. z4 + penradius * down {right}
       -- z5 + penradius * (down + left)
       -- z1 + penradius * left {down}
       .. z1 + penradius * down {right}
       .. cycle;
fet_endchar;

fet_endgroup ("accordion");
