From 02ee2f8107f4af15dbd186c12ab7b2518c825089 Mon Sep 17 00:00:00 2001 From: hamed-musallam <35760236+hamed-musallam@users.noreply.github.com> Date: Fri, 17 Jan 2025 12:43:25 +0100 Subject: [PATCH] feat: fill chemical shift input by using the cursor on the spectrum (#3334) --- .../editRange/forms/components/DeltaInput.tsx | 30 +++++++++- .../forms/components/SignalsContent.tsx | 60 ++++++++++++++++--- .../signal-tabs/SignalJCouplingsTable.tsx | 10 +++- .../signal-tabs/SignalPeaksTable.tsx | 10 +++- 4 files changed, 96 insertions(+), 14 deletions(-) diff --git a/src/component/modal/editRange/forms/components/DeltaInput.tsx b/src/component/modal/editRange/forms/components/DeltaInput.tsx index 618102e6f..cc5de6e75 100644 --- a/src/component/modal/editRange/forms/components/DeltaInput.tsx +++ b/src/component/modal/editRange/forms/components/DeltaInput.tsx @@ -1,7 +1,10 @@ import { translateMultiplet } from 'nmr-processing'; -import { useFormContext } from 'react-hook-form'; +import { useFormContext, useWatch } from 'react-hook-form'; import { NumberInput2Controller } from '../../../../elements/NumberInput2Controller.js'; +import { useEvent } from '../../../../utility/Events.js'; + +import { useEventFocusInput } from './SignalsContent.js'; interface DeltaInputProps { signal: any; @@ -16,8 +19,30 @@ export function DeltaInput({ signal, index }: DeltaInputProps) { const { control, formState: { errors }, + setValue, } = useFormContext(); const isNotValid = hasError(errors, index); + const { signalIndex } = useWatch(); + const { focusSource, setFocusSource } = useEventFocusInput(); + + useEvent({ + onClick: ({ xPPM, shiftKey }) => { + if (index === signalIndex && shiftKey && focusSource === 'delta') { + setValue(`signals.${index}.delta`, xPPM); + } + }, + onBrushEnd: (options) => { + const { + range: [from, to], + shiftKey, + } = options; + if (index === signalIndex && shiftKey && focusSource === 'delta') { + const delta = (to - from) / 2 + from; + setValue(`signals.${index}.delta`, delta); + } + }, + }); + return (
{ + setFocusSource('delta'); + }} /> {signal.js diff --git a/src/component/modal/editRange/forms/components/SignalsContent.tsx b/src/component/modal/editRange/forms/components/SignalsContent.tsx index 28d66a630..e5f875ab8 100644 --- a/src/component/modal/editRange/forms/components/SignalsContent.tsx +++ b/src/component/modal/editRange/forms/components/SignalsContent.tsx @@ -1,7 +1,15 @@ /** @jsxImportSource @emotion/react */ import { Tab, Tabs } from '@blueprintjs/core'; import type { Range } from 'nmr-processing'; -import { memo, useCallback, useEffect, useMemo } from 'react'; +import { + createContext, + memo, + useCallback, + useContext, + useEffect, + useMemo, + useState, +} from 'react'; import { useFormContext, useWatch } from 'react-hook-form'; import { FaPlus } from 'react-icons/fa'; @@ -16,6 +24,38 @@ interface SignalsFormProps { range: Range; } +type FocusSource = 'peak' | 'coupling' | 'delta' | null; +interface FocusInputContextState { + focusSource: 'peak' | 'coupling' | 'delta' | null; + setFocusSource: (source: FocusSource) => void; +} + +const FocusInputContext = createContext(null); + +export function useEventFocusInput() { + const context = useContext(FocusInputContext); + + if (!context) { + throw new Error('FocusInputContext was not found.'); + } + + return context; +} + +function FocusInputProvider({ children }) { + const [focusSource, setFocusSource] = useState(null); + + const state = useMemo(() => { + return { focusSource, setFocusSource }; + }, [focusSource]); + + return ( + + {children} + + ); +} + function SignalsContent({ range }: SignalsFormProps) { const { setValue } = useFormContext(); const { signals, signalIndex } = useWatch(); @@ -78,14 +118,16 @@ function SignalsContent({ range }: SignalsFormProps) { return (
- tapClickHandler(id)} - animate={false} - > - {signalFormTabs} - + + tapClickHandler(id)} + animate={false} + > + {signalFormTabs} + +
); } diff --git a/src/component/modal/editRange/forms/components/signal-tabs/SignalJCouplingsTable.tsx b/src/component/modal/editRange/forms/components/signal-tabs/SignalJCouplingsTable.tsx index de3dc6eeb..6b0da60bb 100644 --- a/src/component/modal/editRange/forms/components/signal-tabs/SignalJCouplingsTable.tsx +++ b/src/component/modal/editRange/forms/components/signal-tabs/SignalJCouplingsTable.tsx @@ -17,6 +17,7 @@ import { Select2Controller } from '../../../../../elements/Select2Controller.js' import useSpectrum from '../../../../../hooks/useSpectrum.js'; import { hasCouplingConstant } from '../../../../../panels/extra/utilities/MultiplicityUtilities.js'; import { useEvent } from '../../../../../utility/Events.js'; +import { useEventFocusInput } from '../SignalsContent.js'; const styles: Record<'input' | 'select' | 'column', CSSProperties> = { input: { @@ -49,6 +50,8 @@ function getCouplingMinErrorMessage(errors, index) { } export function SignalJCouplingsTable(props: SignalJCouplingsTableProps) { + const { focusSource, setFocusSource } = useEventFocusInput(); + const { setValue, control, @@ -67,7 +70,8 @@ export function SignalJCouplingsTable(props: SignalJCouplingsTableProps) { if ( props.index === signalIndex && typeof lastSelectedCouplingIndexRef.current === 'number' && - shiftKey + shiftKey && + focusSource === 'coupling' ) { setValue( getJCouplingKey( @@ -89,7 +93,8 @@ export function SignalJCouplingsTable(props: SignalJCouplingsTableProps) { props.index === signalIndex && typeof lastSelectedCouplingIndexRef.current === 'number' && shiftKey && - isSpectrum1D(spectrum) + isSpectrum1D(spectrum) && + focusSource === 'coupling' ) { const value = Math.abs(to - from) * spectrum.info.originFrequency; @@ -218,6 +223,7 @@ export function SignalJCouplingsTable(props: SignalJCouplingsTableProps) { ); function selectRowHandler(index) { + setFocusSource('coupling'); lastSelectedCouplingIndexRef.current = index; } diff --git a/src/component/modal/editRange/forms/components/signal-tabs/SignalPeaksTable.tsx b/src/component/modal/editRange/forms/components/signal-tabs/SignalPeaksTable.tsx index f6a8e6def..9652b3563 100644 --- a/src/component/modal/editRange/forms/components/signal-tabs/SignalPeaksTable.tsx +++ b/src/component/modal/editRange/forms/components/signal-tabs/SignalPeaksTable.tsx @@ -15,6 +15,7 @@ import type { Column } from '../../../../../elements/ReactTable/ReactTable.js'; import ReactTable from '../../../../../elements/ReactTable/ReactTable.js'; import useSpectrum from '../../../../../hooks/useSpectrum.js'; import { useEvent } from '../../../../../utility/Events.js'; +import { useEventFocusInput } from '../SignalsContent.js'; const styles: Record<'input' | 'column', CSSProperties> = { input: { @@ -41,6 +42,8 @@ function getPeakKey(signalIndex: number, peakIndex, key?: keyof Peak1D) { } export function SignalPeaksTable(props: SignalPeaksTableProps) { + const { focusSource, setFocusSource } = useEventFocusInput(); + const { setValue, control, setFocus } = useFormContext(); const { signals, signalIndex } = useWatch(); const signal = signals?.[signalIndex] || {}; @@ -57,7 +60,8 @@ export function SignalPeaksTable(props: SignalPeaksTableProps) { if ( props.index === signalIndex && typeof lastSelectedPeakIndexRef.current === 'number' && - shiftKey + shiftKey && + focusSource === 'peak' ) { const delta = xPPM; const xIndex = xFindClosestIndex(xArray, delta, { sorted: false }); @@ -77,7 +81,8 @@ export function SignalPeaksTable(props: SignalPeaksTableProps) { if ( props.index === signalIndex && typeof lastSelectedPeakIndexRef.current === 'number' && - shiftKey + shiftKey && + focusSource === 'peak' ) { const delta = (to - from) / 2 + from; @@ -206,6 +211,7 @@ export function SignalPeaksTable(props: SignalPeaksTableProps) { ); function selectRowHandler(index) { + setFocusSource('peak'); lastSelectedPeakIndexRef.current = index; setFocus(`signals.${signalIndex}.peaks.${index}.x`, { shouldSelect: true }); }