FunctionArea.tsx 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. import React, { useState } from 'react';
  2. import { Button, Flex, Divider } from 'antd';
  3. import { useIntl } from 'react-intl';
  4. import '@/themes/truncateText.css';
  5. import { useDispatch } from 'react-redux';
  6. import { setAction, toggleTool, deactivateAllTools } from '@/states/view/functionAreaSlice';
  7. import { switchToMeasurementPanel, switchToMorePanel, switchToAdvancedProcessingPanel, switchToRectCropPanel, switchToMarkPanel } from '@/states/panelSwitchSliceForView';
  8. import Icon from '@/components/Icon';
  9. import { showNotImplemented } from '@/utils/notificationHelper';
  10. import { useAppSelector } from '@/states/store';
  11. import { useButtonAvailability } from '@/utils/useButtonAvailability';
  12. import { theme } from 'antd';
  13. const { useToken } = theme;
  14. // 有状态按钮列表 - 这些按钮代表持续的状态,不应在执行后清理action
  15. const STATEFUL_BUTTON_ACTIONS = new Set([
  16. 'Adjust Brightness and Contrast',
  17. 'Magnifier',
  18. 'Zoom Image',
  19. 'Pan',
  20. 'Rotate Any Angle'
  21. ]);
  22. const FunctionButton = ({
  23. title,
  24. action,
  25. iconName,
  26. }: {
  27. title: string;
  28. action: string;
  29. iconName: string;
  30. }) => {
  31. const intl = useIntl();
  32. const dispatch = useDispatch();
  33. const themeType = useAppSelector((state) => state.theme.themeType);
  34. const activeTools = useAppSelector((state) => state.functionArea.activeTools);
  35. const { disabled } = useButtonAvailability(action);
  36. // 对于有状态按钮,基于工具激活状态;对于无状态按钮,基于action
  37. const isActive = STATEFUL_BUTTON_ACTIONS.has(action)
  38. ? activeTools[action] || false
  39. : false; // 无状态按钮不显示激活状态
  40. const [isHovered, setIsHovered] = useState(false);
  41. const colorPrimary = useToken().token.colorPrimary;
  42. // 根据状态计算Icon的样式
  43. const getIconStyle = () => {
  44. const baseStyle = {
  45. /*控制svg图标的大小,暂时使用这种fontSize方式 */
  46. fontSize: '48px',
  47. };
  48. if (disabled) {
  49. return { ...baseStyle, opacity: 0.4, filter: 'grayscale(1)' };
  50. }
  51. if (isActive) {
  52. return { ...baseStyle, color: colorPrimary };
  53. }
  54. if (isHovered) {
  55. return { ...baseStyle };
  56. }
  57. return { ...baseStyle }; // 默认颜色
  58. };
  59. const handleButtonClick = () => {
  60. if (disabled) {
  61. return;
  62. }
  63. // 检查是否为未实现的功能
  64. if (action === 'Delete Digital Mask' ||
  65. action === 'Crop Selected Area' ||
  66. ['Image Comparison', , 'Snapshot',
  67. ].includes(action)
  68. ) {
  69. showNotImplemented();
  70. return;
  71. }
  72. // 处理有状态工具按钮(鼠标左键绑定工具)
  73. if (STATEFUL_BUTTON_ACTIONS.has(action)) {
  74. dispatch(toggleTool(action));
  75. return;
  76. }
  77. // 对于其他按钮,先停用所有工具
  78. dispatch(deactivateAllTools());
  79. // 面板切换按钮
  80. if (action === 'Image Measurement') {
  81. dispatch(switchToMeasurementPanel());
  82. } else if (action === 'Rectangle Crop') {
  83. dispatch(switchToRectCropPanel());
  84. } else if (action === 'More') {
  85. dispatch(switchToMorePanel());
  86. } else if (action === 'Advanced Processing') {
  87. dispatch(switchToAdvancedProcessingPanel());
  88. } else if (action === 'AddMark') {
  89. dispatch(switchToMarkPanel());
  90. } else {
  91. // 其他功能按钮保持原有逻辑
  92. dispatch(setAction(action));
  93. }
  94. };
  95. return (
  96. <Button
  97. onClick={handleButtonClick}
  98. onMouseEnter={() => setIsHovered(true)}
  99. onMouseLeave={() => setIsHovered(false)}
  100. disabled={disabled}
  101. icon={
  102. <Icon
  103. module="module-process"
  104. name={iconName}
  105. userId="base"
  106. theme="default"
  107. size="2x"
  108. state="normal"
  109. style={getIconStyle()}
  110. className={`text-[${useToken().token.colorPrimary}] `}
  111. />
  112. }
  113. style={{
  114. width: '1.5rem',
  115. height: '1.5rem',
  116. padding: 0, // 关键
  117. border: isHovered ? `1px solid ${colorPrimary}` : '1px solid transparent',
  118. //backgroundColor: isHovered ? `${colorPrimary}` : 'transparent',
  119. //minWidth: 44, // 保险
  120. //overflow: 'hidden', // 超出的文字裁掉
  121. }}
  122. title={disabled ? `${title}${intl.formatMessage({ id: 'functionArea.disabledTooltipSuffix' })}` : title}
  123. className="truncate-text"
  124. >
  125. {/* {title} */}
  126. </Button>
  127. );
  128. };
  129. const FunctionArea = () => {
  130. const intl = useIntl();
  131. return (
  132. <Flex wrap gap="small" align="center" justify="start" className="p-1">
  133. <FunctionButton title={intl.formatMessage({ id: "functionArea.addLMark" })} action="Add L Mark" iconName="LMark" />
  134. <FunctionButton title={intl.formatMessage({ id: "functionArea.addRMark" })} action="Add R Mark" iconName="RMark" />
  135. <FunctionButton title={intl.formatMessage({ id: "functionArea.addMark" })} action="AddMark" iconName="AddMark" />
  136. <FunctionButton
  137. title={intl.formatMessage({ id: "functionArea.deleteSelectedMark" })}
  138. action="Delete Selected Mark"
  139. iconName="EraseMark"
  140. />
  141. <FunctionButton
  142. title={intl.formatMessage({ id: "functionArea.horizontalFlip" })}
  143. action="Horizontal Flip"
  144. iconName="HReverse"
  145. />
  146. <FunctionButton
  147. title={intl.formatMessage({ id: "functionArea.verticalFlip" })}
  148. action="Vertical Flip"
  149. iconName="VReverse"
  150. />
  151. <FunctionButton
  152. title={intl.formatMessage({ id: "functionArea.rotateCounterclockwise90" })}
  153. action="Rotate Counterclockwise 90"
  154. iconName="RotateL90"
  155. />
  156. <FunctionButton
  157. title={intl.formatMessage({ id: "functionArea.rotateClockwise90" })}
  158. action="Rotate Clockwise 90"
  159. iconName="RotateR90"
  160. />
  161. <FunctionButton
  162. title={intl.formatMessage({ id: "functionArea.rotateAnyAngle" })}
  163. action="Rotate Any Angle"
  164. iconName="RotateAnyDegree"
  165. />
  166. <FunctionButton
  167. title={intl.formatMessage({ id: "functionArea.cropSelectedArea" })}
  168. action="Crop Selected Area"
  169. iconName="Crop"
  170. />
  171. <FunctionButton
  172. title={intl.formatMessage({ id: "functionArea.deleteDigitalMask" })}
  173. action="Delete Digital Mask"
  174. iconName="btn_RemoveCrop"
  175. />
  176. <FunctionButton
  177. title={intl.formatMessage({ id: "functionArea.adjustBrightnessAndContrast" })}
  178. action="Adjust Brightness and Contrast"
  179. iconName="btn_BrightnessContrast"
  180. />
  181. <FunctionButton
  182. title={intl.formatMessage({ id: "functionArea.addMask" })}
  183. action="Add Mask"
  184. iconName="AddMask"
  185. />
  186. <FunctionButton
  187. title={intl.formatMessage({ id: "functionArea.deleteMask" })}
  188. action="Delete Mask"
  189. iconName="DeleteMask"
  190. />
  191. <FunctionButton
  192. title={intl.formatMessage({ id: "functionArea.imageComparison" })}
  193. action="Image Comparison"
  194. iconName="btn_Compare"
  195. />
  196. <FunctionButton
  197. title={intl.formatMessage({ id: "functionArea.invertContrast" })}
  198. action="Invert Contrast"
  199. iconName="btn_ReverseColour"
  200. />
  201. <FunctionButton
  202. title={intl.formatMessage({ id: "functionArea.1x1Layout" })}
  203. action="1x1 Layout"
  204. iconName="1x1_normal"
  205. />
  206. <FunctionButton
  207. title={intl.formatMessage({ id: "functionArea.1x2Layout" })}
  208. action="1x2 Layout"
  209. iconName="1x2_normal"
  210. />
  211. <FunctionButton
  212. title={intl.formatMessage({ id: "functionArea.2x2Layout" })}
  213. action="2x1 Layout"
  214. iconName="2x1_normal"
  215. />
  216. <FunctionButton
  217. title={intl.formatMessage({ id: "functionArea.4x4Layout" })}
  218. action="2x2 Layout"
  219. iconName="2x2_normal"
  220. />
  221. <FunctionButton
  222. title={intl.formatMessage({ id: "functionArea.magnifier" })}
  223. action="Magnifier"
  224. iconName="Magnifier"
  225. />
  226. <FunctionButton
  227. title={intl.formatMessage({ id: "functionArea.fitSize" })}
  228. action="Fit Size"
  229. iconName="FitInWindow"
  230. />
  231. <FunctionButton
  232. title={intl.formatMessage({ id: "functionArea.originalSize" })}
  233. action="Original Size"
  234. iconName="1by1_normal"
  235. />
  236. <FunctionButton title={intl.formatMessage({ id: "functionArea.zoomImage" })} action="Zoom Image" iconName="Zoom" />
  237. <FunctionButton
  238. title={intl.formatMessage({ id: "functionArea.resetCursor" })}
  239. action="Reset Cursor"
  240. iconName="btn_pointer"
  241. />
  242. <FunctionButton title={intl.formatMessage({ id: "functionArea.pan" })} action="Pan" iconName="Pan" />
  243. <FunctionButton
  244. title={intl.formatMessage({ id: "functionArea.invertImage" })}
  245. action="Invert Image"
  246. iconName="Invert"
  247. />
  248. <FunctionButton
  249. title={intl.formatMessage({ id: "functionArea.resetImage" })}
  250. action="Reset Image"
  251. iconName="Reset"
  252. />
  253. <FunctionButton
  254. title={intl.formatMessage({ id: "functionArea.snapshot" })}
  255. action="Snapshot"
  256. iconName="imgsnapshot"
  257. />
  258. <Divider type="horizontal" style={{ height: 'auto', margin: '8px' }} />
  259. <FunctionButton
  260. title={intl.formatMessage({ id: "functionArea.advancedProcessing" })}
  261. action="Advanced Processing"
  262. iconName="btn_Imageprocess"
  263. />
  264. <FunctionButton
  265. title={intl.formatMessage({ id: "functionArea.imageMeasurement" })}
  266. action="Image Measurement"
  267. iconName="btn_Measurements"
  268. />
  269. <FunctionButton
  270. title={intl.formatMessage({ id: "functionArea.rectangleCrop" })}
  271. action="Rectangle Crop"
  272. iconName="rectangle-crop"
  273. />
  274. <FunctionButton title={intl.formatMessage({ id: "functionArea.more" })} action="More" iconName="btn_OtherSetting" />
  275. </Flex>
  276. );
  277. };
  278. export default FunctionArea;