diff --git a/source/Component/BehaviorList/BehaviorList.scss b/source/Component/BehaviorList/BehaviorList.scss index 364421b..0de9edc 100644 --- a/source/Component/BehaviorList/BehaviorList.scss +++ b/source/Component/BehaviorList/BehaviorList.scss @@ -20,20 +20,65 @@ div.behavior-list { width: 100%; div { - // position: relative; - // top: 5px; - // left: 5px; width: 0; height: 0; - // border-left: 8px solid red; border-bottom: 12px solid transparent; - // border-radius: 8px; + position: relative; + z-index: 2; } } div.behavior-item-root { display: flex; + div.behavior-popup-menu { + width: 0; + max-width: 0; + height: $behavior-item-height; + min-height: $behavior-item-height; + position: relative; + z-index: 1; + + div.behavior-popup-layout { + width: 0; + opacity: 0; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + + div.behavior-popup-action-view { + height: 15px; + min-height: 26px; + max-height: 26px; + width: 100%; + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + + div.behavior-action-button { + height: 100%; + flex-shrink: 0; + display: flex; + flex-direction: column; + justify-content: center; + align-content: center; + align-items: center; + padding: 0 2px; + } + + div.behavior-action-button.hover-red:hover i { + color: $lt-red; + } + + div.behavior-action-button.hover-blue:hover i { + color: $lt-green; + } + } + } + } + div.behavior-icon-view { height: $behavior-item-height; min-width: $behavior-item-height; @@ -73,38 +118,16 @@ div.behavior-list { opacity: .75; } } - - div.behavior-action-view { - height: $behavior-item-height; - min-width: 20px; - width: 20px; - flex-shrink: 0; - display: flex; - flex-direction: column; - justify-content: center; - align-content: center; - align-items: center; - - div.behavior-action-button { - height: 100%; - width: 100%; - display: flex; - justify-content: center; - align-items: center; - user-select: none; - cursor: pointer; - } - - div.behavior-action-button.hover-red:hover i { - color: $lt-red; - } - - div.behavior-action-button.hover-blue:hover i { - color: $lt-blue; - } - } } } + + div.behavior-item:hover { + + div.behavior-popup-menu div.behavior-popup-layout { + width: $behavior-item-height !important; + opacity: 1 !important; + } + } div.add-button { width: 26px; @@ -124,11 +147,19 @@ div.dark.behavior-list { div.behavior-item:hover { color: $lt-font-color-lvl2-dark; background-color: $lt-bg-color-lvl2-dark; + + div.behavior-popup-menu div.behavior-popup-layout { + background-color: $lt-bg-color-lvl2-dark; + } } div.behavior-item.focus { color: $lt-font-color-lvl1-dark; background-color: $lt-bg-color-lvl1-dark; + + div.behavior-popup-menu div.behavior-popup-layout { + background-color: $lt-bg-color-lvl1-dark; + } } } @@ -141,10 +172,18 @@ div.light.behavior-list { div.behavior-item:hover { color: $lt-font-color-lvl2-light; background-color: $lt-bg-color-lvl2-light; + + div.behavior-popup-menu div.behavior-popup-layout { + background-color: $lt-bg-color-lvl2-light; + } } div.behavior-item.focus { color: $lt-font-color-lvl1-light; background-color: $lt-bg-color-lvl1-light; + + div.behavior-popup-menu div.behavior-popup-layout { + background-color: $lt-bg-color-lvl1-light; + } } } \ No newline at end of file diff --git a/source/Component/BehaviorList/BehaviorList.tsx b/source/Component/BehaviorList/BehaviorList.tsx index 46fdcdd..1e11a30 100644 --- a/source/Component/BehaviorList/BehaviorList.tsx +++ b/source/Component/BehaviorList/BehaviorList.tsx @@ -2,20 +2,23 @@ import { Theme } from "@Component/Theme/Theme"; import { Component, ReactNode } from "react"; import { IRenderBehavior, Behavior, BehaviorRecorder } from "@Model/Behavior"; import { useSettingWithEvent, IMixinSettingProps } from "@Context/Setting"; +import { useStatus, IMixinStatusProps } from "@Context/Status"; import { Icon } from "@fluentui/react"; +import { ConfirmPopup } from "@Component/ConfirmPopup/ConfirmPopup"; +import { Message } from "@Component/Message/Message"; import "./BehaviorList.scss"; interface IBehaviorListProps { behaviors: IRenderBehavior[]; focusBehaviors?: IRenderBehavior[]; click?: (behavior: IRenderBehavior) => void; - action?: (behavior: IRenderBehavior) => void; + delete?: (behavior: IRenderBehavior) => void; onAdd?: () => void; - actionType?: "info" | "delete"; } +@useStatus @useSettingWithEvent("language") -class BehaviorList extends Component { +class BehaviorList extends Component { private isFocus(behavior: IRenderBehavior): boolean { if (this.props.focusBehaviors) { @@ -28,32 +31,55 @@ class BehaviorList extends Component { return false; } - private renderActionButton(behavior: IRenderBehavior) { + private renderActionButton(behavior: IRenderBehavior, actionType: "info" | "delete") { const classList: string[] = ["info-button", "behavior-action-button"]; let iconName = "Info"; + let action: () => void = () => {}; - switch (this.props.actionType) { + switch (actionType) { case "delete": classList.push("hover-red"); iconName = "Delete"; + action = () => { + this.isActionClick = true; + if (this.props.delete) { + this.props.delete(behavior) + } + } break; + case "info": classList.push("hover-blue"); iconName = "Info"; + action = () => { + this.isActionClick = true; + if (!this.props.status) { + return; + } + const status = this.props.status; + status.popup.showPopup(ConfirmPopup, { + renderInfo: () => { + return + }, + titleI18N: "Popup.Behavior.Info.Title", + yesI18n: "Popup.Behavior.Info.Confirm", + titleI18NOption: { + behavior: behavior.getTerms(behavior.behaviorName, this.props.setting?.language) + } + }) + } break; + default: classList.push("hover-blue"); } return
{ - this.isActionClick = true; - if (this.props.action) { - this.props.action(behavior) - } - }} + onClick={action} >
@@ -116,6 +142,14 @@ class BehaviorList extends Component {
+
+
+
+ {this.props.delete ? this.renderActionButton(behavior, "delete") : null} + {this.renderActionButton(behavior, "info")} +
+
+
@@ -123,9 +157,6 @@ class BehaviorList extends Component { {this.renderTerm(behavior, name, "title-view", needLocal)} {this.renderTerm(behavior, info, "info-view", true)}
- {/*
- {this.renderActionButton(behavior)} -
*/} } diff --git a/source/Component/BehaviorPicker/BehaviorPicker.scss b/source/Component/BehaviorPicker/BehaviorPicker.scss new file mode 100644 index 0000000..7e0889a --- /dev/null +++ b/source/Component/BehaviorPicker/BehaviorPicker.scss @@ -0,0 +1,86 @@ +@import "../Theme/Theme.scss"; + +div.behavior-picker-list { + width: 100%; + max-width: 400px; + padding: 8px 0; + + div.behavior-picker-line { + width: 100%; + padding: 0 !important; + display: flex !important; + justify-content: flex-start !important; + + div.behavior-picker-line-color-view { + width: 0; + max-width: 0; + height: 100%; + + div { + width: 0; + height: 0; + border-bottom: 10px solid transparent; + position: relative; + z-index: 2; + } + } + + div.behavior-picker-line-icon-view { + width: 30px; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + + i.behavior-icon { + display: inline-block; + } + + i.view-icon { + display: none; + } + + i.view-icon:hover { + color: $lt-green; + } + } + + div.behavior-picker-title { + height: 100%; + width: calc(100% - 60px); + display: flex; + align-items: center; + + div { + text-overflow: ellipsis; + overflow: hidden; + } + } + + div.behavior-picker-line-delete-view { + width: 30px; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + + i:hover { + color: $lt-red; + } + } + } + + div.behavior-picker-line:hover { + + div.behavior-picker-line-icon-view { + + i.behavior-icon { + display: none; + } + + i.view-icon { + display: inline-block; + } + } + } +} \ No newline at end of file diff --git a/source/Component/BehaviorPicker/BehaviorPicker.tsx b/source/Component/BehaviorPicker/BehaviorPicker.tsx new file mode 100644 index 0000000..92813d5 --- /dev/null +++ b/source/Component/BehaviorPicker/BehaviorPicker.tsx @@ -0,0 +1,77 @@ +import { DetailsList } from "@Component/DetailsList/DetailsList"; +import { Component, ReactNode } from "react"; +import { Behavior } from "@Model/Behavior"; +import { Icon } from "@fluentui/react"; +import { useSettingWithEvent, IMixinSettingProps } from "@Context/Setting"; +import { Localization } from "@Component/Localization/Localization"; +import "./BehaviorPicker.scss"; + +interface IBehaviorPickerProps { + behavior: Behavior[]; + delete?: (behavior: Behavior) => void; + action?: (behavior: Behavior) => void; + add?: () => void; +} + +@useSettingWithEvent("language") +class BehaviorPicker extends Component { + + private getData() { + let data: Array<{key: string, behavior: Behavior | undefined}> = []; + for (let i = 0; i < this.props.behavior.length; i++) { + data.push({ + key: this.props.behavior[i].id, + behavior: this.props.behavior[i] + }) + } + data.push({ + key: "@@AddButton_List_Key", + behavior: undefined + }) + return data; + } + + private renderLine = (behavior?: Behavior): ReactNode => { + if (behavior) { + return <> +
+
+
+
+ + +
+
+
{behavior.name}
+
+
+ +
+ ; + } else { + return <> +
+ +
+
+ +
+ ; + } + } + + public render(): ReactNode { + return + } +} + +export { BehaviorPicker }; \ No newline at end of file diff --git a/source/Component/BehaviorPopup/BehaviorPopup.tsx b/source/Component/BehaviorPopup/BehaviorPopup.tsx index eb5691c..263a920 100644 --- a/source/Component/BehaviorPopup/BehaviorPopup.tsx +++ b/source/Component/BehaviorPopup/BehaviorPopup.tsx @@ -64,24 +64,6 @@ class BehaviorPopupComponent extends Component<
; } - private showBehaviorInfo = (behavior: IRenderBehavior) => { - if (this.props.status) { - const status = this.props.status; - status.popup.showPopup(ConfirmPopup, { - renderInfo: () => { - return - }, - titleI18N: "Popup.Behavior.Info.Title", - titleI18NOption: { - behavior: behavior.getTerms(behavior.behaviorName, this.props.setting?.language) - }, - yesI18n: "Popup.Behavior.Info.Confirm", - }) - } - } - private renderActionBar = () => { return { let language = this.props.setting?.language ?? "EN_US"; + let filterReg: RegExp | undefined = undefined; + if (this.state.searchValue) { + filterReg = new RegExp(this.state.searchValue, "i"); + } let filterItem = behaviors.item.filter((item) => { let name = item.getTerms(item.behaviorName, this.props.setting?.language); - if (this.state.searchValue) { - return name.includes(this.state.searchValue); + if (filterReg) { + return filterReg.test(name); } else { return true; } @@ -114,7 +100,6 @@ class BehaviorPopupComponent extends Component< { if (this.state.focusBehavior.has(behavior)) { this.state.focusBehavior.delete(behavior); diff --git a/source/Component/HeaderBar/HeaderBar.tsx b/source/Component/HeaderBar/HeaderBar.tsx index 0eb6d2e..fa605cf 100644 --- a/source/Component/HeaderBar/HeaderBar.tsx +++ b/source/Component/HeaderBar/HeaderBar.tsx @@ -40,6 +40,9 @@ class HeaderBar extends Component< private createFpsCalc(type: "renderFps" | "physicsFps") { return (t: number) => { + if (t === 0) { + return; + } let newState: HeaderBarState = {} as any; newState[type] = 1 / t; if (this.updateTime > 20) { diff --git a/source/Component/Localization/Localization.scss b/source/Component/Localization/Localization.scss index f16e746..aad22d9 100644 --- a/source/Component/Localization/Localization.scss +++ b/source/Component/Localization/Localization.scss @@ -1,7 +1,7 @@ -span.ZH_CN { +span.ZH_CN, div.span.ZH_CN { font-family: 'Microsoft Yahei', Verdana, Simsun, 'Segoe UI', Tahoma, Arial, sans-serif; } -span.EN_US { +span.EN_US, div.span.EN_US { font-family: 'Segoe UI Web Regular', 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif; } \ No newline at end of file diff --git a/source/Component/Theme/Theme.scss b/source/Component/Theme/Theme.scss index 8069a6d..967ae65 100644 --- a/source/Component/Theme/Theme.scss +++ b/source/Component/Theme/Theme.scss @@ -1,5 +1,6 @@ @import "@fluentui/react/dist/sass/References"; +$lt-green: rgb(50, 237, 69); $lt-blue: rgb(81, 79, 235); $lt-red: rgb(240, 94, 94); diff --git a/source/Localization/EN-US.ts b/source/Localization/EN-US.ts index ced4fa1..ba2cfe8 100644 --- a/source/Localization/EN-US.ts +++ b/source/Localization/EN-US.ts @@ -30,6 +30,7 @@ const EN_US = { "Object.List.New.Label": "Label {id}", "Object.List.No.Data": "There are no objects in the model, click the button to create it", "Object.Picker.List.No.Data": "There is no model in the model for this option", + "Behavior.Picker.Add.Button": "Click here to assign behavior to this group", "Panel.Title.Notfound": "{id}", "Panel.Info.Notfound": "This panel with id {id} can not found!", "Panel.Title.Render.View": "Live preview", @@ -69,6 +70,7 @@ const EN_US = { "Common.Attr.Title.Basic": "Basic properties", "Common.Attr.Title.Spatial": "Spatial property", "Common.Attr.Title.Individual.Generation": "Individual generation", + "Common.Attr.Title.Behaviors": "Behaviors list", "Common.Attr.Title.Individual.kill": "Individual kill", "Common.Attr.Key.Display.Name": "Display name", "Common.Attr.Key.Position.X": "Position X", diff --git a/source/Localization/ZH-CN.ts b/source/Localization/ZH-CN.ts index 3e71c1a..8cbe5bb 100644 --- a/source/Localization/ZH-CN.ts +++ b/source/Localization/ZH-CN.ts @@ -30,6 +30,7 @@ const ZH_CN = { "Object.List.New.Label": "标签 {id}", "Object.List.No.Data": "模型中没有任何对象,点击按钮以创建", "Object.Picker.List.No.Data": "模型中没有合适此选项的模型", + "Behavior.Picker.Add.Button": "点击此处以赋予行为到此群", "Panel.Title.Notfound": "{id}", "Panel.Info.Notfound": "这个编号为 {id} 的面板无法找到!", "Panel.Title.Render.View": "实时预览", @@ -69,6 +70,7 @@ const ZH_CN = { "Common.Attr.Title.Basic": "基础属性", "Common.Attr.Title.Spatial": "空间属性", "Common.Attr.Title.Individual.Generation": "生成个体", + "Common.Attr.Title.Behaviors": "行为列表", "Common.Attr.Title.Individual.kill": "消除个体", "Common.Attr.Key.Display.Name": "显示名称", "Common.Attr.Key.Position.X": "X 坐标", diff --git a/source/Page/SimulatorWeb/SimulatorWeb.tsx b/source/Page/SimulatorWeb/SimulatorWeb.tsx index 7ad6144..462c9bd 100644 --- a/source/Page/SimulatorWeb/SimulatorWeb.tsx +++ b/source/Page/SimulatorWeb/SimulatorWeb.tsx @@ -91,6 +91,7 @@ class SimulatorWeb extends Component { }, { panels: ["GroupDetails", "RangeDetails", "LabelDetails"] }], + scale: 30, layout: LayoutDirection.Y } ], diff --git a/source/Panel/BehaviorList/BehaviorList.tsx b/source/Panel/BehaviorList/BehaviorList.tsx index 780ffd8..cb3989b 100644 --- a/source/Panel/BehaviorList/BehaviorList.tsx +++ b/source/Panel/BehaviorList/BehaviorList.tsx @@ -36,7 +36,6 @@ class BehaviorList extends Component : null } { this.props.status?.popup.showPopup(BehaviorPopup, {}); }} - action={(behavior) => { + delete={(behavior) => { if (this.props.status && behavior instanceof Behavior) { const status = this.props.status; status.popup.showPopup(ConfirmPopup, { diff --git a/source/Panel/GroupDetails/GroupDetails.tsx b/source/Panel/GroupDetails/GroupDetails.tsx index 2010964..baa824b 100644 --- a/source/Panel/GroupDetails/GroupDetails.tsx +++ b/source/Panel/GroupDetails/GroupDetails.tsx @@ -11,6 +11,7 @@ import { AllI18nKeys } from "@Component/Localization/Localization"; import { ComboInput, IDisplayItem } from "@Component/ComboInput/ComboInput"; import { ObjectPicker } from "@Component/ObjectPicker/ObjectPicker"; import { ConfirmPopup } from "@Component/ConfirmPopup/ConfirmPopup"; +import { BehaviorPicker } from "@Component/BehaviorPicker/BehaviorPicker"; import "./GroupDetails.scss"; interface IGroupDetailsProps {} @@ -107,6 +108,12 @@ class GroupDetails extends Component { } }} /> + + + + diff --git a/source/Panel/ObjectList/ObjectList.scss b/source/Panel/ObjectList/ObjectList.scss index e0e197a..6b4a749 100644 --- a/source/Panel/ObjectList/ObjectList.scss +++ b/source/Panel/ObjectList/ObjectList.scss @@ -20,6 +20,10 @@ div.object-list { opacity: 0; } + i.checkbox-icon:hover { + color: $lt-green; + } + i.type-icon { display: inline-block; opacity: 1;