import * as ppt from "tc-shared/PPTListener"; import {KeyDescriptor} from "tc-shared/PPTListener"; import {ReactComponentBase} from "tc-shared/ui/react-elements/ReactComponentBase"; import {EventHandler, ReactEventHandler, Registry} from "tc-shared/events"; import * as React from "react"; import {useRef} from "react"; import {Button} from "tc-shared/ui/react-elements/Button"; import {Translatable} from "tc-shared/ui/react-elements/i18n"; import {KeyTypes, TypeCategories} from "tc-shared/KeyControl"; import {IconRenderer} from "tc-shared/ui/react-elements/Icon"; import {spawnKeySelect} from "tc-shared/ui/modal/ModalKeySelect"; import {createErrorModal} from "tc-shared/ui/elements/Modal"; import {tra} from "tc-shared/i18n/localize"; import * as keycontrol from "./../../../KeyControl"; import {MenuEntryType, spawn_context_menu} from "tc-shared/ui/elements/ContextMenu"; const cssStyle = require("./Keymap.scss"); export interface KeyMapEvents { query_keymap: { action: string, query_type: "query-selected" | "general" }, query_keymap_result: { action: string, status: "success" | "error" | "timeout", error?: string, key?: KeyDescriptor }, set_keymap: { action: string, key?: KeyDescriptor }, set_keymap_result: { action: string, status: "success" | "error" | "timeout", error?: string, key?: KeyDescriptor }, set_selected_action: { action: string } } interface KeyActionEntryState { assignedKey: KeyDescriptor | undefined; selected: boolean; state: "loading" | "applying" | "loaded" | "error"; error?: string; } interface KeyActionEntryProperties { action: string; icon: string; description: string; eventRegistry: Registry; hidden: boolean; } @ReactEventHandler(e => e.props.eventRegistry) class KeyActionEntry extends ReactComponentBase { protected defaultState(): KeyActionEntryState { return { assignedKey: undefined, selected: false, state: "loading" }; } componentDidMount(): void { this.props.eventRegistry.fire("query_keymap", {action: this.props.action, query_type: "general"}); } render() { let rightItem; if (this.state.state === "loading") { rightItem =
loading...
; } else if (this.state.state === "applying") { rightItem =
applying...
; } else if (this.state.state === "loaded") { rightItem = null; if (this.state.assignedKey) rightItem =
{ppt.key_description(this.state.assignedKey)}
; } else { rightItem =
{this.state.error || "unknown error"}
; } return (
this.onClick()} onDoubleClick={() => this.onDoubleClick()} hidden={this.props.hidden} onContextMenu={e => this.onContextMenu(e)} > {this.props.description} {rightItem}
); } private onClick() { this.props.eventRegistry.fire("set_selected_action", {action: this.props.action}); } private onDoubleClick() { spawnKeySelect(key => { if (!key) return; this.props.eventRegistry.fire("set_keymap", {action: this.props.action, key: key}); }); } private onContextMenu(event) { event.preventDefault(); spawn_context_menu(event.pageX, event.pageY, { type: MenuEntryType.ENTRY, name: tr("Set key"), icon_class: "client-hotkeys", callback: () => this.onDoubleClick() }, { type: MenuEntryType.ENTRY, name: tr("Remove key"), icon_class: "client-delete", callback: () => this.props.eventRegistry.fire("set_keymap", {action: this.props.action, key: undefined}), visible: !!this.state.assignedKey }); } @EventHandler("set_selected_action") private handleSelectedChange(event: KeyMapEvents["set_selected_action"]) { this.setState({ selected: this.props.action === event.action }); } @EventHandler("query_keymap") private handleQueryKeymap(event: KeyMapEvents["query_keymap"]) { if (event.action !== this.props.action) return; if (event.query_type !== "general") return; this.setState({ state: "loading" }); } @EventHandler("query_keymap_result") private handleQueryKeymapResult(event: KeyMapEvents["query_keymap_result"]) { if (event.action !== this.props.action) return; if (event.status === "success") { this.setState({ state: "loaded", assignedKey: event.key }); } else { this.setState({ state: "error", error: event.status === "timeout" ? tr("query timeout") : event.error }); } } @EventHandler("set_keymap") private handleSetKeymap(event: KeyMapEvents["set_keymap"]) { if (event.action !== this.props.action) return; this.setState({state: "applying"}); } @EventHandler("set_keymap_result") private handleSetKeymapResult(event: KeyMapEvents["set_keymap_result"]) { if (event.action !== this.props.action) return; if (event.status === "success") { this.setState({ state: "loaded", assignedKey: event.key }); } else { this.setState({state: "loaded"}); createErrorModal(tr("Failed to change key"), tra("Failed to change key for action \"{}\":{:br:}{}", this.props.action, event.status === "timeout" ? tr("timeout") : event.error)); } } } interface KeyActionGroupProperties { id: string; name: string; eventRegistry: Registry; } class KeyActionGroup extends ReactComponentBase { protected defaultState(): { collapsed: boolean } { return {collapsed: false} } render() { const result = []; result.push(
this.toggleCollapsed()}> ); result.push(...Object.keys(KeyTypes).filter(e => KeyTypes[e].category === this.props.id).map(e => (