sysperfana/heapanalyser/Libraries/UI/HeapCtrlLib/Renderers/HeapDataRenderer.cs
changeset 8 15296fd0af4a
equal deleted inserted replaced
7:8e12a575a9b5 8:15296fd0af4a
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 *
       
     5 * Redistribution and use in source and binary forms, with or without
       
     6 * modification, are permitted provided that the following conditions are met:
       
     7 *
       
     8 * - Redistributions of source code must retain the above copyright notice,
       
     9 *   this list of conditions and the following disclaimer.
       
    10 * - Redistributions in binary form must reproduce the above copyright notice,
       
    11 *   this list of conditions and the following disclaimer in the documentation
       
    12 *   and/or other materials provided with the distribution.
       
    13 * - Neither the name of Nokia Corporation nor the names of its contributors
       
    14 *   may be used to endorse or promote products derived from this software
       
    15 *   without specific prior written permission.
       
    16 *
       
    17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
       
    18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
       
    20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
       
    21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
       
    22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
       
    23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
       
    24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
       
    25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
       
    26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
       
    27 * POSSIBILITY OF SUCH DAMAGE.
       
    28 * 
       
    29 * Initial Contributors:
       
    30 * Nokia Corporation - initial contribution.
       
    31 *
       
    32 * Contributors:
       
    33 *
       
    34 * Description: 
       
    35 *
       
    36 */
       
    37 
       
    38 using System;
       
    39 using System.Collections;
       
    40 using System.ComponentModel;
       
    41 using System.Drawing;
       
    42 using System.Data;
       
    43 using System.Windows.Forms;
       
    44 using HeapLib;
       
    45 using HeapLib.Cells;
       
    46 using HeapLib.Array;
       
    47 using HeapLib.Relationships;
       
    48 using HeapLib.Reconstructor;
       
    49 using HeapCtrlLib.Utilities;
       
    50 using HeapCtrlLib.Interfaces;
       
    51 using HeapCtrlLib.Factories;
       
    52 using HeapCtrlLib.Types;
       
    53 using SymbianUtils.Range;
       
    54 using SymbianUtils.RawItems;
       
    55 
       
    56 namespace HeapCtrlLib.Renderers
       
    57 {
       
    58     internal class HeapDataRenderer : UserControl
       
    59     {
       
    60         #region Delegates & events
       
    61         public delegate void AddressChangeHandler( uint aAddressOld, uint aAddressNew, HeapCell aFirstCell, int aFirstCellIndex );
       
    62         public event AddressChangeHandler AddressChanged;
       
    63         public delegate void CellSelectionHandler( HeapCell aCell );
       
    64         public event CellSelectionHandler CellSelected;
       
    65         public delegate void CellDoubleClickHandler( HeapCell aCell );
       
    66         public event CellDoubleClickHandler CellDoubleClicked;
       
    67         public delegate void CellRightClickedHandler( HeapCell aCell, RawItem aItem, Point aViewerPos );
       
    68         public event CellRightClickedHandler CellRightClicked;
       
    69         #endregion
       
    70 
       
    71         #region Constructors & destructor
       
    72         internal HeapDataRenderer()
       
    73         {
       
    74             InitializeComponent();
       
    75             //
       
    76             LoadTypeSet( THeapCtrlRenderingType.EHeapCtrlRenderingTypeByCell );
       
    77             //
       
    78             this.SetStyle( ControlStyles.UserPaint, true );
       
    79             this.SetStyle( ControlStyles.DoubleBuffer, true );
       
    80             this.SetStyle( ControlStyles.AllPaintingInWmPaint, true );
       
    81             this.SetStyle( ControlStyles.ResizeRedraw, true );
       
    82             this.SetStyle( ControlStyles.Selectable, true );
       
    83             //
       
    84             this.MouseWheel += new MouseEventHandler( HeapDataRenderer_MouseWheel );
       
    85         }
       
    86 
       
    87         protected override void Dispose( bool disposing )
       
    88         {
       
    89             if  ( disposing )
       
    90             {
       
    91             }
       
    92             base.Dispose( disposing );
       
    93         }
       
    94         #endregion
       
    95 
       
    96         #region Component Designer generated code
       
    97         private void InitializeComponent()
       
    98         {
       
    99             this.iLbl_NoContent = new System.Windows.Forms.Label();
       
   100             this.SuspendLayout();
       
   101             // 
       
   102             // iLbl_NoContent
       
   103             // 
       
   104             this.iLbl_NoContent.Dock = System.Windows.Forms.DockStyle.Fill;
       
   105             this.iLbl_NoContent.Location = new System.Drawing.Point( 0, 0 );
       
   106             this.iLbl_NoContent.Name = "iLbl_NoContent";
       
   107             this.iLbl_NoContent.Size = new System.Drawing.Size( 600, 408 );
       
   108             this.iLbl_NoContent.TabIndex = 0;
       
   109             this.iLbl_NoContent.Text = "No Content";
       
   110             this.iLbl_NoContent.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
       
   111             // 
       
   112             // HeapDataRenderer
       
   113             // 
       
   114             this.Controls.Add( this.iLbl_NoContent );
       
   115             this.DoubleBuffered = true;
       
   116             this.Name = "HeapDataRenderer";
       
   117             this.Size = new System.Drawing.Size( 600, 408 );
       
   118             this.MouseDown += new System.Windows.Forms.MouseEventHandler( this.HeapDataRenderer_MouseDown );
       
   119             this.MouseMove += new System.Windows.Forms.MouseEventHandler( this.HeapDataRenderer_MouseMove );
       
   120             this.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler( this.HeapDataRenderer_MouseDoubleClick );
       
   121             this.MouseLeave += new System.EventHandler( this.HeapDataRenderer_MouseLeave );
       
   122             this.MouseUp += new System.Windows.Forms.MouseEventHandler( this.HeapDataRenderer_MouseUp );
       
   123             this.KeyDown += new System.Windows.Forms.KeyEventHandler( this.HeapDataRenderer_KeyDown );
       
   124             this.ResumeLayout( false );
       
   125 
       
   126         }
       
   127         #endregion
       
   128 
       
   129         #region API
       
   130         public void SetupFilters()
       
   131         {
       
   132             if ( !SupportsFiltering )
       
   133             {
       
   134                 throw new NotSupportedException();
       
   135             }
       
   136 
       
   137             iFactory.Renderers.Content.SetupFilters();
       
   138         }
       
   139 
       
   140         public void LoadTypeSet( THeapCtrlRenderingType aType )
       
   141         {
       
   142             iFactory = HeapCtrlLib.Factories.Factory.CreateByType( aType );
       
   143 
       
   144             // Set sizes
       
   145             CellBoxSize = iFactory.CellBoxSize( Zoom );
       
   146             CellPadding = iFactory.CellPadding( Zoom );
       
   147 
       
   148             // Do init.
       
   149             InitialiseRenderers();
       
   150         }
       
   151 
       
   152         public int RowForAddress( uint aAddress )
       
   153         {
       
   154             uint addressOffset = aAddress - Reconstructor.Statistics.HeapAddressStart;
       
   155             uint bytesPerRow = BytesPerRow;
       
   156             int row = (int) ( addressOffset / bytesPerRow );
       
   157             //System.Diagnostics.Debug.WriteLine( "base: 0x" + Reconstructor.Statistics.HeapAddressStart.ToString("x8") + ", offset: 0x" + addressOffset.ToString("x8") + ", addr: 0x" + aAddress.ToString("x8") + ", row: " + row + ", remainder: " + ( addressOffset % bytesPerRow ) + ", bytesPerRow: " + bytesPerRow );
       
   158             //
       
   159             return row;
       
   160         }
       
   161         #endregion
       
   162 
       
   163         #region Properties
       
   164         public HeapReconstructor Reconstructor
       
   165         {
       
   166             get
       
   167             {
       
   168                 return iReconstructor;
       
   169             }
       
   170             set
       
   171             {
       
   172                 iReconstructor = value;
       
   173                 if  ( iReconstructor != null )
       
   174                 {
       
   175                     iCells = iReconstructor.Data;
       
   176                     InitialiseRenderers();
       
   177                     if  ( iCells.Count > 0 )
       
   178                     {
       
   179                         HeapCell cell = Cells[ 0 ];
       
   180 
       
   181                         // Must first set the address, or else this messes up
       
   182                         // VisibleAddressRange...
       
   183                         Address = cell.Address;
       
   184 
       
   185                         // ... which is needed by FocusedCell when changing
       
   186                         // the focus.
       
   187                         FocusedCell = cell;
       
   188                     }
       
   189                 }
       
   190             }
       
   191         }
       
   192 
       
   193         public HeapCellArray Cells
       
   194         {
       
   195             get
       
   196             {
       
   197                 return iCells;
       
   198             }
       
   199         }
       
   200 
       
   201         public HeapCell FocusedCell
       
   202         {
       
   203             get
       
   204             {
       
   205                 return iFocusedCellKeyboard;
       
   206             }
       
   207             set
       
   208             {
       
   209                 iFocusedCellKeyboard = value;
       
   210                 if  ( iFocusedCellKeyboard != null )
       
   211                 {
       
   212                     uint visRangeMin = (uint) VisibleAddressRange.Min;
       
   213                     uint visRangeMax = (uint) VisibleAddressRange.Max - BytesPerRow;
       
   214 
       
   215                     // Do we need to move the view?
       
   216                     int currentMinRow = RowForAddress( visRangeMin );
       
   217                     int row = RowForAddress( value.Address );
       
   218                     int currentMaxRow = RowForAddress ( visRangeMax );
       
   219 
       
   220                     //
       
   221                     //System.Diagnostics.Debug.WriteLine( "row: " + row + ", minR: " + currentMinRow + "(" + visRangeMin.ToString("x8") + "), maxR: " + currentMaxRow + "(" + visRangeMax.ToString("x8") + ")" );
       
   222                     //System.Diagnostics.Debug.WriteLine( " " );
       
   223 
       
   224                     if  ( row < currentMinRow || row > currentMaxRow )
       
   225                     {
       
   226                         Address = (uint) ( Reconstructor.Statistics.HeapAddressStart + ( row * BytesPerRow ) );
       
   227                     }
       
   228                     else
       
   229                     {
       
   230                         Invalidate();
       
   231                     }
       
   232                 }
       
   233 
       
   234                 if  ( CellSelected != null )
       
   235                 {
       
   236                     CellSelected( iFocusedCellKeyboard );
       
   237                 }
       
   238             }
       
   239         }
       
   240 
       
   241         public uint Address
       
   242         {
       
   243             get { return iCellAddress; }
       
   244             set
       
   245             {
       
   246                 this.Enabled = ( value > 0 );
       
   247                 iLbl_NoContent.Visible = ( value == 0 );
       
   248 
       
   249                 // Validate
       
   250                 int index = -1;
       
   251                 HeapCell cell = Cells.CellByAddress( value, out index );
       
   252                 if  ( cell != null )
       
   253                 {
       
   254                     iFactory.PopupManager.PopupHide();
       
   255                     //
       
   256                     iCellIndex = index;
       
   257                     uint oldAddress = iCellAddress;
       
   258                     iCellAddress = value;
       
   259                     iFocusedCellMouse = null;
       
   260                     //
       
   261                     if  ( AddressChanged != null )
       
   262                     {
       
   263                         AddressChanged( oldAddress, iCellAddress, cell, iCellIndex );
       
   264                     }
       
   265                     //
       
   266                     Invalidate();
       
   267                 }
       
   268                 else if ( value == 0 )
       
   269                 {
       
   270                     // Do nothing, we're disabled
       
   271                 }
       
   272                 else
       
   273                 {
       
   274                     // Bad address
       
   275                     throw new ArgumentException( "Invalid cell address", "value" );
       
   276                 }
       
   277             }
       
   278         }
       
   279 
       
   280         public uint BytesPerRow
       
   281         {
       
   282             get
       
   283             {
       
   284                 uint bytesPerRow = (uint) RowsAndColumns.Width * 4;
       
   285                 return bytesPerRow;
       
   286             }
       
   287         }
       
   288 
       
   289         public uint BytesPerScreen
       
   290         {
       
   291             get
       
   292             {
       
   293                 uint bytesPerScreen = BytesPerRow * (uint) RowsAndColumns.Height;
       
   294                 return bytesPerScreen;
       
   295             }
       
   296         }
       
   297 
       
   298         public THeapCtrlZoom Zoom
       
   299         {
       
   300             get { return iZoom; }
       
   301             set
       
   302             {
       
   303                 if ( value != iZoom )
       
   304                 {
       
   305                     // Get base size from factory
       
   306                     CellBoxSize = iFactory.CellBoxSize( value );
       
   307                     CellPadding = iFactory.CellPadding( value );
       
   308                 }
       
   309                 //
       
   310                 iZoom = value;
       
   311             }
       
   312         }
       
   313 
       
   314         public AddressRange VisibleAddressRange
       
   315         {
       
   316             get
       
   317             {
       
   318                 AddressRange range = new AddressRange();
       
   319                 //
       
   320                 range.UpdateMin( Address );
       
   321                 range.UpdateMax( Address + BytesPerScreen );
       
   322                 //
       
   323                 return range;
       
   324             }
       
   325         }
       
   326 
       
   327         public bool SupportsFiltering
       
   328         {
       
   329             get { return iFactory.Renderers.Content.SupportsFiltering; }
       
   330         }
       
   331 
       
   332         public HeapCellArrayBase BreadcrumbCellsOutgoing
       
   333         {
       
   334             get { return iBreadcrumbCellsOutgoing; }
       
   335             set { iBreadcrumbCellsOutgoing = new HeapCellArrayUnsorted( value ); }
       
   336         }
       
   337 
       
   338         public HeapCellArrayBase BreadcrumbCellsIncoming
       
   339         {
       
   340             get { return iBreadcrumbCellsIncoming; }
       
   341             set { iBreadcrumbCellsIncoming = new HeapCellArrayUnsorted( value ); }
       
   342         }
       
   343 
       
   344         internal Factory Factory
       
   345         {
       
   346             get { return iFactory; }
       
   347         }
       
   348         #endregion
       
   349 
       
   350         #region Co-ordinate mapping
       
   351         public Point AddressToPixelCoordinate( uint aAddress )
       
   352         {
       
   353             Point ret = new Point( 0, 0 );
       
   354             //
       
   355             Size overallPaddingSize = RowsAndColumnsRemainingPixels;
       
   356             Size rowAndColumnDimensions = RowsAndColumns;
       
   357 
       
   358             // First, work out how many boxes would be required to draw
       
   359             // the specific cell address
       
   360             long delta = ((long) aAddress - (long) iCellAddress);
       
   361 
       
   362             // This can be a negative number
       
   363             int boxesForDelta = (int) ( delta / KDWordSize );
       
   364 
       
   365             // Then work out how many rows and columns would be needed to reach
       
   366             // that value.
       
   367             Point numberOfRowsAndColumns = new Point( 0, 0 );
       
   368 
       
   369             if ( delta > 0 )
       
   370             {
       
   371                 // Going forwards from current top left of view port.
       
   372                 numberOfRowsAndColumns.Y = ( boxesForDelta / rowAndColumnDimensions.Width );
       
   373                 numberOfRowsAndColumns.X = ( boxesForDelta - ( numberOfRowsAndColumns.Y * rowAndColumnDimensions.Width ) );
       
   374             }
       
   375             else
       
   376             {
       
   377                 numberOfRowsAndColumns.Y = ( boxesForDelta / rowAndColumnDimensions.Width ) - 1;
       
   378                 numberOfRowsAndColumns.X = Math.Abs( ( numberOfRowsAndColumns.Y * rowAndColumnDimensions.Width ) - boxesForDelta );
       
   379             }
       
   380 
       
   381             // Work our pixel pos
       
   382             ret.X = numberOfRowsAndColumns.X * CellBoxSizeIncludingPadding.Width;
       
   383             ret.Y = numberOfRowsAndColumns.Y * CellBoxSizeIncludingPadding.Height;
       
   384 
       
   385             // And take into account padding and header size
       
   386             ret.X += CellBoxRect.X;
       
   387             ret.Y += CellBoxRect.Y;
       
   388 
       
   389             //
       
   390             return ret;
       
   391         }
       
   392 
       
   393         public Point CoordinateToBox( Point aPixelPos )
       
   394         {
       
   395             Point ret = new Point( -1, -1 );
       
   396             //
       
   397             Size rowsAndColumns = RowsAndColumns;
       
   398             if  ( CellBoxRect.Contains( aPixelPos ) )
       
   399             {
       
   400                 Size overallPaddingSize = RowsAndColumnsRemainingPixels;
       
   401 
       
   402                 // Work out which row this event occurs within.
       
   403                 int row = ( aPixelPos.Y - ( overallPaddingSize.Height / 2 ) ) / CellBoxSizeIncludingPadding.Height;
       
   404                 if  ( row >= 0 && row < rowsAndColumns.Height )
       
   405                 {
       
   406                     // Work out the column index for that cell.
       
   407                     int xpos = aPixelPos.X - ( overallPaddingSize.Width / 2 ) - CellAddressHeaderSize.Width;
       
   408 
       
   409                     // How many boxes could we have rendered for that xpos
       
   410                     int boxCount = ( xpos / CellBoxSizeIncludingPadding.Width );
       
   411 
       
   412                     ret.X = boxCount;
       
   413                     ret.Y = row;
       
   414                 }
       
   415             }
       
   416             //System.Diagnostics.Debug.WriteLine( "aPixelPos[ " + aPixelPos.X + ", " + aPixelPos.Y + " ], boxPos: [ " + ret.X + ", " + ret.Y + " ]" );
       
   417             //
       
   418             return ret;
       
   419         }
       
   420 
       
   421         public Point BoxCoordinateByAddress( uint aAddress )
       
   422         {
       
   423             Point ret = new Point( -1, -1 );
       
   424 
       
   425             // First, work out how many boxes would be required to draw
       
   426             // the specific cell address
       
   427             uint delta = aAddress - iCellAddress;
       
   428             int boxesForDelta = (int) ( delta / KDWordSize );
       
   429 
       
   430             // Then work out how many rows & columns would need to be
       
   431             // drawn to reach that value.
       
   432             Size rowAndColumnDimensions = RowsAndColumns;
       
   433             ret.Y = boxesForDelta / rowAndColumnDimensions.Width;
       
   434             ret.X = boxesForDelta - ( ret.Y * rowAndColumnDimensions.Width );
       
   435             //
       
   436             return ret;
       
   437         }
       
   438 
       
   439         public uint AddressByBoxCoordinates( Point aBoxCoordinates )
       
   440         {
       
   441             uint ret = iCellAddress;
       
   442             //
       
   443             if  ( Cells.Count > 0 && aBoxCoordinates.X >= 0 && aBoxCoordinates.Y >= 0 )
       
   444             {
       
   445                 Size rowsAndColumns = RowsAndColumns;
       
   446                 //
       
   447                 ret += (uint) ( aBoxCoordinates.Y * KDWordSize * rowsAndColumns.Width );
       
   448                 ret += (uint) ( aBoxCoordinates.X * KDWordSize );
       
   449             }
       
   450             //
       
   451             return ret;
       
   452         }
       
   453 
       
   454         public uint AddressByCoordinate( Point aPixelPos )
       
   455         {
       
   456             Point boxPos = CoordinateToBox( aPixelPos );
       
   457             uint ret = AddressByBoxCoordinates( boxPos );
       
   458             return ret;
       
   459         }
       
   460 
       
   461         public RawItem RawItemByPixelPos( Point aPixelPos )
       
   462         {
       
   463             RawItem ret = null;
       
   464             //
       
   465             Point boxPos = CoordinateToBox( aPixelPos );
       
   466             HeapCell cell = CellByBoxCoordinates( boxPos );
       
   467             //
       
   468             if ( cell != null )
       
   469             {
       
   470                 uint rawItemAddress = AddressByBoxCoordinates( boxPos );
       
   471                 HeapCell.TRegion region = cell.RegionForAddress( rawItemAddress );
       
   472                 
       
   473                 // We only provide raw items for payload sections
       
   474                 if ( region == HeapCell.TRegion.EPayload )
       
   475                 {
       
   476                     ret = cell[ rawItemAddress ];
       
   477                 }
       
   478             }
       
   479             //
       
   480             return ret;
       
   481         }
       
   482 
       
   483         public HeapCell CellByPosition( Point aPixelPos )
       
   484         {
       
   485             HeapCell ret = null;
       
   486             //
       
   487             Point boxPos = CoordinateToBox( aPixelPos );
       
   488             if  ( Cells.Count > 0 && boxPos.X >= 0 && boxPos.Y >= 0 )
       
   489             {
       
   490                 ret = CellByBoxCoordinates( boxPos );
       
   491             }
       
   492             //
       
   493             return ret;
       
   494         }
       
   495 
       
   496         public HeapCell CellByBoxCoordinates( Point aBoxCoordinates )
       
   497         {
       
   498             uint address = AddressByBoxCoordinates( aBoxCoordinates );
       
   499             HeapCell ret = Cells.CellByAddress( address );
       
   500             return ret;
       
   501         }
       
   502 
       
   503         public int CellIndex( HeapCell aCell )
       
   504         {
       
   505             int index = -1;
       
   506             Cells.CellByExactAddress( aCell.Address, out index );
       
   507             return index;
       
   508         }
       
   509         #endregion
       
   510 
       
   511         #region Sizing
       
   512         internal Rectangle CellBoxRect
       
   513         {
       
   514             get
       
   515             {
       
   516                 Size overallPaddingSize = RowsAndColumnsRemainingPixels;
       
   517                 Size bodySize = RowsAndColumnsInPixels;
       
   518                 //
       
   519                 Rectangle ret = new Rectangle();
       
   520                 ret.X = ( overallPaddingSize.Width / 2 ) + CellAddressHeaderSize.Width;
       
   521                 ret.Y = overallPaddingSize.Height / 2;
       
   522                 ret.Width = bodySize.Width;
       
   523                 ret.Height = bodySize.Height;
       
   524                 //
       
   525                 return ret;
       
   526             }
       
   527         }
       
   528 
       
   529         [Browsable(false)]
       
   530         internal Size CellBoxSize
       
   531         {
       
   532             get { return iCellBoxSize; }
       
   533             set
       
   534             {
       
   535                 iCellBoxSize = value;
       
   536                 Invalidate();
       
   537             }
       
   538         }
       
   539 
       
   540         internal Size CellBoxSizeIncludingPadding
       
   541         {
       
   542             get
       
   543             {
       
   544                 Size size = CellBoxSize;
       
   545                 //
       
   546                 size.Width += CellPadding.Width;
       
   547                 size.Height += CellPadding.Height;
       
   548                 //
       
   549                 return size;
       
   550             }
       
   551         }
       
   552 
       
   553         internal Size CellBoxSizeIncludingPaddingHalved
       
   554         {
       
   555             get
       
   556             {
       
   557                 Size size = CellBoxSize;
       
   558                 //
       
   559                 size.Width += CellPadding.Width;
       
   560                 size.Height += CellPadding.Height;
       
   561                 //
       
   562                 return new Size( size.Width / 2, size.Height / 2 );
       
   563             }
       
   564         }
       
   565 
       
   566         [Browsable(false)]
       
   567         internal Size CellPadding
       
   568         {
       
   569             get { return iCellPadding; }
       
   570             set
       
   571             {
       
   572                 iCellPadding = value;
       
   573                 Invalidate();
       
   574             }
       
   575         }
       
   576 
       
   577         internal Size CellPaddingHalved
       
   578         {
       
   579             get { return new Size( iCellPadding.Width / 2, iCellPadding.Height / 2 ); }
       
   580         }
       
   581 
       
   582         internal Size RowsAndColumns
       
   583         {
       
   584             get
       
   585             {
       
   586                 Size s = this.Size;
       
   587                 
       
   588                 // First, strip off the address header text width
       
   589                 s.Width -= iHeaderTextWidth;
       
   590 
       
   591                 // Next, calculate how wide each box will be, including padding
       
   592                 int boxWidthPerCell = CellBoxSizeIncludingPadding.Width;
       
   593                 int cols = Math.Max( 0, ( s.Width - 1 ) / boxWidthPerCell );
       
   594 
       
   595                 // Now, do the same for rows
       
   596                 int boxHeightPerCell = CellBoxSizeIncludingPadding.Height;
       
   597                 int rows = Math.Max( 0, ( s.Height - 1 ) / boxHeightPerCell );
       
   598                 //
       
   599                 return new Size( cols, rows );
       
   600             }
       
   601         }
       
   602 
       
   603         internal Size RowsAndColumnsInPixels
       
   604         {
       
   605             get
       
   606             {
       
   607                 Size rowsAndCols = RowsAndColumns;
       
   608                 Size rowsAndColsInPixels = new Size( rowsAndCols.Width * CellBoxSizeIncludingPadding.Width, rowsAndCols.Height * CellBoxSizeIncludingPadding.Height );
       
   609                 //
       
   610                 return rowsAndColsInPixels;
       
   611             }
       
   612         }
       
   613 
       
   614         internal Size RowsAndColumnsRemainingPixels
       
   615         {
       
   616             get
       
   617             {
       
   618                 Size s = this.Size;
       
   619                 Size rowsAndColsInPixels = RowsAndColumnsInPixels;
       
   620                 //
       
   621                 int colsRemainder = s.Width - rowsAndColsInPixels.Width - CellAddressHeaderSize.Width;
       
   622                 int rowsRemainder = s.Height - rowsAndColsInPixels.Height;
       
   623                 //
       
   624                 return new Size( colsRemainder, rowsRemainder );
       
   625             }
       
   626         }
       
   627 
       
   628         internal Size RowsAndColumnsRemainingPixelsDistributedEvenly
       
   629         {
       
   630             get
       
   631             {
       
   632                 Size overallPaddingSize = RowsAndColumnsRemainingPixels;
       
   633                 overallPaddingSize.Width /= 2;
       
   634                 overallPaddingSize.Height /= 2;
       
   635                 return overallPaddingSize;
       
   636             }
       
   637         }
       
   638 
       
   639         internal Size CellAddressHeaderSize
       
   640         {
       
   641             get
       
   642             {
       
   643                 return new Size( iHeaderTextWidth, CellBoxSize.Height );
       
   644             }
       
   645         }
       
   646         #endregion
       
   647 
       
   648         #region Drawing
       
   649         protected override void OnPaint( PaintEventArgs aArgs )
       
   650         {
       
   651             try
       
   652             {
       
   653                 // First must measure the size of the header text as we need
       
   654                 // this in order to layout the boxes. We cannot measure the text width
       
   655                 // without a graphics object, hence we have to do that here. There must
       
   656                 // be a better way?
       
   657                 iHeaderTextWidth = iFactory.Renderers.Header.MeasureCellHeaderText( aArgs.Graphics );
       
   658 
       
   659                 // Store our graphics object for later use
       
   660                 iGraphics = aArgs.Graphics;
       
   661 
       
   662                 // Make the navigator object that will help us lay out the cells
       
   663                 HeapRenderingNavigator navigator = new HeapRenderingNavigator( Cells );
       
   664 
       
   665                 // Queue events we want to receive
       
   666                 navigator.iNavBegin += new HeapCtrlLib.Utilities.HeapRenderingNavigator.NavBegin( Navigator_NavBegin );
       
   667                 navigator.iNavEnd += new HeapCtrlLib.Utilities.HeapRenderingNavigator.NavEnd( Navigator_NavEnd );
       
   668                 navigator.iNavNewRowHeader += new HeapCtrlLib.Utilities.HeapRenderingNavigator.NavNewRowHeader( Navigator_NavNewRowHeader );
       
   669                 navigator.iNavNewColumn += new HeapCtrlLib.Utilities.HeapRenderingNavigator.NavNewColumn( Navigator_NavNewColumn );
       
   670                 navigator.iNavHeapCellEnd += new HeapCtrlLib.Utilities.HeapRenderingNavigator.NavHeapCellEnd( Navigator_NavHeapCellEnd );
       
   671 
       
   672                 // The padding amount we apply around the entire control area in order to
       
   673                 // center the data.
       
   674                 Size centerAlignmentPadding = RowsAndColumnsRemainingPixelsDistributedEvenly;
       
   675 
       
   676                 // The co-ordinates at which we will render a box (or header).
       
   677                 Point startPos = new Point( centerAlignmentPadding.Width, centerAlignmentPadding.Height );
       
   678 
       
   679                 // Tell the renderers we're about to start
       
   680                 iFactory.Renderers.PrepareToNavigate( navigator );
       
   681 
       
   682                 // Do it
       
   683                 navigator.Navigate( iCellIndex, iCellAddress, iHeaderTextWidth, startPos, RowsAndColumns, CellBoxSize, CellPadding );
       
   684 
       
   685                 // Draw link lines
       
   686                 aArgs.Graphics.Clip = new Region( CellBoxRect );
       
   687 
       
   688                 foreach ( HeapCell cell in BreadcrumbCellsOutgoing )
       
   689                 {
       
   690                     RelationshipManager relManager = cell.RelationshipManager;
       
   691 
       
   692                     // Draw embedded (outgoing) lines
       
   693                     foreach ( RelationshipInfo outgoingRelationship in relManager.EmbeddedReferencesTo )
       
   694                     {
       
   695                         // Get coordinates of top left corner of the box for the specified 
       
   696                         // address. If we have a clean link, we point right at the cell header.
       
   697                         // If not, then we point at the box in question within the target cell.
       
   698                         uint targetAddress = outgoingRelationship.FromCellRawItem.Data;
       
   699                         if ( outgoingRelationship.IsCleanLink )
       
   700                         {
       
   701                             targetAddress = outgoingRelationship.ToCell.Address;
       
   702                         }
       
   703                         Point pixelPosEnd = AddressToPixelCoordinate( targetAddress );
       
   704                         pixelPosEnd += CellBoxSizeIncludingPaddingHalved;
       
   705                         Point pixelPosStart = AddressToPixelCoordinate( outgoingRelationship.FromCellRawItem.Address );
       
   706                         pixelPosStart += CellBoxSizeIncludingPaddingHalved;
       
   707                         //
       
   708                         Color outgoingPenColour = Color.FromArgb( 120, 255, 0, 0 );
       
   709                         using ( Pen pen = new Pen( outgoingPenColour, 4.0f ) )
       
   710                         {
       
   711                             pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
       
   712                             pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
       
   713                             //
       
   714                             aArgs.Graphics.DrawLine( pen, pixelPosStart, pixelPosEnd );
       
   715                         }
       
   716                     }
       
   717                 }
       
   718 
       
   719                 foreach( HeapCell cell in BreadcrumbCellsIncoming )
       
   720                 {
       
   721                     RelationshipManager relManager = cell.RelationshipManager;
       
   722                     
       
   723                     // Draw incoming links
       
   724                     foreach ( HeapCell fromCell in relManager.ReferencedBy )
       
   725                     {
       
   726                         Point pixelPosStart = AddressToPixelCoordinate( fromCell.Address );
       
   727                         pixelPosStart += CellBoxSizeIncludingPaddingHalved;
       
   728                         Point pixelPosEnd = AddressToPixelCoordinate( cell.Address );
       
   729                         pixelPosEnd += CellBoxSizeIncludingPaddingHalved;
       
   730                         //
       
   731                         Color outgoingPenColour = Color.FromArgb( 100, 0, 0, 255 );
       
   732                         using ( Pen pen = new Pen( outgoingPenColour, 4.0f ) )
       
   733                         {
       
   734                             pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
       
   735                             pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
       
   736                             //
       
   737                             aArgs.Graphics.DrawLine( pen, pixelPosStart, pixelPosEnd );
       
   738                         }
       
   739                     }
       
   740                 }
       
   741             }
       
   742             finally
       
   743             {
       
   744                 iGraphics = null;
       
   745                 base.OnPaint( aArgs );
       
   746             }
       
   747         }
       
   748         #endregion
       
   749 
       
   750         #region Navigation call backs
       
   751         private void Navigator_NavBegin()
       
   752         {
       
   753             iRenderStartTime = DateTime.Now;
       
   754             //System.Diagnostics.Debug.WriteLine( "DRAW START" );
       
   755 
       
   756             // Clear any existing data
       
   757             iGraphics.Clear( Color.White );
       
   758         }
       
   759 
       
   760         private void Navigator_NavEnd()
       
   761         {
       
   762             iFactory.Renderers.RenderingComplete( iGraphics );
       
   763 
       
   764             System.DateTime renderTimeEnd = DateTime.Now;
       
   765             //System.Diagnostics.Debug.WriteLine( "DRAW END - " + ( renderTimeEnd.Ticks - iRenderStartTime.Ticks ) / 100 );
       
   766         }
       
   767 
       
   768         private void Navigator_NavNewRowHeader( uint aAddress, Point aPosition, Size aDimensions, Size aBoxSize, Size aPadding )
       
   769         {
       
   770             // Draw the address at the start of each row
       
   771             iFactory.Renderers.Header.PaintRowHeader( iGraphics, aPosition, CellAddressHeaderSize, aAddress );
       
   772         }
       
   773 
       
   774         private void Navigator_NavNewColumn( HeapCell aCell, HeapCellMetaData aMetaData, uint aAddress, Point aPixelPos, Point aBoxPos, Size aDimensions, Size aBoxSize, Size aPadding )
       
   775         {
       
   776             // Draw content
       
   777             iFactory.Renderers.Content.PaintContent( iGraphics, aMetaData, aCell, aAddress, aPixelPos, aBoxSize, aPadding );
       
   778 
       
   779             // Draw cell border
       
   780             iFactory.Renderers.ContentBorder.PaintContentBorder( iGraphics, aMetaData, aCell, aAddress, aPixelPos, aBoxSize, aPadding );
       
   781 
       
   782             // If we are handling a click & drag operation, then check whether the cell
       
   783             // needs a border.
       
   784             if  ( iMouseSelectionCell != null )
       
   785             {
       
   786                 // Get the cell index within the cell array 
       
   787                 int index = CellIndex( aCell );
       
   788                 int mouseBoundLower = (int) iMouseSelectionCellBoundaryLower.Tag;
       
   789                 int mouseBoundUpper = (int) iMouseSelectionCellBoundaryUpper.Tag;
       
   790 
       
   791                 if  ( index >= mouseBoundLower && index <= mouseBoundUpper )
       
   792                 {
       
   793                     iFactory.Renderers.SelectionBorder.PaintSelectionBorder( iGraphics, aMetaData, aCell, aAddress, aPixelPos, aBoxSize, aPadding, THeapSelectionBorderType.ESelectionMouse );
       
   794                 }
       
   795             }
       
   796             else if ( iFocusedCellKeyboard == aCell )
       
   797             {
       
   798                 // Draw border around currently mouse over'd cell
       
   799                 iFactory.Renderers.SelectionBorder.PaintSelectionBorder( iGraphics, aMetaData, aCell, aAddress, aPixelPos, aBoxSize, aPadding, THeapSelectionBorderType.ESelectionKeyboard );
       
   800             }
       
   801             else if ( iFocusedCellMouse == aCell )
       
   802             {
       
   803                 // Draw border around currently mouse over'd cell
       
   804                 iFactory.Renderers.SelectionBorder.PaintSelectionBorder( iGraphics, aMetaData, aCell, aAddress, aPixelPos, aBoxSize, aPadding, THeapSelectionBorderType.ESelectionMouse );
       
   805             }
       
   806         }
       
   807 
       
   808         private void Navigator_NavHeapCellEnd( HeapCell aCell, HeapCellMetaData aMetaData, uint aAddress, Point aPosition, Size aDimensions, Size aBoxSize, Size aPadding )
       
   809         {
       
   810             iFactory.Renderers.HeapCellRenderingComplete( iGraphics, aCell, aMetaData );
       
   811         }
       
   812         #endregion
       
   813 
       
   814         #region Internal constants
       
   815         private const uint KDWordSize = SymbianUtils.RawItems.RawItem.KSizeOfOneRawItemInBytes;
       
   816         private Label iLbl_NoContent;
       
   817         #endregion
       
   818 
       
   819         #region Internal methods
       
   820         private void InitialiseRenderers()
       
   821         {
       
   822             if  ( Reconstructor != null )
       
   823             {
       
   824                 iFactory.Renderers.Initialise( Cells, Reconstructor, this );
       
   825             }
       
   826         }
       
   827 
       
   828         private void AsyncShowPopup( HeapCellArrayWithStatistics aCells, Point aPos, RawItem aRawItem )
       
   829         {
       
   830             if ( iFactory.PopupManager.SupportsRawItemInfo && aRawItem != null && aRawItem.Tag != null && aRawItem.Tag is RelationshipInfo && aCells.Count == 1 )
       
   831             {
       
   832                 HeapCell cell = aCells[ 0 ];
       
   833                 iFactory.PopupManager.PopupShowAsync( cell, aRawItem, Reconstructor.Statistics, aPos, PointToScreen( aPos ), CellBoxSizeIncludingPadding, new KeyEventHandler( HeapDataRenderer_KeyDown ) );
       
   834             }
       
   835             else
       
   836             {
       
   837                 iFactory.PopupManager.PopupShowAsync( aCells, Reconstructor.Statistics, aPos, PointToScreen( aPos ), CellBoxSizeIncludingPadding, new KeyEventHandler( HeapDataRenderer_KeyDown ) );
       
   838             }
       
   839 
       
   840             iMouseHoverPosition = aPos;
       
   841         }
       
   842         #endregion
       
   843 
       
   844         #region Key handling
       
   845         protected override bool ProcessCmdKey(ref Message aMsg, Keys aKeyData)
       
   846         {
       
   847             const int WM_KEYFIRST = 0x100;
       
   848             bool handled = false;
       
   849             //
       
   850             if ( aMsg.Msg == WM_KEYFIRST )
       
   851             {
       
   852                 //SymbianUtilsUi.Utilities.WindowMessages.PrintMessage( "RCMD [" + aKeyData + "] ", aMsg.Msg );
       
   853                 KeyEventArgs keyArgs = new KeyEventArgs( aKeyData );
       
   854                 HandleKey( this, keyArgs );
       
   855                 handled = keyArgs.Handled;
       
   856             }
       
   857             //
       
   858             if  ( !handled )
       
   859             {
       
   860                 handled = base.ProcessCmdKey( ref aMsg, aKeyData );
       
   861             }
       
   862             //
       
   863             return handled;
       
   864         }
       
   865 
       
   866         private void HeapDataRenderer_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
       
   867         {
       
   868             //System.Diagnostics.Debug.WriteLine( "Key Down: " + e.KeyCode );
       
   869             HandleKey( sender, e );
       
   870         }
       
   871 
       
   872         private void HandleKey( object sender, System.Windows.Forms.KeyEventArgs e )
       
   873         {
       
   874             switch( e.KeyCode )
       
   875             {
       
   876                     // Move up & down one LINE at a time...
       
   877                 case Keys.Down:
       
   878                     ScrollByLineDelta( 1 );
       
   879                     e.Handled = true;
       
   880                     break;
       
   881                 case Keys.Up:
       
   882                     ScrollByLineDelta( -1 );
       
   883                     e.Handled = true;
       
   884                     break;
       
   885 
       
   886                     // Move up & down one PAGE at a time...
       
   887                 case Keys.Next:
       
   888                     ScrollByLineDelta( RowsAndColumns.Height );
       
   889                     e.Handled = true;
       
   890                     break;
       
   891                 case Keys.Prior:
       
   892                     ScrollByLineDelta( -RowsAndColumns.Height );
       
   893                     e.Handled = true;
       
   894                     break;
       
   895 
       
   896                     // Move to beginning or end of heap
       
   897                 case Keys.Home:
       
   898                     ScrollToAddress( Reconstructor.Statistics.HeapAddressStart );
       
   899                     e.Handled = true;
       
   900                     break;
       
   901                 case Keys.End:
       
   902                 {
       
   903                     uint rowsForHeap = iReconstructor.Statistics.HeapSize / BytesPerRow;
       
   904                     uint rowsPerPage = (uint) RowsAndColumns.Height;
       
   905                     uint targetRow = rowsForHeap - rowsPerPage + 1;
       
   906                     uint address = Reconstructor.Statistics.HeapAddressStart + ( targetRow *  BytesPerRow );
       
   907                     ScrollToAddress( address );
       
   908                     e.Handled = true;
       
   909                     break;
       
   910                 }
       
   911 
       
   912                     // Move one cell at a time
       
   913                 case Keys.Right:
       
   914                 {
       
   915                     if  ( iFocusedCellKeyboard != null )
       
   916                     {
       
   917                         int index = Cells.CellIndex( iFocusedCellKeyboard );
       
   918                         if  ( index + 1 < Cells.Count )
       
   919                         {
       
   920                             iFactory.PopupManager.PopupHide();
       
   921                             FocusedCell = Cells[ index + 1 ];
       
   922                             e.Handled = true;
       
   923                         }
       
   924                     }
       
   925                     break;
       
   926                 }
       
   927                 case Keys.Left:
       
   928                 {
       
   929                     if  ( iFocusedCellKeyboard != null )
       
   930                     {
       
   931                         int index = Cells.CellIndex( iFocusedCellKeyboard );
       
   932                         if  ( index - 1 >= 0 )
       
   933                         {
       
   934                             iFactory.PopupManager.PopupHide();
       
   935                             FocusedCell = Cells[ index - 1 ];
       
   936                             e.Handled = true;
       
   937                         }
       
   938                     }
       
   939                     break;
       
   940                 }
       
   941 
       
   942                     // Unhandled
       
   943                 default:
       
   944                     e.Handled = false;
       
   945                     break;
       
   946             }
       
   947         } 
       
   948        
       
   949         private void ScrollByLineDelta( int aLines )
       
   950         {
       
   951             // Update delta to now finally take into account how many
       
   952             // bytes we are going to offset the current address by
       
   953             uint delta = (uint) ( aLines * BytesPerRow );
       
   954 
       
   955             // Get current address from renderer
       
   956             uint address = Address;
       
   957 
       
   958             // We are going to attempt to offset the current renderer address
       
   959             // by the delta, but we don't want to fall out of bounds (before or
       
   960             // after the min/max address range for the heap).
       
   961             address += delta;
       
   962 
       
   963             // Set address
       
   964             ScrollToAddress( address );
       
   965         }
       
   966 
       
   967         private void ScrollToAddress( uint aAddress )
       
   968         {
       
   969             // Work out the maximum address. We never prevent the user to scroll so far
       
   970             // that they go past the last line.
       
   971             uint rowsForHeap = Reconstructor.Statistics.HeapSize / BytesPerRow;
       
   972             uint lastRowStartingAddress = Reconstructor.Statistics.HeapAddressStart + ( rowsForHeap *  BytesPerRow );
       
   973             uint address = Math.Min( lastRowStartingAddress, Math.Max( Reconstructor.Statistics.HeapAddressStart, aAddress ) );
       
   974 
       
   975             if  ( address >= Reconstructor.Statistics.HeapAddressStart )
       
   976             {
       
   977                 Address = address;
       
   978             }
       
   979         }
       
   980         #endregion
       
   981 
       
   982         #region Mouse handling
       
   983         /*protected override void WndProc(ref Message m)
       
   984         {
       
   985             SymbianUtilsUi.Utilities.WindowMessages.PrintMessage( "RNDR ", m.Msg );
       
   986             base.WndProc (ref m);
       
   987         }*/
       
   988 
       
   989         private void HeapDataRenderer_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
       
   990         {
       
   991             if ( e.Button == MouseButtons.Right )
       
   992             {
       
   993                 // Convert the click pos to a cell
       
   994                 HeapCell cell = CellByPosition( new Point( e.X, e.Y ) );
       
   995                 if ( cell != null && CellRightClicked != null )
       
   996                 {
       
   997                     // Convert the click pos to a box
       
   998                     Point boxPos = CoordinateToBox( e.Location );
       
   999                     
       
  1000                     // and then convert the box coordinate to an address
       
  1001                     uint address = AddressByBoxCoordinates( boxPos );
       
  1002                     
       
  1003                     // And the try to map that address to a raw item
       
  1004                     RawItem rawItem = cell[ address ];
       
  1005 
       
  1006                     // Then notify observer
       
  1007                     CellRightClicked( cell, rawItem, e.Location );
       
  1008                 }
       
  1009             }
       
  1010             else
       
  1011             {
       
  1012                 bool fc = Focus();
       
  1013                 Select();
       
  1014                 //System.Diagnostics.Debug.WriteLine( "RNDR Focused: " + fc );
       
  1015 
       
  1016                 if ( Cells.Count > 0 && iMouseSelectionCell == null )
       
  1017                 {
       
  1018                     iMouseSelectionCell = CellByPosition( new Point( e.X, e.Y ) );
       
  1019                     //
       
  1020                     if ( iMouseSelectionCell != null )
       
  1021                     {
       
  1022                         iFactory.PopupManager.PopupHide();
       
  1023                         //
       
  1024                         iMouseSelectionCell.Tag = CellIndex( iMouseSelectionCell );
       
  1025                         //
       
  1026                         iMouseSelectionCellBoundaryLower = iMouseSelectionCell;
       
  1027                         iMouseSelectionCellBoundaryUpper = iMouseSelectionCell;
       
  1028                         //
       
  1029                         //System.Diagnostics.Debug.WriteLine( "MouseDOWN: [ " + e.X + ", " + e.Y + " ] " + iMouseSelectionCell.ToString() );
       
  1030                         //
       
  1031                     }
       
  1032                 }
       
  1033             }
       
  1034         }
       
  1035  
       
  1036         private void HeapDataRenderer_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
       
  1037         {
       
  1038             //System.Diagnostics.Debug.WriteLine( "MouseUP:   [ " + e.X + ", " + e.Y + " ]" );
       
  1039             if  ( Cells.Count > 0 && iMouseSelectionCell != null )
       
  1040             {
       
  1041                 HeapCell mouseUpHeapCell = CellByPosition( new Point( e.X, e.Y ) );
       
  1042                 //
       
  1043                 if  ( mouseUpHeapCell != null )
       
  1044                 {
       
  1045                     //System.Diagnostics.Debug.WriteLine( "MouseUP:   [ " + e.X + ", " + e.Y + " ] " + mouseUpHeapCell.ToString() );
       
  1046                 }
       
  1047 
       
  1048                 FocusedCell = mouseUpHeapCell;
       
  1049 
       
  1050                 iMouseSelectionCell = null;
       
  1051                 Invalidate();
       
  1052             }
       
  1053         }
       
  1054 
       
  1055         private void HeapDataRenderer_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
       
  1056         {
       
  1057             if  ( Cells.Count > 0 )
       
  1058             {
       
  1059                 Point mousePos = new Point( e.X, e.Y );
       
  1060                 HeapCell cell = CellByPosition( mousePos );
       
  1061                 //
       
  1062                 if  ( cell != null )
       
  1063                 {
       
  1064                     // Also try to get the raw item associated with the hover position. This can
       
  1065                     // also return null.
       
  1066                     RawItem rawItem = RawItemByPixelPos( mousePos );
       
  1067 
       
  1068                     // Now process the mouse movement
       
  1069                     if  ( iMouseSelectionCell != null )
       
  1070                     {
       
  1071                         int mouseBoundStart = (int) iMouseSelectionCell.Tag;
       
  1072                         int mouseBoundLower = (int) iMouseSelectionCellBoundaryLower.Tag;
       
  1073                         int mouseBoundUpper = (int) iMouseSelectionCellBoundaryUpper.Tag;
       
  1074                         int originalSelectionRangeCount = ( mouseBoundUpper - mouseBoundLower );
       
  1075 
       
  1076                         int index = CellIndex( cell );
       
  1077                         if  ( index < mouseBoundStart )
       
  1078                         {
       
  1079                             // Reset upper boundary
       
  1080                             iMouseSelectionCellBoundaryUpper = iMouseSelectionCell;
       
  1081                             iMouseSelectionCellBoundaryLower = cell;
       
  1082                             iMouseSelectionCellBoundaryLower.Tag = index;
       
  1083                         }
       
  1084                         else if ( index > mouseBoundStart )
       
  1085                         {
       
  1086                             // Reset lower boundary
       
  1087                             iMouseSelectionCellBoundaryLower = iMouseSelectionCell;
       
  1088                             iMouseSelectionCellBoundaryUpper = cell;
       
  1089                             iMouseSelectionCellBoundaryUpper.Tag = index;
       
  1090                         }
       
  1091                         else if ( index == mouseBoundStart )
       
  1092                         {
       
  1093                             iMouseSelectionCellBoundaryUpper = iMouseSelectionCell;
       
  1094                             iMouseSelectionCellBoundaryLower = iMouseSelectionCell;
       
  1095                         }
       
  1096 
       
  1097                         // Update boundary
       
  1098                         mouseBoundLower = (int) iMouseSelectionCellBoundaryLower.Tag;
       
  1099                         mouseBoundUpper = (int) iMouseSelectionCellBoundaryUpper.Tag;
       
  1100 
       
  1101                         // Work out if this is a multi-select scenario
       
  1102                         int selectionRangeCount = mouseBoundUpper - mouseBoundLower;
       
  1103                         bool selectionHasChanged = ( selectionRangeCount != originalSelectionRangeCount );
       
  1104                         if  ( selectionHasChanged && Math.Abs( selectionRangeCount ) + 1 > 1 )
       
  1105                         {
       
  1106                             // Build array of selected cells
       
  1107                             HeapCellArrayWithStatistics cells = new HeapCellArrayWithStatistics();
       
  1108                             for( index = mouseBoundLower; index <= mouseBoundUpper; index++ )
       
  1109                             {
       
  1110                                 cell = Cells[ index ];
       
  1111                                 cells.Add( cell );
       
  1112                             }
       
  1113 
       
  1114                             // Show popup
       
  1115                             bool popupVisible = iFactory.PopupManager.Visible;
       
  1116                             Point pos = new Point( e.X, e.Y );
       
  1117 
       
  1118                             if  ( !popupVisible || !( e.X == iMouseHoverPosition.X && e.Y == iMouseHoverPosition.Y ) )
       
  1119                             {
       
  1120                                 if  ( !popupVisible )
       
  1121                                 {
       
  1122                                     //System.Diagnostics.Debug.WriteLine( "Mouse MOVE - MS [popup not vis], Differing Coords: [ " + e.X + ", " + e.Y + " ] -> Popup Show" );
       
  1123                                     AsyncShowPopup( cells, pos, rawItem );
       
  1124                                 }
       
  1125                                 else
       
  1126                                 {
       
  1127                                     //System.Diagnostics.Debug.WriteLine( "Mouse MOVE - MS [popup visible], Differing Coords: [ " + e.X + ", " + e.Y + " ] -> Popup Already Shown" );
       
  1128                                     iMouseHoverPosition = pos;
       
  1129                                     iFactory.PopupManager.PopupRelocate( cells, Reconstructor.Statistics, pos, PointToScreen( pos ), CellBoxSizeIncludingPadding );
       
  1130                                 }
       
  1131                             }
       
  1132                             else if ( !popupVisible )
       
  1133                             {
       
  1134                                 //System.Diagnostics.Debug.WriteLine( "Mouse MOVE - MS [popup not vis], Differing Coords: [ " + e.X + ", " + e.Y + " ] -> Popup Show" );
       
  1135                                 AsyncShowPopup( cells, pos, rawItem );
       
  1136                             }
       
  1137                        }
       
  1138                         else if ( selectionHasChanged )
       
  1139                         {
       
  1140                             //System.Diagnostics.Debug.WriteLine( "Mouse MOVE - Have Existing Selection: [ " + e.X + ", " + e.Y + " ] -> Single Item Hover" );
       
  1141                             iFactory.PopupManager.PopupHide();
       
  1142                         }
       
  1143                     }
       
  1144                     else
       
  1145                     {
       
  1146                         if  ( iFactory.PopupManager.Visible )
       
  1147                         {
       
  1148                             if  ( ! ( e.X == iMouseHoverPosition.X && e.Y == iMouseHoverPosition.Y ) )
       
  1149                             {
       
  1150                                 //System.Diagnostics.Debug.WriteLine( "Mouse MOVE: [ " + e.X + ", " + e.Y + " ] -> Popup Hidden" );
       
  1151                                 iFactory.PopupManager.PopupHide();
       
  1152                             }
       
  1153                         }
       
  1154                         else if  ( ! ( e.X == iMouseHoverPosition.X && e.Y == iMouseHoverPosition.Y ) )
       
  1155                         {
       
  1156                             //System.Diagnostics.Debug.WriteLine( "Mouse MOVE: [ " + e.X + ", " + e.Y + " ] -> Popup Show Async" );
       
  1157                             Point pos = new Point( e.X, e.Y );
       
  1158                             HeapCellArrayWithStatistics cells = new HeapCellArrayWithStatistics();
       
  1159                             cells.Add( cell );
       
  1160                             AsyncShowPopup( cells, pos, rawItem );
       
  1161                         }
       
  1162                     }
       
  1163                     //
       
  1164                     Invalidate();
       
  1165                 }
       
  1166                 //
       
  1167                 iFocusedCellMouse = cell;
       
  1168             }
       
  1169         }
       
  1170 
       
  1171         private void HeapDataRenderer_MouseLeave(object sender, System.EventArgs e)
       
  1172         {
       
  1173             Point pos = System.Windows.Forms.Cursor.Position;
       
  1174             //System.Diagnostics.Debug.WriteLine( "Mouse LEAVE: Popup hidden - pos: " + pos + ", locY: " + PointToScreen( Location ).Y );
       
  1175 
       
  1176             iFactory.PopupManager.PopupHide();
       
  1177             //
       
  1178             iFocusedCellMouse = null;
       
  1179             iMouseSelectionCell = null;
       
  1180             //
       
  1181             Invalidate();
       
  1182         }
       
  1183 
       
  1184         private void HeapDataRenderer_MouseWheel(object sender, MouseEventArgs e)
       
  1185         {
       
  1186             // For each scroll of the mouse wheel
       
  1187             int mouseScrollLines = SystemInformation.MouseWheelScrollLines;
       
  1188 
       
  1189             // Odd(?), but scrolling down results in a negative delta (-120), and
       
  1190             // scrolling up results in positive
       
  1191             int delta = ( e.Delta < 0 ) ? 1 : -1;
       
  1192             delta *= mouseScrollLines;
       
  1193 
       
  1194             ScrollByLineDelta( delta );
       
  1195         }
       
  1196 
       
  1197         private void HeapDataRenderer_MouseDoubleClick( object sender, MouseEventArgs e )
       
  1198         {
       
  1199             HeapCell cell = CellByPosition( new Point( e.X, e.Y ) );
       
  1200             //
       
  1201             if ( cell !=  null && CellDoubleClicked != null )
       
  1202             {
       
  1203                 CellDoubleClicked( cell );
       
  1204             }
       
  1205         }
       
  1206         #endregion
       
  1207 
       
  1208         #region Data members
       
  1209         private HeapCell iFocusedCellKeyboard = null;
       
  1210         private HeapCell iFocusedCellMouse = null;
       
  1211         private Point iMouseHoverPosition;
       
  1212         private HeapCell iMouseSelectionCell = null;
       
  1213         private HeapCell iMouseSelectionCellBoundaryLower = null;
       
  1214         private HeapCell iMouseSelectionCellBoundaryUpper = null;
       
  1215         private HeapReconstructor iReconstructor = null;
       
  1216         private HeapCellArray iCells = new HeapCellArray();
       
  1217         private int iHeaderTextWidth = 30;
       
  1218         private Size iCellBoxSize = new Size( 100, 100 );
       
  1219         private Size iCellPadding = new Size(  20,  20 );
       
  1220         private int iCellIndex = 0;
       
  1221         private uint iCellAddress = 0;
       
  1222         private Factory iFactory = null;
       
  1223         private Graphics iGraphics = null;
       
  1224         private THeapCtrlZoom iZoom = THeapCtrlZoom.EHeapCtrlZoomMedium;
       
  1225         private HeapCellArrayWithStatistics iSelectedCells = new HeapCellArrayWithStatistics();
       
  1226         private System.DateTime iRenderStartTime = new DateTime();
       
  1227         private HeapCellArrayUnsorted iBreadcrumbCellsOutgoing = new HeapCellArrayUnsorted();
       
  1228         private HeapCellArrayUnsorted iBreadcrumbCellsIncoming = new HeapCellArrayUnsorted();
       
  1229         #endregion
       
  1230     }
       
  1231 }