using System; using System.Collections.Generic; namespace Dashboard.CommandMachine { public class CommandEngine { private int _zIndex = 0; private readonly Stack _zStack = new Stack(); public int ZIndex => _zIndex; private QRectangle _viewport; private readonly Stack _viewportStack = new Stack(); private readonly Stack _matrixStack = new Stack(); private Command _customCommandBase = Command.CustomCommandBase; private readonly List _customCommands = new List(); public QRectangle Viewport => _viewport; public QMat4 ActiveTransforms { get; } public StyleStack Style { get; } = new StyleStack(new Style()); protected CommandEngine() { Reset(); } public Command RegisterCustomCommand(QuikCommandHandler handler) { Command id = _customCommandBase++; _customCommands.Insert(id - Command.CustomCommandBase, handler); return id; } public void ProcessCommands(QRectangle bounds, CommandList queue) { CommandQueue iterator = queue.GetEnumerator(); if (!iterator.Peek().IsCommand) throw new ArgumentException("The first element in the iterator must be a command frame."); Reset(); _viewport = bounds; _viewportStack.Push(_viewport); Frame frame; while (iterator.TryDequeue(out frame)) { Command cmd = (Command)frame; switch (cmd) { default: if (cmd > Command.CustomCommandBase) { _customCommands[cmd - Command.CustomCommandBase].Invoke(this, iterator); } else { ChildProcessCommand(cmd, iterator); } break; case Command.ConditionalBegin: ConditionalHandler(iterator); break; case Command.ConditionalEnd: /* nop */ break; case Command.Invoke: iterator.Dequeue().As().Invoke(this, iterator); break; case Command.PushViewport: _viewportStack.Push(_viewport); break; case Command.IntersectViewport: _viewport = QRectangle.Intersect((QRectangle)iterator.Dequeue(), _viewport); break; case Command.StoreViewport: _viewport = (QRectangle)iterator.Dequeue(); break; case Command.PopViewport: _viewport = _viewportStack.TryPop(out QRectangle viewport) ? viewport : bounds; break; case Command.PushZ: _zStack.Push(_zIndex); break; case Command.IncrementZ: _zIndex++; break; case Command.AddZ: _zIndex += (int)iterator.Dequeue(); break; case Command.StoreZ: _zIndex = (int)iterator.Dequeue(); break; case Command.DecrementZ: _zIndex--; break; case Command.PopZ: _zIndex = _zStack.TryPop(out int zindex) ? zindex : 0; break; case Command.PushStyle: Style.Push(iterator.Dequeue().As