Interrim Checkin

This commit is contained in:
Robin Davies
2023-06-28 10:38:08 -04:00
parent bc410edd88
commit 2904518181
14 changed files with 86 additions and 42 deletions
+1 -1
View File
@@ -200,7 +200,7 @@ const appStyles = (theme: Theme) => createStyles({
}, },
heroContent: { heroContent: {
backgroundColor: isDarkMode()? theme.palette.background.default: "#FFFFFF", backgroundColor: isDarkMode()? "#222": "#FFFFFF",
position: "relative", position: "relative",
height: "100%", height: "100%",
width: "100%" width: "100%"
+5 -2
View File
@@ -33,6 +33,7 @@ import { PiPedalModel, PiPedalModelFactory, ListenHandle} from './PiPedalModel';
import ButtonBase from '@mui/material/ButtonBase' import ButtonBase from '@mui/material/ButtonBase'
import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
import {PedalboardItem} from './Pedalboard'; import {PedalboardItem} from './Pedalboard';
import isDarkMode from './DarkMode';
export const StandardItemSize = { width: 80, height: 140 } export const StandardItemSize = { width: 80, height: 140 }
@@ -204,14 +205,16 @@ const FilePropertyControl =
<div style={{ flex: "0 0 auto", width: "100%" }}> <div style={{ flex: "0 0 auto", width: "100%" }}>
<ButtonBase style={{ width: "100%", borderRadius: "4px 4px 0px 0px", overflow: "hidden", marginTop: 8 }} onClick={() => { this.onFileClick() }} > <ButtonBase style={{ width: "100%", borderRadius: "4px 4px 0px 0px", overflow: "hidden", marginTop: 8 }} onClick={() => { this.onFileClick() }} >
<div style={{ width: "100%", background: "rgba(0,0,0,0.07)", borderRadius: "4px 4px 0px 0px" }}> <div style={{ width: "100%", background:
isDarkMode()? "rgba(255,255,255,0.03)": "rgba(0,0,0,0.07)",
borderRadius: "4px 4px 0px 0px" }}>
<div style={{ display: "flex", alignItems: "center", flexFlow: "row nowrap" }}> <div style={{ display: "flex", alignItems: "center", flexFlow: "row nowrap" }}>
<Typography noWrap={true} style={{ flex: "1 1 100%", textAlign: "start", verticalAlign: "center", paddingTop: 4, paddingBottom: 4, paddingLeft: 4 }} <Typography noWrap={true} style={{ flex: "1 1 100%", textAlign: "start", verticalAlign: "center", paddingTop: 4, paddingBottom: 4, paddingLeft: 4 }}
variant='caption' variant='caption'
>{value}</Typography> >{value}</Typography>
<MoreHorizIcon style={{ flex: "0 0 auto", width: "16px", height: "16px", verticalAlign: "center", opacity: 0.5, marginRight: 4 }} /> <MoreHorizIcon style={{ flex: "0 0 auto", width: "16px", height: "16px", verticalAlign: "center", opacity: 0.5, marginRight: 4 }} />
</div> </div>
<div style={{ height: "1px", width: "100%", background: "black" }}>&nbsp;</div> <div style={{ height: "1px", width: "100%", background: this.props.theme.palette.text.secondary }}>&nbsp;</div>
</div> </div>
</ButtonBase> </ButtonBase>
</div> </div>
+1 -1
View File
@@ -86,7 +86,7 @@ const pluginGridStyles = (theme: Theme) => createStyles({
justifyContent: "space-between", justifyContent: "space-between",
paddingLeft: "24px", paddingLeft: "24px",
paddingRight: "48px", paddingRight: "48px",
background: theme.palette.background.paper,
}, },
paper: { paper: {
position: "relative", position: "relative",
+5 -3
View File
@@ -45,6 +45,8 @@ import PluginInfoDialog from './PluginInfoDialog';
import { GetControlView } from './ControlViewFactory'; import { GetControlView } from './ControlViewFactory';
import MidiBindingsDialog from './MidiBindingsDialog'; import MidiBindingsDialog from './MidiBindingsDialog';
import PluginPresetSelector from './PluginPresetSelector'; import PluginPresetSelector from './PluginPresetSelector';
import {ReactComponent as OldDeleteIcon} from "./svg/old_delete_outline_24dp.svg";
import {ReactComponent as MidiIcon} from "./svg/ic_midi.svg";
@@ -461,7 +463,7 @@ export const MainPage =
</div> </div>
<div style={{ flex: "0 0 auto", display: (canInsert || canAppend) ? "block" : "none", paddingRight: 8 }}> <div style={{ flex: "0 0 auto", display: (canInsert || canAppend) ? "block" : "none", paddingRight: 8 }}>
<IconButton onClick={(e) => { this.onAddClick(e) }} size="large"> <IconButton onClick={(e) => { this.onAddClick(e) }} size="large">
<AddIcon /> <AddIcon style={{opacity: 0.6}} />
</IconButton> </IconButton>
<Menu <Menu
id="add-menu" id="add-menu"
@@ -482,7 +484,7 @@ export const MainPage =
<IconButton <IconButton
onClick={() => { this.onDeletePedal(pedalboardItem?.instanceId ?? -1) }} onClick={() => { this.onDeletePedal(pedalboardItem?.instanceId ?? -1) }}
size="large"> size="large">
<img src="/img/old_delete_outline_black_24dp.svg" alt="Delete" style={{ width: 24, height: 24, opacity: 0.6 }} /> <OldDeleteIcon style={{height: 24, width: 24,fill: this.props.theme.palette.text.primary, opacity: 0.6}} />
</IconButton> </IconButton>
</div> </div>
<div style={{ flex: "0 0 auto" }}> <div style={{ flex: "0 0 auto" }}>
@@ -502,7 +504,7 @@ export const MainPage =
<IconButton <IconButton
onClick={(e) => { this.handleMidiConfiguration(instanceId); }} onClick={(e) => { this.handleMidiConfiguration(instanceId); }}
size="large"> size="large">
<img src="img/ic_midi.svg" style={{ width: 24, height: 24, opacity: 0.6 }} alt="Midi configuration" /> <MidiIcon style={{height: 24, width: 24,fill: this.props.theme.palette.text.primary, opacity: 0.6}} />
</IconButton> </IconButton>
</div> </div>
+6 -4
View File
@@ -33,6 +33,7 @@ import Draggable from './Draggable'
import Rect from './Rect'; import Rect from './Rect';
import {PiPedalStateError} from './PiPedalError'; import {PiPedalStateError} from './PiPedalError';
import Utility from './Utility'; import Utility from './Utility';
import isDarkMode from './DarkMode';
import { import {
Pedalboard, PedalboardItem, PedalboardSplitItem, SplitType Pedalboard, PedalboardItem, PedalboardSplitItem, SplitType
@@ -45,8 +46,9 @@ const END_CONTROL = Pedalboard.END_CONTROL;
const START_PEDALBOARD_ITEM_URI = Pedalboard.START_PEDALBOARD_ITEM_URI; const START_PEDALBOARD_ITEM_URI = Pedalboard.START_PEDALBOARD_ITEM_URI;
const END_PEDALBOARD_ITEM_URI = Pedalboard.END_PEDALBOARD_ITEM_URI; const END_PEDALBOARD_ITEM_URI = Pedalboard.END_PEDALBOARD_ITEM_URI;
const ENABLED_CONNECTOR_COLOR = "#666"; const ENABLED_CONNECTOR_COLOR = isDarkMode() ? "#CCC": "#666";
const DISABLED_CONNECTOR_COLOR = "#CCC"; const DISABLED_CONNECTOR_COLOR = isDarkMode() ? "#666": "#CCC";
const CELL_WIDTH: number = 96; const CELL_WIDTH: number = 96;
@@ -130,14 +132,14 @@ const pedalboardStyles = (theme: Theme) => createStyles({
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
background: theme.palette.background.paper, background: theme.palette.background.default,
marginLeft: (CELL_WIDTH - FRAME_SIZE) / 2, marginLeft: (CELL_WIDTH - FRAME_SIZE) / 2,
marginRight: (CELL_WIDTH - FRAME_SIZE) / 2, marginRight: (CELL_WIDTH - FRAME_SIZE) / 2,
marginTop: (CELL_HEIGHT - FRAME_SIZE) / 2, marginTop: (CELL_HEIGHT - FRAME_SIZE) / 2,
marginBottom: (CELL_HEIGHT - FRAME_SIZE) / 2, marginBottom: (CELL_HEIGHT - FRAME_SIZE) / 2,
width: FRAME_SIZE, width: FRAME_SIZE,
height: FRAME_SIZE, height: FRAME_SIZE,
border: "1pt #666 solid", border: isDarkMode()? "1pt #AAA solid": "1pt #666 solid",
borderRadius: 6 borderRadius: 6
}, },
borderlessIconFrame: { borderlessIconFrame: {
+21 -21
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2022 Robin Davies // Copyright (c) 2022 Robin Davies
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of // Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in // this software and associated documentation files (the "Software"), to deal in
@@ -30,7 +30,7 @@ import Switch from '@mui/material/Switch';
import Utility, {nullCast} from './Utility'; import Utility, {nullCast} from './Utility';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import {PiPedalModel,PiPedalModelFactory} from './PiPedalModel'; import {PiPedalModel,PiPedalModelFactory} from './PiPedalModel';
import {ReactComponent as DialIcon} from './svg/fx_dial.svg';
const MIN_ANGLE = -135; const MIN_ANGLE = -135;
const MAX_ANGLE = 135; const MAX_ANGLE = 135;
@@ -72,8 +72,8 @@ const styles = (theme: Theme) => createStyles({
right: 0, right: 0,
bottom: 4, bottom: 4,
textAlign: "center", textAlign: "center",
background: "white", background: theme.palette.background.paper,
color: "#666", color: theme.palette.text.secondary,
// zIndex: -1, // zIndex: -1,
} }
}); });
@@ -98,7 +98,7 @@ const PluginControl =
{ {
frameRef: React.RefObject<HTMLDivElement>; frameRef: React.RefObject<HTMLDivElement>;
imgRef: React.RefObject<HTMLImageElement>; imgRef: React.RefObject<SVGSVGElement>;
inputRef: React.RefObject<HTMLInputElement>; inputRef: React.RefObject<HTMLInputElement>;
selectRef: React.RefObject<HTMLSelectElement>; selectRef: React.RefObject<HTMLSelectElement>;
@@ -243,7 +243,7 @@ const PluginControl =
e.preventDefault(); e.preventDefault();
} }
isValidPointer(e: PointerEvent<HTMLImageElement>): boolean { isValidPointer(e: PointerEvent<SVGSVGElement>): boolean {
if (e.pointerType === "mouse") { if (e.pointerType === "mouse") {
return e.button === 0; return e.button === 0;
} else if (e.pointerType === "pen") { } else if (e.pointerType === "pen") {
@@ -257,9 +257,9 @@ const PluginControl =
touchDown: boolean = false; touchDown: boolean = false;
touchIdentifier: number = -1; touchIdentifier: number = -1;
onTouchStart(e: TouchEvent<HTMLImageElement>) { onTouchStart(e: TouchEvent<SVGSVGElement>) {
} }
onTouchMove(e: TouchEvent<HTMLImageElement>) { onTouchMove(e: TouchEvent<SVGSVGElement>) {
// e.preventDefault(); // e.preventDefault();
e.stopPropagation(); // cancels scroll!!! e.stopPropagation(); // cancels scroll!!!
@@ -282,7 +282,7 @@ const PluginControl =
pointerId: number = 0; pointerId: number = 0;
pointerType: string = ""; pointerType: string = "";
isCapturedPointer(e: PointerEvent<HTMLImageElement>): boolean { isCapturedPointer(e: PointerEvent<SVGSVGElement>): boolean {
return this.mouseDown return this.mouseDown
&& e.pointerId === this.pointerId && e.pointerId === this.pointerId
&& e.pointerType === this.pointerType; && e.pointerType === this.pointerType;
@@ -294,9 +294,9 @@ const PluginControl =
dRange: number = 0; dRange: number = 0;
pointersDown: number = 0; pointersDown: number = 0;
captureElement?: HTMLElement = undefined; captureElement?: SVGSVGElement = undefined;
onPointerDown(e: PointerEvent<HTMLImageElement>): void { onPointerDown(e: PointerEvent<SVGSVGElement>): void {
if (!this.mouseDown && this.isValidPointer(e)) { if (!this.mouseDown && this.isValidPointer(e)) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@@ -351,7 +351,7 @@ const PluginControl =
} }
onPointerLostCapture(e: PointerEvent<HTMLImageElement>) { onPointerLostCapture(e: PointerEvent<SVGSVGElement>) {
if (this.isCapturedPointer(e)) { if (this.isCapturedPointer(e)) {
--this.pointersDown; --this.pointersDown;
@@ -361,7 +361,7 @@ const PluginControl =
} }
updateRange(e: PointerEvent<HTMLImageElement>): number { updateRange(e: PointerEvent<SVGSVGElement>): number {
let ultraHigh = false; let ultraHigh = false;
let high = false; let high = false;
@@ -396,7 +396,7 @@ const PluginControl =
this.lastX = e.clientX; this.lastX = e.clientX;
return this.dRange; return this.dRange;
} }
onPointerUp(e: PointerEvent<HTMLImageElement>) { onPointerUp(e: PointerEvent<SVGSVGElement>) {
if (this.isCapturedPointer(e)) { if (this.isCapturedPointer(e)) {
--this.pointersDown; --this.pointersDown;
@@ -414,7 +414,7 @@ const PluginControl =
} }
} }
releaseCapture(e: PointerEvent<HTMLImageElement>) releaseCapture(e: PointerEvent<SVGSVGElement>)
{ {
let img = this.imgRef.current; let img = this.imgRef.current;
@@ -437,7 +437,7 @@ const PluginControl =
} }
onPointerMove(e: PointerEvent<HTMLImageElement>): void { onPointerMove(e: PointerEvent<SVGSVGElement>): void {
if (this.isCapturedPointer(e)) { if (this.isCapturedPointer(e)) {
e.preventDefault(); e.preventDefault();
let dRange = this.updateRange(e) let dRange = this.updateRange(e)
@@ -651,6 +651,7 @@ const PluginControl =
return (<div>#Error</div>); return (<div>#Error</div>);
} }
let dialColor = this.props.theme.palette.text.primary;
let control: UiControl = t; let control: UiControl = t;
this.uiControl = control; this.uiControl = control;
let value = this.props.value; let value = this.props.value;
@@ -684,13 +685,12 @@ const PluginControl =
this.makeSelect(control, value) this.makeSelect(control, value)
) : ( ) : (
<div style={{ flex: "0 1 auto" }}> <div style={{ flex: "0 1 auto" }}>
<img ref={this.imgRef} src="img/fx_dial.svg" <DialIcon ref={this.imgRef}
style={{ overscrollBehavior: "none", touchAction: "none", style={{ overscrollBehavior: "none", touchAction: "none", fill: dialColor,
width: 36, height: 36, opacity: DEFAULT_OPACITY, transform: this.getRotationTransform() }} width: 36, height: 36, opacity: DEFAULT_OPACITY, transform: this.getRotationTransform() }}
draggable="true"
onTouchStart={this.onTouchStart} onTouchMove={this.onTouchMove} onTouchStart={this.onTouchStart} onTouchMove={this.onTouchMove}
onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp} onPointerMoveCapture={this.onPointerMove} onDrag={this.onDrag} onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp} onPointerMoveCapture={this.onPointerMove} onDrag={this.onDrag}
alt={control.name}
/> />
</div> </div>
) )
@@ -736,7 +736,7 @@ const PluginControl =
); );
} }
/* /*
isSamePointer(PointerEvent<HTMLImageElement> e): boolean isSamePointer(PointerEvent<SVGSVGElement> e): boolean
{ {
return e.pointerId === this.pointerId return e.pointerId === this.pointerId
&& e.pointerType === this.pointerType; && e.pointerType === this.pointerType;
+7 -4
View File
@@ -39,6 +39,7 @@ import FilePropertyDialog from './FilePropertyDialog';
import JsonAtom from './JsonAtom'; import JsonAtom from './JsonAtom';
import PluginOutputControl from './PluginOutputControl'; import PluginOutputControl from './PluginOutputControl';
import Units from './Units'; import Units from './Units';
import isDarkMode from './DarkMode';
export const StandardItemSize = { width: 80, height: 110 }; export const StandardItemSize = { width: 80, height: 110 };
@@ -78,6 +79,8 @@ let endPluginInfo: UiPlugin =
makeIoPluginInfo("Output", Pedalboard.END_PEDALBOARD_ITEM_URI); makeIoPluginInfo("Output", Pedalboard.END_PEDALBOARD_ITEM_URI);
const darkBackgroundColor = "#181818";
const styles = (theme: Theme) => createStyles({ const styles = (theme: Theme) => createStyles({
frame: { frame: {
display: "block", display: "block",
@@ -96,7 +99,7 @@ const styles = (theme: Theme) => createStyles({
paddingRight: 4, paddingRight: 4,
paddingBottom: 24, paddingBottom: 24,
left: 0, left: 0,
background: "white", background: isDarkMode() ? darkBackgroundColor: theme.palette.background.default,
zIndex: 3 zIndex: 3
}, },
@@ -106,7 +109,7 @@ const styles = (theme: Theme) => createStyles({
marginRight: 22, marginRight: 22,
paddingLeft: 4, paddingLeft: 4,
paddingBottom: 24, paddingBottom: 24,
background: "white", background: isDarkMode() ? darkBackgroundColor: theme.palette.background.default,
zIndex: 3 zIndex: 3
}, },
@@ -116,7 +119,7 @@ const styles = (theme: Theme) => createStyles({
paddingRight: 22, paddingRight: 22,
paddingLeft: 12, paddingLeft: 12,
paddingBottom: 24, paddingBottom: 24,
background: "white", background: isDarkMode() ? darkBackgroundColor: theme.palette.background.default,
zIndex: 3 zIndex: 3
}, },
@@ -188,7 +191,7 @@ const styles = (theme: Theme) => createStyles({
portGroupTitle: { portGroupTitle: {
position: "absolute", position: "absolute",
top: -15, top: -15,
background: "white", background: isDarkMode() ? darkBackgroundColor: theme.palette.background.default,
textOverflow: "ellipsis", textOverflow: "ellipsis",
minWidth: 0, minWidth: 0,
marginLeft: 20, marginLeft: 20,
+12 -2
View File
@@ -33,6 +33,8 @@ import {PluginUiPresets} from './PluginPreset';
import Divider from "@mui/material/Divider"; import Divider from "@mui/material/Divider";
import {ReactComponent as PluginPresetsIcon} from "./svg/ic_pluginpreset.svg";
import {ReactComponent as PluginPresetIcon} from "./svg/ic_pluginpreset2.svg";
interface PluginPresetSelectorProps extends WithStyles<typeof styles> { interface PluginPresetSelectorProps extends WithStyles<typeof styles> {
pluginUri?: string; pluginUri?: string;
@@ -60,6 +62,12 @@ interface PluginPresetSelectorState {
const styles = (theme: Theme) => createStyles({ const styles = (theme: Theme) => createStyles({
itemIcon: { itemIcon: {
width: 24, height: 24, marginRight: "4px", opacity: 0.6 width: 24, height: 24, marginRight: "4px", opacity: 0.6
},
pluginIcon: {
width: 24, height: 24, opacity: 0.6,fill: theme.palette.text.primary
},
pluginMenuIcon: {
width: 24, height: 24, opacity: 0.6,fill: theme.palette.text.primary, marginRight: 4
} }
}); });
@@ -285,7 +293,7 @@ const PluginPresetSelector =
return ( return (
<div > <div >
<IconButton onClick={(e)=> this.handlePresetMenuClick(e)} size="large"> <IconButton onClick={(e)=> this.handlePresetMenuClick(e)} size="large">
<img src="img/ic_pluginpreset.svg" style={{ width: 24, height: 24,opacity: 0.6 }} alt="Plugin Presets" /> <PluginPresetsIcon className={classes.pluginIcon}/>
</IconButton> </IconButton>
<Menu <Menu
id="edit-plugin-presets-menu" id="edit-plugin-presets-menu"
@@ -310,7 +318,9 @@ const PluginPresetSelector =
this.state.presets.presets.map((preset) => { this.state.presets.presets.map((preset) => {
return (<MenuItem key={preset.instanceId} return (<MenuItem key={preset.instanceId}
onClick={(e) => this.handleLoadPluginPreset(preset.instanceId)} onClick={(e) => this.handleLoadPluginPreset(preset.instanceId)}
><img src="img/ic_pluginpreset2.svg" className={classes.itemIcon} alt="" /> >
<PluginPresetIcon className={classes.pluginMenuIcon}/>
{preset.label}</MenuItem>); {preset.label}</MenuItem>);
}) })
} }
+4 -4
View File
@@ -36,15 +36,15 @@ const styles = ({ palette }: Theme) => createStyles({
position: "absolute", position: "absolute",
width: "100%", width: "100%",
height: "100%", height: "100%",
background: "#000000", background: palette.action.hover,
opacity: 0.1 //opacity: palette.action.hoverOpacity
}, },
selected: { selected: {
position: "absolute", position: "absolute",
width: "100%", width: "100%",
height: "100%", height: "100%",
background: palette.action.active, background: palette.action.selected,
opacity: 0.3 //opacity: palette.action.selectedOpacity
} }
}); });

Before

Width:  |  Height:  |  Size: 882 B

After

Width:  |  Height:  |  Size: 882 B

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<path d="M20.953,7.993L20.949,4c0-1.1-0.891-2-1.99-2h-4h-3h-3c-1.1,0-1.99,0.9-1.99,2h1.99h4h1h5h0.006v16h0.004
c1.1,0,1.99-0.9,1.99-2V8L20.953,7.993z"/>
<path d="M17.993,10.993L17.99,7c0-1.1-0.891-2-1.99-2h-4H9H6C4.9,5,4.01,5.9,4.01,7l-0.003,3.993L4,11v10c0,1.1,0.891,2,1.99,2H6h10
h0.01c1.1,0,1.99-0.9,1.99-2V11L17.993,10.993z M16,12v9H6v-9V7h4h1h5V12z"/>
<rect x="8" y="9" width="6" height="2"/>
<circle cx="11" cy="15.859" r="2"/>
</svg>

After

Width:  |  Height:  |  Size: 919 B

+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<path fill="none" d="M0,0h24v24H0V0z"/>
<g>
<path d="M20,4h-4.5l-1-1h-5l-1,1H4v2h1v13c0,1.1,0.9,2,2,2h10c1.1,0,2-0.9,2-2V6h1V4z M17,19H7V6h10V19z"/>
<rect x="9" y="8" width="2" height="8"/>
<rect x="13" y="8" width="2" height="8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 723 B