diff --git a/Opus/App.config b/Opus/App.config
index ce22e30..f616e78 100644
--- a/Opus/App.config
+++ b/Opus/App.config
@@ -9,6 +9,7 @@
+
diff --git a/Opus/UI/HexGrid.cs b/Opus/UI/HexGrid.cs
index f20ba08..678d26e 100644
--- a/Opus/UI/HexGrid.cs
+++ b/Opus/UI/HexGrid.cs
@@ -136,6 +136,50 @@ public void EnsureCellsVisible(Bounds bounds, bool scrollToCenter = false)
}
}
+ ///
+ /// Checks if scrolling the grid if necessary so that the cells in the coordinates given by bounds
+ /// are completely visible.
+ ///
+ public bool CheckCellsVisible(Vector2 position, out Rectangle scrollTargetRect, bool scrollToCenter = false)
+ {
+ return CheckCellsVisible(new Bounds(position, position), out scrollTargetRect, scrollToCenter);
+ }
+
+ ///
+ /// Checks if scrolling the grid if necessary so that the cells in the coordinates given by bounds
+ /// are completely visible.
+ ///
+ public bool CheckCellsVisible(Bounds bounds, out Rectangle scrollTargetRect, bool scrollToCenter = false)
+ {
+ var bottomLeft = GetCellLocationLocal(bounds.Min);
+ var topRight = GetCellLocationLocal(bounds.Max.Add(new Vector2(0, 1))); // Add (0, 1) so we avoid the exit button in the top-right corner of the screen
+ scrollTargetRect = new Rectangle(bottomLeft.X - HexWidth / 2, topRight.Y - HexHeight / 2,
+ topRight.X - bottomLeft.X + HexWidth, bottomLeft.Y - topRight.Y + HexHeight);
+ if (scrollToCenter)
+ {
+ return m_area.CheckScrollToCenterIfNecessary(scrollTargetRect);
+ }
+ else
+ {
+ return m_area.CheckScrollMinimalIfNecessary(scrollTargetRect);
+ }
+ }
+
+ ///
+ /// Applies scrolling to a specific rect.
+ ///
+ public void ApplyCellsVisible(Rectangle rect, bool scrollToCenter = false)
+ {
+ if (scrollToCenter)
+ {
+ m_area.ScrollToCenterIfNecessary(rect);
+ }
+ else
+ {
+ m_area.ScrollMinimalIfNecessary(rect);
+ }
+ }
+
///
/// Scrolls the grid so that the center of the cell at the specified coordinates is in the middle of the grid.
///
diff --git a/Opus/UI/Rendering/InstructionRenderer.cs b/Opus/UI/Rendering/InstructionRenderer.cs
index 3b3cbf4..7daf84c 100644
--- a/Opus/UI/Rendering/InstructionRenderer.cs
+++ b/Opus/UI/Rendering/InstructionRenderer.cs
@@ -25,6 +25,8 @@ public class InstructionRenderer
{ Instruction.Repeat, Keys.V }
};
+ public static bool QuickHotkeysEnabled { get; set; } = false;
+
public InstructionRenderer(ProgramGrid grid)
{
m_grid = grid;
@@ -42,15 +44,27 @@ public void Render(Vector2 position, Instruction instruction, int delay = 0)
var gridLocation = m_grid.GetCellLocation(position);
int keyTime = delay;
- int clickTime = delay + 50;
+ int clickTime = delay + 50;
- KeyDown(key);
- MouseUtils.SetCursorPosition(gridLocation);
- ThreadUtils.SleepOrAbort(keyTime);
- MouseUtils.LeftClick(clickTime);
+ if (!QuickHotkeysEnabled)
+ {
+ KeyDown(key);
+ MouseUtils.SetCursorPosition(gridLocation);
+ ThreadUtils.SleepOrAbort(keyTime);
+ MouseUtils.LeftClick(clickTime);
- KeyUp(key);
- ThreadUtils.SleepOrAbort(keyTime);
+ KeyUp(key);
+ ThreadUtils.SleepOrAbort(keyTime);
+ }
+ else
+ {
+ MouseUtils.SetCursorPosition(gridLocation);
+ ThreadUtils.SleepOrAbort(keyTime);
+ KeyDown(key);
+ ThreadUtils.SleepOrAbort(keyTime);
+ KeyUp(key);
+ ThreadUtils.SleepOrAbort(keyTime);
+ }
}
}
}
diff --git a/Opus/UI/Rendering/ProgramRenderer.cs b/Opus/UI/Rendering/ProgramRenderer.cs
index 4cd54bd..6e6121e 100644
--- a/Opus/UI/Rendering/ProgramRenderer.cs
+++ b/Opus/UI/Rendering/ProgramRenderer.cs
@@ -20,6 +20,9 @@ public class ProgramRenderer
private InstructionRenderer m_instructionRenderer;
private int m_renderDelay = 10;
+ private List lastCopy;
+ private bool lastRowErrored = false;
+
public ProgramRenderer(ProgramGrid grid, Program program, IEnumerable arms)
{
m_grid = grid;
@@ -62,6 +65,8 @@ private void RenderRow(int startTime, int endTime, int armIndex, List 1)
{
m_grid.EnsureCellsVisible(new Vector2(startTime, armIndex - 1), new Vector2(numToCopy, 2));
- CopyInstructionsFromPrevious(timeIndex, numToCopy, armIndex);
+ CopyInstructionsFromPrevious(timeIndex, numToCopy, armIndex, out chainCopy, copyList);
+
+ if (chainCopy > 0)
+ {
+ chainCopy = numToCopy;
+ }
timeIndex += numToCopy - 1;
}
else
{
+ lastCopy = null;
m_instructionRenderer.Render(new Vector2(timeIndex, armIndex), instructions[timeIndex], m_renderDelay);
}
}
- EnsureRowCorrect(startTime, endTime, armIndex, instructions);
+ EnsureRowCorrect(startTime, endTime, armIndex, instructions, chainCopy);
}
///
/// Finds the number of instructions that are the same between the specified arm and the
/// previous arm, starting at startTime.
///
- private int FindCopyableInstructions(int startTime, int endTime, int armIndex)
+ private int FindCopyableInstructions(int startTime, int endTime, int armIndex, out List copyList)
{
+ copyList = null;
+ int result = 0;
if (armIndex == 0)
{
- return 0;
+ return result;
}
var instructions = m_program.GetArmInstructions(m_arms[armIndex]);
@@ -119,24 +132,39 @@ private int FindCopyableInstructions(int startTime, int endTime, int armIndex)
int lastRenderable = instructions.FindLastIndex(lastSame, lastSame - startTime + 1, i => i.IsRenderable());
if (lastRenderable < 0)
{
- return 0;
+ return result;
}
else
{
- return lastRenderable - startTime + 1;
+ result = lastRenderable - startTime + 1;
+ copyList = instructions.GetRange(startTime, result);
+ return result;
}
}
- return lastSame - startTime + 1;
+ result = lastSame - startTime + 1;
+ copyList = instructions.GetRange(startTime, result);
+ return result;
}
- private void CopyInstructionsFromPrevious(int timeIndex, int width, int armIndex)
+ private void CopyInstructionsFromPrevious(int timeIndex, int width, int armIndex, out int chainCopy, List copyList = null)
{
+ chainCopy = 0;
+
// Select the instructions to copy
var sourcePos = new Vector2(timeIndex, armIndex - 1);
- var dragStart = m_grid.GetCellLocation(new Vector2(timeIndex + width - 1, armIndex));
var dragEnd = m_grid.GetCellLocation(sourcePos);
- MouseUtils.LeftDrag(dragStart, dragEnd);
+
+ if (lastCopy == null || copyList == null || !copyList.SequenceEqual(lastCopy))
+ {
+ var dragStart = m_grid.GetCellLocation(new Vector2(timeIndex + width - 1, armIndex));
+ MouseUtils.LeftDrag(dragStart, dragEnd);
+ lastCopy = copyList;
+ }
+ else
+ {
+ chainCopy = 1;
+ }
// Copy them
KeyDown(Keys.ControlKey);
@@ -148,7 +176,7 @@ private void CopyInstructionsFromPrevious(int timeIndex, int width, int armIndex
ThreadUtils.SleepOrAbort(m_renderDelay);
}
- private void EnsureRowCorrect(int startTime, int endTime, int armIndex, List instructions)
+ private void EnsureRowCorrect(int startTime, int endTime, int armIndex, List instructions, int chainCopy = 0)
{
const int maxRetries = 5;
int retryCount = 0;
@@ -157,10 +185,16 @@ private void EnsureRowCorrect(int startTime, int endTime, int armIndex, List 1)
+ {
+ // First retry did not work, increase render delay
+ m_renderDelay += 10;
+ sm_log.Info("Increasing render delay to " + m_renderDelay);
+ }
foreach (int timeIndex in errors)
{
sm_log.Info(Invariant($"Re-rendering instruction for arm {armIndex} at time {timeIndex}"));
- m_instructionRenderer.Render(new Vector2(timeIndex, armIndex), instructions[timeIndex], m_renderDelay);
+ if (chainCopy > 0)
+ {
+ m_grid.EnsureCellsVisible(new Vector2(startTime, armIndex - 1), new Vector2(chainCopy, 2));
+ CopyInstructionsFromPrevious(timeIndex, chainCopy, armIndex, out chainCopy);
+ }
+ else
+ {
+ m_instructionRenderer.Render(new Vector2(timeIndex, armIndex), instructions[timeIndex], m_renderDelay);
+ }
}
errors = FindErrors(startTime, endTime, armIndex, instructions);
}
+ if (retryCount == 0)
+ {
+ lastRowErrored = false;
+ }
}
private IEnumerable FindErrors(int startTime, int endTime, int armIndex, List instructions)
diff --git a/Opus/UI/Rendering/SolutionRenderer.cs b/Opus/UI/Rendering/SolutionRenderer.cs
index 77aae4d..df0c797 100644
--- a/Opus/UI/Rendering/SolutionRenderer.cs
+++ b/Opus/UI/Rendering/SolutionRenderer.cs
@@ -2,6 +2,7 @@
using System.Windows.Forms;
using Opus.Solution;
using static System.FormattableString;
+using System.Drawing;
namespace Opus.UI.Rendering
{
@@ -68,11 +69,15 @@ private void RenderTracks()
var objects = Solution.GetObjects