Exemple #1
0
        protected override void OnRender(Direct2DGraphics g)
        {
            g.FillRectangle(0, 0, Width, Height, toolbarBrush);

            var pt = this.PointToClient(Cursor.Position);

            // Buttons
            foreach (var btn in buttons)
            {
                bool hover = btn.IsPointIn(pt.X, pt.Y);
                var  bmp   = btn.GetBitmap != null?btn.GetBitmap() : btn.Bmp;

                if (bmp == null)
                {
                    bmp = btn.Bmp;
                }
                bool enabled = btn.Enabled != null?btn.Enabled() : true;

                g.DrawBitmap(bmp, btn.X, btn.Y, enabled ? (hover ? 0.75f : 1.0f) : 0.25f);
            }

            // Timecode
            int frame      = App.CurrentFrame;
            int patternIdx = frame / App.Song.PatternLength;
            int noteIdx    = frame % App.Song.PatternLength;

            g.FillAndDrawRectangleHalfPixel(TimecodePosX, 4, TimecodePosX + TimecodeSizeX, Height - 4, theme.DarkGreyFillBrush1, theme.BlackBrush);
            g.DrawText($"{patternIdx:D3}:{noteIdx:D3}", Theme.FontHuge, TimecodePosX + 30, 2, theme.LightGreyFillBrush1, TimecodeSizeX);

            // Tooltip
            if (!string.IsNullOrEmpty(tooltip))
            {
                g.DrawText(tooltip, Theme.FontMediumRight, Width - 314, 12, theme.BlackBrush, 300);
            }
        }
Exemple #2
0
        public static Direct2DTheme CreateResourcesForGraphics(Direct2DGraphics g)
        {
            var theme = new Direct2DTheme();

            theme.InitializeForGraphics(g);
            return(theme);
        }
Exemple #3
0
        private Button CreateButton(ExportFormat format)
        {
            var btn = new NoFocusButton();

            btn.BackColor  = BackColor;
            btn.ForeColor  = Direct2DGraphics.ToDrawingColor4(Theme.LightGreyFillColor2);
            btn.ImageAlign = ContentAlignment.MiddleLeft;
            btn.TextAlign  = ContentAlignment.MiddleLeft;
            btn.FlatStyle  = FlatStyle.Flat;
            btn.FlatAppearance.BorderSize         = 0;
            btn.FlatAppearance.MouseOverBackColor = Direct2DGraphics.ToDrawingColor4(Theme.DarkGreyFillColor2);
            btn.FlatAppearance.MouseDownBackColor = Direct2DGraphics.ToDrawingColor4(Theme.DarkGreyFillColor2);
            btn.Image             = (Bitmap)Resources.ResourceManager.GetObject("Export" + format.ToString(), Resources.Culture);
            btn.Top               = ((int)format) * 32;
            btn.Left              = 0;
            btn.Width             = panelTabs.Width;
            btn.Height            = 32;
            btn.Font              = format == 0 ? fontBold : font;
            btn.Text              = format.ToString();
            btn.TextImageRelation = TextImageRelation.ImageBeforeText;
            btn.Click            += Btn_Click;

            panelTabs.Controls.Add(btn);

            return(btn);
        }
Exemple #4
0
 private void TerminateRenderGraphics()
 {
     if (!DesignMode)
     {
         OnRenderTerminated();
         d2dGraphics.Dispose();
         d2dGraphics = null;
     }
 }
Exemple #5
0
 private void InitRenderGraphics()
 {
     if (!DesignMode)
     {
         DoubleBuffered = false;
         ResizeRedraw   = true;
         d2dGraphics    = new Direct2DGraphics(this);
         OnRenderInitialized(d2dGraphics);
     }
 }
Exemple #6
0
        private Label CreateLabel(string str)
        {
            var label = new Label();

            label.Text      = str;
            label.Font      = font;
            label.AutoSize  = true;
            label.ForeColor = Direct2DGraphics.ToDrawingColor4(Theme.LightGreyFillColor2);
            label.BackColor = BackColor;

            return(label);
        }
Exemple #7
0
            public RawColor4 GetColor()
            {
                switch (type)
                {
                case ButtonType.SongHeader:
                case ButtonType.InstrumentHeader: return(Theme.LightGreyFillColor2);

                case ButtonType.Song: return(Direct2DGraphics.ToRawColor4(song.Color));

                case ButtonType.Instrument: return(instrument == null ? Theme.LightGreyFillColor1 : Direct2DGraphics.ToRawColor4(instrument.Color));
                }

                return(Theme.LightGreyFillColor1);
            }
Exemple #8
0
        public static Theme CreateResourcesForGraphics(Direct2DGraphics g)
        {
            var theme = new Theme();

            theme.BlackBrush          = g.CreateSolidBrush(BlackColor);
            theme.LightGreyFillBrush1 = g.CreateSolidBrush(LightGreyFillColor1);
            theme.LightGreyFillBrush2 = g.CreateSolidBrush(LightGreyFillColor2);
            theme.DarkGreyLineBrush1  = g.CreateSolidBrush(DarkGreyLineColor1);
            theme.DarkGreyLineBrush2  = g.CreateSolidBrush(DarkGreyLineColor2);
            theme.DarkGreyFillBrush1  = g.CreateSolidBrush(DarkGreyFillColor1);
            theme.DarkGreyFillBrush2  = g.CreateSolidBrush(DarkGreyFillColor2);

            return(theme);
        }
Exemple #9
0
        protected override void OnDirect2DInitialized(Direct2DGraphics g)
        {
            theme        = Theme.CreateResourcesForGraphics(g);
            toolbarBrush = g.CreateHorizontalGradientBrush(0, 81, Theme.LightGreyFillColor1, Theme.LightGreyFillColor2);

            bmpLoopNone    = g.ConvertBitmap(Resources.LoopNone);
            bmpLoopSong    = g.ConvertBitmap(Resources.Loop);
            bmpLoopPattern = g.ConvertBitmap(Resources.LoopPattern);
            bmpPlay        = g.ConvertBitmap(Resources.Play);
            bmpPause       = g.ConvertBitmap(Resources.Pause);

            buttons[ButtonNew] = new Button {
                X = 4, Y = 4, Bmp = g.ConvertBitmap(Resources.File), Click = OnNew
            };
            buttons[ButtonOpen] = new Button {
                X = 44, Y = 4, Bmp = g.ConvertBitmap(Resources.Open), Click = OnOpen
            };
            buttons[ButtonSave] = new Button {
                X = 84, Y = 4, Bmp = g.ConvertBitmap(Resources.Save), Click = OnSave, RightClick = OnSaveAs
            };
            buttons[ButtonExport] = new Button {
                X = 124, Y = 4, Bmp = g.ConvertBitmap(Resources.Export), Click = OnExport, Enabled = OnExportEnabled
            };
            buttons[ButtonUndo] = new Button {
                X = 164, Y = 4, Bmp = g.ConvertBitmap(Resources.Undo), Click = OnUndo, Enabled = OnUndoEnabled
            };
            buttons[ButtonRedo] = new Button {
                X = 204, Y = 4, Bmp = g.ConvertBitmap(Resources.Redo), Click = OnRedo, Enabled = OnRedoEnabled
            };
            buttons[ButtonPlay] = new Button {
                X = 436, Y = 4, Click = OnPlay, GetBitmap = OnPlayGetBitmap
            };
            buttons[ButtonRewind] = new Button {
                X = 476, Y = 4, Bmp = g.ConvertBitmap(Resources.Rewind), Click = OnRewind
            };
            buttons[ButtonLoop] = new Button {
                X = 516, Y = 4, Click = OnLoop, GetBitmap = OnLoopGetBitmap
            };

            buttons[ButtonNew].ToolTip    = "New Project (Ctrl-N)";
            buttons[ButtonOpen].ToolTip   = "Open Project (Ctrl-O)";
            buttons[ButtonSave].ToolTip   = "Save Project (Ctrl-S) [Right-Click: Save As...]";
            buttons[ButtonExport].ToolTip = "Export to various formats (Ctrl+E)";
            buttons[ButtonUndo].ToolTip   = "Undo (Ctrl+Z)";
            buttons[ButtonRedo].ToolTip   = "Redo (Ctrl+Y)";
            buttons[ButtonPlay].ToolTip   = "Play/Pause (Space) [Ctrl+Space: Play pattern loop, Shift-Space: Play song loop]";
            buttons[ButtonRewind].ToolTip = "Rewind (Home) [Ctrl+Home: Rewind to beginning of current pattern]";
            buttons[ButtonLoop].ToolTip   = "Toggle Loop Mode";
        }
Exemple #10
0
        protected override void OnDirect2DInitialized(Direct2DGraphics g)
        {
            theme = Theme.CreateResourcesForGraphics(g);

            bmpVolume     = g.ConvertBitmap(Resources.Volume);
            bmpPitch      = g.ConvertBitmap(Resources.Pitch);
            bmpArpeggio   = g.ConvertBitmap(Resources.Arpeggio);
            bmpDuty[0]    = g.ConvertBitmap(Resources.Duty0);
            bmpDuty[1]    = g.ConvertBitmap(Resources.Duty1);
            bmpDuty[2]    = g.ConvertBitmap(Resources.Duty2);
            bmpDuty[3]    = g.ConvertBitmap(Resources.Duty3);
            bmpDPCM       = g.ConvertBitmap(Resources.DPCM);
            bmpSong       = g.ConvertBitmap(Resources.Music);
            bmpAdd        = g.ConvertBitmap(Resources.Add);
            bmpInstrument = g.ConvertBitmap(Resources.Pattern);
        }
Exemple #11
0
        protected override void OnDirect2DInitialized(Direct2DGraphics g)
        {
            theme = Theme.CreateResourcesForGraphics(g);

            bmpButtonIcons[(int)ButtonType.Song]       = g.ConvertBitmap(Resources.Music);
            bmpButtonIcons[(int)ButtonType.Instrument] = g.ConvertBitmap(Resources.Pattern);

            bmpSubButtonIcons[(int)SubButtonType.Add]        = g.ConvertBitmap(Resources.Add);
            bmpSubButtonIcons[(int)SubButtonType.DPCM]       = g.ConvertBitmap(Resources.DPCM);
            bmpSubButtonIcons[(int)SubButtonType.DutyCycle0] = g.ConvertBitmap(Resources.Duty0);
            bmpSubButtonIcons[(int)SubButtonType.DutyCycle1] = g.ConvertBitmap(Resources.Duty1);
            bmpSubButtonIcons[(int)SubButtonType.DutyCycle2] = g.ConvertBitmap(Resources.Duty2);
            bmpSubButtonIcons[(int)SubButtonType.DutyCycle3] = g.ConvertBitmap(Resources.Duty3);
            bmpSubButtonIcons[(int)SubButtonType.Arpeggio]   = g.ConvertBitmap(Resources.Arpeggio);
            bmpSubButtonIcons[(int)SubButtonType.Pitch]      = g.ConvertBitmap(Resources.Pitch);
            bmpSubButtonIcons[(int)SubButtonType.Volume]     = g.ConvertBitmap(Resources.Volume);
        }
Exemple #12
0
        protected override void OnRender(Direct2DGraphics g)
        {
            g.Clear(Theme.DarkGreyFillColor1);
            g.DrawLineHalfPixel(0, 0, 0, Height, theme.BlackBrush);

            int actualWidth = Width - ScrollBarSizeX;

            int y = -scrollY;

            foreach (var button in buttons)
            {
                var icon = bmpButtonIcons[(int)button.type];

                g.PushTranslation(0, y);
                g.FillAndDrawRectangleHalfPixel(0, 0, actualWidth, ButtonSizeY, g.GetVerticalGradientBrush(button.GetColor(), ButtonSizeY, 0.8f), theme.BlackBrush);
                g.DrawText(button.GetText(App.Project), button.GetFont(selectedSong, selectedInstrument), icon == null ? 5 : 24, 5, theme.BlackBrush, actualWidth - 10);

                if (icon != null)
                {
                    g.DrawBitmap(icon, 4, 4);
                }

                var subButtons = button.GetSubButtons(out var active);
                if (subButtons != null)
                {
                    for (int i = 0, x = actualWidth - 20; i < subButtons.Length; i++, x -= 20)
                    {
                        g.DrawBitmap(bmpSubButtonIcons[(int)subButtons[i]], x, 4, active[i] ? 1.0f : 0.2f);
                    }
                }

                g.PopTransform();
                y += ButtonSizeY;
            }

            if (NeedsScrollBar)
            {
                int virtualSizeY   = VirtualSizeY;
                int scrollBarSizeY = (int)Math.Round(Height * (Height / (float)virtualSizeY));
                int scrollBarPosY  = (int)Math.Round(Height * (scrollY / (float)virtualSizeY));

                g.FillAndDrawRectangleHalfPixel(actualWidth, 0, Width - 1, Height, theme.DarkGreyFillBrush1, theme.BlackBrush);
                g.FillAndDrawRectangleHalfPixel(actualWidth, scrollBarPosY, Width - 1, scrollBarPosY + scrollBarSizeY, theme.LightGreyFillBrush1, theme.BlackBrush);
            }
        }
Exemple #13
0
        protected override void OnDirect2DInitialized(Direct2DGraphics g)
        {
            theme = Theme.CreateResourcesForGraphics(g);

            bmpTracks[Channel.Square1]  = g.ConvertBitmap(Resources.Square);
            bmpTracks[Channel.Square2]  = g.ConvertBitmap(Resources.Square);
            bmpTracks[Channel.Triangle] = g.ConvertBitmap(Resources.Triangle);
            bmpTracks[Channel.Noise]    = g.ConvertBitmap(Resources.Noise);
            bmpTracks[Channel.DPCM]     = g.ConvertBitmap(Resources.DPCM);

            bmpEdit      = g.ConvertBitmap(Resources.EditSmall);
            bmpGhostNote = g.ConvertBitmap(Resources.GhostSmall);

            playPositionBrush = g.CreateSolidBrush(new RawColor4(Theme.LightGreyFillColor1.R, Theme.LightGreyFillColor1.G, Theme.LightGreyFillColor1.B, 0.75f));

            whiteKeyBrush        = g.CreateHorizontalGradientBrush(0, TrackNameSizeX, Theme.LightGreyFillColor1, Theme.LightGreyFillColor2);
            patternHeaderBrush   = g.CreateVerticalGradientBrush(0, PatternHeaderSizeY, Theme.LightGreyFillColor1, Theme.LightGreyFillColor2);
            selectedPatternBrush = g.CreateSolidBrush(new RawColor4(Theme.LightGreyFillColor1.R, Theme.LightGreyFillColor1.G, Theme.LightGreyFillColor1.B, 0.5f));
        }
Exemple #14
0
        private unsafe Bitmap GetPatternBitmapFromCache(Pattern p)
        {
            int patternSizeX = Song.PatternLength - 1;
            int patternSizeY = TrackSizeY - PatternHeaderSizeY - 1;

            Bitmap bmp;

            if (patternBitmapCache.TryGetValue(p.Id, out bmp))
            {
                if (bmp.Size.Width == patternSizeX)
                {
                    return(bmp);
                }
                else
                {
                    bmp.Dispose();
                    bmp = null;
                }
            }

            uint[] data = new uint[patternSizeX * patternSizeY];

            Note minNote;
            Note maxNote;

            if (p.GetMinMaxNote(out minNote, out maxNote))
            {
                if (maxNote.Value == minNote.Value)
                {
                    minNote.Value = (byte)(minNote.Value - 5);
                    maxNote.Value = (byte)(maxNote.Value + 5);
                }
                else
                {
                    minNote.Value = (byte)(minNote.Value - 2);
                    maxNote.Value = (byte)(maxNote.Value + 2);
                }

                Note lastValid = new Note {
                    Value = Note.NoteInvalid
                };

                for (int i = 0; i < Song.PatternLength - 1; i++) // TODO: We always skip the last note.
                {
                    var n = p.Notes[i];

                    if (n.IsValid && !n.IsStop)
                    {
                        lastValid = p.Notes[i];
                    }

                    if (lastValid.IsValid)
                    {
                        float scaleY = (patternSizeY - NoteSizeY) / (float)patternSizeY;

                        int x = i;
                        int y = Math.Min((int)Math.Round((lastValid.Value - minNote.Value) / (float)(maxNote.Value - minNote.Value) * scaleY * patternSizeY), patternSizeY - NoteSizeY);

                        var instrument = lastValid.Instrument;
                        var color      = instrument == null?Direct2DGraphics.ToDrawingColor4(Theme.LightGreyFillColor1) : instrument.Color;

                        for (int j = 0; j < NoteSizeY; j++)
                        {
                            data[(patternSizeY - 1 - (y + j)) * patternSizeX + x] = (uint)color.ToArgb();
                        }
                    }

                    //if (n.HasEffect)
                    //{
                    //    for (int y = 0; y < patternSizeY; y++)
                    //    {
                    //        data[y * patternSizeX + i] = 0xff000000;
                    //    }
                    //}
                }
            }

            fixed(uint *ptr = &data[0])
            {
                DataStream       stream   = new DataStream(new IntPtr(ptr), data.Length * sizeof(uint), true, false);
                BitmapProperties bmpProps = new BitmapProperties(new PixelFormat(Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied));

                bmp = new Bitmap(d2dGraphics.RenderTarget, new Size2(patternSizeX, patternSizeY), stream, patternSizeX * sizeof(uint), bmpProps);
                patternBitmapCache[p.Id] = bmp;
                stream.Dispose();
            }

            return(bmp);
        }
Exemple #15
0
        protected override void OnRender(Direct2DGraphics g)
        {
            g.Clear(Theme.DarkGreyFillColor1);

            int patternSizeX      = PatternSizeX;
            int minVisiblePattern = Math.Max((int)Math.Floor(scrollX / (float)patternSizeX), 0);
            int maxVisiblePattern = Math.Min((int)Math.Ceiling((scrollX + Width) / (float)patternSizeX), Song.Length);

            // Track name background
            g.FillRectangle(0, 0, TrackNameSizeX, Height, whiteKeyBrush);

            // Header
            g.DrawLineHalfPixel(0, 0, Width, 0, theme.BlackBrush);
            g.DrawLineHalfPixel(TrackNameSizeX - 1, 0, TrackNameSizeX - 1, HeaderSizeY, theme.DarkGreyLineBrush1);
            g.PushTranslation(TrackNameSizeX, 0);
            g.PushClipHalfPixel(0, 0, Width, Height);

            for (int i = minVisiblePattern, x = minVisiblePattern * patternSizeX - scrollX; i <= maxVisiblePattern; i++, x += patternSizeX)
            {
                if (i != 0)
                {
                    g.DrawLineHalfPixel(x, 0, x, Height, theme.DarkGreyLineBrush1);
                }
            }

            for (int i = minVisiblePattern, x = minVisiblePattern * patternSizeX - scrollX; i < maxVisiblePattern; i++, x += patternSizeX)
            {
                g.PushTranslation(x, 0);
                g.DrawText(i.ToString(), Theme.FontMediumCenter, 0, 2, theme.LightGreyFillBrush1, patternSizeX);
                g.PopTransform();
            }

            g.PopClip();
            g.PopTransform();

            g.PushTranslation(0, HeaderSizeY);

            // Icons
            for (int i = 0, y = 0; i < Song.Channels.Length; i++, y += TrackSizeY)
            {
                g.DrawBitmap(bmpTracks[(int)Song.Channels[i].Type], 4, y + 4, (App.ChannelMask & (1 << i)) != 0 ? 1.0f : 0.2f);
            }

            // Track names
            for (int i = 0, y = 0; i < Song.Channels.Length; i++, y += TrackSizeY)
            {
                g.DrawText(Song.Channels[i].Name, i == selectedChannel ? Theme.FontMediumBold : Theme.FontMedium, 24, y + 4, theme.BlackBrush);
            }

            // Ghost note icons
            for (int i = 0, y = 0; i < Song.Channels.Length; i++, y += TrackSizeY)
            {
                g.DrawBitmap(bmpGhostNote, TrackNameSizeX - 16, y + TrackSizeY - 15, (App.GhostChannelMask & (1 << i)) != 0 ? 1.0f : 0.2f);
            }

            // Vertical line seperating the track labels.
            g.DrawLineHalfPixel(TrackNameSizeX - 1, 0, TrackNameSizeX - 1, Height, theme.DarkGreyLineBrush1);

            // Grey background rectangles ever other pattern + vertical lines
            g.PushClipHalfPixel(TrackNameSizeX, 0, Width, Height);
            g.PushTranslation(TrackNameSizeX, 0);
            for (int i = minVisiblePattern, x = minVisiblePattern * patternSizeX - scrollX; i < maxVisiblePattern; i++, x += patternSizeX)
            {
                if ((i & 1) == 0)
                {
                    g.FillRectangle(x, 0, x + patternSizeX, Height, theme.DarkGreyFillBrush2);
                }
            }
            for (int i = minVisiblePattern, x = minVisiblePattern * patternSizeX - scrollX; i <= maxVisiblePattern; i++, x += patternSizeX)
            {
                if (i != 0)
                {
                    g.DrawLineHalfPixel(x, 0, x, Height, theme.DarkGreyLineBrush1);
                }
            }
            g.PopTransform();
            g.PopClip();

            // Horizontal lines
            for (int i = 0, y = 0; i < Song.Channels.Length; i++, y += TrackSizeY)
            {
                g.DrawLineHalfPixel(0, y, Width, y, theme.DarkGreyLineBrush1);
            }

            g.PushClipHalfPixel(TrackNameSizeX, 0, Width, Height);

            // Seek
            int xxx = ScaleForZoom(App.CurrentFrame) + TrackNameSizeX - scrollX;

            g.DrawLineHalfPixel(xxx, -HeaderSizeY, xxx, Height, playPositionBrush);

            // Patterns
            for (int t = 0, y = 0; t < Song.Channels.Length; t++, y += TrackSizeY)
            {
                for (int i = minVisiblePattern, x = minVisiblePattern * patternSizeX + TrackNameSizeX - scrollX; i < maxVisiblePattern; i++, x += patternSizeX)
                {
                    var pattern = Song.Channels[t].PatternInstances[i];

                    if (pattern != null)
                    {
                        var bmp = GetPatternBitmapFromCache(pattern);

                        g.PushTranslation(x, y);
                        g.FillRectangle(1, 1, patternSizeX, PatternHeaderSizeY, g.GetVerticalGradientBrush(pattern.Color, PatternHeaderSizeY, 0.9f));
                        g.DrawLineHalfPixel(0, PatternHeaderSizeY, patternSizeX, PatternHeaderSizeY, theme.DarkGreyLineBrush1);
                        if (IsPatternSelected(t, i))
                        {
                            g.FillRectangle(1, 1 + PatternHeaderSizeY, PatternSizeX, PatternHeaderSizeY + bmp.Size.Height + 1, selectedPatternBrush);
                        }

                        g.DrawBitmap(bmp, 1, 1 + PatternHeaderSizeY, PatternSizeX - 1, bmp.Size.Height);
                        g.PushClipHalfPixel(0, 0, PatternSizeX, Height);
                        g.DrawText(pattern.Name, Theme.FontSmall, 2, 3, theme.BlackBrush);
                        g.PopClip();
                        g.PopTransform();
                    }
                }
            }

            // Dragging selection
            if (isDraggingSelection)
            {
                var pt = this.PointToClient(Cursor.Position);

                //pt.X -= TrackNameSizeX;
                pt.Y -= HeaderSizeY;

                var drawX = pt.X - selectionDragAnchorX;
                var drawY = minSelectedChannelIdx * TrackSizeY;
                var sizeX = (maxSelectedPatternIdx - minSelectedPatternIdx + 1) * patternSizeX;
                var sizeY = (maxSelectedChannelIdx - minSelectedChannelIdx + 1) * TrackSizeY;

                g.FillRectangle(drawX, drawY, drawX + sizeX, drawY + sizeY, selectedPatternBrush);
            }

            g.PopClip();
            g.PopTransform();

            g.DrawLineHalfPixel(0, Height - 1, Width, Height - 1, theme.DarkGreyLineBrush1);
        }
Exemple #16
0
        protected override void OnRender(Direct2DGraphics g)
        {
            g.Clear(Theme.DarkGreyFillColor1);
            g.DrawLineHalfPixel(0, 0, 0, Height, theme.BlackBrush);

            int actualWidth = Width - ScrollBarSizeX;

            int y = -scrollY;

            g.PushTranslation(0, y);
            g.FillAndDrawRectangleHalfPixel(0, 0, actualWidth, ButtonSizeY, g.GetVerticalGradientBrush(Theme.LightGreyFillColor2, ButtonSizeY, 0.8f), theme.BlackBrush);
            g.DrawText("Songs", Theme.FontMediumBoldCenter, 0, 5, theme.BlackBrush, actualWidth);
            g.DrawBitmap(bmpAdd, actualWidth - 20, 4);
            g.PopTransform();
            y += ButtonSizeY;

            for (int i = 0; i < App.Project.Songs.Count; i++, y += ButtonSizeY)
            {
                var song = App.Project.Songs[i];

                g.PushTranslation(0, y);
                g.FillAndDrawRectangleHalfPixel(0, 0, actualWidth, ButtonSizeY, g.GetVerticalGradientBrush(Direct2DGraphics.ToRawColor4(song.Color), ButtonSizeY, 0.8f), theme.BlackBrush);
                g.DrawText(song.Name, song == selectedSong ? Theme.FontMediumBold : Theme.FontMedium, 24, 5, theme.BlackBrush);
                g.DrawBitmap(bmpSong, 4, 4);

                //var rcVolume = GetVolumeRect();
                //g.DrawBitmap(bmpVolume, rcVolume.X, rcVolume.Y, instrument.Envelopes[Envelope.Volume].Length > 0 ? 1.0f : 0.2f);

                g.PopTransform();
            }

            g.PushTranslation(0, y);
            g.FillAndDrawRectangleHalfPixel(0, 0, actualWidth, ButtonSizeY, g.GetVerticalGradientBrush(Theme.LightGreyFillColor2, ButtonSizeY, 0.8f), theme.BlackBrush);
            g.DrawText("Instruments", Theme.FontMediumBoldCenter, 0, 5, theme.BlackBrush, actualWidth);
            g.DrawBitmap(bmpAdd, actualWidth - 20, 4);
            g.PopTransform();
            y += ButtonSizeY;

            g.PushTranslation(0, y);
            g.FillAndDrawRectangleHalfPixel(0, 0, actualWidth, ButtonSizeY, g.GetVerticalGradientBrush(Theme.LightGreyFillColor1, ButtonSizeY, 0.8f), theme.BlackBrush);
            g.DrawText("DPCM Samples", SelectedInstrument == null ? Theme.FontMediumBold : Theme.FontMedium, 24, 5, theme.BlackBrush);
            g.DrawBitmap(bmpInstrument, 4, 4);
            g.DrawBitmap(bmpDPCM, actualWidth - 20, 4);
            g.PopTransform();
            y += ButtonSizeY;

            for (int i = 0; i < App.Project.Instruments.Count; i++, y += ButtonSizeY)
            {
                var instrument = App.Project.Instruments[i];

                g.PushTranslation(0, y);
                g.FillAndDrawRectangleHalfPixel(0, 0, actualWidth, ButtonSizeY, g.GetVerticalGradientBrush(instrument.Color, ButtonSizeY, 0.8f), theme.BlackBrush);
                g.DrawText(instrument.Name, instrument == SelectedInstrument ? Theme.FontMediumBold : Theme.FontMedium, 24, 5, theme.BlackBrush);

                var rcVolume   = GetButtonRect(4);
                var rcPitch    = GetButtonRect(3);
                var rcArpeggio = GetButtonRect(2);
                var rcDuty     = GetButtonRect(1);

                g.DrawBitmap(bmpInstrument, 4, 4);
                g.DrawBitmap(bmpVolume, rcVolume.X, rcVolume.Y, instrument.Envelopes[Envelope.Volume].Length > 0 ? 1.0f : 0.2f);
                g.DrawBitmap(bmpPitch, rcPitch.X, rcPitch.Y, instrument.Envelopes[Envelope.Pitch].Length > 0 ? 1.0f : 0.2f);
                g.DrawBitmap(bmpArpeggio, rcArpeggio.X, rcArpeggio.Y, instrument.Envelopes[Envelope.Arpeggio].Length > 0 ? 1.0f : 0.2f);
                g.DrawBitmap(bmpDuty[instrument.DutyCycle], rcDuty.X, rcDuty.Y, 1.0f);

                g.PopTransform();
            }

            if (NeedsScrollBar)
            {
                int virtualSizeY   = VirtualSizeY;
                int scrollBarSizeY = (int)Math.Round(Height * (Height / (float)virtualSizeY));
                int scrollBarPosY  = (int)Math.Round(Height * (scrollY / (float)virtualSizeY));

                g.FillAndDrawRectangleHalfPixel(actualWidth, 0, Width - 1, Height, theme.DarkGreyFillBrush1, theme.BlackBrush);
                g.FillAndDrawRectangleHalfPixel(actualWidth, scrollBarPosY, Width - 1, scrollBarPosY + scrollBarSizeY, theme.LightGreyFillBrush1, theme.BlackBrush);
            }
        }
 protected virtual void OnDirect2DInitialized(Direct2DGraphics g)
 {
 }
 protected virtual void OnRender(Direct2DGraphics g)
 {
 }