using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace xServer.Controls.HexEditor { public class HexViewHandler { #region Fields bool _isEditing; /// /// Contains info about how to /// present the hex values /// (Upper or Lower case) /// string _hexType = "X2"; /// /// Contains the boundary for one single /// hexa value that is visible /// Rectangle _recHexValue; /// /// Contains the format of the hexadecimal /// strings that are presented /// StringFormat _stringFormat; private HexEditor _editor; #endregion #region Properties public int MaxWidth { get { return _recHexValue.X + (_recHexValue.Width * _editor.BytesPerLine); } } #endregion #region Constructor public HexViewHandler(HexEditor editor) { _editor = editor; //Set String format for the hex values _stringFormat = new StringFormat(StringFormat.GenericTypographic); _stringFormat.Alignment = StringAlignment.Center; _stringFormat.LineAlignment = StringAlignment.Center; } #endregion #region Method #region KeyMouseEvents #region KeyEvents public void OnKeyPress(KeyPressEventArgs e) { if (IsHex(e.KeyChar)) HandleUserInput(e.KeyChar); } public void OnKeyDown(KeyEventArgs e) { if (e.KeyCode == Keys.Delete || e.KeyCode == Keys.Back) { if (_editor.SelectionLength > 0) { //Remove the selected bytes HandleUserRemove(); int index = _editor.CaretIndex; Point newLocation = GetCaretLocation(index); _editor.SetCaretStart(index, newLocation); } else if (_editor.CaretIndex < _editor.LastVisibleByte && e.KeyCode == Keys.Delete) { //Remove the byte after the caret _editor.RemoveByteAt(_editor.CaretIndex); Point newLocation = GetCaretLocation(_editor.CaretIndex); _editor.SetCaretStart(_editor.CaretIndex, newLocation); } else if (_editor.CaretIndex > 0 && e.KeyCode == Keys.Back) { //Remove byte before the caret int index = _editor.CaretIndex - 1; if (_isEditing) { //Remove the byte that is being edited index = _editor.CaretIndex; } _editor.RemoveByteAt(index); Point newLocation = GetCaretLocation(index); _editor.SetCaretStart(index, newLocation); } _isEditing = false; } else if (e.KeyCode == Keys.Up && (_editor.CaretIndex - _editor.BytesPerLine) >= 0) { int index = _editor.CaretIndex - _editor.BytesPerLine; //Check ig caret is att the end of the line if (index % _editor.BytesPerLine == 0 && _editor.CaretPosX >= _recHexValue.X + _recHexValue.Width * _editor.BytesPerLine) { Point position = new Point(_editor.CaretPosX, _editor.CaretPosY - _recHexValue.Height); //check that this is not the last row (nothing above) if (index == 0) { //Last row do not change index and position position = new Point(_editor.CaretPosX, _editor.CaretPosY); index = _editor.BytesPerLine; } if (e.Shift) _editor.SetCaretEnd(index, position); else _editor.SetCaretStart(index, position); _isEditing = false; } else { HandleArrowKeys(index, e.Shift); } } else if (e.KeyCode == Keys.Down && (_editor.CaretIndex - 1) / _editor.BytesPerLine < _editor.HexTableLength / _editor.BytesPerLine) { int index = _editor.CaretIndex + _editor.BytesPerLine; if (index > _editor.HexTableLength) { index = _editor.HexTableLength; HandleArrowKeys(index, e.Shift); } else { Point position = new Point(_editor.CaretPosX, _editor.CaretPosY + _recHexValue.Height); if (e.Shift) _editor.SetCaretEnd(index, position); else _editor.SetCaretStart(index, position); _isEditing = false; } } else if (e.KeyCode == Keys.Left && (_editor.CaretIndex - 1) >= 0) { int index = _editor.CaretIndex - 1; HandleArrowKeys(index, e.Shift); } else if (e.KeyCode == Keys.Right && (_editor.CaretIndex + 1) <= _editor.HexTableLength) { int index = _editor.CaretIndex + 1; HandleArrowKeys(index, e.Shift); } } public void HandleArrowKeys(int index, bool isShiftDown) { Point position = GetCaretLocation(index); if (isShiftDown) _editor.SetCaretEnd(index, position); else _editor.SetCaretStart(index, position); _isEditing = false; } #endregion #region MouseEvent public void OnMouseDown(int x, int y) { int iX = (x - _recHexValue.X) / _recHexValue.Width; int iY = (y - _recHexValue.Y) / _recHexValue.Height; //Check that values are good iX = iX > _editor.BytesPerLine ? _editor.BytesPerLine : iX; iX = iX < 0 ? 0 : iX; iY = iY > _editor.MaxBytesV ? _editor.MaxBytesV : iY; iY = iY < 0 ? 0 : iY; //Make sure values are withing the given bounds if ((_editor.LastVisibleByte - _editor.FirstVisibleByte) / _editor.BytesPerLine <= iY) { //Check that column is not greater than max if ((_editor.LastVisibleByte - _editor.FirstVisibleByte) % _editor.BytesPerLine <= iX) { iX = (_editor.LastVisibleByte - _editor.FirstVisibleByte) % _editor.BytesPerLine; } iY = (_editor.LastVisibleByte - _editor.FirstVisibleByte) / _editor.BytesPerLine; } //Get the smallest possible location (do not want to exceed the max) int index = Math.Min(_editor.LastVisibleByte, _editor.FirstVisibleByte + iX + (iY * _editor.BytesPerLine)); int xPos = (iX * _recHexValue.Width) + _recHexValue.X; int yPos = (iY * _recHexValue.Height) + _recHexValue.Y; _editor.SetCaretStart(index, new Point(xPos, yPos)); _isEditing = false; } public void OnMouseDragged(int x, int y) { int iX = (x - _recHexValue.X) / _recHexValue.Width; int iY = (y - _recHexValue.Y) / _recHexValue.Height; //Check that values are good iX = iX > _editor.BytesPerLine ? _editor.BytesPerLine : iX; iX = iX < 0 ? 0 : iX; iY = iY > _editor.MaxBytesV ? _editor.MaxBytesV : iY; if (_editor.FirstVisibleByte > 0) { iY = iY < 0 ? -1 : iY; } else { iY = iY < 0 ? 0 : iY; } //Make sure values are withing the given bounds if ((_editor.LastVisibleByte - _editor.FirstVisibleByte) / _editor.BytesPerLine <= iY) { //Check that column is not greater than max if ((_editor.LastVisibleByte - _editor.FirstVisibleByte) % _editor.BytesPerLine <= iX) { iX = (_editor.LastVisibleByte - _editor.FirstVisibleByte) % _editor.BytesPerLine; } iY = (_editor.LastVisibleByte - _editor.FirstVisibleByte) / _editor.BytesPerLine; } //Get the smallest possible location (do not want to exceed the max) int index = Math.Min(_editor.LastVisibleByte, _editor.FirstVisibleByte + iX + (iY * _editor.BytesPerLine)); int xPos = (iX * _recHexValue.Width) + _recHexValue.X; int yPos = (iY * _recHexValue.Height) + _recHexValue.Y; _editor.SetCaretEnd(index, new Point(xPos, yPos)); } public void OnMouseDoubleClick() { if (_editor.CaretIndex < _editor.LastVisibleByte) { int index = _editor.CaretIndex + 1; Point newLocation = GetCaretLocation(index); _editor.SetCaretEnd(index, newLocation); } } #endregion #endregion #region PaintMethod public void Update(int startPositionX, Rectangle area) { _recHexValue = new Rectangle( startPositionX, area.Y, (int)(_editor.CharSize.Width * 3), (int)(_editor.CharSize.Height) - 2 ); _recHexValue.X += _editor.EntityMargin; } public void Paint(Graphics g, int index, int startIndex) { Point columnAndRow = GetByteColumnAndRow(index); if (_editor.IsSelected(index + startIndex)) { PaintByteAsSelected(g, columnAndRow, (index + startIndex)); } else { PaintByte(g, columnAndRow, (index + startIndex)); } } private void PaintByteAsSelected(Graphics g, Point point, int index) { SolidBrush backBrush = new SolidBrush(_editor.SelectionBackColor); SolidBrush textBrush = new SolidBrush(_editor.SelectionForeColor); RectangleF drawSurface = GetBound(point); string hexValue = _editor.GetByte(index).ToString(_hexType); g.FillRectangle(backBrush, drawSurface); g.DrawString(hexValue, _editor.Font, textBrush, drawSurface, _stringFormat); } private void PaintByte(Graphics g, Point point, int index) { SolidBrush brush = new SolidBrush(_editor.ForeColor); RectangleF drawSurface = GetBound(point); string hexValue = _editor.GetByte(index).ToString(_hexType); g.DrawString(hexValue, _editor.Font, brush, drawSurface, _stringFormat); } #endregion public void SetLowerCase() { _hexType = "x2"; } public void SetUpperCase() { _hexType = "X2"; } public void Focus() { int index = _editor.CaretIndex; Point location = GetCaretLocation(index); _editor.SetCaretStart(index, location); } #endregion #region Caret /// /// Get the caret current location /// in the given bound. /// private Point GetCaretLocation(int index) { int xPos = _recHexValue.X + (_recHexValue.Width * (index % _editor.BytesPerLine)); int yPos = _recHexValue.Y + (_recHexValue.Height * ((index - (_editor.FirstVisibleByte + index % _editor.BytesPerLine)) / _editor.BytesPerLine)); Point ret = new Point(xPos, yPos); return ret; } #endregion #region Misc private void HandleUserRemove() { //Calculate where to position the caret after the removal int index = _editor.SelectionStart; Point position = GetCaretLocation(index); //Remove all of the selected bytes _editor.RemoveSelectedBytes(); //Set the new position of the caret _editor.SetCaretStart(index, position); } private void HandleUserInput(char key) { if (!_editor.CaretFocused) return; //Perform overwrite HandleUserRemove(); if (_isEditing) { //Editing has already started, should change the second nibble _isEditing = false; //Load old bytes to allow change byte oldByte = _editor.GetByte(_editor.CaretIndex); //Append the new nibble oldByte += Convert.ToByte(key.ToString(), 16); _editor.SetByte(_editor.CaretIndex, oldByte); //Relocate the caret int index = _editor.CaretIndex + 1; Point newLocation = GetCaretLocation(index); _editor.SetCaretStart(index, newLocation); } else { //Begin new edit phase _isEditing = true; string hexByte = key.ToString() + "0"; byte newByte = Convert.ToByte(hexByte, 16); if (_editor.HexTable.Length <= 0) { _editor.AppendByte(newByte); } else { _editor.InsertByte(_editor.CaretIndex, newByte); } //Relocate the caret to the middle of the hex value (provide illusion of editing the second value) int xPos = (_recHexValue.X + (_recHexValue.Width * ((_editor.CaretIndex) % _editor.BytesPerLine)) + (_recHexValue.Width / 2)); int yPos = _recHexValue.Y + (_recHexValue.Height * ((_editor.CaretIndex - (_editor.FirstVisibleByte + _editor.CaretIndex % _editor.BytesPerLine)) / _editor.BytesPerLine)); _editor.SetCaretStart(_editor.CaretIndex, new Point(xPos, yPos)); } } private Point GetByteColumnAndRow(int index) { int column = index % _editor.BytesPerLine; int row = index / _editor.BytesPerLine; Point ret = new Point(column, row); return ret; } private RectangleF GetBound(Point point) { RectangleF ret = new RectangleF( _recHexValue.X + (point.X * _recHexValue.Width), _recHexValue.Y + (point.Y * _recHexValue.Height), _recHexValue.Width, _recHexValue.Height ); return ret; } private bool IsHex(char c) { return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || Char.IsDigit(c); } #endregion } }