Skip to content

Commit 68860c6

Browse files
committed
Merge branch 'dev'
2 parents 721c4cb + 54986ee commit 68860c6

17 files changed

Lines changed: 425 additions & 224 deletions

public/locales/en/translation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
"still": "Still",
9494
"editAnimation": "Edit Animation",
9595
"spriteAnimationEditor": "Sprite Animation Editor",
96+
"exportSpriteAnimation": "Export Sprite Animation",
9697
"animated": "Animated",
9798
"openDoor": "Open Door",
9899
"closeDoor": "Close Door",
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from "react";
2+
import useSpriteAnimEditorOpen from "../../hooks/spriteAnim/useSpriteAnimEditorOpen";
3+
import {Button} from "@mui/material";
4+
import {useTranslation} from "react-i18next";
5+
import {Animation} from "@mui/icons-material";
6+
7+
export default function EditAnimationButton() {
8+
const {t} = useTranslation();
9+
const [isAnimEditorOpen, setAnimEditorOpen] = useSpriteAnimEditorOpen();
10+
11+
return (
12+
<Button
13+
variant={"outlined"}
14+
color={"secondary"}
15+
size={"small"}
16+
fullWidth
17+
onClick={() => setAnimEditorOpen(true)}
18+
disabled={isAnimEditorOpen}
19+
>
20+
<Animation
21+
sx={{marginRight: 0.5}}
22+
fontSize={"small"}
23+
/>
24+
{t("sprite.editAnimation")}
25+
</Button>
26+
)
27+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import {Download} from "@mui/icons-material";
2+
import {Button, CircularProgress} from "@mui/material";
3+
import React from "react";
4+
import {useTranslation} from "react-i18next";
5+
import useDownloadSpriteAnimsAsPNG from "../../hooks/spriteAnim/useDownloadSpriteAnimsAsPNG";
6+
import {useSelectedElemIDValue} from "../../hooks/elements/useSelectedElem";
7+
8+
export default function SpriteAnimExportButton() {
9+
const {t} = useTranslation();
10+
const selectedElementID = useSelectedElemIDValue();
11+
const downloadPNGs = useDownloadSpriteAnimsAsPNG();
12+
const [isDownloadingPNGs, setIsDownloadingPNGs] = React.useState(false);
13+
14+
const onClick = React.useCallback(() => {
15+
if (isDownloadingPNGs)
16+
return;
17+
18+
setIsDownloadingPNGs(true);
19+
downloadPNGs({elementID: selectedElementID}).finally(() => setIsDownloadingPNGs(false));
20+
}, [isDownloadingPNGs, downloadPNGs, selectedElementID]);
21+
22+
return (
23+
<Button
24+
variant={"outlined"}
25+
color={"secondary"}
26+
size={"small"}
27+
fullWidth
28+
disabled={isDownloadingPNGs}
29+
onClick={onClick}
30+
>
31+
{isDownloadingPNGs && (
32+
<CircularProgress
33+
sx={{marginRight: 0.5}}
34+
size={16}
35+
color={"inherit"}
36+
/>
37+
)}
38+
{!isDownloadingPNGs && (
39+
<Download
40+
sx={{marginRight: 0.5}}
41+
fontSize={"small"}
42+
/>
43+
)}
44+
{t("sprite.exportSpriteAnimation")}
45+
</Button>
46+
);
47+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import {convertImageAssetToDDS} from "../../utils/dds/convertImageToDDS";
2+
import {Gradient} from "@mui/icons-material";
3+
import {Button} from "@mui/material";
4+
import React from "react";
5+
import useMapAsset from "../../hooks/assets/useMapAsset";
6+
import GUID from "../../types/common/GUID";
7+
import {useTranslation} from "react-i18next";
8+
9+
export interface SpriteConvertToDDSButtonProps {
10+
assetID: GUID | undefined;
11+
}
12+
13+
export default function SpriteConvertToDDSButton(props: SpriteConvertToDDSButtonProps) {
14+
const {t} = useTranslation();
15+
const asset = useMapAsset(props.assetID);
16+
17+
const isGIF = asset?.blob.type === "image/gif";
18+
const isDDS = asset?.blob.type === "image/dds";
19+
20+
if (!asset || isGIF || isDDS)
21+
return null;
22+
return (
23+
<Button
24+
variant={"outlined"}
25+
color={"secondary"}
26+
size={"small"}
27+
fullWidth
28+
onClick={() => convertImageAssetToDDS(props.assetID).catch(console.error)}
29+
>
30+
<Gradient
31+
sx={{marginRight: 0.5}}
32+
fontSize={"small"}
33+
/>
34+
{t("sprite.convertToDDS")}
35+
</Button>
36+
);
37+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import {Download} from "@mui/icons-material";
2+
import {Button, CircularProgress, IconButton, Tooltip} from "@mui/material";
3+
import React from "react";
4+
import useMapAsset from "../../hooks/assets/useMapAsset";
5+
import GUID from "../../types/common/GUID";
6+
import {useTranslation} from "react-i18next";
7+
import useDownloadMapAssetAsPNG from "../../hooks/assets/useDownloadMapAssetAsPNG";
8+
9+
export interface SpriteDownloadPNGButtonProps {
10+
assetID: GUID | undefined;
11+
small?: boolean;
12+
}
13+
14+
export default function SpriteDownloadPNGButton(props: SpriteDownloadPNGButtonProps) {
15+
const {t} = useTranslation();
16+
const asset = useMapAsset(props.assetID);
17+
const downloadPNG = useDownloadMapAssetAsPNG();
18+
const [isDownloadingPNG, setIsDownloadingPNG] = React.useState(false);
19+
20+
const onClick = React.useCallback(() => {
21+
if (isDownloadingPNG)
22+
return;
23+
24+
setIsDownloadingPNG(true);
25+
downloadPNG({id: props.assetID}).finally(() => setIsDownloadingPNG(false));
26+
}, [isDownloadingPNG, downloadPNG, asset]);
27+
28+
const isDDS = asset?.blob.type === "image/dds";
29+
30+
if (!asset || !isDDS)
31+
return null;
32+
33+
if (props.small)
34+
return (
35+
<Tooltip title={t("sprite.downloadAsPNG")}>
36+
<IconButton
37+
color={"secondary"}
38+
size={"small"}
39+
disabled={isDownloadingPNG}
40+
onClick={onClick}
41+
>
42+
{isDownloadingPNG ? (
43+
<CircularProgress
44+
size={16}
45+
color={"inherit"}
46+
/>
47+
) : (
48+
<Download
49+
fontSize={"small"}
50+
/>
51+
)}
52+
</IconButton>
53+
</Tooltip>
54+
);
55+
56+
return (
57+
<Button
58+
variant={"outlined"}
59+
color={"secondary"}
60+
size={"small"}
61+
fullWidth
62+
disabled={isDownloadingPNG}
63+
onClick={onClick}
64+
>
65+
{isDownloadingPNG && (
66+
<CircularProgress
67+
sx={{marginRight: 0.5}}
68+
size={16}
69+
color={"inherit"}
70+
/>
71+
)}
72+
{!isDownloadingPNG && (
73+
<Download
74+
sx={{marginRight: 0.5}}
75+
fontSize={"small"}
76+
/>
77+
)}
78+
{t("sprite.downloadAsPNG")}
79+
</Button>
80+
);
81+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import {Download} from "@mui/icons-material";
2+
import {Button, IconButton, Tooltip} from "@mui/material";
3+
import React from "react";
4+
import useMapAsset from "../../hooks/assets/useMapAsset";
5+
import GUID from "../../types/common/GUID";
6+
import {useTranslation} from "react-i18next";
7+
import useDownloadMapAsset from "../../hooks/assets/useDownloadMapAsset";
8+
9+
export interface SpriteDownloadRawButtonProps {
10+
assetID: GUID | undefined;
11+
small?: boolean;
12+
}
13+
14+
export default function SpriteDownloadRawButton(props: SpriteDownloadRawButtonProps) {
15+
const {t} = useTranslation();
16+
const asset = useMapAsset(props.assetID);
17+
const downloadRaw = useDownloadMapAsset();
18+
19+
const fileName = asset?.id ?? "sprite";
20+
const assetType = asset?.blob.type.split("/")[1].toLowerCase();
21+
22+
const onClick = React.useCallback(() => {
23+
if (!asset)
24+
return;
25+
26+
downloadRaw({id: props.assetID, fileName});
27+
}, [downloadRaw, props.assetID, fileName, asset]);
28+
29+
if (!asset)
30+
return null;
31+
32+
if (props.small)
33+
return (
34+
<Tooltip title={t("sprite.downloadAsType", {type: assetType || "N/A"})}>
35+
<IconButton
36+
color={"primary"}
37+
size={"small"}
38+
onClick={onClick}
39+
>
40+
<Download fontSize={"small"}/>
41+
</IconButton>
42+
</Tooltip>
43+
);
44+
45+
return (
46+
<Button
47+
variant={"outlined"}
48+
color={"secondary"}
49+
size={"small"}
50+
fullWidth
51+
onClick={onClick}
52+
>
53+
<Download
54+
sx={{marginRight: 0.5}}
55+
fontSize={"small"}
56+
/>
57+
{t("sprite.downloadAsType", {type: assetType || "N/A"})}
58+
</Button>
59+
);
60+
}

src/components/modals/MapAssets/Images/ImageAssetModalButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export interface MapAssetModalButtonProps {
1111

1212
export default function ImageAssetModalButton(props: MapAssetModalButtonProps) {
1313
const asset = useMapAsset(props.id);
14-
// const image = useElementAsImageBlob(props.id);
14+
// const image = useMapAssetAsImageBlob(props.id);
1515

1616
if (!asset)
1717
return null;

src/components/modals/SpriteAnimation/AnimatedSpriteEditorActions.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {Button, ButtonGroup} from "@mui/material";
33
import uploadSpriteAnimFrames from "../../../utils/spriteAnim/uploadSpriteAnimFrames";
44
import uploadSpriteAnimGIF from "../../../utils/spriteAnim/uploadSpriteAnimGIF";
55
import useSelectedSpriteAnim from "../../../hooks/spriteAnim/useSelectedSpriteAnim";
6+
import SpriteAnimExportButton from "../../buttons/SpriteAnimExportButton";
67

78
export function AnimatedSpriteEditorActions() {
89
const [, setAnimation] = useSelectedSpriteAnim();
@@ -28,6 +29,7 @@ export function AnimatedSpriteEditorActions() {
2829
>
2930
Upload GIF
3031
</Button>
32+
<SpriteAnimExportButton/>
3133
<Button
3234
startIcon={<RestartAlt/>}
3335
variant={"outlined"}

src/components/modals/SpriteAnimation/frames/AnimatedSpriteFrameRow.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import React from "react";
22
import {Delete, DragHandle} from "@mui/icons-material";
3-
import {IconButton, InputAdornment, ListItem} from "@mui/material";
3+
import {ButtonGroup, IconButton, InputAdornment, ListItem} from "@mui/material";
44
import FlexNumericInput from "../../../properties/util/FlexNumericInput";
55
import LISpriteAnimationFrame from "../../../../types/li/LISpriteAnimationFrame";
66
import useSpriteThumbnail from "../../../../hooks/sprites/useSpriteThumbnail";
7+
import SpriteDownloadPNGButton from "../../../buttons/SpriteDownloadPNGButton";
8+
import SpriteDownloadRawButton from "../../../buttons/SpriteDownloadRawButton";
79

810
export interface AnimatedSpriteFrameRowProps {
911
frame: LISpriteAnimationFrame;
@@ -70,13 +72,19 @@ export default function AnimatedSpriteFrameRow(props: AnimatedSpriteFrameRowProp
7072
}}
7173
/>
7274

73-
<IconButton
74-
size={"small"}
75+
<ButtonGroup
7576
sx={{ml: 1, mr: 1}}
76-
onClick={props.onDelete}
7777
>
78-
<Delete/>
79-
</IconButton>
78+
<SpriteDownloadRawButton assetID={props.frame.spriteID} small/>
79+
<SpriteDownloadPNGButton assetID={props.frame.spriteID} small/>
80+
81+
<IconButton
82+
size={"small"}
83+
onClick={props.onDelete}
84+
>
85+
<Delete/>
86+
</IconButton>
87+
</ButtonGroup>
8088

8189
</ListItem>
8290
);

0 commit comments

Comments
 (0)