Merge branch 'ui_vr_settings' into develop

This commit is contained in:
Sakamoto Shiina
2025-06-02 14:32:03 +09:00
4 changed files with 410 additions and 62 deletions

View File

@@ -4,22 +4,9 @@ import MUI_Slider from "@mui/material/Slider";
import clsx from "clsx";
export const Slider = (props) => {
return (
<div className={clsx(styles.container, props.className, {[styles.no_padding]: props.no_padding || props.is_break_point})}>
<MUI_Slider
aria-label="Default"
valueLabelDisplay="auto"
value={props.variable}
step={props.step}
min={Number(props.min)}
max={Number(props.max)}
onChange={(_e, value) => props.onchangeFunction(value)}
onChangeCommitted={(_e, value) => props.onchangeCommittedFunction ? props.onchangeCommittedFunction(value) : null}
marks={props.marks}
track={props.track}
orientation={props.orientation}
valueLabelFormat={`${props.valueLabelFormat ? props.valueLabelFormat : props.variable}`}
sx={{
const location = props.valueLabelDisplayLocation || "top";
const sliderSx = {
color: "var(--dark_700_color)",
"& .MuiSlider-thumb": {
backgroundColor: "var(--primary_600_color)",
@@ -27,10 +14,54 @@ export const Slider = (props) => {
boxShadow: `0 0 0 0.8rem var(--primary_600_color_44)`,
},
"& .MuiSlider-valueLabel": {
fontSize: "1.4rem",
position: "absolute",
backgroundColor: "var(--dark_800_color)",
padding: "0.6rem 1rem",
width: "fit-content",
minWidth: "4.8rem",
padding: "0.4rem 0.8rem",
lineHeight: "1.15",
"& .MuiSlider-valueLabelLabel": {
fontSize: "1.4rem",
},
...(location === "top" && {
top: "-110%",
left: "50%",
transform: "translate(-50%, -50%) scale(0)",
transformOrigin: "bottom center",
"&.MuiSlider-valueLabelOpen": {
transform: "translate(-50%, -50%) scale(1)",
},
"&::before": {
bottom: "0%",
left: "50%",
},
}),
...(location === "right" && {
top: "50%",
left: "150%",
transform: "translate(0, -50%) scale(0)",
transformOrigin: "left center",
"&.MuiSlider-valueLabelOpen": {
transform: "translate(0, -50%) scale(1)",
},
"&::before": {
bottom: "50%",
left: "0",
},
}),
...(location === "left" && {
// top: "50%",
// right: "50%",
// transform: "translate(-50%, -50%) scale(0)",
// transformOrigin: "bottom center",
// "&.MuiSlider-valueLabelOpen": {
// transform: "translate(-50%, -50%) scale(1)",
// },
// "&::before": {
// bottom: "50%",
// left: "100%",
// },
}),
},
},
"& .MuiSlider-markLabel": {
@@ -41,7 +72,39 @@ export const Slider = (props) => {
"& .MuiSlider-markLabelActive": {
color: "var(--primary_300_color)",
},
}}
};
return (
<div
className={clsx(
styles.container,
props.className,
{ [styles.no_padding]: props.no_padding || props.is_break_point }
)}
>
<MUI_Slider
aria-label="Default"
// valueLabelDisplay="on"
valueLabelDisplay={props.valueLabelDisplay ? props.valueLabelDisplay : "auto"}
value={props.variable}
step={props.step}
min={Number(props.min)}
max={Number(props.max)}
onChange={(_e, value) => props.onchangeFunction(value)}
onChangeCommitted={(_e, value) =>
props.onchangeCommittedFunction ? props.onchangeCommittedFunction(value) : null
}
onMouseEnter={(event) =>
props.onMouseEnterFunction ? props.onMouseEnterFunction(event) : null
}
onMouseLeave={(event) =>
props.onMouseLeaveFunction ? props.onMouseLeaveFunction(event) : null
}
marks={props.marks}
track={props.track}
orientation={props.orientation}
valueLabelFormat={`${props.valueLabelFormat ? props.valueLabelFormat : props.variable}`}
sx={sliderSx}
/>
</div>
);

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import clsx from "clsx";
import styles from "./Vr.module.scss";
@@ -25,6 +25,10 @@ import {
import RedoSvg from "@images/redo.svg?react";
import SquareSvg from "@images/square.svg?react";
import TriangleSvg from "@images/triangle.svg?react";
import { randomIntMinMax } from "@utils";
export const Vr = () => {
const { t } = useTranslation();
const [is_opened_small_settings, setIsOpenedSmallSettings] = useState(true);
@@ -187,9 +191,34 @@ const PageSwitcherContainer = (props) => {
);
};
const PositionControls = ({settings, onchangeFunction, selectFunction, ui_configs, default_ui_configs}) => {
export const PositionControls = ({ settings, onchangeFunction, selectFunction, ui_configs, default_ui_configs }) => {
const { t } = useTranslation();
const {
variable_display: x_variable_display,
is_max: is_max_position_x,
is_min: is_min_position_x,
countUp: countUpPositionX,
countDown: countDownPositionX,
} = useVariableControl("x_pos", settings, onchangeFunction, ui_configs);
const {
variable_display: y_variable_display,
is_max: is_max_position_y,
is_min: is_min_position_y,
countUp: countUpPositionY,
countDown: countDownPositionY,
} = useVariableControl("y_pos", settings, onchangeFunction, ui_configs);
const {
variable_display: z_variable_display,
is_max: is_max_position_z,
is_min: is_min_position_z,
countUp: countUpPositionZ,
countDown: countDownPositionZ,
} = useVariableControl("z_pos", settings, onchangeFunction, ui_configs);
return (
<div className={styles.position_controls}>
<div className={styles.position_wrapper}>
@@ -205,8 +234,18 @@ const PositionControls = ({settings, onchangeFunction, selectFunction, ui_config
min={ui_configs.x_pos.min}
max={ui_configs.x_pos.max}
onchangeFunction={(value) => onchangeFunction("x_pos", value)}
valueLabelDisplay={x_variable_display}
valueLabelDisplayLocation="top"
/>
<AdjustButtonContainer
wrapper_class_name={styles.x_position_button_wrapper}
is_max={is_max_position_x}
is_min={is_min_position_x}
countUp={countUpPositionX}
countDown={countDownPositionX}
/>
</div>
<div className={styles.position_wrapper}>
<p className={clsx(styles.slider_label, styles.y_position_label)}>
{t("config_page.vr.y_position")}
@@ -221,8 +260,18 @@ const PositionControls = ({settings, onchangeFunction, selectFunction, ui_config
max={ui_configs.y_pos.max}
onchangeFunction={(value) => onchangeFunction("y_pos", value)}
orientation="vertical"
valueLabelDisplay={y_variable_display}
valueLabelDisplayLocation="right"
/>
<AdjustButtonContainer
wrapper_class_name={styles.y_position_button_wrapper}
is_max={is_max_position_y}
is_min={is_min_position_y}
countUp={countUpPositionY}
countDown={countDownPositionY}
/>
</div>
<div className={styles.position_wrapper}>
<p className={clsx(styles.slider_label, styles.z_position_label)}>
{t("config_page.vr.z_position")}
@@ -237,69 +286,162 @@ const PositionControls = ({settings, onchangeFunction, selectFunction, ui_config
max={ui_configs.z_pos.max}
onchangeFunction={(value) => onchangeFunction("z_pos", value)}
orientation="vertical"
valueLabelDisplay={z_variable_display}
valueLabelDisplayLocation="left"
/>
<AdjustButtonContainer
wrapper_class_name={styles.z_position_button_wrapper}
is_max={is_max_position_z}
is_min={is_min_position_z}
countUp={countUpPositionZ}
countDown={countDownPositionZ}
/>
</div>
</div>
);
};
const RotationControls = ({settings, onchangeFunction, selectFunction, default_ui_configs}) => {
export const RotationControls = ({ settings, onchangeFunction, selectFunction, ui_configs, default_ui_configs }) => {
const { t } = useTranslation();
const {
variable_display: x_variable_display,
is_max: is_max_rotation_x,
is_min: is_min_rotation_x,
countUp: countUpRotationX,
countDown: countDownRotationX,
} = useVariableControl("x_rotation", settings, onchangeFunction, ui_configs);
const {
variable_display: y_variable_display,
is_max: is_max_rotation_y,
is_min: is_min_rotation_y,
countUp: countUpRotationY,
countDown: countDownRotationY,
} = useVariableControl("y_rotation", settings, onchangeFunction, ui_configs);
const {
variable_display: z_variable_display,
is_max: is_max_rotation_z,
is_min: is_min_rotation_z,
countUp: countUpRotationZ,
countDown: countDownRotationZ,
} = useVariableControl("z_rotation", settings, onchangeFunction, ui_configs);
return (
<div className={styles.rotation_controls}>
<div className={styles.rotation_wrapper}>
<p className={clsx(styles.slider_label, styles.x_rotation_label)}>
{t("config_page.vr.x_rotation")}
<ResetButton onClickFunction={() => selectFunction("x_rotation", default_ui_configs.y_pos)} />
<ResetButton onClickFunction={() => selectFunction("x_rotation", default_ui_configs.x_rotation)} />
</p>
<Slider
className={styles.x_rotation_slider}
no_padding={true}
variable={-settings.x_rotation}
valueLabelFormat={settings.x_rotation}
step={5}
min={-180}
max={180}
step={ui_configs.x_rotation.step}
min={ui_configs.x_rotation.min}
max={ui_configs.x_rotation.max}
onchangeFunction={(value) => onchangeFunction("x_rotation", -value)}
orientation="vertical"
valueLabelDisplay={x_variable_display}
valueLabelDisplayLocation="right"
/>
<AdjustButtonContainer
wrapper_class_name={styles.x_rotation_button_wrapper}
is_max={is_min_rotation_x}
is_min={is_max_rotation_x}
countUp={countDownRotationX}
countDown={countUpRotationX}
/>
</div>
<div className={styles.rotation_wrapper}>
<p className={clsx(styles.slider_label, styles.y_rotation_label)}>
{t("config_page.vr.y_rotation")}
<ResetButton onClickFunction={() => selectFunction("y_rotation", default_ui_configs.y_pos)} />
<ResetButton onClickFunction={() => selectFunction("y_rotation", default_ui_configs.y_rotation)} />
</p>
<Slider
className={styles.y_rotation_slider}
no_padding={true}
variable={settings.y_rotation}
step={5}
min={-180}
max={180}
step={ui_configs.y_rotation.step}
min={ui_configs.y_rotation.min}
max={ui_configs.y_rotation.max}
onchangeFunction={(value) => onchangeFunction("y_rotation", value)}
valueLabelDisplay={y_variable_display}
valueLabelDisplayLocation="top"
/>
<AdjustButtonContainer
wrapper_class_name={styles.y_rotation_button_wrapper}
is_max={is_max_rotation_y}
is_min={is_min_rotation_y}
countUp={countUpRotationY}
countDown={countDownRotationY}
/>
</div>
<div className={styles.rotation_wrapper}>
<p className={clsx(styles.slider_label, styles.z_rotation_label)}>
{t("config_page.vr.z_rotation")}
<ResetButton onClickFunction={() => selectFunction("z_rotation", default_ui_configs.y_pos)} />
<ResetButton onClickFunction={() => selectFunction("z_rotation", default_ui_configs.z_rotation)} />
</p>
<Slider
className={styles.z_rotation_slider}
no_padding={true}
variable={settings.z_rotation}
step={5}
min={-180}
max={180}
step={ui_configs.z_rotation.step}
min={ui_configs.z_rotation.min}
max={ui_configs.z_rotation.max}
onchangeFunction={(value) => onchangeFunction("z_rotation", value)}
orientation="vertical"
valueLabelDisplay={z_variable_display}
valueLabelDisplayLocation="left"
/>
<AdjustButtonContainer
wrapper_class_name={styles.z_rotation_button_wrapper}
is_max={is_max_rotation_z}
is_min={is_min_rotation_z}
countUp={countUpRotationZ}
countDown={countDownRotationZ}
/>
</div>
</div>
);
};
const AdjustButtonContainer = ({ wrapper_class_name, is_max, is_min, countUp, countDown }) => {
return (
<div className={wrapper_class_name}>
<div
className={clsx(
styles.button_wrapper,
{
[styles.is_disabled]: is_max,
[styles.up]: true,
}
)}
onClick={countUp}
>
<TriangleSvg className={styles.adjust_button_triangle_svg} />
</div>
<div
className={clsx(
styles.button_wrapper,
{
[styles.is_disabled]: is_min,
}
)}
onClick={countDown}
>
<TriangleSvg className={styles.adjust_button_triangle_svg} />
</div>
</div>
);
};
const OtherControls = ({settings, onchangeFunction, ui_configs}) => {
const { t } = useTranslation();
@@ -393,10 +535,6 @@ const ResetButton = ({onClickFunction}) => {
);
};
import SquareSvg from "@images/square.svg?react";
import TriangleSvg from "@images/triangle.svg?react";
import { randomIntMinMax } from "@utils";
const SendSampleTextToggleButton = () => {
const { t } = useTranslation();
const { sendTextToOverlay } = useSendTextToOverlay();
@@ -446,3 +584,57 @@ const SendSampleTextToggleButton = () => {
</div>
);
};
const useVariableControl = (key, settings, onchangeFunction, ui_configs) => {
const [variable_display, setVariableDisplay] = useState("auto");
const [is_max, setIsMax] = useState(settings[key] >= ui_configs[key].max);
const [is_min, setIsMin] = useState(settings[key] <= ui_configs[key].min);
const timerRef = useRef();
useEffect(() => {
return () => {
clearTimeout(timerRef.current);
};
}, []);
const triggerDisplay = () => {
setVariableDisplay("on");
clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => {
setVariableDisplay("auto");
}, 2000);
};
useEffect(() => {
setIsMax(settings[key] >= ui_configs[key].max);
setIsMin(settings[key] <= ui_configs[key].min);
}, [settings[key]]);
const countUp = () => {
if (is_max) return;
const step = ui_configs[key].step;
const new_value = parseFloat((settings[key] + step).toFixed(2));
onchangeFunction(key, new_value);
triggerDisplay();
};
const countDown = () => {
if (is_min) return;
const step = ui_configs[key].step;
const new_value = parseFloat((settings[key] - step).toFixed(2));
onchangeFunction(key, new_value);
triggerDisplay();
};
return {
variable_display,
is_max,
is_min,
countUp,
countDown,
};
};

View File

@@ -16,7 +16,7 @@
justify-content: center;
width: 100%;
max-width: 56rem;
gap: 2rem;
gap: 4rem;
}
.controller_type_switch {
@@ -58,12 +58,13 @@
.sample_text_button_wrapper {
position: absolute;
bottom: 0;
left: -74%;
bottom: -12%;
left: -80%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
// transform: translate(-50%, -50%);
}
.sample_text_button {
background-color: var(--dark_850_color);
@@ -121,20 +122,20 @@
}
.x_position_label {
position: absolute;
bottom: -4.6rem;
bottom: -5rem;
right: -46%;
justify-content: end;
}
.y_position_label {
position: absolute;
top: -44%;
left: 10%;
justify-content: start;
bottom: 110%;
right: 119%;
justify-content: end;
}
.z_position_label {
position: absolute;
top: 30%;
left: 80%;
top: 14%;
left: 110%;
}
.x_position_slider {
@@ -155,14 +156,84 @@
.z_position_slider {
position: absolute;
bottom: 61%;
left: 61%;
bottom: 80%;
left: 88%;
transform: translate(50%,50%) rotate(45deg);
width: 0%;
height: 100%;
}
%variable-button {
width: 3.8rem;
border-radius: 0.4rem;
aspect-ratio: 1.2 / 1;
background-color: var(--dark_850_color);
display: flex;
justify-content: center;
align-items: center;
font-size: 1.6rem;
cursor: pointer;
&:hover {
background-color: var(--primary_500_color);
}
&:active {
background-color: var(--primary_600_color);
}
&.is_disabled {
pointer-events: none;
background-color: var(--dark_875_color);
& .adjust_button_triangle_svg {
color: var(--dark_800_color);
}
}
}
@mixin variable-button-wrapper($vertical-pos, $vertical-value, $horizontal-pos, $horizontal-value, $rotate: 0deg) {
position: absolute;
#{$vertical-pos}: $vertical-value;
#{$horizontal-pos}: $horizontal-value;
display: flex;
gap: 1.6rem;
flex-direction: column;
transform: translate(-50%) rotate($rotate);
}
.button_wrapper {
@extend %variable-button;
&.up .adjust_button_triangle_svg {
transform: rotate(0deg);
}
&:not(.up) .adjust_button_triangle_svg {
transform: rotate(180deg);
}
&.is_disabled {
pointer-events: none;
color: var(--dark_875_color);
}
}
.adjust_button_triangle_svg {
width: 1.8rem;
color: var(--dark_400_color);
}
.y_position_button_wrapper {
@include variable-button-wrapper(top, 30%, left, -26%);
}
.x_position_button_wrapper {
@include variable-button-wrapper(bottom, -38%, left, 46%, 90deg);
}
.z_position_button_wrapper {
@include variable-button-wrapper(bottom, 26%, right, -4%, 45deg);
}
// .rotation_controls {
@@ -175,19 +246,20 @@
.x_rotation_label {
position: absolute;
top: -44%;
left: 10%;
bottom: 110%;
right: 119%;
justify-content: end;
}
.y_rotation_label {
position: absolute;
bottom: -4.6rem;
bottom: -5rem;
right: -46%;
justify-content: end;
}
.z_rotation_label {
position: absolute;
top: -10%;
right: -110%;
top: -20%;
right: -100%;
}
.x_rotation_slider {
@@ -216,6 +288,21 @@
}
.x_rotation_button_wrapper {
@include variable-button-wrapper(top, 30%, left, -26%);
}
.y_rotation_button_wrapper {
@include variable-button-wrapper(bottom, -38%, left, 46%, 90deg);
}
.z_rotation_button_wrapper {
@include variable-button-wrapper(bottom, 50%, right, -60%, -45deg);
}
.slider_reset_button {
background-color: var(--dark_875_color);
padding: 0.6rem;

View File

@@ -7,12 +7,18 @@ export const ui_configs = {
x_pos: { step: 0.05, min: -0.5, max: 0.5 },
y_pos: { step: 0.05, min: -0.8, max: 0.8 },
z_pos: { step: 0.05, min: -0.5, max: 1.5 },
x_rotation: { min: -180, max: 180, step: 5 },
y_rotation: { min: -180, max: 180, step: 5 },
z_rotation: { min: -180, max: 180, step: 5 },
ui_scaling: { step: 10, min: 40, max: 200 },
},
overlay_large_log: {
x_pos: { step: 0.05, min: -0.5, max: 0.5 },
y_pos: { step: 0.05, min: -0.8, max: 0.8 },
z_pos: { step: 0.05, min: -0.5, max: 1.5 },
x_rotation: { min: -180, max: 180, step: 5 },
y_rotation: { min: -180, max: 180, step: 5 },
z_rotation: { min: -180, max: 180, step: 5 },
ui_scaling: { step: 10, min: 40, max: 200 },
},