Fix/update branch cherry pick (#2039)

* 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
This commit is contained in:
Danny Brown authored and GitHub committed 2020-09-14 21:18:46 -04:00
1 parent 365ba2fa72
commit cae54b0779
78 files changed
+1678 -1263

No files matched your search

@@ -29,8 +29,7 @@ function LayoutSelector() {
};
}, []);
const onClickHandler = () => setIsOpen(!isOpen);
const onInteractionHandler = () => setIsOpen(!isOpen);
const DropdownContent = isOpen ? OHIFLayoutSelector : null;
return (
@@ -38,7 +37,7 @@ function LayoutSelector() {
id="Layout"
label="Grid Layout"
icon="tool-layout"
onClick={onClickHandler}
onInteraction={onInteractionHandler}
dropdownContent={
DropdownContent !== null && (
<DropdownContent
@@ -0,0 +1,3 @@
import { SplitButton } from '@ohif/ui';
export default SplitButton;
+69 -145
View File
@@ -1,141 +1,69 @@
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 {
SidePanel,
ErrorBoundary,
UserPreferences,
AboutModal,
Header,
useModal,
} from '@ohif/ui';
import NestedMenu from './ToolbarButtonNestedMenu.jsx';
// TODO: Having ToolbarPrimary and ToolbarSecondary is ugly, but
// these are going to be unified shortly so this is good enough for now.
function ToolbarPrimary({ servicesManager }) {
function Toolbar({ servicesManager }) {
const { ToolBarService } = servicesManager.services;
const defaultTool = {
icon: 'tool-more-menu',
label: 'More',
isActive: false,
};
const [toolbars, setToolbars] = useState({ primary: [], secondary: [] });
const [activeTool, setActiveTool] = useState(defaultTool);
const setActiveToolHandler = (tool, isNested) => {
setActiveTool(isNested ? tool : defaultTool);
};
const onPrimaryClickHandler = (evt, btn) => {
if (
btn.props &&
btn.props.commands &&
evt.value &&
btn.props.commands[evt.value]
) {
const { commandName, commandOptions } = btn.props.commands[evt.value];
commandsManager.runCommand(commandName, commandOptions);
}
};
const [toolbarButtons, setToolbarButtons] = useState([]);
const [buttonState, setButtonState] = useState({
primaryToolId: '',
toggles: {},
groups: {},
});
// Could track buttons and state separately...?
useEffect(() => {
const { unsubscribe } = ToolBarService.subscribe(
const { unsubscribe: unsub1 } = ToolBarService.subscribe(
ToolBarService.EVENTS.TOOL_BAR_MODIFIED,
() => {
console.warn('~~~ TOOL BAR MODIFIED EVENT CAUGHT');
const updatedToolbars = {
primary: ToolBarService.getButtonSection('primary', {
onClick: onPrimaryClickHandler,
setActiveTool: setActiveToolHandler,
}),
secondary: ToolBarService.getButtonSection('secondary', {
setActiveTool: setActiveToolHandler,
}),
};
setToolbars(updatedToolbars);
}
() => setToolbarButtons(ToolBarService.getButtonSection('primary'))
);
const { unsubscribe: unsub2 } = ToolBarService.subscribe(
ToolBarService.EVENTS.TOOL_BAR_STATE_MODIFIED,
() => setButtonState({ ...ToolBarService.state })
);
return unsubscribe;
return () => {
unsub1();
unsub2();
};
}, [ToolBarService]);
return <>
{toolbars.primary.map((toolDef, index) => {
const isNested = Array.isArray(toolDef);
if (!isNested) {
return (
<>
{toolbarButtons.map((toolDef, index) => {
const { id, Component, componentProps } = toolDef;
return <Component key={id} id={id} {...componentProps} />;
} else {
// TODO: ...
// isActive if:
// - id is primary?
// - id is in list of "toggled on"?
// 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 (
<NestedMenu
key={index}
isActive={activeTool.isActive}
icon={activeTool.icon}
label={activeTool.label}
>
<div className="flex">
{toolDef.map(x => {
const { id, Component, componentProps } = x;
return (
<Component key={id} id={id} {...componentProps} />
);
})}
</div>
</NestedMenu>
<Component
key={id}
id={id}
{...componentProps}
bState={buttonState}
onInteraction={args => ToolBarService.recordInteraction(args)}
/>
);
}
})}
</>
}
function ToolbarSecondary({ servicesManager }) {
const { ToolBarService } = servicesManager.services;
const defaultTool = {
icon: 'tool-more-menu',
label: 'More',
isActive: false,
};
const [toolbars, setToolbars] = useState({ primary: [], secondary: [] });
const [nestedActiveTool, setNestedActiveTool] = useState(defaultTool);
const setActiveToolHandler = (tool, isNested) => {
setNestedActiveTool(isNested ? tool : defaultTool);
};
const onPrimaryClickHandler = (evt, btn) => {
if (
btn.props &&
btn.props.commands &&
evt.item && evt.item.value &&
btn.props.commands[evt.item.value]
) {
const { commandName, commandOptions } = btn.props.commands[evt.item.value];
commandsManager.runCommand(commandName, commandOptions);
}
};
useEffect(() => {
const { unsubscribe } = ToolBarService.subscribe(
ToolBarService.EVENTS.TOOL_BAR_MODIFIED,
() => {
console.warn('~~~ TOOL BAR MODIFIED EVENT CAUGHT');
const updatedToolbars = {
primary: ToolBarService.getButtonSection('primary', {
onClick: onPrimaryClickHandler,
setActiveTool: setActiveToolHandler,
}),
secondary: ToolBarService.getButtonSection('secondary', {
setActiveTool: setActiveToolHandler,
}),
};
setToolbars(updatedToolbars);
}
);
return unsubscribe;
}, [ToolBarService]);
return <>
{toolbars.secondary.map(toolDef => {
const { id, Component, componentProps } = toolDef;
return <Component key={id} id={id} {...componentProps} />;
})}
</>
})}
</>
);
}
function ViewerLayout({
@@ -158,25 +86,28 @@ function ViewerLayout({
{
title: t('Header:About'),
icon: 'info',
onClick: () => show({ content: AboutModal, title: 'About OHIF Viewer' })
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,
onCancel: hide,
onSubmit: ({ hotkeyDefinitions }) => {
hotkeysManager.setHotkeys(hotkeyDefinitions);
hide();
onClick: () =>
show({
title: t('UserPreferencesModal:User Preferences'),
content: UserPreferences,
contentProps: {
hotkeyDefaults: hotkeysManager.getValidHotkeyDefinitions(
hotkeyDefaults
),
hotkeyDefinitions,
onCancel: hide,
onSubmit: ({ hotkeyDefinitions }) => {
hotkeysManager.setHotkeys(hotkeyDefinitions);
hide();
},
onReset: () => hotkeysManager.restoreDefaultBindings(),
},
onReset: () => hotkeysManager.restoreDefaultBindings()
}
})
}),
},
];
@@ -226,7 +157,7 @@ function ViewerLayout({
<Header menuOptions={menuOptions}>
<ErrorBoundary context="Primary Toolbar">
<div className="relative flex justify-center">
<ToolbarPrimary servicesManager={servicesManager} />
<Toolbar servicesManager={servicesManager} />
</div>
</ErrorBoundary>
</Header>
@@ -246,13 +177,6 @@ function ViewerLayout({
)}
{/* TOOLBAR + GRID */}
<div className="flex flex-col flex-1 h-full">
<div className="flex h-12 border-b border-transparent flex-2 w-100">
<ErrorBoundary context="Secondary Toolbar">
<div className="flex items-center w-full px-3 bg-primary-dark">
<ToolbarSecondary servicesManager={servicesManager} />
</div>
</ErrorBoundary>
</div>
<div className="flex items-center justify-center flex-1 h-full pt-1 pb-2 overflow-hidden bg-black">
<ErrorBoundary context="Grid">
<ViewportGridComp
+10 -47
View File
@@ -1,6 +1,7 @@
import { ToolbarButton } from '@ohif/ui';
import ToolbarDivider from './Toolbar/ToolbarDivider.jsx';
import ToolbarLayoutSelector from './Toolbar/ToolbarLayoutSelector.jsx';
import ToolbarSplitButton from './Toolbar/ToolbarSplitButton.jsx';
export default function getToolbarModule({ commandsManager, servicesManager }) {
const toolbarService = servicesManager.services.ToolBarService;
@@ -9,65 +10,27 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
{
name: 'ohif.divider',
defaultComponent: ToolbarDivider,
clickHandler: () => { },
clickHandler: () => {},
},
{
name: 'ohif.action',
defaultComponent: ToolbarButton,
requiredConfig: [],
optionalConfig: [],
requiredProps: [],
optionalProps: [],
clickHandler: (evt, btn, btnSectionName) => {
const { props } = btn;
commandsManager.runCommand(props.commandName, props.commandOptions);
},
clickHandler: () => {},
},
{
name: 'ohif.radioGroup',
defaultComponent: ToolbarButton,
requiredConfig: ['groupName'],
optionalConfig: [],
requiredProps: [],
optionalProps: [],
clickHandler: (evt, clickedBtn, btnSectionName, metadata, viewerProps) => {
const { props } = clickedBtn;
const allButtons = toolbarService.getButtons();
// Set all buttons in same group to inactive
Object.keys(allButtons).forEach(btnName => {
const btn = allButtons[btnName];
const isRadioGroupBtn =
btn.config &&
btn.config.groupName &&
btn.type === 'ohif.radioGroup';
if (
isRadioGroupBtn &&
clickedBtn.config.groupName === btn.config.groupName
) {
btn.props.isActive = false;
if (viewerProps.setActiveTool) {
viewerProps.setActiveTool(props, metadata.isNested);
}
}
});
// Set our clicked button to active
allButtons[clickedBtn.id].props.isActive = true;
// Run button logic/command
commandsManager.runCommand(props.commandName, props.commandOptions);
// Set buttons & trigger notification
toolbarService.setButtons(allButtons);
},
clickHandler: () => {},
},
{
name: 'ohif.splitButton',
defaultComponent: ToolbarSplitButton,
clickHandler: () => {},
},
{
name: 'ohif.layoutSelector',
defaultComponent: ToolbarLayoutSelector,
clickHandler: (evt, clickedBtn, btnSectionName) => { },
clickHandler: (evt, clickedBtn, btnSectionName) => {},
},
{
name: 'ohif.toggle',