Skip to content

Commit

Permalink
Add tooltips for options to explain configuration directly within app…
Browse files Browse the repository at this point in the history
…lication.
  • Loading branch information
We-Gold committed Aug 9, 2024
1 parent 9a54fc0 commit 4dcaa05
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 69 deletions.
2 changes: 1 addition & 1 deletion documentation/docs/guide/backproject.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ The offset of the minimum bounding box is stored in the output tiff's descriptio
- 📁 `Slice Configuration File` - Path to the `-configuration.json` file which includes information generated during slicing needed for backprojection.
- 📁 `Output File Folder` - The folder to save all the resulting files into.
- `Output File Name` - Base name for all output files.
- `Output MIP Level` - The mip level to output the backprojection in (essentially an upsample option). Use this if you downsampled in the slicing step.
- `Output MIP Level` - The MIP level to output the backprojection in (essentially an upsample option). Use this if you downsampled in the slicing step.
- `Upsample Order` - The interpolation order Ouroboros uses to interpolate values from a lower MIP level. If you check the binary option, feel free to set this to 0.
- `Backprojection Compression` - The compression option to use for the backprojected tiff(s). Recommended options: `none`, `zlib`, `zstd`.
- `Output Single File` - Whether to output one tiff stack file or a folder of files.
Expand Down
7 changes: 3 additions & 4 deletions documentation/docs/guide/slicing.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,13 @@ Slicing is one of the primary features of Ouroboros, available in the CLI and th
- `Slice Height` - The output height of each slice image.
- 📁 `Output File Folder` - The folder to save all the resulting files into.
- `Output File Name` - Base name for all output files.
- `Annotation MIP Level` - The annotation layer's MIP level.
- `Output MIP Level` - The mip level to output slices in (essentially a downsample option).
- `Annotation MIP Level` - The annotation layer's MIP level. 0 is the highest resolution.
- `Output MIP Level` - The MIP level to output slices in (essentially a downsample option). 1 is a good starting point.
- `Slicing Parameters`
- `Distance Between Slices` - The distance between each slice along the annotation path.
- `Use Adaptive Slicing` - Rather than just using equidistant slices, add more slices in more curved areas.
- `Adaptive Slicing Ratio` - 1 means consider distance and curvature equally, 0.5 is biased towards distance, and 2 is biased towards curvature.
- `Adaptive Slicing Ratio` - 1 indicates to consider distance and curvature equally, 0.5 is biased towards distance, and 2 is biased towards curvature.
- `Output Single File` - Whether to output one tiff stack file or a folder of files.
- `Connect Endpoints` - Connect the first point in the path to the last point. This is not recommended.
- `Bounding Box Parameters`
- `Max Depth` - The maximum depth for binary space partitioning. It is not recommended to change this option unless you encounter RAM issues.
- `Target Slices Per Box` - If you are running on a low-RAM system, or you are taking very large slices, you may want to decrease this.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useDroppable } from '@dnd-kit/core'
import { ValueType, Entry } from '@renderer/interfaces/options'
import { DragContext } from '@renderer/contexts/DragContext'
import { DirectoryContext } from '@renderer/contexts/DirectoryContext'
import { useTooltip } from '@renderer/components/Tooltip/Tooltip'

const MIN_WIDTH = 25
const LABEL_GAP = 15
Expand All @@ -27,6 +28,8 @@ function OptionEntry({
const labelRef = useRef<HTMLDivElement>(null)
const [labelWidth, setLabelWidth] = useState(0)

const tooltip = useTooltip(labelRef, entry.description)

const [inputValue, setInputValue] = useState(initialValue)

const { parentChildData, clearDragEvent } = useContext(DragContext)
Expand Down Expand Up @@ -157,44 +160,47 @@ function OptionEntry({
}

return (
<div ref={setNodeRef} style={style}>
<div className={`${styles.optionEntry} poppins-medium`}>
<div
ref={labelRef}
className={`${styles.optionLabel} option-font-size ${isOver && inputType == 'filePath' ? 'poppins-bold' : ''}`}
>
{label}
</div>
{htmlInputType === 'select' ? (
<select
name={inputName}
className={`${styles.optionInput} ${styles.optionSelect}`}
value={inputValue as string}
onInput={onInput}
<>
<div ref={setNodeRef} style={style}>
<div className={`${styles.optionEntry} poppins-medium`}>
<div
ref={labelRef}
className={`${styles.optionLabel} option-font-size ${isOver && inputType == 'filePath' ? 'poppins-bold' : ''}`}
>
{inputOptions?.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
) : (
<input
name={inputName}
ref={inputRef}
type={htmlInputType}
className={styles.optionInput}
checked={
inputType == 'boolean'
? inputValue === 'true' || inputValue === true
: undefined
}
value={inputValue as string}
onChange={onChange}
/>
)}
{label}
</div>
{htmlInputType === 'select' ? (
<select
name={inputName}
className={`${styles.optionInput} ${styles.optionSelect}`}
value={inputValue as string}
onInput={onInput}
>
{inputOptions?.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
) : (
<input
name={inputName}
ref={inputRef}
type={htmlInputType}
className={styles.optionInput}
checked={
inputType == 'boolean'
? inputValue === 'true' || inputValue === true
: undefined
}
value={inputValue as string}
onChange={onChange}
/>
)}
</div>
</div>
</div>
{tooltip}
</>
)
}

Expand Down
14 changes: 14 additions & 0 deletions src/renderer/src/components/Tooltip/Tooltip.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.tooltip {
position: fixed;
width: 300px;
background-color: rgba(100, 100, 100, 0.3);
color: white;
border-radius: 0.25rem;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(100, 100, 100, 0.35);
box-sizing: border-box;
font-size: 0.95rem;
z-index: 999999;
padding: 0.1rem 0.4rem;
}
66 changes: 66 additions & 0 deletions src/renderer/src/components/Tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useEffect, useRef, useState } from 'react'
import styles from './Tooltip.module.css'

function Tooltip({ x, y, message }: { x: number; y: number; message: string }): JSX.Element {
const ref = useRef<HTMLDivElement>(null)

return (
<div
className={`poppins-light ${styles.tooltip}`}
style={{ top: `${y}px`, right: `${x}px`, transform: 'translateY(-50%)' }}
ref={ref}
>
{message}
</div>
)
}

export default Tooltip

export function useTooltip(
ref: React.RefObject<HTMLElement>,
message?: string,
gap = 10
): JSX.Element {
if (!message) return <></>

const [point, setPoint] = useState({ x: 0, y: 0 })
const [show, setShow] = useState(false)

useEffect(() => {
const handleMouseOver = (): void => {
if (ref.current) {
const { innerWidth } = window

// Determine bottom left corner of the element
const rect = ref.current.getBoundingClientRect()
const x = innerWidth - rect.left + gap
const y = (rect.bottom - rect.top) / 2 + rect.top

setPoint({ x, y })
setShow(true)

// If the right side of the tooltip goes off screen, decrease the width to match
if (x + ref.current.offsetWidth > innerWidth) {
ref.current.style.width = `${innerWidth - x}px`
} else {
ref.current.style.width = '350px'
}
}
}

const handleMouseOut = (): void => {
setShow(false)
}

ref.current?.addEventListener('mouseover', handleMouseOver)
ref.current?.addEventListener('mouseout', handleMouseOut)

return (): void => {
ref.current?.removeEventListener('mouseover', handleMouseOver)
ref.current?.removeEventListener('mouseout', handleMouseOut)
}
}, [ref])

return <>{show ? <Tooltip {...point} message={message} /> : null}</>
}
Loading

0 comments on commit 4dcaa05

Please sign in to comment.