mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
First tests and integration of radio panel
This commit is contained in:
56
frontend/react/src/ui/components/olfrequencyinput.tsx
Normal file
56
frontend/react/src/ui/components/olfrequencyinput.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import React from "react";
|
||||
import { ChangeEvent } from "react";
|
||||
import { OlNumberInput } from "./olnumberinput";
|
||||
|
||||
export function OlFrequencyInput(props: { value: number; className?: string; onChange: (value: number) => void }) {
|
||||
let frequency = props.value;
|
||||
|
||||
return (
|
||||
<div className={`
|
||||
${props.className}
|
||||
flex gap-2
|
||||
`}>
|
||||
<OlNumberInput
|
||||
min={1}
|
||||
max={400}
|
||||
onChange={(e) => {
|
||||
let newValue = Math.max(Math.min(Number(e.target.value), 400), 1) * 1000000;
|
||||
let decimalPart = frequency - Math.floor(frequency / 1000000) * 1000000;
|
||||
frequency = newValue + decimalPart;
|
||||
props.onChange(frequency);
|
||||
}}
|
||||
onDecrease={() => {
|
||||
frequency = Math.max(Math.min(Number(frequency - 1000000), 400000000), 1000000);
|
||||
props.onChange(frequency);
|
||||
}}
|
||||
onIncrease={() => {
|
||||
frequency = Math.max(Math.min(Number(frequency + 1000000), 400000000), 1000000);
|
||||
props.onChange(frequency);
|
||||
}}
|
||||
value={Math.floor(frequency / 1000000)}
|
||||
></OlNumberInput>
|
||||
<div className="my-auto">.</div>
|
||||
<OlNumberInput
|
||||
min={0}
|
||||
max={990}
|
||||
minLength={3}
|
||||
onChange={(e) => {
|
||||
let newValue = Math.max(Math.min(Number(e.target.value), 990), 0) * 1000;
|
||||
let integerPart = Math.floor(frequency / 1000000) * 1000000;
|
||||
frequency = newValue + integerPart;
|
||||
props.onChange(frequency);
|
||||
}}
|
||||
onDecrease={() => {
|
||||
frequency = Math.max(Math.min(Number(frequency - 25000), 400000000), 1000000);
|
||||
props.onChange(frequency);
|
||||
}}
|
||||
onIncrease={() => {
|
||||
frequency = Math.max(Math.min(Number(frequency + 25000), 400000000), 1000000);
|
||||
props.onChange(frequency);
|
||||
}}
|
||||
value={(frequency - Math.floor(frequency / 1000000) * 1000000) / 1000}
|
||||
></OlNumberInput>
|
||||
<div className="my-auto">MHz</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ export function OlRangeSlider(props: {
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
className?: string;
|
||||
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||
}) {
|
||||
var elementRef = useRef(null);
|
||||
@@ -28,6 +29,7 @@ export function OlRangeSlider(props: {
|
||||
max={props.max ?? 100}
|
||||
step={props.step ?? 1}
|
||||
className={`
|
||||
${props.className}
|
||||
h-2 w-full cursor-pointer appearance-none rounded-lg bg-gray-200
|
||||
dark:bg-gray-700
|
||||
`}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { OlNumberInput } from "../components/olnumberinput";
|
||||
import { MapOptions } from "../../types/types";
|
||||
import { getApp } from "../../olympusapp";
|
||||
|
||||
export function Options(props: { open: boolean; onClose: () => void; options: MapOptions; children?: JSX.Element | JSX.Element[] }) {
|
||||
export function OptionsMenu(props: { open: boolean; onClose: () => void; options: MapOptions; children?: JSX.Element | JSX.Element[] }) {
|
||||
return (
|
||||
<Menu title="User preferences" open={props.open} showBackButton={false} onClose={props.onClose}>
|
||||
<div
|
||||
73
frontend/react/src/ui/panels/radiomenu.tsx
Normal file
73
frontend/react/src/ui/panels/radiomenu.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Menu } from "./components/menu";
|
||||
import { OlCheckbox } from "../components/olcheckbox";
|
||||
import { OlRangeSlider } from "../components/olrangeslider";
|
||||
import { OlNumberInput } from "../components/olnumberinput";
|
||||
import { MapOptions } from "../../types/types";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { OlFrequencyInput } from "../components/olfrequencyinput";
|
||||
import { OlStateButton } from "../components/olstatebutton";
|
||||
import { faEarListen, faMicrophoneLines } from "@fortawesome/free-solid-svg-icons";
|
||||
import { OlLabelToggle } from "../components/ollabeltoggle";
|
||||
import { FaVolumeHigh } from "react-icons/fa6";
|
||||
|
||||
export function RadioMenu(props: { open: boolean; onClose: () => void; children?: JSX.Element | JSX.Element[] }) {
|
||||
const [frequency1, setFrequency1] = useState(124000000);
|
||||
const [ptt1, setPTT1] = useState(false);
|
||||
const [frequency2, setFrequency2] = useState(251000000);
|
||||
const [frequency3, setFrequency3] = useState(243000000);
|
||||
const [frequency4, setFrequency4] = useState(11200000);
|
||||
|
||||
useEffect(() => {
|
||||
if (getApp()) {
|
||||
let settings = getApp().getAudioManager().getRadioSettings();
|
||||
settings[0].frequency = frequency1;
|
||||
settings[0].ptt = ptt1;
|
||||
getApp().getAudioManager().setRadioSettings(settings);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Menu title="Radio" open={props.open} showBackButton={false} onClose={props.onClose}>
|
||||
<div
|
||||
className={`
|
||||
flex flex-col gap-2 p-5 font-normal text-gray-800
|
||||
dark:text-white
|
||||
`}
|
||||
>
|
||||
<div
|
||||
className={`
|
||||
flex flex-col content-center justify-between gap-2 rounded-md
|
||||
bg-olympus-200/30 py-3 pl-4 pr-5
|
||||
`}
|
||||
>
|
||||
Radio 1
|
||||
<OlFrequencyInput
|
||||
value={frequency1}
|
||||
onChange={(value) => {
|
||||
setFrequency1(value);
|
||||
}}
|
||||
/>
|
||||
<div className="flex gap-4 py-2">
|
||||
<FaVolumeHigh className="h-8 w-8 p-1" />
|
||||
<OlRangeSlider value={50} onChange={() => {}} className="my-auto" />
|
||||
<span className="my-auto">50</span>
|
||||
</div>
|
||||
<div className="flex flex-row gap-2">
|
||||
<OlLabelToggle leftLabel="AM" rightLabel="FM" toggled={false} onClick={() => {}}></OlLabelToggle>
|
||||
<OlStateButton
|
||||
className="ml-auto"
|
||||
checked={ptt1}
|
||||
icon={faMicrophoneLines}
|
||||
onClick={() => {
|
||||
setPTT1(!ptt1);
|
||||
}}
|
||||
tooltip="Talk on frequency"
|
||||
></OlStateButton>
|
||||
<OlStateButton checked={false} icon={faEarListen} onClick={() => {}} tooltip="Tune to radio"></OlStateButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import { OlStateButton } from "../components/olstatebutton";
|
||||
import { faGamepad, faRuler, faPencil, faEllipsisV, faCog, faQuestionCircle, faPlusSquare, faMagnifyingGlass, faPlaneDeparture } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faGamepad, faRuler, faPencil, faEllipsisV, faCog, faQuestionCircle, faPlusSquare, faMagnifyingGlass, faPlaneDeparture, faRadio } from "@fortawesome/free-solid-svg-icons";
|
||||
import { EventsConsumer } from "../../eventscontext";
|
||||
import { StateConsumer } from "../../statecontext";
|
||||
import { IDLE } from "../../constants/constants";
|
||||
@@ -58,6 +58,12 @@ export function SideBar() {
|
||||
icon={faPlaneDeparture}
|
||||
tooltip="Hide/show airbase menu"
|
||||
></OlStateButton>
|
||||
<OlStateButton
|
||||
onClick={events.toggleRadioMenuVisible}
|
||||
checked={appState.radioMenuVisible}
|
||||
icon={faRadio}
|
||||
tooltip="Hide/show radio menu"
|
||||
></OlStateButton>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-16 flex-wrap content-end justify-center p-4">
|
||||
|
||||
@@ -48,6 +48,7 @@ import { FaRadio } from "react-icons/fa6";
|
||||
import { OlNumberInput } from "../components/olnumberinput";
|
||||
import { Radio, TACAN } from "../../interfaces";
|
||||
import { OlStringInput } from "../components/olstringinput";
|
||||
import { OlFrequencyInput } from "../components/olfrequencyinput";
|
||||
|
||||
export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
|
||||
const [selectedUnits, setSelectedUnits] = useState([] as Unit[]);
|
||||
@@ -1112,71 +1113,12 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
|
||||
|
||||
<div className="text-sm text-gray-200">Radio frequency</div>
|
||||
<div className="flex content-center gap-2">
|
||||
<OlNumberInput
|
||||
min={1}
|
||||
max={400}
|
||||
onChange={(e) => {
|
||||
let newValue = Math.max(Math.min(Number(e.target.value), 400), 1) * 1000000;
|
||||
if (activeAdvancedSettings) {
|
||||
let decimalPart = activeAdvancedSettings.radio.frequency - Math.floor(activeAdvancedSettings.radio.frequency / 1000000) * 1000000;
|
||||
activeAdvancedSettings.radio.frequency = newValue + decimalPart;
|
||||
}
|
||||
<OlFrequencyInput value={activeAdvancedSettings? activeAdvancedSettings.radio.frequency: 124000000} onChange={(value) => {
|
||||
if (activeAdvancedSettings) {
|
||||
activeAdvancedSettings.radio.frequency = value;
|
||||
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
|
||||
}}
|
||||
onDecrease={() => {
|
||||
if (activeAdvancedSettings)
|
||||
activeAdvancedSettings.radio.frequency = Math.max(
|
||||
Math.min(Number(activeAdvancedSettings.radio.frequency - 1000000), 400000000),
|
||||
1000000
|
||||
);
|
||||
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
|
||||
}}
|
||||
onIncrease={() => {
|
||||
if (activeAdvancedSettings)
|
||||
activeAdvancedSettings.radio.frequency = Math.max(
|
||||
Math.min(Number(activeAdvancedSettings.radio.frequency + 1000000), 400000000),
|
||||
1000000
|
||||
);
|
||||
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
|
||||
}}
|
||||
value={activeAdvancedSettings ? Math.floor(activeAdvancedSettings.radio.frequency / 1000000) : 124}
|
||||
></OlNumberInput>
|
||||
<div className="my-auto">.</div>
|
||||
<OlNumberInput
|
||||
min={0}
|
||||
max={990}
|
||||
minLength={3}
|
||||
onChange={(e) => {
|
||||
let newValue = Math.max(Math.min(Number(e.target.value), 990), 0) * 1000;
|
||||
if (activeAdvancedSettings) {
|
||||
let integerPart = Math.floor(activeAdvancedSettings.radio.frequency / 1000000) * 1000000;
|
||||
activeAdvancedSettings.radio.frequency = newValue + integerPart;
|
||||
}
|
||||
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
|
||||
}}
|
||||
onDecrease={() => {
|
||||
if (activeAdvancedSettings)
|
||||
activeAdvancedSettings.radio.frequency = Math.max(
|
||||
Math.min(Number(activeAdvancedSettings.radio.frequency - 25000), 400000000),
|
||||
1000000
|
||||
);
|
||||
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
|
||||
}}
|
||||
onIncrease={() => {
|
||||
if (activeAdvancedSettings)
|
||||
activeAdvancedSettings.radio.frequency = Math.max(
|
||||
Math.min(Number(activeAdvancedSettings.radio.frequency + 25000), 400000000),
|
||||
1000000
|
||||
);
|
||||
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
|
||||
}}
|
||||
value={
|
||||
activeAdvancedSettings
|
||||
? (activeAdvancedSettings.radio.frequency - Math.floor(activeAdvancedSettings.radio.frequency / 1000000) * 1000000) / 1000
|
||||
: 0
|
||||
}
|
||||
></OlNumberInput>
|
||||
<div className="my-auto">MHz</div>
|
||||
}}/>
|
||||
</div>
|
||||
|
||||
<div className="flex pt-8">
|
||||
|
||||
@@ -9,7 +9,7 @@ import { SpawnMenu } from "./panels/spawnmenu";
|
||||
import { UnitControlMenu } from "./panels/unitcontrolmenu";
|
||||
import { MainMenu } from "./panels/mainmenu";
|
||||
import { SideBar } from "./panels/sidebar";
|
||||
import { Options } from "./panels/options";
|
||||
import { OptionsMenu } from "./panels/optionsmenu";
|
||||
import { MapHiddenTypes, MapOptions } from "../types/types";
|
||||
import { BLUE_COMMANDER, CONTEXT_ACTION, GAME_MASTER, IDLE, MAP_HIDDEN_TYPES_DEFAULTS, MAP_OPTIONS_DEFAULTS, RED_COMMANDER } from "../constants/constants";
|
||||
import { getApp, setupApp } from "../olympusapp";
|
||||
@@ -22,6 +22,7 @@ import { ControlsPanel } from "./panels/controlspanel";
|
||||
import { MapContextMenu } from "./contextmenus/mapcontextmenu";
|
||||
import { AirbaseMenu } from "./panels/airbasemenu";
|
||||
import { Airbase } from "../mission/airbase";
|
||||
import { RadioMenu } from "./panels/radiomenu";
|
||||
|
||||
export type OlympusUIState = {
|
||||
mainMenuVisible: boolean;
|
||||
@@ -42,6 +43,7 @@ export function UI() {
|
||||
const [unitControlMenuVisible, setUnitControlMenuVisible] = useState(false);
|
||||
const [measureMenuVisible, setMeasureMenuVisible] = useState(false);
|
||||
const [drawingMenuVisible, setDrawingMenuVisible] = useState(false);
|
||||
const [radioMenuVisible, setRadioMenuVisible] = useState(false);
|
||||
const [optionsMenuVisible, setOptionsMenuVisible] = useState(false);
|
||||
const [airbaseMenuVisible, setAirbaseMenuVisible] = useState(false);
|
||||
const [mapHiddenTypes, setMapHiddenTypes] = useState(MAP_HIDDEN_TYPES_DEFAULTS);
|
||||
@@ -97,6 +99,7 @@ export function UI() {
|
||||
setDrawingMenuVisible(false);
|
||||
setOptionsMenuVisible(false);
|
||||
setAirbaseMenuVisible(false);
|
||||
setRadioMenuVisible(false);
|
||||
}
|
||||
|
||||
function checkPassword(password: string) {
|
||||
@@ -153,6 +156,7 @@ export function UI() {
|
||||
drawingMenuVisible: drawingMenuVisible,
|
||||
optionsMenuVisible: optionsMenuVisible,
|
||||
airbaseMenuVisible: airbaseMenuVisible,
|
||||
radioMenuVisible: radioMenuVisible,
|
||||
mapOptions: mapOptions,
|
||||
mapHiddenTypes: mapHiddenTypes,
|
||||
mapSources: mapSources,
|
||||
@@ -169,6 +173,7 @@ export function UI() {
|
||||
setMeasureMenuVisible: setMeasureMenuVisible,
|
||||
setOptionsMenuVisible: setOptionsMenuVisible,
|
||||
setAirbaseMenuVisible: setAirbaseMenuVisible,
|
||||
setRadioMenuVisible: setRadioMenuVisible,
|
||||
toggleMainMenuVisible: () => {
|
||||
hideAllMenus();
|
||||
setMainMenuVisible(!mainMenuVisible);
|
||||
@@ -197,6 +202,10 @@ export function UI() {
|
||||
hideAllMenus();
|
||||
setAirbaseMenuVisible(!airbaseMenuVisible);
|
||||
},
|
||||
toggleRadioMenuVisible: () => {
|
||||
hideAllMenus();
|
||||
setRadioMenuVisible(!radioMenuVisible);
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Header />
|
||||
@@ -227,10 +236,11 @@ export function UI() {
|
||||
<div id="map-container" className="z-0 h-full w-screen" />
|
||||
<MainMenu open={mainMenuVisible} onClose={() => setMainMenuVisible(false)} />
|
||||
<SpawnMenu open={spawnMenuVisible} onClose={() => setSpawnMenuVisible(false)} />
|
||||
<Options open={optionsMenuVisible} onClose={() => setOptionsMenuVisible(false)} options={mapOptions} />
|
||||
<OptionsMenu open={optionsMenuVisible} onClose={() => setOptionsMenuVisible(false)} options={mapOptions} />
|
||||
<UnitControlMenu open={unitControlMenuVisible} onClose={() => setUnitControlMenuVisible(false)} />
|
||||
<DrawingMenu open={drawingMenuVisible} onClose={() => setDrawingMenuVisible(false)} />
|
||||
<AirbaseMenu open={airbaseMenuVisible} onClose={() => setAirbaseMenuVisible(false)} airbase={airbase}/>
|
||||
<RadioMenu open={radioMenuVisible} onClose={() => setRadioMenuVisible(false)} />
|
||||
|
||||
<MiniMapPanel />
|
||||
<ControlsPanel />
|
||||
|
||||
Reference in New Issue
Block a user