LayerBox.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * <<
  3. * Davinci
  4. * ==
  5. * Copyright (C) 2016 - 2017 EDP
  6. * ==
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. * >>
  19. */
  20. import React, {
  21. useContext,
  22. useMemo,
  23. useCallback,
  24. useState,
  25. memo,
  26. ReactNode
  27. } from 'react'
  28. import classnames from 'classnames'
  29. import { LayerListContext, LayerContext } from '../util'
  30. import { DraggableProxyContext } from '../Draggable'
  31. import { ContextMenuProxyContext } from '../ContextMenu'
  32. import { useSelector } from 'react-redux'
  33. import { makeSelectCurrentOperateItemParams } from 'app/containers/Display/selectors'
  34. import { SecondaryGraphTypes } from '../../Setting'
  35. interface ILayerBoxProps {
  36. children?: ReactNode
  37. }
  38. const LayerBox: React.FC = (props: ILayerBoxProps) => {
  39. const { onSelectionChange, onEditLabelChange } = useContext(LayerListContext)
  40. const { layer, operationInfo } = useContext(LayerContext)
  41. const { id: layerId, index, subType } = layer
  42. const operateItemParams = useSelector(makeSelectCurrentOperateItemParams())
  43. const dragging = operationInfo?.dragging
  44. const params = useMemo(
  45. () =>
  46. dragging
  47. ? operateItemParams.find((_) => _.id === layerId)?.params
  48. : layer.params,
  49. [dragging, operateItemParams, layer.params]
  50. )
  51. const labelText = useMemo(
  52. (): boolean => subType === SecondaryGraphTypes.Label,
  53. [subType]
  54. )
  55. const { style: draggableStyle, ...restDraggableProps } = useContext(
  56. DraggableProxyContext
  57. )
  58. const { className, ...restContextMenuProps } = useContext(
  59. ContextMenuProxyContext
  60. )
  61. const layerStyle = useMemo(() => {
  62. const {
  63. width,
  64. height,
  65. positionX,
  66. positionY,
  67. backgroundImage,
  68. backgroundRepeat,
  69. backgroundSize,
  70. backgroundColor,
  71. borderWidth,
  72. borderStyle,
  73. borderColor,
  74. borderRadius
  75. } = params
  76. const style: React.CSSProperties = {
  77. transform: `translate(${positionX}px, ${positionY}px)`,
  78. width: `${width}px`,
  79. height: `${height}px`,
  80. zIndex: index,
  81. ...draggableStyle
  82. }
  83. if (borderWidth && borderStyle && borderColor) {
  84. style.border = `${borderWidth}px ${borderStyle} rgba(${borderColor.join()}`
  85. }
  86. if (borderRadius) {
  87. style.borderRadius = `${borderRadius}px`
  88. }
  89. if (backgroundImage) {
  90. style.background = `url("${backgroundImage}") 0% 0% / ${backgroundSize} ${backgroundRepeat}`
  91. } else if (backgroundColor) {
  92. style.backgroundColor = `rgba(${backgroundColor.join()})`
  93. }
  94. if(labelText) {
  95. style.height = 'auto'
  96. }
  97. return style
  98. }, [params, index, draggableStyle])
  99. const [lastPosition, setLastPosition] = useState([
  100. params.positionX,
  101. params.positionY
  102. ])
  103. const selectionChange = useCallback(
  104. (e: React.MouseEvent<HTMLDivElement>) => {
  105. e.stopPropagation()
  106. if (
  107. !onSelectionChange ||
  108. (e.target as HTMLDivElement).nodeName.toLowerCase() === 'span'
  109. ) {
  110. return
  111. }
  112. // to solve the onMouseDown/onMouseUp onClick confliction
  113. const isSamePos =
  114. lastPosition[0] === params.positionX &&
  115. lastPosition[1] === params.positionY
  116. setLastPosition([params.positionX, params.positionY])
  117. if (!isSamePos) {
  118. return
  119. }
  120. const { altKey, metaKey } = e
  121. const exclusive = !altKey && !metaKey
  122. onSelectionChange(layerId, !operationInfo.selected, exclusive)
  123. },
  124. [
  125. onSelectionChange,
  126. layerId,
  127. operationInfo,
  128. lastPosition,
  129. params.positionX,
  130. params.positionY
  131. ]
  132. )
  133. const editLabelChange = useCallback(
  134. (e: React.MouseEvent<HTMLDivElement>) => {
  135. e.stopPropagation()
  136. if(labelText && onEditLabelChange){
  137. onEditLabelChange(layerId, { editing: true })
  138. }
  139. },
  140. [onEditLabelChange, layerId]
  141. )
  142. const boxCls = classnames({
  143. 'display-slide-layer': true,
  144. 'display-slide-layer-editing': operationInfo && !operationInfo.editing,
  145. 'display-slide-layer-selected': operationInfo && !operationInfo.editing && operationInfo.selected,
  146. [className]: !!className
  147. })
  148. return (
  149. <div
  150. className={boxCls}
  151. style={layerStyle}
  152. {...restContextMenuProps}
  153. {...restDraggableProps}
  154. onClick={selectionChange}
  155. onDoubleClick={editLabelChange}
  156. >
  157. {props.children}
  158. </div>
  159. )
  160. }
  161. export default memo<ILayerBoxProps>(LayerBox)