@@ -3,8 +3,8 @@ import { useTranslation } from "react-i18next"
33import Button from "react-bootstrap/Button"
44import ListGroup from "react-bootstrap/ListGroup"
55import { Tooltip } from "react-tooltip"
6- import { FaEye , FaEyeSlash } from "react-icons/fa"
7- import { useSelector , useDispatch } from "react-redux"
6+ import { FaEye , FaEyeSlash , FaMask } from "react-icons/fa"
7+ import { useSelector , useDispatch , useStore } from "react-redux"
88import { DndContext , useSensor , useSensors , PointerSensor } from "@dnd-kit/core"
99import { restrictToVerticalAxis } from "@dnd-kit/modifiers"
1010import {
@@ -20,18 +20,26 @@ import {
2020 selectSelectedLayer ,
2121 selectNumLayers ,
2222 selectAllLayers ,
23+ selectLayerIds ,
2324 updateLayer ,
2425} from "@/features/layers/layersSlice"
26+ import {
27+ selectMaskSources ,
28+ selectAllEffects ,
29+ updateEffect ,
30+ } from "@/features/effects/effectsSlice"
2531
2632const LayerRow = React . memo ( function LayerRow ( {
2733 current,
2834 selected,
2935 numLayers,
3036 layer,
37+ maskTargetName,
3138 handleLayerSelected,
3239 handleToggleLayerVisible,
3340 t,
3441} ) {
42+ const usedAsMask = ! ! maskTargetName
3543 const { name, id, visible } = layer
3644 const activeClass = current ? "active" : selected ? "selected" : ""
3745 const dragClass = numLayers > 1 ? "cursor-move" : ""
@@ -63,23 +71,30 @@ const LayerRow = React.memo(function LayerRow({
6371 onClick = { handleLayerSelected }
6472 >
6573 < div className = "layer-left" >
66- < Button
67- className = "layer-button"
68- variant = "light"
69- data-id = { id }
70- data-tooltip-content = { visible ? t ( "Hide layer" ) : t ( "Show layer" ) }
71- data-tooltip-id = { tooltipId }
72- data-tooltip-place = "top-end"
73- onClick = { ( e ) => {
74- handleToggleLayerVisible ( id , layer . visible )
75- } }
76- >
77- { visible ? < FaEye size = "0.8em" /> : < FaEyeSlash size = "0.8em" /> }
78- </ Button >
74+ { usedAsMask ? (
75+ < span className = "layer-icon" >
76+ < FaMask />
77+ </ span >
78+ ) : (
79+ < Button
80+ className = "layer-button"
81+ variant = "light"
82+ data-id = { id }
83+ data-tooltip-content = { visible ? t ( "Hide layer" ) : t ( "Show layer" ) }
84+ data-tooltip-id = { tooltipId }
85+ data-tooltip-place = "top-end"
86+ onClick = { ( e ) => {
87+ handleToggleLayerVisible ( id , layer . visible )
88+ } }
89+ >
90+ { visible ? < FaEye size = "0.8em" /> : < FaEyeSlash size = "0.8em" /> }
91+ </ Button >
92+ ) }
7993 </ div >
8094
8195 < div className = "d-flex no-select flex-grow-1 align-items-center" >
82- < div className = "flex-grow-1" > { name } </ div >
96+ < div > { name } </ div >
97+ < div className = "flex-grow-1" />
8398 < span
8499 className = "me-2"
85100 style = { { fontSize : "80%" } }
@@ -94,6 +109,7 @@ const LayerRow = React.memo(function LayerRow({
94109
95110const LayerList = ( ) => {
96111 const { t } = useTranslation ( )
112+ const store = useStore ( )
97113 // row has to be dragged 3 pixels before dragging starts; this allows the buttons
98114 // on the row to work properly.
99115 const sensors = useSensors (
@@ -108,6 +124,9 @@ const LayerList = () => {
108124 const selectedLayer = useSelector ( selectSelectedLayer )
109125 const numLayers = useSelector ( selectNumLayers )
110126 const layers = useSelector ( selectAllLayers )
127+ const maskSources = useSelector ( selectMaskSources )
128+
129+ const layersById = Object . fromEntries ( layers . map ( ( l ) => [ l . id , l ] ) )
111130
112131 const handleLayerSelected = useCallback (
113132 ( event ) => {
@@ -139,9 +158,28 @@ const LayerList = () => {
139158 const oldIndex = layers . findIndex ( ( layer ) => layer . id === active . id )
140159 const newIndex = layers . findIndex ( ( layer ) => layer . id === over . id )
141160 dispatch ( moveLayer ( { oldIndex, newIndex } ) )
161+
162+ const state = store . getState ( )
163+ const newLayerIds = selectLayerIds ( state )
164+ const effects = selectAllEffects ( state )
165+
166+ effects
167+ . filter (
168+ ( e ) =>
169+ e . type === "mask" && e . maskMachine === "layer" && e . maskLayerId ,
170+ )
171+ . forEach ( ( effect ) => {
172+ const targetIdx = newLayerIds . indexOf ( effect . layerId )
173+ const sourceIdx = newLayerIds . indexOf ( effect . maskLayerId )
174+
175+ if ( sourceIdx === - 1 || sourceIdx >= targetIdx ) {
176+ dispatch ( updateLayer ( { id : effect . maskLayerId , visible : true } ) )
177+ dispatch ( updateEffect ( { id : effect . id , maskLayerId : null } ) )
178+ }
179+ } )
142180 }
143181 } ,
144- [ dispatch , layers ] ,
182+ [ dispatch , layers , store ] ,
145183 )
146184
147185 return (
@@ -161,20 +199,26 @@ const LayerList = () => {
161199 id = "layers"
162200 style = { { maxHeight : "200px" } }
163201 >
164- { layers . map ( ( layer , index ) => (
165- < LayerRow
166- id = { layer . id }
167- key = { layer . id }
168- current = { currentLayerId === layer . id }
169- selected = { selectedLayer . id === layer . id }
170- numLayers = { numLayers }
171- layer = { layer }
172- handleLayerSelected = { handleLayerSelected }
173- handleToggleLayerVisible = { handleToggleLayerVisible }
174- index = { index }
175- t = { t }
176- />
177- ) ) }
202+ { layers . map ( ( layer , index ) => {
203+ const targetLayerId = maskSources . get ( layer . id )
204+ const targetLayer = targetLayerId && layersById [ targetLayerId ]
205+
206+ return (
207+ < LayerRow
208+ id = { layer . id }
209+ key = { layer . id }
210+ current = { currentLayerId === layer . id }
211+ selected = { selectedLayer . id === layer . id }
212+ numLayers = { numLayers }
213+ layer = { layer }
214+ maskTargetName = { targetLayer ?. name }
215+ handleLayerSelected = { handleLayerSelected }
216+ handleToggleLayerVisible = { handleToggleLayerVisible }
217+ index = { index }
218+ t = { t }
219+ />
220+ )
221+ } ) }
178222 </ ListGroup >
179223 </ div >
180224 </ SortableContext >
0 commit comments