feat(segmentation mode): Add create, and export SEG with Brushes (#3632)

This commit is contained in:
Alireza authored and GitHub committed 2023-09-22 10:23:44 -04:00
1 parent 896866e9d0
commit 48bbd6281a
186 files changed
+6801 -2883

No files matched your search

@@ -0,0 +1,64 @@
import React, { useState, useEffect } from 'react';
import classnames from 'classnames';
import { PanelSection, Icon, Tooltip } from '../../components';
import ToolSettings from './ToolSettings';
const AdvancedToolbox = ({ title, items }) => {
const [activeItemName, setActiveItemName] = useState(null);
useEffect(() => {
// see if any of the items are active from the outside
const activeItem = items?.find(item => item.active);
setActiveItemName(activeItem ? activeItem.name : null);
}, [items]);
const activeItemOptions = items?.find(item => item.name === activeItemName)?.options;
return (
<PanelSection title={title}>
<div className="flex flex-col bg-black">
<div className="bg-primary-dark mt-0.5 flex flex-wrap py-2">
{items?.map(item => {
return (
<Tooltip
position="bottom"
content={<span className="text-white">{item.name}</span>}
key={item.name}
>
<div
className="ml-2 mb-2"
onClick={() => {
if (item.disabled) {
return;
}
setActiveItemName(item.name);
item.onClick(item.name);
}}
>
<div
className={classnames(
'text-primary-active grid h-[40px] w-[40px] place-items-center rounded-md bg-black ',
activeItemName === item.name && 'bg-primary-light text-black',
item.disabled && 'opacity-50',
!item.disabled &&
'hover:bg-primary-light cursor-pointer hover:cursor-pointer hover:text-black'
)}
>
<Icon name={item.icon} />
</div>
</div>
</Tooltip>
);
})}
</div>
<div className="bg-primary-dark h-auto px-2">
<ToolSettings options={activeItemOptions} />
</div>
</div>
</PanelSection>
);
};
AdvancedToolbox.propTypes = {};
export default AdvancedToolbox;
@@ -0,0 +1,84 @@
import React from 'react';
import { ButtonGroup, InputRange, ButtonEnums } from '../../components';
const SETTING_TYPES = {
RANGE: 'range',
RADIO: 'radio',
CUSTOM: 'custom',
};
function ToolSettings({ options }) {
if (!options) {
return null;
}
const getButtons = option => {
const buttons = [];
option.values?.map(({ label, value: optionValue }, index) => {
buttons.push({
children: label,
onClick: () => option.onChange(optionValue),
key: `button-${option.id}-${index}`, // A unique key
});
});
return buttons;
};
return (
<div className="space-y-2 py-2 text-white">
{options?.map(option => {
if (option.type === SETTING_TYPES.RANGE) {
return (
<div
className="flex items-center"
key={option.id}
>
<div className="w-1/3 text-xs text-[13px]">{option.name}</div>
<div className="w-2/3">
<InputRange
minValue={option.min}
maxValue={option.max}
step={option.step}
value={option.value}
onChange={e => option.onChange(e)}
allowNumberEdit={true}
showAdjustmentArrows={false}
inputClassName="ml-2 w-4/5"
/>
</div>
</div>
);
}
if (option.type === SETTING_TYPES.RADIO) {
return (
<div
className="flex items-center justify-between text-[13px]"
key={option.id}
>
<span>{option.name}</span>
<div className="max-w-1/2">
<ButtonGroup
buttons={getButtons(option)}
defaultActiveIndex={option.defaultActiveIndex}
size={ButtonEnums.size.small}
/>
</div>
</div>
);
}
if (option.type === SETTING_TYPES.CUSTOM) {
return (
<div key={option.id}>
{typeof option.children === 'function' ? option.children() : option.children}
</div>
);
}
})}
</div>
);
}
export default ToolSettings;
@@ -0,0 +1,144 @@
import AdvancedToolbox from '../../AdvancedToolbox';
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
import {
createComponentTemplate,
createStoryMetaSettings,
} from '../../../storybook/functions/create-component-story';
export const argTypes = {
component: AdvancedToolbox,
title: 'Components/AdvancedToolbox',
};
<Meta
title="Components/AdvancedToolbox"
component={AdvancedToolbox}
/>
export const advancedToolboxTemplate = args => (
<div className="bg-primary-dark h-96 w-64">
<AdvancedToolbox {...args} />
</div>
);
<Heading
title="Advanced Toolbox"
componentRelativePath="AdvancedToolbox/AdvancedToolbox.tsx"
/>
- [Overview](#overview)
- [Props](#props)
- [Usage](#usage)
- [Contribute](#contribute)
## Overview
OHIF advanced toolbox which can host set of tools that require more space for customization.
<Canvas>
<Story
name="Overview"
args={{
title: 'Segmentation Tools',
items: [
{
name: 'Brush',
icon: 'icon-tool-brush',
active: false,
onClick: () => console.log('Brush clicked'),
options: [
{
name: 'Radius (mm)',
type: 'range',
min: 1,
max: 10,
value: 5,
step: 1,
onChange: value => console.log('Brush size changed', value),
},
{
name: 'Mode',
type: 'radio',
value: 'Circle',
values: [
{ value: 'Circle', label: 'Circle' },
{ value: 'Sphere', label: 'Sphere' },
{ value: 'Rectangle', label: 'Rectangle' },
],
onChange: value => console.log('Brush mode changed', value),
},
],
},
{
name: 'Eraser',
icon: 'icon-tool-eraser',
onClick: () => console.log('eraser clicked'),
options: [
{
name: 'Mode',
type: 'radio',
value: 'EraserSphere',
values: [
{ value: 'EraserCircle', label: 'Circle' },
{ value: 'EraserSphere', label: 'Sphere' },
],
onChange: value => console.log('Brush mode changed', value),
},
],
},
{
name: 'Threshold',
icon: 'icon-tool-threshold',
active: true,
onClick: () => console.log('eraser clicked'),
options: [
{
name: 'Radius (mm)',
type: 'range',
min: 1,
max: 10,
value: 5,
step: 1,
onChange: value => console.log('Brush size changed', value),
},
{
name: 'Mode',
type: 'radio',
value: 'Circle',
values: [
{ value: 'Circle', label: 'Circle' },
{ value: 'Sphere', label: 'Sphere' },
{ value: 'Rectangle', label: 'Rectangle' },
],
onChange: value => console.log('Brush mode changed', value),
},
{
name: 'custom',
type: 'custom',
children: () => {
return (
<div>
<div>Custom</div>
<input type="text" />
</div>
);
},
},
],
},
],
}}
>
{advancedToolboxTemplate.bind({})}
</Story>
</Canvas>
## Props
<ArgsTable of={AdvancedToolbox} />
## Usage
## Contribute
<Footer componentRelativePath="AdvancedToolbox/__stories__/AdvancedToolbox.stories.mdx" />
@@ -0,0 +1,2 @@
import AdvancedToolbox from './AdvancedToolbox';
export default AdvancedToolbox;