diff --git a/src-ui/app/config_page/setting_section/setting_box/SettingBox.jsx b/src-ui/app/config_page/setting_section/setting_box/SettingBox.jsx
index d78ec87e..adec9373 100644
--- a/src-ui/app/config_page/setting_section/setting_box/SettingBox.jsx
+++ b/src-ui/app/config_page/setting_section/setting_box/SettingBox.jsx
@@ -5,6 +5,7 @@ import { Appearance } from "./appearance/Appearance";
import { Transcription } from "./transcription/Transcription";
import { Others } from "./others/Others";
import { AdvancedSettings } from "./advanced_settings/AdvancedSettings";
+import { Vr } from "./vr/Vr";
// import { AboutVrct } from "./about_vrct/AboutVrct";
export const SettingBox = () => {
@@ -18,6 +19,8 @@ export const SettingBox = () => {
return ;
case "others":
return ;
+ case "vr":
+ return ;
case "advanced_settings":
return ;
// case "about_vrct":
diff --git a/src-ui/app/config_page/setting_section/setting_box/_components/slider/Slider.jsx b/src-ui/app/config_page/setting_section/setting_box/_components/slider/Slider.jsx
index 280ec3f9..7f96bd86 100644
--- a/src-ui/app/config_page/setting_section/setting_box/_components/slider/Slider.jsx
+++ b/src-ui/app/config_page/setting_section/setting_box/_components/slider/Slider.jsx
@@ -1,6 +1,7 @@
import React, { useState, useEffect } from "react";
import styles from "./Slider.module.scss";
import MUI_Slider from "@mui/material/Slider";
+import { clsx } from "clsx";
export const Slider = (props) => {
const [baseColor, setBaseColor] = useState("");
@@ -17,10 +18,9 @@ export const Slider = (props) => {
}, []);
return (
-
+
{
min={Number(props.min)}
max={Number(props.max)}
onChange={(_e, value) => props.onchangeFunction(value)}
- onChangeCommitted={(_e, value) => props.onchangeCommittedFunction(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={{
color: baseColor,
- "& .MuiSlider-thumb": {
- backgroundColor: activeColor,
- "&:hover, &.Mui-focusVisible, &.Mui-active": {
- boxShadow: "0 0 0 0.8rem" + activeColor + "44",
- },
- "& .MuiSlider-valueLabel": {
- fontSize: "1.4rem",
- backgroundColor: toolTipColor,
- padding: "0.6rem 1rem",
- lineHeight: "1.15",
- top: "-1.4rem",
- "&::before": {
- left: "30%",
- width: "1rem",
- height: "1rem",
- clipPath: "polygon(50% 0, 100% 100%, 0 100%)",
- }
- }
+ "& .MuiSlider-thumb": {
+ backgroundColor: activeColor,
+ "&:hover, &.Mui-focusVisible, &.Mui-active": {
+ boxShadow: `0 0 0 0.8rem ${activeColor}44`,
},
- "& .MuiSlider-markLabel": {
+ "& .MuiSlider-valueLabel": {
fontSize: "1.4rem",
- color: "white"
+ backgroundColor: toolTipColor,
+ padding: "0.6rem 1rem",
+ lineHeight: "1.15",
+ // top: "-1.4rem",
+ // "&::before": {
+ // left: "30%",
+ // width: "1rem",
+ // height: "1rem",
+ // clipPath: "polygon(50% 0, 100% 100%, 0 100%)",
+ // },
},
- "& .MuiSlider-markLabelActive": {
- color: activeColor,
- }
- }}
+ },
+ "& .MuiSlider-markLabel": {
+ fontSize: "1.4rem",
+ color: "white",
+ whiteSpace: "nowrap",
+ },
+ "& .MuiSlider-markLabelActive": {
+ color: activeColor,
+ },
+ }}
/>
);
diff --git a/src-ui/app/config_page/setting_section/setting_box/_components/slider/Slider.module.scss b/src-ui/app/config_page/setting_section/setting_box/_components/slider/Slider.module.scss
index 873029b1..645a3a24 100644
--- a/src-ui/app/config_page/setting_section/setting_box/_components/slider/Slider.module.scss
+++ b/src-ui/app/config_page/setting_section/setting_box/_components/slider/Slider.module.scss
@@ -1,12 +1,30 @@
.container {
display: flex;
flex-direction: column;
- align-items: end;
+ align-items: center; // 中央に揃え
justify-content: center;
width: 100%;
- padding-left: 4rem;
+ // padding-left: 4rem;
}
.range_slider {
- // max-width: 60rem;
-}
\ No newline at end of file
+ // スライダーの幅を調整(必要に応じて調整)
+ height: 200px; // 縦スライダーの高さ
+ padding: 10px 0; // スライダーの上下のパディング
+
+ & .MuiSlider-thumb {
+ // スライダーのつまみのサイズを調整
+ height: 24px;
+ width: 24px;
+ margin-top: -12px; // つまみが中心に来るように調整
+ }
+
+ & .MuiSlider-track {
+ height: 2px; // トラックの高さを調整
+ }
+
+ & .MuiSlider-vertical {
+ // 縦スライダー用のスタイル
+ height: 100%; // コンテナの高さにフィット
+ }
+}
diff --git a/src-ui/app/config_page/setting_section/setting_box/vr/Vr.jsx b/src-ui/app/config_page/setting_section/setting_box/vr/Vr.jsx
new file mode 100644
index 00000000..92bc97cf
--- /dev/null
+++ b/src-ui/app/config_page/setting_section/setting_box/vr/Vr.jsx
@@ -0,0 +1,271 @@
+import React, { useState } from "react";
+import { useTranslation } from "react-i18next";
+import styles from "./Vr.module.scss";
+import { Slider } from "../_components/";
+import { clsx } from "clsx";
+import {
+ useOverlaySettings,
+ useOverlaySmallLogSettings,
+} from "@logics_configs";
+
+export const Vr = () => {
+ const { t } = useTranslation();
+ const [is_opened_position_controller, setIsOpenedPositionController] = useState(true);
+ const toggleController = () => {
+ setIsOpenedPositionController(!is_opened_position_controller);
+ };
+
+ const { currentOverlaySmallLogSettings, setOverlaySmallLogSettings } = useOverlaySmallLogSettings();
+
+ const [settings, setSettings] = useState({
+ x_pos: 0,
+ y_pos: 0,
+ z_pos: 0,
+ x_rotation: 0,
+ y_rotation: 0,
+ z_rotation: 0,
+ display_duration: 5,
+ fadeout_duration: 2,
+ });
+
+ const [timeout_id, setTimeoutId] = useState(null);
+
+ const onchangeFunction = (key, value) => {
+ setSettings((prev) => {
+ const new_data = { ...prev, [key]: value };
+ return new_data;
+ });
+
+ if (timeout_id) {
+ clearTimeout(timeout_id);
+ }
+
+ const newTimeoutId = setTimeout(() => {
+ let new_data = settings;
+ new_data[key] = value;
+ setOverlaySmallLogSettings(new_data);
+ }, 50);
+
+ setTimeoutId(newTimeoutId);
+ };
+
+ const toggle_button_class_names__position = clsx(styles.controller_type_switcher, {
+ [styles.is_selected]: is_opened_position_controller,
+ });
+ const toggle_button_class_names__rotation = clsx(styles.controller_type_switcher, {
+ [styles.is_selected]: !is_opened_position_controller,
+ });
+
+ return (
+
+
+
+
+ {is_opened_position_controller
+ ?
+ :
+ }
+
+
+
+ );
+};
+
+const CommonControls = () => {
+ const { t } = useTranslation();
+ const { currentOverlaySettings, setOverlaySettings } = useOverlaySettings();
+
+ const [settings, setSettings] = useState({
+ opacity: 1,
+ ui_scaling: 1,
+ });
+
+ const [timeout_id, setTimeoutId] = useState(null);
+
+ const onchangeFunction = (key, value) => {
+ setSettings((prev) => {
+ const new_data = { ...prev, [key]: value };
+ return new_data;
+ });
+
+ if (timeout_id) {
+ clearTimeout(timeout_id);
+ }
+
+ const newTimeoutId = setTimeout(() => {
+ let new_data = settings;
+ new_data[key] = value;
+ setOverlaySettings(settings);
+ }, 50);
+
+ setTimeoutId(newTimeoutId);
+ };
+
+ const ui_variable_opacity = (settings.opacity * 100).toFixed(0);
+ const ui_variable_ui_scaling = (settings.ui_scaling * 100).toFixed(0);
+
+ return (
+
+
+
+ onchangeFunction("opacity", value / 100)}
+ />
+
+
+
+ onchangeFunction("ui_scaling", value / 100)}
+ />
+
+
+ );
+};
+
+
+
+
+const PositionControls = ({settings, onchangeFunction}) => {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+ onchangeFunction("x_pos", value)}
+ />
+
+
+
+ onchangeFunction("y_pos", value)}
+ orientation="vertical"
+ />
+
+
+
+ onchangeFunction("z_pos", value)}
+ orientation="vertical"
+ />
+
+
+ );
+};
+
+const RotationControls = ({settings, onchangeFunction}) => {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+ onchangeFunction("x_rotation", -value)}
+ orientation="vertical"
+ />
+
+
+
+ onchangeFunction("y_rotation", value)}
+ />
+
+
+
+ onchangeFunction("z_rotation", value)}
+ orientation="vertical"
+ />
+
+
+ );
+};
+
+const OtherControls = ({settings, onchangeFunction}) => {
+ const { t } = useTranslation();
+
+ return(
+
+
+
+ onchangeFunction("display_duration", value)}
+ />
+
+
+
+ onchangeFunction("fadeout_duration", value)}
+ />
+
+
+ );
+};
\ No newline at end of file
diff --git a/src-ui/app/config_page/setting_section/setting_box/vr/Vr.module.scss b/src-ui/app/config_page/setting_section/setting_box/vr/Vr.module.scss
new file mode 100644
index 00000000..7a00c692
--- /dev/null
+++ b/src-ui/app/config_page/setting_section/setting_box/vr/Vr.module.scss
@@ -0,0 +1,215 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ padding: 2rem;
+}
+
+.controller_type_switch {
+ margin-top: 6rem;
+ display: flex;
+ border: 0.1rem solid var(--dark_600_color);
+ border-radius: 0.4rem;
+ width: 50%;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ color: var(--dark_600_color);
+ &:hover {
+ color: var(--dark_400_color);
+ }
+}
+.controller_type_switcher {
+ width: 100%;
+ &.is_selected {
+ background-color: var(--dark_850_color);
+ }
+ &.is_selected .controller_switcher_label {
+ color: var(--dark_basic_text_color);
+ }
+}
+.controller_switcher_label {
+ padding: 1rem;
+ font-size: 1.6rem;
+}
+
+.position_rotation_controls_box {
+ margin-top: 8rem;
+ position: relative;
+ aspect-ratio: 1 / 1;
+ width: 36%;
+ max-width: 36rem;
+ transform: translate(-10%);
+}
+
+// .position_controls {
+// background-color: gray;
+// }
+
+// .position_wrapper {
+// background-color: gray;
+// }
+
+.slider_label {
+ font-size: 1.6rem;
+ width: 100%;
+}
+.x_position_label {
+ position: absolute;
+ bottom: -4rem;
+ right: -30%;
+ text-align: end;
+}
+.y_position_label {
+ position: absolute;
+ top: -27%;
+ left: 10%;
+}
+.z_position_label {
+ position: absolute;
+ top: 30%;
+ left: 80%;
+}
+
+.x_position_slider {
+ position: absolute;
+ bottom: 0;
+ left: 27%;
+ width: 100%;
+ height: 0%;
+}
+
+.y_position_slider {
+ position: absolute;
+ bottom: 27%;
+ left: 0;
+ width: 0%;
+ height: 100%;
+}
+
+.z_position_slider {
+ position: absolute;
+ bottom: 61%;
+ left: 61%;
+ transform: translate(50%,50%) rotate(45deg);
+ width: 0%;
+ height: 100%;
+}
+
+
+
+
+// .rotation_controls {
+// background-color: gray;
+// }
+
+// .rotation_wrapper {
+// background-color: gray;
+// }
+
+.x_rotation_label {
+ position: absolute;
+ top: -27%;
+ left: 10%;
+}
+.y_rotation_label {
+ position: absolute;
+ bottom: -4rem;
+ right: -30%;
+ text-align: end;
+}
+.z_rotation_label {
+ position: absolute;
+ top: -10%;
+ right: -110%;
+}
+
+.x_rotation_slider {
+ position: absolute;
+ bottom: 27%;
+ left: 0;
+ width: 0%;
+ height: 100%;
+}
+
+.y_rotation_slider {
+ position: absolute;
+ bottom: 0;
+ left: 27%;
+ width: 100%;
+ height: 0%;
+}
+
+.z_rotation_slider {
+ position: absolute;
+ bottom: 90%;
+ left: 100%;
+ transform: translate(50%,50%) rotate(-45deg);
+ width: 0%;
+ height: 100%;
+}
+
+
+
+
+.common_controls {
+ padding-top: 4rem;
+ padding-bottom: 2rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 2rem;
+ width: 100%;
+ max-width: 56rem;
+ border-bottom: 0.1rem solid var(--dark_700_color);
+}
+
+.common_controls_wrapper {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ position: relative;
+}
+.common_controls_slider {
+ margin-left: 18rem;
+}
+
+.common_controls_slider_label {
+ position: absolute;
+ font-size: 1.6rem;
+ width: 100%;
+}
+
+
+
+.other_controls {
+ margin-top: 6rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 2rem;
+ width: 100%;
+ max-width: 56rem;
+}
+
+.other_controls_wrapper {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ position: relative;
+}
+.other_controls_slider {
+ margin-left: 18rem;
+}
+
+.other_controls_slider_label {
+ position: absolute;
+ font-size: 1.6rem;
+ width: 100%;
+}
\ No newline at end of file
diff --git a/src-ui/logics/configs/index.js b/src-ui/logics/configs/index.js
index 9badb2fd..d5cdffab 100644
--- a/src-ui/logics/configs/index.js
+++ b/src-ui/logics/configs/index.js
@@ -31,6 +31,9 @@ export { useSpeakerRecordTimeout } from "./transcription/useSpeakerRecordTimeout
export { useSpeakerPhraseTimeout } from "./transcription/useSpeakerPhraseTimeout";
export { useSpeakerMaxWords } from "./transcription/useSpeakerMaxWords";
+export { useOverlaySettings } from "./vr/useOverlaySettings";
+export { useOverlaySmallLogSettings } from "./vr/useOverlaySmallLogSettings";
+
export { useOscIpAddress } from "./advanced_settings/useOscIpAddress";
export { useOscPort } from "./advanced_settings/useOscPort";
diff --git a/src-ui/logics/configs/vr/useOverlaySettings.js b/src-ui/logics/configs/vr/useOverlaySettings.js
new file mode 100644
index 00000000..3394c800
--- /dev/null
+++ b/src-ui/logics/configs/vr/useOverlaySettings.js
@@ -0,0 +1,24 @@
+import { useStore_OverlaySettings } from "@store";
+import { useStdoutToPython } from "@logics/useStdoutToPython";
+
+export const useOverlaySettings = () => {
+ const { asyncStdoutToPython } = useStdoutToPython();
+ const { currentOverlaySettings, updateOverlaySettings, pendingOverlaySettings } = useStore_OverlaySettings();
+
+ const getOverlaySettings = () => {
+ // pendingOverlaySettings();
+ asyncStdoutToPython("/get/data/overlay_settings");
+ };
+
+ const setOverlaySettings = (overlay_settings) => {
+ // pendingOverlaySettings();
+ asyncStdoutToPython("/set/data/overlay_settings", overlay_settings);
+ };
+
+ return {
+ currentOverlaySettings,
+ getOverlaySettings,
+ updateOverlaySettings,
+ setOverlaySettings,
+ };
+};
\ No newline at end of file
diff --git a/src-ui/logics/configs/vr/useOverlaySmallLogSettings.js b/src-ui/logics/configs/vr/useOverlaySmallLogSettings.js
new file mode 100644
index 00000000..03b61393
--- /dev/null
+++ b/src-ui/logics/configs/vr/useOverlaySmallLogSettings.js
@@ -0,0 +1,24 @@
+import { useStore_OverlaySmallLogSettings } from "@store";
+import { useStdoutToPython } from "@logics/useStdoutToPython";
+
+export const useOverlaySmallLogSettings = () => {
+ const { asyncStdoutToPython } = useStdoutToPython();
+ const { currentOverlaySmallLogSettings, updateOverlaySmallLogSettings, pendingOverlaySmallLogSettings } = useStore_OverlaySmallLogSettings();
+
+ const getOverlaySmallLogSettings = () => {
+ // pendingOverlaySmallLogSettings();
+ asyncStdoutToPython("/get/data/overlay_small_log_settings");
+ };
+
+ const setOverlaySmallLogSettings = (overlay_small_log_settings) => {
+ // pendingOverlaySmallLogSettings();
+ asyncStdoutToPython("/set/data/overlay_small_log_settings", overlay_small_log_settings);
+ };
+
+ return {
+ currentOverlaySmallLogSettings,
+ getOverlaySmallLogSettings,
+ updateOverlaySmallLogSettings,
+ setOverlaySmallLogSettings,
+ };
+};
\ No newline at end of file
diff --git a/src-ui/logics/useReceiveRoutes.js b/src-ui/logics/useReceiveRoutes.js
index fe75557d..639edfd1 100644
--- a/src-ui/logics/useReceiveRoutes.js
+++ b/src-ui/logics/useReceiveRoutes.js
@@ -45,6 +45,8 @@ import {
useSpeakerRecordTimeout,
useSpeakerPhraseTimeout,
useSpeakerMaxWords,
+ useOverlaySettings,
+ useOverlaySmallLogSettings,
useOscIpAddress,
useOscPort,
} from "@logics_configs";
@@ -113,6 +115,9 @@ export const useReceiveRoutes = () => {
const { updateSpeakerPhraseTimeout } = useSpeakerPhraseTimeout();
const { updateSpeakerMaxWords } = useSpeakerMaxWords();
+ const { updateOverlaySettings } = useOverlaySettings();
+ const { updateOverlaySmallLogSettings } = useOverlaySmallLogSettings();
+
const { updateOscIpAddress } = useOscIpAddress();
const { updateOscPort } = useOscPort();
@@ -311,6 +316,13 @@ export const useReceiveRoutes = () => {
"/get/data/speaker_max_phrases": updateSpeakerMaxWords,
"/set/data/speaker_max_phrases": updateSpeakerMaxWords,
+ // VR
+ "/get/data/overlay_settings": updateOverlaySettings,
+ "/set/data/overlay_settings": updateOverlaySettings,
+
+ "/get/data/overlay_small_log_settings": updateOverlaySmallLogSettings,
+ "/set/data/overlay_small_log_settings": updateOverlaySmallLogSettings,
+
// Others Tab
"/get/data/auto_clear_message_box": updateEnableAutoClearMessageInputBox,
"/set/enable/auto_clear_message_box": updateEnableAutoClearMessageInputBox,
diff --git a/src-ui/store.js b/src-ui/store.js
index 2bb95a9d..856a24cb 100644
--- a/src-ui/store.js
+++ b/src-ui/store.js
@@ -189,6 +189,22 @@ export const { atomInstance: Atom_SpeakerRecordTimeout, useHook: useStore_Speake
export const { atomInstance: Atom_SpeakerPhraseTimeout, useHook: useStore_SpeakerPhraseTimeout } = createAtomWithHook(0, "SpeakerPhraseTimeout");
export const { atomInstance: Atom_SpeakerMaxWords, useHook: useStore_SpeakerMaxWords } = createAtomWithHook(0, "SpeakerMaxWords");
+// VR
+export const { atomInstance: Atom_OverlaySettings, useHook: useStore_OverlaySettings } = createAtomWithHook({
+ opacity: 1.0,
+ ui_scaling: 1.0,
+}, "OverlaySettings");
+export const { atomInstance: Atom_OverlaySmallLogSettings, useHook: useStore_OverlaySmallLogSettings } = createAtomWithHook({
+ x_pos: 0.0,
+ y_pos: 0.0,
+ z_pos: 0.0,
+ x_rotation: 0.0,
+ y_rotation: 0.0,
+ z_rotation: 0.0,
+ display_duration: 5,
+ fadeout_duration: 2,
+}, "OverlaySmallLogSettings");
+
// Others
export const { atomInstance: Atom_EnableAutoClearMessageInputBox, useHook: useStore_EnableAutoClearMessageInputBox } = createAtomWithHook(true, "EnableAutoClearMessageInputBox");
export const { atomInstance: Atom_EnableSendOnlyTranslatedMessages, useHook: useStore_EnableSendOnlyTranslatedMessages } = createAtomWithHook(false, "EnableSendOnlyTranslatedMessages");