Skip to content

Commit

Permalink
[3981] Add the last used tool entry in the palette
Browse files Browse the repository at this point in the history
Bug: #3981
Signed-off-by: Florian Barbin <[email protected]>
  • Loading branch information
florianbarbin committed Oct 3, 2024
1 parent 32f8298 commit 955a924
Show file tree
Hide file tree
Showing 12 changed files with 161 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
DiagramPaletteContextProviderProps,
DiagramPaletteContextProviderState,
DiagramPaletteContextValue,
ToolSectionWithLastTool,
PaletteWithLastTool,
} from './DiagramPaletteContext.types';
import { GQLTool } from './Palette.types';

Expand Down Expand Up @@ -50,25 +50,22 @@ export const DiagramPaletteContextProvider = ({ children }: DiagramPaletteContex
}
}, [state.isOpened]);

const getLastToolInvoked = (toolSectionId: string): GQLTool | null => {
const getLastToolInvoked = (paletteId: string): GQLTool | null => {
return (
state.lastToolsInvoked.find(
(toolSectionWithDefaultTool) => toolSectionWithDefaultTool.toolSectionId === toolSectionId
)?.lastTool || null
state.lastToolsInvoked.find((toolSectionWithDefaultTool) => toolSectionWithDefaultTool.paletteId === paletteId)
?.lastTool || null
);
};

const setLastToolInvoked = (toolSectionId: string, tool: GQLTool) => {
const lastToolsInvoked: ToolSectionWithLastTool[] = state.lastToolsInvoked;
if (lastToolsInvoked.some((toolSectionWithLastTool) => toolSectionWithLastTool.toolSectionId === toolSectionId)) {
const setLastToolInvoked = (paletteId: string, tool: GQLTool) => {
const lastToolsInvoked: PaletteWithLastTool[] = state.lastToolsInvoked;
if (lastToolsInvoked.some((toolSectionWithLastTool) => toolSectionWithLastTool.paletteId === paletteId)) {
lastToolsInvoked.splice(
lastToolsInvoked.findIndex(
(toolSectionWithLastTool) => toolSectionWithLastTool.toolSectionId === toolSectionId
),
lastToolsInvoked.findIndex((toolSectionWithLastTool) => toolSectionWithLastTool.paletteId === paletteId),
1
);
}
lastToolsInvoked.push({ toolSectionId: toolSectionId, lastTool: tool });
lastToolsInvoked.push({ paletteId, lastTool: tool });
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export interface DiagramPaletteContextValue {
isOpened: boolean;
showDiagramPalette: (x: number, y: number) => void;
hideDiagramPalette: () => void;
getLastToolInvoked: (toolSectionId: string) => GQLTool | null;
setLastToolInvoked: (toolSectionId: string, tool: GQLTool) => void;
getLastToolInvoked: (paletteId: string) => GQLTool | null;
setLastToolInvoked: (paletteId: string, tool: GQLTool) => void;
}

export interface DiagramPaletteContextProviderProps {
Expand All @@ -31,10 +31,10 @@ export interface DiagramPaletteContextProviderState {
x: number | null;
y: number | null;
isOpened: boolean;
lastToolsInvoked: ToolSectionWithLastTool[];
lastToolsInvoked: PaletteWithLastTool[];
}

export interface ToolSectionWithLastTool {
toolSectionId: string;
export interface PaletteWithLastTool {
paletteId: string;
lastTool: GQLTool;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/

import { IconOverlay } from '@eclipse-sirius/sirius-components-core';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Tooltip from '@mui/material/Tooltip';
import { makeStyles } from 'tss-react/mui';
import { GQLTool } from '../Palette.types';
import { usePaletteEntryTooltip } from '../usePaletteEntryTooltip';
import { ToolListItemProps } from './ToolListItem.types';
const useStyle = makeStyles()((theme) => ({
toolListContainer: {
display: 'grid',
overflowY: 'auto',
overflowX: 'hidden',
gridTemplateColumns: '100%',
},
toolList: {
gridRowStart: 1,
gridColumnStart: 1,
width: '100%',
padding: 0,
},
listItemText: {
'& .MuiListItemText-primary': {
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
},
},
listItemButton: {
paddingTop: 0,
paddingBottom: 0,
},
listItemIcon: {
minWidth: 0,
marginRight: theme.spacing(2),
},
}));
export const ToolListItem = ({ tool, onToolClick }: ToolListItemProps) => {
const { classes } = useStyle();
const { tooltipEnterDelay, tooltipPlacement } = usePaletteEntryTooltip();
const handleToolClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, tool: GQLTool) => {
event.stopPropagation();
onToolClick(tool);
};
return (
<Tooltip enterDelay={tooltipEnterDelay} placement={tooltipPlacement} title={tool.label} key={'tooltip_' + tool.id}>
<ListItemButton className={classes.listItemButton} onClick={(event) => handleToolClick(event, tool)}>
<ListItemIcon className={classes.listItemIcon}>
<IconOverlay iconURL={tool.iconURL} alt={tool.label} customIconHeight={16} customIconWidth={16} />
</ListItemIcon>
<ListItemText primary={tool.label} className={classes.listItemText} />
</ListItemButton>
</Tooltip>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/

import { GQLTool } from '../Palette.types';
export interface ToolListItemProps {
tool: GQLTool;
onToolClick: (tool: GQLTool) => void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import { useEffect, useMemo, useState } from 'react';
import { makeStyles } from 'tss-react/mui';
import { isSingleClickOnDiagramElementTool, isToolSection } from '../Palette';
import { GQLPaletteEntry, GQLSingleClickOnDiagramElementTool, GQLTool } from '../Palette.types';
import { usePaletteEntryTooltip } from '../usePaletteEntryTooltip';
import { HighlightedLabelProps, PaletteSearchResultProps } from './PaletteSearchResult.types';
import { usePaletteEntryTooltip } from './usePaletteEntryTooltip';

const convertToToolList = (entry: GQLPaletteEntry): GQLSingleClickOnDiagramElementTool[] => {
if (isSingleClickOnDiagramElementTool(entry)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,29 @@
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
import { IconOverlay } from '@eclipse-sirius/sirius-components-core';
import NavigateNextIcon from '@mui/icons-material/NavigateNext';
import Box from '@mui/material/Box';
import Divider from '@mui/material/Divider';
import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Slide from '@mui/material/Slide';
import Tooltip from '@mui/material/Tooltip';
import React, { useState } from 'react';
import { makeStyles } from 'tss-react/mui';
import { isPaletteDivider, isSingleClickOnDiagramElementTool, isToolSection } from '../Palette';
import { GQLPaletteEntry, GQLTool, GQLToolSection } from '../Palette.types';
import { GQLPaletteEntry, GQLToolSection } from '../Palette.types';
import { ToolListItem } from '../tool-list-item/ToolListItem';
import { useDiagramPalette } from '../useDiagramPalette';
import { usePaletteEntryTooltip } from '../usePaletteEntryTooltip';
import { PaletteToolListProps, PaletteToolListStateValue } from './PaletteToolList.types';
import { PaletteToolSectionList } from './PaletteToolSectionList';
import { usePaletteEntryTooltip } from './usePaletteEntryTooltip';

const useStyle = makeStyles()((theme) => ({
container: {
display: 'grid',
gridTemplateRows: `repeat(2,min-content) 1fr`,
},
toolListContainer: {
display: 'grid',
overflowY: 'auto',
Expand Down Expand Up @@ -70,11 +74,6 @@ export const PaletteToolList = ({ palette, onToolClick }: PaletteToolListProps)
setState((prevState) => ({ ...prevState, toolSection }));
};

const handleToolClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, tool: GQLTool) => {
event.stopPropagation();
onToolClick(tool);
};

const onBackToMainList = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
event.stopPropagation();
setState((prevState) => ({ ...prevState, toolSection: null }));
Expand All @@ -85,25 +84,7 @@ export const PaletteToolList = ({ palette, onToolClick }: PaletteToolListProps)
const convertPaletteEntry = (paletteEntry: GQLPaletteEntry): JSX.Element | null => {
let jsxElement: JSX.Element | null = null;
if (isSingleClickOnDiagramElementTool(paletteEntry)) {
jsxElement = (
<Tooltip
enterDelay={tooltipEnterDelay}
placement={tooltipPlacement}
title={paletteEntry.label}
key={'tooltip_' + paletteEntry.id}>
<ListItemButton className={classes.listItemButton} onClick={(event) => handleToolClick(event, paletteEntry)}>
<ListItemIcon className={classes.listItemIcon}>
<IconOverlay
iconURL={paletteEntry.iconURL}
alt={paletteEntry.label}
customIconHeight={16}
customIconWidth={16}
/>
</ListItemIcon>
<ListItemText primary={paletteEntry.label} className={classes.listItemText} />
</ListItemButton>
</Tooltip>
);
jsxElement = <ToolListItem onToolClick={onToolClick} tool={paletteEntry} />;
} else if (isToolSection(paletteEntry)) {
jsxElement = (
<Tooltip
Expand All @@ -125,39 +106,51 @@ export const PaletteToolList = ({ palette, onToolClick }: PaletteToolListProps)
return jsxElement;
};

const { getLastToolInvoked } = useDiagramPalette();
const lastToolInvoked = getLastToolInvoked(palette.id);
const lastUsedTool: JSX.Element | null = lastToolInvoked ? (
<>
<ToolListItem onToolClick={onToolClick} tool={lastToolInvoked} />
<Divider />
</>
) : null;

const containerRef = React.useRef<HTMLElement>(null);
return (
<Box className={classes.toolListContainer} ref={containerRef}>
{palette.paletteEntries.filter(isToolSection).map((entry) => (
<Box className={classes.container}>
{lastUsedTool}
<Box className={classes.toolListContainer} ref={containerRef}>
{palette.paletteEntries.filter(isToolSection).map((entry) => (
<Slide
key={'slide_' + entry.id}
direction={'left'}
in={state.toolSection?.id === entry.id}
container={containerRef.current}
unmountOnExit
mountOnEnter>
<div className={classes.toolList}>
<PaletteToolSectionList
toolSection={entry as GQLToolSection}
onToolClick={onToolClick}
onBackToMainList={onBackToMainList}
tooltipDelay={tooltipEnterDelay}
tooltipPlacement={tooltipPlacement}
/>
</div>
</Slide>
))}
<Slide
key={'slide_' + entry.id}
direction={'left'}
in={state.toolSection?.id === entry.id}
direction={'right'}
in={state.toolSection === null}
container={containerRef.current}
appear={false}
unmountOnExit
mountOnEnter>
<div className={classes.toolList}>
<PaletteToolSectionList
toolSection={entry as GQLToolSection}
onToolClick={handleToolClick}
onBackToMainList={onBackToMainList}
tooltipDelay={tooltipEnterDelay}
tooltipPlacement={tooltipPlacement}
/>
</div>
<List className={classes.toolList} component="nav">
{palette?.paletteEntries.map(convertPaletteEntry)}
</List>
</Slide>
))}
<Slide
direction={'right'}
in={state.toolSection === null}
container={containerRef.current}
appear={false}
unmountOnExit
mountOnEnter>
<List className={classes.toolList} component="nav">
{palette?.paletteEntries.map(convertPaletteEntry)}
</List>
</Slide>
</Box>
</Box>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
import { IconOverlay } from '@eclipse-sirius/sirius-components-core';
import NavigateBeforeIcon from '@mui/icons-material/NavigateBefore';
import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Tooltip from '@mui/material/Tooltip';
import { makeStyles } from 'tss-react/mui';
import { ToolListItem } from '../tool-list-item/ToolListItem';
import { PaletteToolSectionListProps } from './PaletteToolSectionList.types';

const useStyle = makeStyles()((theme) => ({
Expand Down Expand Up @@ -71,15 +70,8 @@ export const PaletteToolSectionList = ({
<ListItemText className={classes.sectionTitleListItemText} primary={toolSection.label} />
</ListItemButton>
</Tooltip>
{toolSection?.tools.map((tool) => (
<Tooltip enterDelay={tooltipDelay} placement={tooltipPlacement} title={tool.label} key={'tooltip_' + tool.id}>
<ListItemButton className={classes.toolListItemButton} onClick={(event) => onToolClick(event, tool)}>
<ListItemIcon className={classes.toolListItemIcon}>
<IconOverlay iconURL={tool.iconURL} alt={tool.label} customIconHeight={16} customIconWidth={16} />
</ListItemIcon>
<ListItemText className={classes.listItemText} primary={tool.label} />
</ListItemButton>
</Tooltip>
{toolSection.tools.map((tool) => (
<ToolListItem onToolClick={onToolClick} tool={tool} />
))}
</List>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import { GQLTool, GQLToolSection } from '../Palette.types';

export interface PaletteToolSectionListProps {
onToolClick: (event: React.MouseEvent<HTMLDivElement, MouseEvent>, tool: GQLTool) => void;
onToolClick: (tool: GQLTool) => void;
onBackToMainList: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
toolSection: GQLToolSection;
tooltipDelay?: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ export interface UseDiagramPaletteValue {
showDiagramPalette: (x: number, y: number) => void;
onDiagramBackgroundClick: (event: React.MouseEvent<Element, MouseEvent>) => void;
onDiagramElementClick: () => void;
getLastToolInvoked: (toolSectionId: string) => GQLTool | null;
setLastToolInvoked: (toolSectionId: string, tool: GQLTool) => void;
getLastToolInvoked: (paletteId: string) => GQLTool | null;
setLastToolInvoked: (paletteId: string, tool: GQLTool) => void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
GQLUpdateCollapsingStateVariables,
} from './Palette.types';

import { useDiagramPalette } from './useDiagramPalette';
import { UsePaletteProps, UsePaletteValue } from './usePalette.types';

const ToolFields = gql`
Expand Down Expand Up @@ -316,6 +317,8 @@ export const usePalette = ({
showDialog(tool.dialogDescriptionId, targetObjectId, onConfirm);
};

const { setLastToolInvoked } = useDiagramPalette();

const handleToolClick = (tool: GQLTool) => {
switch (tool.id) {
case 'edit':
Expand Down Expand Up @@ -345,6 +348,9 @@ export const usePalette = ({
}
break;
}
if (palette) {
setLastToolInvoked(palette.id, tool);
}
};
return { handleToolClick, palette };
};

0 comments on commit 955a924

Please sign in to comment.