Skip to content

Commit

Permalink
Feature: show current selection in both panes of the CombinedCodeView (
Browse files Browse the repository at this point in the history
  • Loading branch information
uxmal committed Jun 7, 2022
1 parent 4cd1790 commit 15d0a29
Show file tree
Hide file tree
Showing 21 changed files with 232 additions and 23 deletions.
1 change: 1 addition & 0 deletions src/Drivers/reko.config
Original file line number Diff line number Diff line change
Expand Up @@ -787,5 +787,6 @@
<Style Name="browser" />
<Style Name="list" />
<Style Name="lastLine" PaddingBottom="10" />
<Style Name="mirrored" BackColor="#E0E0FF" />
</UiPreferences>
</Reko>
3 changes: 3 additions & 0 deletions src/Gui/Forms/MainFormInteractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,9 @@ private void CreateServices(IServiceFactory svcFactory, IServiceContainer sc)
var selSvc = svcFactory.CreateSelectionService();
sc.AddService<ISelectionService>(selSvc);

var selAddrSvc = svcFactory.CreateSelectedAddressService();
sc.AddService<ISelectedAddressService>(selAddrSvc);

var testGenSvc = svcFactory.CreateTestGenerationService();
sc.AddService<ITestGenerationService>(testGenSvc);

Expand Down
1 change: 1 addition & 0 deletions src/Gui/IServiceFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public interface IServiceFactory
IViewImportsService CreateViewImportService();
ISymbolLoadingService CreateSymbolLoadingService();
ISelectionService CreateSelectionService();
ISelectedAddressService CreateSelectedAddressService();
IProcedureListService CreateProcedureListService();
ICallHierarchyService CreateCallHierarchyService();
IDecompiledFileService CreateDecompiledFileService();
Expand Down
71 changes: 71 additions & 0 deletions src/Gui/SelectedAddressService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#region License
/*
* Copyright (C) 1999-2022 John Källén.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#endregion

#nullable enable

using Reko.Core;
using Reko.Gui.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Reko.Gui
{
public class SelectedAddressService : ISelectedAddressService
{
public event EventHandler? SelectedAddressChanged;


private Address? address;
private long length;

public SelectedAddressService()
{
}

public Address? SelectedAddress
{
get => address;
set
{
if (object.Equals(this.address, value))
return;
this.address = value;
SelectedAddressChanged?.Invoke(this, EventArgs.Empty);
}
}

public long Length
{
get => length;
set
{
if (value < 0)
throw new ArgumentOutOfRangeException();
if (this.length == value)
return;
this.length = value;
SelectedAddressChanged?.Invoke(this, EventArgs.Empty);
}
}
}
}
56 changes: 56 additions & 0 deletions src/Gui/Services/ISelectedAddressService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#region License
/*
* Copyright (C) 1999-2022 John Källén.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#endregion

using Reko.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

#nullable enable

namespace Reko.Gui.Services
{
/// <summary>
/// This service is used by components that are interested
/// in the currently selected address.
/// </summary>
public interface ISelectedAddressService
{
/// <summary>
/// This event is raised when the selected address is changed.
/// </summary>
event EventHandler? SelectedAddressChanged;

/// <summary>
/// If not null, indicates the address the user has
/// selected.
/// </summary>
public Address? SelectedAddress { get; set; }

/// <summary>
/// Indicates the length of the selection the user has
/// made. A length of 0 indicates that only the address
/// has been selected, not a range of bytes.
/// </summary>
public long Length { get; }
}
}
2 changes: 2 additions & 0 deletions src/UnitTests/Mocks/FakeCallingConvention.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
using System.Text;
using System.Threading.Tasks;

#nullable enable

namespace Reko.UnitTests.Mocks
{
public class FakeCallingConvention : CallingConvention
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ public ISearchResultService CreateSearchResultService()
return new AvaloniaSearchResultService(services);
}

public ISelectedAddressService CreateSelectedAddressService()
{
return new SelectedAddressService();
}

public ISelectionService CreateSelectionService()
{
return new SelectionService();
Expand Down
2 changes: 1 addition & 1 deletion src/UserInterfaces/WindowsForms/CodeViewInteractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private void CreateNestedTextModel()
this.nodeByAddress = new SortedList<Address, MixedCodeDataModel.DataItemNode>();
foreach (var proc in program.Procedures.Values)
{
var model = new ProcedureCodeModel(proc);
var model = new ProcedureCodeModel(proc, services.RequireService<ISelectedAddressService>());
//$TODO: make spacing between globals / procedures user adjustable
model.NumEmptyLinesAfter = 2;
nestedTextModel.Nodes.Add(model);
Expand Down
34 changes: 31 additions & 3 deletions src/UserInterfaces/WindowsForms/CombinedCodeViewInteractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
Expand All @@ -41,6 +42,14 @@

namespace Reko.UserInterfaces.WindowsForms
{
/// <summary>
/// Handles events on the <see cref="CombinedCodeView"/> control.
/// </summary>
/// <remarks>
/// The left side of the control is the <see cref="MixedCodeDataControl"/>,
/// while the right side of the control can be switched between a view of
/// IR code or a Graph viewer.
/// </remarks>
public class CombinedCodeViewInteractor : IWindowPane, ICommandTarget
{
private IServiceProvider services;
Expand Down Expand Up @@ -141,7 +150,7 @@ private void CreateNestedTextModel()
{
this.nestedTextModel = new NestedTextModel();

if (!(combinedCodeView.MixedCodeDataView.Model is MixedCodeDataModel mixedCodeDataModel))
if (combinedCodeView.MixedCodeDataView.Model is not MixedCodeDataModel mixedCodeDataModel)
return;

var dataItemNodes = mixedCodeDataModel.GetDataItemNodes();
Expand All @@ -157,7 +166,8 @@ private void CreateNestedTextModel()
{
if (proc != null)
{
var model = new ProcedureCodeModel(proc);
var selSvc = services.RequireService<ISelectedAddressService>();
var model = new ProcedureCodeModel(proc, selSvc);
//$TODO: make spacing between globals / procedures user adjustable
model.NumEmptyLinesAfter = 2;
nestedTextModel.Nodes.Add(model);
Expand Down Expand Up @@ -188,7 +198,6 @@ private void CreateNestedTextModel()
this.nodeByAddress[curAddr] = dataItemNode;
}
}

combinedCodeView.CodeView.Model = nestedTextModel;
}

Expand Down Expand Up @@ -520,14 +529,33 @@ private async ValueTask Rename()

private void MixedCodeDataView_MouseDown(object sender, MouseEventArgs e)
{
var mixedViewTag = combinedCodeView.MixedCodeDataView.GetLineTagFromPoint(new Point(e.X, e.Y));
UpdateSelectedAddress(mixedViewTag);
combinedCodeView.CodeView.ClearSelection();
combinedCodeView.MixedCodeDataView.ClearSelection();
}

private void CodeView_MouseDown(object sender, MouseEventArgs e)
{
var codeViewTag = combinedCodeView.CodeView.GetLineTagFromPoint(new Point(e.X, e.Y));
UpdateSelectedAddress(codeViewTag);
combinedCodeView.CodeView.ClearSelection();
combinedCodeView.MixedCodeDataView.ClearSelection();
}

private void UpdateSelectedAddress(object tag)
{
if (tag is not Address addr)
{
if (tag is ulong uAddr)
addr = this.program.SegmentMap.MapLinearAddressToAddress(uAddr);
else
return;
}
var selSvc = services.RequireService<ISelectedAddressService>();
selSvc.SelectedAddress = addr;
}

public void ViewGraph()
{
gViewer.Parent = combinedCodeView.Parent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#endregion

using Reko.Core;
using Reko.Gui;
using Reko.Gui.Services;
using System;

Expand Down Expand Up @@ -73,9 +74,10 @@ private void OnProgramChanged()
{
try
{
if (program != null)
if (program is not null && Services is not null)
{
Model = new MixedCodeDataModel(program, program.ImageMap.Clone());
var selSvc = Services.RequireService<ISelectedAddressService>();
Model = new MixedCodeDataModel(program, program.ImageMap.Clone(), selSvc);
var currentPos = Model.CurrentPosition;
addrTop = MixedCodeDataModel.PositionAddress(currentPos);
return;
Expand Down Expand Up @@ -118,7 +120,8 @@ protected override void OnScroll()
private void RefreshModel()
{
var currentPos = Model.CurrentPosition;
var model = new MixedCodeDataModel(program, program.ImageMap.Clone());
var selSvc = Services.RequireService<ISelectedAddressService>();
var model = new MixedCodeDataModel(program, program.ImageMap.Clone(), selSvc);
model.MoveToLine(currentPos, 0);
currentPos = Model.CurrentPosition;
this.addrTop = MixedCodeDataModel.PositionAddress(currentPos);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
namespace Reko.UserInterfaces.WindowsForms.Controls
{
public partial class MixedCodeDataModel
{
{
private bool TryReadComment(out LineSpan line)
{
if (comments.TryGetValue(curPos.Address, out var commentLines) &&
Expand Down Expand Up @@ -131,7 +131,12 @@ public LineSpan[] GetLineSpans(int count)
SpanGenerator sp;
if (item is ImageMapBlock b && b.Block.Procedure != null)
{
sp = new AsmSpanifyer(program, b.Block.Procedure.Architecture, instructions[b], pos);
sp = new AsmSpanifyer(
program,
b.Block.Procedure.Architecture,
instructions[b],
pos,
this.selSvc?.SelectedAddress);
}
else
{
Expand Down Expand Up @@ -159,24 +164,27 @@ public void DecorateLastLine(LineSpan line)

private class AsmSpanifyer : SpanGenerator
{
private Program program;
private IProcessorArchitecture arch;
private MachineInstruction[] instrs;
private readonly Program program;
private readonly IProcessorArchitecture arch;
private readonly MachineInstruction[] instrs;
private int offset;
private ModelPosition position;
private readonly Address addrSelected;

public AsmSpanifyer(
Program program,
IProcessorArchitecture arch,
MachineInstruction[] instrs,
ModelPosition pos)
ModelPosition pos,
Address addrSelected)
{
this.instrs = instrs;
this.arch = arch;
var addr = pos.Address;
this.offset = FindIndexOfInstructionAddress(instrs, addr);
this.position = pos;
this.program = program;
this.addrSelected = addrSelected;
}

public override (ModelPosition, LineSpan)? GenerateSpan()
Expand All @@ -193,6 +201,8 @@ public override (ModelPosition, LineSpan)? GenerateSpan()
arch,
instr,
options);
if (instr.Address == addrSelected)
asmLine.Style = "mirrored";
if (offset == instrs.Length)
{
DecorateLastLine(asmLine);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
using Reko.Core;
using Reko.Core.Collections;
using Reko.Core.Machine;
using Reko.Gui;
using Reko.Gui.Services;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
Expand All @@ -38,17 +40,20 @@ public partial class MixedCodeDataModel : TextViewModel

private readonly Program program;
private readonly ImageMap imageMap;
private readonly ISelectedAddressService selSvc;
private ModelPosition curPos;
private readonly ModelPosition endPos;
private readonly Dictionary<ImageMapBlock, MachineInstruction[]> instructions;
private readonly IDictionary<Address, string[]> comments;

public MixedCodeDataModel(Program program, ImageMap imageMap)
public MixedCodeDataModel(Program program, ImageMap imageMap, ISelectedAddressService selSvc)
{
this.program = program;
this.imageMap = imageMap;
this.selSvc = selSvc;

var firstSeg = program.SegmentMap.Segments.Values.FirstOrDefault();
if (firstSeg == null)
if (firstSeg is null)
{
this.curPos = Pos(imageMap.BaseAddress);
this.StartPosition = Pos(imageMap.BaseAddress);
Expand Down
Loading

0 comments on commit 15d0a29

Please sign in to comment.