mirror of
https://github.com/fadden/6502bench.git
synced 2024-12-24 07:29:42 +00:00
More progress on visualization
Implemented Apple II hi-res bitmap conversion. Supports B&W and color. Uses essentially the same algorithm as CiderPress. Experimented with displaying non-text items in ListView. I assumed it would work, since it's the sort of thing WPF is designed to do, but it's always wise to approach with caution. Visualization Sets now show a 64x64 button as a placeholder for the eventual thumbnail. Some things were being flaky, which turned out to be because I wasn't Prepare()ing the plugins before using them from Edit Visualization. To make this a deterministic failure I added an Unprepare() call that tells the plugin that we're all done. NOTE: this breaks all existing plugins.
This commit is contained in:
parent
9244ceda7c
commit
365864ccdf
@ -39,6 +39,11 @@ namespace PluginCommon {
|
||||
/// <param name="fileData">65xx code and data.</param>
|
||||
/// <param name="addrMap">Mapping between offsets and addresses.</param>
|
||||
void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans);
|
||||
|
||||
/// <summary>
|
||||
/// Tells the plugin that we're done talking to it for now.
|
||||
/// </summary>
|
||||
void Unprepare();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -138,7 +143,8 @@ namespace PluginCommon {
|
||||
/// </summary>
|
||||
/// <param name="descr">VisGen identifier.</param>
|
||||
/// <param name="parms">Parameter set.</param>
|
||||
/// <returns>2D visualization object reference.</returns>
|
||||
/// <returns>2D visualization object reference, or null if something went
|
||||
/// wrong (unknown ident, bad parameters, etc).</returns>
|
||||
IVisualization2d Generate2d(VisDescr descr, Dictionary<string, object> parms);
|
||||
}
|
||||
|
||||
|
@ -169,6 +169,16 @@ namespace PluginCommon {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the Unprepare() method on all active plugins.
|
||||
/// </summary>
|
||||
public void UnpreparePlugins() {
|
||||
foreach (KeyValuePair<string, IPlugin> kvp in mActivePlugins) {
|
||||
IPlugin ipl = kvp.Value;
|
||||
ipl.Unprepare();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if any of the plugins report that the before or after label is
|
||||
/// significant.
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using CommonUtil;
|
||||
|
||||
namespace PluginCommon {
|
||||
@ -97,5 +97,23 @@ namespace PluginCommon {
|
||||
public static int MakeARGB(int a, int r, int g, int b) {
|
||||
return (a << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts a typed value from a dictionary with plain object values.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of value to retrieve.</typeparam>
|
||||
/// <param name="dict">Dictionary with values.</param>
|
||||
/// <param name="key">Entry to find.</param>
|
||||
/// <param name="defVal">Default value.</param>
|
||||
/// <returns>Value found, or the default if the key doesn't exist or the value has the
|
||||
/// wrong type.</returns>
|
||||
public static T GetFromObjDict<T>(Dictionary<string, object> dict, string key, T defVal) {
|
||||
if (dict.TryGetValue(key, out object objVal)) {
|
||||
if (objVal is T) {
|
||||
return (T)objVal;
|
||||
}
|
||||
}
|
||||
return defVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ namespace PluginCommon {
|
||||
}
|
||||
|
||||
public void SetPixelIndex(int x, int y, byte colorIndex) {
|
||||
if (x < 0 || x >= Width || y < 0 || y >= Width) {
|
||||
if (x < 0 || x >= Width || y < 0 || y >= Height) {
|
||||
throw new ArgumentException("Bad x/y: " + x + "," + y + " (width=" + Width +
|
||||
" height=" + Height + ")");
|
||||
}
|
||||
@ -82,7 +82,18 @@ namespace PluginCommon {
|
||||
Debug.WriteLine("Palette is full");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < mNextColor; i++) {
|
||||
if (mPalette[i] == color) {
|
||||
Debug.WriteLine("Color " + color.ToString("x6") +
|
||||
" already exists in palette (" + i + ")");
|
||||
return;
|
||||
}
|
||||
}
|
||||
mPalette[mNextColor++] = color;
|
||||
}
|
||||
|
||||
public void AddColor(byte a, byte r, byte g, byte b) {
|
||||
AddColor(Util.MakeARGB(a, r, g, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -292,6 +292,9 @@ namespace SourceGen {
|
||||
searchStart = FindFirstUnvisitedInstruction(searchStart);
|
||||
}
|
||||
|
||||
if (mScriptManager != null) {
|
||||
mScriptManager.UnprepareScripts();
|
||||
}
|
||||
mScriptSupport.Shutdown();
|
||||
|
||||
MarkUnexecutedEmbeddedCode();
|
||||
|
@ -2443,9 +2443,16 @@ namespace SourceGen {
|
||||
return bestSym;
|
||||
}
|
||||
|
||||
// Punch-through functions; trying to avoid exposing ScriptManager for now.
|
||||
public List<PluginCommon.IPlugin> GetActivePlugins() {
|
||||
return mScriptManager.GetActivePlugins();
|
||||
}
|
||||
public void PrepareScripts(PluginCommon.IApplication appRef) {
|
||||
mScriptManager.PrepareScripts(appRef);
|
||||
}
|
||||
public void UnprepareScripts() {
|
||||
mScriptManager.UnprepareScripts();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For debugging purposes, get some information about the currently loaded
|
||||
|
@ -354,6 +354,7 @@ namespace SourceGen {
|
||||
public string Operand { get; private set; }
|
||||
public string Comment { get; private set; }
|
||||
public bool IsLongComment { get; private set; }
|
||||
public bool IsVisualizationSet { get; private set; }
|
||||
public bool HasBackgroundColor { get; private set; }
|
||||
public Brush BackgroundBrush { get; private set; }
|
||||
|
||||
@ -448,6 +449,13 @@ namespace SourceGen {
|
||||
return parts;
|
||||
}
|
||||
|
||||
public static FormattedParts CreateVisualizationSet(string summary) {
|
||||
FormattedParts parts = new FormattedParts();
|
||||
parts.Comment = summary;
|
||||
parts.IsVisualizationSet = true;
|
||||
return parts;
|
||||
}
|
||||
|
||||
public static FormattedParts AddSelectionHighlight(FormattedParts orig) {
|
||||
FormattedParts newParts = Clone(orig);
|
||||
newParts.HasAddrLabelHighlight = true;
|
||||
|
@ -509,7 +509,7 @@ namespace SourceGen {
|
||||
// TODO(xyzzy)
|
||||
mProject.VisualizationSets.TryGetValue(line.FileOffset,
|
||||
out VisualizationSet visSet);
|
||||
parts = FormattedParts.CreateLongComment("!VISUALIZATION SET! " +
|
||||
parts = FormattedParts.CreateVisualizationSet("!VISUALIZATION SET! " +
|
||||
(visSet != null ? "VS:" + visSet.Count : "???"));
|
||||
break;
|
||||
case Line.Type.Blank:
|
||||
|
@ -54,7 +54,11 @@ namespace RuntimeData.Apple {
|
||||
|
||||
mAppRef.DebugLog("GSOS(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
|
||||
//System.Diagnostics.Debugger.Break();
|
||||
}
|
||||
|
||||
public void Unprepare() {
|
||||
mAppRef = null;
|
||||
mFileData = null;
|
||||
}
|
||||
|
||||
public void UpdateSymbolList(List<PlSymbol> plSyms) {
|
||||
|
@ -47,6 +47,11 @@ namespace RuntimeData.Apple {
|
||||
mAppRef.DebugLog("IIgsToolbox(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
|
||||
}
|
||||
|
||||
public void Unprepare() {
|
||||
mAppRef = null;
|
||||
mFileData = null;
|
||||
}
|
||||
|
||||
public void UpdateSymbolList(List<PlSymbol> plSyms) {
|
||||
// Extract the list of function name constants from the platform symbol file.
|
||||
mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, TOOLBOX_FUNC_TAG, mAppRef);
|
||||
|
@ -166,8 +166,14 @@ namespace RuntimeData.Apple {
|
||||
|
||||
mAppRef.DebugLog("ProDOS(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
|
||||
//System.Diagnostics.Debugger.Break();
|
||||
|
||||
}
|
||||
|
||||
public void Unprepare() {
|
||||
mAppRef = null;
|
||||
mFileData = null;
|
||||
mAddrTrans = null;
|
||||
}
|
||||
|
||||
public void UpdateSymbolList(List<PlSymbol> plSyms) {
|
||||
// Extract the list of function name constants from the platform symbol file.
|
||||
mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, P8_MLI_TAG, mAppRef);
|
||||
|
@ -51,6 +51,11 @@ namespace RuntimeData.Apple {
|
||||
//System.Diagnostics.Debugger.Break();
|
||||
}
|
||||
|
||||
public void Unprepare() {
|
||||
mAppRef = null;
|
||||
mFileData = null;
|
||||
}
|
||||
|
||||
public void UpdateSymbolList(List<PlSymbol> plSyms) {
|
||||
// Extract the list of function name constants from the platform symbol file.
|
||||
mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, SOS_MLI_TAG, mAppRef);
|
||||
|
@ -21,6 +21,7 @@ using PluginCommon;
|
||||
|
||||
namespace RuntimeData.Apple {
|
||||
public class VisHiRes : MarshalByRefObject, IPlugin, IPlugin_Visualizer {
|
||||
// IPlugin
|
||||
public string Identifier {
|
||||
get { return "Apple II Hi-Res Graphic Visualizer"; }
|
||||
}
|
||||
@ -32,49 +33,71 @@ namespace RuntimeData.Apple {
|
||||
private const string VIS_GEN_BITMAP = "apple2-hi-res-bitmap";
|
||||
private const string VIS_GEN_MULTI_MAP = "apple2-hi-res-multi-map";
|
||||
|
||||
private const string P_OFFSET = "offset";
|
||||
private const string P_BYTE_WIDTH = "byteWidth";
|
||||
private const string P_HEIGHT = "height";
|
||||
private const string P_COL_STRIDE = "colStride";
|
||||
private const string P_ROW_STRIDE = "rowStride";
|
||||
private const string P_IS_COLOR = "isColor";
|
||||
private const string P_IS_FIRST_ODD = "isFirstOdd";
|
||||
|
||||
private const string P_ITEM_BYTE_WIDTH = "itemByteWidth";
|
||||
private const string P_ITEM_HEIGHT = "itemHeight";
|
||||
private const string P_COUNT = "count";
|
||||
|
||||
private const int MAX_DIM = 4096;
|
||||
|
||||
// Visualization descriptors.
|
||||
private VisDescr[] mDescriptors = new VisDescr[] {
|
||||
new VisDescr(VIS_GEN_BITMAP, "Apple II Hi-Res Bitmap", VisDescr.VisType.Bitmap,
|
||||
new VisParamDescr[] {
|
||||
new VisParamDescr("File offset (hex)",
|
||||
"offset", typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset,
|
||||
P_OFFSET, typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset,
|
||||
0x2000),
|
||||
new VisParamDescr("Width (in bytes)",
|
||||
"byteWidth", typeof(int), 1, 40, 0, 1),
|
||||
P_BYTE_WIDTH, typeof(int), 1, 40, 0, 1),
|
||||
new VisParamDescr("Height",
|
||||
"height", typeof(int), 1, 192, 0, 1),
|
||||
P_HEIGHT, typeof(int), 1, 192, 0, 1),
|
||||
new VisParamDescr("Column stride (bytes)",
|
||||
"colStride", typeof(int), 0, 256, 0, 0),
|
||||
P_COL_STRIDE, typeof(int), 0, 256, 0, 0),
|
||||
new VisParamDescr("Row stride (bytes)",
|
||||
"rowStride", typeof(int), 0, 256, 0, 0),
|
||||
P_ROW_STRIDE, typeof(int), 0, 256, 0, 0),
|
||||
new VisParamDescr("Color",
|
||||
"color", typeof(bool), 0, 0, 0, true),
|
||||
new VisParamDescr("First byte odd",
|
||||
"firstOdd", typeof(bool), 0, 0, 0, false),
|
||||
P_IS_COLOR, typeof(bool), 0, 0, 0, true),
|
||||
new VisParamDescr("First col odd",
|
||||
P_IS_FIRST_ODD, typeof(bool), 0, 0, 0, false),
|
||||
new VisParamDescr("Test Float",
|
||||
"floaty", typeof(float), -5.0f, 5.0f, 0, 0.1f),
|
||||
}),
|
||||
new VisDescr(VIS_GEN_MULTI_MAP, "Apple II Hi-Res Multi-Map", VisDescr.VisType.Bitmap,
|
||||
new VisParamDescr[] {
|
||||
new VisParamDescr("File offset (hex)",
|
||||
"offset", typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset,
|
||||
P_OFFSET, typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset,
|
||||
0x1000),
|
||||
new VisParamDescr("Item width (in bytes)",
|
||||
"itemByteWidth", typeof(int), 1, 40, 0, 1),
|
||||
P_ITEM_BYTE_WIDTH, typeof(int), 1, 40, 0, 1),
|
||||
new VisParamDescr("Item height",
|
||||
"itemHeight", typeof(int), 1, 192, 0, 8),
|
||||
P_ITEM_HEIGHT, typeof(int), 1, 192, 0, 8),
|
||||
new VisParamDescr("Number of items",
|
||||
"count", typeof(int), 1, 256, 0, 1),
|
||||
P_COUNT, typeof(int), 1, 256, 0, 1),
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
// IPlugin
|
||||
public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
|
||||
mAppRef = appRef;
|
||||
mFileData = fileData;
|
||||
mAddrTrans = addrTrans;
|
||||
}
|
||||
|
||||
// IPlugin
|
||||
public void Unprepare() {
|
||||
mAppRef = null;
|
||||
mFileData = null;
|
||||
mAddrTrans = null;
|
||||
}
|
||||
|
||||
// IPlugin_Visualizer
|
||||
public VisDescr[] GetVisGenDescrs() {
|
||||
return mDescriptors;
|
||||
@ -83,17 +106,241 @@ namespace RuntimeData.Apple {
|
||||
// IPlugin_Visualizer
|
||||
public IVisualization2d Generate2d(VisDescr descr,
|
||||
Dictionary<string, object> parms) {
|
||||
// TODO: replace with actual
|
||||
VisBitmap8 vb = new VisBitmap8(16, 16);
|
||||
vb.AddColor(Util.MakeARGB(0xff, 0x40, 0x40, 0x40));
|
||||
vb.AddColor(Util.MakeARGB(0xff, 0xff, 0x00, 0x00));
|
||||
vb.AddColor(Util.MakeARGB(0xff, 0x00, 0xff, 0x80));
|
||||
switch (descr.Ident) {
|
||||
case VIS_GEN_BITMAP:
|
||||
return GenerateBitmap(parms);
|
||||
case VIS_GEN_MULTI_MAP:
|
||||
// TODO
|
||||
return null;
|
||||
default:
|
||||
mAppRef.DebugLog("Unknown ident " + descr.Ident);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
vb.SetPixelIndex(i, i, 1);
|
||||
vb.SetPixelIndex(15 - i, i, 2);
|
||||
private IVisualization2d GenerateBitmap(Dictionary<string, object> parms) {
|
||||
int offset, byteWidth, height, colStride, rowStride;
|
||||
bool isColor, isFirstOdd;
|
||||
|
||||
offset = Util.GetFromObjDict(parms, P_OFFSET, 0);
|
||||
byteWidth = Util.GetFromObjDict(parms, P_BYTE_WIDTH, 0); // width ignoring colStride
|
||||
height = Util.GetFromObjDict(parms, P_HEIGHT, 0);
|
||||
colStride = Util.GetFromObjDict(parms, P_COL_STRIDE, 0);
|
||||
rowStride = Util.GetFromObjDict(parms, P_ROW_STRIDE, 0);
|
||||
isColor = Util.GetFromObjDict(parms, P_IS_COLOR, true);
|
||||
isFirstOdd = Util.GetFromObjDict(parms, P_IS_FIRST_ODD, false);
|
||||
|
||||
// We allow the stride entries to be zero to indicate a "dense" bitmap.
|
||||
if (colStride == 0) {
|
||||
colStride = 1;
|
||||
}
|
||||
if (rowStride == 0) {
|
||||
rowStride = byteWidth * colStride;
|
||||
}
|
||||
|
||||
if (offset < 0 || offset >= mFileData.Length ||
|
||||
byteWidth <= 0 || byteWidth > MAX_DIM ||
|
||||
height <= 0 || height > MAX_DIM ||
|
||||
colStride <= 0 || colStride > MAX_DIM ||
|
||||
rowStride < byteWidth * colStride - (colStride-1) || rowStride > MAX_DIM) {
|
||||
mAppRef.DebugLog("Invalid parameter");
|
||||
return null;
|
||||
}
|
||||
|
||||
int lastOffset = offset + rowStride * height - (colStride - 1) - 1;
|
||||
if (lastOffset >= mFileData.Length) {
|
||||
mAppRef.DebugLog("Bitmap runs off end of file (lastOffset=" + lastOffset + ")");
|
||||
return null;
|
||||
}
|
||||
|
||||
VisBitmap8 vb = new VisBitmap8(byteWidth * 7, height);
|
||||
SetHiResPalette(vb);
|
||||
|
||||
if (!isColor) {
|
||||
// B&W mode. Since we're not displaying this we don't need to worry about
|
||||
// half-pixel shifts, and can just convert 7 bits to pixels.
|
||||
int bx = 0;
|
||||
int by = 0;
|
||||
for (int row = 0; row < height; row++) {
|
||||
int colIdx = 0;
|
||||
for (int col = 0; col < byteWidth; col++) {
|
||||
byte val = mFileData[offset + colIdx];
|
||||
for (int bit = 0; bit < 7; bit++) {
|
||||
vb.SetPixelIndex(bx, by, (byte)((val & 0x01) + 1)); // black or white
|
||||
val >>= 1;
|
||||
bx++;
|
||||
}
|
||||
colIdx += colStride;
|
||||
}
|
||||
bx = 0;
|
||||
by++;
|
||||
offset += rowStride;
|
||||
}
|
||||
} else {
|
||||
int bx = 0;
|
||||
int by = 0;
|
||||
|
||||
#if false
|
||||
// Color mode. We treat the data as a strictly 140-mode bitmap, which doesn't
|
||||
// quite match up with how the pixels will be displayed, but does allow a
|
||||
// straightforward conversion between file formats. Color fringing is severe.
|
||||
for (int row = 0; row < height; row++) {
|
||||
int lastBit;
|
||||
if (isFirstOdd) {
|
||||
lastBit = 0; // pretend we already have one bit
|
||||
} else {
|
||||
lastBit = -1;
|
||||
}
|
||||
|
||||
for (int colByte = 0; colByte < byteWidth; colByte += colStride) {
|
||||
byte val = mFileData[offset + colByte];
|
||||
bool hiBitSet = (val & 0x80) != 0;
|
||||
|
||||
// Grab 3 or 4 pairs of bits.
|
||||
int pairCount = (lastBit < 0) ? 3 : 4;
|
||||
while (pairCount-- > 0) {
|
||||
int twoBits;
|
||||
if (lastBit >= 0) {
|
||||
// merge with bit from previous byte
|
||||
twoBits = (lastBit << 1) | (val & 0x01);
|
||||
val >>= 1;
|
||||
lastBit = -1;
|
||||
} else {
|
||||
// grab two bits
|
||||
twoBits = (val & 0x03);
|
||||
val >>= 2;
|
||||
}
|
||||
|
||||
if (hiBitSet) {
|
||||
twoBits += 4;
|
||||
}
|
||||
|
||||
// We're in 140 mode, so set two adjacent pixels.
|
||||
vb.SetPixelIndex(bx++, by, sHiResColorMap[twoBits]);
|
||||
vb.SetPixelIndex(bx++, by, sHiResColorMap[twoBits]);
|
||||
}
|
||||
|
||||
bool thisEven = ((colByte & 0x01) == 0) ^ isFirstOdd;
|
||||
if (thisEven) {
|
||||
// started in even column we have one bit left over
|
||||
lastBit = val & 0x01;
|
||||
} else {
|
||||
// started in odd column, all bits consumed
|
||||
lastBit = -1;
|
||||
}
|
||||
}
|
||||
bx = 0;
|
||||
by++;
|
||||
offset += rowStride;
|
||||
}
|
||||
#else
|
||||
// Color conversion similar to what CiderPress does, but without the half-pixel
|
||||
// shift (we're trying to create a 1:1 bitmap).
|
||||
bool[] lineBits = new bool[byteWidth * 7];
|
||||
bool[] hiFlags = new bool[byteWidth * 7]; // overkill, but simplifies things
|
||||
int[] colorBuf = new int[byteWidth * 7];
|
||||
for (int row = 0; row < height; row++) {
|
||||
// Unravel the bits.
|
||||
int idx = 0;
|
||||
int colIdx = 0;
|
||||
for (int col = 0; col < byteWidth; col++) {
|
||||
byte val = mFileData[offset + colIdx];
|
||||
bool hiBitSet = (val & 0x80) != 0;
|
||||
|
||||
for (int bit = 0; bit < 7; bit++) {
|
||||
hiFlags[idx] = hiBitSet;
|
||||
lineBits[idx] = (val & 0x01) != 0;
|
||||
idx++;
|
||||
val >>= 1;
|
||||
}
|
||||
colIdx += colStride;
|
||||
}
|
||||
|
||||
// Convert to color.
|
||||
int lastBit = byteWidth * 7;
|
||||
for (idx = 0; idx < lastBit; idx++) {
|
||||
int colorShift = hiFlags[idx] ? 4 : 0;
|
||||
if (!lineBits[idx]) {
|
||||
// Bit not set, set pixel to black.
|
||||
colorBuf[idx] = (int)HiResColors.Black0 + colorShift;
|
||||
} else {
|
||||
// Bit set, set pixel to white or color.
|
||||
if (idx > 0 && colorBuf[idx - 1] != (int)HiResColors.Black0 &&
|
||||
colorBuf[idx - 1] != (int)HiResColors.Black1) {
|
||||
// previous bit was also set, this is white
|
||||
colorBuf[idx] = (int)HiResColors.White0 + colorShift;
|
||||
|
||||
// the previous pixel is part of a run of white
|
||||
colorBuf[idx - 1] = (int)HiResColors.White0 + colorShift;
|
||||
} else {
|
||||
// previous bit not set *or* was first pixel in line;
|
||||
// set color based on whether this is even or odd pixel col
|
||||
bool isOdd = ((idx & 0x01) != 0) ^ isFirstOdd;
|
||||
if (isOdd) {
|
||||
colorBuf[idx] = (int)HiResColors.Green + colorShift;
|
||||
} else {
|
||||
colorBuf[idx] = (int)HiResColors.Purple + colorShift;
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have a run of the same color? If so, smooth the color out.
|
||||
// Note that white blends smoothly with everything.
|
||||
if (idx > 1 && (colorBuf[idx - 2] == colorBuf[idx] ||
|
||||
colorBuf[idx - 2] == (int)HiResColors.White0 ||
|
||||
colorBuf[idx - 2] == (int)HiResColors.White1)) {
|
||||
|
||||
//if (colorBuf[idx - 1] != (int)HiResColors.Black0 &&
|
||||
// colorBuf[idx - 1] != (int) HiResColors.Black1) {
|
||||
// mAppRef.DebugLog("Unexpected color at row=" + by +
|
||||
// " idx=" + idx + ": " + colorBuf[idx - 1]);
|
||||
//}
|
||||
|
||||
colorBuf[idx - 1] = colorBuf[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write to bitmap.
|
||||
for (idx = 0; idx < lastBit; idx++) {
|
||||
vb.SetPixelIndex(bx++, by, sHiResColorMap[colorBuf[idx]]);
|
||||
}
|
||||
|
||||
// move to next row
|
||||
bx = 0;
|
||||
by++;
|
||||
offset += rowStride;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return vb;
|
||||
}
|
||||
|
||||
private enum HiResColors {
|
||||
Black0 = 0,
|
||||
Green = 1,
|
||||
Purple = 2,
|
||||
White0 = 3,
|
||||
Black1 = 4,
|
||||
Orange = 5,
|
||||
Blue = 6,
|
||||
White1 = 7
|
||||
}
|
||||
|
||||
// HiRes: black0, green, purple, white0, black1, orange, blue, white1
|
||||
private static readonly byte[] sHiResColorMap = new byte[8] {
|
||||
1, 3, 4, 2, 1, 5, 6, 2
|
||||
};
|
||||
|
||||
private void SetHiResPalette(VisBitmap8 vb) {
|
||||
// These don't match directly to hi-res color numbers because we want to
|
||||
// avoid adding black/white twice.
|
||||
vb.AddColor(0xff, 0xff, 0, 0); // 0=transparent (xyzzy: all 0)
|
||||
vb.AddColor(0xff, 0x00, 0x00, 0x00); // 1=black0/black1
|
||||
vb.AddColor(0xff, 0xff, 0xff, 0xff); // 2=white0/white1
|
||||
vb.AddColor(0xff, 0x11, 0xdd, 0x00); // 3=green
|
||||
vb.AddColor(0xff, 0xdd, 0x22, 0xdd); // 4=purple
|
||||
vb.AddColor(0xff, 0xff, 0x66, 0x00); // 5=orange
|
||||
vb.AddColor(0xff, 0x22, 0x22, 0xff); // 6=blue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,11 @@ namespace RuntimeData.Test2011 {
|
||||
mAppRef.DebugLog("Test2011(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
|
||||
}
|
||||
|
||||
public void Unprepare() {
|
||||
mAppRef = null;
|
||||
mFileData = null;
|
||||
}
|
||||
|
||||
public void CheckJsr(int offset, int operand, out bool noContinue) {
|
||||
int ADDR = 0x2456;
|
||||
|
||||
|
@ -31,6 +31,12 @@ namespace RuntimeData.Test2022 {
|
||||
|
||||
mAppRef.DebugLog("Test2022-A(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
|
||||
}
|
||||
|
||||
public void Unprepare() {
|
||||
mAppRef = null;
|
||||
mFileData = null;
|
||||
}
|
||||
|
||||
public void UpdateSymbolList(List<PlSymbol> plSyms) {
|
||||
foreach (PlSymbol sym in plSyms) {
|
||||
switch (sym.Label) {
|
||||
|
@ -26,6 +26,12 @@ namespace RuntimeData.Test2022 {
|
||||
mAppRef.DebugLog("Test2022-B(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
|
||||
}
|
||||
|
||||
public void Unprepare() {
|
||||
mAppRef = null;
|
||||
mFileData = null;
|
||||
mAddrTrans = null;
|
||||
}
|
||||
|
||||
public void CheckBrk(int offset, bool twoByteBrk, out bool noContinue) {
|
||||
noContinue = true;
|
||||
|
||||
|
@ -173,6 +173,22 @@ namespace SourceGen.Sandbox {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts scripts back to sleep.
|
||||
/// </summary>
|
||||
public void UnprepareScripts() {
|
||||
if (DomainMgr == null) {
|
||||
foreach (KeyValuePair<string, IPlugin> kvp in mActivePlugins) {
|
||||
IPlugin ipl = kvp.Value;
|
||||
ipl.Unprepare();
|
||||
}
|
||||
} else {
|
||||
List<AddressMap.AddressMapEntry> addrEnts = mProject.AddrMap.GetEntryList();
|
||||
DomainMgr.PluginMgr.UnpreparePlugins();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if any of the plugins report that the before or after label is
|
||||
/// significant.
|
||||
|
@ -38,15 +38,15 @@ namespace SourceGen {
|
||||
/// </summary>
|
||||
public Dictionary<string, object> VisGenParams { get; private set; }
|
||||
|
||||
public double Thumbnail { get; } // TODO - 64x64(?) bitmap
|
||||
private BitmapSource Thumbnail { get; set; } // TODO - 64x64(?) bitmap
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="tag"></param>
|
||||
/// <param name="visGenIdent"></param>
|
||||
/// <param name="visGenParams"></param>
|
||||
/// <param name="tag">Unique identifier.</param>
|
||||
/// <param name="visGenIdent">Visualization generator identifier.</param>
|
||||
/// <param name="visGenParams">Parameters for visualization generator.</param>
|
||||
public Visualization(string tag, string visGenIdent,
|
||||
Dictionary<string, object> visGenParams) {
|
||||
Tag = tag;
|
||||
@ -54,7 +54,12 @@ namespace SourceGen {
|
||||
VisGenParams = visGenParams;
|
||||
}
|
||||
|
||||
public static BitmapSource CreateBitmapSource(IVisualization2d vis2d) {
|
||||
/// <summary>
|
||||
/// Converts an IVisualization2d to a BitmapSource for display.
|
||||
/// </summary>
|
||||
/// <param name="vis2d"></param>
|
||||
/// <returns></returns>
|
||||
public static BitmapSource ConvertToBitmapSource(IVisualization2d vis2d) {
|
||||
// Create indexed color palette.
|
||||
int[] intPal = vis2d.GetPalette();
|
||||
List<Color> colors = new List<Color>(intPal.Length);
|
||||
|
@ -76,6 +76,38 @@ See also https://github.com/fadden/DisasmUiTest
|
||||
Width="{Binding LongCommentWidth}"/>
|
||||
</GridViewColumnCollection>
|
||||
|
||||
<GridViewColumnCollection x:Key="gvcc_vs">
|
||||
<GridViewColumn DisplayMemberBinding="{Binding Offset}" Width="{Binding
|
||||
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}
|
||||
}, Path=View.Columns[0].ActualWidth}"/>
|
||||
<GridViewColumn DisplayMemberBinding="{Binding Addr}" Width="{Binding
|
||||
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}
|
||||
}, Path=View.Columns[1].ActualWidth}"/>
|
||||
<GridViewColumn DisplayMemberBinding="{Binding Bytes}" Width="{Binding
|
||||
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}
|
||||
}, Path=View.Columns[2].ActualWidth}"/>
|
||||
<GridViewColumn DisplayMemberBinding="{Binding Flags}" Width="{Binding
|
||||
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}
|
||||
}, Path=View.Columns[3].ActualWidth}"/>
|
||||
<GridViewColumn DisplayMemberBinding="{Binding Attr}" Width="{Binding
|
||||
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}
|
||||
}, Path=View.Columns[4].ActualWidth}"/>
|
||||
<!-- This column holds the long comment. There's no easy way to set its width, so we
|
||||
have to let the main window take care of that. (It's tempting to just make its width
|
||||
very large, but that causes the GridView contents to horizontally scroll independently
|
||||
of the GridView header when you reach the edge of the "normal" column set.) -->
|
||||
<GridViewColumn Header="(visualization set)" Width="{Binding LongCommentWidth}">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Path=Comment}" VerticalAlignment="Center"/>
|
||||
<Button Width="64" Height="64" Content="Whee"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
</GridViewColumnCollection>
|
||||
|
||||
<!-- Base template for ListView items, derived from the system default. We have to define
|
||||
this fully so things don't turn into a big mess on long-comment lines. -->
|
||||
<ControlTemplate x:Key="baseListItemTemplate" TargetType="{x:Type ListViewItem}">
|
||||
@ -199,6 +231,68 @@ See also https://github.com/fadden/DisasmUiTest
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
<!-- yet another copy of the template, this one for VisualizationSet lines -->
|
||||
<ControlTemplate x:Key="visualizationSetTemplate" TargetType="{x:Type ListViewItem}">
|
||||
<StackPanel>
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="2"
|
||||
SnapsToDevicePixels="true">
|
||||
<Border x:Name="InnerBorder" BorderThickness="1" CornerRadius="1">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition MaxHeight="11"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Rectangle x:Name="UpperHighlight" Fill="#75ffffff" Visibility="Collapsed"/>
|
||||
<GridViewRowPresenter Content="{TemplateBinding Content}"
|
||||
Columns="{StaticResource gvcc_vs}"
|
||||
Grid.RowSpan="2"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<!-- triggers for hover, selection, and activation effects -->
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Background" Value="{StaticResource ListItemHoverFill}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource Brush_MouseOverBorder}"/>
|
||||
<Setter Property="Visibility" TargetName="UpperHighlight" Value="Visible"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="true">
|
||||
<Setter Property="Background" Value="{StaticResource ListItemSelectedFill}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource Brush_SelectedBorder}"/>
|
||||
<Setter Property="BorderBrush" TargetName="InnerBorder" Value="#80FFFFFF"/>
|
||||
<Setter Property="Visibility" TargetName="UpperHighlight" Value="Visible"/>
|
||||
<Setter Property="Fill" TargetName="UpperHighlight" Value="#40FFFFFF"/>
|
||||
</Trigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsSelected" Value="true"/>
|
||||
<Condition Property="Selector.IsSelectionActive" Value="false"/>
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter Property="Background" Value="{StaticResource ListItemSelectedInactiveFill}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource Brush_SelectedActiveBorder}"/>
|
||||
</MultiTrigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsSelected" Value="true"/>
|
||||
<Condition Property="IsMouseOver" Value="true"/>
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter Property="Background" Value="{StaticResource ListItemSelectedHoverFill}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource Brush_SelectedMouseOverBorder}"/>
|
||||
</MultiTrigger>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
|
||||
<!-- ListView style. We have to override the general foreground/background colors to
|
||||
avoid making the whole thing look freakish. -->
|
||||
<Style x:Key="codeListStyle" TargetType="{x:Type ListView}">
|
||||
@ -225,6 +319,9 @@ See also https://github.com/fadden/DisasmUiTest
|
||||
<DataTrigger Binding="{Binding Path=IsLongComment}" Value="True">
|
||||
<Setter Property="Template" Value="{StaticResource longCommentTemplate}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=IsVisualizationSet}" Value="True">
|
||||
<Setter Property="Template" Value="{StaticResource visualizationSetTemplate}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=HasBackgroundColor}" Value="True">
|
||||
<Setter Property="Background" Value="{Binding Path=BackgroundBrush}"/>
|
||||
</DataTrigger>
|
||||
|
@ -25,7 +25,8 @@ limitations under the License.
|
||||
Title="Edit Visualization"
|
||||
Width="460" SizeToContent="Height" ResizeMode="NoResize"
|
||||
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
|
||||
Loaded="Window_Loaded">
|
||||
Loaded="Window_Loaded"
|
||||
Closed="Window_Closed">
|
||||
|
||||
<Window.Resources>
|
||||
<!-- big thanks: http://drwpf.com/blog/2008/01/03/itemscontrol-d-is-for-datatemplate/ -->
|
||||
@ -125,7 +126,8 @@ limitations under the License.
|
||||
</Grid>
|
||||
|
||||
<Border Grid.Row="1" BorderThickness="1"
|
||||
BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}">
|
||||
BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}"
|
||||
Background="LightGray">
|
||||
<Image Name="previewImage" Width="400" Height="400" Source="/Res/AboutImage.png"
|
||||
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
|
||||
</Border>
|
||||
|
@ -100,6 +100,21 @@ namespace SourceGen.WpfGui {
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
private class ScriptSupport : MarshalByRefObject, PluginCommon.IApplication {
|
||||
public ScriptSupport() { }
|
||||
public void DebugLog(string msg) {
|
||||
Debug.WriteLine("Vis plugin: " + msg);
|
||||
}
|
||||
public bool SetOperandFormat(int offset, DataSubType subType, string label) {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
public bool SetInlineDataFormat(int offset, int length, DataType type,
|
||||
DataSubType subType, string label) {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
private ScriptSupport mScriptSupport = new ScriptSupport();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
@ -140,6 +155,7 @@ namespace SourceGen.WpfGui {
|
||||
|
||||
// Set the selection. This should cause the sel change event to fire.
|
||||
visComboBox.SelectedIndex = visSelection;
|
||||
mProject.PrepareScripts(mScriptSupport);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -188,6 +204,10 @@ namespace SourceGen.WpfGui {
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e) {
|
||||
}
|
||||
|
||||
private void Window_Closed(object sender, EventArgs e) {
|
||||
mProject.UnprepareScripts();
|
||||
}
|
||||
|
||||
private void OkButton_Click(object sender, RoutedEventArgs e) {
|
||||
VisualizationItem item = (VisualizationItem)visComboBox.SelectedItem;
|
||||
Debug.Assert(item != null);
|
||||
@ -305,12 +325,27 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
|
||||
if (!IsValid) {
|
||||
// TODO(xyzzy): default to a meaningful image
|
||||
previewImage.Source = new BitmapImage(new Uri("pack://application:,,,/Res/Logo.png"));
|
||||
} else {
|
||||
VisualizationItem item = (VisualizationItem)visComboBox.SelectedItem;
|
||||
IVisualization2d vis2d = item.Plugin.Generate2d(item.VisDescriptor,
|
||||
IVisualization2d vis2d;
|
||||
try {
|
||||
vis2d = item.Plugin.Generate2d(item.VisDescriptor,
|
||||
CreateVisGenParams());
|
||||
previewImage.Source = Visualization.CreateBitmapSource(vis2d);
|
||||
if (vis2d == null) {
|
||||
Debug.WriteLine("Vis generator returned null");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// TODO(xyzzy): use different image for failure
|
||||
Debug.WriteLine("Vis generation failed: " + ex.Message);
|
||||
vis2d = null;
|
||||
}
|
||||
if (vis2d == null) {
|
||||
previewImage.Source = new BitmapImage(new Uri("pack://application:,,,/Res/Logo.png"));
|
||||
} else {
|
||||
previewImage.Source = Visualization.ConvertToBitmapSource(vis2d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,8 +98,9 @@ namespace SourceGen.WpfGui {
|
||||
|
||||
private void EditButton_Click(object sender, RoutedEventArgs e) {
|
||||
Dictionary<string, object> testDict = new Dictionary<string, object>();
|
||||
testDict.Add("offset", 0x1234);
|
||||
testDict.Add("height", 57);
|
||||
testDict.Add("offset", 0);
|
||||
testDict.Add("byteWidth", 2);
|
||||
testDict.Add("height", 7);
|
||||
EditVisualization dlg = new EditVisualization(this, mProject, mFormatter,
|
||||
new Visualization("arbitrary tag", "apple2-hi-res-bitmap", testDict));
|
||||
if (dlg.ShowDialog() == true) {
|
||||
|
Loading…
Reference in New Issue
Block a user