mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-29 08:08:49 +01:00
[MIRROR] Adds an admin signal handler circuit component (#8218)
* Adds an admin signal handler circuit component * Update FundamentalTypes.js Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Co-authored-by: Gandalf <jzo123@hotmail.com>
This commit is contained in:
co-authored by
Watermelon914
Gandalf
parent
9269849f62
commit
c302124fd5
@@ -1,3 +1,4 @@
|
||||
/// The basic types that don't have any super special behaviour.
|
||||
GLOBAL_LIST_INIT(wiremod_basic_types, list(
|
||||
PORT_TYPE_ANY,
|
||||
PORT_TYPE_STRING,
|
||||
@@ -7,3 +8,12 @@ GLOBAL_LIST_INIT(wiremod_basic_types, list(
|
||||
PORT_TYPE_TABLE,
|
||||
PORT_TYPE_ATOM,
|
||||
))
|
||||
|
||||
/// The fundamental datatypes of the byond game engine.
|
||||
GLOBAL_LIST_INIT(wiremod_fundamental_types, list(
|
||||
PORT_TYPE_ANY,
|
||||
PORT_TYPE_NUMBER,
|
||||
PORT_TYPE_ATOM,
|
||||
PORT_TYPE_STRING,
|
||||
PORT_TYPE_LIST,
|
||||
))
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
output_value = add_output_port("Output Value", PORT_TYPE_ANY)
|
||||
|
||||
/obj/item/circuit_component/proccall/input_received(datum/port/input/port)
|
||||
|
||||
var/called_on
|
||||
if(proccall_options.value == COMP_PROC_OBJECT)
|
||||
called_on = entity.value
|
||||
@@ -58,6 +57,9 @@
|
||||
if(!to_invoke)
|
||||
return
|
||||
|
||||
INVOKE_ASYNC(src, .proc/do_proccall, called_on, to_invoke, params)
|
||||
|
||||
/obj/item/circuit_component/proccall/proc/do_proccall(called_on, to_invoke, params)
|
||||
GLOB.AdminProcCaller = "CHAT_[parent.display_name]" //_ won't show up in ckeys so it'll never match with a real admin
|
||||
var/result = WrapAdminProcCall(called_on, to_invoke, params)
|
||||
GLOB.AdminProcCaller = null
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
#define COMP_SIGNAL_HANDLER_GLOBAL "Global"
|
||||
#define COMP_SIGNAL_HANDLER_OBJECT "Object"
|
||||
|
||||
/**
|
||||
* # Signal Handler Component
|
||||
*
|
||||
* A component that registers signals on events and listens for them.
|
||||
*/
|
||||
/obj/item/circuit_component/signal_handler
|
||||
display_name = "Signal Handler"
|
||||
desc = "A component that listens for signals on an object. Registering a new object will automatically unregister the old."
|
||||
circuit_flags = CIRCUIT_FLAG_ADMIN|CIRCUIT_FLAG_INSTANT
|
||||
|
||||
/// Whether it is a global or object signal
|
||||
var/datum/port/input/option/signal_handler_options
|
||||
|
||||
/// The list of signal IDs that can be selected as an option.
|
||||
var/datum/port/input/option/signal_id
|
||||
|
||||
var/list/signal_map
|
||||
|
||||
/// Entity to register the signal on
|
||||
var/datum/port/input/target
|
||||
/// Registers the signal
|
||||
var/datum/port/input/register
|
||||
/// Unregisters the signal from the current registered entity.
|
||||
var/datum/port/input/unregister
|
||||
|
||||
/// The custom signal ports from the current signal type. Used for saving and loading.
|
||||
var/list/signal_ports
|
||||
/// The custom input from the current signal type.
|
||||
var/list/datum/port/input/input_signal_ports = list()
|
||||
/// The custom output from the current signal type.
|
||||
var/list/datum/port/output/output_signal_ports = list()
|
||||
|
||||
/// The entity received from the event.
|
||||
var/datum/port/output/entity
|
||||
/// The event has been triggered
|
||||
var/datum/port/output/event_triggered
|
||||
|
||||
/// The current entity that has the signal registered on it
|
||||
var/datum/weakref/current_registered_entity
|
||||
/// The current registered signal
|
||||
var/registered_signal
|
||||
|
||||
/// Whether it is a custom signal id or not.
|
||||
var/custom_signal = FALSE
|
||||
|
||||
/obj/item/circuit_component/signal_handler/populate_options()
|
||||
var/static/list/component_options = list(
|
||||
COMP_SIGNAL_HANDLER_OBJECT,
|
||||
COMP_SIGNAL_HANDLER_GLOBAL,
|
||||
)
|
||||
signal_handler_options = add_option_port("Signal Handler Options", component_options, trigger = null)
|
||||
|
||||
signal_id = add_option_port("Signal ID", GLOB.integrated_circuit_signal_ids, trigger = null)
|
||||
signal_map = GLOB.integrated_circuit_signal_ids
|
||||
|
||||
/obj/item/circuit_component/signal_handler/populate_ports()
|
||||
register = add_input_port("Register", PORT_TYPE_SIGNAL, order = 2, trigger = .proc/register_signals)
|
||||
unregister = add_input_port("Unregister Current", PORT_TYPE_SIGNAL, order = 2, trigger = .proc/unregister_signals)
|
||||
|
||||
add_source_entity()
|
||||
event_triggered = add_output_port("Triggered", PORT_TYPE_SIGNAL, order = 2)
|
||||
|
||||
/obj/item/circuit_component/signal_handler/proc/add_source_entity()
|
||||
if(target)
|
||||
remove_input_port(target)
|
||||
if(entity)
|
||||
remove_output_port(entity)
|
||||
|
||||
target = add_input_port("Target", PORT_TYPE_ATOM, order = 1, trigger = null)
|
||||
entity = add_output_port("Source Entity", PORT_TYPE_ATOM, order = 0)
|
||||
|
||||
/obj/item/circuit_component/signal_handler/save_data_to_list(list/component_data)
|
||||
. = ..()
|
||||
component_data["signal_id"] = signal_id.value
|
||||
component_data["signal_port_data"] = signal_ports
|
||||
|
||||
/obj/item/circuit_component/signal_handler/load_data_from_list(list/component_data)
|
||||
signal_id.set_value(component_data["signal_id"], force = TRUE)
|
||||
registered_signal = signal_id.value
|
||||
load_new_ports(component_data["signal_port_data"])
|
||||
custom_signal = TRUE
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/circuit_component/signal_handler/pre_input_received(datum/port/input/port)
|
||||
if(signal_id == port)
|
||||
custom_signal = FALSE
|
||||
if(current_registered_entity)
|
||||
unregister_signals(port)
|
||||
|
||||
var/last_registered_signal = registered_signal
|
||||
registered_signal = signal_id.value
|
||||
|
||||
if(registered_signal != last_registered_signal)
|
||||
var/list/data = signal_map[registered_signal]
|
||||
if(data)
|
||||
load_new_ports(data)
|
||||
unregister_signals(port)
|
||||
|
||||
if(signal_handler_options == port)
|
||||
set_signal_options(port)
|
||||
|
||||
/obj/item/circuit_component/signal_handler/proc/set_signal_options(datum/port/input/port)
|
||||
CIRCUIT_TRIGGER
|
||||
|
||||
switch(signal_handler_options.value)
|
||||
if(COMP_SIGNAL_HANDLER_GLOBAL)
|
||||
signal_id.possible_options = GLOB.integrated_circuit_global_signal_ids
|
||||
signal_map = GLOB.integrated_circuit_global_signal_ids
|
||||
remove_output_port(entity)
|
||||
remove_input_port(target)
|
||||
if(COMP_SIGNAL_HANDLER_OBJECT)
|
||||
signal_id.possible_options = GLOB.integrated_circuit_signal_ids
|
||||
signal_map = GLOB.integrated_circuit_signal_ids
|
||||
add_source_entity()
|
||||
|
||||
if(!custom_signal)
|
||||
signal_id.set_value(null, TRUE)
|
||||
unregister_signals()
|
||||
|
||||
/obj/item/circuit_component/signal_handler/proc/register_signals(datum/port/input/port)
|
||||
CIRCUIT_TRIGGER
|
||||
if(current_registered_entity)
|
||||
unregister_signals(port)
|
||||
|
||||
var/datum/target_datum = target.value
|
||||
if(signal_handler_options.value == COMP_SIGNAL_HANDLER_GLOBAL)
|
||||
target_datum = SSdcs
|
||||
|
||||
if(target_datum)
|
||||
RegisterSignal(target_datum, registered_signal, .proc/handle_signal_received)
|
||||
current_registered_entity = WEAKREF(target_datum)
|
||||
|
||||
/obj/item/circuit_component/signal_handler/proc/load_new_ports(list/ports_to_load)
|
||||
for(var/datum/port/input/input_port as anything in input_signal_ports)
|
||||
remove_input_port(input_port)
|
||||
for(var/datum/port/output/output_port as anything in output_signal_ports)
|
||||
remove_output_port(output_port)
|
||||
input_signal_ports = list()
|
||||
output_signal_ports = list()
|
||||
|
||||
signal_ports = ports_to_load
|
||||
for(var/list/data in signal_ports)
|
||||
if(data["is_response"])
|
||||
var/datum/port/input/bitflag_input = add_input_port(data["name"], PORT_TYPE_SIGNAL, order = 1, trigger = .proc/handle_bitflag_received)
|
||||
input_signal_ports[bitflag_input] = data["bitflag"]
|
||||
else
|
||||
output_signal_ports += add_output_port(data["name"], data["type"], order = 1)
|
||||
|
||||
|
||||
/obj/item/circuit_component/signal_handler/proc/unregister_signals(datum/port/input/port)
|
||||
CIRCUIT_TRIGGER
|
||||
|
||||
var/datum/registered_datum = current_registered_entity?.resolve()
|
||||
if(!registered_datum)
|
||||
return
|
||||
|
||||
UnregisterSignal(registered_datum, registered_signal)
|
||||
current_registered_entity = null
|
||||
|
||||
/obj/item/circuit_component/signal_handler/proc/handle_signal_received(...)
|
||||
SIGNAL_HANDLER
|
||||
var/list/arguments = args.Copy()
|
||||
|
||||
// usr is not supposed to be defined whilst these execute, which it can be for some signal IDs.
|
||||
// Especially if you try to proccall something - it'll fail because of this reason.
|
||||
// No other way to solve this problem without refactoring proccall code, but it's admin tooling so it's whatever.
|
||||
var/temp_usr = usr
|
||||
usr = null
|
||||
|
||||
SScircuit_component.queue_instant_run()
|
||||
var/first_arg = popleft(arguments)
|
||||
if(entity)
|
||||
entity.set_output(first_arg)
|
||||
|
||||
for(var/datum/port/output/port as anything in output_signal_ports)
|
||||
port.set_output(popleft(arguments))
|
||||
event_triggered.set_output(COMPONENT_SIGNAL)
|
||||
var/list/output = SScircuit_component.execute_instant_run()
|
||||
|
||||
usr = temp_usr
|
||||
|
||||
if(!output)
|
||||
message_admins("[parent.get_creator_admin()] took too much CPU time trying to handle a signal. Reduce the amount of circuit components attached to your [name] circuit component.")
|
||||
return
|
||||
|
||||
return output["bitflag"] || NONE
|
||||
|
||||
/obj/item/circuit_component/signal_handler/proc/handle_bitflag_received(datum/port/input/port, list/return_values)
|
||||
CIRCUIT_TRIGGER
|
||||
if(!return_values)
|
||||
return
|
||||
|
||||
if(!return_values["bitflag"])
|
||||
return_values["bitflag"] = NONE
|
||||
|
||||
return_values["bitflag"] |= input_signal_ports[port]
|
||||
|
||||
#undef COMP_SIGNAL_HANDLER_GLOBAL
|
||||
#undef COMP_SIGNAL_HANDLER_OBJECT
|
||||
@@ -0,0 +1,103 @@
|
||||
/proc/circuit_signal_response(name, bitflag)
|
||||
SHOULD_BE_PURE(TRUE)
|
||||
return list(
|
||||
"name" = name,
|
||||
"bitflag" = bitflag,
|
||||
"is_response" = TRUE
|
||||
)
|
||||
|
||||
/proc/circuit_signal_param(name, type)
|
||||
SHOULD_BE_PURE(TRUE)
|
||||
return list(
|
||||
"name" = name,
|
||||
"type" = type,
|
||||
"is_response" = FALSE
|
||||
)
|
||||
|
||||
GLOBAL_LIST_INIT(integrated_circuit_signal_ids, generate_circuit_signal_list())
|
||||
|
||||
/proc/generate_circuit_signal_list()
|
||||
var/cancel_attack = circuit_signal_response("Cancel Attack", COMPONENT_CANCEL_ATTACK_CHAIN)
|
||||
var/target = circuit_signal_param("Target", PORT_TYPE_ATOM)
|
||||
var/user = circuit_signal_param("User", PORT_TYPE_ATOM)
|
||||
var/item = circuit_signal_param("Item", PORT_TYPE_ATOM)
|
||||
var/entity = circuit_signal_param("Entity", PORT_TYPE_ATOM)
|
||||
|
||||
return list(
|
||||
COMSIG_PARENT_QDELETING = list(),
|
||||
COMSIG_PARENT_ATTACKBY = list(circuit_signal_response("Cancel Attack", COMPONENT_NO_AFTERATTACK), item, user),
|
||||
COMSIG_PARENT_ATTACKBY_SECONDARY = list(circuit_signal_response("Cancel Attack", COMPONENT_NO_AFTERATTACK), item, user),
|
||||
COMSIG_PARENT_EXAMINE = list(user),
|
||||
|
||||
COMSIG_ATOM_ATTACK_HAND = list(cancel_attack, user),
|
||||
COMSIG_ATOM_ATTACK_GHOST = list(cancel_attack, user),
|
||||
COMSIG_ATOM_BUMPED = list(entity),
|
||||
COMSIG_ATOM_HITBY = list(entity),
|
||||
|
||||
COMSIG_ITEM_ATTACK = list(cancel_attack, target, user),
|
||||
COMSIG_ITEM_PRE_ATTACK = list(cancel_attack, target, user),
|
||||
COMSIG_ITEM_AFTERATTACK = list(cancel_attack, target, user),
|
||||
COMSIG_ITEM_ATTACK_SECONDARY = list(circuit_signal_response("Cancel Attack", COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN), target, user),
|
||||
COMSIG_ITEM_ATTACK_SELF = list(cancel_attack, user),
|
||||
COMSIG_ITEM_ATTACK_SELF_SECONDARY = list(cancel_attack, user),
|
||||
)
|
||||
|
||||
GLOBAL_LIST_INIT(integrated_circuit_global_signal_ids, generate_global_circuit_signal_list())
|
||||
|
||||
/proc/generate_global_circuit_signal_list()
|
||||
var/client_ent = circuit_signal_param("Client", PORT_TYPE_ATOM)
|
||||
var/entity = circuit_signal_param("Entity", PORT_TYPE_ATOM)
|
||||
|
||||
return list(
|
||||
COMSIG_GLOB_MOB_DEATH = list(entity, circuit_signal_param("Gibbed", PORT_TYPE_NUMBER)),
|
||||
COMSIG_GLOB_MOB_CREATED = list(entity),
|
||||
COMSIG_GLOB_CLIENT_CONNECT = list(client_ent),
|
||||
|
||||
COMSIG_GLOB_JOB_AFTER_LATEJOIN_SPAWN = list(circuit_signal_param("Job Subsystem", PORT_TYPE_ATOM), entity, client_ent),
|
||||
COMSIG_GLOB_CREWMEMBER_JOINED = list(circuit_signal_param("Crewmember", PORT_TYPE_ATOM), circuit_signal_param("Rank", PORT_TYPE_STRING))
|
||||
)
|
||||
|
||||
/obj/item/circuit_component/signal_handler/ui_state(mob/user)
|
||||
return GLOB.admin_state
|
||||
|
||||
/obj/item/circuit_component/signal_handler/ui_static_data(mob/user)
|
||||
. = list()
|
||||
.["global_port_types"] = GLOB.wiremod_fundamental_types
|
||||
|
||||
|
||||
/obj/item/circuit_component/signal_handler/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "CircuitSignalHandler", name)
|
||||
ui.open()
|
||||
ui.set_autoupdate(FALSE)
|
||||
|
||||
/obj/item/circuit_component/signal_handler/ui_act(action, list/params, datum/tgui/ui)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/signal_id = params["signal_id"]
|
||||
|
||||
if(!istext(signal_id))
|
||||
return
|
||||
|
||||
var/list/responses = params["responses"]
|
||||
var/list/parameters = params["parameters"]
|
||||
if(!islist(responses) || !islist(parameters))
|
||||
return
|
||||
|
||||
var/list/sanitized_data = list()
|
||||
|
||||
for(var/list/data as anything in responses)
|
||||
sanitized_data += list(circuit_signal_response(data["name"], text2num(data["bitflag"])))
|
||||
for(var/list/data as anything in parameters)
|
||||
sanitized_data += list(circuit_signal_param(data["name"], data["datatype"]))
|
||||
|
||||
var/extra_info = ""
|
||||
if(params["global"])
|
||||
GLOB.integrated_circuit_global_signal_ids[signal_id] = sanitized_data
|
||||
extra_info = " as a global signal"
|
||||
else
|
||||
GLOB.integrated_circuit_signal_ids[signal_id] = sanitized_data
|
||||
balloon_alert(usr, "successfully added [signal_id][extra_info]")
|
||||
@@ -10,11 +10,17 @@
|
||||
/// The shell this component is attached to.
|
||||
var/datum/port/output/output
|
||||
|
||||
/// The signal sent when the status is updated.
|
||||
var/datum/port/output/shell_received
|
||||
|
||||
/obj/item/circuit_component/self/populate_ports()
|
||||
output = add_output_port("Self", PORT_TYPE_ATOM)
|
||||
output = add_output_port("Shell", PORT_TYPE_ATOM)
|
||||
shell_received = add_output_port("Shell Updated", PORT_TYPE_SIGNAL)
|
||||
|
||||
/obj/item/circuit_component/self/register_shell(atom/movable/shell)
|
||||
output.set_output(shell)
|
||||
shell_received.set_output(COMPONENT_SIGNAL)
|
||||
|
||||
/obj/item/circuit_component/self/unregister_shell(atom/movable/shell)
|
||||
output.set_output(null)
|
||||
shell_received.set_output(COMPONENT_SIGNAL)
|
||||
|
||||
@@ -28,7 +28,7 @@ GLOBAL_LIST_INIT(circuit_datatypes, generate_circuit_datatypes())
|
||||
* Used for implicit conversions between outputs and inputs (e.g. number -> string)
|
||||
* and applying/removing signals on inputs
|
||||
*/
|
||||
/datum/circuit_datatype/proc/convert_value(datum/port/port, value_to_convert)
|
||||
/datum/circuit_datatype/proc/convert_value(datum/port/port, value_to_convert, force = FALSE)
|
||||
return value_to_convert
|
||||
|
||||
/**
|
||||
|
||||
@@ -84,7 +84,7 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit)
|
||||
for(var/obj/item/circuit_component/to_delete in attached_components)
|
||||
remove_component(to_delete)
|
||||
qdel(to_delete)
|
||||
QDEL_LIST(circuit_variables)
|
||||
QDEL_LIST_ASSOC_VAL(circuit_variables)
|
||||
attached_components.Cut()
|
||||
shell = null
|
||||
examined_component = null
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
if(src.value != value || force)
|
||||
if(isatom(value))
|
||||
UnregisterSignal(value, COMSIG_PARENT_QDELETING)
|
||||
src.value = datatype_handler.convert_value(src, value)
|
||||
src.value = datatype_handler.convert_value(src, value, force)
|
||||
if(isatom(value))
|
||||
RegisterSignal(value, COMSIG_PARENT_QDELETING, .proc/null_value)
|
||||
SEND_SIGNAL(src, COMSIG_PORT_SET_VALUE, value)
|
||||
|
||||
@@ -7,4 +7,7 @@
|
||||
return TRUE
|
||||
|
||||
/datum/circuit_datatype/any/handle_manual_input(datum/port/input/port, mob/user, user_input)
|
||||
return text2num(user_input) || user_input
|
||||
var/result = text2num(user_input)
|
||||
if(isnull(result))
|
||||
return user_input
|
||||
return result
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/datum/port/input/option
|
||||
var/list/possible_options
|
||||
|
||||
/datum/port/input/option/New(obj/item/circuit_component/to_connect, name, datatype, trigger, default, possible_options)
|
||||
/datum/port/input/option/New(obj/item/circuit_component/to_connect, name, datatype, order = 1, trigger = null, default = null, possible_options)
|
||||
. = ..()
|
||||
src.possible_options = possible_options
|
||||
set_value(default, force = TRUE)
|
||||
if(length(possible_options))
|
||||
set_value(possible_options[1])
|
||||
|
||||
/datum/circuit_datatype/option
|
||||
datatype = PORT_TYPE_OPTION
|
||||
@@ -21,7 +22,10 @@
|
||||
|
||||
return datatype_to_check == PORT_TYPE_STRING
|
||||
|
||||
/datum/circuit_datatype/option/convert_value(datum/port/input/option/port, value_to_convert)
|
||||
/datum/circuit_datatype/option/convert_value(datum/port/input/option/port, value_to_convert, force = FALSE)
|
||||
if(force)
|
||||
return value_to_convert
|
||||
|
||||
if(!port.possible_options)
|
||||
return null
|
||||
|
||||
|
||||
@@ -3800,6 +3800,8 @@
|
||||
#include "code\modules\wiremod\components\admin\setvar.dm"
|
||||
#include "code\modules\wiremod\components\admin\spawn.dm"
|
||||
#include "code\modules\wiremod\components\admin\to_type.dm"
|
||||
#include "code\modules\wiremod\components\admin\signal_handler\signal_handler.dm"
|
||||
#include "code\modules\wiremod\components\admin\signal_handler\signal_list.dm"
|
||||
#include "code\modules\wiremod\components\atom\direction.dm"
|
||||
#include "code\modules\wiremod\components\atom\gps.dm"
|
||||
#include "code\modules\wiremod\components\atom\health.dm"
|
||||
|
||||
@@ -72,6 +72,7 @@ export class Dropdown extends Component {
|
||||
noscroll,
|
||||
nochevron,
|
||||
width,
|
||||
openWidth = width,
|
||||
onClick,
|
||||
selected,
|
||||
disabled,
|
||||
@@ -90,7 +91,7 @@ export class Dropdown extends Component {
|
||||
ref={menu => { this.menuRef = menu; }}
|
||||
tabIndex="-1"
|
||||
style={{
|
||||
'width': width,
|
||||
'width': openWidth,
|
||||
}}
|
||||
className={classes([
|
||||
noscroll && 'Dropdown__menu-noscroll' || 'Dropdown__menu',
|
||||
@@ -103,7 +104,7 @@ export class Dropdown extends Component {
|
||||
return (
|
||||
<div className="Dropdown">
|
||||
<Box
|
||||
width={width}
|
||||
width={this.state.open ? openWidth : width}
|
||||
className={classes([
|
||||
'Dropdown__control',
|
||||
'Button',
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
import { Component } from "inferno";
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Stack, Section, Input, Button, Dropdown } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
|
||||
type Response = {
|
||||
name: string;
|
||||
bitflag: number;
|
||||
}
|
||||
|
||||
type Parameter = {
|
||||
name: string;
|
||||
datatype: string;
|
||||
}
|
||||
|
||||
type CircuitSignalHandlerState = {
|
||||
signal_id: string;
|
||||
responseList: Response[];
|
||||
parameterList: Parameter[];
|
||||
global: Boolean;
|
||||
}
|
||||
|
||||
type CircuitSignalHandlerData ={
|
||||
global_port_types: string[];
|
||||
}
|
||||
|
||||
type BitflagToString = {
|
||||
[key: number]: string;
|
||||
}
|
||||
|
||||
export class CircuitSignalHandler
|
||||
extends Component<{}, CircuitSignalHandlerState> {
|
||||
bitflags: BitflagToString;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
signal_id: "signal_id",
|
||||
responseList: [],
|
||||
parameterList: [],
|
||||
global: false,
|
||||
};
|
||||
|
||||
this.bitflags = {};
|
||||
|
||||
for (let i = 0; i < 24; i++) {
|
||||
this.bitflags[1 << i] = `Flag ${i+1}`;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { act, data } = useBackend<CircuitSignalHandlerData>(this.context);
|
||||
const { responseList, parameterList, signal_id, global }
|
||||
= this.state as CircuitSignalHandlerState;
|
||||
const {
|
||||
global_port_types,
|
||||
} = data;
|
||||
return (
|
||||
<Window width={600} height={300}>
|
||||
<Window.Content>
|
||||
<Stack vertical fill>
|
||||
<Stack.Item>
|
||||
<Stack fill>
|
||||
<Stack.Item grow>
|
||||
<Input
|
||||
placeholder="Signal ID"
|
||||
value={signal_id}
|
||||
fluid
|
||||
onChange={(e, value) => this.setState({ signal_id: value })}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button.Checkbox
|
||||
checked={global}
|
||||
content="Global"
|
||||
onClick={(e) => this.setState({ global: !global })}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Stack fill>
|
||||
<Stack.Item grow={1} basis={0}>
|
||||
<Section title="Responses" fill scrollable>
|
||||
<Stack vertical>
|
||||
{responseList.map((val, index) => (
|
||||
<Entry
|
||||
key={index}
|
||||
name={val.name}
|
||||
current_option={this.bitflags[val.bitflag]}
|
||||
onRemove={() => {
|
||||
responseList.splice(index, 1);
|
||||
this.setState({ parameterList });
|
||||
}}
|
||||
onEnter={(e, value) => {
|
||||
const param = responseList[index];
|
||||
param.name = value;
|
||||
this.setState({ parameterList });
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<Stack.Item>
|
||||
<Button
|
||||
fluid
|
||||
content="Add Response"
|
||||
color="good"
|
||||
icon="plus"
|
||||
onClick={() => {
|
||||
// Object.keys returns strings here, even though we
|
||||
// have a number->key assoc array here, so we have
|
||||
// to explicitly cast it to a number[] type.
|
||||
const bitflag_keys = Object.keys(
|
||||
this.bitflags
|
||||
) as unknown as number[];
|
||||
responseList.push({
|
||||
name: "Response",
|
||||
bitflag: bitflag_keys[responseList.length],
|
||||
});
|
||||
this.setState({ parameterList });
|
||||
}}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow={1} basis={0}>
|
||||
<Section title="Parameters" fill scrollable>
|
||||
<Stack vertical>
|
||||
{parameterList.map((val, index) => (
|
||||
<Entry
|
||||
key={index}
|
||||
name={val.name}
|
||||
current_option={val.datatype}
|
||||
options={global_port_types}
|
||||
onRemove={() => {
|
||||
parameterList.splice(index, 1);
|
||||
this.setState({ parameterList });
|
||||
}}
|
||||
onSetOption={type => {
|
||||
const param = parameterList[index];
|
||||
param.datatype = type;
|
||||
this.setState({ parameterList });
|
||||
}}
|
||||
onEnter={(e, value) => {
|
||||
const param = parameterList[index];
|
||||
param.name = value;
|
||||
this.setState({ parameterList });
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<Stack.Item>
|
||||
<Button
|
||||
fluid
|
||||
content="Add Parameter"
|
||||
color="good"
|
||||
icon="plus"
|
||||
onClick={() => {
|
||||
parameterList.push({
|
||||
name: "Parameter",
|
||||
datatype: global_port_types[0],
|
||||
});
|
||||
this.setState({ parameterList });
|
||||
}}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
content="Submit"
|
||||
textAlign="center"
|
||||
fluid
|
||||
onClick={() => act("add_new_id", {
|
||||
signal_id: signal_id,
|
||||
responses: responseList,
|
||||
parameters: parameterList,
|
||||
global: global,
|
||||
})}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
type EntryProps = {
|
||||
onRemove: (e: MouseEvent) => any;
|
||||
onEnter: (e: MouseEvent, value: string) => any;
|
||||
onSetOption?: (type: string) => any;
|
||||
name: string;
|
||||
current_option: string;
|
||||
options?: string[];
|
||||
}
|
||||
|
||||
const Entry = (props: EntryProps, context) => {
|
||||
const {
|
||||
onRemove,
|
||||
onEnter,
|
||||
onSetOption,
|
||||
name,
|
||||
current_option,
|
||||
options = [],
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Stack.Item {...rest}>
|
||||
<Stack>
|
||||
<Stack.Item grow>
|
||||
<Input
|
||||
placeholder="Name"
|
||||
value={name}
|
||||
onChange={onEnter}
|
||||
fluid
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
{options.length && (
|
||||
<Dropdown
|
||||
displayText={current_option}
|
||||
options={options}
|
||||
onSelected={onSetOption}
|
||||
/>
|
||||
) || (
|
||||
<Box
|
||||
textAlign="center"
|
||||
py="2px"
|
||||
px={2}
|
||||
>
|
||||
{current_option}
|
||||
</Box>
|
||||
)}
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="times"
|
||||
color="red"
|
||||
onClick={onRemove}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
import { BasicInput } from './BasicInput';
|
||||
import { NumberInput, Button, Stack, Input, Dropdown, Box } from '../../components';
|
||||
import { NumberInput, Button, Stack, Input, Dropdown } from '../../components';
|
||||
import { OPTION_DROPDOWN_LARGE_CHAR_AMOUNT } from './constants';
|
||||
|
||||
export const FUNDAMENTAL_DATA_TYPES = {
|
||||
'string': (props, context) => {
|
||||
@@ -57,15 +58,25 @@ export const FUNDAMENTAL_DATA_TYPES = {
|
||||
},
|
||||
'option': (props, context) => {
|
||||
const { value, setValue, extraData } = props;
|
||||
let large = false;
|
||||
const data = Array.isArray(extraData)
|
||||
? extraData
|
||||
: Object.keys(extraData);
|
||||
|
||||
data.forEach(element => {
|
||||
if (element.length > OPTION_DROPDOWN_LARGE_CHAR_AMOUNT) {
|
||||
large = true;
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
className="Datatype__Option"
|
||||
color={"transparent"}
|
||||
options={Array.isArray(extraData)
|
||||
? extraData
|
||||
: Object.keys(extraData)}
|
||||
options={data}
|
||||
onSelected={setValue}
|
||||
displayText={value}
|
||||
openWidth={large ? "200px" : undefined}
|
||||
noscroll
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -3,3 +3,4 @@ export const ABSOLUTE_Y_OFFSET = -32;
|
||||
export const SVG_CURVE_INTENSITY = 64;
|
||||
|
||||
export const MOUSE_BUTTON_LEFT = 0;
|
||||
export const OPTION_DROPDOWN_LARGE_CHAR_AMOUNT = 12;
|
||||
|
||||
Reference in New Issue
Block a user