LayerBox.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. import { ASSETS_HOST } from 'app/globalConstants'
  36. interface ILayerBoxProps {
  37. children?: ReactNode
  38. }
  39. const LayerBox: React.FC = (props: ILayerBoxProps) => {
  40. const { onSelectionChange, onEditLabelChange } = useContext(LayerListContext)
  41. const { layer, operationInfo } = useContext(LayerContext)
  42. const { id: layerId, index, subType } = layer
  43. const operateItemParams = useSelector(makeSelectCurrentOperateItemParams())
  44. const dragging = operationInfo?.dragging
  45. const params = useMemo(
  46. () =>
  47. dragging
  48. ? operateItemParams.find((_) => _.id === layerId)?.params
  49. : layer.params,
  50. [dragging, operateItemParams, layer.params]
  51. )
  52. const labelText = useMemo(
  53. (): boolean => subType === SecondaryGraphTypes.Label,
  54. [subType]
  55. )
  56. const { style: draggableStyle, ...restDraggableProps } = useContext(
  57. DraggableProxyContext
  58. )
  59. const { className, ...restContextMenuProps } = useContext(
  60. ContextMenuProxyContext
  61. )
  62. const layerStyle = useMemo(() => {
  63. const {
  64. width,
  65. height,
  66. positionX,
  67. positionY,
  68. backgroundImage,
  69. backgroundRepeat,
  70. backgroundSize,
  71. backgroundColor,
  72. borderWidth,
  73. borderStyle,
  74. borderColor,
  75. borderRadius
  76. } = params
  77. const style: React.CSSProperties = {
  78. transform: `translate(${positionX}px, ${positionY}px)`,
  79. width: `${width}px`,
  80. height: `${height}px`,
  81. zIndex: index,
  82. ...draggableStyle
  83. }
  84. if (borderWidth && borderStyle && borderColor) {
  85. style.border = `${borderWidth}px ${borderStyle} rgba(${borderColor.join()}`
  86. }
  87. if (borderRadius) {
  88. style.borderRadius = `${borderRadius}px`
  89. }
  90. if (backgroundImage) {
  91. style.background = `url("${ASSETS_HOST}${backgroundImage}") 0% 0% / ${backgroundSize} ${backgroundRepeat}`
  92. } else if (backgroundColor) {
  93. style.backgroundColor = `rgba(${backgroundColor.join()})`
  94. }
  95. if (labelText) {
  96. style.height = 'auto'
  97. }
  98. return style
  99. }, [params, index, draggableStyle])
  100. const [lastPosition, setLastPosition] = useState([
  101. params.positionX,
  102. params.positionY
  103. ])
  104. const selectionChange = useCallback(
  105. (e: React.MouseEvent<HTMLDivElement>) => {
  106. e.stopPropagation()
  107. if (
  108. !onSelectionChange ||
  109. (e.target as HTMLDivElement).nodeName.toLowerCase() === 'span'
  110. ) {
  111. return
  112. }
  113. // to solve the onMouseDown/onMouseUp onClick confliction
  114. const isSamePos =
  115. lastPosition[0] === params.positionX &&
  116. lastPosition[1] === params.positionY
  117. setLastPosition([params.positionX, params.positionY])
  118. if (!isSamePos) {
  119. return
  120. }
  121. const { altKey, metaKey } = e
  122. const exclusive = !altKey && !metaKey
  123. onSelectionChange(layerId, !operationInfo.selected, exclusive)
  124. },
  125. [
  126. onSelectionChange,
  127. layerId,
  128. operationInfo,
  129. lastPosition,
  130. params.positionX,
  131. params.positionY
  132. ]
  133. )
  134. const editLabelChange = useCallback(
  135. (e: React.MouseEvent<HTMLDivElement>) => {
  136. e.stopPropagation()
  137. if(labelText && onEditLabelChange){
  138. onEditLabelChange(layerId, { editing: true })
  139. }
  140. },
  141. [onEditLabelChange, layerId]
  142. )
  143. const boxCls = classnames({
  144. 'display-slide-layer': true,
  145. 'display-slide-layer-editing': operationInfo && !operationInfo.editing,
  146. 'display-slide-layer-selected': operationInfo && !operationInfo.editing && operationInfo.selected,
  147. [className]: !!className
  148. })
  149. return (
  150. <div
  151. className={boxCls}
  152. style={layerStyle}
  153. {...restContextMenuProps}
  154. {...restDraggableProps}
  155. onClick={selectionChange}
  156. onDoubleClick={editLabelChange}
  157. >
  158. {props.children}
  159. </div>
  160. )
  161. }
  162. export default memo<ILayerBoxProps>(LayerBox)