Added tooltips in top bar

main
Boris Sekachev 6 years ago
parent ff0a5659c7
commit 0fda72bb99

@ -3,12 +3,8 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import React from 'react'; import React from 'react';
import Menu, { ClickParam } from 'antd/lib/menu';
import { import Modal from 'antd/lib/modal';
Menu, Modal,
} from 'antd';
import { ClickParam } from 'antd/lib/menu/index';
import DumpSubmenu from 'components/actions-menu/dump-submenu'; import DumpSubmenu from 'components/actions-menu/dump-submenu';
import LoadSubmenu from 'components/actions-menu/load-submenu'; import LoadSubmenu from 'components/actions-menu/load-submenu';

@ -3,30 +3,29 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import React from 'react'; import React from 'react';
import { Col } from 'antd/lib/grid';
import { import Icon from 'antd/lib/icon';
Col, import Modal from 'antd/lib/modal';
Icon, import Button from 'antd/lib/button';
Modal, import Timeline from 'antd/lib/timeline';
Button, import Dropdown from 'antd/lib/dropdown';
Timeline,
Dropdown,
} from 'antd';
import AnnotationMenuContainer from 'containers/annotation-page/top-bar/annotation-menu'; import AnnotationMenuContainer from 'containers/annotation-page/top-bar/annotation-menu';
import { import {
MainMenuIcon, MainMenuIcon,
SaveIcon, SaveIcon,
UndoIcon, UndoIcon,
RedoIcon, RedoIcon,
} from '../../../icons'; } from 'icons';
interface Props { interface Props {
saving: boolean; saving: boolean;
savingStatuses: string[]; savingStatuses: string[];
undoAction?: string; undoAction?: string;
redoAction?: string; redoAction?: string;
saveShortcut: string;
undoShortcut: string;
redoShortcut: string;
onSaveAnnotation(): void; onSaveAnnotation(): void;
onUndoClick(): void; onUndoClick(): void;
onRedoClick(): void; onRedoClick(): void;
@ -38,6 +37,9 @@ function LeftGroup(props: Props): JSX.Element {
savingStatuses, savingStatuses,
undoAction, undoAction,
redoAction, redoAction,
saveShortcut,
undoShortcut,
redoShortcut,
onSaveAnnotation, onSaveAnnotation,
onUndoClick, onUndoClick,
onRedoClick, onRedoClick,
@ -52,6 +54,7 @@ function LeftGroup(props: Props): JSX.Element {
</Button> </Button>
</Dropdown> </Dropdown>
<Button <Button
title={`Save current changes ${saveShortcut}`}
onClick={saving ? undefined : onSaveAnnotation} onClick={saving ? undefined : onSaveAnnotation}
type='link' type='link'
className={saving className={saving
@ -79,7 +82,7 @@ function LeftGroup(props: Props): JSX.Element {
</Modal> </Modal>
</Button> </Button>
<Button <Button
title={undoAction} title={`Undo: ${undoAction} ${undoShortcut}`}
disabled={!undoAction} disabled={!undoAction}
style={{ pointerEvents: undoAction ? 'initial' : 'none', opacity: undoAction ? 1 : 0.5 }} style={{ pointerEvents: undoAction ? 'initial' : 'none', opacity: undoAction ? 1 : 0.5 }}
type='link' type='link'
@ -90,7 +93,7 @@ function LeftGroup(props: Props): JSX.Element {
<span>Undo</span> <span>Undo</span>
</Button> </Button>
<Button <Button
title={redoAction} title={`Redo: ${redoAction} ${redoShortcut}`}
disabled={!redoAction} disabled={!redoAction}
style={{ pointerEvents: redoAction ? 'initial' : 'none', opacity: redoAction ? 1 : 0.5 }} style={{ pointerEvents: redoAction ? 'initial' : 'none', opacity: redoAction ? 1 : 0.5 }}
type='link' type='link'

@ -4,11 +4,9 @@
import React from 'react'; import React from 'react';
import { import { Col } from 'antd/lib/grid';
Col, import Icon from 'antd/lib/icon';
Icon, import Tooltip from 'antd/lib/tooltip';
Tooltip,
} from 'antd';
import { import {
FirstIcon, FirstIcon,
@ -19,10 +17,15 @@ import {
NextIcon, NextIcon,
ForwardJumpIcon, ForwardJumpIcon,
LastIcon, LastIcon,
} from '../../../icons'; } from 'icons';
interface Props { interface Props {
playing: boolean; playing: boolean;
playPauseShortcut: string;
nextFrameShortcut: string;
previousFrameShortcut: string;
forwardShortcut: string;
backwardShortcut: string;
onSwitchPlay(): void; onSwitchPlay(): void;
onPrevFrame(): void; onPrevFrame(): void;
onNextFrame(): void; onNextFrame(): void;
@ -35,6 +38,11 @@ interface Props {
function PlayerButtons(props: Props): JSX.Element { function PlayerButtons(props: Props): JSX.Element {
const { const {
playing, playing,
playPauseShortcut,
nextFrameShortcut,
previousFrameShortcut,
forwardShortcut,
backwardShortcut,
onSwitchPlay, onSwitchPlay,
onPrevFrame, onPrevFrame,
onNextFrame, onNextFrame,
@ -49,16 +57,16 @@ function PlayerButtons(props: Props): JSX.Element {
<Tooltip title='Go to the first frame'> <Tooltip title='Go to the first frame'>
<Icon component={FirstIcon} onClick={onFirstFrame} /> <Icon component={FirstIcon} onClick={onFirstFrame} />
</Tooltip> </Tooltip>
<Tooltip title='Go back with a step'> <Tooltip title={`Go back with a step ${backwardShortcut}`}>
<Icon component={BackJumpIcon} onClick={onBackward} /> <Icon component={BackJumpIcon} onClick={onBackward} />
</Tooltip> </Tooltip>
<Tooltip title='Go back'> <Tooltip title={`Go back ${previousFrameShortcut}`}>
<Icon component={PreviousIcon} onClick={onPrevFrame} /> <Icon component={PreviousIcon} onClick={onPrevFrame} />
</Tooltip> </Tooltip>
{!playing {!playing
? ( ? (
<Tooltip title='Play'> <Tooltip title={`Play ${playPauseShortcut}`}>
<Icon <Icon
component={PlayIcon} component={PlayIcon}
onClick={onSwitchPlay} onClick={onSwitchPlay}
@ -66,7 +74,7 @@ function PlayerButtons(props: Props): JSX.Element {
</Tooltip> </Tooltip>
) )
: ( : (
<Tooltip title='Pause'> <Tooltip title={`Pause ${playPauseShortcut}`}>
<Icon <Icon
component={PauseIcon} component={PauseIcon}
onClick={onSwitchPlay} onClick={onSwitchPlay}
@ -74,10 +82,10 @@ function PlayerButtons(props: Props): JSX.Element {
</Tooltip> </Tooltip>
)} )}
<Tooltip title='Go next'> <Tooltip title={`Go next ${nextFrameShortcut}`}>
<Icon component={NextIcon} onClick={onNextFrame} /> <Icon component={NextIcon} onClick={onNextFrame} />
</Tooltip> </Tooltip>
<Tooltip title='Go next with a step'> <Tooltip title={`Go next with a step ${forwardShortcut}`}>
<Icon component={ForwardJumpIcon} onClick={onForward} /> <Icon component={ForwardJumpIcon} onClick={onForward} />
</Tooltip> </Tooltip>
<Tooltip title='Go to the last frame'> <Tooltip title='Go to the last frame'>

@ -18,6 +18,7 @@ interface Props {
stopFrame: number; stopFrame: number;
frameNumber: number; frameNumber: number;
frameFilename: string; frameFilename: string;
focusFrameInputShortcut: string;
inputFrameRef: React.RefObject<InputNumber>; inputFrameRef: React.RefObject<InputNumber>;
onSliderChange(value: SliderValue): void; onSliderChange(value: SliderValue): void;
onInputChange(value: number): void; onInputChange(value: number): void;
@ -30,6 +31,7 @@ function PlayerNavigation(props: Props): JSX.Element {
stopFrame, stopFrame,
frameNumber, frameNumber,
frameFilename, frameFilename,
focusFrameInputShortcut,
inputFrameRef, inputFrameRef,
onSliderChange, onSliderChange,
onInputChange, onInputChange,
@ -72,26 +74,27 @@ function PlayerNavigation(props: Props): JSX.Element {
</Row> </Row>
</Col> </Col>
<Col> <Col>
<InputNumber <Tooltip title={`Press ${focusFrameInputShortcut} to focus here`}>
className='cvat-player-frame-selector' <InputNumber
type='number' className='cvat-player-frame-selector'
value={frameInputValue} type='number'
// https://stackoverflow.com/questions/38256332/in-react-whats-the-difference-between-onchange-and-oninput value={frameInputValue}
onChange={(value: number | undefined) => { onChange={(value: number | undefined) => {
if (typeof (value) === 'number') { if (typeof (value) === 'number') {
setFrameInputValue(Math.floor( setFrameInputValue(Math.floor(
clamp(value, startFrame, stopFrame), clamp(value, startFrame, stopFrame),
)); ));
} }
}} }}
onBlur={() => { onBlur={() => {
onInputChange(frameInputValue); onInputChange(frameInputValue);
}} }}
onPressEnter={() => { onPressEnter={() => {
onInputChange(frameInputValue); onInputChange(frameInputValue);
}} }}
ref={inputFrameRef} ref={inputFrameRef}
/> />
</Tooltip>
</Col> </Col>
</> </>
); );

@ -3,16 +3,13 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import React from 'react'; import React from 'react';
import { Col } from 'antd/lib/grid';
import { import Icon from 'antd/lib/icon';
Col, import Select from 'antd/lib/select';
Icon, import Button from 'antd/lib/button';
Select,
Button,
} from 'antd';
import { Workspace } from 'reducers/interfaces'; import { Workspace } from 'reducers/interfaces';
import { InfoIcon, FullscreenIcon } from '../../../icons'; import { InfoIcon, FullscreenIcon } from 'icons';
interface Props { interface Props {
workspace: Workspace; workspace: Workspace;

@ -3,18 +3,13 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import React from 'react'; import React from 'react';
import { Row, Col } from 'antd/lib/grid';
import { import Tooltip from 'antd/lib/tooltip';
Tooltip, import Select from 'antd/lib/select';
Select, import Table from 'antd/lib/table';
Table, import Modal from 'antd/lib/modal';
Modal, import Spin from 'antd/lib/spin';
Spin, import Icon from 'antd/lib/icon';
Icon,
Row,
Col,
} from 'antd';
import Text from 'antd/lib/typography/Text'; import Text from 'antd/lib/typography/Text';
interface Props { interface Props {

@ -26,6 +26,15 @@ interface Props {
undoAction?: string; undoAction?: string;
redoAction?: string; redoAction?: string;
workspace: Workspace; workspace: Workspace;
saveShortcut: string;
undoShortcut: string;
redoShortcut: string;
playPauseShortcut: string;
nextFrameShortcut: string;
previousFrameShortcut: string;
forwardShortcut: string;
backwardShortcut: string;
focusFrameInputShortcut: string;
changeWorkspace(workspace: Workspace): void; changeWorkspace(workspace: Workspace): void;
showStatistics(): void; showStatistics(): void;
onSwitchPlay(): void; onSwitchPlay(): void;
@ -56,6 +65,15 @@ export default function AnnotationTopBarComponent(props: Props): JSX.Element {
startFrame, startFrame,
stopFrame, stopFrame,
workspace, workspace,
saveShortcut,
undoShortcut,
redoShortcut,
playPauseShortcut,
nextFrameShortcut,
previousFrameShortcut,
forwardShortcut,
backwardShortcut,
focusFrameInputShortcut,
showStatistics, showStatistics,
changeWorkspace, changeWorkspace,
onSwitchPlay, onSwitchPlay,
@ -78,9 +96,12 @@ export default function AnnotationTopBarComponent(props: Props): JSX.Element {
<LeftGroup <LeftGroup
saving={saving} saving={saving}
savingStatuses={savingStatuses} savingStatuses={savingStatuses}
onSaveAnnotation={onSaveAnnotation}
undoAction={undoAction} undoAction={undoAction}
redoAction={redoAction} redoAction={redoAction}
saveShortcut={saveShortcut}
undoShortcut={undoShortcut}
redoShortcut={redoShortcut}
onSaveAnnotation={onSaveAnnotation}
onUndoClick={onUndoClick} onUndoClick={onUndoClick}
onRedoClick={onRedoClick} onRedoClick={onRedoClick}
/> />
@ -88,6 +109,11 @@ export default function AnnotationTopBarComponent(props: Props): JSX.Element {
<Row type='flex' align='middle'> <Row type='flex' align='middle'>
<PlayerButtons <PlayerButtons
playing={playing} playing={playing}
playPauseShortcut={playPauseShortcut}
nextFrameShortcut={nextFrameShortcut}
previousFrameShortcut={previousFrameShortcut}
forwardShortcut={forwardShortcut}
backwardShortcut={backwardShortcut}
onPrevFrame={onPrevFrame} onPrevFrame={onPrevFrame}
onNextFrame={onNextFrame} onNextFrame={onNextFrame}
onForward={onForward} onForward={onForward}
@ -101,6 +127,7 @@ export default function AnnotationTopBarComponent(props: Props): JSX.Element {
stopFrame={stopFrame} stopFrame={stopFrame}
frameNumber={frameNumber} frameNumber={frameNumber}
frameFilename={frameFilename} frameFilename={frameFilename}
focusFrameInputShortcut={focusFrameInputShortcut}
inputFrameRef={inputFrameRef} inputFrameRef={inputFrameRef}
onSliderChange={onSliderChange} onSliderChange={onSliderChange}
onInputChange={onInputChange} onInputChange={onInputChange}

@ -5,11 +5,9 @@
import React from 'react'; import React from 'react';
import copy from 'copy-to-clipboard'; import copy from 'copy-to-clipboard';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import { RouteComponentProps } from 'react-router-dom'; import { RouteComponentProps } from 'react-router-dom';
import { GlobalHotKeys, ExtendedKeyMapOptions } from 'react-hotkeys'; import { GlobalHotKeys, ExtendedKeyMapOptions } from 'react-hotkeys';
import InputNumber from 'antd/lib/input-number'; import InputNumber from 'antd/lib/input-number';
import { SliderValue } from 'antd/lib/slider'; import { SliderValue } from 'antd/lib/slider';
@ -28,6 +26,7 @@ import {
import AnnotationTopBarComponent from 'components/annotation-page/top-bar/top-bar'; import AnnotationTopBarComponent from 'components/annotation-page/top-bar/top-bar';
import { CombinedState, FrameSpeed, Workspace } from 'reducers/interfaces'; import { CombinedState, FrameSpeed, Workspace } from 'reducers/interfaces';
import { formatShortcuts } from 'utils/shortcuts';
interface StateToProps { interface StateToProps {
jobInstance: any; jobInstance: any;
@ -482,7 +481,7 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
SAVE_JOB: keyMap.SAVE_JOB, SAVE_JOB: keyMap.SAVE_JOB,
UNDO: keyMap.UNDO, UNDO: keyMap.UNDO,
REDO: keyMap.REDO, REDO: keyMap.REDO,
NEXT_FRAME: keyMap.SAVE_JOB, NEXT_FRAME: keyMap.NEXT_FRAME,
PREV_FRAME: keyMap.PREV_FRAME, PREV_FRAME: keyMap.PREV_FRAME,
FORWARD_FRAME: keyMap.FORWARD_FRAME, FORWARD_FRAME: keyMap.FORWARD_FRAME,
BACKWARD_FRAME: keyMap.BACKWARD_FRAME, BACKWARD_FRAME: keyMap.BACKWARD_FRAME,
@ -585,6 +584,15 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
inputFrameRef={this.inputFrameRef} inputFrameRef={this.inputFrameRef}
undoAction={undoAction} undoAction={undoAction}
redoAction={redoAction} redoAction={redoAction}
saveShortcut={formatShortcuts(keyMap.SAVE_JOB)}
undoShortcut={formatShortcuts(keyMap.UNDO)}
redoShortcut={formatShortcuts(keyMap.REDO)}
playPauseShortcut={formatShortcuts(keyMap.PLAY_PAUSE)}
nextFrameShortcut={formatShortcuts(keyMap.NEXT_FRAME)}
previousFrameShortcut={formatShortcuts(keyMap.PREV_FRAME)}
forwardShortcut={formatShortcuts(keyMap.FORWARD_FRAME)}
backwardShortcut={formatShortcuts(keyMap.BACKWARD_FRAME)}
focusFrameInputShortcut={formatShortcuts(keyMap.FOCUS_INPUT_FRAME)}
onUndoClick={this.undo} onUndoClick={this.undo}
onRedoClick={this.redo} onRedoClick={this.redo}
/> />

@ -0,0 +1,17 @@
// Copyright (C) 2020 Intel Corporation
//
// SPDX-License-Identifier: MIT
import { ExtendedKeyMapOptions } from 'react-hotkeys';
/* eslint-disable-next-line import/prefer-default-export */
export function formatShortcuts(shortcuts: ExtendedKeyMapOptions): string {
const list: string[] = shortcuts.sequences as string[];
return `[${list.map((shortcut: string): string => {
let keys = shortcut.split('+');
keys = keys.map((key: string): string => `${key ? key[0].toUpperCase() : key}${key.slice(1)}`);
keys = keys.join('+').split(/\s/g);
keys = keys.map((key: string): string => `${key ? key[0].toUpperCase() : key}${key.slice(1)}`);
return keys.join(' ');
}).join(', ')}]`;
}
Loading…
Cancel
Save