Hosted by
|
with Enum_Strings; use Enum_Strings;
with Messages; use Messages;
package body Boxes.Chords is
function Create
return Chord_Box_Access
is
Result : Chord_Box_Access := new Chord_Box;
begin
Result.Note_Heads := Head_Lists.Create;
return Result;
end Create;
procedure Add_Note
(This : access Chord_Box;
Add : access Note;
Middle_C : in Integer)
is
Note_Head : Note_Head_Enum;
Filled : Boolean;
Position : Integer;
begin
Note_Head := Get_Note_Head(Add);
Filled := Get_Filled(Add);
Position := Middle_C + Get_Position(Add);
if Head_Lists.Empty(This.Note_Heads) then
This.Note_Type := Get_Note_Type(Add);
This.Stem := This.Note_Type >= Half;
This.Dots := Get_Dots(Add);
This.Lowest := Position;
This.Highest := Position;
else
if Position < This.Lowest then This.Lowest := Position; end if;
if Position > This.Highest then This.Highest := Position; end if;
end if;
Head_Lists.Push(This.Note_Heads, Create(Note_Head, Filled, Position));
end Add_Note;
procedure Layout_Note_Heads
(This : access Chord_Box;
Font : access Font_Loader)
is
use Head_Lists;
Note_Head : Note_Head_Box_Access;
Position : Integer;
Extra : Real;
Y : Real;
begin
This.Stem_Box := (others => 0.0);
Reset(This.Note_Heads);
while Next(This.Note_Heads) loop
Note_Head := Current(This.Note_Heads);
Position := Get_Position(Current(This.Note_Heads));
Extra := 0.0;
if Position mod 2 = 1 then -- Sitting in a space between lines.
if Position = This.Highest then -- Above the highest staff line.
if Position = 5 then Extra := -5.0; end if;
if Position >= 7 then Extra := -20.0; end if;
end if;
if Position = This.Lowest then -- Under the lowest staff line.
if Position = -5 then Extra := 5.0; end if;
if Position <= -7 then Extra := 20.0; end if;
end if;
if not Get_Filled(Note_Head) then
Extra := Extra * 2.0;
end if;
end if;
Y := -50.0 * Real(Position) + Extra;
Set_Center(Note_Head, (0.0, Y));
This.Stem_Box.Bottom := Real'Max(This.Stem_Box.Bottom, Y - 20.0);
This.Stem_Box.Top := Real'Min(This.Stem_Box.Top, Y + 20.0);
Layout(Note_Head, Font);
Max_Bounds(This, Note_Head);
end loop;
end Layout_Note_Heads;
procedure Layout_Stem_Down
(This : access Chord_Box;
Font : access Font_Loader) is
begin
This.Stem_Box.Left := This.Bounds.Left + 6.0;
This.Stem_Box.Right := This.Stem_Box.Left + 8.0;
This.Stem_Box.Bottom := -50.0 * Real(This.Lowest - 7);
if This.Stem_Box.Bottom < 0.0 then
This.Stem_Box.Bottom := 0.0;
end if;
case This.Note_Type is
when Long | Breve | Whole | Half | Quarter => null;
when Eighth =>
This.Flag := Load_Glyph(Font, "flags/stem-down/single");
when N_16th =>
This.Flag := Load_Glyph(Font, "flags/stem-down/double");
This.Stem_Box.Bottom := This.Stem_Box.Bottom + 50.0;
when N_32nd =>
This.Flag := Load_Glyph(Font, "flags/stem-down/triple");
This.Stem_Box.Bottom := This.Stem_Box.Bottom + 100.0;
when others =>
Error("unsupported flag type: " & To_XML(This.Note_Type'Img));
end case;
if This.Flag /= null then
This.Flag_Offset := (This.Stem_Box.Left, This.Stem_Box.Bottom);
This.Bounds := Max(This.Bounds, Get_Bounds(This.Flag) + This.Flag_Offset);
end if;
This.Bounds := Max(This.Bounds, This.Stem_Box);
end Layout_Stem_Down;
procedure Layout_Stem_Up
(This : access Chord_Box;
Font : access Font_Loader) is
begin
This.Stem_Box.Right := This.Bounds.Right - 6.0;
This.Stem_Box.Left := This.Stem_Box.Right - 8.0;
This.Stem_Box.Top := -50.0 * Real(This.Highest + 7);
if This.Stem_Box.Top > 0.0 then
This.Stem_Box.Top := 0.0;
end if;
case This.Note_Type is
when Long | Breve | Whole | Half | Quarter => null;
when Eighth =>
This.Flag := Load_Glyph(Font, "flags/stem-up/single");
when N_16th =>
This.Flag := Load_Glyph(Font, "flags/stem-up/double");
This.Stem_Box.Top := This.Stem_Box.Top - 50.0;
when N_32nd =>
This.Flag := Load_Glyph(Font, "flags/stem-up/triple");
This.Stem_Box.Top := This.Stem_Box.Top - 100.0;
when others =>
Error("unsupported flag type: " & To_XML(This.Note_Type'Img));
end case;
if This.Flag /= null then
This.Flag_Offset := (This.Stem_Box.Left, This.Stem_Box.Top);
This.Bounds := Max(This.Bounds, Get_Bounds(This.Flag) + This.Flag_Offset);
end if;
This.Bounds := Max(This.Bounds, This.Stem_Box);
end Layout_Stem_Up;
procedure Layout_Dots
(This : access Chord_Box;
Font : access Font_Loader)
is
use Head_Lists;
Note_Head : Note_Head_Box_Access;
Position : Integer;
begin
if This.Dots /= 0 then
Reset(This.Note_Heads);
while Next(This.Note_Heads) loop
Note_Head := Current(This.Note_Heads);
Position := Get_Position(Current(This.Note_Heads));
if Position mod 2 = 1
then Add_Dots(Note_Head, Font, This.Dots, (150.0, 0.0));
else Add_Dots(Note_Head, Font, This.Dots, (150.0, -50.0));
end if;
Max_Bounds(This, Note_Head);
end loop;
end if;
end Layout_Dots;
procedure Layout_Ledger
(This : access Chord_Box;
Font : access Font_Loader) is
begin
for Index in 3 .. This.Highest / 2 loop
This.High_Ledger(Index) := Load_Glyph(Font, "lines/ledger");
This.Bounds := Max(This.Bounds,
Get_Bounds(This.High_Ledger(Index)) + (0.0, -100.0 * Real(Index)));
end loop;
for Index in This.Lowest / 2 .. -3 loop
This.Low_Ledger(Index) := Load_Glyph(Font, "lines/ledger");
This.Bounds := Max(This.Bounds,
Get_Bounds(This.Low_Ledger(Index)) + (0.0, -100.0 * Real(Index)));
end loop;
end Layout_Ledger;
procedure Layout
(This : access Chord_Box;
Font : access Font_Loader) is
begin
Layout_Note_Heads(This, Font);
if This.Stem then
This.Stem_Down := -This.Lowest <= This.Highest;
if This.Stem_Down
then Layout_Stem_Down(This, Font);
else Layout_Stem_Up(This, Font);
end if;
end if;
Layout_Dots(This, Font);
Layout_Ledger(This, Font);
end Layout;
procedure Print
(This : access Chord_Box;
To : access Printer'Class;
Center : in Vector)
is
use Head_Lists;
begin
Reset(This.Note_Heads);
while Next(This.Note_Heads) loop
Print(Current(This.Note_Heads), To, Center + This.Center);
end loop;
for Index in 3 .. This.Highest / 2 loop
Print(To, This.High_Ledger(Index),
Center + This.Center + (0.0, -100.0 * Real(Index)));
end loop;
for Index in This.Lowest / 2 .. -3 loop
Print(To, This.Low_Ledger(Index),
Center + This.Center + (0.0, -100.0 * Real(Index)));
end loop;
if This.Stem then
Fill_Box(To, This.Stem_Box + Center + This.Center, 0);
end if;
if This.Flag /= null then
Print(To, This.Flag, Center + This.Center + This.Flag_Offset);
end if;
Print_Bounds(This, To, Center);
end Print;
end Boxes.Chords;
|