Add group list panel #20
@ -11,6 +11,7 @@ div.attr-input {
 | 
			
		||||
	div.input-intro {
 | 
			
		||||
		width: 50%;
 | 
			
		||||
		height: 100%;
 | 
			
		||||
        min-height: $line-min-height;
 | 
			
		||||
		max-width: 220px;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,7 @@ div.color-input-root {
 | 
			
		||||
		width: 50%;
 | 
			
		||||
		height: 100%;
 | 
			
		||||
		max-width: 220px;
 | 
			
		||||
        min-height: $line-min-height;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
        padding-right: 5px;
 | 
			
		||||
 | 
			
		||||
@ -1,3 +0,0 @@
 | 
			
		||||
div.panel-error-message {
 | 
			
		||||
    padding-top: 5px;
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +0,0 @@
 | 
			
		||||
import { AllI18nKeys, Localization } from "@Component/Localization/Localization";
 | 
			
		||||
import { FunctionComponent } from "react";
 | 
			
		||||
import "./ErrorMessage.scss";
 | 
			
		||||
 | 
			
		||||
interface IErrorMessageProps {
 | 
			
		||||
    i18nKey: AllI18nKeys;
 | 
			
		||||
    options?: Record<string, string>;
 | 
			
		||||
    className?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ErrorMessage: FunctionComponent<IErrorMessageProps> = (props) => {
 | 
			
		||||
    return <div className={["panel-error-message", props.className].filter(c => !!c).join(" ")}>
 | 
			
		||||
        <Localization i18nKey={props.i18nKey} options={props.options}/>
 | 
			
		||||
    </div>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export { ErrorMessage };
 | 
			
		||||
@ -2,7 +2,6 @@ import { Component, RefObject } from "react";
 | 
			
		||||
import { Label } from "@Model/Label";
 | 
			
		||||
import { Icon } from "@fluentui/react";
 | 
			
		||||
import { useSetting, IMixinSettingProps, Themes } from "@Context/Setting";
 | 
			
		||||
import { ErrorMessage } from "@Component/ErrorMessage/ErrorMessage";
 | 
			
		||||
import "./LabelList.scss";
 | 
			
		||||
 | 
			
		||||
interface ILabelListProps {
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,7 @@ div.label-picker-root {
 | 
			
		||||
    div.input-intro {
 | 
			
		||||
		width: 50%;
 | 
			
		||||
		height: 100%;
 | 
			
		||||
		min-height: $line-min-height;
 | 
			
		||||
		max-width: 220px;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								source/Component/Message/Message.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								source/Component/Message/Message.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
div.panel-error-message {
 | 
			
		||||
    transition: none !important;
 | 
			
		||||
    padding-top: 5px;
 | 
			
		||||
    padding-bottom: 5px;
 | 
			
		||||
    min-height: 26px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
 | 
			
		||||
    span {
 | 
			
		||||
        display: block;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.panel-error-message.title {
 | 
			
		||||
    padding: 15px 0 5px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.panel-error-message.title.first {
 | 
			
		||||
    padding: 5px 0 5px 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								source/Component/Message/Message.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								source/Component/Message/Message.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
			
		||||
import { AllI18nKeys, I18N } from "@Component/Localization/Localization";
 | 
			
		||||
import { useSetting, IMixinSettingProps, Themes, Language } from "@Context/Setting";
 | 
			
		||||
import { FunctionComponent } from "react";
 | 
			
		||||
import "./Message.scss";
 | 
			
		||||
 | 
			
		||||
interface IMessageProps {
 | 
			
		||||
    i18nKey: AllI18nKeys;
 | 
			
		||||
    options?: Record<string, string>;
 | 
			
		||||
    className?: string;
 | 
			
		||||
    isTitle?: boolean;
 | 
			
		||||
    first?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const MessageView: FunctionComponent<IMessageProps & IMixinSettingProps> = (props) => {
 | 
			
		||||
 | 
			
		||||
    let theme = props.setting ? props.setting.themes : Themes.dark;
 | 
			
		||||
    let language: Language = props.setting ? props.setting.language : "EN_US";
 | 
			
		||||
    let classList: string[] = [
 | 
			
		||||
        "panel-error-message",
 | 
			
		||||
        theme === Themes.dark ? "dark" : "light",
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    if (props.first) {
 | 
			
		||||
        classList.push("first");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (props.isTitle) {
 | 
			
		||||
        classList.push("title");
 | 
			
		||||
        classList.push("font-lvl3");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (props.className) {
 | 
			
		||||
        classList.push(props.className);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return <div className={classList.join(" ")}>
 | 
			
		||||
        <span className={language}>{I18N(language, props.i18nKey, props.options)}</span>
 | 
			
		||||
    </div>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Message = useSetting(MessageView);
 | 
			
		||||
export { Message };
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
div.picker-list-root {
 | 
			
		||||
	max-width: 200px;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	padding: 0px;
 | 
			
		||||
	margin: 0px;
 | 
			
		||||
	overflow-y: auto;
 | 
			
		||||
@ -45,7 +46,7 @@ div.picker-list-root {
 | 
			
		||||
 | 
			
		||||
	span.picker-list-nodata {
 | 
			
		||||
		display: inline-block;
 | 
			
		||||
		padding: 5px;
 | 
			
		||||
		padding: 8px;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -62,7 +63,7 @@ div.picker-list-root::-webkit-scrollbar {
 | 
			
		||||
div.picker-list-root::-webkit-scrollbar-thumb {
 | 
			
		||||
	/*滚动条里面小方块*/
 | 
			
		||||
	border-radius: 8px;
 | 
			
		||||
	background-color: rgba($color: #000000, $alpha: .1);
 | 
			
		||||
	background-color: rgba($color: #000000, $alpha: .2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.picker-list-root::-webkit-scrollbar-track {
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,7 @@ div.toggles-input {
 | 
			
		||||
		width: 50%;
 | 
			
		||||
		height: 100%;
 | 
			
		||||
		max-width: 220px;
 | 
			
		||||
        min-height: $line-min-height;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
        padding-right: 5px;
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,8 @@ const EN_US = {
 | 
			
		||||
    "Panel.Info.Label.List.View": "Edit view label list",
 | 
			
		||||
    "Panel.Title.Label.Details.View": "Label attributes",
 | 
			
		||||
    "Panel.Info.Label.Details.View": "Edit view label attributes",
 | 
			
		||||
    "Common.Attr.Title.Basic": "Basic properties",
 | 
			
		||||
    "Common.Attr.Title.Spatial": "Spatial property",
 | 
			
		||||
    "Common.Attr.Key.Display.Name": "Display name",
 | 
			
		||||
    "Common.Attr.Key.Position.X": "Position X",
 | 
			
		||||
    "Common.Attr.Key.Position.Y": "Position Y",
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,8 @@ const ZH_CN = {
 | 
			
		||||
    "Panel.Info.Label.List.View": "编辑查看标签列表",
 | 
			
		||||
    "Panel.Title.Label.Details.View": "标签属性",
 | 
			
		||||
    "Panel.Info.Label.Details.View": "编辑查看标签属性",
 | 
			
		||||
    "Common.Attr.Title.Basic": "基础属性",
 | 
			
		||||
    "Common.Attr.Title.Spatial": "空间属性",
 | 
			
		||||
    "Common.Attr.Key.Display.Name": "显示名称",
 | 
			
		||||
    "Common.Attr.Key.Position.X": "X 坐标",
 | 
			
		||||
    "Common.Attr.Key.Position.Y": "Y 坐标",
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,7 @@
 | 
			
		||||
import { Component, ReactNode } from "react";
 | 
			
		||||
import { AttrInput } from "@Component/AttrInput/AttrInput";
 | 
			
		||||
import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
 | 
			
		||||
import { AllI18nKeys } from "@Component/Localization/Localization";
 | 
			
		||||
import { ErrorMessage } from "@Component/ErrorMessage/ErrorMessage";
 | 
			
		||||
import { Message } from "@Component/Message/Message";
 | 
			
		||||
import { ColorInput } from "@Component/ColorInput/ColorInput";
 | 
			
		||||
import { Label } from "@Model/Label";
 | 
			
		||||
import { TogglesInput } from "@Component/TogglesInput/TogglesInput";
 | 
			
		||||
@ -14,6 +13,8 @@ class LabelDetails extends Component<IMixinStatusProps> {
 | 
			
		||||
    private renderFrom(label: Label) {
 | 
			
		||||
        return <>
 | 
			
		||||
 | 
			
		||||
            <Message i18nKey="Common.Attr.Title.Basic" isTitle first/>
 | 
			
		||||
            
 | 
			
		||||
            <AttrInput keyI18n="Common.Attr.Key.Display.Name" maxLength={15} value={label.name} valueChange={(value) => {
 | 
			
		||||
                if (this.props.status) {
 | 
			
		||||
                    this.props.status.changeLabelAttrib(label, "name", value);
 | 
			
		||||
@ -42,7 +43,7 @@ class LabelDetails extends Component<IMixinStatusProps> {
 | 
			
		||||
                return this.renderFrom(this.props.status.focusLabel);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
		return <ErrorMessage i18nKey="Panel.Info.Label.Details.Error.Unspecified"/>;
 | 
			
		||||
		return <Message i18nKey="Panel.Info.Label.Details.Error.Unspecified"/>;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,3 @@ div.label-list-panel-root {
 | 
			
		||||
    padding: 10px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.label-list-pabel-err-msg {
 | 
			
		||||
    padding-bottom: 5px;
 | 
			
		||||
}
 | 
			
		||||
@ -3,7 +3,7 @@ import { Component } from "react";
 | 
			
		||||
import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
 | 
			
		||||
import { useSetting, IMixinSettingProps } from "@Context/Setting";
 | 
			
		||||
import { Label } from "@Model/Label";
 | 
			
		||||
import { ErrorMessage } from "@Component/ErrorMessage/ErrorMessage";
 | 
			
		||||
import { Message } from "@Component/Message/Message";
 | 
			
		||||
import "./LabelList.scss";
 | 
			
		||||
 | 
			
		||||
interface ILabelListProps {
 | 
			
		||||
@ -31,10 +31,7 @@ class LabelList extends Component<ILabelListProps & IMixinStatusProps & IMixinSe
 | 
			
		||||
            }}
 | 
			
		||||
        >
 | 
			
		||||
            {labels.length <=0 ? 
 | 
			
		||||
                <ErrorMessage
 | 
			
		||||
                    className="label-list-pabel-err-msg"
 | 
			
		||||
                    i18nKey="Panel.Info.Label.List.Error.Nodata"
 | 
			
		||||
                /> : null
 | 
			
		||||
                <Message i18nKey="Panel.Info.Label.List.Error.Nodata"/> : null
 | 
			
		||||
            }
 | 
			
		||||
            <LabelListComponent
 | 
			
		||||
                labels={labels}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { ReactNode, Component, FunctionComponent } from "react";
 | 
			
		||||
import { Theme } from "@Component/Theme/Theme";
 | 
			
		||||
import { ErrorMessage } from "@Component/ErrorMessage/ErrorMessage";
 | 
			
		||||
import { Message } from "@Component/Message/Message";
 | 
			
		||||
import { RenderView } from "./RenderView/RenderView";
 | 
			
		||||
import { ObjectList } from "./ObjectList/ObjectList";
 | 
			
		||||
import { ObjectCommand } from "./ObjectList/ObjectCommand";
 | 
			
		||||
@ -57,7 +57,7 @@ function getPanelById(panelId: PanelId): ReactNode {
 | 
			
		||||
				const C = info.class;
 | 
			
		||||
				return <C></C>
 | 
			
		||||
			} else return <Theme>
 | 
			
		||||
				<ErrorMessage i18nKey={"Panel.Info.Notfound"} options={{ id: panelId }}/>
 | 
			
		||||
				<Message i18nKey={"Panel.Info.Notfound"} options={{ id: panelId }}/>
 | 
			
		||||
			</Theme>
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ import { Component, ReactNode } from "react";
 | 
			
		||||
import { AttrInput } from "@Component/AttrInput/AttrInput";
 | 
			
		||||
import { useStatusWithEvent, IMixinStatusProps, Status } from "@Context/Status";
 | 
			
		||||
import { AllI18nKeys, Localization } from "@Component/Localization/Localization";
 | 
			
		||||
import { ErrorMessage } from "@Component/ErrorMessage/ErrorMessage";
 | 
			
		||||
import { Message } from "@Component/Message/Message";
 | 
			
		||||
import { Range } from "@Model/Range";
 | 
			
		||||
import { ObjectID } from "@Model/Renderer";
 | 
			
		||||
import { ColorInput } from "@Component/ColorInput/ColorInput";
 | 
			
		||||
@ -15,10 +15,10 @@ class RangeDetails extends Component<IMixinStatusProps> {
 | 
			
		||||
    
 | 
			
		||||
    public readonly AttrI18nKey: AllI18nKeys[] = [
 | 
			
		||||
        "Common.Attr.Key.Display.Name",
 | 
			
		||||
        "Common.Attr.Key.Color",
 | 
			
		||||
        "Common.Attr.Key.Label",
 | 
			
		||||
        "Common.Attr.Key.Display",
 | 
			
		||||
        "Common.Attr.Key.Update",
 | 
			
		||||
        "Common.Attr.Key.Color",
 | 
			
		||||
        "Common.Attr.Key.Position.X",
 | 
			
		||||
        "Common.Attr.Key.Position.Y",
 | 
			
		||||
        "Common.Attr.Key.Position.Z",
 | 
			
		||||
@ -57,10 +57,19 @@ class RangeDetails extends Component<IMixinStatusProps> {
 | 
			
		||||
        let keyIndex = 0;
 | 
			
		||||
 | 
			
		||||
        return <>
 | 
			
		||||
 | 
			
		||||
            <Message i18nKey="Common.Attr.Title.Basic" isTitle first/>
 | 
			
		||||
 | 
			
		||||
            {this.renderAttrInput(range.id, keyIndex ++, range.displayName, (val, status) => {
 | 
			
		||||
                status.changeRangeAttrib(range.id, "displayName", val);
 | 
			
		||||
            })}
 | 
			
		||||
 | 
			
		||||
            <ColorInput keyI18n={this.AttrI18nKey[keyIndex ++]} value={range.color} normal valueChange={(color) => {
 | 
			
		||||
                if (this.props.status) {
 | 
			
		||||
                    this.props.status.changeRangeAttrib(range.id, "color", color);
 | 
			
		||||
                }
 | 
			
		||||
            }}/>
 | 
			
		||||
 | 
			
		||||
            <LabelPicker keyI18n={this.AttrI18nKey[keyIndex ++]}
 | 
			
		||||
                labels={range.allLabels()}
 | 
			
		||||
                labelAdd={(label) => {
 | 
			
		||||
@ -87,11 +96,7 @@ class RangeDetails extends Component<IMixinStatusProps> {
 | 
			
		||||
                }
 | 
			
		||||
            }}/>
 | 
			
		||||
 | 
			
		||||
            <ColorInput keyI18n={this.AttrI18nKey[keyIndex ++]} value={range.color} normal valueChange={(color) => {
 | 
			
		||||
                if (this.props.status) {
 | 
			
		||||
                    this.props.status.changeRangeAttrib(range.id, "color", color);
 | 
			
		||||
                }
 | 
			
		||||
            }}/>
 | 
			
		||||
            <Message i18nKey="Common.Attr.Title.Spatial" isTitle/>
 | 
			
		||||
 | 
			
		||||
            {this.renderAttrInput(range.id, keyIndex ++, range.position[0], (val, status) => {
 | 
			
		||||
                range.position[0] = (val as any) / 1;
 | 
			
		||||
@ -124,10 +129,10 @@ class RangeDetails extends Component<IMixinStatusProps> {
 | 
			
		||||
	public render(): ReactNode {
 | 
			
		||||
        if (this.props.status) {
 | 
			
		||||
            if (this.props.status.focusObject.size <= 0) {
 | 
			
		||||
                return <ErrorMessage i18nKey="Panel.Info.Range.Details.Attr.Error.Unspecified"/>;
 | 
			
		||||
                return <Message i18nKey="Panel.Info.Range.Details.Attr.Error.Unspecified"/>;
 | 
			
		||||
            }
 | 
			
		||||
            if (this.props.status.focusObject.size > 1) {
 | 
			
		||||
                return <ErrorMessage i18nKey="Common.Attr.Key.Error.Multiple"/>;
 | 
			
		||||
                return <Message i18nKey="Common.Attr.Key.Error.Multiple"/>;
 | 
			
		||||
            }
 | 
			
		||||
            let id: ObjectID = "";
 | 
			
		||||
            this.props.status.focusObject.forEach((cid => id = cid));
 | 
			
		||||
@ -137,10 +142,10 @@ class RangeDetails extends Component<IMixinStatusProps> {
 | 
			
		||||
            if (range instanceof Range) {
 | 
			
		||||
                return this.renderFrom(range);
 | 
			
		||||
            } else {
 | 
			
		||||
                return <ErrorMessage i18nKey="Panel.Info.Range.Details.Attr.Error.Not.Range"/>;
 | 
			
		||||
                return <Message i18nKey="Panel.Info.Range.Details.Attr.Error.Not.Range"/>;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
		return <ErrorMessage i18nKey="Panel.Info.Range.Details.Attr.Error.Unspecified"/>;
 | 
			
		||||
		return <Message i18nKey="Panel.Info.Range.Details.Attr.Error.Unspecified"/>;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user