From 32ed34c9310c447051fc4f240ce8241235450b01 Mon Sep 17 00:00:00 2001 From: jr-k Date: Thu, 22 Jun 2023 18:52:59 +0200 Subject: [PATCH 1/7] add color feature + byte range in tooltip, png as example --- .gitignore | 2 + src/core/color.tsx | 97 +++++++++++++++++++++++++++++++++++++++ src/core/range.ts | 12 +++++ src/core/tree.tsx | 12 ++++- src/inspectors/png.tsx | 13 +++--- src/ui/binaryview.tsx | 51 ++++++++++++++------ src/ui/treebinaryview.tsx | 4 +- src/ui/treeview.tsx | 24 ++++++++-- 8 files changed, 190 insertions(+), 25 deletions(-) create mode 100644 src/core/color.tsx diff --git a/.gitignore b/.gitignore index 0f44920..2b28f19 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ +.idea/ .cache dist node_modules .DS_Store +yarn.lock diff --git a/src/core/color.tsx b/src/core/color.tsx new file mode 100644 index 0000000..1d901ba --- /dev/null +++ b/src/core/color.tsx @@ -0,0 +1,97 @@ +export class Color { + hex: string; + + constructor( + hex: string + ) { + if (hex.length === 3) { + hex = hex + hex; + } + + this.hex = hex; + } + + lightenColor(color: string, percentage: number): string { + let r = Math.round(Math.min(255, parseInt(color.substring(1, 3), 16) * (1 + percentage))).toString(16); + let g = Math.round(Math.min(255, parseInt(color.substring(3, 5), 16) * (1 + percentage))).toString(16); + let b = Math.round(Math.min(255, parseInt(color.substring(5, 7), 16) * (1 + percentage))).toString(16); + return "#" + (r.length<2 ? "0" + r : r) + (g.length<2 ? "0" + g : g) + (b.length<2 ? "0" + b : b); + } + + hexAlpha(alpha: number): string { + alpha = parseInt((alpha * 255).toFixed(0)); + + if (alpha <= 0) { + alpha = 0; + } else if (alpha >= 255) { + alpha = 255; + } + + return this.hex + alpha.toString(16); + } + + hexLighter(): string { + return this.hexAlpha(.7); + } + + static default(): Color { + return new Color('#dedede'); + } + + static white(): Color { + return new Color('#ffffff'); + } + + static pink(): Color { + return new Color('#ffbefa'); + } + + static purple(): Color { + return new Color('#e2beff'); + } + + static brown(): Color { + return new Color('#c9a15f'); + } + + static red(): Color { + return new Color('#ffbebe'); + } + + static green(): Color { + return new Color('#c8ffc8'); + } + + static blue(): Color { + return new Color('#b6b6ff'); + } + + static cyan(): Color { + return new Color('#beffff'); + } + + static yellow(): Color { + return new Color('#ffffa1'); + } + + static magenta(): Color { + return new Color('#ffa6ff'); + } + + static orange(): Color { + return new Color('#ffcb99'); + } + + static black(): Color { + return new Color('#868686'); + } + + equals(color: Color): boolean { + return this.hex === color.hex; + } + + isDefault(): boolean { + return this.equals(Color.default()); + } + +} diff --git a/src/core/range.ts b/src/core/range.ts index 9724666..45b0169 100644 --- a/src/core/range.ts +++ b/src/core/range.ts @@ -15,6 +15,10 @@ export class ByteRange { this.byteLength = byteLength; } + offset(): number { + return this.byteStart; + } + size(): number { return this.byteLength; } @@ -153,6 +157,14 @@ export class BitRange { this.bitLength = bitLength; } + offset(): number { + return this.bitStart; + } + + size(): number { + return this.bitLength; + } + enclosingByteRange(): ByteRange { let byteStart = Math.floor(this.bitStart / 8); let byteEnd = Math.floor((this.bitStart + this.bitLength - 1) / 8) + 1; diff --git a/src/core/tree.tsx b/src/core/tree.tsx index 7a686c9..46daf65 100644 --- a/src/core/tree.tsx +++ b/src/core/tree.tsx @@ -1,10 +1,12 @@ import { ByteRange, BitRange } from "./range"; +import { Color } from "./color"; export class Tree { label: string; range: ByteRange | BitRange; children: Array; error?: Error; + color: Color; parent?: Tree; @@ -12,12 +14,14 @@ export class Tree { label: string, range: ByteRange | BitRange, children: Array = [], - error?: Error + error?: Error, + color?: Color ) { this.label = label; this.range = range; this.children = children; this.error = error; + this.color = color || Color.default(); // Set parent pointers for the children tree objects. for (let child of this.children) { @@ -38,4 +42,10 @@ export class Tree { isParentOf(other: Tree): boolean { return other.isChildOf(this); } + + withColor(color: Color): Tree { + this.color = color; + + return this; + } } diff --git a/src/inspectors/png.tsx b/src/inspectors/png.tsx index 95a1b36..26d91de 100644 --- a/src/inspectors/png.tsx +++ b/src/inspectors/png.tsx @@ -6,6 +6,7 @@ import { assert } from "chai"; import { ByteRange, BitRange } from "../core/range"; import { SimpleInspector } from "../ui/simpleinspector"; import { Tree } from "../core/tree"; +import { Color } from "../core/color"; import { hexEllipsis } from "../core/utils"; @@ -91,20 +92,20 @@ function inspect(range: ByteRange): Tree { `Chunk (${type.readUTF8()})`, ptr.bytes(0, chunkSize), [ - new Tree(`Length: ${byteLen}`, length), - new Tree(`Type: ${type.readUTF8()}`, type) + new Tree(`Length: ${byteLen}`, length).withColor(Color.blue()), + new Tree(`Type: ${type.readUTF8()}`, type).withColor(Color.orange()) ] .concat(chunkElements) - .concat([new Tree(`CRC: ${crc.readUIntBE()}`, crc)]) - ) + .concat([new Tree(`CRC: ${crc.readUIntBE()}`, crc).withColor(Color.brown())]) + ).withColor(Color.green()) ); ptr = ptr.bytes(chunkSize); } return new Tree("PNG Image", range, [ - new Tree(`Signature: ${signature.toHex()}`, signature), - new Tree(`Chunks (${chunks.length})`, range.bytes(8), chunks) + new Tree(`Signature: ${signature.toHex()}`, signature).withColor(Color.red()), + new Tree(`Chunks (${chunks.length})`, range.bytes(8), chunks).withColor(Color.magenta()) ]); } diff --git a/src/ui/binaryview.tsx b/src/ui/binaryview.tsx index a69e485..26071c8 100644 --- a/src/ui/binaryview.tsx +++ b/src/ui/binaryview.tsx @@ -2,6 +2,8 @@ import * as React from "react"; import { Col, Form, Row } from "react-bootstrap"; import { ByteRange, BitRange } from "../core/range"; +import { Color } from "../core/color"; +import { Tree } from "../core/tree"; const HEX_BYTES_PER_ROW = 16; const HEX_BYTES_PER_GROUP = 8; @@ -11,12 +13,10 @@ const BINARY_BYTES_PER_GROUP = 4; const DEFAULT_MAX_ROWS = 1000; -const SELECTED_COLOR = "#dedede"; - type Format = "hex" | "binary"; export class BinaryView extends React.Component< - { data: ByteRange; selected?: ByteRange | BitRange; maxRows: number }, + { data: ByteRange; selected?: ByteRange | BitRange; maxRows: number; tree: Tree }, { format: Format } > { static defaultProps = { @@ -83,6 +83,24 @@ export class BinaryView extends React.Component< } } + byteColor(tree: Tree, byteNumber: number, color?: Color) { + for (const t of tree.children) { + if (t.range.offset() <= byteNumber && byteNumber <= (t.range.offset() + t.range.size())) { + if (!t.color.isDefault()) { + color = t.color; + } + + const deepColor = this.byteColor(t, byteNumber, color); + + if (deepColor !== undefined) { + color = deepColor; + } + } + } + + return color; + } + renderHex() { let data = this.props.data; @@ -153,11 +171,12 @@ export class BinaryView extends React.Component< ))} + - {data.chunks(HEX_BYTES_PER_ROW).map((row, i) => ( -
- {row.chunks(HEX_BYTES_PER_GROUP).map((group, i) => ( - + {data.chunks(HEX_BYTES_PER_ROW).map((row, k) => ( +
+ {row.chunks(HEX_BYTES_PER_GROUP).map((group, j) => ( + {group.chunks(1).map((byte, i) => { let selected = false; if (this.props.selected) { @@ -170,11 +189,15 @@ export class BinaryView extends React.Component< } } + const byteNumber = i + (j * 8) + (k * 16); + const color = this.byteColor(this.props.tree, byteNumber, undefined) || this.props.tree.color; + return ( @@ -206,8 +229,7 @@ export class BinaryView extends React.Component<
{row.chunks(BINARY_BYTES_PER_GROUP).map((group, i) => ( - {group.chunks(1).map((byte, i) => { - return ( + {group.chunks(1).map((byte, i) => ( @@ -242,8 +268,7 @@ export class BinaryView extends React.Component< ); })} - ); - })} + ))} ))}
diff --git a/src/ui/treebinaryview.tsx b/src/ui/treebinaryview.tsx index 49004f8..9e0827e 100644 --- a/src/ui/treebinaryview.tsx +++ b/src/ui/treebinaryview.tsx @@ -16,8 +16,8 @@ export class TreeBinaryView extends React.Component< super(props); this.state = {}; } - render() { + return ( <> @@ -34,7 +34,9 @@ export class TreeBinaryView extends React.Component<
+ 0) { @@ -83,7 +97,9 @@ export class TreeView extends React.Component< icon={this.state.open ? faCaretDown : faCaretRight} />
- {tree.label} + + {tree.label} +
{this.state.open && @@ -101,7 +117,7 @@ export class TreeView extends React.Component< ); } else { return ( -
Date: Thu, 22 Jun 2023 18:58:45 +0200 Subject: [PATCH 2/7] add Color class to custom --- src/inspectors/custom.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/inspectors/custom.tsx b/src/inspectors/custom.tsx index 676838b..221037e 100644 --- a/src/inspectors/custom.tsx +++ b/src/inspectors/custom.tsx @@ -1,5 +1,6 @@ import { ByteRange, BitRange } from "../core/range"; import { Tree } from "../core/tree"; +import { Color } from "../core/color"; import { assert } from "chai"; import * as React from "react"; @@ -93,6 +94,7 @@ Object.assign(window, { Tree: Tree, ByteRange: ByteRange, BitRange: BitRange, + Color: Color, opus: require("../decoders/opus"), rtp: require("../decoders/rtp") }); From db136c9e965074396b12719bace63cb85887e5b9 Mon Sep 17 00:00:00 2001 From: jr-k Date: Thu, 22 Jun 2023 19:03:11 +0200 Subject: [PATCH 3/7] fix custom empty tree edge case --- src/ui/binaryview.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ui/binaryview.tsx b/src/ui/binaryview.tsx index 26071c8..7a332ea 100644 --- a/src/ui/binaryview.tsx +++ b/src/ui/binaryview.tsx @@ -84,6 +84,10 @@ export class BinaryView extends React.Component< } byteColor(tree: Tree, byteNumber: number, color?: Color) { + if (tree === undefined) { + return Color.default(); + } + for (const t of tree.children) { if (t.range.offset() <= byteNumber && byteNumber <= (t.range.offset() + t.range.size())) { if (!t.color.isDefault()) { From b1eec12f4e4561404c8f1c45f145e3202e7b3625 Mon Sep 17 00:00:00 2001 From: jr-k Date: Thu, 22 Jun 2023 19:04:21 +0200 Subject: [PATCH 4/7] add color example in custom sample --- src/inspectors/custom.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/inspectors/custom.tsx b/src/inspectors/custom.tsx index 221037e..e92da37 100644 --- a/src/inspectors/custom.tsx +++ b/src/inspectors/custom.tsx @@ -100,7 +100,7 @@ Object.assign(window, { }); const DEFAULT_CODE = `((range) => { - return new Tree("Example Tree", range, []); + return new Tree("Example Tree", range, []).withColor(Color.red()); })`; class CustomInspector extends React.Component<{}, CustomInspectorState> { From 049b737425e5a366014fad3c8d6e99d074a65073 Mon Sep 17 00:00:00 2001 From: jr-k Date: Thu, 22 Jun 2023 19:05:21 +0200 Subject: [PATCH 5/7] tooltip label --- src/ui/treeview.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/treeview.tsx b/src/ui/treeview.tsx index f9cb2a8..b4e57e8 100644 --- a/src/ui/treeview.tsx +++ b/src/ui/treeview.tsx @@ -97,7 +97,7 @@ export class TreeView extends React.Component< icon={this.state.open ? faCaretDown : faCaretRight} /> - + {tree.label}
@@ -117,7 +117,7 @@ export class TreeView extends React.Component< ); } else { return ( -
Date: Thu, 22 Jun 2023 21:16:58 +0200 Subject: [PATCH 6/7] Fix bad color limit due to range size --- src/ui/binaryview.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/binaryview.tsx b/src/ui/binaryview.tsx index 7a332ea..b942cd4 100644 --- a/src/ui/binaryview.tsx +++ b/src/ui/binaryview.tsx @@ -89,7 +89,7 @@ export class BinaryView extends React.Component< } for (const t of tree.children) { - if (t.range.offset() <= byteNumber && byteNumber <= (t.range.offset() + t.range.size())) { + if (t.range.offset() <= byteNumber && byteNumber < (t.range.offset() + t.range.size())) { if (!t.color.isDefault()) { color = t.color; } From 95b5add85b5e1ed3463289827f878dccdeb444d3 Mon Sep 17 00:00:00 2001 From: JRK Date: Sat, 24 Jun 2023 01:15:30 +0200 Subject: [PATCH 7/7] Use constants for byte group --- src/ui/binaryview.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/binaryview.tsx b/src/ui/binaryview.tsx index b942cd4..f878ef6 100644 --- a/src/ui/binaryview.tsx +++ b/src/ui/binaryview.tsx @@ -193,7 +193,7 @@ export class BinaryView extends React.Component< } } - const byteNumber = i + (j * 8) + (k * 16); + const byteNumber = i + (j * HEX_BYTES_PER_GROUP) + (k * HEX_BYTES_PER_ROW); const color = this.byteColor(this.props.tree, byteNumber, undefined) || this.props.tree.color; return ( @@ -257,7 +257,7 @@ export class BinaryView extends React.Component< } } - const color = this.byteColor(this.props.tree, Math.floor(b.offset() / 8), undefined) || this.props.tree.color; + const color = this.byteColor(this.props.tree, Math.floor(b.offset() / HEX_BYTES_PER_GROUP), undefined) || this.props.tree.color; return (