protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); int index = this.IndexFromPoint(e.Location); if (index >= 0) { bool needsInvalidate = false; int oldIndex = _hoveredIndex; if (_hoveredIndex != index) { //Debug.WriteLine( "up " + _hoveredIndex.ToString() ); //Debug.WriteLine( "down " + _hoveredIndex.ToString() ); _hoveredIndex = index; _hoveredColumn = Column.None; _hoveredValue = null; needsInvalidate = true; } int x = e.X; int y = e.Y + (this.TopIndex * this.ItemHeight); Column newColumn = this.GetColumn(x); if (_hoveredColumn != newColumn) { //Debug.WriteLine( "out " + _hoveredColumn.ToString() ); //Debug.WriteLine( "in " + newColumn.ToString() ); _hoveredColumn = newColumn; needsInvalidate = true; } Instruction instr = ( Instruction )this.Items[index]; string tipText = null; switch (_hoveredColumn) { case Column.Gutter: { this.ContextMenuStrip = this.gutterContextMenuStrip; bool hasBreakpoint = (instr.BreakpointID != Instruction.InvalidBreakpointID); if (hasBreakpoint == true) { tipText = "Breakpoint ????"; } else { tipText = "Click to add a breakpoint"; } } break; case Column.Address: this.ContextMenuStrip = this.lineContextMenuStrip; break; case Column.Instruction: { this.ContextMenuStrip = this.lineContextMenuStrip; object newValue = null; // Try to find the opcode/operand the cursor is over CachedFormatting formatting = _formatCache[index]; if (formatting.Opcode.Bounds.Contains(x, y)) { newValue = formatting.Opcode; tipText = string.Format("0x{0:X8}", instr.Code); //Debug.WriteLine( "hover opcode " + formatting.Opcode.Opcode.ToString() ); } else { for (int n = 0; n < formatting.Operands.Length; n++) { CachedOperand cop = formatting.Operands[n]; if (cop.Bounds.Contains(x, y) == true) { newValue = cop; // Ignore annotations if (cop.Operand.Type != OperandType.Annotation) { tipText = this.RequestOperandValue(instr, cop.Operand, true); } //Debug.WriteLine( "hover operand " + cop.Operand.ToString() ); break; } } } if (_hoveredValue != newValue) { //if( newValue == null ) // Debug.WriteLine( "hover up" ); _hoveredValue = newValue; needsInvalidate = true; } } break; case Column.Visualizer: this.ContextMenuStrip = null; break; default: case Column.None: this.ContextMenuStrip = null; break; } if (needsInvalidate == true) { if ((oldIndex >= 0) && (oldIndex != _hoveredIndex)) { this.Invalidate(this.GetItemRectangle(oldIndex)); } this.Invalidate(this.GetItemRectangle(_hoveredIndex)); this.toolTip1.SetToolTip(this, tipText); } } else { this.ClearHovered(); } }
protected override void OnDrawItem(DrawItemEventArgs e) { if ((this.Items.Count == 0) || (e.Index < 0)) { return; } Graphics g = e.Graphics; e.Graphics.Clip = new Region(e.Bounds); int y = e.Bounds.Top; int height = e.Bounds.Height; int offset = -(this.TopIndex * height); Instruction instr = ( Instruction )this.Items[e.Index]; CachedFormatting formatting = _formatCache[e.Index]; int x = 0; // Gutter g.FillRectangle(_gutterBrush, x, y, _gutterWidth, height); { if (instr.BreakpointID != Instruction.InvalidBreakpointID) { Image icon; Breakpoint bp = this.Debugger.Breakpoints[instr.BreakpointID]; if (bp.Enabled == true) { icon = _breakpointOnIcon; } else { icon = _breakpointOffIcon; } g.DrawImage(icon, x, y - 1, 14, 14); } // Show icons for address state (such as dead/parent) if (this.CurrentAddress == instr.Address) { Image icon = _statementIcon; g.DrawImage(icon, x, y - 1, 14, 14); } } x += _gutterWidth; // -- sep -- g.DrawLine(_vertGridPen, x, y, x, y + height); x += 1; // Address g.FillRectangle(_addressBrush, x, y, _addressWidth, height); { string addressString = string.Format("0x{0:X8}", instr.Address); Brush brush = (this.Enabled) ? _addressFontBrush : _disabledFontBrush; g.DrawString(addressString, _addressFont, brush, x + 2, y); } x += _addressWidth; // -- sep -- g.DrawLine(_vertGridPen, x, y, x, y + height); x += 1; // Instruction g.FillRectangle(_instrBrush, x, y, _instrWidth, height); { Matrix originalTransform = g.Transform; g.TranslateTransform(0.0f, offset); Brush brush = (this.Enabled) ? _instrFontBrush : _disabledFontBrush; g.DrawString(instr.Opcode.ToString(), _instrFont, brush, formatting.Opcode.Bounds, _instrFormat); for (int n = 0; n < instr.Operands.Length; n++) { RectangleF opBounds = formatting.Operands[n].Bounds; g.DrawString(instr.Operands[n].ToString(), _instrFont, brush, opBounds, _instrFormat); if (n != instr.Operands.Length - 1) { g.DrawString(", ", _instrFont, brush, new RectangleF( opBounds.Right - (CachedFormatting.OpSepWidth / 2), opBounds.Y, CachedFormatting.OpSepWidth, opBounds.Height)); } } g.Transform = originalTransform; } x += _instrWidth; // -- sep -- g.DrawLine(_vertGridPen, x, y, x, y + height); x += 1; // Visualizer g.FillRectangle(_vizBrush, x, y, _vizWidth, height); { } x += _vizWidth; if (_hoveredIndex == e.Index) { switch (_hoveredColumn) { case Column.Gutter: break; case Column.Address: break; case Column.Instruction: if (_hoveredValue is CachedOpcode) { CachedOpcode cop = ( CachedOpcode )_hoveredValue; ControlPaint.DrawFocusRectangle(g, new Rectangle(( int )cop.Bounds.X, ( int )cop.Bounds.Y + offset, ( int )cop.Bounds.Width, ( int )cop.Bounds.Height)); } else if (_hoveredValue is CachedOperand) { CachedOperand cop = ( CachedOperand )_hoveredValue; ControlPaint.DrawFocusRectangle(g, new Rectangle(( int )cop.Bounds.X, ( int )cop.Bounds.Y + offset, ( int )cop.Bounds.Width, ( int )cop.Bounds.Height)); } break; case Column.Visualizer: break; default: case Column.None: break; } } if (_contextIndex == e.Index) { Rectangle realBounds = e.Bounds; ControlPaint.DrawFocusRectangle(g, realBounds); } }