Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 69 additions & 74 deletions src/component/hooks/useCheckToolsVisibility.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { Info1D, Info2D } from '@zakodium/nmr-types';
import { useCallback } from 'react';

import { useChartData } from '../context/ChartContext.js';
Expand All @@ -7,102 +6,98 @@ import type { MainTool, ToolOptionItem } from '../toolbar/ToolTypes.js';
import { options } from '../toolbar/ToolTypes.js';

import useCheckExperimentalFeature from './useCheckExperimentalFeature.js';
import useSpectrum from './useSpectrum.js';
import { useSelectedSpectra } from './useSelectedSpectra.ts';
import useSpectraByActiveNucleus from './useSpectraPerNucleus.ts';

type SpectrumInfo = Info1D | Info2D;

export interface CheckOptions {
checkSpectrumType?: boolean;
checkMode?: boolean;
extraInfoCheckParameters?: SpectrumInfo;
}

export function useCheckToolsVisibility(): (
toolKey: MainTool,
checkOptions?: CheckOptions,
) => boolean {
export function useCheckToolsVisibility(): (toolKey: MainTool) => boolean {
const { displayerMode } = useChartData();
const preferences = usePreferences();
const spectrum = useSpectrum(null);
const selectedSpectra = useSelectedSpectra();
const spectra = useSpectraByActiveNucleus();
const isExperimentalFeatureActivated = useCheckExperimentalFeature();
const toolBarButtons = preferences?.current?.display?.toolBarButtons;

return useCallback(
(toolKey: MainTool, checkOptions: CheckOptions = {}) => {
(toolKey: MainTool): boolean => {
const {
checkMode = true,
checkSpectrumType = true,
extraInfoCheckParameters,
} = checkOptions;

const { spectraOptions, mode, isExperimental } = options[toolKey];
spectraFilter,
spectraMatch = 'all',
selectedSpectra: selectionRules = { min: 1, max: 1 },
mode,
isExperimental,
} = options[toolKey];

// TODO: make sure preferences are not a lie and remove the optional chaining.
const flag =
preferences?.current?.display?.toolBarButtons?.[toolKey] ?? false;

const modeFlag =
!checkMode || (checkMode && (!mode || displayerMode === mode));

const spectrumCheckFlag =
!checkSpectrumType ||
(checkSpectrumType && checkSpectrum(spectrum, spectraOptions));
// 1. Tool status
const flag = toolBarButtons?.[toolKey] ?? false;

const isToolActivated =
(flag && !isExperimental) ||
(isExperimental && isExperimentalFeatureActivated);
return !!(
isToolActivated &&
modeFlag &&
spectrumCheckFlag &&
(!extraInfoCheckParameters ||
checkInfo(extraInfoCheckParameters, spectrum?.info))
);
},

[displayerMode, isExperimentalFeatureActivated, preferences, spectrum],
);
}
if (!isToolActivated) return false;

function checkSpectrum(
spectrum: any,
options: ToolOptionItem['spectraOptions'],
) {
let outerConditionResult = false;
// 2. Mode check
if (mode && displayerMode !== mode) return false;

if (!options) {
return true;
}
// 3. No spectra rules, always visible
if (!spectraFilter) return true;

// 4. Resolve spectra source
const spectraToCheck =
selectedSpectra && selectedSpectra.length > 0
? selectedSpectra
: spectra;

for (const option of options) {
let innerConditionFlag = true;
// 5. Selection constraints
if (selectionRules) {
const { min, max } = selectionRules;

if (option.active) {
if (spectrum) {
for (const { key, value } of option.info || []) {
if (spectrum.info[key] !== value) {
innerConditionFlag = false;
}
if (typeof min === 'number' && spectraToCheck.length < min) {
return false;
}

if (typeof max === 'number' && spectraToCheck.length > max) {
return false;
}
} else {
innerConditionFlag = false;
}
}

outerConditionResult = outerConditionResult || innerConditionFlag;
}
// 6. Evaluate spectra filters
const matchCount = spectraToCheck.filter((spectrum) =>
checkSpectrum(spectrum, spectraFilter),
).length;

return outerConditionResult;
// 7. Match strategy
if (spectraMatch === 'any') {
return matchCount > 0;
}

return matchCount === spectraToCheck.length;
},
[
displayerMode,
isExperimentalFeatureActivated,
toolBarButtons,
selectedSpectra,
spectra,
],
);
}

function checkInfo(checkParameters: SpectrumInfo, data: SpectrumInfo) {
for (const key in checkParameters) {
if (
checkParameters[key as keyof SpectrumInfo] !==
data[key as keyof SpectrumInfo]
) {
return false;
}
function checkSpectrum(
spectrum: any,
spectraFilter: ToolOptionItem['spectraFilter'],
): boolean {
if (!spectraFilter) return true;

for (const option of spectraFilter) {
if (!spectrum) continue;

const infoConditionsMet = (option.info ?? []).every(
({ key, value }) => spectrum.info[key] === value,
);

if (infoConditionsMet) return true;
}

return true;
return false;
}
9 changes: 2 additions & 7 deletions src/component/toolbar/ToolBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import { ToolbarPopoverItem } from '../elements/ToolbarPopoverItem.js';
import { useExportManagerAPI } from '../elements/export/ExportManager.js';
import { useActiveSpectrum } from '../hooks/useActiveSpectrum.js';
import useCheckExperimentalFeature from '../hooks/useCheckExperimentalFeature.js';
import type { CheckOptions } from '../hooks/useCheckToolsVisibility.js';
import { useCheckToolsVisibility } from '../hooks/useCheckToolsVisibility.js';
import useDatumWithSpectraStatistics from '../hooks/useDatumWithSpectraStatistics.js';
import { useDialogToggle } from '../hooks/useDialogToggle.js';
Expand All @@ -58,7 +57,6 @@ import { EXPORT_MENU, IMPORT_MENU } from './toolbarMenu.js';

interface BaseToolItem extends Pick<ToolbarItemProps, 'icon' | 'disabled'> {
id: MainTool;
checkOptions?: CheckOptions;
isVisible?: boolean;
}
interface ToolItem extends BaseToolItem {
Expand Down Expand Up @@ -303,7 +301,6 @@ export default function ToolBar() {
'Integrate multiple spectra at once and adjust integration zones by dragging their edges.',
},
icon: <SvgNmrMultipleAnalysis />,
checkOptions: { checkSpectrumType: false },
isVisible: ftCounter > 0,
},
{
Expand Down Expand Up @@ -398,7 +395,6 @@ export default function ToolBar() {
description: `Define exclusion zones by clicking, dragging, releasing${!invert ? ' while holding SHIFT' : ''}. This option is practical for excluding large peaks like solvents.`,
},
icon: <SvgNmrMultipleAnalysis />,
checkOptions: { checkSpectrumType: false },
isVisible: ftCounter > 0,
},
{
Expand Down Expand Up @@ -510,10 +506,9 @@ export default function ToolBar() {
<SaveAsModal isOpen={dialog.saveAs} onCloseDialog={closeDialog} />
<Toolbar vertical>
{toolItems.map((item) => {
const { id, icon, tooltip, checkOptions, disabled, isVisible } = item;
const { id, icon, tooltip, disabled, isVisible } = item;
const isToolVisible =
isButtonVisible(id, checkOptions) &&
(isVisible === undefined || isVisible);
isButtonVisible(id) && (isVisible === undefined || isVisible);

if (!isToolVisible) return null;

Expand Down
Loading
Loading