context: /* Copyright (c) 2007-2013 Madhav Vaidyanathan
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License version 2.
   *
   *  This program 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.
   */
  
  using System;
  using System.IO;
  using System.Drawing;
  using System.Drawing.Printing;
  using System.Windows.Forms;
  using System.Collections.Generic;
  using System.Reflection;
  using System.Resources;
  
  namespace MidiSheetMusic
  {
  
  
      /** @class SheetMusicWindow
       *
       * The SheetMusicWindow is the main window/form of the application,
       * that contains the Midi Player and the Sheet Music.
       * The form supports the following menu commands
       *
       * File
       *   Open 
       *     Open a midi file, read it into a MidiFile object, and create a
       *     SheetMusic child control based on the MidiFile.  The SheetMusic 
       *     control is then displayed.
       *
       *   Open Sample Song
       *     Open one of the sample midi files that comes with MidiSheetMusic.
       *
       *   Close 
       *     Close the SheetMusic control.
       *
       *   Save As Images
       *     Save the sheet music as images (one per page)
       *
       *   Print Preview 
       *     Create a PrintPreview dialog and generate a preview of the SheetMusic.
       *     The SheetMusic.DoPrint() method handles the PrintPage callback function.
       *
       *   Print 
       *     Create a PrintDialog to print the sheet music.  
       *
       *   Recent File List
       *     A list of recently opened MIDI files
       * 
       *   Exit 
       *     Exit the application.
       *
       * View
       *   Scroll Vertically
       *     Scroll the sheet music vertically.
       *
       *   Scroll Horizontally
       *     Scroll the sheet music horizontally.
       *
       *   Zoom In
       *     Increase the zoom level on the sheet music.
       *
       *   Zoom Out
       *     Decrease the zoom level on the sheet music.
       *
       *   Zoom to 100/150%
       *     Set the zoom level to 100/150%.
       *
       *   Large/Small Notes
       *     Display large or small note sizes
       *
       * Color
       *   Enable Color
       *     Show colored notes instead of black notes
       *
       *   Choose Color
       *     Choose the colors for each note
       *
       * Tracks
       *  Track X
       *     Select which tracks of the Midi file to display
       *
       *   Use One/Two Staffs
       *     Display the Midi tracks in one staff per track, or two staffs 
       *     for all tracks.
       *
       *   Choose Instruments...
       *     Choose which instruments to use per track, when playing the sound.
       *
       * Notes
       *
       *   Key Signature
       *     Change the key signature.
       *
       *   Time Signature
       *     Change the time signature to 3/4, 4/4, etc
       *
       *   Transpose Keys
       *     Shift the note keys up or down.
       *
       *   Shift Notes
       *     Shift the notes left/right by the given number of 8th notes.
       *
       *   Measure Length
       *     Adjust the length (in pulses) of a single measure
       *
       *   Combine Notes Within
       *     Combine notes within the given millisec interval.
       *
       *   Show Note Letters
       *     In the sheet music, display the note letters (A, A#, Bb, etc)
       *     next to the notes.
       *
       *   Show Lyrics
       *     If the midi file has lyrics, display them under the notes.
       * 
       *   Show Measure Numbers.
       *     In the sheet music, display the measure numbers in the staffs.
       *
       *   Play Measures in a Loop
       *     Play the selected measures in a loop
       *
       * Help
       *   Contents
       *     Display a text area describing the MidiSheetMusic options.
       */
      public class SheetMusicWindow : Form
      {
  
          MidiFile midifile;         /* The MIDI file to display */
          SheetMusic sheetmusic;     /* The Control which displays the sheet music */
          Panel scrollView;          /* The Control for scrolling the sheetmusic */
          MidiPlayer player;         /* The top panel for playing the music */
          Piano piano;               /* The piano at the top, for highlighting notes */
          ConfigINI config;          /* The midisheetmusic.config.ini file, containing per-song settings */
          PrintDocument printdoc;    /* The printer settings */
          int toPage;                /* The last page number to print */
          int currentpage;           /* The current page we are printing */
          float zoom;                /* The current zoom level (1.0 == 100%) */
  
          /* Color options */
          NoteColorDialog colordialog;
  
          /* Dialog for showing sample songs */
          SampleSongDialog sampleSongDialog;
  
          /* Dialog for choosing instruments */
          InstrumentDialog instrumentDialog;
  
          /* Dialog for playing measures in a loop */
          PlayMeasuresDialog playMeasuresDialog;
  
          /* Label on how to select a MIDI file */
          Label selectMidi;
  
          /* Menu Items */
          MenuItem fileMenu;
          MenuItem newMenu;
          MenuItem openMenu;
          MenuItem openSampleSongMenu;
          MenuItem writeMenu;
          MenuItem saveImagesMenu;
          MenuItem savePDFMenu;
          MenuItem closeMenu;
          MenuItem previewMenu;
          MenuItem printMenu;
          MenuItem exitMenu;
          MenuItem trackMenu;
          MenuItem trackDisplayMenu;
          MenuItem trackMuteMenu;
          MenuItem oneStaffMenu;
          MenuItem twoStaffMenu;
          MenuItem viewMenu;
          MenuItem scrollHorizMenu;
          MenuItem scrollVertMenu;
          MenuItem largeNotesMenu;
          MenuItem smallNotesMenu;
          MenuItem notesMenu;
          MenuItem showLettersMenu;
          MenuItem showLyricsMenu;
          MenuItem showMeasuresMenu;
          MenuItem measureMenu;
          MenuItem changeKeyMenu;
          MenuItem transposeMenu;
          MenuItem shiftNotesMenu;
          MenuItem timeSigMenu;
          MenuItem combineNotesMenu;
          MenuItem playMeasuresMenu;
          MenuItem colorMenu;
          MenuItem useColorMenu;
          MenuItem chooseColorMenu;
          MenuItem chooseInstrumentsMenu;
  
          /** Create a new instance of this Form.
           * This window has three child controls:
           * - The MidiPlayer
           * - The SheetMusic 
           * - The scrollView, for scrolling the SheetMusic.
           * Create the menus.
           * Create the color dialog.
           */
          public SheetMusicWindow()
          {
  
              config = new ConfigINI(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "/midisheetmusic.config.ini");
              Text = "Midi Sheet Music";
              Icon = new Icon(GetType(), "Resources.Images.NotePair.ico");
              BackColor = Color.Gray;
              Rectangle bounds = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
              Size = new Size(bounds.Width - 20, bounds.Height * 9 / 10);
  
              CreateMenu();
              DisableMenus();
              AutoScroll = false;
  
              if (System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width >= 1200)
              {
                  zoom = 1.5f;
              }
              else
              {
                  zoom = 1.0f;
              }
  
              /* Create the player panel */
              player = new MidiPlayer();
              player.Parent = this;
              player.Dock = DockStyle.Top;
              player.BackColor = Color.LightGray;
              player.BorderStyle = BorderStyle.FixedSingle;
  
              piano = new Piano();
              piano.Parent = this;
              // piano.BackColor = Color.LightGray;
              piano.Location = new Point(piano.Location.X, piano.Location.Y + player.Height);
              player.SetPiano(piano);
  
              scrollView = new Panel();
              scrollView.Parent = this;
              scrollView.Location = new Point(scrollView.Location.X,
                                              scrollView.Location.Y + player.Height + piano.Height);
              scrollView.BackColor = Color.Gray;
              scrollView.AutoScroll = true;
              scrollView.HorizontalScroll.Enabled = true;
              scrollView.VerticalScroll.Enabled = true;
  
              selectMidi = new Label();
              selectMidi.Font = new Font("Arial", 16, FontStyle.Bold);
              selectMidi.Text = "Use the menu File:Open to select a MIDI file";
              selectMidi.Dock = DockStyle.Fill;
              selectMidi.TextAlign = ContentAlignment.TopCenter;
              selectMidi.Parent = scrollView;
  
              colordialog = new NoteColorDialog();
  
              CreatePrintSettings();
  
              // Drag-and-drop midi files
              this.AllowDrop = true;
              this.DragDrop += new DragEventHandler(this.DragDropHandler);
              this.DragEnter += new DragEventHandler(this.DragEnterHandler);
              // wang1ang
              Toub.Sound.Midi.MidiPlayer.OpenMidi();
              New(null, null);
          }
  
  
          /** When the window is resized, adjust the scrollView to fill the window */
          protected override void OnResize(EventArgs e)
          {
              base.OnResize(e);
              if (piano != null)
              {
                  piano.Size = new Size(player.Width, piano.Size.Height);
              }
              if (scrollView != null)
              {
                  scrollView.Size = new Size(player.Width, ClientSize.Height - (player.Height + piano.Height));
              }
          }
  
          /** When the window is closing, call the Exit() function */
          protected override void OnClosed(EventArgs e)
          {
              Toub.Sound.Midi.MidiPlayer.CloseMidi();
              base.OnClosed(e);
              this.Exit(null, null);
          }
  
          /** Create the MidiOptions based on the menus */
          MidiOptions GetMidiOptions()
          {
              MidiOptions options = new MidiOptions(midifile);
  
              /* Get the list of selected tracks from the Tracks menu */
              for (int track = 0; track < midifile.Tracks.Count; track++)
              {
                  options.tracks[track] = trackDisplayMenu.MenuItems[track + 2].Checked;
                  options.mute[track] = trackMuteMenu.MenuItems[track + 2].Checked;
              }
              options.scrollVert = scrollVertMenu.Checked;
              options.largeNoteSize = largeNotesMenu.Checked;
              options.twoStaffs = twoStaffMenu.Checked;
              options.showNoteLetters = MidiOptions.NoteNameNone;
              for (int i = 0; i < 6; i++)
              {
                  if (showLettersMenu.MenuItems[i].Checked)
                  {
                      options.showNoteLetters = (int)showLettersMenu.MenuItems[i].Tag;
                  }
              }
              if (showLyricsMenu != null)
              {
                  options.showLyrics = showLyricsMenu.Checked;
              }
              options.showMeasures = showMeasuresMenu.Checked;
              options.shifttime = 0;
              options.transpose = 0;
              options.key = -1;
              options.time = midifile.Time;
  
              /* Get the time signature to use */
              foreach (MenuItem menu in timeSigMenu.MenuItems)
              {
                  int quarter = options.time.Quarter;
                  int tempo = options.time.Tempo;
                  if (menu.Checked && !menu.Text.Contains(Resources.Localization.Strings.showDefault))
                  {
                      if (menu.Text == "3/4")
                      {
                          options.time = new TimeSignature(3, 4, quarter, tempo);
                      }
                      else if (menu.Text == "4/4")
                      {
                          options.time = new TimeSignature(4, 4, quarter, tempo);
                      }
                  }
              }
  
              /* Get the measure length to use */
              foreach (MenuItem menu in measureMenu.MenuItems)
              {
                  if (menu.Checked)
                  {
                      int num = options.time.Numerator;
                      int denom = options.time.Denominator;
                      int measure = (int)menu.Tag;
                      int tempo = options.time.Tempo;
                      int quarter = measure * options.time.Quarter / options.time.Measure;
                      options.time = new TimeSignature(num, denom, quarter, tempo);
                  }
              }
  
              /* Get the amount to shift the notes left/right */
              foreach (MenuItem menu in shiftNotesMenu.MenuItems)
              {
                  if (menu.Checked)
                  {
                      int shift = (int)menu.Tag;
                      if (shift >= 0)
                          options.shifttime = midifile.Time.Quarter / 2 * (shift);
                      else
                          options.shifttime = shift;
                  }
              }
  
              /* Get the key signature to use */
              foreach (MenuItem menu in changeKeyMenu.MenuItems)
              {
                  if (menu.Checked && !menu.Text.Contains("Default"))
                  {
                      int tag = (int)menu.Tag;
                      /* If the tag is positive, it has the number of sharps.
                       * If the tag is negative, it has the number of flats.
                       */
                      int num_flats = 0;
                      int num_sharps = 0;
                      if (tag < 0)
                          num_flats = -tag;
                      else
                          num_sharps = tag;
                      options.key = new KeySignature(num_sharps, num_flats).Notescale();
                  }
              }
  
              /* Get the amount to transpose the key up/down */
              foreach (MenuItem menu in transposeMenu.MenuItems)
              {
                  if (menu.Checked)
                  {
                      options.transpose = (int)menu.Tag;
                  }
              }
  
              /* Get the time interval for combining notes into the same chord. */
              foreach (MenuItem menu in combineNotesMenu.MenuItems)
              {
                  if (menu.Checked)
                  {
                      options.combineInterval = (int)menu.Tag;
                  }
              }
  
              /* Get the list of instruments from the Instrument dialog */
              options.instruments = instrumentDialog.Instruments;
              options.useDefaultInstruments = instrumentDialog.isDefault();
  
              /* Get the speed/tempo to use */
              options.tempo = midifile.Time.Tempo;
  
              /* Get whether to play measures in a loop */
              options.playMeasuresInLoop = playMeasuresDialog.Enabled;
              if (options.playMeasuresInLoop)
              {
                  options.playMeasuresInLoopStart = playMeasuresDialog.StartMeasure;
                  options.playMeasuresInLoopEnd = playMeasuresDialog.EndMeasure;
                  if (options.playMeasuresInLoopStart > options.playMeasuresInLoopEnd)
                  {
                      options.playMeasuresInLoopEnd = options.playMeasuresInLoopStart;
                  }
              }
  
              /* Get the note colors to use */
              options.shadeColor = colordialog.ShadeColor;
              options.shade2Color = colordialog.Shade2Color;
              if (useColorMenu.Checked)
              {
                  options.colors = colordialog.Colors;
              }
              else
              {
                  options.colors = null;
              }
              return options;
          }
  
          /** Set the menu values to those given in the MidiOptions */
          void SetMenuFromMidiOptions(MidiOptions options)
          {
              /* Set the Track Display and Track Mute menus */
              for (int track = 0; track < midifile.Tracks.Count; track++)
              {
                  trackDisplayMenu.MenuItems[track + 2].Checked = options.tracks[track];
                  trackMuteMenu.MenuItems[track + 2].Checked = options.mute[track];
              }
              scrollVertMenu.Checked = options.scrollVert;
              scrollHorizMenu.Checked = !options.scrollVert;
              largeNotesMenu.Checked = options.largeNoteSize;
              smallNotesMenu.Checked = !options.largeNoteSize;
              twoStaffMenu.Checked = options.twoStaffs;
              oneStaffMenu.Checked = !options.twoStaffs;
  
              /* Set the show letters menu value */
              for (int i = 0; i < 6; i++)
              {
                  if (i == options.showNoteLetters)
                  {
                      showLettersMenu.MenuItems[i].Checked = true;
                  }
                  else
                  {
                      showLettersMenu.MenuItems[i].Checked = false;
                  }
              }
  
              /* Set the Show Measures menu value */
              showMeasuresMenu.Checked = options.showMeasures;
              foreach (MenuItem menu in shiftNotesMenu.MenuItems)
              {
                  int tag = (int)menu.Tag;
                  if (options.shifttime == tag ||
                      options.shifttime == (tag * midifile.Time.Quarter / 2))
                  {
                      menu.Checked = true;
                  }
                  else
                  {
                      menu.Checked = false;
                  }
              }
  
              /* Set the time signature menu value */
              if (options.time != null)
              {
                  string text = options.time.Numerator.ToString() + "/" + options.time.Denominator.ToString();
                  MenuItem match = null;
                  foreach (MenuItem menu in timeSigMenu.MenuItems)
                  {
                      if (menu.Text == text)
                      {
                          match = menu; break;
                      }
                  }
                  if (match != null)
                  {
                      foreach (MenuItem menu in timeSigMenu.MenuItems)
                      {
                          menu.Checked = false;
                      }
                      match.Checked = true;
                  }
              }
  
              /* Set the measure length menu value - TODO */
  
              /* Set the key signature menu value */
              foreach (MenuItem menu in changeKeyMenu.MenuItems)
              {
                  int tag = (int)menu.Tag;
                  if (options.key == -1)
                  {
                      if (menu.Text.Contains("Default"))
                      {
                          menu.Checked = true;
                      }
                      else
                      {
                          menu.Checked = false;
                      }
                  }
                  else
                  {
                      if (menu.Text.Contains("Default"))
                      {
                          menu.Checked = false;
                      }
                      else if (options.key == tag)
                      {
                          menu.Checked = true;
                      }
                      else
                      {
                          menu.Checked = false;
                      }
                  }
              }
  
              /* Set the transpose menu value */
              foreach (MenuItem menu in transposeMenu.MenuItems)
              {
                  if ((int)menu.Tag == options.transpose)
                  {
                      menu.Checked = true;
                  }
                  else
                  {
                      menu.Checked = false;
                  }
              }
  
              /* Set the combine notes menu value */
              foreach (MenuItem menu in combineNotesMenu.MenuItems)
              {
                  if ((int)menu.Tag == options.combineInterval)
                  {
                      menu.Checked = true;
                  }
                  else
                  {
                      menu.Checked = false;
                  }
              }
  
              /* Set the instruments to use */
              if (!options.useDefaultInstruments)
              {
                  instrumentDialog.Instruments = options.instruments;
              }
  
              /* Set the menu values for play measures in a loop */
              if (options.playMeasuresInLoop)
              {
                  playMeasuresDialog.Enabled = options.playMeasuresInLoop;
                  playMeasuresDialog.StartMeasure = options.playMeasuresInLoopStart;
                  playMeasuresDialog.EndMeasure = options.playMeasuresInLoopEnd;
              }
  
              /* Set the note colors */
              colordialog.ShadeColor = options.shadeColor;
              colordialog.Shade2Color = options.shade2Color;
              colordialog.Colors = options.colors;
          }
  
          /** The Sheet Music needs to be redrawn.  Gather the sheet music
           * options from the menu items.  Then create the sheetmusic
           * control, and add it to this form. Update the MidiPlayer with
           * the new midi file.
           */
          void RedrawSheetMusic()
          {
              if (selectMidi != null)
              {
                  selectMidi.Dispose();
              }
  
              if (sheetmusic != null)
              {
                  sheetmusic.Dispose();
              }
  
              MidiOptions options = GetMidiOptions();
  
              /* Create a new SheetMusic Control from the midifile */
              sheetmusic = new SheetMusic(midifile, options);
              sheetmusic.SetZoom(zoom);
              sheetmusic.Parent = scrollView;
              sheetmusic.MouseDown += sheetmusic_MouseDown; // wang1ang
  
              BackColor = Color.White;
              scrollView.BackColor = Color.White;
  
              /* Update the Midi Player and piano */
              piano.SetMidiFile(midifile, options);
              piano.SetShadeColors(colordialog.ShadeColor, colordialog.Shade2Color);
              piano.MouseDown += piano_MouseDown;
              player.SetMidiFile(midifile, options, sheetmusic);
          }
  
          void piano_MouseDown(object sender, MouseEventArgs e)
          {
              if (player.playstate == 1 || player.playstate == 3)
                  piano.OnClick(sender, e);
          }
  
          void sheetmusic_MouseDown(object sender, MouseEventArgs e)
          {
              // yangwa
              if (player.playstate == 1 || player.playstate == 3)
                  sheetmusic.OnClick(sender, e);
              /*
              Point p = sheetmusic.PointToScreen(new Point(e.X, e.Y));
              Graphics g = CreateGraphics();
              g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
              g.ScaleTransform(zoom, zoom);
              Pen pen = new Pen(Color.Black, 1);
              g.DrawEllipse(pen, new Rectangle(new Point(e.X, e.Y), new Size(20, 20)));
              g.DrawEllipse(pen, new Rectangle(p, new Size(20, 20)));
              /*
              int ypos = 0;
          
          
              int x_shade = 0;
              int y_shade = 0;
  
              foreach (Staff staff in staffs)
              {
                  g.TranslateTransform(0, ypos);
                  staff.ShadeNotes(g, shadeBrush, pen,
                                   currentPulseTime, prevPulseTime, ref x_shade);
                  g.TranslateTransform(0, -ypos);
                  ypos += staff.Height;
                  if (currentPulseTime >= staff.EndTime)
                  {
                      y_shade += staff.Height;
                  }
              }
              g.ScaleTransform(1.0f / zoom, 1.0f / zoom);
              g.Dispose();
              x_shade = (int)(x_shade * zoom);
              y_shade -= NoteHeight;
              y_shade = (int)(y_shade * zoom);
              if (currentPulseTime >= 0)
              {
                  ScrollToShadedNotes(x_shade, y_shade, scrollGradually);
              }
              */
          }
  
          /** Create the menu for this form. */
          void CreateMenu()
          {
  
              this.Menu = new MainMenu();
  
              CreateFileMenu();
              CreateViewMenu();
              CreateColorMenu();
  
              trackMenu = new MenuItem(Resources.Localization.Strings.trackMenu);
              notesMenu = new MenuItem(Resources.Localization.Strings.notesMenu);
              Menu.MenuItems.Add(trackMenu);
              Menu.MenuItems.Add(notesMenu);
  
              CreateHelpMenu();
          }
  
          /** Create the File menu */
          void CreateFileMenu()
          {
  
              if (fileMenu == null)
              {
                  fileMenu = new MenuItem(Resources.Localization.Strings.fileMenu);
                  openMenu = new MenuItem(Resources.Localization.Strings.openMenu,
                                       new EventHandler(Open),
                                       Shortcut.CtrlO);
                  // wang1ang:
                  newMenu = new MenuItem(Resources.Localization.Strings.newMenu, new EventHandler(New), Shortcut.CtrlN);
                  writeMenu = new MenuItem(Resources.Localization.Strings.writeMenu, new EventHandler(Write), Shortcut.CtrlW);
  
                  openSampleSongMenu = new MenuItem(Resources.Localization.Strings.openSampleSongMenu,
                                       new EventHandler(OpenSampleSong));
  
                  closeMenu = new MenuItem(Resources.Localization.Strings.closeMenu,
                                       new EventHandler(Close),
                                       Shortcut.CtrlC);
  
                  saveImagesMenu = new MenuItem(Resources.Localization.Strings.saveImagesMenu,
                                       new EventHandler(SaveAsImages));
  
                  savePDFMenu = new MenuItem(Resources.Localization.Strings.savePDFMenu,
                                       new EventHandler(SaveAsPDF),
                                       Shortcut.CtrlS);
  
                  previewMenu = new MenuItem(Resources.Localization.Strings.previewMenu,
                                         new EventHandler(PrintPreview));
  
                  printMenu = new MenuItem(Resources.Localization.Strings.printMenu,
                                       new EventHandler(Print),
                                   Shortcut.CtrlP);
  
                  exitMenu = new MenuItem(Resources.Localization.Strings.exitMenu, new EventHandler(Exit));
                  Menu.MenuItems.Add(fileMenu);
              }
  
  
              fileMenu.MenuItems.Clear();
              fileMenu.MenuItems.Add(newMenu);
              fileMenu.MenuItems.Add(openMenu);
              fileMenu.MenuItems.Add(openSampleSongMenu);
              fileMenu.MenuItems.Add(closeMenu);
              fileMenu.MenuItems.Add(writeMenu);
              fileMenu.MenuItems.Add(saveImagesMenu);
              fileMenu.MenuItems.Add(savePDFMenu);
              fileMenu.MenuItems.Add("-");
              fileMenu.MenuItems.Add(previewMenu);
              fileMenu.MenuItems.Add(printMenu);
              fileMenu.MenuItems.Add("-");
              CreateRecentFilesMenu();
              fileMenu.MenuItems.Add("-");
              fileMenu.MenuItems.Add(exitMenu);
          }
  
          /** Create a list of recently opened midi files,
           *  and add them to the file menu.
           */
          void CreateRecentFilesMenu()
          {
              List<string> recentFiles = config.GetRecentFilenames();
              for (int i = 0; i < recentFiles.Count; i++)
              {
                  string number = "" + (i + 1) + ". ";
                  MenuItem menu = new MenuItem(number + Path.GetFileName(recentFiles[i]),
                                               new EventHandler(OpenRecentFile));
                  menu.Tag = (object)recentFiles[i];
                  fileMenu.MenuItems.Add(menu);
              }
          }
  
  
          /** Create the View menu */
          void CreateViewMenu()
          {
              viewMenu = new MenuItem(Resources.Localization.Strings.viewMenu);
              MenuItem zoomin = new MenuItem(Resources.Localization.Strings.zoomInMenu, new EventHandler(ZoomIn), Shortcut.CtrlZ);
              MenuItem zoomout = new MenuItem(Resources.Localization.Strings.zoomOutMenu, new EventHandler(ZoomOut), Shortcut.CtrlX);
              MenuItem zoom100 = new MenuItem(Resources.Localization.Strings.zoom100Menu, new EventHandler(Zoom100));
              MenuItem zoom150 = new MenuItem(Resources.Localization.Strings.zoom150Menu, new EventHandler(Zoom150));
              viewMenu.MenuItems.Add(zoomin);
              viewMenu.MenuItems.Add(zoomout);
              viewMenu.MenuItems.Add(zoom100);
              viewMenu.MenuItems.Add(zoom150);
              viewMenu.MenuItems.Add("-");
  
              scrollVertMenu = new MenuItem(Resources.Localization.Strings.scrollVertMenu, new EventHandler(ScrollVertically));
              scrollHorizMenu = new MenuItem(Resources.Localization.Strings.scrollHorizMenu, new EventHandler(ScrollHorizontally));
              scrollVertMenu.RadioCheck = true;
              scrollVertMenu.Checked = true;
              scrollHorizMenu.RadioCheck = true;
              scrollHorizMenu.Checked = false;
              viewMenu.MenuItems.Add(scrollVertMenu);
              viewMenu.MenuItems.Add(scrollHorizMenu);
              viewMenu.MenuItems.Add("-");
  
              smallNotesMenu = new MenuItem(Resources.Localization.Strings.smallNotesMenu, new EventHandler(SmallNotes));
              largeNotesMenu = new MenuItem(Resources.Localization.Strings.largeNotesMenu, new EventHandler(LargeNotes));
              smallNotesMenu.RadioCheck = true;
              smallNotesMenu.Checked = true;
              largeNotesMenu.RadioCheck = true;
              largeNotesMenu.Checked = false;
              viewMenu.MenuItems.Add(smallNotesMenu);
              viewMenu.MenuItems.Add(largeNotesMenu);
              Menu.MenuItems.Add(viewMenu);
          }
  
          /** Create the Color menu */
          void CreateColorMenu()
          {
              colorMenu = new MenuItem(Resources.Localization.Strings.colorMenu);
              useColorMenu = new MenuItem(Resources.Localization.Strings.useColorMenu, new EventHandler(UseColor));
              useColorMenu.Checked = false;
              chooseColorMenu = new MenuItem(Resources.Localization.Strings.chooseColorMenu, new EventHandler(ChooseColor));
              colorMenu.MenuItems.Add(useColorMenu);
              colorMenu.MenuItems.Add(chooseColorMenu);
              Menu.MenuItems.Add(colorMenu);
          }
  
  
          /* Create the "Select Tracks to Display" menu. */
          void CreateTrackDisplayMenu()
          {
              MenuItem menu;
              trackDisplayMenu = new MenuItem(Resources.Localization.Strings.trackDisplayMenu);
              trackMenu.MenuItems.Add(trackDisplayMenu);
  
              menu = new MenuItem(Resources.Localization.Strings.selectAllTracksMenu, new EventHandler(SelectAllTracks));
              menu.Enabled = true;
              trackDisplayMenu.MenuItems.Add(menu);
  
              menu = new MenuItem(Resources.Localization.Strings.deselectAllTracksMenu, new EventHandler(DeselectAllTracks));
              menu.Enabled = true;
              trackDisplayMenu.MenuItems.Add(menu);
  
              for (int i = 0; i < midifile.Tracks.Count; i++)
              {
                  int num = i + 1;
                  string name = midifile.Tracks[i].InstrumentName;
                  if (name != "")
                  {
                      name = "   (" + name + ")";
                  }
                  menu = new MenuItem(Resources.Localization.Strings.trackMenu + " " + num + name,
                                    new EventHandler(TrackSelect));
                  menu.Checked = true;
                  if (midifile.Tracks[i].InstrumentName == "Percussion")
                  {
                      menu.Checked = false;  // Disable percussion by default
                  }
                  menu.Tag = (int)i;
                  trackDisplayMenu.MenuItems.Add(menu);
              }
          }
  
          /* Create the "Select Tracks to Mute" menu. */
          void CreateTrackMuteMenu()
          {
              MenuItem menu;
              trackMuteMenu = new MenuItem(Resources.Localization.Strings.trackMuteMenu);
              trackMenu.MenuItems.Add(trackMuteMenu);
  
              menu = new MenuItem(Resources.Localization.Strings.muteAllTracksMenu, new EventHandler(MuteAllTracks));
              menu.Enabled = true;
              trackMuteMenu.MenuItems.Add(menu);
  
              menu = new MenuItem(Resources.Localization.Strings.unmuteAllTracksMenu, new EventHandler(UnmuteAllTracks));
              menu.Enabled = true;
              trackMuteMenu.MenuItems.Add(menu);
  
              for (int i = 0; i < midifile.Tracks.Count; i++)
              {
                  int num = i + 1;
                  string name = midifile.Tracks[i].InstrumentName;
                  if (name != "")
                  {
                      name = "   (" + name + ")";
                  }
                  menu = new MenuItem(Resources.Localization.Strings.trackMenu + " " + num + name,
                                    new EventHandler(TrackMute));
                  menu.Checked = false;
                  if (midifile.Tracks[i].InstrumentName == "Percussion")
                  {
                      menu.Checked = true;  // Disable percussion by default
                  }
                  menu.Tag = (int)i;
                  trackMuteMenu.MenuItems.Add(menu);
              }
          }
  
  
          /** Create the "Track" Menu after a Midi file has been selected.
           * Add a menu item to enable/disable displaying each track.
           * Add a menu item to mute/unmute each track.
           * 
           * The MenuItem.Tag is the track number (starting at 0).
           * Add a menu item to select one staff per track.
           * Add a menu item to combine all tracks into two staffs.
           * Add a menu item to choose track instruments.
           */
          void CreateTrackMenu()
          {
              CreateTrackDisplayMenu();
              CreateTrackMuteMenu();
              trackMenu.MenuItems.Add("-");
              oneStaffMenu = new MenuItem(Resources.Localization.Strings.oneStaffMenu,
                                          new EventHandler(UseOneStaff));
              if (midifile.Tracks.Count == 1)
              {
                  twoStaffMenu = new MenuItem(Resources.Localization.Strings.splitStaffMenu,
                                              new EventHandler(UseTwoStaffs));
                  oneStaffMenu.Checked = false;
                  twoStaffMenu.Checked = true;
              }
              else
              {
  
                  twoStaffMenu = new MenuItem(Resources.Localization.Strings.combineStaffMenu,
                                              new EventHandler(UseTwoStaffs));
                  oneStaffMenu.Checked = true;
                  twoStaffMenu.Checked = false;
              }
              oneStaffMenu.RadioCheck = true;
              twoStaffMenu.RadioCheck = true;
              trackMenu.MenuItems.Add(oneStaffMenu);
              trackMenu.MenuItems.Add(twoStaffMenu);
              trackMenu.MenuItems.Add("-");
              chooseInstrumentsMenu = new MenuItem(Resources.Localization.Strings.chooseInstrumentsMenu,
                                                   new EventHandler(ChooseInstruments));
              trackMenu.MenuItems.Add(chooseInstrumentsMenu);
          }
  
          /** Enable the "Notes" menu after a Midi file has been selected. */
          void CreateNotesMenu()
          {
              CreateKeySignatureMenu();
              CreateTimeSignatureMenu();
              CreateTransposeMenu();
              CreateShiftNoteMenu();
              CreateMeasureLengthMenu();
              CreateCombineNotesMenu();
              CreateShowLettersMenu();
              CreateShowLyricsMenu();
              CreateShowMeasuresMenu();
              CreatePlayMeasuresMenu();
          }
  
          /** Create the "Show Note Letters" sub-menu. */
          void CreateShowLettersMenu()
          {
              MenuItem menu;
              showLettersMenu = new MenuItem(Resources.Localization.Strings.showLettersMenu);
  
              menu = new MenuItem(Resources.Localization.Strings.none, new EventHandler(ShowNoteLetters));
              menu.Checked = true;
              menu.Tag = 0;
              showLettersMenu.MenuItems.Add(menu);
  
              menu = new MenuItem(Resources.Localization.Strings.showLetters, new EventHandler(ShowNoteLetters));
              menu.Checked = false;
              menu.Tag = MidiOptions.NoteNameLetter;
              showLettersMenu.MenuItems.Add(menu);
  
              menu = new MenuItem(Resources.Localization.Strings.showFixedDoReMi, new EventHandler(ShowNoteLetters));
              menu.Checked = false;
              menu.Tag = MidiOptions.NoteNameFixedDoReMi;
              showLettersMenu.MenuItems.Add(menu);
  
              menu = new MenuItem(Resources.Localization.Strings.showMovableDoReMi, new EventHandler(ShowNoteLetters));
              menu.Checked = false;
              menu.Tag = MidiOptions.NoteNameMovableDoReMi;
              showLettersMenu.MenuItems.Add(menu);
  
              menu = new MenuItem(Resources.Localization.Strings.showFixedNumbers, new EventHandler(ShowNoteLetters));
              menu.Checked = false;
              menu.Tag = MidiOptions.NoteNameFixedNumber;
              showLettersMenu.MenuItems.Add(menu);
  
              menu = new MenuItem(Resources.Localization.Strings.showMovableNumbers, new EventHandler(ShowNoteLetters));
              menu.Checked = false;
              menu.Tag = MidiOptions.NoteNameMovableNumber;
              showLettersMenu.MenuItems.Add(menu);
  
              notesMenu.MenuItems.Add(showLettersMenu);
          }
  
          /** Create the "Show Lyrics" sub-menu. */
          void CreateShowLyricsMenu()
          {
              if (!midifile.HasLyrics())
              {
                  showLyricsMenu = null;
                  return;
              }
              showLyricsMenu = new MenuItem(Resources.Localization.Strings.showLyricsMenu,
                                             new EventHandler(ShowLyrics));
  
              showLyricsMenu.Checked = true;
              notesMenu.MenuItems.Add(showLyricsMenu);
          }
  
          /** Create the "Show Measure Numbers" sub-menu. */
          void CreateShowMeasuresMenu()
          {
              showMeasuresMenu = new MenuItem(Resources.Localization.Strings.showMeasuresMenu,
                                             new EventHandler(ShowMeasures));
  
              showMeasuresMenu.Checked = false;
              notesMenu.MenuItems.Add(showMeasuresMenu);
          }
  
          /** Create the "Key Signature" sub-menu.
           * Create the sub-menus for changing the key signature.
           * The Menu.Tag contains the number of sharps (if positive)
           * or the number of flats (if negative) in the key.
           */
          void CreateKeySignatureMenu()
          {
              MenuItem menu;
              KeySignature key;
  
              changeKeyMenu = new MenuItem(Resources.Localization.Strings.changeKeyMenu);
  
              /* Add the default key signature */
              menu = new MenuItem(Resources.Localization.Strings.showDefault, new EventHandler(ChangeKeySignature));
              menu.Checked = true;
              menu.RadioCheck = true;
              menu.Tag = 0;
              changeKeyMenu.MenuItems.Add(menu);
  
              /* Add the sharp key signatures */
              for (int sharps = 0; sharps <= 5; sharps++)
              {
                  key = new KeySignature(sharps, 0);
                  menu = new MenuItem(key.ToString(), new EventHandler(ChangeKeySignature));
                  menu.Checked = false;
                  menu.RadioCheck = true;
                  menu.Tag = sharps;
                  changeKeyMenu.MenuItems.Add(menu);
              }
  
              /* Add the flat key signatures */
              for (int flats = 1; flats <= 6; flats++)
              {
                  key = new KeySignature(0, flats);
                  menu = new MenuItem(key.ToString(), new EventHandler(ChangeKeySignature));
                  menu.Checked = false;
                  menu.RadioCheck = true;
                  menu.Tag = -flats;
                  changeKeyMenu.MenuItems.Add(menu);
              }
              notesMenu.MenuItems.Add(changeKeyMenu);
          }
  
  
          /** Create the "Transpose" sub-menu.
           * Create sub-menus for moving the key up or down.
           * The Menu.Tag contains the amount to shift the key by.
           */
          void CreateTransposeMenu()
          {
              MenuItem menu;
  
              transposeMenu = new MenuItem(Resources.Localization.Strings.transposeMenu);
              int[] amounts = new int[] { 12, 6, 5, 4, 3, 2, 1, 0,
                                     -1, -2, -3, -4, -5, -6, -12 };
  
              foreach (int amount in amounts)
              {
                  string name = Resources.Localization.Strings.none;
                  if (amount > 0)
                      name = Resources.Localization.Strings.up + " " + amount;
                  else if (amount < 0)
                      name = Resources.Localization.Strings.down + " " + (-amount);
                  menu = new MenuItem(name, new EventHandler(Transpose));
                  menu.RadioCheck = true;
                  if (amount == 0)
                      menu.Checked = true;
                  else
                      menu.Checked = false;
                  menu.Tag = amount;
                  transposeMenu.MenuItems.Add(menu);
              }
              notesMenu.MenuItems.Add(transposeMenu);
          }
  
          /** Create the "Shift Note" sub-menu.
           * For the "Left to Start" sub-menu, the Menu.Tag contains the
           * time (in pulses) where the first note occurs.
           * For the "Right" sub-menus, the Menu.Tag contains the number
           * of eighth notes to shift right by.
           */
          void CreateShiftNoteMenu()
          {
              MenuItem menu;
              shiftNotesMenu = new MenuItem(Resources.Localization.Strings.shiftNotesMenu);
              menu = new MenuItem("Left to start", new EventHandler(ShiftTime));
              menu.RadioCheck = true;
              menu.Checked = false;
              shiftNotesMenu.MenuItems.Add(menu);
              int firsttime = midifile.Time.Measure * 10;
              foreach (MidiTrack t in midifile.Tracks)
              {
                  if (firsttime > t.Notes[0].StartTime)
                  {
                      firsttime = t.Notes[0].StartTime;
                  }
              }
              menu.Tag = -firsttime;
              string[] labels = new string[] {
  
  
              Resources.Localization.Strings.none,
              Resources.Localization.Strings.shiftRight18,
              Resources.Localization.Strings.shiftRight14,
              Resources.Localization.Strings.shiftRight38,
              Resources.Localization.Strings.shiftRight12,
              Resources.Localization.Strings.shiftRight58,
              Resources.Localization.Strings.shiftRight34,
              Resources.Localization.Strings.shiftRight78 
          };
  
              for (int i = 0; i < 8; i++)
              {
                  menu = new MenuItem(labels[i], new EventHandler(ShiftTime));
                  menu.Checked = false;
                  menu.RadioCheck = true;
                  menu.Tag = i;
                  shiftNotesMenu.MenuItems.Add(menu);
              }
              shiftNotesMenu.MenuItems[1].Checked = true;
              notesMenu.MenuItems.Add(shiftNotesMenu);
          }
  
          /** Create the Measure Length sub-menu.
           * The method MidiFile.GuessMeasureLength guesses possible values for the
           * measure length (in pulses). Create a sub-menu for each possible measure
           * length.  The Menu.Tag field contains the measure length (in pulses) for
           * each menu item.
           */
          void CreateMeasureLengthMenu()
          {
              MenuItem menu;
              measureMenu = new MenuItem(Resources.Localization.Strings.measureMenu);
              menu = new MenuItem(midifile.Time.Measure + " " + Resources.Localization.Strings.pulses + " " + Resources.Localization.Strings.showDefault,
                               new EventHandler(MeasureLength));
              menu.RadioCheck = true;
              menu.Checked = true;
              menu.Tag = midifile.Time.Measure;
              measureMenu.MenuItems.Add(menu);
              measureMenu.MenuItems.Add("-");
              List<int> lengths = midifile.GuessMeasureLength();
              foreach (int len in lengths)
              {
                  menu = new MenuItem(len + " " + Resources.Localization.Strings.pulses + " ", new EventHandler(MeasureLength));
                  menu.RadioCheck = true;
                  menu.Tag = len;
                  menu.Checked = false;
                  measureMenu.MenuItems.Add(menu);
              }
              notesMenu.MenuItems.Add(measureMenu);
          }
  
  
          /** Create the Time Signature Menu.
           * In addition to the default time signature, add 3/4 and 4/4
           */
          void CreateTimeSignatureMenu()
          {
              MenuItem menu;
              timeSigMenu = new MenuItem(Resources.Localization.Strings.timeSigMenu);
              menu = new MenuItem("3/4", new EventHandler(ChangeTimeSignature));
              menu.RadioCheck = true;
              menu.Checked = false;
              timeSigMenu.MenuItems.Add(menu);
              menu = new MenuItem("4/4", new EventHandler(ChangeTimeSignature));
              menu.RadioCheck = true;
              menu.Checked = false;
              timeSigMenu.MenuItems.Add(menu);
              if (midifile.Time.Numerator == 3 && midifile.Time.Denominator == 4)
              {
                  timeSigMenu.MenuItems[0].Text += " (" + Resources.Localization.Strings.showDefault + ")";
                  timeSigMenu.MenuItems[0].Checked = true;
              }
              else if (midifile.Time.Numerator == 4 && midifile.Time.Denominator == 4)
              {
                  timeSigMenu.MenuItems[1].Text += " (" + Resources.Localization.Strings.showDefault + ")";
                  timeSigMenu.MenuItems[1].Checked = true;
              }
              else
              {
                  string name = midifile.Time.Numerator + "/" +
                                midifile.Time.Denominator + " (" + Resources.Localization.Strings.showDefault + ")";
                  timeSigMenu.MenuItems.Add(
                    new MenuItem(name, new EventHandler(ChangeTimeSignature))
                  );
                  timeSigMenu.MenuItems[2].Checked = true;
              }
              notesMenu.MenuItems.Add(timeSigMenu);
  
          }
  
          /** Create the Combine Notes Within Interval sub-menu.
           * The method MidiFile.RoundStartTimes() is used to combine notes within
           * a given time interval (millisec) into the same chord.
           * The Menu.Tag field contains the millisecond value.
           */
          void CreateCombineNotesMenu()
          {
              MenuItem menu;
              combineNotesMenu = new MenuItem(Resources.Localization.Strings.combineNotesMenu);
              for (int millisec = 20; millisec <= 100; millisec += 20)
              {
                  if (millisec == 40)
                  {
                      menu = new MenuItem(millisec + " " + Resources.Localization.Strings.milliseconds + " (" + Resources.Localization.Strings.showDefault + ")", new EventHandler(CombineNotes));
                      menu.Checked = true;
                  }
                  else
                  {
                      menu = new MenuItem(millisec + " " + Resources.Localization.Strings.milliseconds + " ", new EventHandler(CombineNotes));
                      menu.Checked = false;
                  }
                  menu.RadioCheck = true;
                  menu.Tag = millisec;
                  combineNotesMenu.MenuItems.Add(menu);
              }
              notesMenu.MenuItems.Add(combineNotesMenu);
          }
  
          /** Create the "Play Measures in a Loop" sub-menu.  */
  
  
          void CreatePlayMeasuresMenu()
          {
              playMeasuresMenu = new MenuItem(Resources.Localization.Strings.playMeasuresMenu,
                                                       new EventHandler(PlayMeasuresInLoop));
              playMeasuresMenu.Checked = false;
              notesMenu.MenuItems.Add(playMeasuresMenu);
          }
  
  
          /** Create the Help menu */
          void CreateHelpMenu()
          {
              MenuItem helpmenu = new MenuItem(Resources.Localization.Strings.helpMenu);
              MenuItem about = new MenuItem(Resources.Localization.Strings.aboutMenu,
                                           new EventHandler(About));
              MenuItem contents = new MenuItem(Resources.Localization.Strings.helpContentsMenu,
                                               new EventHandler(Help));
              helpmenu.MenuItems.Add(about);
              helpmenu.MenuItems.Add(contents);
              Menu.MenuItems.Add(helpmenu);
          }
  
          /** Initialize the Printer settings */
          void CreatePrintSettings()
          {
              printdoc = new PrintDocument();
              printdoc.PrinterSettings.FromPage = 1;
              printdoc.PrinterSettings.ToPage = printdoc.PrinterSettings.MaximumPage;
              printdoc.PrintPage += new PrintPageEventHandler(PrintPage);
              toPage = 0;
              currentpage = 1;
          }
  
          /** The callback function for the "New..." menu.
           * Display a "File New" dialog, to select a midi filename.
           * If a file is selected, call NewMidiFile()
           * wang1ang
           */
          void New(object obj, EventArgs args)
          {
              midifile = new MidiFile();
              DisableMenus();
              EnableMenus();
              string displayName = "New Sheet"; // Path.GetFileName(filename);
              Text = displayName + " - Midi Sheet Music";
              instrumentDialog = new InstrumentDialog(midifile);
              playMeasuresDialog = new PlayMeasuresDialog(midifile);
              RedrawSheetMusic();
          }
  
          /** The callback function for the "Open..." menu.
           * Display a "File Open" dialog, to select a midi filename.
           * If a file is selected, call OpenMidiFile()
           */
          void Open(object obj, EventArgs args)
          {
              OpenFileDialog dialog = new OpenFileDialog();
              dialog.Filter = "Midi Files (*.mid)|*.mid*|All Files (*.*)|*.*";
              dialog.FilterIndex = 1;
              dialog.RestoreDirectory = false;
              if (dialog.ShowDialog() == DialogResult.OK)
              {
                  SaveMidiOptions();
                  OpenMidiFile(dialog.FileName);
              }
          }
  
          /** The callback function for the "Open Sample Song..." menu.
           * Create a SampleSongDialog.  If a song is chosen, read the resource
           * file, and save it to an actual file in the temp directory.
           * Then call OpenMidiFile() using that temp filename.
           */
          void OpenSampleSong(object obj, EventArgs args)
          {
              if (sampleSongDialog == null)
              {
                  sampleSongDialog = new SampleSongDialog();
              }
              if (sampleSongDialog.ShowDialog() == DialogResult.OK)
              {
                  string name = sampleSongDialog.GetSong();
                  string resourceName = "MidiSheetMusic.songs." + name + ".mid";
                  Assembly assembly = this.GetType().Assembly;
                  Stream stream = assembly.GetManifestResourceStream(resourceName);
                  try
                  {
                      string path = System.IO.Path.GetTempPath() + name + ".mid";
                      FileStream tempFile = new FileStream(path, FileMode.Create);
                      byte[] buf = new byte[8192];
                      int len = stream.Read(buf, 0, 8192);
                      while (len > 0)
                      {
                          tempFile.Write(buf, 0, len);
                          len = stream.Read(buf, 0, 8192);
                      }
                      tempFile.Close();
                      stream.Close();
                      SaveMidiOptions();
                      OpenMidiFile(path);
                  }
                  catch (IOException e)
                  {
                      string message = "MidiSheetMusic was unable to open the sample song: " + name;
                      MessageBox.Show(message, "Error Opening File",
                                      MessageBoxButtons.OK, MessageBoxIcon.Error);
                  }
              }
          }
  
          /**
           * Open the recent midi file, stored in the menu Tag.
           */
          void OpenRecentFile(object obj, EventArgs args)
          {
              MenuItem menu = (MenuItem)obj;
              string filename = (string)menu.Tag;
              OpenMidiFile(filename);
          }
  
          /**
           * Read the midi file into a MidiFile instance.
           * Create a SheetMusic control based on the MidiFile.
           * Add the sheetmusic control to this form.
           * Enable all the menu items.
           *
           * If any error occurs while reading the midi file,
           * display a MessageBox with the error message.
           */
          public void OpenMidiFile(string filename)
          {
  
              try
              {
                  midifile = new MidiFile(filename);
                  DisableMenus();
                  EnableMenus();
                  string displayName = Path.GetFileName(filename);
                  displayName = displayName.Replace("__", ": ");
                  displayName = displayName.Replace("_", " ");
                  Text = displayName + " - Midi Sheet Music";
  
gt:                 instrumentDialog = new InstrumentDialog(midifile);