Skip to content
Merged
23 changes: 20 additions & 3 deletions src/ui/widgets/EmbeddedDisplay/bobParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ const BOB_WIDGET_MAPPING: { [key: string]: any } = {
progressbar: "progressbar",
rectangle: "shape",
choice: "choicebutton",
scaledslider: "slidecontrol"
scaledslider: "slidecontrol",
symbol: "symbol"
};

// Default width and height of widgets in Phoebus
Expand All @@ -75,7 +76,8 @@ export const WIDGET_DEFAULT_SIZES: { [key: string]: [number, number] } = {
polyline: [100, 20],
progressbar: [100, 20],
rectangle: [100, 20],
scaledslider: [400, 55]
scaledslider: [400, 55],
symbol: [100, 100]
};

function bobParseType(props: any): string {
Expand Down Expand Up @@ -206,6 +208,16 @@ function bobParseResizing(jsonProp: ElementCompact): string {
}
}

function bobParseSymbols(jsonProp: ElementCompact): string[] {
const symbols: string[] = [];
Object.values(jsonProp["symbol"]).forEach((item: any) => {
// For a single symbol, we are passed a string. For multiple symbols
// we are passed an object, so we need to return string from it
symbols.push(typeof item === "string" ? item : item._text);
});
return symbols;
}

function bobGetTargetWidget(props: any): React.FC {
const typeid = bobParseType(props);
let targetWidget;
Expand Down Expand Up @@ -257,7 +269,12 @@ export function parseBob(
squareLed: ["square", opiParseBoolean],
formatType: ["format", bobParseFormatType],
stretchToFit: ["stretch_image", opiParseBoolean],
macros: ["macros", opiParseMacros]
macros: ["macros", opiParseMacros],
symbols: ["symbols", bobParseSymbols],
initialIndex: ["initial_index", bobParseNumber],
showIndex: ["show_index", opiParseBoolean],
fallbackSymbol: ["fallback_symbol", opiParseString],
rotation: ["rotation", bobParseNumber]
};

const complexParsers = {
Expand Down
5 changes: 3 additions & 2 deletions src/ui/widgets/Image/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const ImageProps = {
rotation: FloatPropOpt,
flipHorizontal: BoolPropOpt,
flipVertical: BoolPropOpt,
onClick: FuncPropOpt
onClick: FuncPropOpt,
overflow: BoolPropOpt
};

export const ImageComponent = (
Expand All @@ -39,7 +40,7 @@ export const ImageComponent = (

let imageHeight: string | undefined = undefined;
let imageWidth: string | undefined = undefined;
const overflow = "hidden";
const overflow = props.overflow ? "visible" : "hidden";
if (props.stretchToFit) {
imageWidth = "100%";
imageHeight = "100%";
Expand Down
74 changes: 70 additions & 4 deletions src/ui/widgets/Symbol/__snapshots__/symbol.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -1,17 +1,83 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`<Symbol /> > matches snapshot 1`] = `
exports[`<Symbol /> from .bob file > matches snapshot (using fallback symbol) 1`] = `
<DocumentFragment>
<div
style="overflow: hidden; text-align: left;"
style="overflow: visible; text-align: left; width: 100%; height: 100%;"
>
<img
src="https://cs-web-symbol.diamond.ac.uk/catalogue/default.svg"
style="width: 100%; height: 100%; display: block; transform: rotate(0deg) scaleX(1) scaleY(1); object-fit: fill;"
/>
</div>
</DocumentFragment>
`;

exports[`<Symbol /> from .bob file > matches snapshot (with index) 1`] = `
<DocumentFragment>
<div
style="overflow: visible; text-align: left; width: 100%; height: 100%;"
>
<img
src="img 3.svg"
style="width: 100%; height: 100%; display: block; transform: rotate(0deg) scaleX(1) scaleY(1); object-fit: fill;"
/>
</div>
</DocumentFragment>
`;

exports[`<Symbol /> from .bob file > matches snapshot (with rotation) 1`] = `
<DocumentFragment>
<div
style="overflow: visible; text-align: left; width: 100%; height: 100%;"
>
<img
src="img 1.gif"
style="width: 100%; height: 100%; display: block; transform: rotate(45deg) scaleX(1) scaleY(1); object-fit: fill;"
/>
</div>
</DocumentFragment>
`;

exports[`<Symbol /> from .bob file > matches snapshot (without index) 1`] = `
<DocumentFragment>
<div
style="overflow: visible; text-align: left; width: 100%; height: 100%;"
>
<img
src="img 1.gif"
style="width: 100%; height: 100%; display: block; transform: rotate(0deg) scaleX(1) scaleY(1); object-fit: fill;"
/>
</div>
</DocumentFragment>
`;

exports[`<Symbol /> from .opi file > matches snapshot (with rotation) 1`] = `
<DocumentFragment>
<div
style="overflow: visible; text-align: left; width: 100%; height: 100%;"
>
<img
src="img 1.gif"
style="width: 100%; height: 100%; display: block; transform: rotate(45deg) scaleX(1) scaleY(1); object-fit: fill;"
/>
</div>
</DocumentFragment>
`;

exports[`<Symbol /> from .opi file > matches snapshot 1`] = `
<DocumentFragment>
<div
style="overflow: visible; text-align: left; width: 100%; height: 100%;"
>
<img
src="img 1.gif"
style="display: block; transform: rotate(0deg) scaleX(1) scaleY(1); object-fit: none;"
style="width: 100%; height: 100%; display: block; transform: rotate(0deg) scaleX(1) scaleY(1); object-fit: fill;"
/>
</div>
<div
style="background-color: transparent; position: absolute; height: 100%; width: 100%; top: 0px; left: 0px; display: flex; align-items: center; justify-content: center;"
class="_SymbolLabel_7b7af1"
style="background-color: transparent; align-items: center; justify-content: center;"
>
<div
style="padding: 5%;"
Expand Down
23 changes: 23 additions & 0 deletions src/ui/widgets/Symbol/symbol.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.IndexLabel {
height: 30px;
width: 30px;
border-radius: 50%;
background-color: black;
border: 1px solid white;
opacity: 50%;
color: white;
position: absolute;
top: calc(50% - 15px);
left: calc(50% - 15px);
text-align: center;
font-size: math;
}

.SymbolLabel {
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
display: flex;
}
120 changes: 119 additions & 1 deletion src/ui/widgets/Symbol/symbol.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { SymbolComponent } from "./symbol";
import { DType } from "../../../types/dtypes";

const fakeValue = new DType({ stringValue: "Fake value" });
const stringValue = new DType({ stringValue: "1.54" });
const arrayValue = new DType({ arrayValue: Float64Array.from([2, 0]) });

describe("<Symbol />", (): void => {
describe("<Symbol /> from .opi file", (): void => {
test("label is not shown if showLabel is false", (): void => {
const symbolProps = {
showBooleanLabel: false,
Expand Down Expand Up @@ -40,4 +42,120 @@ describe("<Symbol />", (): void => {

expect(asFragment()).toMatchSnapshot();
});

test("matches snapshot (with rotation)", (): void => {
const symbolProps = {
showBooleanLabel: false,
imageFile: "img 1.gif",
value: fakeValue,
rotation: 45
};

const { asFragment } = render(
<SymbolComponent {...(symbolProps as any)} />
);

expect(asFragment()).toMatchSnapshot();
});
});

describe("<Symbol /> from .bob file", (): void => {
test("index is not shown if showIndex is false", (): void => {
const symbolProps = {
symbols: ["img 1.gif"],
value: new DType({ stringValue: "0" })
};

render(<SymbolComponent {...(symbolProps as any)} />);

expect(screen.queryByText("0")).not.toBeInTheDocument();
});

test("index is added", (): void => {
const symbolProps = {
showIndex: true,
symbols: ["img 1.gif", "img 2.png"],
value: stringValue
};
render(<SymbolComponent {...(symbolProps as any)} />);

expect(screen.getByText("1")).toBeInTheDocument();
});

test("use initialIndex if no props value provided", (): void => {
const symbolProps = {
showIndex: true,
initialIndex: 2,
symbols: ["img 1.gif", "img 2.png", "img 3.svg"],
value: undefined
};

render(<SymbolComponent {...(symbolProps as any)} />);

expect(screen.getByText("2")).toBeInTheDocument();
});

test("use arrayIndex to find index if value is an array", (): void => {
const symbolProps = {
arrayIndex: 0,
showIndex: true,
symbols: ["img 1.gif", "img 2.png", "img 3.svg"],
value: arrayValue
};
render(<SymbolComponent {...(symbolProps as any)} />);

expect(screen.getByText("2")).toBeInTheDocument();
});

test("matches snapshot (without index)", (): void => {
const symbolProps = {
symbols: ["img 1.gif"],
value: new DType({ stringValue: "0" })
};

const { asFragment } = render(
<SymbolComponent {...(symbolProps as any)} />
);

expect(asFragment()).toMatchSnapshot();
});

test("matches snapshot (with index)", (): void => {
const symbolProps = {
symbols: ["img 1.gif", "img 2.png", "img 3.svg"],
value: new DType({ stringValue: "2" })
};

const { asFragment } = render(
<SymbolComponent {...(symbolProps as any)} />
);

expect(asFragment()).toMatchSnapshot();
});

test("matches snapshot (using fallback symbol)", (): void => {
const symbolProps = {
symbols: ["img 1.gif"],
value: new DType({ doubleValue: 1 })
};
const { asFragment } = render(
<SymbolComponent {...(symbolProps as any)} />
);

expect(asFragment()).toMatchSnapshot();
});

test("matches snapshot (with rotation)", (): void => {
const symbolProps = {
symbols: ["img 1.gif"],
value: new DType({ stringValue: "0" }),
rotation: 45
};

const { asFragment } = render(
<SymbolComponent {...(symbolProps as any)} />
);

expect(asFragment()).toMatchSnapshot();
});
});
Loading
Loading