//
        // Interface

        public HexagonButton(Style style)
        {
            Style = style;

            _neighbors    = new HexagonButton[6];
            _nominalColor = Color.FromScRgb(1f, 1f, 1f, 1f);
        }
        void cell_Clicked(object sender, RoutedEventArgs e)
        {
            HexagonButton cell = sender as HexagonButton;

            if (cell != null)
            {
                m_selectedColor = cell.NominalColor;
            }
            FireColorSelected();
        }
        void InitializeChildrenR(HexagonButton parent, int generation)
        {
            if (generation > MaxGenerations)
            {
                return;
            }

            // Create up to 6 surrounding nodes.
            for (int i = 0; i < 6; ++i)
            {
                if (parent.Neighbors[i] == null)
                {
                    HexagonButton cell = new HexagonButton(FindResource("HexagonButtonStyle") as Style);
                    double        dx   = Canvas.GetLeft(parent) + HexagonButton.Offset * Math.Cos(i * Math.PI / 3d);
                    double        dy   = Canvas.GetTop(parent) + HexagonButton.Offset * Math.Sin(i * Math.PI / 3d);
                    Canvas.SetLeft(cell, dx);
                    Canvas.SetTop(cell, dy);
                    canvas1.Children.Add(cell);
                    parent.Neighbors[i] = cell;

                    cell.Click += cell_Clicked;
                }
            }

            // Set the cross-pointers on the 6 surrounding nodes.
            for (int i = 0; i < 6; ++i)
            {
                HexagonButton child = parent.Neighbors[i];
                if (child != null)
                {
                    int ip3 = (i + 3) % 6;
                    child.Neighbors[ip3] = parent;

                    int ip1 = (i + 1) % 6;
                    int ip2 = (i + 2) % 6;
                    int im1 = (i + 5) % 6;
                    int im2 = (i + 4) % 6;
                    child.Neighbors[ip2] = parent.Neighbors[ip1];
                    child.Neighbors[im2] = parent.Neighbors[im1];
                }
            }

            // Recurse into each of the 6 surrounding nodes.
            for (int i = 0; i < 6; ++i)
            {
                InitializeChildrenR(parent.Neighbors[i], generation + 1);
            }
        }
        void InitializeChildren()
        {
            // Define honeycomb of 127 hexagons, starting in the center of the canvas.
            _rootCell = new HexagonButton(FindResource("HexagonButtonStyle") as Style);
            Canvas.SetLeft(_rootCell, canvas1.Width / 2);
            Canvas.SetTop(_rootCell, canvas1.Height / 2);
            canvas1.Children.Add(_rootCell);

            _rootCell.Click += cell_Clicked;

            // Expand outward (recursive loop).
            InitializeChildrenR(_rootCell, 1);

            // Apply nominal color gradients.
            CascadeChildColors();
        }
        static void CascadeChildColorsR(HexagonButton parent)
        {
            const float delta   = 1f / MaxGenerations;
            const float ceiling = 0.99f;

            System.Collections.Generic.List <HexagonButton> visitedNodes =
                new System.Collections.Generic.List <HexagonButton>(6);

            for (int i = 0; i < 6; ++i)
            {
                HexagonButton child = parent.Neighbors[i];
                if (child == null || child.Visited)
                {
                    continue;
                }
                Color c = parent.NominalColor;
                switch (i)
                {
                case 0: // increase cyan; else reduce red
                    if (c.ScG < ceiling && c.ScB < ceiling)
                    {
                        c.ScG = Math.Min(Math.Max(0f, c.ScG + delta), 1f);
                        c.ScB = Math.Min(Math.Max(0f, c.ScB + delta), 1f);
                    }
                    else
                    {
                        c.ScR = Math.Min(Math.Max(0f, c.ScR - delta), 1f);
                    }
                    break;

                case 1: // increase blue; else reduce yellow
                    if (c.ScB < ceiling)
                    {
                        c.ScB = Math.Min(Math.Max(0f, c.ScB + delta), 1f);
                    }
                    else
                    {
                        c.ScR = Math.Min(Math.Max(0f, c.ScR - delta), 1f);
                        c.ScG = Math.Min(Math.Max(0f, c.ScG - delta), 1f);
                    }
                    break;

                case 2: // increase magenta; else reduce green
                    if (c.ScR < ceiling && c.ScB < ceiling)
                    {
                        c.ScR = Math.Min(Math.Max(0f, c.ScR + delta), 1f);
                        c.ScB = Math.Min(Math.Max(0f, c.ScB + delta), 1f);
                    }
                    else
                    {
                        c.ScG = Math.Min(Math.Max(0f, c.ScG - delta), 1f);
                    }
                    break;

                case 3: // increase red; else reduce cyan
                    if (c.ScR < ceiling)
                    {
                        c.ScR = Math.Min(Math.Max(0f, c.ScR + delta), 1f);
                    }
                    else
                    {
                        c.ScG = Math.Min(Math.Max(0f, c.ScG - delta), 1f);
                        c.ScB = Math.Min(Math.Max(0f, c.ScB - delta), 1f);
                    }
                    break;

                case 4: // increase yellow; else reduce blue
                    if (c.ScR < ceiling && c.ScG < ceiling)
                    {
                        c.ScR = Math.Min(Math.Max(0f, c.ScR + delta), 1f);
                        c.ScG = Math.Min(Math.Max(0f, c.ScG + delta), 1f);
                    }
                    else
                    {
                        c.ScB = Math.Min(Math.Max(0f, c.ScB - delta), 1f);
                    }
                    break;

                case 5: // increase green; else reduce magenta
                    if (c.ScG < ceiling)
                    {
                        c.ScG = Math.Min(Math.Max(0f, c.ScG + delta), 1f);
                    }
                    else
                    {
                        c.ScR = Math.Min(Math.Max(0f, c.ScR - delta), 1f);
                        c.ScB = Math.Min(Math.Max(0f, c.ScB - delta), 1f);
                    }
                    break;
                }
                child.NominalColor = c;
                child.Visited      = true;
                visitedNodes.Add(child);
            }

            parent.Visited = true; // ensures root node not over-visited
            foreach (HexagonButton child in visitedNodes)
            {
                CascadeChildColorsR(child);
            }
        }