Hide top row buttons in bitmap mode (#423)

This commit is contained in:
DD Liu 2018-05-03 14:23:00 -04:00 committed by GitHub
parent 10d35d066c
commit d71ca021f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 599 additions and 486 deletions

View file

@ -0,0 +1,93 @@
@import "../../css/colors.css";
@import "../../css/units.css";
.row {
display: flex;
flex-direction: row;
align-items: center;
}
.costume-input {
width: 8rem;
}
.mod-dashed-border {
border-right: 1px dashed $ui-pane-border;
padding-right: calc(2 * $grid-unit);
}
.mod-unselect {
user-select: none;
}
$border-radius: 0.25rem;
.button-group-button {
display: inline-block;
border: 1px solid $ui-pane-border;
border-radius: 0;
border-left: none;
padding: .35rem;
}
.button-group-button:last-of-type {
border-top-right-radius: $border-radius;
border-bottom-right-radius: $border-radius;
}
.button-group-button:first-of-type {
border-left: 1px solid $ui-pane-border;
border-top-left-radius: $border-radius;
border-bottom-left-radius: $border-radius;
}
.button-group-button.mod-left-border {
border-left: 1px solid $ui-pane-border;
}
.button-group-button.mod-no-right-border {
border-right: none;
}
.button-group-button-icon {
width: 1.25rem;
height: 1.25rem;
vertical-align: middle;
}
.mod-context-menu {
display: flex;
flex-direction: column;
}
.mod-top-divider {
border-top: 1px solid $ui-pane-border;
}
.mod-menu-item {
display: flex;
margin: 0 -$grid-unit;
min-width: 6.25rem;
padding: calc(3 * $grid-unit);
white-space: nowrap;
cursor: pointer;
transition: 0.1s ease;
align-items: center;
font-family: "Helvetica Neue", Helvetica, sans-serif;
}
.mod-disabled {
cursor: auto;
}
.mod-menu-item:hover {
background: $motion-transparent;
}
.mod-disabled:hover {
background-color: transparent;
}
.menu-item-icon {
margin-right: calc(2 * $grid-unit);
}

View file

@ -0,0 +1,309 @@
import classNames from 'classnames';
import {connect} from 'react-redux';
import PropTypes from 'prop-types';
import React from 'react';
import MediaQuery from 'react-responsive';
import {shouldShowGroup, shouldShowUngroup} from '../../helper/group';
import {shouldShowBringForward, shouldShowSendBackward} from '../../helper/order';
import BufferedInputHOC from '../forms/buffered-input-hoc.jsx';
import Button from '../button/button.jsx';
import ButtonGroup from '../button-group/button-group.jsx';
import Dropdown from '../dropdown/dropdown.jsx';
import {defineMessages, injectIntl, intlShape} from 'react-intl';
import Formats from '../../lib/format';
import Input from '../forms/input.jsx';
import InputGroup from '../input-group/input-group.jsx';
import Label from '../forms/label.jsx';
import LabeledIconButton from '../labeled-icon-button/labeled-icon-button.jsx';
import {isVector} from '../../lib/format';
import layout from '../../lib/layout-constants';
import styles from './fixed-tools.css';
import groupIcon from './icons/group.svg';
import redoIcon from './icons/redo.svg';
import sendBackIcon from './icons/send-back.svg';
import sendBackwardIcon from './icons/send-backward.svg';
import sendForwardIcon from './icons/send-forward.svg';
import sendFrontIcon from './icons/send-front.svg';
import undoIcon from './icons/undo.svg';
import ungroupIcon from './icons/ungroup.svg';
const BufferedInput = BufferedInputHOC(Input);
const messages = defineMessages({
costume: {
id: 'paint.paintEditor.costume',
description: 'Label for the name of a costume',
defaultMessage: 'Costume'
},
group: {
defaultMessage: 'Group',
description: 'Label for the button to group shapes',
id: 'paint.paintEditor.group'
},
ungroup: {
defaultMessage: 'Ungroup',
description: 'Label for the button to ungroup shapes',
id: 'paint.paintEditor.ungroup'
},
undo: {
defaultMessage: 'Undo',
description: 'Alt to image for the button to undo an action',
id: 'paint.paintEditor.undo'
},
redo: {
defaultMessage: 'Redo',
description: 'Alt to image for the button to redo an action',
id: 'paint.paintEditor.redo'
},
forward: {
defaultMessage: 'Forward',
description: 'Label for the `Send forward on canvas` button',
id: 'paint.paintEditor.forward'
},
backward: {
defaultMessage: 'Backward',
description: 'Label for the `Send backward on canvas` button',
id: 'paint.paintEditor.backward'
},
front: {
defaultMessage: 'Front',
description: 'Label for the `Send to front of canvas` button',
id: 'paint.paintEditor.front'
},
back: {
defaultMessage: 'Back',
description: 'Label for the `Send to back of canvas` button',
id: 'paint.paintEditor.back'
},
more: {
defaultMessage: 'More',
description: 'Label for dropdown to access more action buttons',
id: 'paint.paintEditor.more'
}
});
const FixedToolsComponent = props => {
const redoDisabled = !props.canRedo();
const undoDisabled = !props.canUndo();
return (
<div className={styles.row}>
{/* Name field */}
<InputGroup>
<MediaQuery minWidth={layout.fullSizeEditorMinWidth}>
<Label text={props.intl.formatMessage(messages.costume)}>
<BufferedInput
className={styles.costumeInput}
type="text"
value={props.name}
onSubmit={props.onUpdateName}
/>
</Label>
</MediaQuery>
<MediaQuery maxWidth={layout.fullSizeEditorMinWidth - 1}>
<BufferedInput
className={styles.costumeInput}
type="text"
value={props.name}
onSubmit={props.onUpdateName}
/>
</MediaQuery>
</InputGroup>
{/* Undo/Redo */}
<InputGroup>
<ButtonGroup>
<Button
className={
classNames(
styles.buttonGroupButton,
{
[styles.modNoRightBorder]: !redoDisabled
}
)
}
disabled={undoDisabled}
onClick={props.onUndo}
>
<img
alt={props.intl.formatMessage(messages.undo)}
className={styles.buttonGroupButtonIcon}
draggable={false}
src={undoIcon}
/>
</Button>
<Button
className={
classNames(
styles.buttonGroupButton,
{
[styles.modLeftBorder]: !redoDisabled
}
)
}
disabled={redoDisabled}
onClick={props.onRedo}
>
<img
alt={props.intl.formatMessage(messages.redo)}
className={styles.buttonGroupButtonIcon}
draggable={false}
src={redoIcon}
/>
</Button>
</ButtonGroup>
</InputGroup>
{/* Group/Ungroup */}
{isVector(props.format) ?
<InputGroup className={styles.modDashedBorder}>
<LabeledIconButton
disabled={!shouldShowGroup()}
imgSrc={groupIcon}
title={props.intl.formatMessage(messages.group)}
onClick={props.onGroup}
/>
<LabeledIconButton
disabled={!shouldShowUngroup()}
imgSrc={ungroupIcon}
title={props.intl.formatMessage(messages.ungroup)}
onClick={props.onUngroup}
/>
</InputGroup> : null
}
{/* Forward/Backward */}
{isVector(props.format) ?
<InputGroup className={styles.modDashedBorder}>
<LabeledIconButton
disabled={!shouldShowBringForward()}
imgSrc={sendForwardIcon}
title={props.intl.formatMessage(messages.forward)}
onClick={props.onSendForward}
/>
<LabeledIconButton
disabled={!shouldShowSendBackward()}
imgSrc={sendBackwardIcon}
title={props.intl.formatMessage(messages.backward)}
onClick={props.onSendBackward}
/>
</InputGroup> : null
}
{isVector(props.format) ?
<MediaQuery minWidth={layout.fullSizeEditorMinWidth}>
<InputGroup className={styles.row}>
<LabeledIconButton
disabled={!shouldShowBringForward()}
imgSrc={sendFrontIcon}
title={props.intl.formatMessage(messages.front)}
onClick={props.onSendToFront}
/>
<LabeledIconButton
disabled={!shouldShowSendBackward()}
imgSrc={sendBackIcon}
title={props.intl.formatMessage(messages.back)}
onClick={props.onSendToBack}
/>
</InputGroup>
{/* To be rotation point */}
{/* <InputGroup>
<LabeledIconButton
imgAlt="Rotation Point"
imgSrc={rotationPointIcon}
title="Rotation Point"
onClick={function () {}}
/>
</InputGroup> */}
</MediaQuery> : null
}
{isVector(props.format) ?
<MediaQuery maxWidth={layout.fullSizeEditorMinWidth - 1}>
<InputGroup>
<Dropdown
className={styles.modUnselect}
enterExitTransitionDurationMs={20}
popoverContent={
<InputGroup className={styles.modContextMenu}>
<Button
className={classNames(styles.modMenuItem, {
[styles.modDisabled]: !shouldShowBringForward()
})}
disabled={!shouldShowBringForward()}
onClick={props.onSendToFront}
>
<img
className={styles.menuItemIcon}
draggable={false}
src={sendFrontIcon}
/>
<span>{props.intl.formatMessage(messages.front)}</span>
</Button>
<Button
className={classNames(styles.modMenuItem, {
[styles.modDisabled]: !shouldShowSendBackward()
})}
disabled={!shouldShowSendBackward()}
onClick={props.onSendToBack}
>
<img
className={styles.menuItemIcon}
draggable={false}
src={sendBackIcon}
/>
<span>{props.intl.formatMessage(messages.back)}</span>
</Button>
{/* To be rotation point */}
{/* <Button
className={classNames(styles.modMenuItem, styles.modTopDivider)}
onClick={function () {}}
>
<img
className={styles.menuItemIcon}
draggable={false}
src={rotationPointIcon}
/>
<span>{'Rotation Point'}</span>
</Button> */}
</InputGroup>
}
tipSize={.01}
>
{props.intl.formatMessage(messages.more)}
</Dropdown>
</InputGroup>
</MediaQuery> : null
}
</div>
);
};
FixedToolsComponent.propTypes = {
canRedo: PropTypes.func.isRequired,
canUndo: PropTypes.func.isRequired,
format: PropTypes.oneOf(Object.keys(Formats)),
intl: intlShape,
name: PropTypes.string,
onGroup: PropTypes.func.isRequired,
onRedo: PropTypes.func.isRequired,
onSendBackward: PropTypes.func.isRequired,
onSendForward: PropTypes.func.isRequired,
onSendToBack: PropTypes.func.isRequired,
onSendToFront: PropTypes.func.isRequired,
onUndo: PropTypes.func.isRequired,
onUngroup: PropTypes.func.isRequired,
onUpdateName: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
format: state.scratchPaint.format,
selectedItems: state.scratchPaint.selectedItems
});
export default connect(
mapStateToProps
)(injectIntl(FixedToolsComponent));

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -28,19 +28,11 @@
margin-top: calc(2 * $grid-unit);
}
.costume-input {
width: 8rem;
}
.mod-dashed-border {
border-right: 1px dashed $ui-pane-border;
padding-right: calc(2 * $grid-unit);
}
.mod-unselect {
user-select: none;
}
.mod-labeled-icon-height {
height: 2.85rem; /* for the second row so the dashed borders are equal in size */
}
@ -80,43 +72,6 @@ $border-radius: 0.25rem;
vertical-align: middle;
}
.mod-context-menu {
display: flex;
flex-direction: column;
}
.mod-top-divider {
border-top: 1px solid $ui-pane-border;
}
.mod-menu-item {
display: flex;
margin: 0 -$grid-unit;
min-width: 6.25rem;
padding: calc(3 * $grid-unit);
white-space: nowrap;
cursor: pointer;
transition: 0.1s ease;
align-items: center;
font-family: "Helvetica Neue", Helvetica, sans-serif;
}
.mod-disabled {
cursor: auto;
}
.mod-menu-item:hover {
background: $motion-transparent;
}
.mod-disabled:hover {
background-color: transparent;
}
.menu-item-icon {
margin-right: calc(2 * $grid-unit);
}
.mod-mode-tools {
margin-left: calc(2 * $grid-unit);
}
@ -175,11 +130,6 @@ $border-radius: 0.25rem;
justify-content: space-between;
}
.bitmap-tooltip {
margin-left: $grid-unit;
max-width: 10rem;
}
.bitmap-button {
display: flex;
border-radius: 5px;

View file

@ -1,15 +1,11 @@
import paper from '@scratch/paper';
import classNames from 'classnames';
import {defineMessages, injectIntl, intlShape} from 'react-intl';
import MediaQuery from 'react-responsive';
import React from 'react';
import PropTypes from 'prop-types';
import PaperCanvas from '../../containers/paper-canvas.jsx';
import {shouldShowGroup, shouldShowUngroup} from '../../helper/group';
import {shouldShowBringForward, shouldShowSendBackward} from '../../helper/order';
import BitBrushMode from '../../containers/bit-brush-mode.jsx';
import BitLineMode from '../../containers/bit-line-mode.jsx';
import BitOvalMode from '../../components/bit-oval-mode/bit-oval-mode.jsx';
@ -22,17 +18,13 @@ import Box from '../box/box.jsx';
import Button from '../button/button.jsx';
import ButtonGroup from '../button-group/button-group.jsx';
import BrushMode from '../../containers/brush-mode.jsx';
import BufferedInputHOC from '../forms/buffered-input-hoc.jsx';
import Dropdown from '../dropdown/dropdown.jsx';
import EraserMode from '../../containers/eraser-mode.jsx';
import FillColorIndicatorComponent from '../../containers/fill-color-indicator.jsx';
import FillMode from '../../containers/fill-mode.jsx';
import Input from '../forms/input.jsx';
import InputGroup from '../input-group/input-group.jsx';
import Label from '../forms/label.jsx';
import LabeledIconButton from '../labeled-icon-button/labeled-icon-button.jsx';
import LineMode from '../../containers/line-mode.jsx';
import Loupe from '../loupe/loupe.jsx';
import FixedToolsComponent from '../fixed-tools/fixed-tools.jsx';
import ModeToolsContainer from '../../containers/mode-tools.jsx';
import OvalMode from '../../containers/oval-mode.jsx';
import RectMode from '../../containers/rect-mode.jsx';
@ -44,74 +36,14 @@ import TextMode from '../../containers/text-mode.jsx';
import Formats from '../../lib/format';
import {isBitmap, isVector} from '../../lib/format';
import layout from '../../lib/layout-constants';
import styles from './paint-editor.css';
import bitmapIcon from './icons/bitmap.svg';
import groupIcon from './icons/group.svg';
import redoIcon from './icons/redo.svg';
import sendBackIcon from './icons/send-back.svg';
import sendBackwardIcon from './icons/send-backward.svg';
import sendForwardIcon from './icons/send-forward.svg';
import sendFrontIcon from './icons/send-front.svg';
import undoIcon from './icons/undo.svg';
import ungroupIcon from './icons/ungroup.svg';
import zoomInIcon from './icons/zoom-in.svg';
import zoomOutIcon from './icons/zoom-out.svg';
import zoomResetIcon from './icons/zoom-reset.svg';
const BufferedInput = BufferedInputHOC(Input);
const messages = defineMessages({
costume: {
id: 'paint.paintEditor.costume',
description: 'Label for the name of a costume',
defaultMessage: 'Costume'
},
group: {
defaultMessage: 'Group',
description: 'Label for the button to group shapes',
id: 'paint.paintEditor.group'
},
ungroup: {
defaultMessage: 'Ungroup',
description: 'Label for the button to ungroup shapes',
id: 'paint.paintEditor.ungroup'
},
undo: {
defaultMessage: 'Undo',
description: 'Alt to image for the button to undo an action',
id: 'paint.paintEditor.undo'
},
redo: {
defaultMessage: 'Redo',
description: 'Alt to image for the button to redo an action',
id: 'paint.paintEditor.redo'
},
forward: {
defaultMessage: 'Forward',
description: 'Label for the `Send forward on canvas` button',
id: 'paint.paintEditor.forward'
},
backward: {
defaultMessage: 'Backward',
description: 'Label for the `Send backward on canvas` button',
id: 'paint.paintEditor.backward'
},
front: {
defaultMessage: 'Front',
description: 'Label for the `Send to front of canvas` button',
id: 'paint.paintEditor.front'
},
back: {
defaultMessage: 'Back',
description: 'Label for the `Send to back of canvas` button',
id: 'paint.paintEditor.back'
},
more: {
defaultMessage: 'More',
description: 'Label for dropdown to access more action buttons',
id: 'paint.paintEditor.more'
},
bitmap: {
defaultMessage: 'Convert to Bitmap',
description: 'Label for button that converts the paint editor to bitmap mode',
@ -124,198 +56,28 @@ const messages = defineMessages({
}
});
const PaintEditorComponent = props => {
const redoDisabled = !props.canRedo();
const undoDisabled = !props.canUndo();
return (
const PaintEditorComponent = props => (
<div className={styles.editorContainer}>
{props.canvas !== null ? ( // eslint-disable-line no-negated-condition
<div className={styles.editorContainerTop}>
{/* First row */}
<div className={styles.row}>
{/* Name field */}
<InputGroup>
<MediaQuery minWidth={layout.fullSizeEditorMinWidth}>
<Label text={props.intl.formatMessage(messages.costume)}>
<BufferedInput
className={styles.costumeInput}
type="text"
value={props.name}
onSubmit={props.onUpdateName}
<FixedToolsComponent
canRedo={props.canRedo}
canUndo={props.canUndo}
name={props.name}
onGroup={props.onGroup}
onRedo={props.onRedo}
onSendBackward={props.onSendBackward}
onSendForward={props.onSendForward}
onSendToBack={props.onSendToBack}
onSendToFront={props.onSendToFront}
onUndo={props.onUndo}
onUngroup={props.onUngroup}
onUpdateImage={props.onUpdateImage}
onUpdateName={props.onUpdateName}
/>
</Label>
</MediaQuery>
<MediaQuery maxWidth={layout.fullSizeEditorMinWidth - 1}>
<BufferedInput
className={styles.costumeInput}
type="text"
value={props.name}
onSubmit={props.onUpdateName}
/>
</MediaQuery>
</InputGroup>
{/* Undo/Redo */}
<InputGroup>
<ButtonGroup>
<Button
className={
classNames(
styles.buttonGroupButton,
{
[styles.modNoRightBorder]: !redoDisabled
}
)
}
disabled={undoDisabled}
onClick={props.onUndo}
>
<img
alt={props.intl.formatMessage(messages.undo)}
className={styles.buttonGroupButtonIcon}
draggable={false}
src={undoIcon}
/>
</Button>
<Button
className={
classNames(
styles.buttonGroupButton,
{
[styles.modLeftBorder]: !redoDisabled
}
)
}
disabled={redoDisabled}
onClick={props.onRedo}
>
<img
alt={props.intl.formatMessage(messages.redo)}
className={styles.buttonGroupButtonIcon}
draggable={false}
src={redoIcon}
/>
</Button>
</ButtonGroup>
</InputGroup>
{/* Group/Ungroup */}
<InputGroup className={styles.modDashedBorder}>
<LabeledIconButton
disabled={!shouldShowGroup()}
imgSrc={groupIcon}
title={props.intl.formatMessage(messages.group)}
onClick={props.onGroup}
/>
<LabeledIconButton
disabled={!shouldShowUngroup()}
imgSrc={ungroupIcon}
title={props.intl.formatMessage(messages.ungroup)}
onClick={props.onUngroup}
/>
</InputGroup>
{/* Forward/Backward */}
<InputGroup className={styles.modDashedBorder}>
<LabeledIconButton
disabled={!shouldShowBringForward()}
imgSrc={sendForwardIcon}
title={props.intl.formatMessage(messages.forward)}
onClick={props.onSendForward}
/>
<LabeledIconButton
disabled={!shouldShowSendBackward()}
imgSrc={sendBackwardIcon}
title={props.intl.formatMessage(messages.backward)}
onClick={props.onSendBackward}
/>
</InputGroup>
<MediaQuery minWidth={layout.fullSizeEditorMinWidth}>
<InputGroup className={styles.row}>
<LabeledIconButton
disabled={!shouldShowBringForward()}
imgSrc={sendFrontIcon}
title={props.intl.formatMessage(messages.front)}
onClick={props.onSendToFront}
/>
<LabeledIconButton
disabled={!shouldShowSendBackward()}
imgSrc={sendBackIcon}
title={props.intl.formatMessage(messages.back)}
onClick={props.onSendToBack}
/>
</InputGroup>
{/* To be rotation point */}
{/* <InputGroup>
<LabeledIconButton
imgAlt="Rotation Point"
imgSrc={rotationPointIcon}
title="Rotation Point"
onClick={function () {}}
/>
</InputGroup> */}
</MediaQuery>
<MediaQuery maxWidth={layout.fullSizeEditorMinWidth - 1}>
<InputGroup>
<Dropdown
className={styles.modUnselect}
enterExitTransitionDurationMs={20}
popoverContent={
<InputGroup className={styles.modContextMenu}>
<Button
className={classNames(styles.modMenuItem, {
[styles.modDisabled]: !shouldShowBringForward()
})}
disabled={!shouldShowBringForward()}
onClick={props.onSendToFront}
>
<img
className={styles.menuItemIcon}
draggable={false}
src={sendFrontIcon}
/>
<span>{props.intl.formatMessage(messages.front)}</span>
</Button>
<Button
className={classNames(styles.modMenuItem, {
[styles.modDisabled]: !shouldShowSendBackward()
})}
disabled={!shouldShowSendBackward()}
onClick={props.onSendToBack}
>
<img
className={styles.menuItemIcon}
draggable={false}
src={sendBackIcon}
/>
<span>{props.intl.formatMessage(messages.back)}</span>
</Button>
{/* To be rotation point */}
{/* <Button
className={classNames(styles.modMenuItem, styles.modTopDivider)}
onClick={function () {}}
>
<img
className={styles.menuItemIcon}
draggable={false}
src={rotationPointIcon}
/>
<span>{'Rotation Point'}</span>
</Button> */}
</InputGroup>
}
tipSize={.01}
>
{props.intl.formatMessage(messages.more)}
</Dropdown>
</InputGroup>
</MediaQuery>
</div>
{/* Second Row */}
{isVector(props.format) ?
<div className={styles.row}>
@ -530,7 +292,6 @@ const PaintEditorComponent = props => {
</div>
</div>
);
};
PaintEditorComponent.propTypes = {
canRedo: PropTypes.func.isRequired,