unit HexEdit;interfaceuses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;type
  TCaretStyle = (csFull , csLeftLine , csBottomLine );  TBlock = record
    BX: Integer;
    BY: Integer;
  end;  THexEdit = class(TCustomControl)
  private
    FActive: Boolean;
    FReadOnly: Boolean;
    FTopLine: Integer;
    FLeftCol: Integer;
    FCurrentLine: Integer;
    FCurrentCol: Integer;
    FUpdateByte: Byte;
    FVisibleLines: Integer;
    FVisibleCols: Integer;
    FLineCount: Integer;
    FColCount: Integer;
    FBytesPerLine: Integer;
    FItemHeight: Integer;
    FItemWidth: Integer;
    FFileColors: array[0..2] of TColor;
    FShowCharacters: Boolean;
    FShowAddress: Boolean;
    FBorder: TBorderStyle;
    FCaretRow,FCaretCol: Integer;
    FLineAddr: array[0..15] of char;
    FTextWidth: Integer;
    FCaretCreate: Boolean;
    FLButtonDown: Boolean;
    FBlockBegin: TBlock;
    FBlockEnd: TBlock;
    //FSelStartCol,FSelStartLine: Integer;
    //FSelectStartCol,FSelectStartLine: Integer;
    //FOldSelectEndCol,FOldSelectEndLine: Integer;
    //FSelectEndCol,FSelectEndLine: Integer;
    FMStream: TMemoryStream;
    FModified: Boolean;
    FInvertRgn: HRGN;
    FOnMouseDown: TNotifyEvent;
    FOffset: Integer;
    FCurrentByteValue: Byte;
    FOnKeyDown: TNotifyEvent;
    FCurrentCardinalValue: Cardinal;
    FCurrentWordValue: Word;
    procedure CalcPaintParams;
    //procedure SetReadOnly(Value: Boolean);
    procedure SetTopLine(Value: Integer);
    procedure SetCurrentCol(Value: Integer);
    procedure SetCurrentLine(Value: Integer);
    procedure SetFileColor(Index: Integer; Value: TColor);
    function GetFileColor(Index: Integer): TColor;
    procedure SetShowCharacters(Value: Boolean);
    procedure SetShowAddress(Value: Boolean);
    procedure SetBorder(Value: TBorderStyle);
    procedure SetAddress(Value: Pointer);
    function GetDataSize: Integer;
    procedure SetDataSize(Value: Integer);
    procedure AdjustScrollBars;
    function LineAddr(Index: Integer): PChar;
    function LineData(Index: Integer): PChar;
    function LineChars(Index: Integer): PChar;
    function ScrollIntoView: Boolean;
//    procedure InvalidateLine(Index: Integer);
    procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
    procedure CMEnter(var Message: TCMGotFocus); message CM_ENTER;
    procedure CMExit(var Message: TCMLostFocus); message CM_EXIT;
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
    procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
    procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
    procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
    //procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
    procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
    procedure SetCaretPosition;
    procedure SetCaretCol(Value: Integer);
    procedure SetCaretRow(Value: Integer);
    procedure SetLeftCol(Value: Integer);
    procedure PaintCell(ACol,ARow: Integer); overload;
    procedure PaintCell; overload;
    procedure PaintLine(Index: Integer);
    procedure SetSelction;
    function GetRgn(var StartCol,StartLine,EndCol,EndLine: Integer): HRgn;
    procedure SetOffset(const Value: Integer);
    procedure SetCurrentByteValue(Value: Byte);
    procedure SetCurrentCardinalValue(Value: Cardinal);
    procedure SetCurrentWordValue(Value: Word);
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure Paint; override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure UpdateView;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure LoadFromFile(const FileName: TFileName);
    procedure LoadFromStream(Stream: TStream);
    procedure SaveToFile(const FileName: TFileName);
    procedure SaveToStream(Stream: TStream);
    property CurrentLine: Integer read FCurrentLine write SetCurrentLine;
    property CaretCol: Integer read FCaretCol write SetCaretCol;
    property CurrentCol: Integer read FCurrentCol write SetCurrentCol;
    property CaretRow: Integer read FCaretRow write SetCaretRow;
    property LeftCol: Integer read FLeftCol write SetLeftCol;
    property Offset: Integer read FOffset write SetOffset;
    property CurrentByteValue: Byte read FCurrentByteValue write SetCurrentByteValue;
    property CurrentWordValue: Word read FCurrentWordValue write SetCurrentWordValue;
    property CurrentCardinalValue: Cardinal read FCurrentCardinalValue write SetCurrentCardinalValue;
    //property DataSize: Integer read GetDataSize write SetDataSize;
    property Modified: Boolean read FModified;
  published
    property Align;
    property Border: TBorderStyle read FBorder write SetBorder default bsNone;
    property Color default clWhite;
    property Ctl3D;
    property Font;
    property PopupMenu;
    property ReadOnly: Boolean read FReadOnly write FReadOnly;
    property TabOrder;
    property TabStop;
    property ShowAddress: Boolean read FShowAddress write SetShowAddress default True;
    property ShowCharacters: Boolean read FShowCharacters write SetShowCharacters default True;
    property AddressColor: TColor index 0 read GetFileColor write SetFileColor default clBlack;
    property HexDataColor: TColor index 1 read GetFileColor write SetFileColor default clBlack;
    property AnsiCharColor: TColor index 2 read GetFileColor write SetFileColor default clBlack;
    property OnMouseDown: TNotifyEvent read FOnMouseDown write FOnMouseDown;
    property OnKeyDown: TNotifyEvent read FOnKeyDown write FOnKeyDown;
  end;const
  MAXDIGITS = 16;
  AlphaDigit = [48..57,65..70,96..105];procedure Register;implementationprocedure Register;
begin
  RegisterComponents('LCC', [THexEdit]);
end;{ THexEdit }constructor THexEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := [csFramed];
  FBorder := bsNone;
  Color := clWhite;
  FShowAddress := True;
  FShowCharacters := True;
  Width := 300;
  Height := 200;
  FBytesPerLine:=16;
  FVisibleLines:=16;
  FItemHeight:=12;
  FItemWidth:=18;
  FCaretCreate:=False;
  FLButtonDown:=False;
  FMStream:=TMemoryStream.Create;
  FModified:=False;
end;destructor THexEdit.Destroy;
begin
  FMStream.Free;
  inherited Destroy;
end;
procedure THexEdit.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  //CreateSubClass(Params, 'RICHEDIT');
  with Params do
  begin
    Style := Style or WS_TABSTOP or WS_VSCROLL or WS_HSCROLL;
    WindowClass.style := CS_DBLCLKS;
    if FBorder = bsSingle then
      if NewStyleControls and Ctl3D then
      begin
        Style := Style and not WS_BORDER;
        ExStyle := ExStyle or WS_EX_CLIENTEDGE;
      end
      else
        Style := Style and not WS_BORDER;
  end;end;{procedure THexEdit.SetReadOnly(Value: Boolean);
begin
  if
end;}{ VCL Command Messages }procedure THexEdit.CMFontChanged(var Message: TMessage);
begin
  inherited;
  Canvas.Font := Self.Font;
  FItemHeight := Canvas.TextHeight('A');// + 2;
  FItemWidth := Canvas.TextWidth('D');
  CalcPaintParams;
  AdjustScrollBars;
end;procedure THexEdit.CMEnter;
begin
  inherited;
{  InvalidateLineMarker; }
end;procedure THexEdit.CMExit;
begin
  inherited;
{  InvalidateLineMarker; }
end;{ Windows Messages }procedure THexEdit.WMSize(var Message: TWMSize);
begin
  inherited;
  CalcPaintParams;
  AdjustScrollBars;
end;procedure THexEdit.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
  Message.Result := DLGC_WANTARROWS;
end;procedure THexEdit.SetLeftCol(Value: Integer);
var
  R: TRect;
begin
  if Value <> FLeftCol then
  begin
    SetScrollPos(Handle, SB_HORZ, Value, True);
    R := Bounds(0, 0, ClientWidth , ClientHeight);
    ScrollWindow(Handle, FItemWidth * (FLeftCol - Value),0, @R, nil);
    FLeftCol := Value;
  end;
end;procedure THexEdit.WMHScroll(var Message: TWMHScroll);
var
  NewLeftCol: Integer;
  //R: TRect;
begin
  inherited;
  NewLeftCol := FLeftCol;
  case Message.ScrollCode of
    SB_LINEDOWN: Inc(NewLeftCol);
    SB_LINEUP: Dec(NewLeftCol);
    SB_PAGEDOWN: Inc(NewLeftCol, FVisibleCols - 1);
    SB_PAGEUP: Dec(NewLeftCol, FVisibleCols - 1);
    SB_THUMBPOSITION, SB_THUMBTRACK: NewLeftCol := Message.Pos;
  end;  if NewLeftCol < 0 then NewLeftCol := 0;
  if NewLeftCol >= 82 then
    NewLeftCol := 81;
  FCaretCol:=FCaretCol+LeftCol-NewLeftCol;
  SetCaretPosition;
  LeftCol:=NewLeftCol;
end;
procedure THexEdit.WMVScroll(var Message: TWMVScroll);
var
  NewTopLine: Integer;
  LinesMoved: Integer;
  R: TRect;
begin
  inherited;
  NewTopLine := FTopLine;
  case Message.ScrollCode of
    SB_LINEDOWN: Inc(NewTopLine);
    SB_LINEUP: Dec(NewTopLine);
    SB_PAGEDOWN: Inc(NewTopLine, FVisibleLines - 1);
    SB_PAGEUP: Dec(NewTopLine, FVisibleLines - 1);
    SB_THUMBPOSITION, SB_THUMBTRACK: NewTopLine := Message.Pos;
  end;  if NewTopLine < 0 then NewTopLine := 0;
  if NewTopLine >= FLineCount then
    NewTopLine := FLineCount - 1;  if NewTopLine <> FTopLine then
  begin
    //FCaretRow:=FCaretRow+FTopLine-NewTopLine;    LinesMoved := FTopLine - NewTopLine;
    FTopLine := NewTopLine;
    SetScrollPos(Handle, SB_VERT, FTopLine, True);
    SetCaretPosition;
    if Abs(LinesMoved) = 1 then
    begin
      if LinesMoved=1 then
      begin
        R := Bounds(0, 0, ClientWidth, ClientHeight - FItemHeight);
        ScrollWindow(Handle, 0, FItemHeight * LinesMoved, @R, nil);
        PaintLine(FTopLine+FVisibleLines+1);
      end
      else
      begin
        R := Bounds(0, FItemHeight, ClientWidth, ClientHeight);
        ScrollWindow(Handle, 0, FItemHeight * LinesMoved, @R, nil);
        PaintLine(FTopLine-1);
      end;
    end
    else Invalidate;
  end;
end;{ Painting Related }procedure THexEdit.CalcPaintParams;
const
  Divisor: array[boolean] of Integer = (3,4);
var
  CharsPerLine: Integer;begin
  if FItemHeight < 1 then Exit;
  FVisibleLines := (ClientHeight div FItemHeight);
  FVisibleCols := (ClientWidth div FItemWidth)+1;
  CharsPerLine := ClientWidth div FItemWidth;
  if FShowAddress then Dec(CharsPerLine, 10);
  FLineCount := ((FMStream.Size-15) div FBytesPerLine)+2;
  if FMStream.Size>0 then FColCount := 82;
  AdjustScrollBars;
end;{procedure THexEdit.InvalidateLine(Index: Integer);
var
  R: TRect;
begin
  if (Index >= FTopLine) and (Index <= FTopLine + FVisibleLines - 1) then
  begin
    R := Rect(0, 0, ClientWidth, FItemHeight);
    OffsetRect(R, 0, (Index - FTopLine) * FItemHeight);
    Windows.InvalidateRect(Handle, @R, False);
  end;
end;}procedure THexEdit.AdjustScrollBars;
var
  ScrollInfo: TScrollInfo;
begin
  ScrollInfo.fMask:=SIF_ALL;
  ScrollInfo.nPage:=FVisibleLines;
  ScrollInfo.nMin:=0;
  ScrollInfo.nMax:=FLineCount;//-FVisibleLines;
  ScrollInfo.nPos:=0;
  SetScrollInfo(Handle,SB_VERT,ScrollInfo,True);
  ScrollInfo.fMask:=SIF_ALL;
  ScrollInfo.nPage:=FVisibleCols;
  ScrollInfo.nMin:=0;
  ScrollInfo.nMax:=FColCount;//-FVisibleCols;// - (ClientWidth div FItemWidth);
  ScrollInfo.nPos:=0;
  SetScrollInfo(Handle,SB_HORZ,ScrollInfo,True);
  LeftCol:=0;
end;function THexEdit.ScrollIntoView: Boolean;
begin
  Result := False;
  if FCurrentLine < FTopLine then
  begin
    Result := True;
    SetTopLine(FCurrentLine);
  end
  else if FCurrentLine >= (FTopLine + FVisibleLines) - 1 then
  begin
    SetTopLine(FCurrentLine - (FVisibleLines - 2));
    Result := True;
  end;
end;procedure THexEdit.SetTopLine(Value: Integer);
var
  LinesMoved: Integer;
  R: TRect;
begin
  if Value <> FTopLine then
  begin
    if Value < 0 then Value := 0;
    if Value >= FLineCount then Value := FLineCount - 1;    LinesMoved := FTopLine - Value;
    FTopLine := Value;
    SetScrollPos(Handle, SB_VERT, FTopLine, True);
    if Abs(LinesMoved) = 1 then
    begin
      R:=Bounds(0,0,ClientWidth,ClientHeight);
      ScrollWindow(Handle, 0, FItemHeight*LinesMoved,@R,nil);
      PaintLine(Value);
    end
    else Invalidate;
  end;
end;procedure THexEdit.SetCurrentLine(Value: Integer);
var
  R: TRect;
  nLineMove: Integer;
begin
  if Value <> FCurrentLine then
  begin
    if Value < 0 then Value := 0;
    if Value >= FLineCount then Value := FLineCount - 1;
    nLineMove:=FCurrentLine-Value;
    //SetTopLine(FTopLine+nLineMove);
    if (Value>=FTopLine+FVisibleLines) or (Value<FTopLine) then
    if Abs(nLineMove)=1 then
    begin
      SetTopLine(FTopLine-nLineMove);
      //SetScrollPos(Handle,SB_VERT,FTopLine,True);
      {R:=Bounds(0,0,ClientWidth,ClientHeight);
      ScrollWindow(Handle, 0, FItemHeight*nLineMove,@R,nil);
      PaintLine(Value);}
    end
    else
    begin
      SetTopLine(FTopLine-nLineMove);
    end;
    FCurrentLine:=Value;
    SetCaretPosition;
  end;
end;procedure THexEdit.PaintCell;
begin
  HideCaret(Handle);
  TextOut(Canvas.Handle,((FCurrentCol div 3)*3-FLeftCol)*FItemWidth,(FCurrentLine-FTopLine)*FItemHeight,PChar(IntToHex(FUpdateByte,2)),2);
  TextOut(Canvas.Handle,(63-FLeftCol)*FItemWidth,(FCurrentLine-FTopLine)*FItemHeight,LineChars(FCurrentLine),19);
  ShowCaret(Handle);
end;procedure THexEdit.PaintCell(ACol,ARow: Integer);
begin
  HideCaret(Handle);
  TextOut(Canvas.Handle,((ACol div 3)*3-FLeftCol)*FItemWidth,(ARow-FTopLine)*FItemHeight,PChar(IntToHex(FUpdateByte,2)),2);
  TextOut(Canvas.Handle,(63-FLeftCol)*FItemWidth,(ARow-FTopLine)*FItemHeight,LineChars(ARow),19);
  ShowCaret(Handle);
end;procedure THexEdit.PaintLine(Index: Integer);
var
  R: TRect;
  AddressWidth: Integer;
  TabStop: Integer;
  ByteCnt: Integer;
  //OldColor,OldBrushColor: TColor;
begin
  HideCaret(Handle);
  R := Bounds(1, FItemHeight*Index, FItemWidth*82, FItemHeight);
  if FShowAddress then AddressWidth := FItemWidth*12
  else AddressWidth := 0;
  TabStop := FItemWidth*3;
  ByteCnt := FBytesPerLine;
  if (Index + FTopLine < FLineCount) and (Index+FTopLine>=0) then
  begin
    R.Left := R.Left-FItemWidth*FLeftCol;
    if FShowAddress then
    begin
      Canvas.Font.Color := FFileColors[0];
      ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED, @R, LineAddr(Index+FTopLine), 10, nil);
      R.Left := R.Left + AddressWidth;
    end;
    {OldBrushColor:=Canvas.Brush.Color;
    OldColor:=Canvas.Font.Color;
    if ((FBlockBegin.BY<Index) and (FBlockEnd.BY>Index)) or
     ((FBlockBegin.BY>Index) and (FBlockEnd.BY<Index)) then
    begin
      Canvas.Brush.Color:=clBlack;
      Canvas.Font.Color:=clWhite;
    end
    else
    begin
      Canvas.Brush.Color:=clWhite;
      Canvas.Font.Color:=clBlack;
    end;}
    if (Index+FTopLine = FLineCount-1) and ((FMStream.Size mod FBytesPerLine) > 0) then
      ByteCnt := FMStream.Size mod FBytesPerLine;
    TabbedTextOut(Canvas.Handle, R.Left, R.Top, LineData(Index+FTopLine),
      (ByteCnt*3)+3, 1, TabStop, R.Left);
    //Canvas.Font.Color := OldColor;
    //Canvas.Brush.Color:=OldBrushColor;
    if FShowCharacters then
    begin
      R.Left := R.Left + (FItemWidth*(FBytesPerLine*3+3));
      Canvas.Font.Color := FFileColors[2];
      ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED, @R, LineChars(Index+FTopLine), ByteCnt+3, nil);
    end;
  end
  else ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED,
    @R, nil, 0, nil);
  ShowCaret(Handle);
end;procedure THexEdit.Paint;
{var
  R: TRect;
  I: Integer;
  AddressWidth: Integer;
  TabStop: Integer;
  ByteCnt: Integer;}
var
  I: Integer;
begin
  inherited Paint;
  Canvas.Brush.Color := Self.Color;
  if FMStream.Size>0 then
    for I := -1 to FVisibleLines+1 do
    begin
      PaintLine(I);
    end;
  {Canvas.Brush.Color := Self.Color;
  if FShowAddress then AddressWidth := FItemWidth*12
  else AddressWidth := 0;
  //R := Bounds(1, 0, ClientWidth, FItemHeight);
  R := Bounds(1, 0, FItemWidth*82, FItemHeight);
  TabStop := FItemWidth*3;
  Canvas.Font.Color := FFileColors[1];
  ByteCnt := FBytesPerLine;
  for I := 0 to FVisibleLines - 1 do
  begin
    R.Left := 1;
    if I + FTopLine < FLineCount then
    begin
      R.Left := R.Left-FItemWidth*FLeftCol;
      if FShowAddress then
      begin
        Canvas.Font.Color := FFileColors[0];
        //R.Right := R.Left + AddressWidth;
        ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED, @R, LineAddr(I+FTopLine), 10, nil);
        R.Left := R.Left + AddressWidth;
        //R.Right := ClientWidth;
        Canvas.Font.Color := FFileColors[1];
      end;
      if (I+FTopLine = FLineCount-1) and ((DataSize mod FBytesPerLine) > 0) then
       ByteCnt := DataSize mod FBytesPerLine;
      TabbedTextOut(Canvas.Handle, R.Left, R.Top, LineData(I+FTopLine),
       (ByteCnt*3)+3, 1, TabStop, R.Left);
      if FShowCharacters then
      begin
        R.Left := R.Left + (FItemWidth*(FBytesPerLine*3+3));
        Canvas.Font.Color := FFileColors[2];
        ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED, @R, LineChars(I+FTopLine), ByteCnt+3, nil);
        //Beep;
      end;
    end
    else ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED,
      @R, nil, 0, nil);
    OffsetRect(R, 0, FItemHeight);
  end;}
end;{ Event Overrides }function GetDigit(Key: Word): Integer;
begin
  Result:=Key-48;
  if Result>9 then
  begin
    Result:=Key-55;
    if Result>16 then
      Result:=Key-96;
  end;
end;procedure THexEdit.KeyDown(var Key: Word; Shift: TShiftState);
var
  nB: Byte;
  nCol: Integer;
begin
  inherited KeyDown(Key, Shift);
//procedure THexEdit.WMKeyDown(var Message: TWMKeyDown);
//var
  //nB: Byte;
//begin
  if not FActive then Exit;
  if FReadOnly then Exit;
  case Key of //Message.CharCode
    VK_DOWN:
    begin
      //CaretRow := CaretRow + 1;
      CurrentLine := CurrentLine + 1;
      SetCaretPosition;
    end;
    VK_UP:
    begin
      //CaretRow := CaretRow - 1;
      CurrentLine := CurrentLine - 1;
      SetCaretPosition;
    end;
    VK_NEXT: CurrentLine := CurrentLine + FVisibleLines;
    VK_PRIOR: CurrentLine := CurrentLine - FVisibleLines;
    VK_HOME:
    begin
      FCurrentCol := 12;
      SetCaretPosition;
    end;
    VK_END:
    begin
      FCurrentCol := 62;
      SetCaretPosition;
    end;
    VK_LEFT:
    begin
      if FCurrentCol=39 then FCurrentCol:=36;
      if (CurrentCol mod 3)=0 then CurrentCol:=CurrentCol-2
      else CurrentCol:=CurrentCol-1;
      SetCaretPosition;
    end;
    VK_RIGHT:
    begin
      CurrentCol:=CurrentCol+1;
      SetCaretPosition;
    end
    else
    begin
      if Key In AlphaDigit then
      begin
        if FTopLine>FCurrentLine then SetTopLine(FCurrentLine)
        else if FTopLine<=FCurrentLine-FVisibleLines then SetTopLine(FCurrentLine-FVisibleLines+2);
        SetCaretPosition;
        nCol:=(FCurrentCol div 3)-4;
        if FCurrentCol>=39 then nCol:=nCol-1;
        FMStream.Position:=FCurrentLine*FBytesPerLine+nCol;//FTopLine+FCaretRow
        FMStream.Read(nB,1);
        if (FCurrentCol mod 3)=0 then
        begin
          nB:=nB and $F;
          nB:=nB +(GetDigit(Key) shl 4);
        end
        else
        begin
          nB:=nB and $F0;
          nB:=nB +GetDigit(Key);
        end;
        FMStream.Position:=FMStream.Position-1;
        FMStream.Write(nB,1);
        FUpdateByte:=nB;
        PaintCell;
        CurrentCol:=CurrentCol+1;
        //CaretCol:=CaretCol+1;
        //if FVisibleCols+FLeftCol<=FCaretCol then
          //LeftCol:=FCaretCol-FVisibleCols+1;
        FModified:=False;
      end
      else
      begin
        inherited;
      end;
    end;
  end;
  if Assigned(FOnKeyDown) then FOnKeyDown(Self);
end;function THexEdit.GetRgn(var StartCol,StartLine,EndCol,EndLine: Integer): HRgn;
var
  rgn: HRgn;
  YOffset1,yOffset,y1,y2: Integer;
  Points: array[0..7] of TPoint;
  nIndex,nTemp: Integer;
  s: string;
begin
  YOffset1:=EndLine-StartLine;
  if Yoffset1<0 then
  begin
    nTemp:=EndLine;
    EndLine:=StartLine;
    StartLine:=nTemp;
    YOffset1:=-YOffset1;
  end;
  if (YOffset1>2) then
  begin
    if YOffset1>0 then
    begin
      yOffset:=1;
      y1:=62;
      y2:=12;
    end;
    //else
    //begin
      //y1:=12;
      //y2:=62;
      //yOffset:=-1;
    //end;
    nIndex:=0;
    Points[nIndex].X:=StartCol*FItemWidth;
    Points[nIndex].Y:=StartLine*FItemHeight;
    s:=s+IntToStr(Points[nIndex].X)+','+IntToStr(Points[nIndex].Y)+' ';
    Inc(nIndex);    Points[nIndex].X:=y1*FItemWidth;
    Points[nIndex].Y:=StartLine*FItemHeight;
    s:=s+IntToStr(Points[nIndex].X)+','+IntToStr(Points[nIndex].Y)+' ';
    Inc(nIndex);    Points[nIndex].X:=y1*FItemWidth;
    Points[nIndex].Y:=(EndLine-yOffset)*FItemHeight;
    s:=s+IntToStr(Points[nIndex].X)+','+IntToStr(Points[nIndex].Y)+' ';
    Inc(nIndex);    Points[nIndex].X:=EndLine*FItemWidth;
    Points[nIndex].Y:=(EndLine-yOffset)*FItemHeight;
    s:=s+IntToStr(Points[nIndex].X)+','+IntToStr(Points[nIndex].Y)+' ';
    Inc(nIndex);    Points[nIndex].X:=EndLine*FItemWidth;
    Points[nIndex].Y:=EndLine*FItemHeight;
    s:=s+IntToStr(Points[nIndex].X)+','+IntToStr(Points[nIndex].Y)+' ';
    Inc(nIndex);
    Points[nIndex].X:=y2*FItemWidth;
    Points[nIndex].Y:=EndLine*FItemHeight;
    s:=s+IntToStr(Points[nIndex].X)+','+IntToStr(Points[nIndex].Y)+' ';
    Inc(nIndex);    Points[nIndex].X:=y2*FItemWidth;
    Points[nIndex].Y:=(StartLine+yOffset)*FItemHeight;
    s:=s+IntToStr(Points[nIndex].X)+','+IntToStr(Points[nIndex].Y)+' ';
    Inc(nIndex);    Points[nIndex].X:=StartCol*FItemWidth;
    Points[nIndex].Y:=(StartLine+yOffset)*FItemHeight;
    s:=s+'('+IntToStr(Points[nIndex].X)+','+IntToStr(Points[nIndex].Y)+') ';
    Inc(nIndex);
    rgn:=CreatePolygonRgn(Points,nIndex,ALTERNATE);
    StartCol:=EndCol;
    StartLine:=EndLine;//-yOffset;
    //if yOffset>0 then Dec(StartLine);
  end;
  {else
    rgn:=CreateRectRgn(StartCol*FItemWidth,StartLine*FItemHeight,
        EndLine*FItemWidth,EndLine*FItemHeight);}
  Result:=rgn;
end;procedure THexEdit.SetSelction;
var
  rgn: HRgn;
begin
  //rgn:=GetRgn(FSelectStartCol,FSelectStartLine,FSelectEndCol,FSelectEndLine);
  //InvertRgn(Canvas.Handle,FInvertRgn);
  //InvertRgn(Canvas.Handle,rgn);
  //FInvertRgn:=rgn;
end;procedure THexEdit.MouseDown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  inherited MouseDown(Button, Shift, X, Y);
  if not Focused then SetFocus;
  FActive:=True;
  if FColCount>0 then
  begin
    if (Button = mbLeft) and FActive then
    begin
      InvertRgn(Canvas.Handle,FInvertRgn);
      FInvertRgn:=CreateRectRgn(0,0,0,0);
      FCurrentLine:=(Y div FItemHeight)+FTopLine;
      FCurrentCol:=(X div FItemWidth)+FLeftCol;
      if FCurrentCol<12 then FCurrentCol:=12
      else if FCurrentCol>62  then FCurrentCol:=62
      else if (FCurrentCol>34) and (FCurrentCol<39) then FCurrentCol:=39;
      if FCurrentCol mod 3=2 then FCurrentCol:=FCurrentCol-1;      SetCaretPosition;
      FLButtonDown:=True;
      FBlockBegin.BX:=FCurrentCol;
      FBlockBegin.BY:=FCurrentLine;
      FBlockEnd:=FBlockBegin;
      FOffset:=FCurrentLine*16+((FCurrentCol-12) div 3);
      if FCurrentCol>=39 then Dec(FOffset);
      //FSelectStartCol:=;
      //FSelectStartLine:=FCurrentLine;
      //FSelStartCol:=FCurrentCol;
      //FSelStartLine:=FCurrentLine;
    end;
    if Assigned(FOnMouseDown) then FOnMouseDown(Self);
  end
  else
    HideCaret(Handle)
end;procedure THexEdit.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  nCol,nLine: Integer;
begin
  inherited MouseUp(Button, Shift, X, Y);
  nCol:=((X-1) div FItemWidth)+FLeftCol;
  nLine:=((Y-1) div FItemHeight)+FTopLine+1;
  if nCol<12 then nCol:=12
  else if nCol>62  then nCol:=62
  else if (nCol>35) and (nCol<39) then nCol:=39;
  if nCol mod 3=2 then nCol:=nCol-1;
  //if nCol>FBlockBegin.BX then Inc(nCol)
  //else Dec(nCol);
  //if nLine>FBlockBegin.BY then Inc(nLine)
  //else Dec(nCol);  FBlockEnd.BX:= nCol;
  FBlockEnd.BY:= nLine;
  FLButtonDown:=False;
end;procedure THexEdit.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  nCol,nLine: Integer;
begin
  inherited MouseMove(Shift, X, Y);
  {if FLButtonDown then
  begin
    nCol:=((X-1) div FItemWidth)+FLeftCol;
    nLine:=((Y-1) div FItemHeight)+FTopLine;
    if nCol<12 then nCol:=12
    else if nCol>62  then nCol:=62
    else if (nCol>35) and (nCol<39) then nCol:=39;
    if nCol mod 3=2 then nCol:=nCol-1;
    //if nCol>FBlockBegin.BX then Inc(nCol)
    //else Dec(nCol);
    //if nLine>FBlockBegin.BY then Inc(nLine)
    //else Dec(nLine);
    FBlockEnd.BX:= nCol;
    FBlockEnd.BY:= nLine;
    PaintLine(nLine-1);
  end;}
end;procedure THexEdit.WMSetFocus(var Msg: TWMSetFocus);
begin
  inherited;
  CreateCaret(Handle,HBitmap(nil),8,FItemHeight);
  SetCaretPosition;
  ShowCaret (Handle);
  //Invalidate;
end;procedure THexEdit.WMKillFocus(var Msg: TWMKillFocus);
begin
  inherited;
  InvertRgn(Canvas.Handle,FInvertRgn);
  FInvertRgn:=CreateRectRgn(0,0,0,0);
  HideCaret(Handle);
  DestroyCaret();
  //Invalidate;
end;
{ Property Set/Get Routines }procedure THexEdit.SetBorder(Value: TBorderStyle);
begin
  if Value <> FBorder then
  begin
    FBorder := Value;
    RecreateWnd;
  end;
end;procedure THexEdit.SetShowAddress(Value: Boolean);
begin
  if FShowAddress <> Value then
  begin
    FShowAddress := Value;
    Invalidate;
  end;
end;procedure THexEdit.SetShowCharacters(Value: Boolean);
begin
  if Value <> FShowCharacters then
  begin
    FShowCharacters := Value;
    Invalidate;
  end;
end;procedure THexEdit.SetFileColor(Index: Integer; Value: TColor);
begin
  if FFileColors[Index] <> Value then
  begin
    FFileColors[Index] := Value;
    Invalidate;
  end;
end;function THexEdit.GetFileColor(Index: Integer): TColor;
begin
  Result := FFileColors[Index];
end;procedure THexEdit.SetAddress(Value: Pointer);
begin
  FActive := Value <> nil;
  //FAddress := Value;
  Invalidate;
end;function THexEdit.GetDataSize: Integer;
begin
  Result:=FMStream.Size;
end;procedure THexEdit.SetDataSize(Value: Integer);
begin
  //FDataSize := Value;
  CalcPaintParams;
  Invalidate;
  //AdjustScrollBars;
end;function THexEdit.LineAddr(Index: Integer): PChar;
begin
  Result :=PChar('0x'+IntToHex(Index*FBytesPerLine,8)+'  ');
end;function THexEdit.LineData(Index: Integer): PChar;
var
  sHex: string;
  nB: Byte;
  i: Integer;
begin
  FMStream.Position:=Index*FBytesPerLine;
  for i:=0 to FBytesPerLine-1 do
  begin
    FMStream.Read(nB,1);
    AppendStr(sHex,IntToHex(nB,2));
    AppendStr(sHex,' ');
    if i=7 then AppendStr(sHex,'   ');
  end;
  Result := PChar(sHex);
end;function THexEdit.LineChars(Index: Integer): PChar;
var
  sChar: string;
  i: Integer;
  nB: Byte;
begin
  sChar:='   ';
  FMStream.Position:=Index*FBytesPerLine;
  for i:=0 to FBytesPerLine-1 do
  begin
    FMStream.Read(nB,1);
    if (nB>=$20) and (nB<$FF) then AppendStr(sChar,chr(nB))
    else AppendStr(sChar,'.');
  end;
  Result := PChar(sChar);
end;procedure THexEdit.LoadFromFile(const FileName: TFileName);
begin
  FMStream.LoadFromFile(FileName);
  UpdateView;   
  FModified:=False;
end;procedure THexEdit.LoadFromStream(Stream: TStream);
begin
  FMStream.LoadFromStream(Stream);
  UpdateView;      
  FModified:=False;
end;procedure THexEdit.UpdateView;
begin
  FTopLine:=0;
  CalcPaintParams;
  Invalidate;
end;procedure THexEdit.SetCaretPosition;
var
  nCol: Integer;
begin
  HideCaret(Handle);
  {if FCaretCol<12 then FCaretCol:=12
  else if FCaretCol>61 then FCaretCol:=61;
  if (FCaretCol mod 3)=2 then Inc(FCaretCol);
  if (FCaretCol>35) and (FCaretCol<39) then FCaretCol:=39;
  if FCaretRow>=FVisibleLines then
  begin
    FCaretRow:=FVisibleLines-1;
    CurrentLine:=CurrentLine+1;
  end
  else if FCaretRow<0 then
  begin
    FCaretRow:=0;
    CurrentLine:=CurrentLine-1;
  end;}
  //SetCaretPos(FCaretCol*FItemWidth,FCaretRow*FItemHeight);
  nCol:=(FCurrentCol div 3)-4;
  if FCurrentCol>=39 then nCol:=nCol-1;
  FOffset:=FCurrentLine*FBytesPerLine+nCol;
  FMStream.Position:=FOffset;
  FMStream.Read(FCurrentWordValue,2);
  FMStream.Position:=FOffset;
  FMStream.Read(FCurrentCardinalValue,4);
  FMStream.Position:=FOffset;
  FMStream.Read(FCurrentByteValue,1);
  
  if FCurrentLine>((FMStream.Size-15) div 16)+1 then
  begin
    FCurrentLine:=((FMStream.Size-15) div 16)+1;
    if FCurrentCol>(FMStream.Size mod 16)*3+12 then FCurrentCol:=(FMStream.Size mod 16)*3+12;
    if (FCurrentCol>34) and (FCurrentCol<39) then FCurrentCol:=34;
  end
  else if FCurrentLine=((FMStream.Size-15) div 16)+1 then
  begin
    if FCurrentCol>(FMStream.Size mod 16)*3+12 then FCurrentCol:=(FMStream.Size mod 16)*3+12;
    if (FCurrentCol>34) and (FCurrentCol<39) then FCurrentCol:=34;
  end;
  SetCaretPos((FCurrentCol-FLeftCol)*FItemWidth,(FCurrentLine-FTopLine)*FItemHeight);
  ShowCaret(Handle);
end;procedure THexEdit.SetCurrentCol(Value: Integer);
begin
  if Value<>FCurrentCol then
  begin
    FCurrentCol:=Value;
    if FCurrentCol>=62 then
    begin
      FCurrentCol:=12;
      CurrentLine:=CurrentLine+1;
    end
    else if (FCurrentCol>34) and (FCurrentCol<39) then
      FCurrentCol:=39
    else if FCurrentCol<12 then
    begin
      FCurrentCol:=61;
      CurrentLine:=CurrentLine-1;
    end;
    if (FCurrentCol mod 3)=2 then
      Inc(FCurrentCol);
    if FCurrentCol-FLeftCol+1>=FVisibleCols then
    begin
      LeftCol:=FCurrentCol-FVisibleCols+4;
    end
    else if FCurrentCol<FLeftCol then
      LeftCol:=FCurrentCol;
    {FCaretCol:=FCurrentCol-FLeftCol;
    if FCaretRow<0 then
    begin
      SetTopLine(FCurrentLine);
      FCaretRow:=0;
    end
    else if FCaretRow>FTopLine+FVisibleLines then
    begin
      SetTopLine(FCurrentLine-FVisibleLines);
      FCaretRow:=FVisibleLines-1;
    end;}
  end;
end;procedure THexEdit.SetCaretCol(Value: Integer);
begin
  if Value<>FCaretCol then
  begin
    FCurrentCol:=FLeftCol+Value;
    if FCurrentCol>=62 then
    begin
      FCurrentCol:=12;
      CaretRow:=CaretRow+1;
    end
    else if (FCurrentCol>34) and (FCurrentCol<39) then
      FCurrentCol:=39
    else if FCurrentCol<12 then
    begin
      FCurrentCol:=61;
      CaretRow:=CaretRow-1;
    end;
    if (FCurrentCol mod 3)=2 then
      Inc(FCurrentCol);
    if FCurrentCol-FLeftCol+1>=FVisibleCols then
    begin
      LeftCol:=FCurrentCol-FVisibleCols+4;
    end
    else if FCurrentCol<FLeftCol then
      LeftCol:=FCurrentCol;
    FCaretCol:=FCurrentCol-FLeftCol;
    if FCaretRow<0 then
    begin
      SetTopLine(FCurrentLine);
      FCaretRow:=0;
    end
    else if FCaretRow>FTopLine+FVisibleLines then
    begin
      SetTopLine(FCurrentLine-FVisibleLines);
      FCaretRow:=FVisibleLines-1;
    end;
  end;
end;procedure THexEdit.SetCaretRow(Value: Integer);
begin
  if Value<>FCaretRow then
  begin
    FCaretRow:=Value;
    CurrentLine:=FCaretRow+FTopLine;
  end;
end;
procedure THexEdit.SaveToFile(const FileName: TFileName);
begin
  FMStream.SaveToFile(FileName);
end;procedure THexEdit.SaveToStream(Stream: TStream);
begin
  FMStream.SaveToStream(Stream);
end;procedure THexEdit.SetOffset(const Value: Integer);
begin
  FOffset := Value;
  CurrentLine:=FOffset div 16;
  CaretCol:=FOffset mod 16;
end;procedure THexEdit.SetCurrentByteValue(Value: Byte);
begin
  FCurrentByteValue:=Value;
  FMStream.Read(Value,1);
end;procedure THexEdit.SetCurrentCardinalValue(Value: Cardinal);
begin
  FCurrentCardinalValue := Value;
  FMStream.Read(Value,4);
end;procedure THexEdit.SetCurrentWordValue(Value: Word);
begin
  FCurrentWordValue := Value;
  FMStream.Read(Value,2);
end;end.