Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

exports[`<ActionButton /> > it matches the snapshot 1`] = `
<button
className="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButton-colorPrimary MuiButton-fullWidth MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButton-colorPrimary MuiButton-fullWidth css-5uchfp-MuiButtonBase-root-MuiButton-root"
className="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButton-colorPrimary MuiButton-fullWidth MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButton-colorPrimary MuiButton-fullWidth css-1po0gow-MuiButtonBase-root-MuiButton-root"
disabled={false}
onBlur={[Function]}
onClick={[MockFunction spy]}
Expand All @@ -25,7 +25,6 @@ exports[`<ActionButton /> > it matches the snapshot 1`] = `
{
"display": "block",
"lineHeight": 1,
"transform": "rotate(0deg)",
}
}
>
Expand Down
74 changes: 38 additions & 36 deletions src/ui/widgets/ActionButton/actionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,38 @@ import {
FuncPropOpt,
FloatPropOpt
} from "../propTypes";
import { Color } from "../../../types/color";
import { Font } from "../../../types/font";
import { Border } from "../../../types/border";
import { MacroContext } from "../../../types/macros";
import { ExitFileContext, FileContext } from "../../../misc/fileContext";
import { styled, Button as MuiButton, useTheme } from "@mui/material";
import { WIDGET_DEFAULT_SIZES } from "../EmbeddedDisplay/bobParser";
import { calculateRotationTransform } from "../utils";

export interface ActionButtonProps {
text: string;
enabled?: boolean;
onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
image?: string;
backgroundColor?: Color;
foregroundColor?: Color;
border?: Border;
font?: Font;
actions?: WidgetActions;
visible?: boolean;
rotationStep?: number;
transparent?: boolean;
}

const ActionButtonPropType = {
text: StringPropOpt,
actions: ActionsPropType,
image: StringPropOpt,
backgroundColor: ColorPropOpt,
foregroundColor: ColorPropOpt,
font: FontPropOpt,
border: BorderPropOpt,
visible: BoolPropOpt,
enabled: BoolPropOpt,
onClick: FuncPropOpt,
transparent: BoolPropOpt,
rotationStep: FloatPropOpt,
height: FloatPropOpt,
width: FloatPropOpt
};

const Button = styled(MuiButton)({
"&.MuiButton-root": {
display: "block",
alignItems: "center",
justifyContent: "center",
height: "100%",
width: "100%",
minWidth: 0,
minHeight: 0,
padding: 0,
Expand All @@ -59,14 +62,16 @@ const Button = styled(MuiButton)({
});

export const ActionButtonComponent = (
props: ActionButtonProps
props: InferWidgetProps<typeof ActionButtonPropType> & ActionButtonProps
): JSX.Element => {
const theme = useTheme();
const {
enabled = true,
foregroundColor = theme.palette.primary.contrastText,
rotationStep = 0,
transparent = false
transparent = false,
height = WIDGET_DEFAULT_SIZES["action_button"][1],
width = WIDGET_DEFAULT_SIZES["action_button"][0]
} = props;

const backgroundColor = transparent
Expand All @@ -75,16 +80,27 @@ export const ActionButtonComponent = (
const font = props.font?.css() ?? theme.typography;
const border = props.border?.css() ?? null;

const [inputWidth, inputHeight, transform] = calculateRotationTransform(
rotationStep,
width,
height
);

return (
<Button
variant={transparent ? "text" : "contained"}
disabled={!enabled}
fullWidth={true}
sx={{
"&.MuiButton-root": {
height: inputHeight,
width: inputWidth
},
color: foregroundColor.toString(),
backgroundColor: backgroundColor,
border: border,
fontFamily: font
fontFamily: font,
transform: transform.toString()
}}
onClick={props.onClick}
>
Expand All @@ -101,8 +117,7 @@ export const ActionButtonComponent = (
<span
style={{
display: "block",
lineHeight: 1,
transform: `rotate(${rotationStep * -90}deg)`
lineHeight: 1
}}
>
{props.text ?? ""}
Expand All @@ -112,21 +127,6 @@ export const ActionButtonComponent = (
);
};

const ActionButtonPropType = {
text: StringPropOpt,
actions: ActionsPropType,
image: StringPropOpt,
backgroundColor: ColorPropOpt,
foregroundColor: ColorPropOpt,
font: FontPropOpt,
border: BorderPropOpt,
visible: BoolPropOpt,
enabled: BoolPropOpt,
onClick: FuncPropOpt,
transparent: BoolPropOpt,
rotationStep: FloatPropOpt
};

const ActionButtonWidgetProps = {
...ActionButtonPropType,
...PVWidgetPropType
Expand Down Expand Up @@ -163,6 +163,8 @@ export const ActionButtonWidget = (
visible={props.visible}
transparent={props.transparent}
rotationStep={props.rotationStep}
height={props.height}
width={props.width}
/>
);
};
Expand Down
23 changes: 6 additions & 17 deletions src/ui/widgets/Label/label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from "../propTypes";
import { Typography as MuiTypography, styled, useTheme } from "@mui/material";
import { WIDGET_DEFAULT_SIZES } from "../EmbeddedDisplay/bobParser";
import { calculateRotationTransform } from "../utils";

const LabelProps = {
macros: MacrosPropOpt,
Expand Down Expand Up @@ -72,23 +73,11 @@ export const LabelComponent = (
const borderColor = props.border?.css().borderColor ?? "#000000";
const borderStyle = props.border?.css().borderStyle ?? "solid";

const inputWidth = rotationStep === 0 || rotationStep === 2 ? width : height;
const inputHeight = rotationStep === 0 || rotationStep === 2 ? height : width;

const offset = width / 2 - height / 2;
const transform = (function () {
switch (rotationStep) {
case 0: // 0 degrees
case 2: // 180 degrees
return `rotate(${rotationStep * -90}deg)`;
case 1: // 90 degrees
return `rotate(${rotationStep * -90}deg) translateY(${offset}px) translateX(${offset}px)`;
case 3: // -90 degrees
return `rotate(${rotationStep * -90}deg) translateY(${-offset}px) translateX(${-offset}px)`;
default: // Unreachable
return "";
}
})();
const [inputWidth, inputHeight, transform] = calculateRotationTransform(
rotationStep,
width,
height
);

// Since display is "flex", use "flex-start" and "flex-end" to align
// the content.
Expand Down
14 changes: 6 additions & 8 deletions src/ui/widgets/Readback/readback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { registerWidget } from "../register";
import { AlarmQuality, DType } from "../../../types/dtypes";
import { TextField as MuiTextField, styled, useTheme } from "@mui/material";
import { WIDGET_DEFAULT_SIZES } from "../EmbeddedDisplay/bobParser";
import { calculateRotationTransform } from "../utils";

const ReadbackProps = {
precision: IntPropOpt,
Expand Down Expand Up @@ -188,14 +189,11 @@ export const ReadbackComponent = (
) * 16
: theme.typography.fontSize;

const inputWidth = rotationStep === 0 || rotationStep === 2 ? width : height;
const inputHeight = rotationStep === 0 || rotationStep === 2 ? height : width;

const offset = width / 2 - height / 2;
const transform =
rotationStep === 1 || rotationStep === 3
? `rotate(${rotationStep * -90}deg) translateY(${offset}px) translateX(${offset}px)`
: `rotate(${rotationStep * -90}deg)`;
const [inputWidth, inputHeight, transform] = calculateRotationTransform(
rotationStep,
width,
height
);

// Calculate max number of rows based on the height of the widget and the height of the font
// an extra row is then subtracted to make it fit nicer
Expand Down
34 changes: 34 additions & 0 deletions src/ui/widgets/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,37 @@ export function trimFromString(value: string): number {
export function getOptionalValue(optionalParam: any, defValue: any): any {
return typeof optionalParam === "undefined" ? defValue : optionalParam;
}

/**
* Returns the corrected width and height for a rotated widget along
* with its calculated transform string.
* @param rotationStep 0 | 1 | 2 | 3
* @param inputWidth current width of the widget
* @param inputHeight current height of the widget
* @returns an array containing the new width, height, and transform string
*/
export function calculateRotationTransform(
rotationStep: number,
inputWidth: number,
inputHeight: number
): [outputWidth: number, outputHeight: number, transform: string] {
const outputWidth =
rotationStep === 0 || rotationStep === 2 ? inputWidth : inputHeight;
const outputHeight =
rotationStep === 0 || rotationStep === 2 ? inputHeight : inputWidth;
const offset = inputWidth / 2 - inputHeight / 2;
const transform = (function () {
switch (rotationStep) {
case 0: // 0 degrees
case 2: // 180 degrees
return `rotate(${rotationStep * -90}deg)`;
case 1: // 90 degrees
return `rotate(${rotationStep * -90}deg) translateY(${offset}px) translateX(${offset}px)`;
case 3: // -90 degrees
return `rotate(${rotationStep * -90}deg) translateY(${-offset}px) translateX(${-offset}px)`;
default: // Unreachable
return "";
}
})();
return [outputWidth, outputHeight, transform];
}
Loading