This project is read-only.

HexView

HexView is a primary rendering content control. It is responsible for the rendering actually visible "window" frame in byte data array.

Legend

This legend text is rendered once per row, if required. DefaultLegend() method is used to measure widest string of chars for a hexadecimal representation of a legend row number. GetLegend() method is used to get actual bounding rectangle for the drawing method. Graphics.DrawString() method is used to render visible content on a screen.

       private SizeF DefaultLegend(Graphics g)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("{0}{0}{0}{0}{0}{0}{0}{0}");
            return GetSize(g, sb.ToString());
        }

        private SizeF DefaultBlock(Graphics g)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < model.BytesPerColumn; i++)
            {
                sb.Append("{0}{0}");
            }
            sb.Append("{1}");
            return GetSize(g, sb.ToString());
        }

        private string GetLegend(int row)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("{0:x8}", row * model.ColumnsPerRow * model.BytesPerColumn);
            return sb.ToString();
        }

        private SizeF GetSize(Graphics g, string format)
        {
            SizeF result = new SizeF();
            foreach (char ch in chars)
            {
                SizeF current = g.MeasureString(string.Format(format, ch, delimiter), Font, 0, StringFormats.Default);
                if (current.Width > result.Width)
                {
                    result = current;
                }
            }
            return result;
        }

        private char delimiter = ' ';
        private char[] chars = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f' };

OnPaint()

Before rendering, we are going to set several high quality rendering options to visually improve graphics rendering (font glyphs, anti-aliasing, etc.)

        protected override void OnPaint(PaintEventArgs e)
        {
            if (!DesignMode)
            {
                SetRenderingOptions(e.Graphics);
                DrawRows(e.Graphics, model.Row, model.Column);
            }
            base.OnPaint(e);
        }

DrawRows()

Render process is very straightforward: render legend, render row. Inspect the implementation:

        private void DrawRows(Graphics g, int row, int col)
        {
            float offset = 0;
            if (model.DrawLegend)
            {
                offset = legend.Width;
            }
            SolidBrush foreBrush = new SolidBrush(this.ForeColor);
            for (int i = row; i < model.MaxRows; i++)
            {
                if ((i - row) * block.Height > this.ClientRectangle.Height)
                {
                    break;
                }
                if (model.DrawLegend)
                {
                    DrawLegend(g, foreBrush, i, row);
                }
                for (int j = col; j < model.MaxColumns; j++)
                {
                    if (offset + (j - col) * block.Width > this.ClientRectangle.Width)
                    {
                        break;
                    }
                    DrawBlock(g, foreBrush, offset, i, j, row, col);
                }
            }
        }

UpdateModel() function

There are two functions, DefaultLegend() and DefaultBlock() are used to measure two rendering block type sizes: one for the legend and the other for the byte group (column). This method affects to the results for all methods of the cotrol.

        public void UpdateModel()
        {
            using (Graphics g = this.CreateGraphics())
            {
                SetRenderingOptions(g);
                legend = DefaultLegend(g);
                block = DefaultBlock(g);
            }
        }

Rendering

Drawing is easy, when you know position and bounding rectangle of object

        private void DrawLegend(Graphics g, SolidBrush foreBrush, int i, int row)
        {
            g.DrawString(
                GetLegend(i), 
                this.Font, 
                foreBrush, 
                new RectangleF(
                    0, 
                    (i - row) * block.Height, 
                    legend.Width, 
                    block.Height), 
                StringFormats.Default);
        }

        private void DrawBlock(Graphics g, SolidBrush foreBrush, float offset, int i, int j, int row, int col)
        {
            g.DrawString(
                GetBlock(i, j), 
                this.Font, 
                foreBrush, 
                new RectangleF(
                    offset + (j - col) * block.Width, 
                    (i - row) * block.Height, 
                    block.Width, 
                    block.Height), 
                StringFormats.Default);
        }

        private void DrawBlock(Graphics g, SolidBrush backBrush, SolidBrush foreBrush, float offset, int i, int j, int row, int col)
        {
            RectangleF rect = new RectangleF(
                offset + (j - col) * block.Width, 
                (i - row) * block.Height, 
                block.Width, 
                block.Height);
            g.FillRectangle(backBrush, rect);
            g.DrawString(
                GetBlock(i, j), 
                this.Font, 
                foreBrush, 
                rect, StringFormats.Default);
        }

DrawBlock()

This is actual DrawBlock() method implementation in a HexView control

        public void DrawBlock(int byteIndex)
        {
            int maxColumns = model.MaxColumns;
            int maxRows = model.MaxRows;
            int modelRow = model.Row;
            int modelColumn = model.Column;

            bool drawLegend = model.DrawLegend;

            int currentIndex = byteIndex / model.BytesPerColumn;
            int currentRow = currentIndex / maxColumns;
            int currentColumn = currentIndex % maxColumns;

            if (currentRow >= modelRow && currentRow <= modelRow + GetVisibleRows() && currentColumn >= modelColumn && currentColumn <= modelColumn + GetVisibleColumns())
            {
                int row = currentIndex / maxColumns;
                int col = currentIndex % maxColumns;
                SolidBrush foreBrush = new SolidBrush(ForeColor);
                SolidBrush backBrush = new SolidBrush(BackColor);
                using (Graphics g = this.CreateGraphics())
                {
                    SetRenderingOptions(g);
                    if (drawLegend)
                    {
                        DrawBlock(g, backBrush, foreBrush, legend.Width, row, col, modelRow, modelColumn);
                    }
                    else
                    {
                        DrawBlock(g, backBrush, foreBrush, 0, row, col, modelRow, modelColumn);
                    }
                }
            }
        }

Last edited May 1, 2012 at 4:34 AM by hack2root, version 24

Comments

No comments yet.