ohif-viewer/extensions/default/src/ViewerLayout/index.jsx

245 lines
7.1 KiB
React
Raw Normal View History

import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import {
SidePanel,
ErrorBoundary,
UserPreferences,
AboutModal,
Header,
useModal,
} from '@ohif/ui';
import i18n from '@ohif/i18n';
import { hotkeys } from '@ohif/core';
const { availableLanguages, defaultLanguage, currentLanguage } = i18n;
import { useAppConfig } from '@state';
function Toolbar({ servicesManager }) {
2020-05-19 11:01:44 +02:00
const { ToolBarService } = servicesManager.services;
const [toolbarButtons, setToolbarButtons] = useState([]);
const [buttonState, setButtonState] = useState({
primaryToolId: '',
toggles: {},
groups: {},
});
// Could track buttons and state separately...?
useEffect(() => {
const { unsubscribe: unsub1 } = ToolBarService.subscribe(
ToolBarService.EVENTS.TOOL_BAR_MODIFIED,
() => setToolbarButtons(ToolBarService.getButtonSection('primary'))
);
const { unsubscribe: unsub2 } = ToolBarService.subscribe(
ToolBarService.EVENTS.TOOL_BAR_STATE_MODIFIED,
() => setButtonState({ ...ToolBarService.state })
);
2020-05-15 19:07:21 +02:00
return () => {
unsub1();
unsub2();
};
}, [ToolBarService]);
2020-05-15 19:07:21 +02:00
return (
<>
{toolbarButtons.map((toolDef, index) => {
const { id, Component, componentProps } = toolDef;
// TODO: ...
// isActive if:
// - id is primary?
// - id is in list of "toggled on"?
let isActive;
if (componentProps.type === 'toggle') {
isActive = buttonState.toggles[id];
}
// Also need... to filter list for splitButton, and set primary based on most recently clicked
// Also need to kill the radioGroup button's magic logic
// Everything should be reactive off these props, so commands can inform ToolbarService
// These can... Trigger toolbar events based on updates?
// Then sync using useEffect, or simply modify the state here?
return (
<Component
key={id}
id={id}
{...componentProps}
bState={buttonState}
isActive={isActive}
onInteraction={args => ToolBarService.recordInteraction(args)}
/>
);
})}
</>
);
}
function ViewerLayout({
// From Extension Module Params
extensionManager,
servicesManager,
hotkeysManager,
commandsManager,
// From Modes
leftPanels,
rightPanels,
viewports,
ViewportGridComp,
}) {
const [appConfig] = useAppConfig();
const { t } = useTranslation();
const { show, hide } = useModal();
const { hotkeyDefinitions, hotkeyDefaults } = hotkeysManager;
const menuOptions = [
{
title: t('Header:About'),
icon: 'info',
onClick: () => show({ content: AboutModal, title: 'About OHIF Viewer' }),
},
{
title: t('Header:Preferences'),
icon: 'settings',
onClick: () =>
show({
title: t('UserPreferencesModal:User Preferences'),
content: UserPreferences,
contentProps: {
hotkeyDefaults: hotkeysManager.getValidHotkeyDefinitions(
hotkeyDefaults
),
hotkeyDefinitions,
currentLanguage: currentLanguage(),
availableLanguages,
defaultLanguage,
onCancel: () => {
hotkeys.stopRecord();
hotkeys.unpause();
hide();
},
onSubmit: ({ hotkeyDefinitions, language }) => {
i18n.changeLanguage(language.value);
hotkeysManager.setHotkeys(hotkeyDefinitions);
hide();
},
onReset: () => hotkeysManager.restoreDefaultBindings(),
},
}),
},
];
/**
* Set body classes (tailwindcss) that don't allow vertical
* or horizontal overflow (no scrolling). Also guarantee window
* is sized to our viewport.
*/
useEffect(() => {
document.body.classList.add('bg-black');
document.body.classList.add('overflow-hidden');
return () => {
document.body.classList.remove('bg-black');
document.body.classList.remove('overflow-hidden');
};
}, []);
const getPanelData = id => {
const entry = extensionManager.getModuleEntry(id);
// TODO, not sure why sidepanel content has to be JSX, and not a children prop?
const content = entry.component;
return {
iconName: entry.iconName,
iconLabel: entry.iconLabel,
label: entry.label,
name: entry.name,
content,
};
};
const getViewportComponentData = viewportComponent => {
const entry = extensionManager.getModuleEntry(viewportComponent.namespace);
return {
component: entry.component,
displaySetsToDisplay: viewportComponent.displaySetsToDisplay,
};
};
2020-05-19 11:01:44 +02:00
const leftPanelComponents = leftPanels.map(getPanelData);
const rightPanelComponents = rightPanels.map(getPanelData);
const viewportComponents = viewports.map(getViewportComponentData);
return (
<div>
<Header menuOptions={menuOptions} WhiteLabeling={appConfig.whiteLabeling} >
2020-06-26 19:08:29 +02:00
<ErrorBoundary context="Primary Toolbar">
<div className="relative flex justify-center">
<Toolbar servicesManager={servicesManager} />
2020-06-26 19:08:29 +02:00
</div>
</ErrorBoundary>
</Header>
<div
className="flex flex-row flex-no-wrap items-stretch w-full overflow-hidden"
fix/chore: Various style improvements (#2015) * Update all the icons * Turn off global tool sync; watch as the world burns * Shift a bunch of things around so we can start tracking/setting per element * ToolBarService to initiate one of three different calls; callback passed to all button types * SplitButton and Toolbar Button to use new `onInteraction` prop and new toolbar state * Changes to toolbar button interface and config * Fix broken layout selector * Update SR viewport to activate tools in viewport component * Duplicate activation logic in measurement tracking extension * Add alternative/dashed variants for SR Viewport * pass through "setToolActive" commands for other viewport types * fix small overlay bugs (no wwwc or scale info) * Show SpacingBetweenSlices instead of PixelSpacing in patient information dialog * Fix prop-types * Update tracked viewport to have alternative tracked styling * alt styling for SR viewports * Update to support isLocked + isRehydratable * fix broken logic * fix broken logic * switch icon style * fix icon styles * hover and click to start flow * expedited workflow when data is not dirty (just after SR hydration) * fix: setting elliptical roi tool * fix arrow annotate dialog * fix: do not show learn more button for now * remove dead code * simpler cache invalidation * simpler cache invalidation part 2 * Fix for unable to spand study cards on separate pages * fix: viewport grid area top padding should align with sidepanel gap * fix: don't wrap split button list item text * fix: cine player moz/chrome styles * fix: split button arrows * fix: tighten toolbar and splitbutton styles * chore: clean up worklist sort logic
2020-09-21 10:42:53 +02:00
style={{ height: 'calc(100vh - 52px' }}
>
2020-05-15 04:55:17 +02:00
{/* LEFT SIDEPANELS */}
{leftPanelComponents.length && (
2020-06-26 19:08:29 +02:00
<ErrorBoundary context="Left Panel">
<SidePanel
side="left"
defaultComponentOpen={leftPanelComponents[0].name}
childComponents={leftPanelComponents}
/>
</ErrorBoundary>
)}
2020-05-15 04:55:17 +02:00
{/* TOOLBAR + GRID */}
<div className="flex flex-col flex-1 h-full">
fix/chore: Various style improvements (#2015) * Update all the icons * Turn off global tool sync; watch as the world burns * Shift a bunch of things around so we can start tracking/setting per element * ToolBarService to initiate one of three different calls; callback passed to all button types * SplitButton and Toolbar Button to use new `onInteraction` prop and new toolbar state * Changes to toolbar button interface and config * Fix broken layout selector * Update SR viewport to activate tools in viewport component * Duplicate activation logic in measurement tracking extension * Add alternative/dashed variants for SR Viewport * pass through "setToolActive" commands for other viewport types * fix small overlay bugs (no wwwc or scale info) * Show SpacingBetweenSlices instead of PixelSpacing in patient information dialog * Fix prop-types * Update tracked viewport to have alternative tracked styling * alt styling for SR viewports * Update to support isLocked + isRehydratable * fix broken logic * fix broken logic * switch icon style * fix icon styles * hover and click to start flow * expedited workflow when data is not dirty (just after SR hydration) * fix: setting elliptical roi tool * fix arrow annotate dialog * fix: do not show learn more button for now * remove dead code * simpler cache invalidation * simpler cache invalidation part 2 * Fix for unable to spand study cards on separate pages * fix: viewport grid area top padding should align with sidepanel gap * fix: don't wrap split button list item text * fix: cine player moz/chrome styles * fix: split button arrows * fix: tighten toolbar and splitbutton styles * chore: clean up worklist sort logic
2020-09-21 10:42:53 +02:00
<div className="flex items-center justify-center flex-1 h-full -mt-1 overflow-hidden bg-black">
2020-06-26 19:08:29 +02:00
<ErrorBoundary context="Grid">
<ViewportGridComp
servicesManager={servicesManager}
viewportComponents={viewportComponents}
commandsManager={commandsManager}
2020-06-26 19:08:29 +02:00
/>
</ErrorBoundary>
</div>
</div>
{rightPanelComponents.length && (
2020-06-26 19:08:29 +02:00
<ErrorBoundary context="Right Panel">
<SidePanel
side="right"
defaultComponentOpen={rightPanelComponents[0].name}
childComponents={rightPanelComponents}
/>
</ErrorBoundary>
)}
</div>
</div>
);
}
ViewerLayout.propTypes = {
// From extension module params
extensionManager: PropTypes.shape({
getModuleEntry: PropTypes.func.isRequired,
}).isRequired,
commandsManager: PropTypes.object,
// From modes
leftPanels: PropTypes.array,
rightPanels: PropTypes.array,
/** Responsible for rendering our grid of viewports; provided by consuming application */
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
};
ViewerLayout.defaultProps = {
leftPanels: [],
rightPanels: [],
};
export default ViewerLayout;